From dca6a265047948859f53d5d8357b2ce404611fe3 Mon Sep 17 00:00:00 2001 From: Fabio Burzigotti Date: Tue, 12 Sep 2023 17:13:24 +0200 Subject: [PATCH] [issue 80] - Adding WildFly Jakarta EE 8/EAP 7.z template based provisioner --- .ci/openshift-ci/build-root/e2e-test-prod.sh | 2 + .../NotForCommunityExecutionProfile.java | 4 +- .../Eap7TemplateProvisionerTestCase.java | 94 ++++++++ .../OpenShiftProvisionerTestBase.java | 42 +++- .../intersmash/tools/IntersmashConfig.java | 12 +- .../OpenShiftTemplateProvisioner.java | 3 +- .../Eap7ImageOpenShiftApplication.java | 2 +- .../Eap7TemplateOpenShiftApplication.java | 20 ++ .../openshift/template/Eap7Template.java | 27 +++ .../Eap7ImageOpenShiftProvisioner.java | 2 +- .../Eap7TemplateOpenShiftProvisioner.java | 208 ++++++++++++++++++ .../template/Eap7TemplateProvisioner.java | 155 +++++++++++++ 12 files changed, 563 insertions(+), 8 deletions(-) create mode 100644 testsuite/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/Eap7TemplateProvisionerTestCase.java create mode 100644 tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/application/openshift/Eap7TemplateOpenShiftApplication.java create mode 100644 tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/application/openshift/template/Eap7Template.java create mode 100644 tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/provision/openshift/Eap7TemplateOpenShiftProvisioner.java create mode 100644 tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/provision/openshift/template/Eap7TemplateProvisioner.java diff --git a/.ci/openshift-ci/build-root/e2e-test-prod.sh b/.ci/openshift-ci/build-root/e2e-test-prod.sh index 8f789b802..01213ac57 100644 --- a/.ci/openshift-ci/build-root/e2e-test-prod.sh +++ b/.ci/openshift-ci/build-root/e2e-test-prod.sh @@ -107,6 +107,8 @@ mvn test -Dmaven.repo.local=./local-repo-prod -pl testsuite/ -Pts.prod \ -Dintersmash.wildfly.helm.charts.name=eap8 \ -Dintersmash.eap7.image=registry.redhat.io/jboss-eap-7/eap74-openjdk17-openshift-rhel8:latest \ -Dintersmash.eap7.runtime.image=registry.redhat.io/jboss-eap-7/eap74-openjdk17-runtime-openshift-rhel8:latest \ + -Dintersmash.eap7.templates.base.url=https://raw.githubusercontent.com/jboss-container-images/jboss-eap-openshift-templates/eap74/ \ + -Dintersmash.eap7.templates.path=templates/ \ -Dintersmash.activemq.image=registry.redhat.io/amq7/amq-broker-rhel8:7.11.0 \ -Dintersmash.activemq.init.image=registry.redhat.io/amq7/amq-broker-init-rhel8:7.11.0 \ -Dintersmash.activemq.operators.catalog_source=redhat-operators \ diff --git a/testsuite/src/main/java/org/jboss/intersmash/testsuite/junit5/categories/NotForCommunityExecutionProfile.java b/testsuite/src/main/java/org/jboss/intersmash/testsuite/junit5/categories/NotForCommunityExecutionProfile.java index 04bbb57d2..08ff9cce9 100644 --- a/testsuite/src/main/java/org/jboss/intersmash/testsuite/junit5/categories/NotForCommunityExecutionProfile.java +++ b/testsuite/src/main/java/org/jboss/intersmash/testsuite/junit5/categories/NotForCommunityExecutionProfile.java @@ -1,11 +1,11 @@ package org.jboss.intersmash.testsuite.junit5.categories; -import org.junit.jupiter.api.Tag; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.Tag; + /** * Mark a test that does not support community deliverables. * Used per class. diff --git a/testsuite/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/Eap7TemplateProvisionerTestCase.java b/testsuite/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/Eap7TemplateProvisionerTestCase.java new file mode 100644 index 000000000..d69c2a61e --- /dev/null +++ b/testsuite/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/Eap7TemplateProvisionerTestCase.java @@ -0,0 +1,94 @@ +package org.jboss.intersmash.testsuite.provision.openshift; + +import java.util.Optional; + +import org.assertj.core.api.Assertions; +import org.assertj.core.api.SoftAssertions; +import org.jboss.intersmash.testsuite.junit5.categories.NotForCommunityExecutionProfile; +import org.jboss.intersmash.tools.application.openshift.Eap7TemplateOpenShiftApplication; +import org.jboss.intersmash.tools.provision.openshift.Eap7TemplateOpenShiftProvisioner; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import cz.xtf.core.openshift.OpenShift; +import cz.xtf.core.openshift.OpenShifts; +import cz.xtf.core.openshift.PodShell; +import cz.xtf.core.openshift.PodShellOutput; +import cz.xtf.junit5.annotations.CleanBeforeAll; +import io.fabric8.openshift.api.model.BuildConfig; +import io.fabric8.openshift.api.model.GitBuildSource; + +@CleanBeforeAll +@NotForCommunityExecutionProfile +public class Eap7TemplateProvisionerTestCase { + private static final OpenShift openShift = OpenShifts.master(); + private static final Eap7TemplateOpenShiftApplication application = OpenShiftProvisionerTestBase + .getEap7OpenShiftTemplateApplication(); + private static final Eap7TemplateOpenShiftProvisioner provisioner = new Eap7TemplateOpenShiftProvisioner(application); + + @BeforeAll + public static void deploy() { + provisioner.preDeploy(); + provisioner.deploy(); + } + + @AfterAll + public static void undeploy() { + provisioner.undeploy(); + provisioner.postUndeploy(); + } + + @Test + public void verifyEapConfiguration() { + SoftAssertions softAssertions = new SoftAssertions(); + // verify system property added via cli + PodShell rsh = new PodShell(openShift, openShift.getAnyPod(application.getName())); + PodShellOutput output = rsh + .executeWithBash(String.format("$JBOSS_HOME/bin/jboss-cli.sh -c /system-property=%s:read-resource", + OpenShiftProvisionerTestBase.WILDFLY_TEST_PROPERTY)); + softAssertions.assertThat(output.getError()).as("CLI configuration check: Error should be empty").isEmpty(); + softAssertions.assertThat(output.getOutput()).as("CLI configuration check: Test property was not set by CLI") + .contains("success", OpenShiftProvisionerTestBase.WILDFLY_TEST_PROPERTY); + + // verify application git + Optional gitBuildConfig = openShift.buildConfigs().list().getItems().stream() + .filter(buildConfig -> buildConfig.getSpec().getSource().getType().equals("Git")) + .findFirst(); + softAssertions.assertThat(gitBuildConfig.isPresent()).as("Cannot find a Git build config").isTrue(); + if (gitBuildConfig.isPresent()) { + softAssertions.assertThat(gitBuildConfig.get().getMetadata().getName()).contains(application.getName()); + GitBuildSource git = gitBuildConfig.get().getSpec().getSource().getGit(); + softAssertions.assertThat(git.getUri()).as("Git repository check") + .isEqualTo(OpenShiftProvisionerTestBase.EAP7_TEST_APP_REPO); + softAssertions.assertThat(git.getRef()).as("Git repository reference check") + .isEqualTo(OpenShiftProvisionerTestBase.EAP7_TEST_APP_REF); + } + softAssertions.assertAll(); + } + + /** + * Any {@code Secret} or {@code ConfigMap} should be created as a preDeploy() operation by a provisioner. + */ + @Test + public void verifyDeployHooks() { + Assertions.assertThat(openShift.getSecret(OpenShiftProvisionerTestBase.TEST_SECRET.getMetadata().getName())) + .isNotNull(); + } + + @Test + public void scale() { + provisioner.scale(1, true); + openShift.waiters().areExactlyNPodsReady(1, application.getName()).waitFor(); + provisioner.scale(2, true); + openShift.waiters().areExactlyNPodsReady(2, application.getName()).waitFor(); + } + + @Test + public void pods() { + provisioner.scale(2, true); + Assertions.assertThat(provisioner.getPods().size()).isEqualTo(2); + provisioner.scale(3, true); + Assertions.assertThat(provisioner.getPods().size()).isEqualTo(3); + } +} diff --git a/testsuite/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/OpenShiftProvisionerTestBase.java b/testsuite/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/OpenShiftProvisionerTestBase.java index ad4570b22..b0d7c8a00 100644 --- a/testsuite/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/OpenShiftProvisionerTestBase.java +++ b/testsuite/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/OpenShiftProvisionerTestBase.java @@ -32,14 +32,16 @@ import org.jboss.intersmash.testsuite.IntersmashTestsuiteProperties; import org.jboss.intersmash.tools.IntersmashConfig; import org.jboss.intersmash.tools.application.openshift.BootableJarOpenShiftApplication; +import org.jboss.intersmash.tools.application.openshift.Eap7ImageOpenShiftApplication; +import org.jboss.intersmash.tools.application.openshift.Eap7TemplateOpenShiftApplication; import org.jboss.intersmash.tools.application.openshift.KafkaOperatorApplication; import org.jboss.intersmash.tools.application.openshift.MysqlImageOpenShiftApplication; import org.jboss.intersmash.tools.application.openshift.PostgreSQLImageOpenShiftApplication; import org.jboss.intersmash.tools.application.openshift.WildflyImageOpenShiftApplication; -import org.jboss.intersmash.tools.application.openshift.Eap7ImageOpenShiftApplication; import org.jboss.intersmash.tools.application.openshift.input.BinarySource; import org.jboss.intersmash.tools.application.openshift.input.BuildInput; import org.jboss.intersmash.tools.application.openshift.input.BuildInputBuilder; +import org.jboss.intersmash.tools.application.openshift.template.Eap7Template; import org.jboss.intersmash.tools.util.wildfly.Eap7CliScriptBuilder; import cz.xtf.builder.builders.SecretBuilder; @@ -78,6 +80,44 @@ public class OpenShiftProvisionerTestBase { static final String EAP7_TEST_APP_REPO = "https://github.com/openshift/openshift-jee-sample.git"; static final String EAP7_TEST_APP_REF = "master"; + static Eap7TemplateOpenShiftApplication getEap7OpenShiftTemplateApplication() { + return new Eap7TemplateOpenShiftApplication() { + + @Override + public List getCliScript() { + Eap7CliScriptBuilder eapCliScriptBuilder = new Eap7CliScriptBuilder(); + eapCliScriptBuilder.addCommand( + String.format("/system-property=%s:add(value=\"%s\")", WILDFLY_TEST_PROPERTY, WILDFLY_TEST_PROPERTY)); + return eapCliScriptBuilder.build(); + } + + @Override + public Map getParameters() { + Map map = new HashMap<>(); + map.put("SOURCE_REPOSITORY_URL", EAP7_TEST_APP_REPO); + map.put("SOURCE_REPOSITORY_REF", EAP7_TEST_APP_REF); + return Collections.unmodifiableMap(map); + } + + @Override + public List getSecrets() { + List secrets = new ArrayList<>(); + secrets.add(TEST_SECRET); + return Collections.unmodifiableList(secrets); + } + + @Override + public Eap7Template getTemplate() { + return Eap7Template.BASIC; + } + + @Override + public String getName() { + return "eap-test-app"; + } + }; + } + static BootableJarOpenShiftApplication getWildflyBootableJarOpenShiftApplication() { return new BootableJarOpenShiftApplication() { @Override diff --git a/tools/intersmash-tools-core/src/main/java/org/jboss/intersmash/tools/IntersmashConfig.java b/tools/intersmash-tools-core/src/main/java/org/jboss/intersmash/tools/IntersmashConfig.java index f005cccde..de810c6ab 100644 --- a/tools/intersmash-tools-core/src/main/java/org/jboss/intersmash/tools/IntersmashConfig.java +++ b/tools/intersmash-tools-core/src/main/java/org/jboss/intersmash/tools/IntersmashConfig.java @@ -100,6 +100,8 @@ public class IntersmashConfig { // EAP 7.z (i.e. Jakarta EE 8 based WildFly) private static final String EAP7_IMAGE_URL = "intersmash.eap7.image"; private static final String EAP7_RUNTIME_IMAGE_URL = "intersmash.eap7.runtime.image"; + private static final String EAP7_TEMPLATES_BASE_URL = "intersmash.eap7.templates.base.url"; + private static final String EAP7_TEMPLATES_PATH = "intersmash.eap7.templates.path"; // WildFLy Maven Plugin private static final String WILDFLY_MAVEN_PLUGIN_GROUPID = "wildfly-maven-plugin.groupId"; @@ -258,10 +260,18 @@ public static String eap7RuntimeImageUrl() { return XTFConfig.get(EAP7_RUNTIME_IMAGE_URL); } - public static String wildflyJakartaEe8ProductCode() { + public static String eap7ProductCode() { return getProductCode(eap7ImageURL()); } + public static String eap7Templates() { + return XTFConfig.get(EAP7_TEMPLATES_BASE_URL) + XTFConfig.get(EAP7_TEMPLATES_PATH); + } + + public static String eap7ImageStreams() { + return XTFConfig.get(EAP7_TEMPLATES_BASE_URL); + } + public static String getProductCode(final String image) { // truncates "-" // e.g. ..fspolti/processserver64-eap70-openshift:1.3 -> processserver64 diff --git a/tools/intersmash-tools-core/src/main/java/org/jboss/intersmash/tools/provision/openshift/template/OpenShiftTemplateProvisioner.java b/tools/intersmash-tools-core/src/main/java/org/jboss/intersmash/tools/provision/openshift/template/OpenShiftTemplateProvisioner.java index d9d2187fe..25e50325d 100644 --- a/tools/intersmash-tools-core/src/main/java/org/jboss/intersmash/tools/provision/openshift/template/OpenShiftTemplateProvisioner.java +++ b/tools/intersmash-tools-core/src/main/java/org/jboss/intersmash/tools/provision/openshift/template/OpenShiftTemplateProvisioner.java @@ -26,7 +26,6 @@ import cz.xtf.core.openshift.OpenShifts; import io.fabric8.openshift.api.model.ImageStream; import io.fabric8.openshift.api.model.Template; -import io.fabric8.openshift.client.dsl.TemplateResource; /** * Provisioner for OpenShift templates. Its goal is to unify the basic operations we need to do with OpenShift templates. @@ -91,7 +90,7 @@ default Template deployTemplate(OpenShiftTemplate openShiftTemplate) { String url = getTemplateFileUrl(openShiftTemplate); try (InputStream is = new URL(url).openStream()) { // workaround for the API version in the data (v1) does not match the expected API version (image.template.io/v1) - template = (Template) ((TemplateResource) openShift.templates().load(is)).get(); + template = openShift.templates().load(is).item(); template.setApiVersion("template.openshift.io/v1"); if (openShift.getTemplate(template.getMetadata().getName()) == null) { openShift.createTemplate(template); diff --git a/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/application/openshift/Eap7ImageOpenShiftApplication.java b/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/application/openshift/Eap7ImageOpenShiftApplication.java index c92416f7e..b8d8fc168 100644 --- a/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/application/openshift/Eap7ImageOpenShiftApplication.java +++ b/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/application/openshift/Eap7ImageOpenShiftApplication.java @@ -4,9 +4,9 @@ import java.util.List; import org.jboss.intersmash.tools.application.openshift.input.BuildInput; +import org.jboss.intersmash.tools.provision.openshift.Eap7ImageOpenShiftProvisioner; import io.fabric8.kubernetes.api.model.EnvVar; -import org.jboss.intersmash.tools.provision.openshift.Eap7ImageOpenShiftProvisioner; /** * End user Application descriptor interface which presents a AP 7.z (i.e. Jakarta EE 8 based WildFly) application on diff --git a/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/application/openshift/Eap7TemplateOpenShiftApplication.java b/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/application/openshift/Eap7TemplateOpenShiftApplication.java new file mode 100644 index 000000000..dc4fe66f4 --- /dev/null +++ b/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/application/openshift/Eap7TemplateOpenShiftApplication.java @@ -0,0 +1,20 @@ +package org.jboss.intersmash.tools.application.openshift; + +import org.jboss.intersmash.tools.application.openshift.template.Eap7Template; +import org.jboss.intersmash.tools.provision.openshift.Eap7TemplateOpenShiftProvisioner; + +/** + * End user Application descriptor interface which presents EAP 7 template application on OpenShift Container Platform. + * + * See {@link Eap7Template} for available templates the + * application can represent. + * + * The application will be deployed by: + *
    + *
  • {@link Eap7TemplateOpenShiftProvisioner}
  • + *
