From 364d6aca157a49f2381916ce7b4ba52c27386b43 Mon Sep 17 00:00:00 2001 From: Matheus Cruz Date: Thu, 11 Apr 2024 23:28:24 -0300 Subject: [PATCH] Allow use of prefix on envFrom --- bom/application/pom.xml | 2 +- .../asciidoc/deploying-to-kubernetes.adoc | 34 +++++++++ .../spi/KubernetesEnvBuildItem.java | 41 +++++++---- .../spi/KubernetesEnvBuildItemTest.java | 29 +++++++- .../deployment/ContainerConfig.java | 2 +- .../deployment/DevClusterHelper.java | 1 + .../kubernetes/deployment/EnvConverter.java | 30 +++++++- .../kubernetes/deployment/EnvVarHolder.java | 14 +++- .../deployment/EnvVarValidator.java | 4 +- .../VanillaKubernetesProcessor.java | 1 + .../deployment/EnvVarValidatorTest.java | 24 +++---- ...vFromConfigMapWithPrefixBehaviorsTest.java | 62 +++++++++++++++++ ...tesWithEnvFromConfigMapWithPrefixTest.java | 61 ++++++++++++++++ ...hEnvFromSecretWithPrefixBehaviorsTest.java | 63 +++++++++++++++++ ...rnetesWithEnvFromSecretWithPrefixTest.java | 69 +++++++++++++++++++ ...configmap-with-prefix-behaviors.properties | 1 + ...-env-from-configmap-with-prefix.properties | 1 + ...om-secret-with-prefix-behaviors.properties | 1 + ...ith-env-from-secret-with-prefix.properties | 3 + 19 files changed, 405 insertions(+), 38 deletions(-) create mode 100644 integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromConfigMapWithPrefixBehaviorsTest.java create mode 100644 integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromConfigMapWithPrefixTest.java create mode 100644 integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromSecretWithPrefixBehaviorsTest.java create mode 100644 integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromSecretWithPrefixTest.java create mode 100644 integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-configmap-with-prefix-behaviors.properties create mode 100644 integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-configmap-with-prefix.properties create mode 100644 integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-secret-with-prefix-behaviors.properties create mode 100644 integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-secret-with-prefix.properties diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 246f6401f7dff1..b1b66ff8b860fa 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -164,7 +164,7 @@ 1.8.0 0.27.0 1.6.2 - 4.1.2 + 4.1.3 3.2.0 4.2.1 3.0.4.Final diff --git a/docs/src/main/asciidoc/deploying-to-kubernetes.adoc b/docs/src/main/asciidoc/deploying-to-kubernetes.adoc index 523793c9373bca..92753476d415f4 100644 --- a/docs/src/main/asciidoc/deploying-to-kubernetes.adoc +++ b/docs/src/main/asciidoc/deploying-to-kubernetes.adoc @@ -467,6 +467,23 @@ This would generate the following in the `env` section of your container: optional: false ---- +It's also possible to add a prefix when you are generating env from Secret, the following configuration creates environment variable from Secret with key `foo` adding a prefix `BAR`: + +[source,properties] +---- +quarkus.kubernetes.env.secrets=foo[BAR] +---- + +This would generate the following in the `env` section of your container: +[source,yaml] +---- +- env: + envFrom: + - secretRef: + name: foo + prefix: BAR +---- + ===== Environment variables from ConfigMap To add all key/value pairs from `ConfigMap` as environment variables just apply the following configuration, separating each @@ -512,6 +529,23 @@ This would generate the following in the `env` section of your container: optional: false ---- +It's also possible to add a prefix when you are generating env from ConfigMap, the following configuration creates environment variable from ConfigMap with key `foo` adding a prefix `BAR`: + +[source,properties] +---- +quarkus.kubernetes.env.configmaps=foo[BAR] +---- + +This would generate the following in the `env` section of your container: +[source,yaml] +---- +- env: + envFrom: + - configMapRef: + name: foo + prefix: BAR +---- + ===== Environment variables from fields It's also possible to use the value from another field to add a new environment variable by specifying the path of the field to be used as a source, as follows: diff --git a/extensions/kubernetes/spi/src/main/java/io/quarkus/kubernetes/spi/KubernetesEnvBuildItem.java b/extensions/kubernetes/spi/src/main/java/io/quarkus/kubernetes/spi/KubernetesEnvBuildItem.java index b1880f3be509d4..6a2bf43671004b 100644 --- a/extensions/kubernetes/spi/src/main/java/io/quarkus/kubernetes/spi/KubernetesEnvBuildItem.java +++ b/extensions/kubernetes/spi/src/main/java/io/quarkus/kubernetes/spi/KubernetesEnvBuildItem.java @@ -54,42 +54,45 @@ public boolean mightConflictWith(EnvType type) { private final EnvType type; private final String target; private final boolean oldStyle; + private final String prefix; public static KubernetesEnvBuildItem createFromField(String name, String targetField, String target, boolean... oldStyle) { - return create(name, null, null, null, targetField, target, isOldStyle(oldStyle)); + return create(name, null, null, null, targetField, target, null, isOldStyle(oldStyle)); } - public static KubernetesEnvBuildItem createFromConfigMap(String configMapName, String target, boolean... oldStyle) { - return create(configMapName, null, null, configMapName, null, target, isOldStyle(oldStyle)); + public static KubernetesEnvBuildItem createFromConfigMap(String configMapName, String target, String prefix, + boolean... oldStyle) { + return create(configMapName, null, null, configMapName, null, target, prefix, isOldStyle(oldStyle)); } - public static KubernetesEnvBuildItem createFromSecret(String secretName, String target, boolean... oldStyle) { - return create(secretName, null, secretName, null, null, target, isOldStyle(oldStyle)); + public static KubernetesEnvBuildItem createFromSecret(String secretName, String target, String prefix, + boolean... oldStyle) { + return create(secretName, null, secretName, null, null, target, prefix, isOldStyle(oldStyle)); } public static KubernetesEnvBuildItem createSimpleVar(String name, String value, String target, boolean... oldStyle) { - return create(name, value, null, null, null, target, isOldStyle(oldStyle)); + return create(name, value, null, null, null, target, null, isOldStyle(oldStyle)); } public static KubernetesEnvBuildItem createFromConfigMapKey(String varName, String key, String configmap, String target, - boolean... oldStyle) { - return create(varName, key, null, configmap, null, target, isOldStyle(oldStyle)); + String prefix, boolean... oldStyle) { + return create(varName, key, null, configmap, null, target, prefix, isOldStyle(oldStyle)); } public static KubernetesEnvBuildItem createFromSecretKey(String varName, String key, String secret, String target, - boolean... oldStyle) { - return create(varName, key, secret, null, null, target, isOldStyle(oldStyle)); + String prefix, boolean... oldStyle) { + return create(varName, key, secret, null, null, target, prefix, isOldStyle(oldStyle)); } public static KubernetesEnvBuildItem createFromResourceKey(String varName, String key, String secret, String configmap, String target, boolean... oldStyle) { - return create(varName, key, secret, configmap, null, target, isOldStyle(oldStyle)); + return create(varName, key, secret, configmap, null, target, null, isOldStyle(oldStyle)); } public static KubernetesEnvBuildItem create(String name, String value, String secret, String configmap, String field, - String target, boolean... oldStyle) throws IllegalArgumentException { + String target, String prefix, boolean... oldStyle) throws IllegalArgumentException { final boolean secretPresent = secret != null; final boolean configmapPresent = configmap != null; final boolean valuePresent = value != null; @@ -134,7 +137,7 @@ public static KubernetesEnvBuildItem create(String name, String value, String se } else { type = EnvType.var; } - return new KubernetesEnvBuildItem(name, value, configmap, secret, field, type, target, isOldStyle(oldStyle)); + return new KubernetesEnvBuildItem(name, value, configmap, secret, field, type, target, prefix, isOldStyle(oldStyle)); } private static boolean isOldStyle(boolean[] oldStyle) { @@ -142,7 +145,7 @@ private static boolean isOldStyle(boolean[] oldStyle) { } KubernetesEnvBuildItem(String name, String value, String configmap, String secret, String field, EnvType type, - String target, boolean oldStyle) { + String target, String prefix, boolean oldStyle) { this.name = name; this.value = value; this.configmap = configmap; @@ -150,6 +153,7 @@ private static boolean isOldStyle(boolean[] oldStyle) { this.field = field; this.type = type; this.target = target; + this.prefix = prefix; this.oldStyle = oldStyle; } @@ -185,9 +189,13 @@ public String getTarget() { return target; } + public String getPrefix() { + return prefix; + } + public KubernetesEnvBuildItem newWithTarget(String newTarget) { return new KubernetesEnvBuildItem(this.name, this.value, this.configmap, this.secret, this.field, this.type, newTarget, - this.oldStyle); + this.prefix, this.oldStyle); } public String toString() { @@ -228,6 +236,8 @@ public boolean equals(Object o) { return false; if (field != null ? !field.equals(that.field) : that.field != null) return false; + if (prefix != null ? !prefix.equals(that.prefix) : that.prefix != null) + return false; return type == that.type; } @@ -239,6 +249,7 @@ public int hashCode() { result = 31 * result + (secret != null ? secret.hashCode() : 0); result = 31 * result + (field != null ? field.hashCode() : 0); result = 31 * result + type.hashCode(); + result = 31 * result + (prefix != null ? prefix.hashCode() : 0); return result; } } diff --git a/extensions/kubernetes/spi/src/test/java/io/quarkus/kubernetes/spi/KubernetesEnvBuildItemTest.java b/extensions/kubernetes/spi/src/test/java/io/quarkus/kubernetes/spi/KubernetesEnvBuildItemTest.java index b3f9f6f299c3e7..a22854a8c21107 100644 --- a/extensions/kubernetes/spi/src/test/java/io/quarkus/kubernetes/spi/KubernetesEnvBuildItemTest.java +++ b/extensions/kubernetes/spi/src/test/java/io/quarkus/kubernetes/spi/KubernetesEnvBuildItemTest.java @@ -29,10 +29,11 @@ public class KubernetesEnvBuildItemTest { private static final String TARGET = "target"; private static final String VALUE = "value"; private static final String NAME = "name"; + private static final String PREFIX = "prefix"; @Test public void testCreateSimpleVarFromEnvConfig() { - final KubernetesEnvBuildItem item = create(NAME, VALUE, null, null, null, TARGET); + final KubernetesEnvBuildItem item = create(NAME, VALUE, null, null, null, TARGET, null); assertEquals(var, item.getType()); assertEquals(NAME, item.getName()); assertEquals(VALUE, item.getValue()); @@ -44,7 +45,7 @@ public void testCreateSimpleVarFromEnvConfig() { @Test public void testCreateLoadFromConfigMapFromEnvConfig() { - final KubernetesEnvBuildItem item = create(NAME, null, null, VALUE, null, TARGET); + final KubernetesEnvBuildItem item = create(NAME, null, null, VALUE, null, TARGET, null); assertEquals(configmap, item.getType()); assertEquals(VALUE, item.getName()); assertNull(item.getValue()); @@ -52,4 +53,28 @@ public void testCreateLoadFromConfigMapFromEnvConfig() { assertNull(item.getSecret()); assertNull(item.getField()); } + + @Test + public void testCreateConfigMapWithPrefix() { + final KubernetesEnvBuildItem item = create(NAME, null, null, VALUE, null, TARGET, PREFIX); + assertEquals(configmap, item.getType()); + assertEquals(VALUE, item.getName()); + assertNull(item.getValue()); + assertEquals(VALUE, item.getConfigMap()); + assertNull(item.getSecret()); + assertNull(item.getField()); + assertEquals(PREFIX, item.getPrefix()); + } + + @Test + public void testCreateSecretWithPrefix() { + final KubernetesEnvBuildItem item = create(NAME, null, VALUE, null, null, TARGET, PREFIX); + assertEquals(configmap, item.getType()); + assertEquals(VALUE, item.getName()); + assertNull(item.getValue()); + assertEquals(VALUE, item.getSecret()); + assertNull(item.getSecret()); + assertNull(item.getField()); + assertEquals(PREFIX, item.getPrefix()); + } } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ContainerConfig.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ContainerConfig.java index 6a31c876ee41bd..c7c8253bfadbbe 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ContainerConfig.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ContainerConfig.java @@ -144,7 +144,7 @@ public String getTargetPlatformName() { public Collection convertToEnvs() { return convertToBuildItems().stream() .map(kebi -> new Env(EnvConverter.convertName(kebi.getName()), kebi.getValue(), kebi.getSecret(), - kebi.getConfigMap(), kebi.getField(), null)) + kebi.getConfigMap(), kebi.getField(), null, kebi.getPrefix())) .collect(Collectors.toList()); } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/DevClusterHelper.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/DevClusterHelper.java index a84b86f6b155a9..f5269003a75273 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/DevClusterHelper.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/DevClusterHelper.java @@ -108,6 +108,7 @@ public static List createDecorators(String clusterKind, .withSecret(e.getSecret()) .withConfigmap(e.getConfigMap()) .withField(e.getField()) + .withPrefix(e.getPrefix()) .build()))); }); diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvConverter.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvConverter.java index 531ae2cfc4f6c5..b998743038e0d7 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvConverter.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvConverter.java @@ -4,11 +4,17 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import io.dekorate.kubernetes.config.Env; import io.dekorate.kubernetes.config.EnvBuilder; public class EnvConverter { + static Pattern EXTRACT_PREFIX_PATTERN = Pattern.compile("\\[([a-zA-Z0-9-]+)]$"); + static Pattern EXTRACT_NAME_PATTERN = Pattern.compile("^([a-zA-Z0-9-]+)\\["); + public static Env convert(Map.Entry e) { return convert(e.getValue()).withName(convertName(e.getKey())).build(); } @@ -25,9 +31,13 @@ private static EnvBuilder convert(EnvConfig env) { public static List convert(EnvVarsConfig e) { List envs = new LinkedList<>(); - e.secrets.ifPresent(sl -> sl.forEach(s -> envs.add(new EnvBuilder().withName(convertName(s)).withSecret(s).build()))); + e.secrets.ifPresent(sl -> sl + .forEach(s -> envs.add(new EnvBuilder().withName(convertName(extractName(s))).withSecret(s) + .withPrefix(extractPrefix(s).orElse(null)).build()))); e.configmaps - .ifPresent(cl -> cl.forEach(c -> envs.add(new EnvBuilder().withName(convertName(c)).withConfigmap(c).build()))); + .ifPresent(cl -> cl.forEach(c -> envs + .add(new EnvBuilder().withName(convertName(extractName(c))).withConfigmap(c) + .withPrefix(extractPrefix(c).orElse(null)).build()))); e.vars.forEach((k, v) -> envs.add(new EnvBuilder().withName(convertName(k)).withValue(v.orElse("")).build())); e.fields.forEach((k, v) -> { // env vars from fields need to have their name set in addition to their field field :) @@ -43,4 +53,20 @@ public static List convert(EnvVarsConfig e) { public static String convertName(String name) { return name != null ? name.toUpperCase().replace('-', '_').replace('.', '_').replace('/', '_') : null; } + + public static String extractName(String input) { + Matcher matcher = EXTRACT_NAME_PATTERN.matcher(input); + if (matcher.find()) { + return matcher.group(1); + } + return input; + } + + public static Optional extractPrefix(String input) { + Matcher matcher = EXTRACT_PREFIX_PATTERN.matcher(input); + if (matcher.find()) { + return Optional.of(matcher.group(1)); + } + return Optional.empty(); + } } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvVarHolder.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvVarHolder.java index 511fb1c080b62c..498a1282b6c020 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvVarHolder.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvVarHolder.java @@ -1,7 +1,11 @@ package io.quarkus.kubernetes.deployment; +import static io.quarkus.kubernetes.deployment.EnvConverter.extractName; +import static io.quarkus.kubernetes.deployment.EnvConverter.extractPrefix; + import java.util.Collection; import java.util.Map; +import java.util.Optional; import io.quarkus.kubernetes.spi.KubernetesEnvBuildItem; @@ -43,7 +47,7 @@ default Collection convertToBuildItems() { final String target = getTargetPlatformName(); getEnvVars().forEach((key, envConfig) -> { validator.process(key, envConfig.value, envConfig.secret, envConfig.configmap, envConfig.field, target, - true); + Optional.empty(), true); }); // override old-style with newer versions if present @@ -51,12 +55,16 @@ default Collection convertToBuildItems() { c.vars.forEach((k, v) -> validator.process(KubernetesEnvBuildItem.createSimpleVar(k, v.orElse(""), target))); c.fields.forEach((k, v) -> validator.process(KubernetesEnvBuildItem.createFromField(k, v, target))); c.configmaps - .ifPresent(cl -> cl.forEach(cm -> validator.process(KubernetesEnvBuildItem.createFromConfigMap(cm, target)))); - c.secrets.ifPresent(sl -> sl.forEach(s -> validator.process(KubernetesEnvBuildItem.createFromSecret(s, target)))); + .ifPresent( + cl -> cl.forEach(cm -> validator.process(KubernetesEnvBuildItem.createFromConfigMap(extractName(cm), + target, extractPrefix(cm).orElse(null))))); + c.secrets.ifPresent(sl -> sl.forEach(s -> validator.process(KubernetesEnvBuildItem.createFromSecret(extractName(s), + target, extractPrefix(s).orElse(null))))); c.mapping.forEach( (varName, config) -> validator.process(KubernetesEnvBuildItem.createFromResourceKey(varName, config.withKey, config.fromSecret.orElse(null), config.fromConfigmap.orElse(null), target))); return validator.getBuildItems(); } + } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvVarValidator.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvVarValidator.java index 6d4cbf74e0f2c9..85c62e5aa0f7c7 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvVarValidator.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvVarValidator.java @@ -18,10 +18,10 @@ public class EnvVarValidator { private final Set errors = new HashSet<>(); void process(String name, Optional value, Optional secret, Optional configmap, - Optional field, String target, boolean... oldStyle) { + Optional field, String target, Optional prefix, boolean... oldStyle) { try { final KubernetesEnvBuildItem kebi = KubernetesEnvBuildItem.create(name, value.orElse(null), - secret.orElse(null), configmap.orElse(null), field.orElse(null), target, oldStyle); + secret.orElse(null), configmap.orElse(null), field.orElse(null), target, prefix.orElse(null), oldStyle); process(kebi); } catch (IllegalArgumentException e) { errors.add(e.getMessage()); diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/VanillaKubernetesProcessor.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/VanillaKubernetesProcessor.java index a97429c6cf610c..a482b0030b2104 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/VanillaKubernetesProcessor.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/VanillaKubernetesProcessor.java @@ -232,6 +232,7 @@ public List createDecorators(ApplicationInfoBuildItem applic new AddEnvVarDecorator(ApplicationContainerDecorator.ANY, name, new EnvBuilder().withName(EnvConverter.convertName(e.getName())).withValue(e.getValue()) .withSecret(e.getSecret()).withConfigmap(e.getConfigMap()).withField(e.getField()) + .withPrefix(e.getPrefix()) .build()))); }); diff --git a/extensions/kubernetes/vanilla/deployment/src/test/java/io/quarkus/kubernetes/deployment/EnvVarValidatorTest.java b/extensions/kubernetes/vanilla/deployment/src/test/java/io/quarkus/kubernetes/deployment/EnvVarValidatorTest.java index b0fa7bfcbf901a..747d7052828f3a 100644 --- a/extensions/kubernetes/vanilla/deployment/src/test/java/io/quarkus/kubernetes/deployment/EnvVarValidatorTest.java +++ b/extensions/kubernetes/vanilla/deployment/src/test/java/io/quarkus/kubernetes/deployment/EnvVarValidatorTest.java @@ -55,8 +55,8 @@ void getBuildItemsTwoConflictingItemsShouldFail() { @Test void getBuildItemsTwoRedundantItemsShouldResultInOnlyOneItem() { final String name = "name"; - final KubernetesEnvBuildItem first = KubernetesEnvBuildItem.createFromConfigMap(name, TARGET); - final KubernetesEnvBuildItem second = KubernetesEnvBuildItem.createFromConfigMap(name, TARGET); + final KubernetesEnvBuildItem first = KubernetesEnvBuildItem.createFromConfigMap(name, TARGET, null); + final KubernetesEnvBuildItem second = KubernetesEnvBuildItem.createFromConfigMap(name, TARGET, null); validator.process(first); validator.process(second); final Collection items = validator.getBuildItems(); @@ -69,8 +69,8 @@ void getBuildItemsSimilarlyNamedCompatibleItemsShouldWork() { final String name = "name"; final String value1 = "foo"; final KubernetesEnvBuildItem first = KubernetesEnvBuildItem.createSimpleVar(name, value1, TARGET); - final KubernetesEnvBuildItem second = KubernetesEnvBuildItem.createFromSecret(name, TARGET); - final KubernetesEnvBuildItem third = KubernetesEnvBuildItem.createFromConfigMap(name, TARGET); + final KubernetesEnvBuildItem second = KubernetesEnvBuildItem.createFromSecret(name, TARGET, null); + final KubernetesEnvBuildItem third = KubernetesEnvBuildItem.createFromConfigMap(name, TARGET, null); validator.process(first); validator.process(second); validator.process(third); @@ -117,14 +117,14 @@ void getBuildItemsOldConflictShouldNotPreventNewToWork() { * quarkus.kubernetes.env.secrets=secret * quarkus.kubernetes.env-vars.xxx.secret=secret */ - final KubernetesEnvBuildItem newCM = KubernetesEnvBuildItem.createFromConfigMap("configmap", TARGET); - final KubernetesEnvBuildItem newS = KubernetesEnvBuildItem.createFromSecret("secret", TARGET); + final KubernetesEnvBuildItem newCM = KubernetesEnvBuildItem.createFromConfigMap("configmap", TARGET, null); + final KubernetesEnvBuildItem newS = KubernetesEnvBuildItem.createFromSecret("secret", TARGET, null); validator.process("foo", Optional.empty(), Optional.empty(), Optional.of("configmap"), Optional.empty(), - TARGET, true); + TARGET, Optional.empty(), true); validator.process(newS); validator.process(newCM); validator.process("foo", Optional.empty(), Optional.of("secret"), Optional.empty(), Optional.empty(), - TARGET, true); + TARGET, Optional.empty(), true); Collection items = validator.getBuildItems(); assertEquals(2, items.size()); assertTrue(items.contains(newCM)); @@ -168,7 +168,7 @@ void getBuildItemsDirectAndFromSecretShouldConflict() { final String configmap = "configmap"; final String key = "key"; final KubernetesEnvBuildItem first = KubernetesEnvBuildItem.createSimpleVar(name, value1, TARGET); - final KubernetesEnvBuildItem second = KubernetesEnvBuildItem.createFromConfigMapKey(name, key, configmap, + final KubernetesEnvBuildItem second = KubernetesEnvBuildItem.createFromConfigMapKey(name, key, configmap, null, TARGET); validator.process(first); validator.process(second); @@ -200,10 +200,10 @@ void getBuildItemsUsingOldStyleProcessAndNewStyleCreateForSameItemShouldKeepNewS final String name = "name"; final String configmap = "configmap"; final String key = "key"; - final KubernetesEnvBuildItem first = KubernetesEnvBuildItem.createFromConfigMapKey(name, key, configmap, TARGET); + final KubernetesEnvBuildItem first = KubernetesEnvBuildItem.createFromConfigMapKey(name, key, configmap, null, TARGET); validator.process(first); validator.process(name, Optional.of("oldKey"), Optional.empty(), Optional.of(configmap), Optional.empty(), - TARGET, true); + TARGET, Optional.empty(), true); Collection buildItems = validator.getBuildItems(); assertEquals(1, buildItems.size()); assertTrue(buildItems.contains(first)); @@ -211,7 +211,7 @@ void getBuildItemsUsingOldStyleProcessAndNewStyleCreateForSameItemShouldKeepNewS // check different order validator = new EnvVarValidator(); validator.process(name, Optional.of("oldKey"), Optional.empty(), Optional.of(configmap), Optional.empty(), - TARGET, true); + TARGET, Optional.empty(), true); validator.process(first); buildItems = validator.getBuildItems(); assertEquals(1, buildItems.size()); diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromConfigMapWithPrefixBehaviorsTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromConfigMapWithPrefixBehaviorsTest.java new file mode 100644 index 00000000000000..03af2748ec7326 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromConfigMapWithPrefixBehaviorsTest.java @@ -0,0 +1,62 @@ +package io.quarkus.it.kubernetes; + +import io.fabric8.kubernetes.api.model.ConfigMapEnvSource; +import io.fabric8.kubernetes.api.model.EnvFromSource; +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.quarkus.test.ProdBuildResults; +import io.quarkus.test.ProdModeTestResults; +import io.quarkus.test.QuarkusProdModeTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class KubernetesWithEnvFromConfigMapWithPrefixBehaviorsTest { + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .withApplicationRoot((jar) -> jar.addClasses(GreetingResource.class)) + .setApplicationName("env-from-config-map-with-prefix-behaviors") + .setApplicationVersion("0.1-SNAPSHOT") + .withConfigurationResource("kubernetes-with-env-from-config-map-with-prefix-behaviors.properties"); + + @ProdBuildResults + private ProdModeTestResults prodModeTestResults; + + @Test + public void assertGeneratedResources() throws IOException { + Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes"); + assertThat(kubernetesDir) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.json")) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.yml")); + List kubernetesList = DeserializationUtil + .deserializeAsList(kubernetesDir.resolve("kubernetes.yml")); + assertThat(kubernetesList.get(0)).isInstanceOfSatisfying(Deployment.class, d -> { + assertThat(d.getMetadata()).satisfies(m -> { + assertThat(m.getName()).isEqualTo("env-from-config-map-with-prefix-behaviors"); + }); + + assertThat(d.getSpec()).satisfies(deploymentSpec -> { + assertThat(deploymentSpec.getTemplate()).satisfies(t -> { + assertThat(t.getSpec()).satisfies(podSpec -> { + assertThat(podSpec.getContainers()).singleElement().satisfies(container -> { + + assertThat(container.getEnvFrom()).containsExactlyInAnyOrder( + new EnvFromSource( + new ConfigMapEnvSource("another", true), "QUARKUS", null), + new EnvFromSource( + new ConfigMapEnvSource("without", true), null, null), + new EnvFromSource( + new ConfigMapEnvSource("configmap", true), "HELLO", null)); + }); + }); + }); + }); + }); + } +} diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromConfigMapWithPrefixTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromConfigMapWithPrefixTest.java new file mode 100644 index 00000000000000..1010568ce929b8 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromConfigMapWithPrefixTest.java @@ -0,0 +1,61 @@ +package io.quarkus.it.kubernetes; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +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.apps.Deployment; +import io.quarkus.test.ProdBuildResults; +import io.quarkus.test.ProdModeTestResults; +import io.quarkus.test.QuarkusProdModeTest; + +public class KubernetesWithEnvFromConfigMapWithPrefixTest { + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .withApplicationRoot((jar) -> jar.addClasses(GreetingResource.class)) + .setApplicationName("env-from-config-map-with-prefix") + .setApplicationVersion("0.1-SNAPSHOT") + .withConfigurationResource("kubernetes-with-env-from-config-map-with-prefix.properties"); + + @ProdBuildResults + private ProdModeTestResults prodModeTestResults; + + @Test + public void assertGeneratedResources() throws IOException { + Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes"); + assertThat(kubernetesDir) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.json")) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.yml")); + List kubernetesList = DeserializationUtil + .deserializeAsList(kubernetesDir.resolve("kubernetes.yml")); + assertThat(kubernetesList.get(0)).isInstanceOfSatisfying(Deployment.class, d -> { + assertThat(d.getMetadata()).satisfies(m -> { + assertThat(m.getName()).isEqualTo("env-from-config-map-with-prefix"); + }); + + assertThat(d.getSpec()).satisfies(deploymentSpec -> { + assertThat(deploymentSpec.getTemplate()).satisfies(t -> { + assertThat(t.getSpec()).satisfies(podSpec -> { + assertThat(podSpec.getContainers()).singleElement().satisfies(container -> { + + assertThat(container.getEnvFrom()) + .singleElement().satisfies(env -> { + assertThat(env.getPrefix()).isEqualTo("QUARKUS"); + assertThat(env.getConfigMapRef()).satisfies(configMapRef -> { + assertThat(configMapRef.getName()).isEqualTo("my-config-map"); + }); + }); + }); + }); + }); + }); + }); + } +} diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromSecretWithPrefixBehaviorsTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromSecretWithPrefixBehaviorsTest.java new file mode 100644 index 00000000000000..f703eea6a207d6 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromSecretWithPrefixBehaviorsTest.java @@ -0,0 +1,63 @@ +package io.quarkus.it.kubernetes; + +import io.fabric8.kubernetes.api.model.ConfigMapEnvSource; +import io.fabric8.kubernetes.api.model.EnvFromSource; +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.SecretEnvSource; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.quarkus.test.ProdBuildResults; +import io.quarkus.test.ProdModeTestResults; +import io.quarkus.test.QuarkusProdModeTest; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class KubernetesWithEnvFromSecretWithPrefixBehaviorsTest { + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .withApplicationRoot((jar) -> jar.addClasses(GreetingResource.class)) + .setApplicationName("env-from-secret-with-prefix") + .setApplicationVersion("0.1-SNAPSHOT") + .withConfigurationResource("kubernetes-with-env-from-secret-with-prefix-behaviors.properties"); + + @ProdBuildResults + private ProdModeTestResults prodModeTestResults; + + @Test + public void assertGeneratedResources() throws IOException { + Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes"); + assertThat(kubernetesDir) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.json")) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.yml")); + List kubernetesList = DeserializationUtil + .deserializeAsList(kubernetesDir.resolve("kubernetes.yml")); + assertThat(kubernetesList.get(0)).isInstanceOfSatisfying(Deployment.class, d -> { + assertThat(d.getMetadata()).satisfies(m -> { + assertThat(m.getName()).isEqualTo("env-from-secret-with-prefix-behaviors"); + }); + + assertThat(d.getSpec()).satisfies(deploymentSpec -> { + assertThat(deploymentSpec.getTemplate()).satisfies(t -> { + assertThat(t.getSpec()).satisfies(podSpec -> { + assertThat(podSpec.getContainers()).singleElement().satisfies(container -> { + assertThat(container.getEnvFrom()).containsExactlyInAnyOrder( + new EnvFromSource( + null, "QUARKUS", new SecretEnvSource("another", true)), + new EnvFromSource( + null, "HELLO", new SecretEnvSource("secrets", true)), + new EnvFromSource( + null, null, new SecretEnvSource("without", true))); + }); + }); + }); + }); + }); + } +} diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromSecretWithPrefixTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromSecretWithPrefixTest.java new file mode 100644 index 00000000000000..985c374f711a30 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromSecretWithPrefixTest.java @@ -0,0 +1,69 @@ +package io.quarkus.it.kubernetes; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +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.apps.Deployment; +import io.quarkus.test.ProdBuildResults; +import io.quarkus.test.ProdModeTestResults; +import io.quarkus.test.QuarkusProdModeTest; + +public class KubernetesWithEnvFromSecretWithPrefixTest { + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .withApplicationRoot((jar) -> jar.addClasses(GreetingResource.class)) + .setApplicationName("env-from-secret-with-prefix") + .setApplicationVersion("0.1-SNAPSHOT") + .withConfigurationResource("kubernetes-with-env-from-secret-with-prefix.properties"); + + @ProdBuildResults + private ProdModeTestResults prodModeTestResults; + + @Test + public void assertGeneratedResources() throws IOException { + Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes"); + assertThat(kubernetesDir) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.json")) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.yml")); + List kubernetesList = DeserializationUtil + .deserializeAsList(kubernetesDir.resolve("kubernetes.yml")); + assertThat(kubernetesList.get(0)).isInstanceOfSatisfying(Deployment.class, d -> { + assertThat(d.getMetadata()).satisfies(m -> { + assertThat(m.getName()).isEqualTo("env-from-secret-with-prefix"); + }); + + assertThat(d.getSpec()).satisfies(deploymentSpec -> { + assertThat(deploymentSpec.getTemplate()).satisfies(t -> { + assertThat(t.getSpec()).satisfies(podSpec -> { + assertThat(podSpec.getContainers()).singleElement().satisfies(container -> { + assertThat(container.getEnvFrom()).singleElement().satisfies(env -> { + assertThat(env.getPrefix()).isEqualTo("QUARKUS"); + assertThat(env.getSecretRef()).satisfies(secretRef -> { + assertThat(secretRef.getName()).isEqualTo("my-secret"); + }); + }); + + assertThat(container.getEnv()).filteredOn(env -> "DB_PASSWORD".equals(env.getName())) + .singleElement().satisfies(env -> { + assertThat(env.getValueFrom()).satisfies(valueFrom -> { + assertThat(valueFrom.getSecretKeyRef()).satisfies(secretKeyRef -> { + assertThat(secretKeyRef.getKey()).isEqualTo("database.password"); + assertThat(secretKeyRef.getName()).isEqualTo("db-secret"); + }); + }); + }); + }); + }); + }); + }); + }); + } +} diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-configmap-with-prefix-behaviors.properties b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-configmap-with-prefix-behaviors.properties new file mode 100644 index 00000000000000..bf8354d1681435 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-configmap-with-prefix-behaviors.properties @@ -0,0 +1 @@ +quarkus.kubernetes.configmaps.secrets=configmap[PREFIX],another[QUARKUS][ANOTHER],configmap[HELLO],without \ No newline at end of file diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-configmap-with-prefix.properties b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-configmap-with-prefix.properties new file mode 100644 index 00000000000000..d24ec13d883cf0 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-configmap-with-prefix.properties @@ -0,0 +1 @@ +quarkus.kubernetes.env.configmaps=my-config-map[QUARKUS],another-config-map[QUARKIVERSE] diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-secret-with-prefix-behaviors.properties b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-secret-with-prefix-behaviors.properties new file mode 100644 index 00000000000000..955dae7c515298 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-secret-with-prefix-behaviors.properties @@ -0,0 +1 @@ +quarkus.kubernetes.env.secrets=secrets[PREFIX],another[QUARKUS][ANOTHER],secrets[HELLO],without \ No newline at end of file diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-secret-with-prefix.properties b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-secret-with-prefix.properties new file mode 100644 index 00000000000000..6b2ca39c198ef6 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-secret-with-prefix.properties @@ -0,0 +1,3 @@ +quarkus.kubernetes.env.secrets=my-secret[QUARKUS] +quarkus.kubernetes.env.mapping.db-password.from-secret=db-secret +quarkus.kubernetes.env.mapping.db-password.with-key=database.password