diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesCommonHelper.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesCommonHelper.java index cfae502c4fc2d..def272daf4b6f 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesCommonHelper.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesCommonHelper.java @@ -166,12 +166,6 @@ public static List createDecorators(Optional projec : AddRoleBindingResourceDecorator.RoleKind.Role)))); } - // The presence of optional is causing issues in OCP 3.11, so we better remove them. - // The following 4 decorator will set the optional property to null, so that it won't make it into the file. - result.add(new DecoratorBuildItem(target, new RemoveOptionalFromSecretEnvSourceDecorator())); - result.add(new DecoratorBuildItem(target, new RemoveOptionalFromConfigMapEnvSourceDecorator())); - result.add(new DecoratorBuildItem(target, new RemoveOptionalFromSecretKeySelectorDecorator())); - result.add(new DecoratorBuildItem(target, new RemoveOptionalFromConfigMapKeySelectorDecorator())); return result; } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftConfig.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftConfig.java index c3d90512c4021..baf3e63bc25fd 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftConfig.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftConfig.java @@ -14,6 +14,19 @@ @ConfigRoot public class OpenshiftConfig implements PlatformConfiguration { + public static enum OpenshiftFlavor { + v3, + v4; + } + + /** + * The OpenShift flavor / version to use. + * Older versions of OpenShift have minor differrences in the labels and fields they support. + * This option allows users to have their manifests automatically aligned to the OpenShift 'flavor' they use. + */ + @ConfigItem(defaultValue = "v4") + OpenshiftFlavor flavor; + /** * The name of the group this component belongs too */ diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftProcessor.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftProcessor.java index f45a21ad6815e..55ae6204be968 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftProcessor.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftProcessor.java @@ -8,6 +8,7 @@ import static io.quarkus.kubernetes.deployment.Constants.OPENSHIFT; import static io.quarkus.kubernetes.deployment.Constants.OPENSHIFT_APP_RUNTIME; import static io.quarkus.kubernetes.deployment.Constants.QUARKUS; +import static io.quarkus.kubernetes.deployment.OpenshiftConfig.OpenshiftFlavor.v3; import static io.quarkus.kubernetes.spi.KubernetesDeploymentTargetBuildItem.DEFAULT_PRIORITY; import java.util.ArrayList; @@ -130,6 +131,20 @@ public List createDecorators(ApplicationInfoBuildItem applic annotations, labels, command, ports, livenessPath, readinessPath, roles, roleBindings)); + if (config.flavor == v3) { + //Openshift 3.x doesn't recognize 'app.kubernetes.io/name', it uses 'app' instead. + //The decorator will be applied even on non-openshift resources is it may affect for example: knative + result.add(new DecoratorBuildItem(new AddLabelDecorator(name, "app", name))); + + // The presence of optional is causing issues in OCP 3.11, so we better remove them. + // The following 4 decorator will set the optional property to null, so that it won't make it into the file. + //The decorators will be applied even on non-openshift resources is they may affect for example: knative + result.add(new DecoratorBuildItem(new RemoveOptionalFromSecretEnvSourceDecorator())); + result.add(new DecoratorBuildItem(new RemoveOptionalFromConfigMapEnvSourceDecorator())); + result.add(new DecoratorBuildItem(new RemoveOptionalFromSecretKeySelectorDecorator())); + result.add(new DecoratorBuildItem(new RemoveOptionalFromConfigMapKeySelectorDecorator())); + } + if (config.getReplicas() != 1) { result.add(new DecoratorBuildItem(OPENSHIFT, new ApplyReplicasDecorator(name, config.getReplicas()))); } diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftV3Test.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftV3Test.java new file mode 100644 index 0000000000000..430d5909cb813 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftV3Test.java @@ -0,0 +1,75 @@ +package io.quarkus.it.kubernetes; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +import org.assertj.core.api.AbstractObjectAssert; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.Service; +import io.quarkus.test.ProdBuildResults; +import io.quarkus.test.ProdModeTestResults; +import io.quarkus.test.QuarkusProdModeTest; + +public class OpenshiftV3Test { + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClasses(GreetingResource.class)) + .setApplicationName("openshift-v3") + .setApplicationVersion("0.1-SNAPSHOT") + .withConfigurationResource("openshift-v3.properties"); + + @ProdBuildResults + private ProdModeTestResults prodModeTestResults; + + @Test + public void assertGeneratedResources() throws IOException { + Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes"); + assertThat(kubernetesDir) + .isDirectoryContaining(p -> p.getFileName().endsWith("openshift.json")) + .isDirectoryContaining(p -> p.getFileName().endsWith("openshift.yml")) + .satisfies(p -> assertThat(p.toFile().listFiles()).hasSize(2)); + List openshiftList = DeserializationUtil + .deserializeAsList(kubernetesDir.resolve("openshift.yml")); + + assertThat(openshiftList).filteredOn(h -> "DeploymentConfig".equals(h.getKind())).singleElement().satisfies(h -> { + assertThat(h.getMetadata()).satisfies(m -> { + assertThat(m.getName()).isEqualTo("openshift-v3"); + assertThat(m.getLabels().get("app.openshift.io/runtime")).isEqualTo("quarkus"); + assertThat(m.getLabels().get("app.kubernetes.io/name")).isEqualTo("openshift-v3"); + assertThat(m.getLabels().get("app")).isEqualTo("openshift-v3"); + assertThat(m.getNamespace()).isNull(); + }); + AbstractObjectAssert specAssert = assertThat(h).extracting("spec"); + specAssert.extracting("selector").isInstanceOfSatisfying(Map.class, selectorsMap -> { + assertThat(selectorsMap).containsOnly(entry("app.kubernetes.io/name", "openshift-v3"), + entry("app.kubernetes.io/version", "0.1-SNAPSHOT")); + }); + }); + + assertThat(openshiftList).filteredOn(h -> "Service".equals(h.getKind())).singleElement().satisfies(h -> { + assertThat(h).isInstanceOfSatisfying(Service.class, s -> { + assertThat(s.getMetadata()).satisfies(m -> { + assertThat(m.getNamespace()).isNull(); + assertThat(m.getLabels().get("app.kubernetes.io/name")).isEqualTo("openshift-v3"); + assertThat(m.getLabels().get("app")).isEqualTo("openshift-v3"); + }); + + assertThat(s.getSpec()).satisfies(spec -> { + assertThat(spec.getSelector()).containsOnly(entry("app.kubernetes.io/name", "openshift-v3"), + entry("app.kubernetes.io/version", "0.1-SNAPSHOT")); + }); + }); + }); + } +} diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftV4Test.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftV4Test.java new file mode 100644 index 0000000000000..96d5ed28fbea5 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/OpenshiftV4Test.java @@ -0,0 +1,75 @@ +package io.quarkus.it.kubernetes; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +import org.assertj.core.api.AbstractObjectAssert; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.Service; +import io.quarkus.test.ProdBuildResults; +import io.quarkus.test.ProdModeTestResults; +import io.quarkus.test.QuarkusProdModeTest; + +public class OpenshiftV4Test { + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClasses(GreetingResource.class)) + .setApplicationName("openshift-v4") + .setApplicationVersion("0.1-SNAPSHOT") + .withConfigurationResource("openshift-v4.properties"); + + @ProdBuildResults + private ProdModeTestResults prodModeTestResults; + + @Test + public void assertGeneratedResources() throws IOException { + Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes"); + assertThat(kubernetesDir) + .isDirectoryContaining(p -> p.getFileName().endsWith("openshift.json")) + .isDirectoryContaining(p -> p.getFileName().endsWith("openshift.yml")) + .satisfies(p -> assertThat(p.toFile().listFiles()).hasSize(2)); + List openshiftList = DeserializationUtil + .deserializeAsList(kubernetesDir.resolve("openshift.yml")); + + assertThat(openshiftList).filteredOn(h -> "DeploymentConfig".equals(h.getKind())).singleElement().satisfies(h -> { + assertThat(h.getMetadata()).satisfies(m -> { + assertThat(m.getName()).isEqualTo("openshift-v4"); + assertThat(m.getLabels().get("app.openshift.io/runtime")).isEqualTo("quarkus"); + assertThat(m.getLabels().get("app.kubernetes.io/name")).isEqualTo("openshift-v4"); + assertThat(m.getLabels().get("app")).isNull(); + assertThat(m.getNamespace()).isNull(); + }); + AbstractObjectAssert specAssert = assertThat(h).extracting("spec"); + specAssert.extracting("selector").isInstanceOfSatisfying(Map.class, selectorsMap -> { + assertThat(selectorsMap).containsOnly(entry("app.kubernetes.io/name", "openshift-v4"), + entry("app.kubernetes.io/version", "0.1-SNAPSHOT")); + }); + }); + + assertThat(openshiftList).filteredOn(h -> "Service".equals(h.getKind())).singleElement().satisfies(h -> { + assertThat(h).isInstanceOfSatisfying(Service.class, s -> { + assertThat(s.getMetadata()).satisfies(m -> { + assertThat(m.getNamespace()).isNull(); + assertThat(m.getLabels().get("app.kubernetes.io/name")).isEqualTo("openshift-v4"); + assertThat(m.getLabels().get("app")).isNull(); + }); + + assertThat(s.getSpec()).satisfies(spec -> { + assertThat(spec.getSelector()).containsOnly(entry("app.kubernetes.io/name", "openshift-v4"), + entry("app.kubernetes.io/version", "0.1-SNAPSHOT")); + }); + }); + }); + } +} diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/openshift-v3.properties b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/openshift-v3.properties new file mode 100644 index 0000000000000..22bc2bebdb904 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/openshift-v3.properties @@ -0,0 +1,2 @@ +quarkus.kubernetes.deployment-target=openshift +quarkus.openshift.flavor=v3 \ No newline at end of file diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/openshift-v4.properties b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/openshift-v4.properties new file mode 100644 index 0000000000000..b1345eed2b92b --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/openshift-v4.properties @@ -0,0 +1,2 @@ +quarkus.kubernetes.deployment-target=openshift +quarkus.openshift.flavor=v4 \ No newline at end of file