33
44package 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 ;
613import 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 ;
821import oracle .weblogic .kubernetes .annotations .IntegrationTest ;
922import oracle .weblogic .kubernetes .annotations .Namespaces ;
1023import 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 ;
1127import org .junit .jupiter .api .AfterAll ;
1228import org .junit .jupiter .api .BeforeAll ;
1329import org .junit .jupiter .api .DisplayName ;
1430import org .junit .jupiter .api .Test ;
1531
32+ import static java .util .concurrent .TimeUnit .MINUTES ;
33+ import static java .util .concurrent .TimeUnit .SECONDS ;
1634import static oracle .weblogic .kubernetes .TestConstants .ADMIN_SERVER_NAME_BASE ;
1735import static oracle .weblogic .kubernetes .TestConstants .K8S_NODEPORT_HOST ;
1836import static oracle .weblogic .kubernetes .TestConstants .MANAGED_SERVER_NAME_BASE ;
1937import static oracle .weblogic .kubernetes .TestConstants .MII_BASIC_IMAGE_NAME ;
2038import 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 ;
2144import static oracle .weblogic .kubernetes .actions .impl .Service .getServiceNodePort ;
45+ import static oracle .weblogic .kubernetes .assertions .TestAssertions .isVoyagerReady ;
2246import static oracle .weblogic .kubernetes .utils .CommonMiiTestUtils .createMiiDomainAndVerify ;
47+ import static oracle .weblogic .kubernetes .utils .CommonTestUtils .createIngressAndRetryIfFail ;
2348import static oracle .weblogic .kubernetes .utils .CommonTestUtils .getExternalServicePodName ;
49+ import static oracle .weblogic .kubernetes .utils .CommonTestUtils .installAndVerifyNginx ;
2450import 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 ;
2553import static oracle .weblogic .kubernetes .utils .CommonTestUtils .installAndVerifyWlsRemoteConsole ;
2654import static oracle .weblogic .kubernetes .utils .CommonTestUtils .shutdownWlsRemoteConsole ;
55+ import static oracle .weblogic .kubernetes .utils .TestUtils .callWebAppAndWaitTillReady ;
2756import static oracle .weblogic .kubernetes .utils .TestUtils .callWebAppAndWaitTillReturnedCode ;
2857import 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 ;
2962import static org .junit .jupiter .api .Assertions .assertNotNull ;
3063import static org .junit .jupiter .api .Assertions .assertTrue ;
3164
3467class 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}, \n stdout: {1}, \n stderr: {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