Skip to content

Commit 00a5a62

Browse files
committed
Merge branch 'vz-sessiontests' into 'main'
Add session migration tests to v8o See merge request weblogic-cloud/weblogic-kubernetes-operator!4460
2 parents 5185daa + b461f12 commit 00a5a62

File tree

5 files changed

+401
-34
lines changed

5 files changed

+401
-34
lines changed
Lines changed: 351 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,351 @@
1+
// Copyright (c) 2023, Oracle and/or its affiliates.
2+
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
3+
4+
package oracle.verrazzano.weblogic.kubernetes;
5+
6+
import java.util.ArrayList;
7+
import java.util.Arrays;
8+
import java.util.Collections;
9+
import java.util.HashMap;
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.Optional;
13+
14+
import io.kubernetes.client.custom.Quantity;
15+
import io.kubernetes.client.openapi.models.V1ObjectMeta;
16+
import io.kubernetes.client.util.Yaml;
17+
import oracle.verrazzano.weblogic.ApplicationConfiguration;
18+
import oracle.verrazzano.weblogic.ApplicationConfigurationSpec;
19+
import oracle.verrazzano.weblogic.Component;
20+
import oracle.verrazzano.weblogic.ComponentSpec;
21+
import oracle.verrazzano.weblogic.Components;
22+
import oracle.verrazzano.weblogic.Destination;
23+
import oracle.verrazzano.weblogic.IngressRule;
24+
import oracle.verrazzano.weblogic.IngressTrait;
25+
import oracle.verrazzano.weblogic.IngressTraitSpec;
26+
import oracle.verrazzano.weblogic.IngressTraits;
27+
import oracle.verrazzano.weblogic.Path;
28+
import oracle.verrazzano.weblogic.Workload;
29+
import oracle.verrazzano.weblogic.WorkloadSpec;
30+
import oracle.verrazzano.weblogic.kubernetes.annotations.VzIntegrationTest;
31+
import oracle.weblogic.domain.DomainResource;
32+
import oracle.weblogic.kubernetes.annotations.Namespaces;
33+
import oracle.weblogic.kubernetes.logging.LoggingFacade;
34+
import org.junit.jupiter.api.BeforeAll;
35+
import org.junit.jupiter.api.DisplayName;
36+
import org.junit.jupiter.api.Tag;
37+
import org.junit.jupiter.api.Test;
38+
39+
import static oracle.weblogic.kubernetes.TestConstants.ADMIN_PASSWORD_DEFAULT;
40+
import static oracle.weblogic.kubernetes.TestConstants.ADMIN_SERVER_NAME_BASE;
41+
import static oracle.weblogic.kubernetes.TestConstants.ADMIN_USERNAME_DEFAULT;
42+
import static oracle.weblogic.kubernetes.TestConstants.MANAGED_SERVER_NAME_BASE;
43+
import static oracle.weblogic.kubernetes.TestConstants.TEST_IMAGES_REPO_SECRET_NAME;
44+
import static oracle.weblogic.kubernetes.actions.impl.primitive.Kubernetes.createApplication;
45+
import static oracle.weblogic.kubernetes.actions.impl.primitive.Kubernetes.createComponent;
46+
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.checkPodReadyAndServiceExists;
47+
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.generateNewModelFileWithUpdatedDomainUid;
48+
import static oracle.weblogic.kubernetes.utils.ConfigMapUtils.createConfigMapAndVerify;
49+
import static oracle.weblogic.kubernetes.utils.ImageUtils.createMiiImageAndVerify;
50+
import static oracle.weblogic.kubernetes.utils.ImageUtils.createTestRepoSecret;
51+
import static oracle.weblogic.kubernetes.utils.ImageUtils.imageRepoLoginAndPushImageToRegistry;
52+
import static oracle.weblogic.kubernetes.utils.IstioUtils.createIstioDomainResource;
53+
import static oracle.weblogic.kubernetes.utils.SecretUtils.createSecretWithUsernamePassword;
54+
import static oracle.weblogic.kubernetes.utils.SessionMigrationUtil.getOrigModelFile;
55+
import static oracle.weblogic.kubernetes.utils.SessionMigrationUtil.getServerAndSessionInfoAndVerify;
56+
import static oracle.weblogic.kubernetes.utils.SessionMigrationUtil.shutdownServerAndVerify;
57+
import static oracle.weblogic.kubernetes.utils.ThreadSafeLogger.getLogger;
58+
import static oracle.weblogic.kubernetes.utils.VerrazzanoUtils.getIstioHost;
59+
import static oracle.weblogic.kubernetes.utils.VerrazzanoUtils.getLoadbalancerAddress;
60+
import static oracle.weblogic.kubernetes.utils.VerrazzanoUtils.setLabelToNamespace;
61+
import static oracle.weblogic.kubernetes.utils.VerrazzanoUtils.verifyVzApplicationAccess;
62+
import static org.junit.jupiter.api.Assertions.assertAll;
63+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
64+
import static org.junit.jupiter.api.Assertions.assertEquals;
65+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
66+
import static org.junit.jupiter.api.Assertions.assertNotNull;
67+
import static org.junit.jupiter.api.Assertions.assertTrue;
68+
69+
@DisplayName("Test WLS Session Migration when istio is enabled")
70+
@VzIntegrationTest
71+
@Tag("v8o")
72+
class ItVzIstioSessionMigration {
73+
74+
private static String domainNamespace = null;
75+
76+
// constants for creating domain image using model in image
77+
private static final String SESSMIGR_IMAGE_NAME = "istio-sessmigr-mii-image";
78+
79+
// constants for web service
80+
private static final String SESSMIGR_APP_NAME = "sessmigr-app";
81+
private static final String SESSMIGR_APP_WAR_NAME = "sessmigr-war";
82+
private static final int SESSION_STATE = 4;
83+
private static Map<String, String> httpAttrMap;
84+
85+
// constants for operator and WebLogic domain
86+
private static String domainUid = "istio-sessmigr-domain";
87+
private static String clusterName = "cluster-1";
88+
private static String adminServerPodName = domainUid + "-" + ADMIN_SERVER_NAME_BASE;
89+
private static String managedServerPrefix = domainUid + "-" + MANAGED_SERVER_NAME_BASE;
90+
private static int managedServerPort = 7100;
91+
private static String finalPrimaryServerName = null;
92+
private static String configMapName = "istio-configmap";
93+
private static int replicaCount = 2;
94+
private static DomainResource domain;
95+
96+
97+
private static LoggingFacade logger = null;
98+
99+
private static Map<String, Quantity> resourceRequest = new HashMap<>();
100+
private static Map<String, Quantity> resourceLimit = new HashMap<>();
101+
102+
/**
103+
* Build custom image using model in image with model files
104+
* and create a verrazzano application with a dynamic cluster.
105+
*
106+
* @param namespaces list of namespaces created by the IntegrationTestWatcher by the
107+
* JUnit engine parameter resolution mechanism
108+
*/
109+
@BeforeAll
110+
public static void initAll(@Namespaces(1) List<String> namespaces) {
111+
logger = getLogger();
112+
113+
logger.info("Assign unique namespace for Domain");
114+
assertNotNull(namespaces.get(0), "Namespace list is null");
115+
domainNamespace = namespaces.get(0);
116+
assertDoesNotThrow(() -> setLabelToNamespace(Arrays.asList(domainNamespace)));
117+
118+
// Generate the model.sessmigr.yaml file at RESULTS_ROOT
119+
String destSessionMigrYamlFile =
120+
generateNewModelFileWithUpdatedDomainUid(domainUid, "ItVzIstioSessionMigration", getOrigModelFile());
121+
122+
List<String> appList = new ArrayList<>();
123+
appList.add(SESSMIGR_APP_NAME);
124+
125+
// build the model file list
126+
final List<String> modelList = Collections.singletonList(destSessionMigrYamlFile);
127+
128+
// create image with model files
129+
logger.info("Create image with model file and verify");
130+
String miiImage = createMiiImageAndVerify(SESSMIGR_IMAGE_NAME, modelList, appList);
131+
132+
// repo login and push image to registry if necessary
133+
imageRepoLoginAndPushImageToRegistry(miiImage);
134+
135+
// set resource request and limit
136+
resourceRequest.put("cpu", new Quantity("250m"));
137+
resourceRequest.put("memory", new Quantity("768Mi"));
138+
resourceLimit.put("cpu", new Quantity("2"));
139+
resourceLimit.put("memory", new Quantity("2Gi"));
140+
141+
// create secret for admin credentials
142+
logger.info("Create secret for admin credentials");
143+
String adminSecretName = "weblogic-credentials";
144+
assertDoesNotThrow(() -> createSecretWithUsernamePassword(
145+
adminSecretName,
146+
domainNamespace,
147+
ADMIN_USERNAME_DEFAULT,
148+
ADMIN_PASSWORD_DEFAULT),
149+
String.format("createSecret failed for %s", adminSecretName));
150+
151+
// create encryption secret
152+
logger.info("Create encryption secret");
153+
String encryptionSecretName = "encryptionsecret";
154+
assertDoesNotThrow(() -> createSecretWithUsernamePassword(
155+
encryptionSecretName,
156+
domainNamespace,
157+
"weblogicenc",
158+
"weblogicenc"),
159+
String.format("createSecret failed for %s", encryptionSecretName));
160+
161+
domain = createDomainCrAndVerify(adminSecretName, encryptionSecretName, miiImage);
162+
createVzApplication();
163+
164+
// map to save HTTP response data
165+
httpAttrMap = new HashMap<String, String>();
166+
httpAttrMap.put("sessioncreatetime", "(.*)sessioncreatetime>(.*)</sessioncreatetime(.*)");
167+
httpAttrMap.put("sessionid", "(.*)sessionid>(.*)</sessionid(.*)");
168+
httpAttrMap.put("primary", "(.*)primary>(.*)</primary(.*)");
169+
httpAttrMap.put("secondary", "(.*)secondary>(.*)</secondary(.*)");
170+
httpAttrMap.put("count", "(.*)countattribute>(.*)</countattribute(.*)");
171+
}
172+
173+
/**
174+
* In an istio enabled Environment, test sends a HTTP request to set http session state(count number),
175+
* get the primary and secondary server name, session create time and session state and from the util method
176+
* and save HTTP session info, then stop the primary server by changing ServerStartPolicy to Never and
177+
* patching domain. Send another HTTP request to get http session state (count number), primary server
178+
* and session create time. Verify that a new primary server is selected and HTTP session state is migrated.
179+
*/
180+
@Test
181+
@DisplayName("Verify session migration in an istio enabled environment")
182+
void testSessionMigrationIstioEnabled() {
183+
final String primaryServerAttr = "primary";
184+
final String secondaryServerAttr = "secondary";
185+
final String sessionCreateTimeAttr = "sessioncreatetime";
186+
final String countAttr = "count";
187+
final String webServiceSetUrl = SESSMIGR_APP_WAR_NAME + "/?setCounter=" + SESSION_STATE;
188+
final String webServiceGetUrl = SESSMIGR_APP_WAR_NAME + "/?getCounter";
189+
final String clusterAddress = domainUid + "-cluster-" + clusterName;
190+
String serverName = managedServerPrefix + "1";
191+
192+
// send a HTTP request to set http session state(count number) and save HTTP session info
193+
// before shutting down the primary server
194+
Map<String, String> httpDataInfo = getServerAndSessionInfoAndVerify(domainNamespace,
195+
adminServerPodName, serverName, clusterAddress, managedServerPort, webServiceSetUrl, " -c ");
196+
197+
// get server and session info from web service deployed on the cluster
198+
String origPrimaryServerName = httpDataInfo.get(primaryServerAttr);
199+
String origSecondaryServerName = httpDataInfo.get(secondaryServerAttr);
200+
String origSessionCreateTime = httpDataInfo.get(sessionCreateTimeAttr);
201+
logger.info("Got the primary server {0}, the secondary server {1} "
202+
+ "and session create time {2} before shutting down the primary server.",
203+
origPrimaryServerName, origSecondaryServerName, origSessionCreateTime);
204+
205+
// stop the primary server by changing ServerStartPolicy to Never and patching domain
206+
logger.info("Shut down the primary server {0}", origPrimaryServerName);
207+
shutdownServerAndVerify(domainUid, domainNamespace, origPrimaryServerName);
208+
209+
// send a HTTP request to get server and session info after shutting down the primary server
210+
serverName = domainUid + "-" + origSecondaryServerName;
211+
httpDataInfo = getServerAndSessionInfoAndVerify(domainNamespace, adminServerPodName,
212+
serverName, clusterAddress, managedServerPort, webServiceGetUrl, " -b ");
213+
214+
// get server and session info from web service deployed on the cluster
215+
String primaryServerName = httpDataInfo.get(primaryServerAttr);
216+
String sessionCreateTime = httpDataInfo.get(sessionCreateTimeAttr);
217+
String countStr = httpDataInfo.get(countAttr);
218+
int count;
219+
if (countStr.equalsIgnoreCase("null")) {
220+
count = managedServerPort;
221+
} else {
222+
count = Optional.ofNullable(countStr).map(Integer::valueOf).orElse(managedServerPort);
223+
}
224+
logger.info("After patching the domain, the primary server changes to {0} "
225+
+ ", session create time {1} and session state {2}",
226+
primaryServerName, sessionCreateTime, countStr);
227+
228+
// verify that a new primary server is picked and HTTP session state is migrated
229+
assertAll("Check that WebLogic server and session vars is not null or empty",
230+
() -> assertNotEquals(origPrimaryServerName, primaryServerName,
231+
"After the primary server stopped, another server should become the new primary server"),
232+
() -> assertEquals(origSessionCreateTime, sessionCreateTime,
233+
"After the primary server stopped, HTTP session state should be migrated to the new primary server"),
234+
() -> assertEquals(SESSION_STATE, count,
235+
"After the primary server stopped, HTTP session state should be migrated to the new primary server")
236+
);
237+
238+
finalPrimaryServerName = primaryServerName;
239+
240+
logger.info("Done testSessionMigration \nThe new primary server is {0}, it was {1}. "
241+
+ "\nThe session state was set to {2}, it is migrated to the new primary server.",
242+
primaryServerName, origPrimaryServerName, SESSION_STATE);
243+
}
244+
245+
private static void createVzApplication() {
246+
247+
Component component = new Component()
248+
.apiVersion("core.oam.dev/v1alpha2")
249+
.kind("Component")
250+
.metadata(new V1ObjectMeta()
251+
.name(domainUid)
252+
.namespace(domainNamespace))
253+
.spec(new ComponentSpec()
254+
.workLoad(new Workload()
255+
.apiVersion("oam.verrazzano.io/v1alpha1")
256+
.kind("VerrazzanoWebLogicWorkload")
257+
.spec(new WorkloadSpec()
258+
.template(domain))));
259+
260+
Map<String, String> keyValueMap = new HashMap<>();
261+
keyValueMap.put("version", "v1.0.0");
262+
keyValueMap.put("description", "My vz wls application");
263+
264+
ApplicationConfiguration application = new ApplicationConfiguration()
265+
.apiVersion("core.oam.dev/v1alpha2")
266+
.kind("ApplicationConfiguration")
267+
.metadata(new V1ObjectMeta()
268+
.name("myvzsessiondomain")
269+
.namespace(domainNamespace)
270+
.annotations(keyValueMap))
271+
.spec(new ApplicationConfigurationSpec()
272+
.components(Arrays.asList(new Components()
273+
.componentName(domainUid)
274+
.traits(Arrays.asList(new IngressTraits()
275+
.trait(new IngressTrait()
276+
.apiVersion("oam.verrazzano.io/v1alpha1")
277+
.kind("IngressTrait")
278+
.metadata(new V1ObjectMeta()
279+
.name("mydomain-ingress")
280+
.namespace(domainNamespace))
281+
.spec(new IngressTraitSpec()
282+
.ingressRules(Arrays.asList(
283+
new IngressRule()
284+
.paths(Arrays.asList(new Path()
285+
.path("/console")
286+
.pathType("Prefix")))
287+
.destination(new Destination()
288+
.host(adminServerPodName)
289+
.port(7001)),
290+
new IngressRule()
291+
.paths(Arrays.asList(new Path()
292+
.path("/sessmigr-app")
293+
.pathType("Prefix")))
294+
.destination(new Destination()
295+
.host(domainUid + "-cluster-" + clusterName)
296+
.port(managedServerPort)))))))))));
297+
298+
logger.info(Yaml.dump(component));
299+
logger.info(Yaml.dump(application));
300+
301+
logger.info("Deploying components");
302+
assertDoesNotThrow(() -> createComponent(component));
303+
logger.info("Deploying application");
304+
assertDoesNotThrow(() -> createApplication(application));
305+
306+
// check admin server pod is ready
307+
logger.info("Wait for admin server pod {0} to be ready in namespace {1}",
308+
adminServerPodName, domainNamespace);
309+
checkPodReadyAndServiceExists(adminServerPodName, domainUid, domainNamespace);
310+
// check managed server pods are ready
311+
for (int i = 1; i <= replicaCount; i++) {
312+
logger.info("Wait for managed server pod {0} to be ready in namespace {1}",
313+
managedServerPrefix + i, domainNamespace);
314+
checkPodReadyAndServiceExists(managedServerPrefix + i, domainUid, domainNamespace);
315+
}
316+
317+
// get istio gateway host and loadbalancer address
318+
String host = getIstioHost(domainNamespace);
319+
String address = getLoadbalancerAddress();
320+
321+
// verify WebLogic console page is accessible through istio/loadbalancer
322+
String message = "Oracle WebLogic Server Administration Console";
323+
String consoleUrl = "https://" + host + "/console/login/LoginForm.jsp --resolve " + host + ":443:" + address;
324+
assertTrue(verifyVzApplicationAccess(consoleUrl, message), "Failed to get WebLogic administration console");
325+
}
326+
327+
private static DomainResource createDomainCrAndVerify(String adminSecretName,
328+
String encryptionSecretName,
329+
String miiImage) {
330+
331+
// Create the repo secret to pull the image
332+
// this secret is used only for non-kind cluster
333+
createTestRepoSecret(domainNamespace);
334+
335+
// create WDT config map without any files
336+
createConfigMapAndVerify(configMapName, domainUid, domainNamespace, Collections.emptyList());
337+
338+
// create the domain object
339+
DomainResource domain = createIstioDomainResource(domainUid,
340+
domainNamespace,
341+
adminSecretName,
342+
TEST_IMAGES_REPO_SECRET_NAME,
343+
encryptionSecretName,
344+
replicaCount,
345+
miiImage,
346+
configMapName,
347+
clusterName);
348+
return domain;
349+
}
350+
351+
}

0 commit comments

Comments
 (0)