diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItMiiConfigMap.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItMiiConfigMap.java index 9c68bc79d2f..c8bd8f3aedd 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItMiiConfigMap.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItMiiConfigMap.java @@ -16,7 +16,6 @@ import io.kubernetes.client.openapi.models.V1EnvVar; import io.kubernetes.client.openapi.models.V1LocalObjectReference; import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.openapi.models.V1Pod; import io.kubernetes.client.openapi.models.V1Secret; import io.kubernetes.client.openapi.models.V1SecretReference; import io.kubernetes.client.openapi.models.V1ServiceAccount; @@ -497,21 +496,14 @@ private void checkServiceCreated(String serviceName, String domNamespace) { } private void checkServerReadyStatusByExec(String podName, String namespace) { - final V1Pod pod = assertDoesNotThrow(() -> oracle.weblogic.kubernetes.assertions.impl.Kubernetes - .getPod(namespace, null, podName)); - - if (pod != null) { - ExecResult execResult = assertDoesNotThrow( - () -> execCommand(pod, null, true, READ_STATE_COMMAND)); - if (execResult.exitValue() == 0) { - logger.info("execResult: " + execResult); - assertEquals("RUNNING", execResult.stdout(), - "Expected " + podName + ", in namespace " + namespace + ", to be in RUNNING ready status"); - } else { - fail("Ready command failed with exit status code: " + execResult.exitValue()); - } + ExecResult execResult = assertDoesNotThrow( + () -> execCommand(namespace, podName, null, true, READ_STATE_COMMAND)); + if (execResult.exitValue() == 0) { + logger.info("execResult: " + execResult); + assertEquals("RUNNING", execResult.stdout(), + "Expected " + podName + ", in namespace " + namespace + ", to be in RUNNING ready status"); } else { - fail("Did not find pod " + podName + " in namespace " + namespace); + fail("Ready command failed with exit status code: " + execResult.exitValue()); } } diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItMiiConfigMapOverride.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItMiiConfigMapOverride.java index e01f0b2b709..4f5eb381ac1 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItMiiConfigMapOverride.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItMiiConfigMapOverride.java @@ -18,7 +18,6 @@ import io.kubernetes.client.openapi.models.V1EnvVar; import io.kubernetes.client.openapi.models.V1LocalObjectReference; import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.openapi.models.V1Pod; import io.kubernetes.client.openapi.models.V1Secret; import io.kubernetes.client.openapi.models.V1SecretReference; import io.kubernetes.client.openapi.models.V1ServiceAccount; @@ -566,21 +565,14 @@ private void checkServiceCreated(String serviceName, String domNamespace) { } private void checkServerReadyStatusByExec(String podName, String namespace) { - final V1Pod pod = assertDoesNotThrow(() -> oracle.weblogic.kubernetes.assertions.impl.Kubernetes - .getPod(namespace, null, podName)); - - if (pod != null) { - ExecResult execResult = assertDoesNotThrow( - () -> execCommand(pod, null, true, READ_STATE_COMMAND)); - if (execResult.exitValue() == 0) { - logger.info("execResult: " + execResult); - assertEquals("RUNNING", execResult.stdout(), - "Expected " + podName + ", in namespace " + namespace + ", to be in RUNNING ready status"); - } else { - fail("Ready command failed with exit status code: " + execResult.exitValue()); - } + ExecResult execResult = assertDoesNotThrow( + () -> execCommand(namespace, podName, null, true, READ_STATE_COMMAND)); + if (execResult.exitValue() == 0) { + logger.info("execResult: " + execResult); + assertEquals("RUNNING", execResult.stdout(), + "Expected " + podName + ", in namespace " + namespace + ", to be in RUNNING ready status"); } else { - fail("Did not find pod " + podName + " in namespace " + namespace); + fail("Ready command failed with exit status code: " + execResult.exitValue()); } } diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItMiiDomain.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItMiiDomain.java index c3c1026de22..17932c762ce 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItMiiDomain.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItMiiDomain.java @@ -3,17 +3,23 @@ package oracle.weblogic.kubernetes; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; import com.google.gson.JsonObject; +import io.kubernetes.client.custom.V1Patch; import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.models.V1EnvVar; import io.kubernetes.client.openapi.models.V1LocalObjectReference; import io.kubernetes.client.openapi.models.V1ObjectMeta; -import io.kubernetes.client.openapi.models.V1Pod; import io.kubernetes.client.openapi.models.V1Secret; import io.kubernetes.client.openapi.models.V1SecretReference; import io.kubernetes.client.openapi.models.V1ServiceAccount; @@ -47,30 +53,58 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static oracle.weblogic.kubernetes.TestConstants.DOMAIN_API_VERSION; import static oracle.weblogic.kubernetes.TestConstants.DOMAIN_VERSION; +import static oracle.weblogic.kubernetes.TestConstants.MII_APP_RESPONSE_V1; +import static oracle.weblogic.kubernetes.TestConstants.MII_APP_RESPONSE_V2; +import static oracle.weblogic.kubernetes.TestConstants.MII_APP_RESPONSE_V3; +import static oracle.weblogic.kubernetes.TestConstants.MII_BASIC_APP_NAME; import static oracle.weblogic.kubernetes.TestConstants.MII_BASIC_IMAGE_NAME; import static oracle.weblogic.kubernetes.TestConstants.MII_BASIC_IMAGE_TAG; +import static oracle.weblogic.kubernetes.TestConstants.MII_BASIC_WDT_MODEL_FILE; +import static oracle.weblogic.kubernetes.TestConstants.MII_TWO_APP_WDT_MODEL_FILE; import static oracle.weblogic.kubernetes.TestConstants.OPERATOR_CHART_DIR; import static oracle.weblogic.kubernetes.TestConstants.OPERATOR_RELEASE_NAME; +import static oracle.weblogic.kubernetes.TestConstants.READ_STATE_COMMAND; +import static oracle.weblogic.kubernetes.TestConstants.REPO_DUMMY_VALUE; import static oracle.weblogic.kubernetes.TestConstants.REPO_EMAIL; +import static oracle.weblogic.kubernetes.TestConstants.REPO_NAME; import static oracle.weblogic.kubernetes.TestConstants.REPO_PASSWORD; import static oracle.weblogic.kubernetes.TestConstants.REPO_REGISTRY; import static oracle.weblogic.kubernetes.TestConstants.REPO_SECRET_NAME; import static oracle.weblogic.kubernetes.TestConstants.REPO_USERNAME; +import static oracle.weblogic.kubernetes.actions.ActionConstants.ARCHIVE_DIR; +import static oracle.weblogic.kubernetes.actions.ActionConstants.MODEL_DIR; +import static oracle.weblogic.kubernetes.actions.ActionConstants.WDT_VERSION; +import static oracle.weblogic.kubernetes.actions.ActionConstants.WIT_BUILD_DIR; +import static oracle.weblogic.kubernetes.actions.TestActions.buildAppArchive; import static oracle.weblogic.kubernetes.actions.TestActions.createDockerConfigJson; import static oracle.weblogic.kubernetes.actions.TestActions.createDomainCustomResource; +import static oracle.weblogic.kubernetes.actions.TestActions.createMiiImage; import static oracle.weblogic.kubernetes.actions.TestActions.createSecret; import static oracle.weblogic.kubernetes.actions.TestActions.createServiceAccount; +import static oracle.weblogic.kubernetes.actions.TestActions.defaultAppParams; +import static oracle.weblogic.kubernetes.actions.TestActions.defaultWitParams; import static oracle.weblogic.kubernetes.actions.TestActions.deleteDomainCustomResource; +import static oracle.weblogic.kubernetes.actions.TestActions.deleteImage; +import static oracle.weblogic.kubernetes.actions.TestActions.dockerLogin; +import static oracle.weblogic.kubernetes.actions.TestActions.dockerPush; import static oracle.weblogic.kubernetes.actions.TestActions.execCommand; import static oracle.weblogic.kubernetes.actions.TestActions.getOperatorImageName; import static oracle.weblogic.kubernetes.actions.TestActions.installOperator; +import static oracle.weblogic.kubernetes.actions.TestActions.patchDomainCustomResource; import static oracle.weblogic.kubernetes.actions.TestActions.upgradeOperator; +import static oracle.weblogic.kubernetes.assertions.TestAssertions.appAccessibleInPod; +import static oracle.weblogic.kubernetes.assertions.TestAssertions.appAccessibleInPodKubectl; +import static oracle.weblogic.kubernetes.assertions.TestAssertions.appNotAccessibleInPod; +import static oracle.weblogic.kubernetes.assertions.TestAssertions.doesImageExist; import static oracle.weblogic.kubernetes.assertions.TestAssertions.domainExists; +import static oracle.weblogic.kubernetes.assertions.TestAssertions.domainResourceImagePatched; import static oracle.weblogic.kubernetes.assertions.TestAssertions.isHelmReleaseDeployed; import static oracle.weblogic.kubernetes.assertions.TestAssertions.operatorIsReady; import static oracle.weblogic.kubernetes.assertions.TestAssertions.podExists; +import static oracle.weblogic.kubernetes.assertions.TestAssertions.podImagePatched; import static oracle.weblogic.kubernetes.assertions.TestAssertions.podReady; import static oracle.weblogic.kubernetes.assertions.TestAssertions.serviceExists; +import static oracle.weblogic.kubernetes.utils.FileUtils.checkDirectory; import static org.awaitility.Awaitility.with; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -85,8 +119,6 @@ @IntegrationTest class ItMiiDomain implements LoggedTest { - private static final String READ_STATE_COMMAND = "/weblogic-operator/scripts/readState.sh"; - private static HelmParams opHelmParams = null; private static V1ServiceAccount serviceAccount = null; private String serviceAccountName = null; @@ -96,10 +128,13 @@ class ItMiiDomain implements LoggedTest { private static String domainNamespace1 = null; private static String domainNamespace2 = null; private static ConditionFactory withStandardRetryPolicy = null; + private static ConditionFactory withQuickRetryPolicy = null; private static String dockerConfigJson = ""; private String domainUid = "domain1"; private String domainUid1 = "domain2"; + private String miiImagePatchAppV2 = null; + private String miiImageAddSecondApp = null; private static Map secretNameMap; @@ -113,7 +148,12 @@ public static void initAll(@Namespaces(3) List namespaces) { // create standard, reusable retry/backoff policy withStandardRetryPolicy = with().pollDelay(2, SECONDS) .and().with().pollInterval(10, SECONDS) - .atMost(5, MINUTES).await(); + .atMost(6, MINUTES).await(); + + // create a reusable quick retry policy + withQuickRetryPolicy = with().pollDelay(0, SECONDS) + .and().with().pollInterval(4, SECONDS) + .atMost(10, SECONDS).await(); // get a new unique opNamespace logger.info("Creating unique namespace for Operator"); @@ -213,7 +253,7 @@ public static void initAll(@Namespaces(3) List namespaces) { @Slow @MustNotRunInParallel public void testCreateMiiDomain() { - // admin/managed server name here should match with model yaml in WDT_MODEL_FILE + // admin/managed server name here should match with model yaml in MII_BASIC_WDT_MODEL_FILE final String adminServerPodName = domainUid + "-admin-server"; final String managedServerPrefix = domainUid + "-managed-server"; final int replicaCount = 2; @@ -290,7 +330,19 @@ public void testCreateMiiDomain() { managedServerPrefix + i, domainNamespace); checkServiceCreated(managedServerPrefix + i, domainNamespace); } - + + // check and wait for the application to be accessible in all server pods + for (int i = 1; i <= replicaCount; i++) { + checkAppRunning( + domainNamespace, + managedServerPrefix + i, + "8001", + "sample-war/index.jsp", + MII_APP_RESPONSE_V1 + i); + } + + logger.info("Domain {0} is fully started - servers are running and application is available", + domainUid); } @Test @@ -299,7 +351,7 @@ public void testCreateMiiDomain() { @Slow @MustNotRunInParallel public void testCreateMiiSecondDomainDiffNSSameImage() { - // admin/managed server name here should match with model yaml in WDT_MODEL_FILE + // admin/managed server name here should match with model yaml in MII_BASIC_WDT_MODEL_FILE final String adminServerPodName = domainUid1 + "-admin-server"; final String managedServerPrefix = domainUid1 + "-managed-server"; final int replicaCount = 2; @@ -397,7 +449,7 @@ public void testCreateMiiSecondDomainDiffNSSameImage() { @Slow @MustNotRunInParallel public void testCreateMiiDomainSameDomainUidDiffNS() { - // admin/managed server name here should match with model yaml in WDT_MODEL_FILE + // admin/managed server name here should match with model yaml in MII_BASIC_WDT_MODEL_FILE final String adminServerPodName = domainUid + "-admin-server"; final String managedServerPrefix = domainUid + "-managed-server"; final int replicaCount = 2; @@ -473,12 +525,204 @@ public void testCreateMiiDomainSameDomainUidDiffNS() { } } + @Test + @Order(4) + @DisplayName("Update the sample-app application to version 2") + @Slow + @MustNotRunInParallel + public void testPatchAppV2() { + + // application in the new image contains what is in the original application directory sample-app, + // plus the replacements or/and additions in the second application directory sample-app-2. + final String appDir1 = "sample-app"; + final String appDir2 = "sample-app-2"; + final String adminServerPodName = domainUid + "-admin-server"; + final String managedServerPrefix = domainUid + "-managed-server"; + final int replicaCount = 2; + + // The verification of application's availability during patching is turned off + // because it fails intermittently right now. It can be enabled using the following system property. + // We'll remove the property and enable it all the time once the product problem (tracked + // by owls-81575) is fixed. + final String enableAppAvailbilityCheck = + System.getProperty("weblogic.operator.enableAppAvailabilityCheck", "false"); + Thread accountingThread = null; + List appAvailability = new ArrayList(); + + if (enableAppAvailbilityCheck.equalsIgnoreCase("true")) { + logger.info("Start a thread to keep track of the application's availability"); + // start a new thread to collect the availability data of the application while the + // main thread performs patching operation, and checking of the results. + accountingThread = + new Thread( + () -> { + collectAppAvaiability( + domainNamespace, + appAvailability, + managedServerPrefix, + replicaCount, + "8001", + "sample-war/index.jsp"); + }); + accountingThread.start(); + } + + try { + logger.info("Check that V1 application is still running"); + for (int i = 1; i <= replicaCount; i++) { + quickCheckAppRunning( + domainNamespace, + managedServerPrefix + i, + "8001", + "sample-war/index.jsp", + MII_APP_RESPONSE_V1 + i); + } + + logger.info("Check that the version 2 application is NOT running"); + for (int i = 1; i <= replicaCount; i++) { + quickCheckAppNotRunning( + domainNamespace, + managedServerPrefix + i, + "8001", + "sample-war/index.jsp", + MII_APP_RESPONSE_V2 + i); + } + + logger.info("Create a new image with application V2"); + miiImagePatchAppV2 = updateImageWithAppV2Patch( + String.format("%s-%s", MII_BASIC_IMAGE_NAME, "test-patch-app-v2"), + Arrays.asList(appDir1, appDir2)); + + // push the image to a registry to make the test work in multi node cluster + pushImageIfNeeded(miiImagePatchAppV2); + + // patch the domain resource with the new image and verify that the domain resource is patched, + // and all server pods are patched as well. + logger.info("Patch domain resource with image {0}, and verify the results", miiImagePatchAppV2); + patchAndVerify( + domainUid, + domainNamespace, + adminServerPodName, + managedServerPrefix, + replicaCount, + miiImagePatchAppV2); + + logger.info("Check and wait for the V2 application to become available"); + for (int i = 1; i <= replicaCount; i++) { + checkAppRunning( + domainNamespace, + managedServerPrefix + i, + "8001", + "sample-war/index.jsp", + MII_APP_RESPONSE_V2 + i); + } + } finally { + + if (accountingThread != null) { + try { + accountingThread.join(); + } catch (InterruptedException ie) { + // do nothing + } + + // check the application availability data that we have collected, and see if + // the application has been available all the time since the beginning of this test method + logger.info("Verify that V2 application was available when domain {0} was being patched with image {1}", + domainUid, miiImagePatchAppV2); + assertTrue(appAlwaysAvailable(appAvailability), + String.format("Application V2 was not always available when domain %s was being patched with image %s", + domainUid, miiImagePatchAppV2)); + } + } + + logger.info("The version 2 application has been deployed correctly on all server pods"); + } + + @Test + @Order(5) + @DisplayName("Update the domain with another application") + @Slow + @MustNotRunInParallel + public void testAddSecondApp() { + + // the existing application is the combination of what are in appDir1 and appDir2 as in test case number 4, + // the second application is in appDir3. + final String appDir1 = "sample-app"; + final String appDir2 = "sample-app-2"; + final String appDir3 = "sample-app-3"; + final String adminServerPodName = domainUid + "-admin-server"; + final String managedServerPrefix = domainUid + "-managed-server"; + final int replicaCount = 2; + + logger.info("Check that V2 application is still running after the previous test"); + for (int i = 1; i <= replicaCount; i++) { + quickCheckAppRunning( + domainNamespace, + managedServerPrefix + i, + "8001", + "sample-war/index.jsp", + MII_APP_RESPONSE_V2 + i); + } + + logger.info("Check that the new application is NOT already running"); + for (int i = 1; i <= replicaCount; i++) { + quickCheckAppNotRunning( + domainNamespace, + managedServerPrefix + i, + "8001", + "sample-war-3/index.jsp", + MII_APP_RESPONSE_V3 + i); + } + + logger.info("Create a new image that contains the additional application"); + miiImageAddSecondApp = updateImageWithSampleApp3( + String.format("%s-%s", MII_BASIC_IMAGE_NAME, "test-add-second-app"), + Arrays.asList(appDir1, appDir2), + Collections.singletonList(appDir3), + MII_TWO_APP_WDT_MODEL_FILE); + + // push the image to a registry to make the test work in multi node cluster + pushImageIfNeeded(miiImageAddSecondApp); + + // patch the domain resource with the new image and verify that the domain resource is patched, + // and all server pods are patched as well. + logger.info("Patch the domain with image {0}, and verify the results", miiImageAddSecondApp); + patchAndVerify( + domainUid, + domainNamespace, + adminServerPodName, + managedServerPrefix, + replicaCount, + miiImageAddSecondApp); + + logger.info("Check and wait for the new application to become ready"); + for (int i = 1; i <= replicaCount; i++) { + checkAppRunning( + domainNamespace, + managedServerPrefix + i, + "8001", + "sample-war-3/index.jsp", + MII_APP_RESPONSE_V3 + i); + } + + logger.info("Check and wait for the original application V2 to become ready"); + for (int i = 1; i <= replicaCount; i++) { + checkAppRunning( + domainNamespace, + managedServerPrefix + i, + "8001", + "sample-war/index.jsp", + MII_APP_RESPONSE_V2 + i); + } + + logger.info("Both of the applications are running correctly after patching"); + } // This method is needed in this test class, since the cleanup util // won't cleanup the images. - @AfterAll - void tearDown() { + @AfterAll + public void tearDownAll() { // Delete domain custom resource logger.info("Delete domain custom resource in namespace {0}", domainNamespace); assertDoesNotThrow(() -> deleteDomainCustomResource(domainUid, domainNamespace), @@ -494,6 +738,187 @@ void tearDown() { assertDoesNotThrow(() -> deleteDomainCustomResource(domainUid, domainNamespace1), "deleteDomainCustomResource failed with ApiException"); logger.info("Deleted Domain Custom Resource " + domainUid + " from " + domainNamespace1); + + // delete the domain images created in the test class + if (miiImagePatchAppV2 != null) { + deleteImage(miiImagePatchAppV2); + } + if (miiImageAddSecondApp != null) { + deleteImage(miiImageAddSecondApp); + } + } + + private void pushImageIfNeeded(String image) { + // push the image to a registry to make the test work in multi node cluster + if (!REPO_USERNAME.equals(REPO_DUMMY_VALUE)) { + logger.info("docker login to registry {0}", REPO_REGISTRY); + assertTrue(dockerLogin(REPO_REGISTRY, REPO_USERNAME, REPO_PASSWORD), "docker login failed"); + } + + // push image + if (!REPO_NAME.isEmpty()) { + logger.info("docker push image {0} to registry", image); + assertTrue(dockerPush(image), String.format("docker push failed for image %s", image)); + } + } + + private String createUniqueImageTag() { + // create unique image name with date + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + Date date = new Date(); + return dateFormat.format(date) + "-" + System.currentTimeMillis(); + } + + private String updateImageWithAppV2Patch( + String imageName, + List appDirList + ) { + logger.info("Build the model file list that contains {0}", MII_BASIC_WDT_MODEL_FILE); + List modelList = + Collections.singletonList(String.format("%s/%s", MODEL_DIR, MII_BASIC_WDT_MODEL_FILE)); + + logger.info("Build an application archive using what is in {0}", appDirList); + assertTrue( + buildAppArchive( + defaultAppParams() + .srcDirList(appDirList)), + String.format("Failed to create application archive for %s", + MII_BASIC_APP_NAME)); + + logger.info("Build the archive list that contains {0}", + String.format("%s/%s.zip", ARCHIVE_DIR, MII_BASIC_APP_NAME)); + List archiveList = + Collections.singletonList( + String.format("%s/%s.zip", ARCHIVE_DIR, MII_BASIC_APP_NAME)); + + return createImageAndVerify( + imageName, + createUniqueImageTag(), + modelList, + archiveList); + } + + private String updateImageWithSampleApp3( + String imageName, + List appDirList1, + List appDirList2, + String modelFile + ) { + logger.info("Build the model file list that contains {0}", modelFile); + List modelList = Collections.singletonList(MODEL_DIR + "/" + modelFile); + + String appName1 = appDirList1.get(0); + String appName2 = appDirList2.get(0); + + logger.info("Build the first application archive using what is in {0}", appDirList1); + assertTrue( + buildAppArchive( + defaultAppParams() + .srcDirList(appDirList1) + .appName(appName1)), + String.format("Failed to create application archive for %s", + appName1)); + + logger.info("Build the second application archive usingt what is in {0}", appDirList2); + assertTrue( + buildAppArchive( + defaultAppParams() + .srcDirList(appDirList2) + .appName(appName2)), + String.format("Failed to create application archive for %s", + appName2)); + + logger.info("Build the archive list with two zip files: {0} and {1}", + String.format("%s/%s.zip", ARCHIVE_DIR, appName1), + String.format("%s/%s.zip", ARCHIVE_DIR, appName2)); + List archiveList = Arrays.asList( + String.format("%s/%s.zip", ARCHIVE_DIR, appName1), + String.format("%s/%s.zip", ARCHIVE_DIR, appName2)); + + return createImageAndVerify( + imageName, + createUniqueImageTag(), + modelList, + archiveList); + } + + /** + * Patch the domain resource with a new image. + * Here is an example of the JSON patch string that is constructed in this method. + * [ + * {"op": "replace", "path": "/spec/image", "value": "mii-image:v2" } + * ] + * + * @param domainResourceName name of the domain resource + * @param namespace Kubernetes namespace that the domain is hosted + * @param image name of the new image + */ + private void patchDomainResourceImage( + String domainResourceName, + String namespace, + String image + ) { + String patch = + String.format("[\n {\"op\": \"replace\", \"path\": \"/spec/image\", \"value\": \"%s\"}\n]\n", + image); + logger.info("About to patch the domain resource {0} in namespace {1} with:{2}\n", + domainResourceName, namespace, patch); + + assertTrue(patchDomainCustomResource( + domainResourceName, + namespace, + new V1Patch(patch), + V1Patch.PATCH_FORMAT_JSON_PATCH), + String.format("Failed to patch the domain resource {0} in namespace {1} with image {2}", + domainResourceName, namespace, image)); + } + + private String createImageAndVerify( + String imageName, + String imageTag, + List modelList, + List archiveList + ) { + String image = String.format("%s:%s", imageName, imageTag); + + // Set additional environment variables for WIT + checkDirectory(WIT_BUILD_DIR); + Map env = new HashMap<>(); + env.put("WLSIMG_BLDDIR", WIT_BUILD_DIR); + + // For k8s 1.16 support and as of May 6, 2020, we presently need a different JDK for these + // tests and for image tool. This is expected to no longer be necessary once JDK 11.0.8 or + // the next JDK 14 versions are released. + String witJavaHome = System.getenv("WIT_JAVA_HOME"); + if (witJavaHome != null) { + env.put("JAVA_HOME", witJavaHome); + } + + // build an image using WebLogic Image Tool + logger.info("Create image {0} using model list {1} and archive list {2}", + image, modelList, archiveList); + boolean result = createMiiImage( + defaultWitParams() + .modelImageName(imageName) + .modelImageTag(imageTag) + .modelFiles(modelList) + .modelArchiveFiles(archiveList) + .wdtVersion(WDT_VERSION) + .env(env) + .redirect(true)); + + assertTrue(result, String.format("Failed to create image %s using WebLogic Image Tool", image)); + + /* Check image exists using docker images | grep image tag. + * Tag name is unique as it contains date and timestamp. + * This is a workaround for the issue on Jenkins machine + * as docker images imagename:imagetag is not working and + * the test fails even though the image exists. + */ + assertTrue(doesImageExist(imageTag), + String.format("Image %s doesn't exist", image)); + + return image; } private void createRepoSecret(String domNamespace) throws ApiException { @@ -605,6 +1030,50 @@ private void checkPodCreated(String podName, String domainUid, String domNamespa } + private void patchAndVerify( + final String domainUid, + final String namespace, + final String adminServerPodName, + final String managedServerPrefix, + final int replicaCount, + final String image + ) { + logger.info( + "Patch the domain resource {0} in namespace {1} to use the new image {2}", + domainUid, namespace, image); + + patchDomainResourceImage(domainUid, namespace, image); + + logger.info( + "Check that domain resource {0} in namespace {1} has been patched with image {2}", + domainUid, namespace, image); + checkDomainPatched(domainUid, namespace, image); + + // check and wait for the admin server pod to be patched with the new image + logger.info( + "Check that admin server pod for domain resource {0} in namespace {1} has been patched with image {2}", + domainUid, namespace, image); + + checkPodImagePatched( + domainUid, + namespace, + adminServerPodName, + image); + + // check and wait for the managed server pods to be patched with the new image + logger.info( + "Check that server pods for domain resource {0} in namespace {1} have been patched with image {2}", + domainUid, namespace, image); + for (int i = 1; i <= replicaCount; i++) { + checkPodImagePatched( + domainUid, + namespace, + managedServerPrefix + i, + image); + } + } + + private void checkPodReady(String podName, String domainUid, String domNamespace) { withStandardRetryPolicy .conditionEvaluationListener( @@ -631,27 +1100,207 @@ private void checkServiceCreated(String serviceName, String domNamespace) { condition.getRemainingTimeInMS())) .until(assertDoesNotThrow(() -> serviceExists(serviceName, null, domNamespace), String.format( - "Service %s is not ready in namespace %s", serviceName, domainNamespace))); + "Service %s is not ready in namespace %s", serviceName, domNamespace))); } - private void checkServerReadyStatusByExec(String podName, String namespace) { - final V1Pod pod = assertDoesNotThrow(() -> oracle.weblogic.kubernetes.assertions.impl.Kubernetes - .getPod(namespace, null, podName)); - - if (pod != null) { - ExecResult execResult = assertDoesNotThrow( - () -> execCommand(pod, null, true, READ_STATE_COMMAND)); - if (execResult.exitValue() == 0) { - logger.info("execResult: " + execResult); - assertEquals("RUNNING", execResult.stdout(), - "Expected " + podName + ", in namespace " + namespace + ", to be in RUNNING ready status"); + private void checkAppRunning( + String namespace, + String podName, + String internalPort, + String appPath, + String expectedStr + ) { + + // check if the application is accessible inside of a server pod using standard retry policy + checkAppIsRunning(withStandardRetryPolicy, namespace, podName, internalPort, appPath, expectedStr); + } + + private void quickCheckAppRunning( + String namespace, + String podName, + String internalPort, + String appPath, + String expectedStr + ) { + // check if the application is accessible inside of a server pod using quick retry policy + checkAppIsRunning(withQuickRetryPolicy, namespace, podName, internalPort, appPath, expectedStr); + } + + private void checkAppIsRunning( + ConditionFactory conditionFactory, + String namespace, + String podName, + String internalPort, + String appPath, + String expectedStr + ) { + + // check if the application is accessible inside of a server pod + conditionFactory + .conditionEvaluationListener( + condition -> logger.info("Waiting for application {0} is running on pod {1} in namespace {2} " + + "(elapsed time {3}ms, remaining time {4}ms)", + appPath, + podName, + namespace, + condition.getElapsedTimeInMS(), + condition.getRemainingTimeInMS())) + .until(() -> appAccessibleInPod( + namespace, + podName, + internalPort, + appPath, + expectedStr)); + + } + + private void quickCheckAppNotRunning( + String namespace, + String podName, + String internalPort, + String appPath, + String expectedStr + ) { + + // check that the application is NOT running inside of a server pod + withQuickRetryPolicy + .conditionEvaluationListener( + condition -> logger.info("Checking if application {0} is not running on pod {1} in namespace {2} " + + "(elapsed time {3}ms, remaining time {4}ms)", + appPath, + podName, + namespace, + condition.getElapsedTimeInMS(), + condition.getRemainingTimeInMS())) + .until(() -> appNotAccessibleInPod( + namespace, + podName, + internalPort, + appPath, + expectedStr)); + } + + private void checkDomainPatched( + String domainUid, + String namespace, + String image + ) { + + // check if the domain resource has been patched with the given image + withStandardRetryPolicy + .conditionEvaluationListener( + condition -> logger.info("Waiting for domain {0} to be patched in namespace {1} " + + "(elapsed time {2}ms, remaining time {3}ms)", + domainUid, + namespace, + condition.getElapsedTimeInMS(), + condition.getRemainingTimeInMS())) + .until(assertDoesNotThrow(() -> domainResourceImagePatched(domainUid, namespace, image), + String.format( + "Domain %s is not patched in namespace %s with image %s", domainUid, namespace, image))); + + } + + private void checkPodImagePatched( + String domainUid, + String namespace, + String podName, + String image + ) { + + // check if the server pod has been patched with the given image + withStandardRetryPolicy + .conditionEvaluationListener( + condition -> logger.info("Waiting for pod {0} to be patched in namespace {1} " + + "(elapsed time {2}ms, remaining time {3}ms)", + podName, + namespace, + condition.getElapsedTimeInMS(), + condition.getRemainingTimeInMS())) + .until(assertDoesNotThrow(() -> podImagePatched(domainUid, namespace, podName, "weblogic-server", image), + String.format( + "Pod %s is not patched with image %s in namespace %s.", + podName, + image, + namespace))); + } + + private static void collectAppAvaiability( + String namespace, + List appAvailability, + String managedServerPrefix, + int replicaCount, + String internalPort, + String appPath + ) { + boolean v2AppAvailable = false; + + // Access the pod periodically to check application's availability across the duration + // of patching the domain with newer version of the application. + // Note: we use the "kubectl exec" command in this method only. This is to avoid + // problems when two threads accessing the same pod at the same time via Kubernetes + // Java client. + while (!v2AppAvailable) { + v2AppAvailable = true; + for (int i = 1; i <= replicaCount; i++) { + v2AppAvailable = v2AppAvailable && appAccessibleInPodKubectl( + namespace, + managedServerPrefix + i, + internalPort, + appPath, + MII_APP_RESPONSE_V2 + i); + } + + int count = 0; + for (int i = 1; i <= replicaCount; i++) { + if (appAccessibleInPodKubectl( + namespace, + managedServerPrefix + i, + internalPort, + appPath, + "Hello World")) { + count++; + } + } + appAvailability.add(count); + + // the following log messages are temporarily here for debugging purposes. + // This part of the code is disabled by default right now, and can be enabled by + // -Dweblogic.operator.enableAppAvailabilityCheck=true. + // TODO remove these log messages when this verification is fully enabled. + if (count == 0) { + logger.info("XXXXXXXXXXX: application not available XXXXXXXX"); } else { - fail("Ready command failed with exit status code: " + execResult.exitValue()); + logger.info("YYYYYYYYYYY: application available YYYYYYYY count = " + count); + } + try { + TimeUnit.MILLISECONDS.sleep(200); + } catch (InterruptedException ie) { + // do nothing + } + } + } + + private static boolean appAlwaysAvailable(List appAvailability) { + for (Integer count: appAvailability) { + if (count == 0) { + logger.warning("Application was not available during patching."); + return false; } - } else { - fail("Did not find pod " + podName + " in namespace " + namespace); } + return true; } + private void checkServerReadyStatusByExec(String podName, String namespace) { + ExecResult execResult = assertDoesNotThrow( + () -> execCommand(namespace, podName, null, true, READ_STATE_COMMAND)); + if (execResult.exitValue() == 0) { + logger.info("execResult: " + execResult); + assertEquals("RUNNING", execResult.stdout(), + "Expected " + podName + ", in namespace " + namespace + ", to be in RUNNING ready status"); + } else { + fail("Read state command failed with exit status code: " + execResult.exitValue()); + } + } } diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItScaleMiiDomainNginx.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItScaleMiiDomainNginx.java index 16b9d6c5e10..02bf85d1524 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItScaleMiiDomainNginx.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/ItScaleMiiDomainNginx.java @@ -575,7 +575,8 @@ private String createImageAndVerify() { // build an application archive using what is in resources/apps/APP_NAME assertTrue(buildAppArchive(defaultAppParams() - .srcDir(APP_NAME)), String.format("Failed to create app archive for %s", APP_NAME)); + .srcDirList(Collections.singletonList(APP_NAME))), + String.format("Failed to create app archive for %s", APP_NAME)); // build the archive list String zipFile = String.format("%s/%s.zip", ARCHIVE_DIR, APP_NAME); diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/TestConstants.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/TestConstants.java index e09be5d89b9..925e6691b82 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/TestConstants.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/TestConstants.java @@ -63,5 +63,12 @@ public interface TestConstants { public static final String MII_BASIC_IMAGE_NAME = REPO_NAME + "mii-basic-image"; public static final String MII_BASIC_IMAGE_TAG = TestUtils.getDateAndTimeStamp(); public static final String MII_BASIC_APP_NAME = "sample-app"; + public static final String MII_TWO_APP_WDT_MODEL_FILE = "model-singlecluster-two-sampleapp-wls.yaml"; + + // application constants + public static final String MII_APP_RESPONSE_V1 = "Hello World, you have reached server managed-server"; + public static final String MII_APP_RESPONSE_V2 = "Hello World AGAIN, you have reached server managed-server"; + public static final String MII_APP_RESPONSE_V3 = "How are you doing! You have reached server managed-server"; + public static final String READ_STATE_COMMAND = "/weblogic-operator/scripts/readState.sh"; } diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/ActionConstants.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/ActionConstants.java index f5d0d30cbeb..e8987abc275 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/ActionConstants.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/ActionConstants.java @@ -43,12 +43,12 @@ public interface ActionConstants { public static final String WIT_DOWNLOAD_URL = "https://github.com/oracle/weblogic-image-tool"; - public static final String WIT_VERSION = System.getProperty("wit.version"); + public static final String WIT_VERSION = System.getProperty("wit.version", "latest"); public static final String WIT_FILE_NAME = "imagetool.zip"; public static final String WDT_DOWNLOAD_URL = "https://github.com/oracle/weblogic-deploy-tooling"; - public static final String WDT_VERSION = System.getProperty("wdt.version"); + public static final String WDT_VERSION = System.getProperty("wdt.version", "latest"); public static final String WDT_FILE_NAME = "weblogic-deploy.zip"; public static final String IMAGE_TOOL = WORK_DIR + "/imagetool/bin/imagetool.sh"; diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/TestActions.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/TestActions.java index 75a14a3c41f..e5d7e3e1d2e 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/TestActions.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/TestActions.java @@ -39,6 +39,7 @@ import oracle.weblogic.kubernetes.actions.impl.primitive.Docker; import oracle.weblogic.kubernetes.actions.impl.primitive.Helm; import oracle.weblogic.kubernetes.actions.impl.primitive.HelmParams; +import oracle.weblogic.kubernetes.actions.impl.primitive.Kubernetes; import oracle.weblogic.kubernetes.actions.impl.primitive.WebLogicImageTool; import oracle.weblogic.kubernetes.actions.impl.primitive.WitParams; import oracle.weblogic.kubernetes.utils.ExecResult; @@ -615,9 +616,10 @@ public static JsonObject createDockerConfigJson(String username, String password // ----------------------- Execute a Command --------------------------- /** - * Execute a command in a container. + * Execute a command in a container of a Kubernetes pod. * - * @param pod The pod where the command is to be run + * @param namespace The Kubernetes namespace that the pod is in + * @param podName The name of the Kubernetes pod where the command is expected to run * @param containerName The container in the Pod where the command is to be run. If no * container name is provided than the first container in the Pod is used. * @param redirectToStdout copy process output to stdout @@ -627,9 +629,20 @@ public static JsonObject createDockerConfigJson(String username, String password * @throws ApiException if Kubernetes client API call fails * @throws InterruptedException if any thread has interrupted the current thread */ - public static ExecResult execCommand(V1Pod pod, String containerName, boolean redirectToStdout, - String... command) - throws IOException, ApiException, InterruptedException { + public static ExecResult execCommand( + String namespace, + String podName, + String containerName, + boolean redirectToStdout, + String... command + ) throws IOException, ApiException, InterruptedException { + // get the pod given the namespace and name of the pod + // no label selector is needed (thus null below) + final V1Pod pod = Kubernetes.getPod(namespace, null, podName); + if (pod == null) { + throw new IllegalArgumentException( + String.format("The pod %s does not exist in namespace %s!", podName, namespace)); + } return Exec.exec(pod, containerName, redirectToStdout, command); } diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/AppBuilder.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/AppBuilder.java index d3d61b883f9..7e5256571c6 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/AppBuilder.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/AppBuilder.java @@ -6,11 +6,12 @@ import java.io.IOException; import oracle.weblogic.kubernetes.actions.impl.primitive.Command; +import oracle.weblogic.kubernetes.logging.LoggingFacade; +import oracle.weblogic.kubernetes.logging.LoggingFactory; import static oracle.weblogic.kubernetes.actions.ActionConstants.APP_DIR; import static oracle.weblogic.kubernetes.actions.ActionConstants.ARCHIVE_DIR; import static oracle.weblogic.kubernetes.actions.impl.primitive.Command.defaultCommandParams; -import static oracle.weblogic.kubernetes.extensions.LoggedTest.logger; import static oracle.weblogic.kubernetes.utils.FileUtils.checkDirectory; import static oracle.weblogic.kubernetes.utils.FileUtils.cleanupDirectory; import static oracle.weblogic.kubernetes.utils.FileUtils.copyFolder; @@ -20,6 +21,8 @@ */ public class AppBuilder { + private static final LoggingFacade logger = LoggingFactory.getLogger(AppBuilder.class); + private static final String ARCHIVE_SRC_DIR = ARCHIVE_DIR + "/wlsdeploy/applications"; private AppParams params; @@ -52,22 +55,29 @@ private AppBuilder params(AppParams params) { public boolean build() { // prepare the archive directory and copy over the app src try { - cleanupDirectory(ARCHIVE_DIR); + cleanupDirectory(ARCHIVE_SRC_DIR); checkDirectory(ARCHIVE_SRC_DIR); - copyFolder( - APP_DIR + "/" + params.srcDir(), - ARCHIVE_SRC_DIR); + for (String item : params.srcDirList()) { + copyFolder( + APP_DIR + "/" + item, + ARCHIVE_SRC_DIR); + } } catch (IOException ioe) { - logger.warning("Failed to get the directory " + ARCHIVE_DIR + " ready"); + logger.severe("Failed to get the directory " + ARCHIVE_DIR + " ready", ioe); return false; } + + // make sure that we always have an app name + if (params.appName() == null) { + params.appName(params.srcDirList().get(0)); + } // build the app archive - String jarPath = String.format("%s.ear", params.srcDir()); + String jarPath = String.format("%s.ear", params.appName()); boolean jarBuilt = buildJarArchive(jarPath, ARCHIVE_SRC_DIR); // build a zip file that can be passed to WIT - String zipPath = String.format("%s/%s.zip", ARCHIVE_DIR, params.srcDir()); + String zipPath = String.format("%s/%s.zip", ARCHIVE_DIR, params.appName()); boolean zipBuilt = buildZipArchive(zipPath, ARCHIVE_DIR); return jarBuilt && zipBuilt; @@ -108,7 +118,7 @@ private boolean buildZipArchive( "cd %s ; zip %s wlsdeploy/applications/%s.ear ", srcDir, zipPath, - params.srcDir()); + params.appName()); return Command.withParams( defaultCommandParams() diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/AppParams.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/AppParams.java index 8337983d8b1..621758093d7 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/AppParams.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/AppParams.java @@ -3,30 +3,46 @@ package oracle.weblogic.kubernetes.actions.impl; +import java.util.List; + /** * Contains the parameters for creating an application archive. */ public class AppParams { - // Location of the source code. - // This is the name of the directory under resources/apps for an application - private String srcDir; + // A list of directories under resources/apps that are part of the application. + // Note: the order of the directory names is significant. Files are copied into + // the staging directory in this order. + private List srcDirList; + + // The name of the final archive file. + // The name of the first dir in srcDirList will be used if the appName is absent. + private String appName; // Whether the output of the command is redirected to system out private boolean redirect = true; - + public AppParams defaults() { return this; } - public AppParams srcDir(String srcDir) { - this.srcDir = srcDir; + public AppParams srcDirList(List srcDirList) { + this.srcDirList = srcDirList; + return this; + } + + public List srcDirList() { + return srcDirList; + } + + public AppParams appName(String appName) { + this.appName = appName; return this; } - public String srcDir() { - return srcDir; + public String appName() { + return appName; } public AppParams redirect(boolean redirect) { diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/Command.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/Command.java index c9d5a4e58a4..de66cde1854 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/Command.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/Command.java @@ -40,11 +40,14 @@ private Command params(CommandParams params) { } /** - * Executes command. - * @return true, on success + * Execute a command. + * + * @return true if the execution succeeded with an exitValue of zero */ public boolean execute() { - logger.info("Executing command {0}", params.command()); + if (params.verbose()) { + logger.info("Executing command {0}", params.command()); + } try { ExecResult result = ExecCommand.exec( params.command(), @@ -56,7 +59,7 @@ public boolean execute() { } // check exitValue to determine if the command execution has failed. - if (result.exitValue() != 0) { + if (params.verbose() && result.exitValue() != 0) { logger.severe("The command execution failed because it returned non-zero exit value: {0}.", result); } @@ -66,4 +69,38 @@ public boolean execute() { return false; } } + + /** + * Execute a command and verify the response. + * + * @param expectedResponse the expected response to verify + * @return true if the execution succeeded and response contains the expected value + */ + public boolean executeAndVerify(String expectedResponse) { + if (params.verbose()) { + logger.info("Executing command {0}", params.command()); + } + try { + ExecResult result = ExecCommand.exec( + params.command(), + params.redirect(), + params.env()); + if (params.saveResults()) { + params.stdout(result.stdout()); + params.stderr(result.stderr()); + } + + // check exitValue to determine if the command execution has failed. + if (params.verbose() && result.exitValue() != 0) { + logger.severe("The command execution failed because it returned non-zero exit value: {0}.", result); + } + + return result.exitValue() == 0 + && result.stdout() != null + && result.stdout().contains(expectedResponse); + } catch (IOException | InterruptedException ie) { + logger.severe("The command execution failed", ie); + return false; + } + } } diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/CommandParams.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/CommandParams.java index 25cf0dac628..7030b6d737e 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/CommandParams.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/CommandParams.java @@ -28,8 +28,10 @@ public class CommandParams { // The stderr of the command execution private String stderr; - + // Whether to turn on verbose logging + private boolean verbose = true; + public CommandParams defaults() { return this; } @@ -87,5 +89,14 @@ public CommandParams stdout(String stdout) { public String stdout() { return stdout; } + + public CommandParams verbose(boolean verbose) { + this.verbose = verbose; + return this; + } + + public boolean verbose() { + return verbose; + } } diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/Installer.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/Installer.java index 41de0d84bac..0a58c29fbba 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/Installer.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/Installer.java @@ -90,7 +90,7 @@ public boolean download() { boolean unzipSucceeded = true; if (params.verify() && new File(DOWNLOAD_DIR, params.fileName()).exists()) { - logger.info("File {0} already exists.", params.fileName()); + logger.fine("File {0} already exists.", params.fileName()); } else { // check and make sure DOWNLOAD_DIR exists; will create it if it is missing checkDirectory(DOWNLOAD_DIR); diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/Kubernetes.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/Kubernetes.java index 9aaaaddd94a..7b92c429422 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/Kubernetes.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/Kubernetes.java @@ -348,6 +348,7 @@ public static boolean deleteDeployment(String namespace, String name) throws Api } // --------------------------- pods ----------------------------------------- + /** * Get a pod's log. * @@ -2045,7 +2046,9 @@ public static ExecResult exec(V1Pod pod, String containerName, boolean redirectT // wait for reading thread to finish any last remaining output if (out != null) { - out.join(); + // need to time out here, otherwise the command can take almost one minute to return. + // yet to see if we'll need a different timeout value for different environments. + out.join(1200); } // Read data from process's stdout diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/WebLogicImageTool.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/WebLogicImageTool.java index cf3b5640f93..2508cf83013 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/WebLogicImageTool.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/actions/impl/primitive/WebLogicImageTool.java @@ -53,7 +53,7 @@ public boolean updateImage() { if (!downloadWit()) { return false; } - + // download WDT if it is not in the expected location if (!downloadWdt()) { return false; diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/TestAssertions.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/TestAssertions.java index f0219d81a41..251fba8c6eb 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/TestAssertions.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/TestAssertions.java @@ -7,6 +7,7 @@ import java.util.concurrent.Callable; import io.kubernetes.client.openapi.ApiException; +import oracle.weblogic.kubernetes.assertions.impl.Application; import oracle.weblogic.kubernetes.assertions.impl.Docker; import oracle.weblogic.kubernetes.assertions.impl.Domain; import oracle.weblogic.kubernetes.assertions.impl.Helm; @@ -74,6 +75,43 @@ public static Callable domainExists(String domainUid, String domainVers return Domain.doesDomainExist(domainUid, domainVersion, namespace); } + /** + * Check if a WebLogic domain custom resource has been patched with a new image. + * + * @param domainUid ID of the domain resource + * @param namespace Kubernetes namespace in which the domain custom resource object exists + * @param image name of the image that was used to patch the domain resource + * @return true if the domain is patched correctly + */ + public static Callable domainResourceImagePatched( + String domainUid, + String namespace, + String image + ) { + return Domain.domainResourceImagePatched(domainUid, namespace, image); + } + + /** + * Check if a WebLogic server pod has been patched with a new image. + * + * @param domainUid ID of the domain resource + * @param namespace Kubernetes namespace in which the domain custom resource object exists + * @param podName name of the WebLogic server pod + * @param image name of the image that was used to patch the domain resource + * @return true if the pod is patched correctly + */ + public static Callable podImagePatched( + String domainUid, + String namespace, + String podName, + String containerName, + String image + ) throws ApiException { + return () -> { + return Kubernetes.podImagePatched(namespace, domainUid, podName, containerName, image); + }; + } + /** * Check if a Kubernetes pod exists in any state in the given namespace. * @@ -187,7 +225,7 @@ public static boolean adminT3ChannelAccessible(String domainUid, String namespac /** * Check if a admin server pod admin node port is accessible. * - * @param domainUid domainUID id of the domain in which admin server pod is running + * @param domainUid id of the domain in which admin server pod is running * @param namespace in which the WebLogic server pod exists * @return true if the admin node port is accessible otherwise false */ @@ -206,6 +244,68 @@ public static boolean dockerImageExists(String imageName, String imageTag) { return WitAssertion.doesImageExist(imageName, imageTag); } + /** + * Check if an application is accessible inside a WebLogic server pod using + * "kubectl exec" command. + * + * @param namespace Kubernetes namespace where the WebLogic server pod is running + * @param podName name of the WebLogic server pod + * @param port internal port of the managed server running in the pod + * @param appPath path to access the application + * @param expectedResponse the expected response from the application + * @return true if the command succeeds + */ + public static boolean appAccessibleInPodKubectl( + String namespace, + String podName, + String port, + String appPath, + String expectedResponse + ) { + return Application.appAccessibleInPodKubectl(namespace, podName, port, appPath, expectedResponse); + } + + /** + * Check if an application is accessible inside a WebLogic server pod using + * Kubernetes Java client API. + * + * @param namespace Kubernetes namespace where the WebLogic server pod is running + * @param podName name of the WebLogic server pod + * @param port internal port of the managed server running in the pod + * @param appPath path to access the application + * @param expectedResponse the expected response from the application + * @return true if the command succeeds + */ + public static boolean appAccessibleInPod( + String namespace, + String podName, + String port, + String appPath, + String expectedResponse + ) { + return Application.appAccessibleInPod(namespace, podName, port, appPath, expectedResponse); + } + + /** + * Check if an application is Not running inside a WebLogic server pod. + * . + * @param namespace Kubernetes namespace where the WebLogic server pod is running + * @param podName name of the WebLogic server pod + * @param port internal port of the managed server running in the pod + * @param appPath path to access the application + * @param expectedResponse the expected response from the application + * @return true if the command succeeds + */ + public static boolean appNotAccessibleInPod( + String namespace, + String podName, + String port, + String appPath, + String expectedResponse + ) { + return !Application.appAccessibleInPod(namespace, podName, port, appPath, expectedResponse); + } + /** * Check if the Docker image containing the search string exists. * @param searchString search string diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Application.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Application.java new file mode 100644 index 00000000000..a3ae061d71e --- /dev/null +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Application.java @@ -0,0 +1,122 @@ +// Copyright (c) 2020, Oracle Corporation and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +package oracle.weblogic.kubernetes.assertions.impl; + +import java.io.IOException; + +import io.kubernetes.client.openapi.ApiException; +import oracle.weblogic.kubernetes.actions.impl.primitive.Command; +import oracle.weblogic.kubernetes.actions.impl.primitive.CommandParams; +import oracle.weblogic.kubernetes.logging.LoggingFacade; +import oracle.weblogic.kubernetes.logging.LoggingFactory; +import oracle.weblogic.kubernetes.utils.ExecResult; + +import static oracle.weblogic.kubernetes.actions.TestActions.execCommand; + +/** + * Assertions for applications that are deployed in a domain custom resource. + * + */ + +public class Application { + private static final LoggingFacade logger = LoggingFactory.getLogger(Application.class); + + /** + * Check if an application is accessible inside a WebLogic server pod. + * + * @param namespace Kubernetes namespace where the WebLogic server pod is running + * @param podName name of the WebLogic server pod + * @param port internal port of the managed server running in the pod + * @param appPath path to access the application + * @param expectedResponse expected response from the app + * @return true if the command succeeds + */ + public static boolean appAccessibleInPodKubectl( + String namespace, + String podName, + String port, + String appPath, + String expectedResponse + ) { + + // calling "kubectl exec" command to access the app inside a pod + String cmd = String.format( + "kubectl -n %s exec -it %s -- /bin/bash -c 'curl http://%s:%s/%s'", + namespace, + podName, + podName, + port, + appPath); + + CommandParams params = Command + .defaultCommandParams() + .command(cmd) + .saveResults(true) + .redirect(false) + .verbose(false); + return Command.withParams(params).executeAndVerify(expectedResponse); + } + + /** + * Check if an application is accessible inside a WebLogic server pod using + * Kubernetes Java client. + * + * @param namespace Kubernetes namespace where the WebLogic server pod is running + * @param podName name of the WebLogic server pod + * @param port internal port of the managed server running in the pod + * @param appPath path to access the application + * @param expectedResponse expected response from the app + * @return true if the command succeeds + */ + public static boolean appAccessibleInPod( + String namespace, + String podName, + String port, + String appPath, + String expectedResponse + ) { + + // access the application in the given pod + String[] cmd = new String[] { + "/usr/bin/curl", + String.format("http://%s:%s/%s", + podName, + port, + appPath)}; + + try { + ExecResult execResult = execCommand( + namespace, + podName, + "weblogic-server", // container name + false, // redirectOutput + cmd); + if (execResult.exitValue() == 0 + && execResult.stdout() != null + && execResult.stdout().contains(expectedResponse)) { + logger.info( + String.format("App is accessible inside pod %s in namespace %s", + podName, + namespace)); + return true; + } else { + logger.warning( + String.format("Failed to access the app inside pod %s in namespace %s", + podName, + namespace)); + return false; + } + } catch (ApiException | IOException | InterruptedException e) { + logger.warning( + String.format("Failed to access the app inside pod %s in namespace %s", + podName, + namespace), + e); + return false; + } catch (IllegalArgumentException iae) { + logger.warning(String.format("Failed to find pod %s to check the app", podName)); + return false; + } + } +} diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Docker.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Docker.java index 2aff43a9553..e5e5d514970 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Docker.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Docker.java @@ -22,10 +22,7 @@ public static boolean doesImageExist(String searchString) { .saveResults(true) .redirect(false); - if (Command.withParams(cmdParams) - .execute()) { - return cmdParams.stdout().contains(searchString); - } - return false; + return Command.withParams(cmdParams) + .executeAndVerify(searchString); } } diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Domain.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Domain.java index adeb9047091..000467ff7d7 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Domain.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Domain.java @@ -16,9 +16,9 @@ import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; +import static oracle.weblogic.kubernetes.actions.impl.primitive.Kubernetes.getPod; import static oracle.weblogic.kubernetes.assertions.impl.Kubernetes.doesPodExist; import static oracle.weblogic.kubernetes.assertions.impl.Kubernetes.doesServiceExist; -import static oracle.weblogic.kubernetes.assertions.impl.Kubernetes.getPod; import static oracle.weblogic.kubernetes.assertions.impl.Kubernetes.isPodReady; import static oracle.weblogic.kubernetes.extensions.LoggedTest.logger; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; @@ -85,6 +85,35 @@ public static Callable doesDomainExist(String domainUid, String domainV }; } + /** + * Check if the domain resource has been patched with a new image. + * + * @param domainUID identifier of the domain resource + * @param namespace Kubernetes namespace in which the domain exists + * @param image name of the image that the pod is expected to be using + * @return true if domain resource's image matches the expected value + */ + public static Callable domainResourceImagePatched( + String domainUID, + String namespace, + String image + ) { + return () -> { + oracle.weblogic.domain.Domain domain = null; + try { + domain = oracle.weblogic.kubernetes.actions.impl.primitive.Kubernetes + .getDomainCustomResource(domainUID, namespace); + } catch (ApiException apex) { + logger.severe("Failed to obtain the domain resource object from the API server", apex); + return false; + } + + boolean domainPatched = (domain.spec().image().equals(image)); + logger.info("Domain Object patched : " + domainPatched + " domain image = " + domain.spec().image()); + return domainPatched; + }; + } + public static boolean adminT3ChannelAccessible(String domainUid, String namespace) { return true; } @@ -153,4 +182,4 @@ public static boolean podStateNotChangedDuringScalingCluster(String podName, return true; } -} \ No newline at end of file +} diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Kubernetes.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Kubernetes.java index c42fc6384cf..49ba8e25823 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Kubernetes.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/assertions/impl/Kubernetes.java @@ -14,6 +14,7 @@ import io.kubernetes.client.openapi.Configuration; import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.apis.CustomObjectsApi; +import io.kubernetes.client.openapi.models.V1Container; import io.kubernetes.client.openapi.models.V1Pod; import io.kubernetes.client.openapi.models.V1PodCondition; import io.kubernetes.client.openapi.models.V1PodList; @@ -171,6 +172,43 @@ public static boolean isPodTerminating(String namespace, String domainUid, Strin return status; } + /** + * Checks if a WebLogic server pod has been patched with an expected image. + * + * @param namespace Kubernetes namespace in which the pod is running + * @param domainUid label that the pod is decorated with + * @param podName name of the WebLogic server pod + * @param containerName name of the container + * @param image name of the image to check for + * @return true if pod's image has been patched + * @throws ApiException when there is an error in querying the Kubernetes cluster + */ + public static boolean podImagePatched( + String namespace, + String domainUid, + String podName, + String containerName, + String image + ) throws ApiException { + boolean podPatched = false; + String labelSelector = null; + if (domainUid != null) { + labelSelector = String.format("weblogic.domainUID in (%s)", domainUid); + } + V1Pod pod = getPod(namespace, labelSelector, podName); + if (pod != null && pod.getSpec() != null) { + List containers = pod.getSpec().getContainers(); + for (V1Container container : containers) { + // look for the container + if (container.getName().equals(containerName) + && (container.getImage().equals(image))) { + podPatched = true; + } + } + } + return podPatched; + } + /** * Checks if an operator pod is running in a given namespace. * The method assumes the operator name to starts with weblogic-operator- diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/extensions/ImageBuilders.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/extensions/ImageBuilders.java index 57d132a017b..9c4656202df 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/extensions/ImageBuilders.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/extensions/ImageBuilders.java @@ -3,6 +3,7 @@ package oracle.weblogic.kubernetes.extensions; +import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -24,6 +25,7 @@ import static oracle.weblogic.kubernetes.TestConstants.REPO_REGISTRY; import static oracle.weblogic.kubernetes.TestConstants.REPO_USERNAME; import static oracle.weblogic.kubernetes.actions.ActionConstants.ARCHIVE_DIR; +import static oracle.weblogic.kubernetes.actions.ActionConstants.DOWNLOAD_DIR; import static oracle.weblogic.kubernetes.actions.ActionConstants.MODEL_DIR; import static oracle.weblogic.kubernetes.actions.ActionConstants.WDT_VERSION; import static oracle.weblogic.kubernetes.actions.ActionConstants.WIT_BUILD_DIR; @@ -37,6 +39,7 @@ import static oracle.weblogic.kubernetes.assertions.TestAssertions.doesImageExist; import static oracle.weblogic.kubernetes.extensions.LoggedTest.logger; import static oracle.weblogic.kubernetes.utils.FileUtils.checkDirectory; +import static oracle.weblogic.kubernetes.utils.FileUtils.cleanupDirectory; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.GLOBAL; @@ -61,6 +64,14 @@ public void beforeAll(ExtensionContext context) { */ if (!started.getAndSet(true)) { try { + // clean up the download directory so that we always get the latest + // versions of the WDT and WIT tools in every run of the test suite. + try { + cleanupDirectory(DOWNLOAD_DIR); + } catch (IOException ioe) { + logger.severe("Failed to cleanup the download directory " + DOWNLOAD_DIR, ioe); + } + // Only the first thread will enter this block. logger.info("Building docker Images before any integration test classes are run"); @@ -149,7 +160,8 @@ private boolean createMiiBasicImage(String imageName, String imageTag) { // build an application archive using what is in resources/apps/APP_NAME logger.info("Build an application archive using resources/apps/{0}", MII_BASIC_APP_NAME); assertTrue(buildAppArchive(defaultAppParams() - .srcDir(MII_BASIC_APP_NAME)), String.format("Failed to create app archive for %s", MII_BASIC_APP_NAME)); + .srcDirList(Collections.singletonList(MII_BASIC_APP_NAME))), + String.format("Failed to create app archive for %s", MII_BASIC_APP_NAME)); // build the archive list String zipFile = String.format("%s/%s.zip", ARCHIVE_DIR, MII_BASIC_APP_NAME); @@ -181,4 +193,4 @@ private boolean createMiiBasicImage(String imageName, String imageTag) { .redirect(true)); } -} \ No newline at end of file +} diff --git a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/utils/FileUtils.java b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/utils/FileUtils.java index 8fc2195e27b..f532867fcfd 100644 --- a/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/utils/FileUtils.java +++ b/new-integration-tests/src/test/java/oracle/weblogic/kubernetes/utils/FileUtils.java @@ -11,6 +11,9 @@ import java.nio.file.Paths; import java.util.stream.Stream; +import oracle.weblogic.kubernetes.logging.LoggingFacade; +import oracle.weblogic.kubernetes.logging.LoggingFactory; + import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static oracle.weblogic.kubernetes.extensions.LoggedTest.logger; import static org.apache.commons.io.FileUtils.cleanDirectory; @@ -19,6 +22,7 @@ * The utility class for file operations. */ public class FileUtils { + private static final LoggingFacade logger = LoggingFactory.getLogger(FileUtils.class); /** * Check if the required directories exist. @@ -31,7 +35,7 @@ public static void checkDirectory(String dir) { File file = new File(dir); if (!(file.exists() && file.isDirectory())) { file.mkdirs(); - logger.info("Made a new dir " + dir); + logger.fine("Made a new directory {0}.", dir); } } @@ -44,7 +48,7 @@ public static void checkDirectory(String dir) { public static void checkFile(String fileName) throws FileNotFoundException { File file = new File(fileName); if (!(file.exists() && file.isFile())) { - logger.warning("The expected file " + fileName + " was not found."); + logger.warning("The expected file {0} was not found.", fileName); throw new FileNotFoundException("The expected file " + fileName + " was not found."); } } @@ -70,15 +74,12 @@ public static boolean doesFileExist(String fileName) { */ public static void cleanupDirectory(String dir) throws IOException { File file = new File(dir); - logger.info("Cleaning up directory " + dir); + logger.info("Cleaning up directory {0}.", dir); if (!file.exists()) { // nothing to do return; } - if (!file.isDirectory()) { - throw new IllegalArgumentException("The parameter " + dir + " should be a directory."); - } cleanDirectory(file); } @@ -98,14 +99,19 @@ public static void copyFolder(String srcDir, String destDir) throws IOException try { copy(source, destPath.resolve(srcPath.relativize(source))); } catch (IOException e) { + String msg = String.format("Failed to copy file %s to %s", source, destDir); + logger.severe(msg, e); // cannot throw non runtime exception. the caller checks throwable - throw new RuntimeException("Failed to copy file " + source); + throw new RuntimeException(msg); } }); } } private static void copy(Path source, Path dest) throws IOException { - Files.copy(source, dest, REPLACE_EXISTING); + logger.finest("Copying {0} to {1} source.fileName = {2}", source, dest, source.getFileName()); + if (!dest.toFile().isDirectory()) { + Files.copy(source, dest, REPLACE_EXISTING); + } } } diff --git a/new-integration-tests/src/test/resources/apps/sample-app-2/sample-war/index.jsp b/new-integration-tests/src/test/resources/apps/sample-app-2/sample-war/index.jsp new file mode 100644 index 00000000000..117ad485eec --- /dev/null +++ b/new-integration-tests/src/test/resources/apps/sample-app-2/sample-war/index.jsp @@ -0,0 +1,7 @@ +<%-- +Copyright (c) 2020, Oracle Corporation and/or its affiliates. +Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +--%> +<% + out.println("Hello World AGAIN, you have reached server " + System.getProperty("weblogic.Name")); +%> diff --git a/new-integration-tests/src/test/resources/apps/sample-app-3/META-INF/MANIFEST.MF b/new-integration-tests/src/test/resources/apps/sample-app-3/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..8a636006c23 --- /dev/null +++ b/new-integration-tests/src/test/resources/apps/sample-app-3/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Created-By: 1.8.0_201 (Oracle Corporation) + diff --git a/new-integration-tests/src/test/resources/apps/sample-app-3/META-INF/application.xml b/new-integration-tests/src/test/resources/apps/sample-app-3/META-INF/application.xml new file mode 100644 index 00000000000..0f9a5fc527b --- /dev/null +++ b/new-integration-tests/src/test/resources/apps/sample-app-3/META-INF/application.xml @@ -0,0 +1,15 @@ + + + + JSP 2.0 Expression Language Example + JSP 2.0 Expression Language Example + + + sample-war-3 + sample-war-3 + + + diff --git a/new-integration-tests/src/test/resources/apps/sample-app-3/META-INF/weblogic-application.xml b/new-integration-tests/src/test/resources/apps/sample-app-3/META-INF/weblogic-application.xml new file mode 100644 index 00000000000..90f03062d3c --- /dev/null +++ b/new-integration-tests/src/test/resources/apps/sample-app-3/META-INF/weblogic-application.xml @@ -0,0 +1,7 @@ + + + + diff --git a/new-integration-tests/src/test/resources/apps/sample-app-3/sample-war-3/WEB-INF/web.xml b/new-integration-tests/src/test/resources/apps/sample-app-3/sample-war-3/WEB-INF/web.xml new file mode 100644 index 00000000000..8640ebd65af --- /dev/null +++ b/new-integration-tests/src/test/resources/apps/sample-app-3/sample-war-3/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + + diff --git a/new-integration-tests/src/test/resources/apps/sample-app-3/sample-war-3/WEB-INF/weblogic.xml b/new-integration-tests/src/test/resources/apps/sample-app-3/sample-war-3/WEB-INF/weblogic.xml new file mode 100644 index 00000000000..9d45e41cb8b --- /dev/null +++ b/new-integration-tests/src/test/resources/apps/sample-app-3/sample-war-3/WEB-INF/weblogic.xml @@ -0,0 +1,15 @@ + + + + + 15 + 60 + + + 1 + true + + diff --git a/new-integration-tests/src/test/resources/apps/sample-app-3/sample-war-3/index.jsp b/new-integration-tests/src/test/resources/apps/sample-app-3/sample-war-3/index.jsp new file mode 100644 index 00000000000..49df464bd08 --- /dev/null +++ b/new-integration-tests/src/test/resources/apps/sample-app-3/sample-war-3/index.jsp @@ -0,0 +1,7 @@ +<%-- +Copyright (c) 2020, Oracle Corporation and/or its affiliates. +Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +--%> +<% + out.println("How are you doing! You have reached server " + System.getProperty("weblogic.Name")); +%> diff --git a/new-integration-tests/src/test/resources/wdt-models/model-singlecluster-two-sampleapp-wls.yaml b/new-integration-tests/src/test/resources/wdt-models/model-singlecluster-two-sampleapp-wls.yaml new file mode 100644 index 00000000000..e953c861be2 --- /dev/null +++ b/new-integration-tests/src/test/resources/wdt-models/model-singlecluster-two-sampleapp-wls.yaml @@ -0,0 +1,38 @@ +# Copyright (c) 2020, Oracle Corporation and/or its affiliates. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +domainInfo: + AdminUserName: '@@SECRET:__weblogic-credentials__:username@@' + AdminPassword: '@@SECRET:__weblogic-credentials__:password@@' + ServerStartMode: 'prod' + +topology: + Name: "wls-domain1" + AdminServerName: "admin-server" + Cluster: + "cluster-1": + DynamicServers: + ServerTemplate: "cluster-1-template" + ServerNamePrefix: "managed-server" + DynamicClusterSize: 5 + MaxDynamicClusterSize: 5 + CalculatedListenPorts: false + Server: + "admin-server": + ListenPort: 7001 + ServerTemplate: + "cluster-1-template": + Cluster: "cluster-1" + ListenPort : 8001 + +appDeployments: + Application: + myear: + SourcePath: "wlsdeploy/applications/sample-app.ear" + ModuleType: ear + Target: 'cluster-1' + + myear3: + SourcePath: "wlsdeploy/applications/sample-app-3.ear" + ModuleType: ear + Target: 'cluster-1'