+ */ +public interface Eap7TemplateOpenShiftApplication + extends WildflyOpenShiftApplication, TemplateApplication { + +} diff --git a/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/application/openshift/template/Eap7Template.java b/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/application/openshift/template/Eap7Template.java new file mode 100644 index 000000000..a7334f230 --- /dev/null +++ b/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/application/openshift/template/Eap7Template.java @@ -0,0 +1,27 @@ +package org.jboss.intersmash.tools.application.openshift.template; + +import org.jboss.intersmash.tools.provision.openshift.template.OpenShiftTemplate; + +/** + * OpenShift template for EAP 7.z (i.e. WildFly Jakarta EE 8 <= 26.1.2) applications. + *

+ * See e.g.: https://github.com/jboss-container-images/jboss-eap-7-openshift-image + */ +public enum Eap7Template implements OpenShiftTemplate { + AMQ_PERSISTENT("amq-persistent"), + AMQ("amq"), + BASIC("basic"), + HTTPS("https"), + SSO("sso"); + + private String name; + + Eap7Template(String name) { + this.name = name; + } + + @Override + public String getLabel() { + return name; + } +} diff --git a/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/provision/openshift/Eap7ImageOpenShiftProvisioner.java b/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/provision/openshift/Eap7ImageOpenShiftProvisioner.java index fa7901fdd..df8f584ed 100644 --- a/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/provision/openshift/Eap7ImageOpenShiftProvisioner.java +++ b/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/provision/openshift/Eap7ImageOpenShiftProvisioner.java @@ -111,7 +111,7 @@ private ApplicationBuilder getAppBuilder() { IntersmashConfig.eap7ImageURL(), binarySource.getArchive(), environmentVariables.stream().collect(Collectors.toMap(EnvVar::getName, EnvVar::getValue)), - application.getName() + "-" + IntersmashConfig.wildflyJakartaEe8ProductCode()); + application.getName() + "-" + IntersmashConfig.eap7ProductCode()); ManagedBuildReference reference = BuildManagers.get().deploy(build); BuildManagers.get().hasBuildCompleted(build).level(Level.DEBUG).waitFor(); diff --git a/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/provision/openshift/Eap7TemplateOpenShiftProvisioner.java b/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/provision/openshift/Eap7TemplateOpenShiftProvisioner.java new file mode 100644 index 000000000..d1d07ed5e --- /dev/null +++ b/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/provision/openshift/Eap7TemplateOpenShiftProvisioner.java @@ -0,0 +1,208 @@ +package org.jboss.intersmash.tools.provision.openshift; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.jboss.intersmash.tools.IntersmashConfig; +import org.jboss.intersmash.tools.application.openshift.Eap7TemplateOpenShiftApplication; +import org.jboss.intersmash.tools.application.openshift.WildflyOpenShiftApplication; +import org.jboss.intersmash.tools.application.openshift.template.Eap7Template; +import org.jboss.intersmash.tools.provision.openshift.template.Eap7TemplateProvisioner; +import org.jboss.intersmash.tools.provision.openshift.template.OpenShiftTemplate; +import org.slf4j.event.Level; + +import cz.xtf.core.config.OpenShiftConfig; +import cz.xtf.core.event.helpers.EventHelper; +import cz.xtf.core.openshift.OpenShiftWaiters; +import cz.xtf.core.openshift.OpenShifts; +import cz.xtf.core.waiting.failfast.FailFastCheck; +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.EnvVarBuilder; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.openshift.api.model.DeploymentConfig; +import io.fabric8.openshift.api.model.ImageStream; +import io.fabric8.openshift.api.model.Template; +import lombok.NonNull; + +public class Eap7TemplateOpenShiftProvisioner + implements OpenShiftProvisioner { + private final Eap7TemplateOpenShiftApplication application; + private final OpenShiftTemplate template; + private List deployedImageStreams; + private Template deployedTemplate; + private FailFastCheck ffCheck = () -> false; + + public Eap7TemplateOpenShiftProvisioner(@NonNull Eap7TemplateOpenShiftApplication application) { + this.application = application; + this.template = application.getTemplate(); + } + + @Override + public Eap7TemplateOpenShiftApplication getApplication() { + return application; + } + + @Override + public void deploy() { + deployTemplate(); + } + + @Override + public void undeploy() { + Map labels = new HashMap<>(2); + labels.put("application", application.getName()); + labels.put(APP_LABEL_KEY, application.getName()); + OpenShiftUtils.deleteResourcesWithLabels(openShift, labels); + // when using geit repo S2I create soe custom maps and build pods + openShift.getConfigMaps() + .stream() + .filter(cfMap -> cfMap.getMetadata().getName().startsWith(application.getName())) + .forEach(openShift::deleteConfigMap); + openShift.getPods() + .stream() + .filter(pod -> pod.getMetadata().getName().startsWith(application.getName())) + .forEach(openShift::deletePod); + deployedImageStreams.forEach(openShift::deleteImageStream); + openShift.deleteTemplate(deployedTemplate); + } + + @Override + public void scale(int replicas, boolean wait) { + openShift.scale(application.getName(), replicas); + if (wait) { + waitForReplicas(replicas); + } + } + + public void waitForReplicas(int replicas) { + OpenShiftWaiters.get(openShift, ffCheck).areExactlyNPodsReady(replicas, application.getName()).level(Level.DEBUG) + .waitFor(); + WaitersUtil.serviceEndpointsAreReady(openShift, getApplication().getName(), replicas, 8080) + .level(Level.DEBUG) + .waitFor(); + if (replicas > 0) { + WaitersUtil.routeIsUp(getUrl(application.getName(), false)) + .level(Level.DEBUG) + .waitFor(); + } + } + + private void deployTemplate() { + // create/update image stream + ffCheck = FailFastUtils.getFailFastCheck(EventHelper.timeOfLastEventBMOrTestNamespaceOrEpoch(), + application.getName()); + Eap7TemplateProvisioner templateProvisioner = new Eap7TemplateProvisioner(); + deployedImageStreams = templateProvisioner.deployImageStreams(); + deployedTemplate = templateProvisioner.deployTemplate(template); + + // env vars + Map params = new HashMap<>(application.getParameters()); + + // Let's be sure that the used template params do carry a reference to the deployed EAP 7 image stream name, + // since the defaults could not be correct. + // For instance, as in the case of EAP 74, where a unique template file exists for each template type, + // and the default value for EAP_IMAGE_NAME would be the one in there, i.e. + // "jboss-eap74-openjdk11-openshift:7.4.0", currently. + // In such a scenario the provisioning would fail if the EAP image is based on open JDK 8, since the deployed + // EAP 7 image stream name would be "jboss-eap74-openjdk8-openshift:7.3" in that case, see: + // * https://github.com/jboss-container-images/jboss-eap-openshift-templates/blob/eap74/eap74-openjdk8-image-stream.json#L16 + // * https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.4/html/getting_started_with_jboss_eap_for_openshift_container_platform/build_run_java_app_s2i#import_imagestreams_templates + // For the reasons above, here we'll set the expected template EAP_IMAGE_URL and EAP_RUNTIME_IMAGE_URL param + // values explicitly, based on the previously deployed resources, in case those were not provided. + if (!params.containsKey("EAP_IMAGE_NAME")) { + // let's build a consistent value for the expected builder image name + Optional deployedBuilderImageNameSearch = deployedImageStreams.stream() + .filter(is -> !is.getMetadata().getName().contains("runtime")) + .findAny() + .map((i) -> String.format("%s:%s", i.getMetadata().getName(), + i.getMetadata().getAnnotations().get("version"))); + if (!deployedBuilderImageNameSearch.isPresent()) { + throw new IllegalStateException(String.format( + "The expected EAP 7 builder image stream was not found in the %s namespace", openShift.getNamespace())); + } + params.put("EAP_IMAGE_NAME", deployedBuilderImageNameSearch.get()); + } + if (!params.containsKey("EAP_RUNTIME_IMAGE_NAME")) { + // and for the runtime one as well + Optional deployedRuntimeImageName = deployedImageStreams.stream() + .filter(is -> is.getMetadata().getName().contains("runtime")) + .map((i) -> String.format("%s:%s", i.getMetadata().getName(), + i.getMetadata().getAnnotations().get("version"))) + .findAny(); + if (!deployedRuntimeImageName.isPresent()) { + throw new IllegalStateException(String.format( + "The expected EAP 7 runtime image stream was not found in the %s namespace", openShift.getNamespace())); + } + params.put("EAP_RUNTIME_IMAGE_NAME", deployedRuntimeImageName.get()); + } + + // map the application configuration + if (!params.containsKey("IMAGE_STREAM_NAMESPACE")) + params.put("IMAGE_STREAM_NAMESPACE", OpenShiftConfig.namespace()); + if (!params.containsKey("APPLICATION_NAME")) + params.put("APPLICATION_NAME", application.getName()); + + if (!params.containsKey("SSO_IMAGE_NAME") && template.equals(Eap7Template.SSO)) { + params.put("SSO_IMAGE_NAME", IntersmashConfig.keycloakImageName()); + } + + // setup context dir + if (!params.containsKey("CONTEXT_DIR")) { + params.put("CONTEXT_DIR", ""); + } + + openShift.processAndDeployTemplate(deployedTemplate.getMetadata().getName(), params); + // run post deploy scripts before waiting, there is a plenty of time (app building) for openshift to deal with it + postDeploy(application); + + OpenShiftWaiters.get(openShift, ffCheck).isDcReady(application.getName()).level(Level.DEBUG).waitFor(); + // by default in all 73 templates there is hardcoded value 1 + // however this is still risky as a template might change or get parametrized + waitForReplicas(1); + } + + private void postDeploy(WildflyOpenShiftApplication eapApplication) { + if (IntersmashConfig.scriptDebug() != null || template.equals(Eap7Template.SSO)) { + DeploymentConfig dc = openShift.getDeploymentConfig(eapApplication.getName()); + if (IntersmashConfig.scriptDebug() != null) { + dc.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv() + .add(new EnvVarBuilder().withName(SCRIPT_DEBUG).withValue(IntersmashConfig.scriptDebug()).build()); + } + openShift.deploymentConfigs().createOrReplace(dc); + } + + // setup cliScript; + if (eapApplication.getCliScript() != null && !eapApplication.getCliScript().isEmpty()) { + // mount postconfigure CLI commands + String postconfigure = "#!/usr/bin/env bash\n" + + "echo \"Executing postconfigure.sh\"\n" + + "$JBOSS_HOME/bin/jboss-cli.sh --file=$JBOSS_HOME/extensions/configure.cli\n"; + ConfigMap cfMap = new ConfigMapBuilder().withNewMetadata() + .withName("jboss-cli") + .withLabels(Collections.singletonMap(APP_LABEL_KEY, eapApplication.getName())) + .endMetadata().addToData("postconfigure.sh", postconfigure) + .addToData("configure.cli", String.join("\n", eapApplication.getCliScript())) + .build(); + openShift.createConfigMap(cfMap); + // TODO make it JAVA https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.3/html-single/getting_started_with_jboss_eap_for_openshift_container_platform/index#custom_scripts + + String output = OpenShifts.masterBinary().execute("set", "volume", "dc/" + eapApplication.getName(), + "--add", "--name=jboss-cli", "-m", "/opt/eap/extensions", "-t", "configmap", "--configmap-name=jboss-cli", + "--default-mode=0755"); + // output is null in case of failure, see ERROR logs + if (output == null) { + throw new RuntimeException( + "Failed to mount CLI custom script to deployment config. See logs for more details."); + } + } + } + + @Override + public List getPods() { + return openShift.getPods(getApplication().getName()); + } +} diff --git a/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/provision/openshift/template/Eap7TemplateProvisioner.java b/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/provision/openshift/template/Eap7TemplateProvisioner.java new file mode 100644 index 000000000..b97664000 --- /dev/null +++ b/tools/intersmash-tools-provisioners/src/main/java/org/jboss/intersmash/tools/provision/openshift/template/Eap7TemplateProvisioner.java @@ -0,0 +1,155 @@ +package org.jboss.intersmash.tools.provision.openshift.template; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import org.jboss.intersmash.tools.IntersmashConfig; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.openshift.api.model.ImageStream; +import io.fabric8.openshift.api.model.TagImportPolicyBuilder; + +public class Eap7TemplateProvisioner implements OpenShiftTemplateProvisioner { + + // supported product versions + // EAP + public static final String SUPPORTED_EAP_VERSION_74 = "eap74"; + public static final String SUPPORTED_EAP_VERSION_XP4 = "eap-xp4"; + public static final String SUPPORTED_JDK_OPENJDK_8 = "openjdk8"; + public static final String SUPPORTED_JDK_OPENJDK_11 = "openjdk11"; + public static final String SUPPORTED_JDK_OPENJDK_17 = "openjdk17"; + + public static final String[] SUPPORTED_EAP_VERSIONS = { SUPPORTED_EAP_VERSION_74, SUPPORTED_EAP_VERSION_XP4 }; + public static final String[] SUPPORTED_JDK_VERSIONS = { SUPPORTED_JDK_OPENJDK_8, SUPPORTED_JDK_OPENJDK_11, + SUPPORTED_JDK_OPENJDK_17 }; + + @Override + public String getTemplatesUrl() { + return IntersmashConfig.eap7Templates(); + } + + @Override + public String getTemplateFileName(OpenShiftTemplate openShiftTemplate) { + final String eapProductCode = getProductCode(); + final String eapJdk = getEapJdk(); + // validate used EAP image product code is allowed + if (!List.of(SUPPORTED_EAP_VERSIONS).stream().anyMatch(allowed -> allowed.equals(eapProductCode))) { + throw new IllegalStateException(String.format("Unsupported EAP product code: %s", eapProductCode)); + } + + // validate used eap image JDK is allowed + if (!List.of(SUPPORTED_JDK_VERSIONS).stream().anyMatch(allowed -> allowed.equals(eapJdk))) { + throw new IllegalStateException("Unsupported JDK version: " + eapJdk); + } + // Don't add any JDK info when dealing with EAP 73 OpenJDK 8 based images or EAP 74 OpenJDK based images since + // template files never include the OpenJDK info, e.g.: + // https://raw.githubusercontent.com/jboss-container-images/jboss-eap-openshift-templates/eap74/templates/eap74-basic-s2i.json + // https://raw.githubusercontent.com/jboss-container-images/jboss-eap-openshift-templates/eap74/templates/eap74-https-s2i.json + // https://raw.githubusercontent.com/jboss-container-images/jboss-eap-7-openshift-image/eap73/templates/eap73-basic-s2i.json + return String.format("%s-%s-s2i", eapProductCode, openShiftTemplate.getLabel()); + } + + /** + * This is a bit different for EAP since the image stream template contains two image streams, one for builder + * image, the other for runtime image. Create both image streams here, but return the list of builder image references + * in order to be aligned with implementations for other products. + *

+ * Update only DockerImage based tags, as the others are just tag references. + * + * @return list of builder image stream references + */ + @Override + public List deployImageStreams() { + List streams = new ArrayList<>(2); + String url = getUsedImageStreamUrl(); + try (InputStream is = new URL(url).openStream()) { + List kubernetesList = openShift.load(is).items(); + for (HasMetadata item : kubernetesList) { + if (item.getMetadata().getName().contains("runtime")) { + ImageStream runtimeImageStream = (ImageStream) item; + // update the DockerImage based tags with EAP runtime image set by configuration + runtimeImageStream.getSpec().getTags().stream() + .filter(tagReference -> tagReference.getFrom().getKind().equals("DockerImage")) + .forEach(tagReference -> { + tagReference.getFrom().setName(IntersmashConfig.eap7ImageURL()); + tagReference.setImportPolicy(new TagImportPolicyBuilder().withInsecure(true).build()); + }); + streams.add(openShift.imageStreams().createOrReplace(runtimeImageStream)); + } else { + ImageStream imageStream = (ImageStream) item; + // update the DockerImage based tags with EAP builder image set by configuration + imageStream.getSpec().getTags().stream() + .filter(tagReference -> tagReference.getFrom().getKind().equals("DockerImage")) + .forEach(tagReference -> { + tagReference.getFrom().setName(IntersmashConfig.eap7ImageURL()); + tagReference.setImportPolicy(new TagImportPolicyBuilder().withInsecure(true).build()); + }); + streams.add(openShift.imageStreams().createOrReplace((ImageStream) item)); + } + } + } catch (IOException e) { + throw new RuntimeException("Failed to deploy EAP 7 image streams from " + url, e); + } + return streams; + } + + @Override + public String getProductCode() { + final String image = IntersmashConfig.eap7ImageURL(); + if (image.matches(".*eap-xp\\d+.*")) { + return image.replaceFirst(".*eap-xp(\\d+).*", "eap-xp$1"); + } else if (image.contains("eap-cd")) { + return "eap-cd"; + } else if (image.matches(".*eap\\d\\d.*")) { + return image.replaceFirst(".*eap(\\d\\d?).*", "eap$1"); + } else { + return IntersmashConfig.getProductCode(image); + } + } + + /** + * Here the actual URL for the used EAP 7 image streams files, depending on the supported EAP 7 version + * + * @return String that represents the URL to the actual EAP 7 image streams files, depending on the supported EAP 7 + * version + */ + private String getUsedImageStreamUrl() { + + final String imageStreamsFileNameSuffix = "-image-stream.json"; + final String eapProductCode = getProductCode(); + final String eapJdk = getEapJdk(); + + // validate used EAP image product code is allowed + if (!List.of(SUPPORTED_EAP_VERSIONS).stream().anyMatch(allowed -> allowed.equals(eapProductCode))) { + throw new IllegalStateException(String.format("Unsupported EAP product code: %s", eapProductCode)); + } + + // validate used eap image JDK is allowed + if (!List.of(SUPPORTED_JDK_VERSIONS).stream().anyMatch(allowed -> allowed.equals(eapJdk))) { + throw new IllegalStateException("Unsupported JDK version: " + eapJdk); + } + + return getImageStreamsUrl() + eapProductCode + + String.format("-%s", eapJdk) + imageStreamsFileNameSuffix; + } + + private String getImageStreamsUrl() { + return IntersmashConfig.eap7ImageStreams(); + } + + private String getEapJdk() { + final String image = IntersmashConfig.eap7ImageURL(); + final String eapProductCode = getProductCode(); + + if (image.matches(".*" + eapProductCode + "-openjdk8.*")) { + return SUPPORTED_JDK_OPENJDK_8; + } else if (image.matches(".*" + eapProductCode + "-openjdk\\d\\d.*")) { + return image.replaceFirst(".*" + eapProductCode + "-openjdk(\\d\\d).*", "openjdk$1"); + } else { + throw new IllegalStateException(String.format("Unsupported JDK: %s", image)); + } + } +}