Skip to content

Commit db0c3c2

Browse files
authored
verify remote console using LB and add retry for voyager ingress creation (#2363)
* verify remote console using LB * disable nginx admissionWebhooks
1 parent 1672325 commit db0c3c2

File tree

5 files changed

+355
-20
lines changed

5 files changed

+355
-20
lines changed

integration-tests/src/test/java/oracle/weblogic/kubernetes/ItRemoteConsole.java

Lines changed: 281 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,62 @@
33

44
package oracle.weblogic.kubernetes;
55

6+
import java.io.IOException;
7+
import java.nio.charset.StandardCharsets;
8+
import java.nio.file.Files;
9+
import java.nio.file.Path;
10+
import java.nio.file.Paths;
11+
import java.util.ArrayList;
12+
import java.util.HashMap;
613
import java.util.List;
714

15+
import io.kubernetes.client.custom.IntOrString;
16+
import io.kubernetes.client.openapi.models.NetworkingV1beta1HTTPIngressPath;
17+
import io.kubernetes.client.openapi.models.NetworkingV1beta1HTTPIngressRuleValue;
18+
import io.kubernetes.client.openapi.models.NetworkingV1beta1IngressBackend;
19+
import io.kubernetes.client.openapi.models.NetworkingV1beta1IngressRule;
20+
import oracle.weblogic.kubernetes.actions.impl.primitive.HelmParams;
821
import oracle.weblogic.kubernetes.annotations.IntegrationTest;
922
import oracle.weblogic.kubernetes.annotations.Namespaces;
1023
import oracle.weblogic.kubernetes.logging.LoggingFacade;
24+
import oracle.weblogic.kubernetes.utils.ExecCommand;
25+
import oracle.weblogic.kubernetes.utils.ExecResult;
26+
import org.awaitility.core.ConditionFactory;
1127
import org.junit.jupiter.api.AfterAll;
1228
import org.junit.jupiter.api.BeforeAll;
1329
import org.junit.jupiter.api.DisplayName;
1430
import org.junit.jupiter.api.Test;
1531

32+
import static java.util.concurrent.TimeUnit.MINUTES;
33+
import static java.util.concurrent.TimeUnit.SECONDS;
1634
import static oracle.weblogic.kubernetes.TestConstants.ADMIN_SERVER_NAME_BASE;
1735
import static oracle.weblogic.kubernetes.TestConstants.K8S_NODEPORT_HOST;
1836
import static oracle.weblogic.kubernetes.TestConstants.MANAGED_SERVER_NAME_BASE;
1937
import static oracle.weblogic.kubernetes.TestConstants.MII_BASIC_IMAGE_NAME;
2038
import static oracle.weblogic.kubernetes.TestConstants.MII_BASIC_IMAGE_TAG;
39+
import static oracle.weblogic.kubernetes.TestConstants.RESULTS_ROOT;
40+
import static oracle.weblogic.kubernetes.TestConstants.VOYAGER_CHART_NAME;
41+
import static oracle.weblogic.kubernetes.actions.ActionConstants.RESOURCE_DIR;
42+
import static oracle.weblogic.kubernetes.actions.TestActions.createIngress;
43+
import static oracle.weblogic.kubernetes.actions.TestActions.listIngresses;
2144
import static oracle.weblogic.kubernetes.actions.impl.Service.getServiceNodePort;
45+
import static oracle.weblogic.kubernetes.assertions.TestAssertions.isVoyagerReady;
2246
import static oracle.weblogic.kubernetes.utils.CommonMiiTestUtils.createMiiDomainAndVerify;
47+
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.createIngressAndRetryIfFail;
2348
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.getExternalServicePodName;
49+
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.installAndVerifyNginx;
2450
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.installAndVerifyOperator;
51+
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.installAndVerifyTraefik;
52+
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.installAndVerifyVoyager;
2553
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.installAndVerifyWlsRemoteConsole;
2654
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.shutdownWlsRemoteConsole;
55+
import static oracle.weblogic.kubernetes.utils.TestUtils.callWebAppAndWaitTillReady;
2756
import static oracle.weblogic.kubernetes.utils.TestUtils.callWebAppAndWaitTillReturnedCode;
2857
import static oracle.weblogic.kubernetes.utils.ThreadSafeLogger.getLogger;
58+
import static org.assertj.core.api.Assertions.assertThat;
59+
import static org.awaitility.Awaitility.with;
60+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
61+
import static org.junit.jupiter.api.Assertions.assertEquals;
2962
import static org.junit.jupiter.api.Assertions.assertNotNull;
3063
import static org.junit.jupiter.api.Assertions.assertTrue;
3164

@@ -34,14 +67,28 @@
3467
class ItRemoteConsole {
3568

3669
private static String domainNamespace = null;
70+
private static String traefikNamespace = null;
71+
private static String voyagerNamespace = null;
72+
private static String nginxNamespace = null;
73+
private static HelmParams traefikHelmParams = null;
74+
private static HelmParams voyagerHelmParams = null;
75+
private static HelmParams nginxHelmParams = null;
76+
private static int voyagerNodePort;
77+
private static int nginxNodePort;
3778

3879
// domain constants
3980
private static final String domainUid = "domain1";
40-
private static final String clusterName = "cluster-1";
4181
private static final int replicaCount = 1;
4282
private static final String adminServerPodName = domainUid + "-" + ADMIN_SERVER_NAME_BASE;
4383
private static final String managedServerPrefix = domainUid + "-" + MANAGED_SERVER_NAME_BASE;
4484
private static LoggingFacade logger = null;
85+
private static final int ADMIN_SERVER_PORT = 7001;
86+
private static final String voyagerIngressName = "voyager-path-routing";
87+
88+
private static ConditionFactory withStandardRetryPolicy =
89+
with().pollDelay(2, SECONDS)
90+
.and().with().pollInterval(10, SECONDS)
91+
.atMost(5, MINUTES).await();
4592

4693
/**
4794
* Get namespaces for operator and WebLogic domain.
@@ -50,7 +97,7 @@ class ItRemoteConsole {
5097
* JUnit engine parameter resolution mechanism
5198
*/
5299
@BeforeAll
53-
public static void initAll(@Namespaces(2) List<String> namespaces) {
100+
public static void initAll(@Namespaces(5) List<String> namespaces) {
54101
logger = getLogger();
55102
// get a unique operator namespace
56103
logger.info("Getting a unique namespace for operator");
@@ -62,9 +109,36 @@ public static void initAll(@Namespaces(2) List<String> namespaces) {
62109
assertNotNull(namespaces.get(1), "Namespace list is null");
63110
domainNamespace = namespaces.get(1);
64111

112+
logger.info("Assign a unique namespace for Traefik");
113+
assertNotNull(namespaces.get(2), "Namespace list is null");
114+
traefikNamespace = namespaces.get(2);
115+
116+
// get a unique Voyager namespace
117+
logger.info("Assign a unique namespace for Voyager");
118+
assertNotNull(namespaces.get(3), "Namespace list is null");
119+
voyagerNamespace = namespaces.get(3);
120+
121+
// get a unique Nginx namespace
122+
logger.info("Assign a unique namespace for Nginx");
123+
assertNotNull(namespaces.get(4), "Namespace list is null");
124+
nginxNamespace = namespaces.get(4);
125+
65126
// install and verify operator
66127
installAndVerifyOperator(opNamespace, domainNamespace);
67128

129+
// install and verify Traefik
130+
logger.info("Installing Traefik controller using helm");
131+
traefikHelmParams = installAndVerifyTraefik(traefikNamespace, 0, 0);
132+
133+
// install and verify Voyager
134+
final String cloudProvider = "baremetal";
135+
final boolean enableValidatingWebhook = false;
136+
voyagerHelmParams =
137+
installAndVerifyVoyager(voyagerNamespace, cloudProvider, enableValidatingWebhook);
138+
139+
// install and verify Nginx
140+
nginxHelmParams = installAndVerifyNginx(nginxNamespace, 0, 0);
141+
68142
// create a basic model in image domain
69143
createMiiDomainAndVerify(
70144
domainNamespace,
@@ -74,32 +148,77 @@ public static void initAll(@Namespaces(2) List<String> namespaces) {
74148
managedServerPrefix,
75149
replicaCount);
76150

151+
// create ingress rules with path routing for Traefik, Voyager and NGINX
152+
createTraefikIngressRoutingRules(domainNamespace);
153+
createVoyagerIngressPathRoutingRules();
154+
createNginxIngressPathRoutingRules();
155+
156+
// install WebLogic remote console
157+
assertTrue(installAndVerifyWlsRemoteConsole(), "Remote Console installation failed");
158+
159+
// Verify k8s WebLogic domain is accessible through remote console using admin server nodeport
160+
verifyWlsRemoteConsoleConnection();
77161
}
78162

79163
/**
80-
* Verify WLS Remote Console installation is successful.
81-
* Verify k8s WebLogic domain is accessible through remote console.
164+
* Verify k8s WebLogic domain is accessible through remote console using Traefik.
82165
*/
83166
@Test
84-
@DisplayName("Verify Connecting to Mii domain through WLS Remote Console is successful")
85-
public void testWlsRemoteConsoleConnection() {
86-
87-
assertTrue(installAndVerifyWlsRemoteConsole(), "Remote Console installation failed");
167+
@DisplayName("Verify Connecting to Mii domain WLS Remote Console through Traefik is successful")
168+
public void testWlsRemoteConsoleConnectionThroughTraefik() {
88169

89-
int nodePort = getServiceNodePort(
90-
domainNamespace, getExternalServicePodName(adminServerPodName), "default");
91-
assertTrue(nodePort != -1,
170+
int traefikNodePort = getServiceNodePort(traefikNamespace, traefikHelmParams.getReleaseName(), "web");
171+
assertTrue(traefikNodePort != -1,
92172
"Could not get the default external service node port");
93-
logger.info("Found the default service nodePort {0}", nodePort);
173+
logger.info("Found the Traefik service nodePort {0}", traefikNodePort);
94174
logger.info("The K8S_NODEPORT_HOST is {0}", K8S_NODEPORT_HOST);
95175
String curlCmd = "curl -v --user weblogic:welcome1 -H Content-Type:application/json -d "
96176
+ "\"{ \\" + "\"domainUrl\\" + "\"" + ": " + "\\" + "\"" + "http://"
97-
+ K8S_NODEPORT_HOST + ":" + nodePort + "\\" + "\" }" + "\""
177+
+ K8S_NODEPORT_HOST + ":" + traefikNodePort + "\\" + "\" }" + "\""
98178
+ " http://localhost:8012/api/connection --write-out %{http_code} -o /dev/null";
99-
logger.info("Executing default nodeport curl command {0}", curlCmd);
179+
logger.info("Executing Traefik nodeport curl command {0}", curlCmd);
100180
assertTrue(callWebAppAndWaitTillReturnedCode(curlCmd, "201", 10), "Calling web app failed");
101-
logger.info("WebLogic domain is accessible through remote console");
181+
logger.info("WebLogic domain is accessible through remote console using Traefik");
182+
}
102183

184+
/**
185+
* Verify k8s WebLogic domain is accessible through remote console using Voyager.
186+
*/
187+
@Test
188+
@DisplayName("Verify Connecting to Mii domain WLS Remote Console through Voyager is successful")
189+
public void testWlsRemoteConsoleConnectionThroughVoyager() {
190+
191+
assertTrue(voyagerNodePort != -1, "Could not get the default external service node port");
192+
logger.info("Found the Voyager service nodePort {0}", voyagerNodePort);
193+
logger.info("The K8S_NODEPORT_HOST is {0}", K8S_NODEPORT_HOST);
194+
195+
String curlCmd = "curl -v --user weblogic:welcome1 -H Content-Type:application/json -d "
196+
+ "\"{ \\" + "\"domainUrl\\" + "\"" + ": " + "\\" + "\"" + "http://"
197+
+ K8S_NODEPORT_HOST + ":" + voyagerNodePort + "\\" + "\" }" + "\""
198+
+ " http://localhost:8012/api/connection --write-out %{http_code} -o /dev/null";
199+
logger.info("Executing Voyager nodeport curl command {0}", curlCmd);
200+
assertTrue(callWebAppAndWaitTillReturnedCode(curlCmd, "201", 10), "Calling web app failed");
201+
logger.info("WebLogic domain is accessible through remote console using Voyager");
202+
}
203+
204+
/**
205+
* Verify k8s WebLogic domain is accessible through remote console using NGINX.
206+
*/
207+
@Test
208+
@DisplayName("Verify Connecting to Mii domain WLS Remote Console through NGINX is successful")
209+
public void testWlsRemoteConsoleConnectionThroughNginx() {
210+
211+
assertTrue(nginxNodePort != -1, "Could not get the default external service node port");
212+
logger.info("Found the NGINX service nodePort {0}", nginxNodePort);
213+
logger.info("The K8S_NODEPORT_HOST is {0}", K8S_NODEPORT_HOST);
214+
215+
String curlCmd = "curl -v --user weblogic:welcome1 -H Content-Type:application/json -d "
216+
+ "\"{ \\" + "\"domainUrl\\" + "\"" + ": " + "\\" + "\"" + "http://"
217+
+ K8S_NODEPORT_HOST + ":" + nginxNodePort + "\\" + "\" }" + "\""
218+
+ " http://localhost:8012/api/connection --write-out %{http_code} -o /dev/null";
219+
logger.info("Executing NGINX nodeport curl command {0}", curlCmd);
220+
assertTrue(callWebAppAndWaitTillReturnedCode(curlCmd, "201", 10), "Calling web app failed");
221+
logger.info("WebLogic domain is accessible through remote console using NGINX");
103222
}
104223

105224
/**
@@ -114,4 +233,151 @@ public void tearDownAll() {
114233
}
115234
}
116235

236+
private static void createTraefikIngressRoutingRules(String domainNamespace) {
237+
logger.info("Creating ingress rules for domain traffic routing");
238+
Path srcFile = Paths.get(RESOURCE_DIR, "traefik/traefik-ingress-rules-remoteconsole.yaml");
239+
Path dstFile = Paths.get(RESULTS_ROOT, "traefik/traefik-ingress-rules-remoteconsole.yaml");
240+
assertDoesNotThrow(() -> {
241+
Files.deleteIfExists(dstFile);
242+
Files.createDirectories(dstFile.getParent());
243+
Files.write(dstFile, Files.readString(srcFile).replaceAll("@NS@", domainNamespace)
244+
.replaceAll("@domain1uid@", domainUid)
245+
.getBytes(StandardCharsets.UTF_8));
246+
});
247+
String command = "kubectl create -f " + dstFile;
248+
logger.info("Running {0}", command);
249+
ExecResult result;
250+
try {
251+
result = ExecCommand.exec(command, true);
252+
String response = result.stdout().trim();
253+
logger.info("exitCode: {0}, \nstdout: {1}, \nstderr: {2}",
254+
result.exitValue(), response, result.stderr());
255+
assertEquals(0, result.exitValue(), "Command didn't succeed");
256+
} catch (IOException | InterruptedException ex) {
257+
logger.severe(ex.getMessage());
258+
}
259+
}
260+
261+
private static void createVoyagerIngressPathRoutingRules() {
262+
263+
// set the annotations for Voyager
264+
HashMap<String, String> annotations = new HashMap<>();
265+
annotations.put("ingress.appscode.com/type", "NodePort");
266+
annotations.put("kubernetes.io/ingress.class", "voyager");
267+
annotations.put("ingress.appscode.com/rewrite-target", "/");
268+
269+
List<NetworkingV1beta1IngressRule> ingressRules = new ArrayList<>();
270+
List<NetworkingV1beta1HTTPIngressPath> httpIngressPaths = new ArrayList<>();
271+
272+
NetworkingV1beta1HTTPIngressPath httpIngressPath = new NetworkingV1beta1HTTPIngressPath()
273+
.path("/")
274+
.backend(new NetworkingV1beta1IngressBackend()
275+
.serviceName(domainUid + "-admin-server")
276+
.servicePort(new IntOrString(ADMIN_SERVER_PORT))
277+
);
278+
httpIngressPaths.add(httpIngressPath);
279+
280+
NetworkingV1beta1IngressRule ingressRule = new NetworkingV1beta1IngressRule()
281+
.host("")
282+
.http(new NetworkingV1beta1HTTPIngressRuleValue()
283+
.paths(httpIngressPaths));
284+
285+
ingressRules.add(ingressRule);
286+
287+
assertDoesNotThrow(() -> createIngress(voyagerIngressName, domainNamespace, annotations, ingressRules, null));
288+
289+
// wait until voyager ingress pod is ready
290+
withStandardRetryPolicy
291+
.conditionEvaluationListener(
292+
condition -> logger.info(
293+
"Waiting for Voyager ingress to be ready in namespace {0} (elapsed time {1}ms, remaining time {2}ms)",
294+
domainNamespace,
295+
condition.getElapsedTimeInMS(),
296+
condition.getRemainingTimeInMS()))
297+
.until(assertDoesNotThrow(() -> isVoyagerReady(domainNamespace, voyagerIngressName),
298+
"isVoyagerReady failed with ApiException"));
299+
300+
// check the ingress was found in the domain namespace
301+
assertThat(assertDoesNotThrow(() -> listIngresses(domainNamespace)))
302+
.as(String.format("Test ingress %s was found in namespace %s", voyagerIngressName, domainNamespace))
303+
.withFailMessage(String.format("Ingress %s was not found in namespace %s", voyagerIngressName, domainNamespace))
304+
.contains(voyagerIngressName);
305+
306+
logger.info("ingress {0} was created in namespace {1}", voyagerIngressName, domainNamespace);
307+
308+
// check the ingress is ready to route the app to the server pod
309+
voyagerNodePort = assertDoesNotThrow(() ->
310+
getServiceNodePort(domainNamespace, VOYAGER_CHART_NAME + "-" + voyagerIngressName, "tcp-80"),
311+
"Getting voyager loadbalancer service node port failed");
312+
String curlCmd = "curl --silent --show-error --noproxy '*' http://" + K8S_NODEPORT_HOST + ":" + voyagerNodePort
313+
+ "/weblogic/ready --write-out %{http_code} -o /dev/null";
314+
315+
logger.info("Executing curl command {0}", curlCmd);
316+
assertTrue(callWebAppAndWaitTillReady(curlCmd, 60));
317+
}
318+
319+
private static void createNginxIngressPathRoutingRules() {
320+
321+
// create an ingress in domain namespace
322+
String ingressName = domainNamespace + "-nginx-path-routing";
323+
324+
HashMap<String, String> annotations = new HashMap<>();
325+
annotations.put("kubernetes.io/ingress.class", "nginx");
326+
327+
// create ingress rules for two domains
328+
List<NetworkingV1beta1IngressRule> ingressRules = new ArrayList<>();
329+
List<NetworkingV1beta1HTTPIngressPath> httpIngressPaths = new ArrayList<>();
330+
331+
NetworkingV1beta1HTTPIngressPath httpIngressPath = new NetworkingV1beta1HTTPIngressPath()
332+
.path("/")
333+
.backend(new NetworkingV1beta1IngressBackend()
334+
.serviceName(domainUid + "-admin-server")
335+
.servicePort(new IntOrString(ADMIN_SERVER_PORT))
336+
);
337+
httpIngressPaths.add(httpIngressPath);
338+
339+
NetworkingV1beta1IngressRule ingressRule = new NetworkingV1beta1IngressRule()
340+
.host("")
341+
.http(new NetworkingV1beta1HTTPIngressRuleValue()
342+
.paths(httpIngressPaths));
343+
344+
ingressRules.add(ingressRule);
345+
346+
createIngressAndRetryIfFail(60, false, ingressName, domainNamespace, annotations, ingressRules, null);
347+
348+
// check the ingress was found in the domain namespace
349+
assertThat(assertDoesNotThrow(() -> listIngresses(domainNamespace)))
350+
.as(String.format("Test ingress %s was found in namespace %s", ingressName, domainNamespace))
351+
.withFailMessage(String.format("Ingress %s was not found in namespace %s", ingressName, domainNamespace))
352+
.contains(ingressName);
353+
354+
logger.info("ingress {0} was created in namespace {1}", ingressName, domainNamespace);
355+
356+
// check the ingress is ready to route the app to the server pod
357+
String nginxServiceName = nginxHelmParams.getReleaseName() + "-ingress-nginx-controller";
358+
nginxNodePort = assertDoesNotThrow(() -> getServiceNodePort(nginxNamespace, nginxServiceName, "http"),
359+
"Getting Nginx loadbalancer service node port failed");
360+
String curlCmd = "curl --silent --show-error --noproxy '*' http://" + K8S_NODEPORT_HOST + ":" + nginxNodePort
361+
+ "/weblogic/ready --write-out %{http_code} -o /dev/null";
362+
363+
logger.info("Executing curl command {0}", curlCmd);
364+
assertTrue(callWebAppAndWaitTillReady(curlCmd, 60));
365+
}
366+
367+
private static void verifyWlsRemoteConsoleConnection() {
368+
369+
int nodePort = getServiceNodePort(
370+
domainNamespace, getExternalServicePodName(adminServerPodName), "default");
371+
assertTrue(nodePort != -1,
372+
"Could not get the default external service node port");
373+
logger.info("Found the default service nodePort {0}", nodePort);
374+
logger.info("The K8S_NODEPORT_HOST is {0}", K8S_NODEPORT_HOST);
375+
String curlCmd = "curl -v --user weblogic:welcome1 -H Content-Type:application/json -d "
376+
+ "\"{ \\" + "\"domainUrl\\" + "\"" + ": " + "\\" + "\"" + "http://"
377+
+ K8S_NODEPORT_HOST + ":" + nodePort + "\\" + "\" }" + "\""
378+
+ " http://localhost:8012/api/connection --write-out %{http_code} -o /dev/null";
379+
logger.info("Executing default nodeport curl command {0}", curlCmd);
380+
assertTrue(callWebAppAndWaitTillReturnedCode(curlCmd, "201", 10), "Calling web app failed");
381+
logger.info("WebLogic domain is accessible through remote console");
382+
}
117383
}

0 commit comments

Comments
 (0)