diff --git a/bom/application/pom.xml b/bom/application/pom.xml index cef5201c031928..70aa537c9ab892 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -154,7 +154,7 @@ 1.8.1 0.27.0 1.7.0 - 4.1.2 + 4.1.3 3.2.0 4.2.1 3.0.6.Final diff --git a/docs/src/main/asciidoc/deploying-to-kubernetes.adoc b/docs/src/main/asciidoc/deploying-to-kubernetes.adoc index 3d68a1fae1803e..1b4cfdf2fe4e8c 100644 --- a/docs/src/main/asciidoc/deploying-to-kubernetes.adoc +++ b/docs/src/main/asciidoc/deploying-to-kubernetes.adoc @@ -467,6 +467,25 @@ This would generate the following in the `env` section of your container: optional: false ---- +It is 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 +quarkus.kubernetes.env.prefix."BAR".from-secret=foo +---- + +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 +531,24 @@ This would generate the following in the `env` section of your container: optional: false ---- +It is 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 +quarkus.kubernetes.prefix."BAR".from-configmap=foo +---- + +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..41612db62653eb 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 @@ -15,6 +15,7 @@ import static io.quarkus.kubernetes.spi.KubernetesEnvBuildItem.create; import static io.quarkus.kubernetes.spi.KubernetesEnvBuildItem.EnvType.configmap; +import static io.quarkus.kubernetes.spi.KubernetesEnvBuildItem.EnvType.secret; import static io.quarkus.kubernetes.spi.KubernetesEnvBuildItem.EnvType.var; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -29,10 +30,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 +46,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 +54,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(secret, item.getType()); + assertEquals(VALUE, item.getName()); + assertNull(item.getValue()); + assertEquals(VALUE, item.getSecret()); + assertNull(item.getConfigMap()); + 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..7d20ae1d9e9e2c 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,14 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; import io.dekorate.kubernetes.config.Env; import io.dekorate.kubernetes.config.EnvBuilder; public class EnvConverter { + public static Env convert(Map.Entry e) { return convert(e.getValue()).withName(convertName(e.getKey())).build(); } @@ -25,9 +28,16 @@ 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()))); + + Map prefixMap = collectPrefixes(e); + + e.secrets.ifPresent(sl -> sl + .forEach(s -> envs.add(new EnvBuilder().withName(convertName(s)).withSecret(s) + .withPrefix(extractSecretPrefix(s, prefixMap).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(c)).withConfigmap(c) + .withPrefix(extractConfigmapPrefix(c, prefixMap).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,22 @@ public static List convert(EnvVarsConfig e) { public static String convertName(String name) { return name != null ? name.toUpperCase().replace('-', '_').replace('.', '_').replace('/', '_') : null; } + + public static Optional extractSecretPrefix(String secret, Map mappingWithPrefix) { + return mappingWithPrefix.entrySet().stream() + .filter(m -> m.getValue().hasPrefixForSecret(secret)) + .findFirst().map(Map.Entry::getKey); + } + + public static Optional extractConfigmapPrefix(String configmap, + Map mappingWithPrefix) { + return mappingWithPrefix.entrySet().stream() + .filter(m -> m.getValue().hasPrefixForConfigmap(configmap)) + .findFirst().map(Map.Entry::getKey); + } + + public static Map collectPrefixes(EnvVarsConfig e) { + return e.prefix.entrySet().stream().filter(p -> p.getValue().anyPresent() && !p.getKey().isBlank()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } } 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..e3b1a4af2bd0a6 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,12 @@ package io.quarkus.kubernetes.deployment; +import static io.quarkus.kubernetes.deployment.EnvConverter.collectPrefixes; +import static io.quarkus.kubernetes.deployment.EnvConverter.extractConfigmapPrefix; +import static io.quarkus.kubernetes.deployment.EnvConverter.extractSecretPrefix; + import java.util.Collection; import java.util.Map; +import java.util.Optional; import io.quarkus.kubernetes.spi.KubernetesEnvBuildItem; @@ -43,20 +48,26 @@ 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 final EnvVarsConfig c = getEnv(); + Map prefixMap = collectPrefixes(c); + 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(cm, + target, extractConfigmapPrefix(cm, prefixMap).orElse(null))))); + c.secrets.ifPresent(sl -> sl.forEach(s -> validator.process(KubernetesEnvBuildItem.createFromSecret(s, + target, extractSecretPrefix(s, prefixMap).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/EnvVarPrefixConfig.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvVarPrefixConfig.java new file mode 100644 index 00000000000000..8f361d5329637f --- /dev/null +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvVarPrefixConfig.java @@ -0,0 +1,60 @@ +/** + * Copyright 2020 Red Hat, Inc. and/or its affiliates. + * + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.quarkus.kubernetes.deployment; + +import java.util.Optional; + +import io.quarkus.runtime.annotations.ConfigGroup; +import io.quarkus.runtime.annotations.ConfigItem; + +/** + * The configuration of environment variables prefix. + * It is used with quarkus.kubernetes.env.secrets and quarkus.kubernetes.env.configmaps to specify the + * prefix to use when adding the environment variable to the container. + */ +@ConfigGroup +public class EnvVarPrefixConfig { + + /** + * The optional prefix to use when adding the environment variable to the container. + */ + @ConfigItem + Optional fromSecret; + + /** + * The optional prefix to use when adding the environment variable to the container. + */ + @ConfigItem + Optional fromConfigmap; + + public boolean anyPresent() { + return fromSecret.isPresent() || fromConfigmap.isPresent(); + } + + public boolean hasConfigmap() { + return fromConfigmap.isPresent(); + } + + public boolean hasSecret() { + return fromSecret.isPresent(); + } + + public boolean hasPrefixForSecret(String secret) { + return fromSecret.map(s -> s.equals(secret)).orElse(false); + } + + public boolean hasPrefixForConfigmap(String configmap) { + return fromConfigmap.map(c -> c.equals(configmap)).orElse(false); + } +} 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/EnvVarsConfig.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvVarsConfig.java index 95ff8ea865e4e5..ee55679d9a7c93 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvVarsConfig.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/EnvVarsConfig.java @@ -44,4 +44,10 @@ public class EnvVarsConfig { */ @ConfigItem Map mapping; + + /** + * The map recording the configuration of environment variable prefix. + */ + @ConfigItem + Map prefix; } 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..891380beb64216 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromConfigMapWithPrefixBehaviorsTest.java @@ -0,0 +1,63 @@ +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 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-configmap-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()).hasSize(3); + assertThat(container.getEnvFrom()) + .anyMatch(item -> item.getConfigMapRef().getName().equals("another") + && !item.getPrefix().isBlank()); + assertThat(container.getEnvFrom()) + .anyMatch(item -> item.getConfigMapRef().getName().equals("configmap") + && !item.getPrefix().isBlank()); + assertThat(container.getEnvFrom()).anyMatch( + item -> item.getConfigMapRef().getName().equals("without") && item.getPrefix() == 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..4bc4120a251b02 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromConfigMapWithPrefixTest.java @@ -0,0 +1,60 @@ +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-configmap-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()).satisfies(env -> { + + assertThat(env).anyMatch(item -> item.getPrefix().equals("QUARKUS") && + item.getConfigMapRef().getName().equals("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..5e06646bee03e0 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithEnvFromSecretWithPrefixBehaviorsTest.java @@ -0,0 +1,62 @@ +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 KubernetesWithEnvFromSecretWithPrefixBehaviorsTest { + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .withApplicationRoot((jar) -> jar.addClasses(GreetingResource.class)) + .setApplicationName("env-from-secret-with-prefix-behaviors") + .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()) + .anyMatch(item -> item.getPrefix() != null && !item.getPrefix().isBlank() + && item.getSecretRef().getName().equals("another")); + assertThat(container.getEnvFrom()) + .anyMatch(item -> item.getPrefix() != null && !item.getPrefix().isBlank() + && item.getSecretRef().getName().equals("secrets")); + assertThat(container.getEnvFrom()).anyMatch( + item -> item.getPrefix() == null && item.getSecretRef().getName().equals("without")); + }); + }); + }); + }); + }); + } +} 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..faaaa717a5d66a --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-configmap-with-prefix-behaviors.properties @@ -0,0 +1,11 @@ +quarkus.kubernetes.env.configmaps=configmap,another,without + +quarkus.kubernetes.env.prefix."PREFIX".from-configmap=configmap +quarkus.kubernetes.env.prefix."QUARKUS".from-configmap=another + +# should be ignored because was declared later +quarkus.kubernetes.env.prefix."ANOTHER".from-configmap=another +quarkus.kubernetes.env.prefix."HELLO".from-configmap=configmap + +# blank +quarkus.kubernetes.env.prefix."".from-configmap=without 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..5e40a3730ac34b --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-configmap-with-prefix.properties @@ -0,0 +1,3 @@ +quarkus.kubernetes.env.configmaps=my-config-map,another-config-map +quarkus.kubernetes.env.prefix."QUARKUS".from-configmap=my-config-map +quarkus.kubernetes.env.prefix."QUARKIVERSE".from-configmap=another-config-map 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..89f5521920177f --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-secret-with-prefix-behaviors.properties @@ -0,0 +1,10 @@ +quarkus.kubernetes.env.secrets=secrets,another,without + +# the order is not guaranteed by the extension +quarkus.kubernetes.env.prefix."HELLO".from-secret=secrets +quarkus.kubernetes.env.prefix."QUARKUS".from-secret=another +quarkus.kubernetes.env.prefix."ANOTHER".from-secret=another +quarkus.kubernetes.env.prefix."PREFIX".from-secret=secrets + +# blank +quarkus.kubernetes.env.prefix."".from-secret=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..51c9f0ac30e8ec --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-env-from-secret-with-prefix.properties @@ -0,0 +1,4 @@ +quarkus.kubernetes.env.secrets=my-secret +quarkus.kubernetes.env.prefix."QUARKUS".from-secret=my-secret +quarkus.kubernetes.env.mapping.db-password.from-secret=db-secret +quarkus.kubernetes.env.mapping.db-password.with-key=database.password \ No newline at end of file