proper order fix (#1052)
* proper order fix * trigger * trigger * trigger
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.client.config;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -154,8 +155,8 @@ public final class KubernetesClientConfigUtils {
|
||||
* 4. gather all the names of the secrets + decoded data they hold
|
||||
* </pre>
|
||||
*/
|
||||
static MultipleSourcesContainer secretsDataByName(CoreV1Api client, String namespace, Set<String> sourceNames,
|
||||
Environment environment) {
|
||||
static MultipleSourcesContainer secretsDataByName(CoreV1Api client, String namespace,
|
||||
LinkedHashSet<String> sourceNames, Environment environment) {
|
||||
List<V1Secret> secrets = secretsSearch(client, namespace);
|
||||
if (ConfigUtils.noSources(secrets, namespace)) {
|
||||
return MultipleSourcesContainer.empty();
|
||||
@@ -174,8 +175,8 @@ public final class KubernetesClientConfigUtils {
|
||||
* 4. gather all the names of the config maps + data they hold
|
||||
* </pre>
|
||||
*/
|
||||
static MultipleSourcesContainer configMapsDataByName(CoreV1Api client, String namespace, Set<String> sourceNames,
|
||||
Environment environment) {
|
||||
static MultipleSourcesContainer configMapsDataByName(CoreV1Api client, String namespace,
|
||||
LinkedHashSet<String> sourceNames, Environment environment) {
|
||||
List<V1ConfigMap> configMaps = configMapsSearch(client, namespace);
|
||||
if (ConfigUtils.noSources(configMaps, namespace)) {
|
||||
return MultipleSourcesContainer.empty();
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.client.config;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.config.MultipleSourcesContainer;
|
||||
@@ -43,7 +43,7 @@ final class NamedConfigMapContextToSourceDataProvider implements Supplier<Kubern
|
||||
|
||||
return new NamedSourceData() {
|
||||
@Override
|
||||
public MultipleSourcesContainer dataSupplier(Set<String> sourceNames) {
|
||||
public MultipleSourcesContainer dataSupplier(LinkedHashSet<String> sourceNames) {
|
||||
return KubernetesClientConfigUtils.configMapsDataByName(context.client(), context.namespace(),
|
||||
sourceNames, context.environment());
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.client.config;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.config.MultipleSourcesContainer;
|
||||
@@ -42,7 +42,7 @@ final class NamedSecretContextToSourceDataProvider implements Supplier<Kubernete
|
||||
|
||||
return new NamedSourceData() {
|
||||
@Override
|
||||
public MultipleSourcesContainer dataSupplier(Set<String> sourceNames) {
|
||||
public MultipleSourcesContainer dataSupplier(LinkedHashSet<String> sourceNames) {
|
||||
return KubernetesClientConfigUtils.secretsDataByName(context.client(), context.namespace(),
|
||||
sourceNames, context.environment());
|
||||
}
|
||||
|
||||
@@ -61,15 +61,16 @@ abstract class LabeledConfigMapWithProfileTests {
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* this one is taken from : "green-configmap.green-configmap-k8s.green-configmap-prod".
|
||||
* We find "green-configmap" by labels, also "green-configmap-k8s" and "green-configmap-prod" exists,
|
||||
* because "includeProfileSpecificSources=true" is set.
|
||||
* this one is taken from : ""green-configmap.green-configmap-k8s.green-configmap-prod.green-purple-configmap.green-purple-configmap-k8s"".
|
||||
* We find "green-configmap" by labels, also "green-configmap-k8s", "green-configmap-prod" exists,
|
||||
* because "includeProfileSpecificSources=true" is set. Also "green-purple-configmap" and "green-purple-configmap-k8s"
|
||||
* are found.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testGreen() {
|
||||
this.webClient.get().uri("/labeled-configmap/profile/green").exchange().expectStatus().isOk()
|
||||
.expectBody(String.class).value(Matchers.equalTo("2#6#7"));
|
||||
.expectBody(String.class).value(Matchers.equalTo("2#6#7#eight-ish"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class LabeledConfigMapWithProfileController {
|
||||
|
||||
@GetMapping("/labeled-configmap/profile/green")
|
||||
public String green() {
|
||||
return green.getTwo() + "#" + green.getSix() + "#" + green.getSeven();
|
||||
return green.getTwo() + "#" + green.getSix() + "#" + green.getSeven() + "#" + green.getEight();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ package org.springframework.cloud.kubernetes.client.config.applications.labeled_
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("green-configmap.green-configmap-k8s.green-configmap-prod")
|
||||
@ConfigurationProperties("green-configmap.green-configmap-k8s.green-configmap-prod.green-purple-configmap.green-purple-configmap-k8s")
|
||||
public class Green {
|
||||
|
||||
private String two;
|
||||
@@ -27,6 +27,8 @@ public class Green {
|
||||
|
||||
private String seven;
|
||||
|
||||
private String eight;
|
||||
|
||||
public String getTwo() {
|
||||
return two;
|
||||
}
|
||||
@@ -51,4 +53,12 @@ public class Green {
|
||||
this.seven = seven;
|
||||
}
|
||||
|
||||
public String getEight() {
|
||||
return eight;
|
||||
}
|
||||
|
||||
public void setEight(String eight) {
|
||||
this.eight = eight;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -73,15 +73,16 @@ abstract class LabeledSecretWithProfileTests {
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* this one is taken from : "green-secret.green-secret-k8s.green-secret-prod".
|
||||
* this one is taken from : "green-purple-secret.green-purple-secret-k8s.green-secret.green-secret-k8s.green-secret-prod".
|
||||
* We find "green-secret" by labels, also "green-secrets-k8s" and "green-secrets-prod" exists,
|
||||
* because "includeProfileSpecificSources=true" is set.
|
||||
* because "includeProfileSpecificSources=true" is set. Also "green-purple-secret" and "green-purple-secret-k8s"
|
||||
* are found.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testGreen() {
|
||||
this.webClient.get().uri("/labeled-secret/profile/green").exchange().expectStatus().isOk()
|
||||
.expectBody(String.class).value(Matchers.equalTo("2#6#7"));
|
||||
.expectBody(String.class).value(Matchers.equalTo("2#6#7#eight-ish"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class LabeledSecretWithProfileController {
|
||||
|
||||
@GetMapping("/labeled-secret/profile/green")
|
||||
public String green() {
|
||||
return green.getTwo() + "#" + green.getSix() + "#" + green.getSeven();
|
||||
return green.getTwo() + "#" + green.getSix() + "#" + green.getSeven() + "#" + green.getEight();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ package org.springframework.cloud.kubernetes.client.config.applications.labeled_
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("green-secret.green-secret-k8s.green-secret-prod")
|
||||
@ConfigurationProperties("green-purple-secret.green-purple-secret-k8s.green-secret.green-secret-k8s.green-secret-prod")
|
||||
public class Green {
|
||||
|
||||
private String two;
|
||||
@@ -27,6 +27,8 @@ public class Green {
|
||||
|
||||
private String seven;
|
||||
|
||||
private String eight;
|
||||
|
||||
public String getTwo() {
|
||||
return two;
|
||||
}
|
||||
@@ -51,4 +53,12 @@ public class Green {
|
||||
this.seven = seven;
|
||||
}
|
||||
|
||||
public String getEight() {
|
||||
return eight;
|
||||
}
|
||||
|
||||
public void setEight(String eight) {
|
||||
this.eight = eight;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -64,16 +64,21 @@ public class LabeledConfigMapWithProfileConfigurationStub {
|
||||
return apiClient;
|
||||
}
|
||||
|
||||
/*
|
||||
* <pre> - configmap with name "color-configmap", with labels: "{color: blue}" and
|
||||
* "explicitPrefix: blue" - configmap with name "green-configmap", with labels:
|
||||
* "{color: green}" and "explicitPrefix: blue-again" - configmap with name
|
||||
* "red-configmap", with labels "{color: not-red}" and "useNameAsPrefix: true" -
|
||||
* configmap with name "yellow-configmap" with labels "{color: not-yellow}" and
|
||||
* useNameAsPrefix: true - configmap with name "color-configmap-k8s", with labels :
|
||||
* "{color: not-blue}" - configmap with name "green-configmap-k8s", with labels :
|
||||
* "{color: green-k8s}" - configmap with name "green-configmap-prod", with labels :
|
||||
* "{color: green-prod}" </pre>
|
||||
/**
|
||||
* <pre>
|
||||
* - configmap with name "color-configmap", with labels: "{color: blue}" and "explicitPrefix: blue"
|
||||
* - configmap with name "green-configmap", with labels: "{color: green}" and "explicitPrefix: blue-again"
|
||||
* - configmap with name "red-configmap", with labels "{color: not-red}" and "useNameAsPrefix: true"
|
||||
* - configmap with name "yellow-configmap" with labels "{color: not-yellow}" and useNameAsPrefix: true
|
||||
* - configmap with name "color-configmap-k8s", with labels : "{color: not-blue}"
|
||||
* - configmap with name "green-configmap-k8s", with labels : "{color: green-k8s}"
|
||||
* - configmap with name "green-configmap-prod", with labels : "{color: green-prod}"
|
||||
*
|
||||
* # a test that proves order: first read non-profile based configmaps, thus profile based
|
||||
* # configmaps override non-profile ones.
|
||||
* - configmap with name "green-purple-configmap", labels "{color: green, shape: round}", data: "{eight: 8}"
|
||||
* - configmap with name "green-purple-configmap-k8s", labels "{color: black}", data: "{eight: eight-ish}"
|
||||
* </pre>
|
||||
*/
|
||||
public static void stubData() {
|
||||
|
||||
@@ -118,6 +123,18 @@ public class LabeledConfigMapWithProfileConfigurationStub {
|
||||
.withLabels(Map.of("color", "yellow")).build())
|
||||
.addToData(Collections.singletonMap("four", "4")).build();
|
||||
|
||||
// is found by labels
|
||||
V1ConfigMap greenPurpleConfigMap = new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("green-purple-configmap").withNamespace("spring-k8s")
|
||||
.withLabels(Map.of("color", "green", "shape", "round")).build())
|
||||
.addToData(Collections.singletonMap("eight", "8")).build();
|
||||
|
||||
// is taken and thus overrides the above
|
||||
V1ConfigMap greenPurpleConfigMapK8s = new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("green-purple-configmap-k8s")
|
||||
.withNamespace("spring-k8s").withLabels(Map.of("color", "black")).build())
|
||||
.addToData(Collections.singletonMap("eight", "eight-ish")).build();
|
||||
|
||||
// the actual stub for CoreV1Api calls
|
||||
V1ConfigMapList configMaps = new V1ConfigMapList();
|
||||
configMaps.addItemsItem(colorConfigMap);
|
||||
@@ -127,6 +144,8 @@ public class LabeledConfigMapWithProfileConfigurationStub {
|
||||
configMaps.addItemsItem(greenConfigMapProd);
|
||||
configMaps.addItemsItem(redConfigMap);
|
||||
configMaps.addItemsItem(yellowConfigMap);
|
||||
configMaps.addItemsItem(greenPurpleConfigMap);
|
||||
configMaps.addItemsItem(greenPurpleConfigMapK8s);
|
||||
|
||||
WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/configmaps")
|
||||
.willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(configMaps))));
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.client.config.boostrap.stubs;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -64,15 +65,21 @@ public class LabeledSecretWithProfileConfigurationStub {
|
||||
return apiClient;
|
||||
}
|
||||
|
||||
/*
|
||||
* <pre> - secret with name "color-secret", with labels: "{color: blue}" and
|
||||
* "explicitPrefix: blue" - secret with name "green-secret", with labels:
|
||||
* "{color: green}" and "explicitPrefix: blue-again" - secret with name "red-secret",
|
||||
* with labels "{color: not-red}" and "useNameAsPrefix: true" - secret with name
|
||||
* "yellow-secret" with labels "{color: not-yellow}" and useNameAsPrefix: true -
|
||||
* secret with name "color-secret-k8s", with labels : "{color: not-blue}" - secret
|
||||
* with name "green-secret-k8s", with labels : "{color: green-k8s}" - secret with name
|
||||
* "green-secret-prod", with labels : "{color: green-prod}" </pre>
|
||||
/**
|
||||
* <pre>
|
||||
* - secret with name "color-secret", with labels: "{color: blue}" and "explicitPrefix: blue"
|
||||
* - secret with name "green-secret", with labels: "{color: green}" and "explicitPrefix: blue-again"
|
||||
* - secret with name "red-secret", with labels "{color: not-red}" and "useNameAsPrefix: true"
|
||||
* - secret with name "yellow-secret" with labels "{color: not-yellow}" and useNameAsPrefix: true
|
||||
* - secret with name "color-secret-k8s", with labels : "{color: not-blue}"
|
||||
* - secret with name "green-secret-k8s", with labels : "{color: green-k8s}"
|
||||
* - secret with name "green-secret-prod", with labels : "{color: green-prod}"
|
||||
*
|
||||
* # a test that proves order: first read non-profile based secrets, thus profile based
|
||||
* # secrets override non-profile ones.
|
||||
* - secret with name "green-purple-secret", labels "{color: green, shape: round}", data: "{eight: 8}"
|
||||
* - secret with name "green-purple-secret-k8s", labels "{color: black}", data: "{eight: eight-ish}"
|
||||
* </pre>
|
||||
*/
|
||||
public static void stubData() {
|
||||
|
||||
@@ -80,42 +87,54 @@ public class LabeledSecretWithProfileConfigurationStub {
|
||||
V1Secret colorSecret = new V1SecretBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("color-secret").withNamespace("spring-k8s")
|
||||
.withLabels(Map.of("color", "blue")).build())
|
||||
.addToData(Collections.singletonMap("one", "1".getBytes())).build();
|
||||
.addToData(Collections.singletonMap("one", "1".getBytes(StandardCharsets.UTF_8))).build();
|
||||
|
||||
// is not taken, since "profileSpecificSources=false" for the above
|
||||
V1Secret colorSecretK8s = new V1SecretBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("color-secret-k8s").withNamespace("spring-k8s")
|
||||
.withLabels(Map.of("color", "not-blue")).build())
|
||||
.addToData(Collections.singletonMap("five", "5".getBytes())).build();
|
||||
.addToData(Collections.singletonMap("five", "5".getBytes(StandardCharsets.UTF_8))).build();
|
||||
|
||||
// is found by labels
|
||||
V1Secret greenSecret = new V1SecretBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("green-secret").withNamespace("spring-k8s")
|
||||
.withLabels(Map.of("color", "green")).build())
|
||||
.addToData(Collections.singletonMap("two", "2".getBytes())).build();
|
||||
.addToData(Collections.singletonMap("two", "2".getBytes(StandardCharsets.UTF_8))).build();
|
||||
|
||||
V1Secret greenSecretK8s = new V1SecretBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("green-secret-k8s").withNamespace("spring-k8s")
|
||||
.withLabels(Map.of("color", "green-k8s")).build())
|
||||
.addToData(Collections.singletonMap("six", "6".getBytes())).build();
|
||||
.addToData(Collections.singletonMap("six", "6".getBytes(StandardCharsets.UTF_8))).build();
|
||||
|
||||
// is taken because prod profile is active and "profileSpecificSources=true"
|
||||
V1Secret shapeSecretProd = new V1SecretBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("green-secret-prod").withNamespace("spring-k8s")
|
||||
.withLabels(Map.of("color", "green-prod")).build())
|
||||
.addToData(Collections.singletonMap("seven", "7".getBytes())).build();
|
||||
.addToData(Collections.singletonMap("seven", "7".getBytes(StandardCharsets.UTF_8))).build();
|
||||
|
||||
// not taken
|
||||
V1Secret redSecret = new V1SecretBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("red-secret").withNamespace("spring-k8s")
|
||||
.withLabels(Map.of("color", "not-red")).build())
|
||||
.addToData(Collections.singletonMap("three", "3".getBytes())).build();
|
||||
.addToData(Collections.singletonMap("three", "3".getBytes(StandardCharsets.UTF_8))).build();
|
||||
|
||||
// not taken
|
||||
V1Secret yellowSecret = new V1SecretBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("yellow-secret").withNamespace("spring-k8s")
|
||||
.withLabels(Map.of("color", "not-yellow")).build())
|
||||
.addToData(Collections.singletonMap("four", "4".getBytes())).build();
|
||||
.addToData(Collections.singletonMap("four", "4".getBytes(StandardCharsets.UTF_8))).build();
|
||||
|
||||
// is found by labels
|
||||
V1Secret greenPurpleSecret = new V1SecretBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("green-purple-secret").withNamespace("spring-k8s")
|
||||
.withLabels(Map.of("color", "green", "shape", "round")).build())
|
||||
.addToData(Collections.singletonMap("eight", "8".getBytes(StandardCharsets.UTF_8))).build();
|
||||
|
||||
// is taken and thus overrides the above
|
||||
V1Secret greenPurpleSecretK8s = new V1SecretBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("green-purple-secret-k8s").withNamespace("spring-k8s")
|
||||
.withLabels(Map.of("color", "black")).build())
|
||||
.addToData(Collections.singletonMap("eight", "eight-ish".getBytes(StandardCharsets.UTF_8))).build();
|
||||
|
||||
// the actual stub for CoreV1Api calls
|
||||
V1SecretList secrets = new V1SecretList();
|
||||
@@ -126,6 +145,8 @@ public class LabeledSecretWithProfileConfigurationStub {
|
||||
secrets.addItemsItem(shapeSecretProd);
|
||||
secrets.addItemsItem(redSecret);
|
||||
secrets.addItemsItem(yellowSecret);
|
||||
secrets.addItemsItem(greenPurpleSecret);
|
||||
secrets.addItemsItem(greenPurpleSecretK8s);
|
||||
|
||||
WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/secrets")
|
||||
.willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(secrets))));
|
||||
|
||||
@@ -66,6 +66,11 @@ public class NamedConfigMapWithProfileConfigurationStub {
|
||||
|
||||
public static void stubData() {
|
||||
|
||||
// "one" and "oneFromK8s" also prove the fact that the right order is preserved:
|
||||
// first non-profile based
|
||||
// and only after profile based sources. Thus, properties from "one" are
|
||||
// overridden by the ones from "oneFromK8s".
|
||||
// We have a test that asserts this.
|
||||
V1ConfigMap one = new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("configmap-one").withNamespace("spring-k8s").build())
|
||||
.addToData(Collections.singletonMap("one.property", "one")).build();
|
||||
|
||||
@@ -64,6 +64,12 @@ public class NamedSecretWithProfileConfigurationStub {
|
||||
}
|
||||
|
||||
public static void stubData() {
|
||||
|
||||
// "one" and "oneWithProfile" also prove the fact that the right order is
|
||||
// preserved: first non-profile based
|
||||
// and only after profile based sources. Thus, properties from "one" are
|
||||
// overridden by the ones from "oneWithProfile".
|
||||
// We have a test that asserts this.
|
||||
V1Secret one = new V1SecretBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("secret-one").withNamespace("spring-k8s")
|
||||
.withResourceVersion("1").build())
|
||||
|
||||
@@ -19,11 +19,11 @@ package org.springframework.cloud.kubernetes.commons.config;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -165,25 +165,32 @@ public final class ConfigUtils {
|
||||
* defined order).
|
||||
*/
|
||||
public static MultipleSourcesContainer processNamedData(List<StrippedSourceContainer> strippedSources,
|
||||
Environment environment, Set<String> sourceNames, String namespace, boolean decode) {
|
||||
Environment environment, LinkedHashSet<String> sourceNames, String namespace, boolean decode) {
|
||||
|
||||
Set<String> foundSourceNames = new HashSet<>();
|
||||
Map<String, StrippedSourceContainer> hashByName = strippedSources.stream()
|
||||
.collect(Collectors.toMap(StrippedSourceContainer::name, Function.identity()));
|
||||
|
||||
LinkedHashSet<String> foundSourceNames = new LinkedHashSet<>();
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
|
||||
strippedSources.stream().filter(source -> sourceNames.contains(source.name())).collect(Collectors.toList())
|
||||
.forEach(foundSource -> {
|
||||
String sourceName = foundSource.name();
|
||||
LOG.debug("Found source with name : '" + sourceName + " in namespace: '" + namespace + "'");
|
||||
foundSourceNames.add(sourceName);
|
||||
// see if data is a single yaml/properties file and if it needs
|
||||
// decoding
|
||||
Map<String, String> rawData = foundSource.data();
|
||||
if (decode) {
|
||||
rawData = decodeData(rawData);
|
||||
}
|
||||
data.putAll(SourceDataEntriesProcessor.processAllEntries(rawData == null ? Map.of() : rawData,
|
||||
environment));
|
||||
});
|
||||
// this is an ordered stream, and it means that non-profile based sources will be
|
||||
// processed before profile based sources. This way, we replicate that
|
||||
// "application-dev.yaml"
|
||||
// overrides properties from "application.yaml"
|
||||
sourceNames.forEach(source -> {
|
||||
StrippedSourceContainer stripped = hashByName.get(source);
|
||||
if (stripped != null) {
|
||||
LOG.debug("Found source with name : '" + source + " in namespace: '" + namespace + "'");
|
||||
foundSourceNames.add(source);
|
||||
// see if data is a single yaml/properties file and if it needs decoding
|
||||
Map<String, String> rawData = stripped.data();
|
||||
if (decode) {
|
||||
rawData = decodeData(rawData);
|
||||
}
|
||||
data.putAll(SourceDataEntriesProcessor.processAllEntries(rawData == null ? Map.of() : rawData,
|
||||
environment));
|
||||
}
|
||||
});
|
||||
|
||||
return new MultipleSourcesContainer(foundSourceNames, data);
|
||||
}
|
||||
@@ -200,16 +207,16 @@ public final class ConfigUtils {
|
||||
boolean decode) {
|
||||
|
||||
// find sources by provided labels
|
||||
List<StrippedSourceContainer> sourcesByLabels = containers.stream().filter(one -> {
|
||||
List<StrippedSourceContainer> byLabels = containers.stream().filter(one -> {
|
||||
Map<String, String> sourceLabels = one.labels();
|
||||
Map<String, String> labelsToSearchAgainst = sourceLabels == null ? Map.of() : sourceLabels;
|
||||
return labelsToSearchAgainst.entrySet().containsAll((labels.entrySet()));
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// compute profile based sources (based on the ones we found by labels)
|
||||
// compute profile based source names (based on the ones we found by labels)
|
||||
List<String> sourceNamesByLabelsWithProfile = new ArrayList<>();
|
||||
if (profiles != null && !profiles.isEmpty()) {
|
||||
for (StrippedSourceContainer one : sourcesByLabels) {
|
||||
for (StrippedSourceContainer one : byLabels) {
|
||||
for (String profile : profiles) {
|
||||
String name = one.name() + "-" + profile;
|
||||
sourceNamesByLabelsWithProfile.add(name);
|
||||
@@ -220,15 +227,18 @@ public final class ConfigUtils {
|
||||
// once we know sources by labels (and thus their names), we can find out
|
||||
// profiles based sources from the above. This would get all sources
|
||||
// we are interested in.
|
||||
List<StrippedSourceContainer> sourcesToTake = containers.stream()
|
||||
.filter(one -> sourceNamesByLabelsWithProfile.contains(one.name()))
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
sourcesToTake.addAll(sourcesByLabels);
|
||||
List<StrippedSourceContainer> byProfile = containers.stream()
|
||||
.filter(one -> sourceNamesByLabelsWithProfile.contains(one.name())).collect(Collectors.toList());
|
||||
|
||||
Set<String> sourceNames = new HashSet<>();
|
||||
// this makes sure that we first have "app" and then "app-dev" in the list
|
||||
List<StrippedSourceContainer> all = new ArrayList<>(byLabels.size() + byProfile.size());
|
||||
all.addAll(byLabels);
|
||||
all.addAll(byProfile);
|
||||
|
||||
LinkedHashSet<String> sourceNames = new LinkedHashSet<>();
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
sourcesToTake.forEach(source -> {
|
||||
all.forEach(source -> {
|
||||
String foundSourceName = source.name();
|
||||
LOG.debug("Loaded source with name : '" + foundSourceName + " in namespace: '" + namespace + "'");
|
||||
sourceNames.add(foundSourceName);
|
||||
|
||||
@@ -16,18 +16,19 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.commons.config;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*
|
||||
* Container that stores multiple sources, to be exact their names and their flattenned
|
||||
* data.
|
||||
* data. We force a LinkedHashSet on purpose, to preserve the order of sources.
|
||||
*/
|
||||
public final record MultipleSourcesContainer(Set<String> names, Map<String, Object> data) {
|
||||
public final record MultipleSourcesContainer(LinkedHashSet<String> names, Map<String, Object> data) {
|
||||
|
||||
private static final MultipleSourcesContainer EMPTY = new MultipleSourcesContainer(Set.of(), Map.of());
|
||||
private static final MultipleSourcesContainer EMPTY = new MultipleSourcesContainer(new LinkedHashSet<>(0),
|
||||
Map.of());
|
||||
|
||||
public static MultipleSourcesContainer empty() {
|
||||
return EMPTY;
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.commons.config;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.onException;
|
||||
@@ -32,27 +31,27 @@ import static org.springframework.cloud.kubernetes.commons.config.Constants.PROP
|
||||
*/
|
||||
public abstract class NamedSourceData {
|
||||
|
||||
public final SourceData compute(String initialSourceName, ConfigUtils.Prefix prefix, String target,
|
||||
boolean profileSources, boolean failFast, String namespace, String[] activeProfiles) {
|
||||
public final SourceData compute(String sourceName, ConfigUtils.Prefix prefix, String target, boolean profileSources,
|
||||
boolean failFast, String namespace, String[] activeProfiles) {
|
||||
|
||||
Set<String> sourceNames = new HashSet<>();
|
||||
sourceNames.add(initialSourceName);
|
||||
LinkedHashSet<String> sourceNames = new LinkedHashSet<>();
|
||||
// first comes non-profile based source
|
||||
sourceNames.add(sourceName);
|
||||
|
||||
MultipleSourcesContainer data = MultipleSourcesContainer.empty();
|
||||
String currentSourceName;
|
||||
|
||||
try {
|
||||
if (profileSources) {
|
||||
for (String activeProfile : activeProfiles) {
|
||||
currentSourceName = initialSourceName + "-" + activeProfile;
|
||||
sourceNames.add(currentSourceName);
|
||||
// add all profile based sources _after_ non-profile based one
|
||||
sourceNames.add(sourceName + "-" + activeProfile);
|
||||
}
|
||||
}
|
||||
|
||||
data = dataSupplier(sourceNames);
|
||||
|
||||
if (data.names().isEmpty()) {
|
||||
return new SourceData(ConfigUtils.sourceName(target, initialSourceName, namespace), Map.of());
|
||||
return new SourceData(ConfigUtils.sourceName(target, sourceName, namespace), Map.of());
|
||||
}
|
||||
|
||||
if (prefix != ConfigUtils.Prefix.DEFAULT) {
|
||||
@@ -74,9 +73,10 @@ public abstract class NamedSourceData {
|
||||
/**
|
||||
* Implementation specific (fabric8 or k8s-native) way to get the data from then given
|
||||
* source names.
|
||||
* @param sourceNames the ones that have been configured
|
||||
* @param sourceNames the ones that have been configured, LinkedHashSet in order ot
|
||||
* preserve the order: non-profile source first and then the rest
|
||||
* @return an Entry that holds the names of the source that were found and their data
|
||||
*/
|
||||
public abstract MultipleSourcesContainer dataSupplier(Set<String> sourceNames);
|
||||
public abstract MultipleSourcesContainer dataSupplier(LinkedHashSet<String> sourceNames);
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -161,7 +162,7 @@ public final class Fabric8ConfigUtils {
|
||||
* </pre>
|
||||
*/
|
||||
static MultipleSourcesContainer secretsDataByName(KubernetesClient client, String namespace,
|
||||
Set<String> sourceNames, Environment environment) {
|
||||
LinkedHashSet<String> sourceNames, Environment environment) {
|
||||
List<Secret> secrets = secretsSearch(client, namespace);
|
||||
if (ConfigUtils.noSources(secrets, namespace)) {
|
||||
return MultipleSourcesContainer.empty();
|
||||
@@ -181,7 +182,7 @@ public final class Fabric8ConfigUtils {
|
||||
* </pre>
|
||||
*/
|
||||
static MultipleSourcesContainer configMapsDataByName(KubernetesClient client, String namespace,
|
||||
Set<String> sourceNames, Environment environment) {
|
||||
LinkedHashSet<String> sourceNames, Environment environment) {
|
||||
List<ConfigMap> configMaps = configMapsSearch(client, namespace);
|
||||
if (ConfigUtils.noSources(configMaps, namespace)) {
|
||||
return MultipleSourcesContainer.empty();
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.config.MultipleSourcesContainer;
|
||||
@@ -50,7 +50,7 @@ final class NamedConfigMapContextToSourceDataProvider implements Supplier<Fabric
|
||||
|
||||
return new NamedSourceData() {
|
||||
@Override
|
||||
public MultipleSourcesContainer dataSupplier(Set<String> sourceNames) {
|
||||
public MultipleSourcesContainer dataSupplier(LinkedHashSet<String> sourceNames) {
|
||||
return Fabric8ConfigUtils.configMapsDataByName(context.client(), context.namespace(), sourceNames,
|
||||
context.environment());
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.config.MultipleSourcesContainer;
|
||||
@@ -41,7 +41,7 @@ final class NamedSecretContextToSourceDataProvider implements Supplier<Fabric8Co
|
||||
|
||||
return new NamedSourceData() {
|
||||
@Override
|
||||
public MultipleSourcesContainer dataSupplier(Set<String> sourceNames) {
|
||||
public MultipleSourcesContainer dataSupplier(LinkedHashSet<String> sourceNames) {
|
||||
return Fabric8ConfigUtils.secretsDataByName(context.client(), context.namespace(), sourceNames,
|
||||
context.environment());
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -211,7 +212,9 @@ class Fabric8ConfigUtilsTests {
|
||||
void testSecretDataByNameSecretNotFound() {
|
||||
client.secrets().inNamespace("spring-k8s").create(
|
||||
new SecretBuilder().withMetadata(new ObjectMetaBuilder().withName("my-secret").build()).build());
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.secretsDataByName(client, "spring-k8s", Set.of("nope"),
|
||||
LinkedHashSet<String> names = new LinkedHashSet<>();
|
||||
names.add("nope");
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.secretsDataByName(client, "spring-k8s", names,
|
||||
new MockEnvironment());
|
||||
Assertions.assertEquals(0, result.names().size());
|
||||
Assertions.assertEquals(0, result.data().size());
|
||||
@@ -223,9 +226,11 @@ class Fabric8ConfigUtilsTests {
|
||||
client.secrets().inNamespace("spring-k8s")
|
||||
.create(new SecretBuilder().withMetadata(new ObjectMetaBuilder().withName("my-secret").build())
|
||||
.addToData(Map.of("property", Base64.getEncoder().encodeToString("value".getBytes()))).build());
|
||||
LinkedHashSet<String> names = new LinkedHashSet<>();
|
||||
names.add("my-secret");
|
||||
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.secretsDataByName(client, "spring-k8s",
|
||||
Set.of("my-secret"), new MockEnvironment());
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.secretsDataByName(client, "spring-k8s", names,
|
||||
new MockEnvironment());
|
||||
Assertions.assertEquals(1, result.names().size());
|
||||
Assertions.assertEquals("value", result.data().get("property"));
|
||||
}
|
||||
@@ -242,9 +247,12 @@ class Fabric8ConfigUtilsTests {
|
||||
.create(new SecretBuilder().withMetadata(new ObjectMetaBuilder().withName("my-secret-2").build())
|
||||
.addToData(Map.of("property-2", Base64.getEncoder().encodeToString("value-2".getBytes())))
|
||||
.build());
|
||||
LinkedHashSet<String> names = new LinkedHashSet<>();
|
||||
names.add("my-secret");
|
||||
names.add("my-secret-2");
|
||||
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.secretsDataByName(client, "spring-k8s",
|
||||
Set.of("my-secret", "my-secret-2"), new MockEnvironment());
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.secretsDataByName(client, "spring-k8s", names,
|
||||
new MockEnvironment());
|
||||
Assertions.assertTrue(result.names().contains("my-secret"));
|
||||
Assertions.assertTrue(result.names().contains("my-secret-2"));
|
||||
|
||||
@@ -259,8 +267,11 @@ class Fabric8ConfigUtilsTests {
|
||||
void testConfigMapsDataByNameFoundNoData() {
|
||||
client.configMaps().inNamespace("spring-k8s").create(
|
||||
new ConfigMapBuilder().withMetadata(new ObjectMetaBuilder().withName("my-config-map").build()).build());
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.configMapsDataByName(client, "spring-k8s",
|
||||
Set.of("my-config-map"), new MockEnvironment());
|
||||
LinkedHashSet<String> names = new LinkedHashSet<>();
|
||||
names.add("my-config-map");
|
||||
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.configMapsDataByName(client, "spring-k8s", names,
|
||||
new MockEnvironment());
|
||||
Assertions.assertEquals(Set.of("my-config-map"), result.names());
|
||||
Assertions.assertTrue(result.data().isEmpty());
|
||||
}
|
||||
@@ -270,8 +281,10 @@ class Fabric8ConfigUtilsTests {
|
||||
void testConfigMapsDataByNameNotFound() {
|
||||
client.configMaps().inNamespace("spring-k8s").create(
|
||||
new ConfigMapBuilder().withMetadata(new ObjectMetaBuilder().withName("my-config-map").build()).build());
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.configMapsDataByName(client, "spring-k8s",
|
||||
Set.of("my-config-map-not-found"), new MockEnvironment());
|
||||
LinkedHashSet<String> names = new LinkedHashSet<>();
|
||||
names.add("my-config-map-not-found");
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.configMapsDataByName(client, "spring-k8s", names,
|
||||
new MockEnvironment());
|
||||
Assertions.assertEquals(Set.of(), result.names());
|
||||
Assertions.assertTrue(result.data().isEmpty());
|
||||
}
|
||||
@@ -283,8 +296,11 @@ class Fabric8ConfigUtilsTests {
|
||||
.create(new ConfigMapBuilder().withMetadata(new ObjectMetaBuilder().withName("my-config-map").build())
|
||||
.addToData(Map.of("property", "value")).build());
|
||||
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.configMapsDataByName(client, "spring-k8s",
|
||||
Set.of("my-config-map"), new MockEnvironment());
|
||||
LinkedHashSet<String> names = new LinkedHashSet<>();
|
||||
names.add("my-config-map");
|
||||
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.configMapsDataByName(client, "spring-k8s", names,
|
||||
new MockEnvironment());
|
||||
Assertions.assertEquals(Set.of("my-config-map"), result.names());
|
||||
Assertions.assertEquals(Map.of("property", "value"), result.data());
|
||||
}
|
||||
@@ -297,8 +313,11 @@ class Fabric8ConfigUtilsTests {
|
||||
.create(new ConfigMapBuilder().withMetadata(new ObjectMetaBuilder().withName("my-config-map").build())
|
||||
.addToData(Map.of("application.yaml", "key1: value1")).build());
|
||||
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.configMapsDataByName(client, "spring-k8s",
|
||||
Set.of("my-config-map"), new MockEnvironment());
|
||||
LinkedHashSet<String> names = new LinkedHashSet<>();
|
||||
names.add("my-config-map");
|
||||
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.configMapsDataByName(client, "spring-k8s", names,
|
||||
new MockEnvironment());
|
||||
Assertions.assertEquals(Set.of("my-config-map"), result.names());
|
||||
Assertions.assertEquals(Map.of("key1", "value1"), result.data());
|
||||
}
|
||||
@@ -315,8 +334,12 @@ class Fabric8ConfigUtilsTests {
|
||||
.create(new ConfigMapBuilder().withMetadata(new ObjectMetaBuilder().withName("my-config-map-2").build())
|
||||
.addToData(Map.of("property-2", "value-2")).build());
|
||||
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.configMapsDataByName(client, "spring-k8s",
|
||||
Set.of("my-config-map", "my-config-map-2"), new MockEnvironment());
|
||||
LinkedHashSet<String> names = new LinkedHashSet<>();
|
||||
names.add("my-config-map");
|
||||
names.add("my-config-map-2");
|
||||
|
||||
MultipleSourcesContainer result = Fabric8ConfigUtils.configMapsDataByName(client, "spring-k8s", names,
|
||||
new MockEnvironment());
|
||||
Assertions.assertTrue(result.names().contains("my-config-map"));
|
||||
Assertions.assertTrue(result.names().contains("my-config-map-2"));
|
||||
|
||||
|
||||
@@ -47,6 +47,11 @@ abstract class LabeledConfigMapWithProfileTests {
|
||||
* - configmap with name "color-configmap-k8s", with labels : "{color: not-blue}"
|
||||
* - configmap with name "green-configmap-k8s", with labels : "{color: green-k8s}"
|
||||
* - configmap with name "green-configmap-prod", with labels : "{color: green-prod}"
|
||||
*
|
||||
* # a test that proves order: first read non-profile based configmaps, thus profile based
|
||||
* # configmaps override non-profile ones.
|
||||
* - configmap with name "green-purple-configmap", labels "{color: green, shape: round}", data: "{eight: 8}"
|
||||
* - configmap with name "green-purple-configmap-k8s", labels "{color: black}", data: "{eight: eight-ish}"
|
||||
* </pre>
|
||||
*/
|
||||
static void setUpBeforeClass(KubernetesClient mockClient) {
|
||||
@@ -72,12 +77,12 @@ abstract class LabeledConfigMapWithProfileTests {
|
||||
createConfigMap("green-configmap", greenConfigMap, Collections.singletonMap("color", "green"));
|
||||
|
||||
// is taken because k8s profile is active and "profileSpecificSources=true"
|
||||
Map<String, String> shapeConfigMapK8s = Collections.singletonMap("six", "6");
|
||||
createConfigMap("green-configmap-k8s", shapeConfigMapK8s, Collections.singletonMap("color", "green-k8s"));
|
||||
Map<String, String> greenConfigMapK8s = Collections.singletonMap("six", "6");
|
||||
createConfigMap("green-configmap-k8s", greenConfigMapK8s, Collections.singletonMap("color", "green-k8s"));
|
||||
|
||||
// is taken because prod profile is active and "profileSpecificSources=true"
|
||||
Map<String, String> shapeConfigMapProd = Collections.singletonMap("seven", "7");
|
||||
createConfigMap("green-configmap-prod", shapeConfigMapProd, Collections.singletonMap("color", "green-prod"));
|
||||
Map<String, String> greenConfigMapProd = Collections.singletonMap("seven", "7");
|
||||
createConfigMap("green-configmap-prod", greenConfigMapProd, Collections.singletonMap("color", "green-prod"));
|
||||
|
||||
// not taken
|
||||
Map<String, String> redConfigMap = Collections.singletonMap("three", "3");
|
||||
@@ -87,6 +92,14 @@ abstract class LabeledConfigMapWithProfileTests {
|
||||
Map<String, String> yellowConfigMap = Collections.singletonMap("four", "4");
|
||||
createConfigMap("yellow-configmap", yellowConfigMap, Collections.singletonMap("color", "not-yellow"));
|
||||
|
||||
// is found by labels
|
||||
Map<String, String> greenPurple = Collections.singletonMap("eight", "8");
|
||||
createConfigMap("green-purple-configmap", greenPurple, Map.of("color", "green", "shape", "round"));
|
||||
|
||||
// is taken and thus overrides the above
|
||||
Map<String, String> greenPurpleK8s = Collections.singletonMap("eight", "eight-ish");
|
||||
createConfigMap("green-purple-configmap-k8s", greenPurpleK8s, Map.of("color", "black"));
|
||||
|
||||
}
|
||||
|
||||
private static void createConfigMap(String name, Map<String, String> data, Map<String, String> labels) {
|
||||
@@ -109,15 +122,16 @@ abstract class LabeledConfigMapWithProfileTests {
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* this one is taken from : "green-configmap.green-configmap-k8s.green-configmap-prod".
|
||||
* this one is taken from : "green-configmap.green-configmap-k8s.green-configmap-prod.green-purple-configmap.green-purple-configmap-k8s".
|
||||
* We find "green-configmap" by labels, also "green-configmap-k8s" and "green-configmap-prod" exists,
|
||||
* because "includeProfileSpecificSources=true" is set.
|
||||
* because "includeProfileSpecificSources=true" is set. Also "green-purple-configmap" and "green-purple-configmap-k8s"
|
||||
* are found.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testGreen() {
|
||||
this.webClient.get().uri("/labeled-configmap/profile/green").exchange().expectStatus().isOk()
|
||||
.expectBody(String.class).value(Matchers.equalTo("2#6#7"));
|
||||
.expectBody(String.class).value(Matchers.equalTo("2#6#7#eight-ish"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class LabeledConfigMapWithProfileController {
|
||||
|
||||
@GetMapping("/labeled-configmap/profile/green")
|
||||
public String green() {
|
||||
return green.getTwo() + "#" + green.getSix() + "#" + green.getSeven();
|
||||
return green.getTwo() + "#" + green.getSix() + "#" + green.getSeven() + "#" + green.getEight();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ package org.springframework.cloud.kubernetes.fabric8.config.labeled_config_map_w
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("green-configmap.green-configmap-k8s.green-configmap-prod")
|
||||
@ConfigurationProperties("green-configmap.green-configmap-k8s.green-configmap-prod.green-purple-configmap.green-purple-configmap-k8s")
|
||||
public class Green {
|
||||
|
||||
private String two;
|
||||
@@ -27,6 +27,8 @@ public class Green {
|
||||
|
||||
private String seven;
|
||||
|
||||
private String eight;
|
||||
|
||||
public String getTwo() {
|
||||
return two;
|
||||
}
|
||||
@@ -51,4 +53,12 @@ public class Green {
|
||||
this.seven = seven;
|
||||
}
|
||||
|
||||
public String getEight() {
|
||||
return eight;
|
||||
}
|
||||
|
||||
public void setEight(String eight) {
|
||||
this.eight = eight;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,15 +40,21 @@ abstract class LabeledSecretWithProfileTests {
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
/*
|
||||
* <pre> - secret with name "color-secret", with labels: "{color: blue}" and
|
||||
* "explicitPrefix: blue" - secret with name "green-secret", with labels:
|
||||
* "{color: green}" and "explicitPrefix: blue-again" - secret with name "red-secret",
|
||||
* with labels "{color: not-red}" and "useNameAsPrefix: true" - secret with name
|
||||
* "yellow-secret" with labels "{color: not-yellow}" and useNameAsPrefix: true -
|
||||
* secret with name "color-secret-k8s", with labels : "{color: not-blue}" - secret
|
||||
* with name "green-secret-k8s", with labels : "{color: green-k8s}" - secret with name
|
||||
* "green-secret-prod", with labels : "{color: green-prod}" </pre>
|
||||
/**
|
||||
* <pre>
|
||||
* - secret with name "color-secret", with labels: "{color: blue}" and "explicitPrefix: blue"
|
||||
* - secret with name "green-secret", with labels: "{color: green}" and "explicitPrefix: blue-again"
|
||||
* - secret with name "red-secret", with labels "{color: not-red}" and "useNameAsPrefix: true"
|
||||
* - secret with name "yellow-secret" with labels "{color: not-yellow}" and useNameAsPrefix: true
|
||||
* - secret with name "color-secret-k8s", with labels : "{color: not-blue}"
|
||||
* - secret with name "green-secret-k8s", with labels : "{color: green-k8s}"
|
||||
* - secret with name "green-secret-prod", with labels : "{color: green-prod}"
|
||||
*
|
||||
* # a test that proves order: first read non-profile based secrets, thus profile based
|
||||
* # secrets override non-profile ones.
|
||||
* - secret with name "green-purple-secret", labels "{color: green, shape: round}", data: "{eight: 8}"
|
||||
* - secret with name "green-purple-secret-k8s", labels "{color: black}", data: "{eight: eight-ish}"
|
||||
* </pre>
|
||||
*/
|
||||
static void setUpBeforeClass(KubernetesClient mockClient) {
|
||||
LabeledSecretWithProfileTests.mockClient = mockClient;
|
||||
@@ -95,6 +101,16 @@ abstract class LabeledSecretWithProfileTests {
|
||||
Base64.getEncoder().encodeToString("4".getBytes(StandardCharsets.UTF_8)));
|
||||
createSecret("yellow-secret", yellowSecret, Collections.singletonMap("color", "not-yellow"));
|
||||
|
||||
// is found by labels
|
||||
Map<String, String> greenPurple = Collections.singletonMap("eight",
|
||||
Base64.getEncoder().encodeToString("8".getBytes(StandardCharsets.UTF_8)));
|
||||
createSecret("green-purple-secret", greenPurple, Map.of("color", "green", "shape", "round"));
|
||||
|
||||
// is taken and thus overrides the above
|
||||
Map<String, String> greenPurpleK8s = Collections.singletonMap("eight",
|
||||
Base64.getEncoder().encodeToString("eight-ish".getBytes(StandardCharsets.UTF_8)));
|
||||
createSecret("green-purple-secret-k8s", greenPurpleK8s, Map.of("color", "black"));
|
||||
|
||||
}
|
||||
|
||||
private static void createSecret(String name, Map<String, String> data, Map<String, String> labels) {
|
||||
@@ -117,15 +133,16 @@ abstract class LabeledSecretWithProfileTests {
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* this one is taken from : "green-secret.green-secret-k8s.green-secret-prod".
|
||||
* this one is taken from : "green-purple-secret.green-purple-secret-k8s.green-secret.green-secret-k8s.green-secret-prod".
|
||||
* We find "green-secret" by labels, also "green-secrets-k8s" and "green-secrets-prod" exists,
|
||||
* because "includeProfileSpecificSources=true" is set.
|
||||
* because "includeProfileSpecificSources=true" is set. Also "green-purple-secret" and "green-purple-secret-k8s"
|
||||
* are found.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testGreen() {
|
||||
this.webClient.get().uri("/labeled-secret/profile/green").exchange().expectStatus().isOk()
|
||||
.expectBody(String.class).value(Matchers.equalTo("2#6#7"));
|
||||
.expectBody(String.class).value(Matchers.equalTo("2#6#7#eight-ish"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class LabeledSecretWithProfileController {
|
||||
|
||||
@GetMapping("/labeled-secret/profile/green")
|
||||
public String green() {
|
||||
return green.getTwo() + "#" + green.getSix() + "#" + green.getSeven();
|
||||
return green.getTwo() + "#" + green.getSix() + "#" + green.getSeven() + "#" + green.getEight();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ package org.springframework.cloud.kubernetes.fabric8.config.labeled_secret_with_
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("green-secret.green-secret-k8s.green-secret-prod")
|
||||
@ConfigurationProperties("green-purple-secret.green-purple-secret-k8s.green-secret.green-secret-k8s.green-secret-prod")
|
||||
public class Green {
|
||||
|
||||
private String two;
|
||||
@@ -27,6 +27,8 @@ public class Green {
|
||||
|
||||
private String seven;
|
||||
|
||||
private String eight;
|
||||
|
||||
public String getTwo() {
|
||||
return two;
|
||||
}
|
||||
@@ -51,4 +53,12 @@ public class Green {
|
||||
this.seven = seven;
|
||||
}
|
||||
|
||||
public String getEight() {
|
||||
return eight;
|
||||
}
|
||||
|
||||
public void setEight(String eight) {
|
||||
this.eight = eight;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ abstract class NamedConfigMapWithProfileTests {
|
||||
System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test");
|
||||
System.setProperty(Config.KUBERNETES_HTTP2_DISABLE, "true");
|
||||
|
||||
// the fact that property names are the same, also tests that we evaluate config
|
||||
// map
|
||||
// properties in order: first non-profile ones and then profile based one
|
||||
Map<String, String> one = Collections.singletonMap("one.property", "one");
|
||||
Map<String, String> oneFromKubernetesProfile = Collections.singletonMap("one.property", "one-from-k8s");
|
||||
|
||||
|
||||
@@ -50,6 +50,9 @@ abstract class NamedSecretWithProfileTests {
|
||||
System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test");
|
||||
System.setProperty(Config.KUBERNETES_HTTP2_DISABLE, "true");
|
||||
|
||||
// both "secret-one" and "secret-one-k8s" have the same property "one.property",
|
||||
// but since non-profile based sources are used before profile based sources,
|
||||
// properties from secret "secret-one-k8s" must be visible in our tests.
|
||||
Map<String, String> one = Collections.singletonMap("one.property",
|
||||
Base64.getEncoder().encodeToString("one".getBytes(StandardCharsets.UTF_8)));
|
||||
Map<String, String> oneFromKubernetesProfile = Collections.singletonMap("one.property",
|
||||
|
||||
Reference in New Issue
Block a user