named secrets add support for prefix (#1009)

This commit is contained in:
erabii
2022-05-23 16:26:30 +03:00
committed by GitHub
parent d5eebcb7c1
commit 19a4e98d6f
80 changed files with 1482 additions and 556 deletions

View File

@@ -52,8 +52,7 @@ public class KubernetesClientConfigMapPropertySource extends ConfigMapPropertySo
// we need to pass various functions because the code we are interested in
// is protected in ConfigMapPropertySource, and must stay that way.
private static KubernetesClientContextToSourceData namedConfigMap() {
return NamedConfigMapContextToSourceDataProvider.of(ConfigMapPropertySource::processAllEntries,
ConfigMapPropertySource::getSourceName, ConfigMapPropertySource::withPrefix).get();
return NamedConfigMapContextToSourceDataProvider.of(ConfigMapPropertySource::processAllEntries).get();
}
}

View File

@@ -52,11 +52,11 @@ public class KubernetesClientSecretsPropertySource extends SecretsPropertySource
}
private static KubernetesClientContextToSourceData namedSecret() {
return NamedSecretContextToSourceDataProvider.of(SecretsPropertySource::getSourceName).get();
return new NamedSecretContextToSourceDataProvider().get();
}
private static KubernetesClientContextToSourceData labeledSecret() {
return LabeledSecretContextToSourceDataProvider.of(SecretsPropertySource::getSourceName).get();
return new LabeledSecretContextToSourceDataProvider().get();
}
}

View File

@@ -19,8 +19,6 @@ package org.springframework.cloud.kubernetes.client.config;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -29,6 +27,7 @@ import io.kubernetes.client.openapi.models.V1Secret;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.kubernetes.commons.config.ConfigUtils;
import org.springframework.cloud.kubernetes.commons.config.LabeledSecretNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.SourceData;
@@ -46,14 +45,8 @@ final class LabeledSecretContextToSourceDataProvider implements Supplier<Kuberne
private static final Log LOG = LogFactory.getLog(LabeledSecretContextToSourceDataProvider.class);
private final BiFunction<String, String, String> sourceNameMapper;
LabeledSecretContextToSourceDataProvider() {
private LabeledSecretContextToSourceDataProvider(BiFunction<String, String, String> sourceNameFunction) {
this.sourceNameMapper = Objects.requireNonNull(sourceNameFunction);
}
static LabeledSecretContextToSourceDataProvider of(BiFunction<String, String, String> sourceNameFunction) {
return new LabeledSecretContextToSourceDataProvider(sourceNameFunction);
}
/*
@@ -96,7 +89,7 @@ final class LabeledSecretContextToSourceDataProvider implements Supplier<Kuberne
onException(source.failFast(), message, e);
}
String propertySourceName = sourceNameMapper.apply(sourceName, namespace);
String propertySourceName = ConfigUtils.sourceName(source.target(), sourceName, namespace);
return new SourceData(propertySourceName, result);
};
}

View File

@@ -24,7 +24,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -32,13 +31,12 @@ import io.kubernetes.client.openapi.ApiException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.kubernetes.commons.config.ConfigMapPrefixContext;
import org.springframework.cloud.kubernetes.commons.config.ConfigUtils;
import org.springframework.cloud.kubernetes.commons.config.NamedConfigMapNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.NormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.PrefixContext;
import org.springframework.cloud.kubernetes.commons.config.SourceData;
import org.springframework.core.env.Environment;
import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.getApplicationName;
import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.onException;
import static org.springframework.cloud.kubernetes.commons.config.Constants.PROPERTY_SOURCE_NAME_SEPARATOR;
@@ -54,24 +52,14 @@ final class NamedConfigMapContextToSourceDataProvider implements Supplier<Kubern
private final BiFunction<Map<String, String>, Environment, Map<String, Object>> entriesProcessor;
private final BiFunction<String, String, String> sourceNameMapper;
private final Function<ConfigMapPrefixContext, SourceData> withPrefix;
private NamedConfigMapContextToSourceDataProvider(
BiFunction<Map<String, String>, Environment, Map<String, Object>> entriesProcessor,
BiFunction<String, String, String> sourceNameMapper,
Function<ConfigMapPrefixContext, SourceData> withPrefix) {
BiFunction<Map<String, String>, Environment, Map<String, Object>> entriesProcessor) {
this.entriesProcessor = Objects.requireNonNull(entriesProcessor);
this.sourceNameMapper = Objects.requireNonNull(sourceNameMapper);
this.withPrefix = Objects.requireNonNull(withPrefix);
}
static NamedConfigMapContextToSourceDataProvider of(
BiFunction<Map<String, String>, Environment, Map<String, Object>> entriesProcessor,
BiFunction<String, String, String> sourceNameMapper,
Function<ConfigMapPrefixContext, SourceData> withPrefix) {
return new NamedConfigMapContextToSourceDataProvider(entriesProcessor, sourceNameMapper, withPrefix);
BiFunction<Map<String, String>, Environment, Map<String, Object>> entriesProcessor) {
return new NamedConfigMapContextToSourceDataProvider(entriesProcessor);
}
@Override
@@ -83,7 +71,7 @@ final class NamedConfigMapContextToSourceDataProvider implements Supplier<Kubern
// namespace has to be read from context, not from the normalized source
String namespace = context.namespace();
Environment environment = context.environment();
String configMapName = appName(environment, source).get();
String configMapName = source.name().orElseThrow();
Set<String> propertySourceNames = new LinkedHashSet<>();
propertySourceNames.add(configMapName);
@@ -117,9 +105,9 @@ final class NamedConfigMapContextToSourceDataProvider implements Supplier<Kubern
});
if (!"".equals(source.prefix())) {
ConfigMapPrefixContext prefixContext = new ConfigMapPrefixContext(result, source.prefix(),
namespace, propertySourceNames);
return withPrefix.apply(prefixContext);
PrefixContext prefixContext = new PrefixContext(result, source.prefix(), namespace,
propertySourceNames);
return ConfigUtils.withPrefix(source.target(), prefixContext);
}
}
@@ -132,13 +120,9 @@ final class NamedConfigMapContextToSourceDataProvider implements Supplier<Kubern
}
String propertySourceTokens = String.join(PROPERTY_SOURCE_NAME_SEPARATOR, propertySourceNames);
return new SourceData(sourceNameMapper.apply(propertySourceTokens, namespace), result);
return new SourceData(ConfigUtils.sourceName(source.target(), propertySourceTokens, namespace), result);
};
}
private Supplier<String> appName(Environment environment, NormalizedSource normalizedSource) {
return () -> getApplicationName(environment, normalizedSource.name().orElse(null), normalizedSource.target());
}
}

View File

@@ -17,17 +17,19 @@
package org.springframework.cloud.kubernetes.client.config;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.Set;
import java.util.function.Supplier;
import io.kubernetes.client.openapi.models.V1Secret;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.kubernetes.commons.config.ConfigUtils;
import org.springframework.cloud.kubernetes.commons.config.NamedSecretNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.PrefixContext;
import org.springframework.cloud.kubernetes.commons.config.SourceData;
import static org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigUtils.dataFromSecret;
@@ -43,14 +45,7 @@ final class NamedSecretContextToSourceDataProvider implements Supplier<Kubernete
private static final Log LOG = LogFactory.getLog(NamedSecretContextToSourceDataProvider.class);
private final BiFunction<String, String, String> sourceNameMapper;
private NamedSecretContextToSourceDataProvider(BiFunction<String, String, String> sourceNameFunction) {
this.sourceNameMapper = Objects.requireNonNull(sourceNameFunction);
}
static NamedSecretContextToSourceDataProvider of(BiFunction<String, String, String> sourceNameFunction) {
return new NamedSecretContextToSourceDataProvider(sourceNameFunction);
NamedSecretContextToSourceDataProvider() {
}
@Override
@@ -58,6 +53,8 @@ final class NamedSecretContextToSourceDataProvider implements Supplier<Kubernete
return context -> {
NamedSecretNormalizedSource source = (NamedSecretNormalizedSource) context.normalizedSource();
Set<String> propertySourceNames = new LinkedHashSet<>();
propertySourceNames.add(source.name().orElseThrow());
Map<String, Object> result = new HashMap<>();
String namespace = context.namespace();
@@ -75,13 +72,19 @@ final class NamedSecretContextToSourceDataProvider implements Supplier<Kubernete
secret.ifPresent(s -> result.putAll(dataFromSecret(s, namespace)));
if (!"".equals(source.prefix()) && !result.isEmpty()) {
PrefixContext prefixContext = new PrefixContext(result, source.prefix(), namespace,
propertySourceNames);
return ConfigUtils.withPrefix(source.target(), prefixContext);
}
}
catch (Exception e) {
String message = "Unable to read Secret with name '" + name + "' in namespace '" + namespace + "'";
onException(source.failFast(), message, e);
}
String propertySourceName = sourceNameMapper.apply(name, namespace);
String propertySourceName = ConfigUtils.sourceName(source.target(), name, namespace);
return new SourceData(propertySourceName, result);
};

View File

@@ -29,7 +29,6 @@ import io.kubernetes.client.openapi.models.V1ConfigMapBuilder;
import io.kubernetes.client.openapi.models.V1ConfigMapList;
import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder;
import io.kubernetes.client.util.ClientBuilder;
import org.junit.ClassRule;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
@@ -68,8 +67,7 @@ public class KubernetesClientConfigReloadAutoConfigurationTest {
private ConfigurableApplicationContext context;
@ClassRule
public static WireMockServer wireMockServer = new WireMockServer(options().dynamicPort());
public static WireMockServer wireMockServer;
protected void setup(String... env) {
List<String> envList = (env != null) ? new ArrayList<>(Arrays.asList(env)) : new ArrayList<>();
@@ -86,13 +84,14 @@ public class KubernetesClientConfigReloadAutoConfigurationTest {
}
@BeforeAll
public static void startWireMockServer() {
static void startWireMockServer() {
wireMockServer = new WireMockServer(options().dynamicPort());
wireMockServer.start();
WireMock.configureFor(wireMockServer.port());
}
@AfterEach
public void afterEach() {
void afterEach() {
if (this.context != null) {
this.context.close();
this.context = null;
@@ -100,7 +99,7 @@ public class KubernetesClientConfigReloadAutoConfigurationTest {
}
@BeforeEach
public void beforeEach() {
void beforeEach() {
V1ConfigMapList TEST_CONFIGMAP = new V1ConfigMapList().addItemsItem(new V1ConfigMapBuilder().withMetadata(
new V1ObjectMetaBuilder().withName("test-cm").withNamespace("default").withResourceVersion("1").build())
.addToData("app.name", "test").build());
@@ -112,7 +111,7 @@ public class KubernetesClientConfigReloadAutoConfigurationTest {
// 1. watchers
@Test
public void kubernetesWatchersWhenKubernetesDisabled() throws Exception {
void kubernetesWatchersWhenKubernetesDisabled() throws Exception {
setup();
assertThat(context.containsBean("configMapPropertySourceLocator")).isFalse();
assertThat(context.containsBean("secretsPropertySourceLocator")).isFalse();
@@ -123,7 +122,7 @@ public class KubernetesClientConfigReloadAutoConfigurationTest {
}
@Test
public void kubernetesWatchersWhenConfigDisabled() throws Exception {
void kubernetesWatchersWhenConfigDisabled() throws Exception {
setup("spring.cloud.kubernetes.config.enabled=false");
assertThat(context.containsBean("configMapPropertyChangePollingWatcher")).isFalse();
assertThat(context.containsBean("secretsPropertyChangePollingWatcher")).isFalse();
@@ -132,7 +131,7 @@ public class KubernetesClientConfigReloadAutoConfigurationTest {
}
@Test
public void kubernetesWatchersWhenReloadDisabled() throws Exception {
void kubernetesWatchersWhenReloadDisabled() throws Exception {
setup("spring.cloud.kubernetes.reload.enabled=false");
assertThat(context.containsBean("configMapPropertyChangePollingWatcher")).isFalse();
assertThat(context.containsBean("secretsPropertyChangePollingWatcher")).isFalse();
@@ -141,7 +140,7 @@ public class KubernetesClientConfigReloadAutoConfigurationTest {
}
@Test
public void kubernetesReloadEnabledButSecretAndConfigDisabled() throws Exception {
void kubernetesReloadEnabledButSecretAndConfigDisabled() throws Exception {
setup("spring.cloud.kubernetes.reload.enabled=true", "spring.cloud.kubernetes.config.enabled=false",
"spring.cloud.kubernetes.secrets.enabled=false");
assertThat(context.containsBean("configMapPropertyChangePollingWatcher")).isFalse();
@@ -151,7 +150,7 @@ public class KubernetesClientConfigReloadAutoConfigurationTest {
}
@Test
public void kubernetesReloadEnabledWithPolling() throws Exception {
void kubernetesReloadEnabledWithPolling() throws Exception {
setup("spring.cloud.kubernetes.reload.enabled=true", "spring.cloud.kubernetes.reload.mode=polling",
"spring.main.cloud-platform=KUBERNETES");
assertThat(context.containsBean("configMapPropertySourceLocator")).isTrue();
@@ -163,7 +162,7 @@ public class KubernetesClientConfigReloadAutoConfigurationTest {
}
@Test
public void kubernetesReloadEnabledWithEvent() throws Exception {
void kubernetesReloadEnabledWithEvent() throws Exception {
setup("spring.cloud.kubernetes.reload.enabled=true", "spring.cloud.kubernetes.reload.mode=event",
"spring.main.cloud-platform=KUBERNETES");
assertThat(context.containsBean("configMapPropertyChangePollingWatcher")).isFalse();
@@ -175,21 +174,21 @@ public class KubernetesClientConfigReloadAutoConfigurationTest {
// 2. config and secrets property source locators
@Test
public void kubernetesConfigAndSecretEnabledByDefault() throws Exception {
void kubernetesConfigAndSecretEnabledByDefault() throws Exception {
setup("spring.main.cloud-platform=KUBERNETES");
assertThat(context.containsBean("configMapPropertySourceLocator")).isTrue();
assertThat(context.containsBean("secretsPropertySourceLocator")).isTrue();
}
@Test
public void kubernetesConfigEnabledButSecretDisabled() throws Exception {
void kubernetesConfigEnabledButSecretDisabled() throws Exception {
setup("spring.cloud.kubernetes.secrets.enabled=false", "spring.main.cloud-platform=KUBERNETES");
assertThat(context.containsBean("configMapPropertySourceLocator")).isTrue();
assertThat(context.containsBean("secretsPropertySourceLocator")).isFalse();
}
@Test
public void kubernetesSecretsEnabledButConfigDisabled() throws Exception {
void kubernetesSecretsEnabledButConfigDisabled() throws Exception {
setup("spring.cloud.kubernetes.config.enabled=false", "spring.main.cloud-platform=KUBERNETES");
assertThat(context.containsBean("configMapPropertySourceLocator")).isFalse();
assertThat(context.containsBean("secretsPropertySourceLocator")).isTrue();

View File

@@ -80,7 +80,7 @@ class KubernetesClientSecretsPropertySourceLocatorTests {
private static final MockEnvironment ENV = new MockEnvironment();
@BeforeAll
public static void setup() {
static void setup() {
wireMockServer = new WireMockServer(options().dynamicPort());
wireMockServer.start();
@@ -92,12 +92,12 @@ class KubernetesClientSecretsPropertySourceLocatorTests {
}
@AfterAll
public static void after() {
static void after() {
wireMockServer.stop();
}
@AfterEach
public void afterEach() {
void afterEach() {
WireMock.reset();
}
@@ -160,7 +160,7 @@ class KubernetesClientSecretsPropertySourceLocatorTests {
}
@Test
public void locateShouldThrowExceptionOnFailureWhenFailFastIsEnabled() {
void locateShouldThrowExceptionOnFailureWhenFailFastIsEnabled() {
CoreV1Api api = new CoreV1Api();
stubFor(get(LIST_API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error")));
@@ -178,7 +178,7 @@ class KubernetesClientSecretsPropertySourceLocatorTests {
}
@Test
public void locateShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled() {
void locateShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled() {
CoreV1Api api = new CoreV1Api();
stubFor(get(LIST_API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error")));

View File

@@ -119,7 +119,7 @@ class KubernetesClientSecretsPropertySourceTests {
CoreV1Api api = new CoreV1Api();
stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(SECRET_LIST))));
NormalizedSource source = new NamedSecretNormalizedSource("db-secret", "default", false);
NormalizedSource source = new NamedSecretNormalizedSource("db-secret", "default", false, "");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, "default",
new MockEnvironment());
@@ -151,7 +151,7 @@ class KubernetesClientSecretsPropertySourceTests {
CoreV1Api api = new CoreV1Api();
stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error")));
NormalizedSource source = new NamedSecretNormalizedSource("secret", "default", true);
NormalizedSource source = new NamedSecretNormalizedSource("secret", "default", true, "");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, "default",
new MockEnvironment());
@@ -166,7 +166,7 @@ class KubernetesClientSecretsPropertySourceTests {
CoreV1Api api = new CoreV1Api();
stubFor(get(API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error")));
NormalizedSource source = new NamedSecretNormalizedSource("secret", "db-secret", false);
NormalizedSource source = new NamedSecretNormalizedSource("secret", "db-secret", false, "");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, "default",
new MockEnvironment());

View File

@@ -38,7 +38,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.cloud.kubernetes.commons.config.LabeledSecretNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.NormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySource;
import org.springframework.cloud.kubernetes.commons.config.SourceData;
import org.springframework.mock.env.MockEnvironment;
@@ -101,11 +100,10 @@ class LabeledSecretContextToSourceDataProviderTests {
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE,
new MockEnvironment());
KubernetesClientContextToSourceData data = LabeledSecretContextToSourceDataProvider
.of(LabeledSecretContextToSourceDataProviderTests.Dummy::sourceName).get();
KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.color.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.color.default");
Assertions.assertEquals(sourceData.sourceData(), Collections.emptyMap());
}
@@ -130,11 +128,10 @@ class LabeledSecretContextToSourceDataProviderTests {
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE,
new MockEnvironment());
KubernetesClientContextToSourceData data = LabeledSecretContextToSourceDataProvider
.of(LabeledSecretContextToSourceDataProviderTests.Dummy::sourceName).get();
KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.test-secret.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.test-secret.default");
Assertions.assertEquals(sourceData.sourceData(), Map.of("color", "really-red"));
}
@@ -164,11 +161,10 @@ class LabeledSecretContextToSourceDataProviderTests {
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE,
new MockEnvironment());
KubernetesClientContextToSourceData data = LabeledSecretContextToSourceDataProvider
.of(LabeledSecretContextToSourceDataProviderTests.Dummy::sourceName).get();
KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.color-one.color-two.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.color-one.color-two.default");
Assertions.assertEquals(sourceData.sourceData().size(), 2);
Assertions.assertEquals(sourceData.sourceData().get("colorOne"), "really-red-one");
Assertions.assertEquals(sourceData.sourceData().get("colorTwo"), "really-red-two");
@@ -190,25 +186,11 @@ class LabeledSecretContextToSourceDataProviderTests {
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE,
new MockEnvironment());
KubernetesClientContextToSourceData data = LabeledSecretContextToSourceDataProvider
.of(LabeledSecretContextToSourceDataProviderTests.Dummy::sourceName).get();
KubernetesClientContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.test-secret.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.test-secret.default");
Assertions.assertEquals(sourceData.sourceData(), Map.of("color", "really-red"));
}
// needed only to allow access to the super methods
private static final class Dummy extends SecretsPropertySource {
private Dummy() {
super(SourceData.emptyRecord("dummy-name"));
}
private static String sourceName(String name, String namespace) {
return getSourceName(name, namespace);
}
}
}

View File

@@ -34,7 +34,6 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.kubernetes.commons.config.ConfigMapPrefixContext;
import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySource;
import org.springframework.cloud.kubernetes.commons.config.NamedConfigMapNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.NormalizedSource;
@@ -95,8 +94,8 @@ class NamedConfigMapContextToSourceDataProviderTests {
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE,
new MockEnvironment());
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries)
.get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.blue.default");
@@ -124,8 +123,8 @@ class NamedConfigMapContextToSourceDataProviderTests {
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE,
new MockEnvironment());
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries)
.get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.red.default");
@@ -160,8 +159,8 @@ class NamedConfigMapContextToSourceDataProviderTests {
environment.setActiveProfiles("with-profile");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment);
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries)
.get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.red.red-with-profile.default");
@@ -201,8 +200,8 @@ class NamedConfigMapContextToSourceDataProviderTests {
environment.setActiveProfiles("with-profile");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment);
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries)
.get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.red.red-with-profile.default");
@@ -248,8 +247,8 @@ class NamedConfigMapContextToSourceDataProviderTests {
environment.setActiveProfiles("with-taste", "with-shape");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE, environment);
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries)
.get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.red.red-with-taste.red-with-shape.default");
@@ -260,11 +259,11 @@ class NamedConfigMapContextToSourceDataProviderTests {
}
// this test makes sure that even if NormalizedSource has no name (which is a valid
// case for config maps),
// it will default to "application" and such a config map will be read.
// when reading config maps and creating normalized sources, we will always be
// providing a name
// for the config map; even if one is not provided explicitly.
@Test
void matchWithoutName() {
void matchWithName() {
V1ConfigMapList configMapList = new V1ConfigMapList()
.addItemsItem(new V1ConfigMapBuilder().withMetadata(new V1ObjectMetaBuilder().withName("application")
.withNamespace(NAMESPACE).withResourceVersion("1").build()).addToData("color", "red").build());
@@ -272,12 +271,12 @@ class NamedConfigMapContextToSourceDataProviderTests {
CoreV1Api api = new CoreV1Api();
stubFor(get("/api/v1/namespaces/default/configmaps")
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(configMapList))));
NormalizedSource source = new NamedConfigMapNormalizedSource(null, NAMESPACE, true, "some", false);
NormalizedSource source = new NamedConfigMapNormalizedSource("application", NAMESPACE, true, "some", false);
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE,
new MockEnvironment());
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries)
.get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.application.default");
@@ -308,8 +307,8 @@ class NamedConfigMapContextToSourceDataProviderTests {
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE,
new MockEnvironment());
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
KubernetesClientContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries)
.get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.red.default");
@@ -323,18 +322,10 @@ class NamedConfigMapContextToSourceDataProviderTests {
super(SourceData.emptyRecord("dummy-name"));
}
private static String sourceName(String name, String namespace) {
return getSourceName(name, namespace);
}
private static Map<String, Object> processEntries(Map<String, String> map, Environment environment) {
return processAllEntries(map, environment);
}
private static SourceData prefix(ConfigMapPrefixContext context) {
return withPrefix(context);
}
}
}

View File

@@ -36,7 +36,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.cloud.kubernetes.commons.config.NamedSecretNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.NormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySource;
import org.springframework.cloud.kubernetes.commons.config.SourceData;
import org.springframework.mock.env.MockEnvironment;
@@ -85,14 +84,14 @@ class NamedSecretContextToSourceDataProviderTests {
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(secretList))));
// blue does not match red
NormalizedSource source = new NamedSecretNormalizedSource("red", NAMESPACE, false);
NormalizedSource source = new NamedSecretNormalizedSource("red", NAMESPACE, false, "");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE,
new MockEnvironment());
KubernetesClientContextToSourceData data = NamedSecretContextToSourceDataProvider.of(Dummy::sourceName).get();
KubernetesClientContextToSourceData data = new NamedSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.red.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.red.default");
Assertions.assertEquals(sourceData.sourceData(), Map.of("color", "really-red"));
}
@@ -126,14 +125,14 @@ class NamedSecretContextToSourceDataProviderTests {
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(secretList))));
// blue does not match red
NormalizedSource source = new NamedSecretNormalizedSource("red", NAMESPACE, false);
NormalizedSource source = new NamedSecretNormalizedSource("red", NAMESPACE, false, "");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE,
new MockEnvironment());
KubernetesClientContextToSourceData data = NamedSecretContextToSourceDataProvider.of(Dummy::sourceName).get();
KubernetesClientContextToSourceData data = new NamedSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.red.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.red.default");
Assertions.assertEquals(sourceData.sourceData().size(), 1);
Assertions.assertEquals(sourceData.sourceData().get("color"), "really-red");
@@ -157,14 +156,14 @@ class NamedSecretContextToSourceDataProviderTests {
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(secretList))));
// blue does not match red
NormalizedSource source = new NamedSecretNormalizedSource("blue", NAMESPACE, false);
NormalizedSource source = new NamedSecretNormalizedSource("blue", NAMESPACE, false, "");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE,
new MockEnvironment());
KubernetesClientContextToSourceData data = NamedSecretContextToSourceDataProvider.of(Dummy::sourceName).get();
KubernetesClientContextToSourceData data = new NamedSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.blue.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.blue.default");
Assertions.assertEquals(sourceData.sourceData(), Collections.emptyMap());
}
@@ -183,28 +182,15 @@ class NamedSecretContextToSourceDataProviderTests {
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(secretList))));
// blue does not match red
NormalizedSource source = new NamedSecretNormalizedSource("red", NAMESPACE + "nope", false);
NormalizedSource source = new NamedSecretNormalizedSource("red", NAMESPACE + "nope", false, "");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, source, NAMESPACE,
new MockEnvironment());
KubernetesClientContextToSourceData data = NamedSecretContextToSourceDataProvider.of(Dummy::sourceName).get();
KubernetesClientContextToSourceData data = new NamedSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.red.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.red.default");
Assertions.assertEquals(sourceData.sourceData(), Map.of("color", "really-red"));
}
// needed only to allow access to the super methods
private static final class Dummy extends SecretsPropertySource {
private Dummy() {
super(SourceData.emptyRecord("dummy-name"));
}
private static String sourceName(String name, String namespace) {
return getSourceName(name, namespace);
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2013-2021 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties.One;
import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties.Three;
import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties.Two;
@SpringBootApplication
@EnableConfigurationProperties({ One.class, Two.class, Three.class })
public class NamedConfigMapWithPrefixApp {
public static void main(String[] args) {
SpringApplication.run(NamedConfigMapWithPrefixApp.class, args);
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2013-2022 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author Ryan Baxter
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedConfigMapWithPrefixApp.class,
properties = { "spring.cloud.bootstrap.name=named-config-map-with-prefix",
"named.config.map.with.prefix.stub=true", "spring.main.cloud-platform=KUBERNETES",
"spring.cloud.bootstrap.enabled=true", "spring.cloud.kubernetes.client.namespace=spring-k8s" })
class NamedConfigMapWithPrefixBootstrapTests extends NamedConfigMapWithPrefixTests {
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2013-2022 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import io.kubernetes.client.util.ClientBuilder;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.mockito.MockedStatic;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.kubernetes.client.KubernetesClientUtils;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.mockito.Mockito.mockStatic;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithPrefixConfigurationStub.stubData;
/**
* @author Ryan Baxter
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedConfigMapWithPrefixApp.class,
properties = { "spring.cloud.application.name=named-configmap-with-prefix",
"named.config.map.with.prefix.stub=true", "spring.main.cloud-platform=KUBERNETES",
"spring.config.import=kubernetes:,classpath:./named-config-map-with-prefix.yaml" })
class NamedConfigMapWithPrefixConfigDataTests extends NamedConfigMapWithPrefixTests {
private static MockedStatic<KubernetesClientUtils> clientUtilsMock;
@BeforeAll
static void wireMock() {
WireMockServer server = new WireMockServer(options().dynamicPort());
server.start();
WireMock.configureFor("localhost", server.port());
clientUtilsMock = mockStatic(KubernetesClientUtils.class);
clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient)
.thenReturn(new ClientBuilder().setBasePath(server.baseUrl()).build());
stubData();
}
@AfterAll
static void teardown() {
clientUtilsMock.close();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2020 the original author or authors.
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.config;
package org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix;
import com.github.tomakehurst.wiremock.client.WireMock;
import org.hamcrest.Matchers;
@@ -30,7 +30,7 @@ import org.springframework.test.web.reactive.server.WebTestClient;
*
* @author wind57
*/
abstract class KubernetesClientConfigMapNameAsPrefixTests {
abstract class NamedConfigMapWithPrefixTests {
@Autowired
private WebTestClient webClient;
@@ -41,7 +41,7 @@ abstract class KubernetesClientConfigMapNameAsPrefixTests {
}
@AfterAll
public static void afterAll() {
static void afterAll() {
WireMock.shutdownServer();
}
@@ -55,9 +55,9 @@ abstract class KubernetesClientConfigMapNameAsPrefixTests {
* </pre>
*/
@Test
public void testOne() {
this.webClient.get().uri("/prefix/one").exchange().expectStatus().isOk().expectBody(String.class)
.value(Matchers.equalTo("one"));
void testOne() {
this.webClient.get().uri("/named-configmap/prefix/one").exchange().expectStatus().isOk()
.expectBody(String.class).value(Matchers.equalTo("one"));
}
/**
@@ -70,9 +70,9 @@ abstract class KubernetesClientConfigMapNameAsPrefixTests {
* </pre>
*/
@Test
public void testTwo() {
this.webClient.get().uri("/prefix/two").exchange().expectStatus().isOk().expectBody(String.class)
.value(Matchers.equalTo("two"));
void testTwo() {
this.webClient.get().uri("/named-configmap/prefix/two").exchange().expectStatus().isOk()
.expectBody(String.class).value(Matchers.equalTo("two"));
}
/**
@@ -85,9 +85,9 @@ abstract class KubernetesClientConfigMapNameAsPrefixTests {
* </pre>
*/
@Test
public void testThree() {
this.webClient.get().uri("/prefix/three").exchange().expectStatus().isOk().expectBody(String.class)
.value(Matchers.equalTo("three"));
void testThree() {
this.webClient.get().uri("/named-configmap/prefix/three").exchange().expectStatus().isOk()
.expectBody(String.class).value(Matchers.equalTo("three"));
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.controller;
import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties.One;
import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties.Three;
import org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties.Two;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class NamedConfigWithPrefixController {
private final One one;
private final Two two;
private final Three three;
public NamedConfigWithPrefixController(One one, Two two, Three three) {
this.one = one;
this.two = two;
this.three = three;
}
@GetMapping("/named-configmap/prefix/one")
public String one() {
return one.getProperty();
}
@GetMapping("/named-configmap/prefix/two")
public String two() {
return two.getProperty();
}
@GetMapping("/named-configmap/prefix/three")
public String three() {
return three.getProperty();
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2013-2021 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("one")
public class One {
private String property;
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.config.applications.config_map_name_as_prefix.properties;
package org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2013-2021 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.client.config.applications.named_config_map_with_prefix.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("two")
public class Two {
private String property;
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
}

View File

@@ -14,21 +14,21 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.config.applications.config_map_name_as_prefix;
package org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.kubernetes.client.config.applications.config_map_name_as_prefix.properties.One;
import org.springframework.cloud.kubernetes.client.config.applications.config_map_name_as_prefix.properties.Three;
import org.springframework.cloud.kubernetes.client.config.applications.config_map_name_as_prefix.properties.Two;
import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties.One;
import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties.Three;
import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties.Two;
@SpringBootApplication
@EnableConfigurationProperties({ One.class, Two.class, Three.class })
public class WithPrefixApp {
public class NamedSecretWithPrefixApp {
public static void main(String[] args) {
SpringApplication.run(WithPrefixApp.class, args);
SpringApplication.run(NamedSecretWithPrefixApp.class, args);
}
}

View File

@@ -14,23 +14,16 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.config;
package org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.kubernetes.client.config.applications.config_map_name_as_prefix.WithPrefixApp;
import org.springframework.test.context.junit.jupiter.SpringExtension;
/**
* @author Ryan Baxter
*/
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WithPrefixApp.class,
properties = { "spring.cloud.bootstrap.name=config-map-name-as-prefix", "config.map.name.as.prefix.stub=true",
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedSecretWithPrefixApp.class,
properties = { "spring.cloud.bootstrap.name=named-secret-with-prefix", "named.secret.with.prefix.stub=true",
"spring.main.cloud-platform=KUBERNETES", "spring.cloud.bootstrap.enabled=true" })
@AutoConfigureWebTestClient
public class KubernetesClientConfigMapBootstrapNameAsPrefixTests extends KubernetesClientConfigMapNameAsPrefixTests {
class NamedSecretWithPrefixBootstrapTests extends NamedSecretWithPrefixTests {
}

View File

@@ -14,41 +14,35 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.config;
package org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import io.kubernetes.client.util.ClientBuilder;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.kubernetes.client.KubernetesClientUtils;
import org.springframework.cloud.kubernetes.client.config.applications.config_map_name_as_prefix.WithPrefixApp;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.mockito.Mockito.mockStatic;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.ConfigMapNameAsPrefixConfigurationStub.stubData;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithPrefixConfigurationStub.stubData;
/**
* @author Ryan Baxter
*/
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WithPrefixApp.class,
properties = { "spring.cloud.application.name=config-map-name-as-prefix", "config.map.name.as.prefix.stub=true",
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedSecretWithPrefixApp.class,
properties = { "spring.cloud.application.name=named-secret-with-prefix", "named.secret.with.prefix.stub=true",
"spring.main.cloud-platform=KUBERNETES",
"spring.config.import=kubernetes:,classpath:./config-map-name-as-prefix.yaml" })
@AutoConfigureWebTestClient
public class KubernetesClientConfigMapConfigDataNameAsPrefixTests extends KubernetesClientConfigMapNameAsPrefixTests {
"spring.config.import=kubernetes:,classpath:./named-secret-with-prefix.yaml" })
class NamedSecretWithPrefixConfigDataTests extends NamedSecretWithPrefixTests {
private static MockedStatic<KubernetesClientUtils> clientUtilsMock;
@BeforeAll
public static void wireMock() {
static void wireMock() {
WireMockServer server = new WireMockServer(options().dynamicPort());
server.start();
WireMock.configureFor("localhost", server.port());

View File

@@ -0,0 +1,94 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix;
import com.github.tomakehurst.wiremock.client.WireMock;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.reactive.server.WebTestClient;
/**
* The stub data for this test is in :
* {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithPrefixConfigurationStub}
*
* @author wind57
*/
abstract class NamedSecretWithPrefixTests {
@Autowired
private WebTestClient webClient;
@AfterEach
void afterEach() {
WireMock.reset();
}
@AfterAll
static void afterAll() {
WireMock.shutdownServer();
}
/**
* <pre>
* 'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
* 'spring.cloud.kubernetes.secrets.sources[0].useNameAsPrefix=false'
* ("one.property", "one")
*
* As such: @ConfigurationProperties("one")
* </pre>
*/
@Test
void testOne() {
this.webClient.get().uri("/named-secret/prefix/one").exchange().expectStatus().isOk().expectBody(String.class)
.value(Matchers.equalTo("one"));
}
/**
* <pre>
* 'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
* 'spring.cloud.kubernetes.secrets.sources[1].explicitPrefix=two'
* ("property", "two")
*
* As such: @ConfigurationProperties("two")
* </pre>
*/
@Test
void testTwo() {
this.webClient.get().uri("/named-secret/prefix/two").exchange().expectStatus().isOk().expectBody(String.class)
.value(Matchers.equalTo("two"));
}
/**
* <pre>
* 'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
* 'spring.cloud.kubernetes.secrets.sources[2].name=config-map-three'
* ("property", "three")
*
* As such: @ConfigurationProperties(prefix = "config-map-three")
* </pre>
*/
@Test
void testThree() {
this.webClient.get().uri("/named-secret/prefix/three").exchange().expectStatus().isOk().expectBody(String.class)
.value(Matchers.equalTo("three"));
}
}

View File

@@ -14,16 +14,16 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.config.applications.config_map_name_as_prefix.controller;
package org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.controller;
import org.springframework.cloud.kubernetes.client.config.applications.config_map_name_as_prefix.properties.One;
import org.springframework.cloud.kubernetes.client.config.applications.config_map_name_as_prefix.properties.Three;
import org.springframework.cloud.kubernetes.client.config.applications.config_map_name_as_prefix.properties.Two;
import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties.One;
import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties.Three;
import org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties.Two;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Controller {
public class NamedSecretWithPrefixController {
private final One one;
@@ -31,23 +31,23 @@ public class Controller {
private final Three three;
public Controller(One one, Two two, Three three) {
public NamedSecretWithPrefixController(One one, Two two, Three three) {
this.one = one;
this.two = two;
this.three = three;
}
@GetMapping("/prefix/one")
@GetMapping("/named-secret/prefix/one")
public String one() {
return one.getProperty();
}
@GetMapping("/prefix/two")
@GetMapping("/named-secret/prefix/two")
public String two() {
return two.getProperty();
}
@GetMapping("/prefix/three")
@GetMapping("/named-secret/prefix/three")
public String three() {
return three.getProperty();
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.config.applications.config_map_name_as_prefix.properties;
package org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2013-2021 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "secret-three")
public class Three {
private String property;
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.config.applications.config_map_name_as_prefix.properties;
package org.springframework.cloud.kubernetes.client.config.applications.named_secret_with_prefix.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -44,8 +44,8 @@ import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options
*/
@Order(0)
@Configuration
@ConditionalOnProperty("config.map.name.as.prefix.stub")
public class ConfigMapNameAsPrefixConfigurationStub {
@ConditionalOnProperty("named.config.map.with.prefix.stub")
public class NamedConfigMapWithPrefixConfigurationStub {
@Bean
public WireMockServer wireMock() {

View File

@@ -0,0 +1,91 @@
/*
* Copyright 2013-2022 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.client.config.boostrap.stubs;
import java.util.Arrays;
import java.util.Collections;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.JSON;
import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder;
import io.kubernetes.client.openapi.models.V1Secret;
import io.kubernetes.client.openapi.models.V1SecretBuilder;
import io.kubernetes.client.openapi.models.V1SecretList;
import io.kubernetes.client.util.ClientBuilder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
/**
* A test bootstrap that takes care to initialize ApiClient _before_ our main bootstrap
* context; with some stub data already present.
*
* @author wind57
*/
@Order(0)
@Configuration
@ConditionalOnProperty("named.secret.with.prefix.stub")
public class NamedSecretWithPrefixConfigurationStub {
@Bean
public WireMockServer wireMock() {
WireMockServer server = new WireMockServer(options().dynamicPort());
server.start();
WireMock.configureFor("localhost", server.port());
return server;
}
@Bean
public ApiClient apiClient(WireMockServer wireMockServer) {
ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build();
io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient);
apiClient.setDebugging(true);
stubData();
return apiClient;
}
public static void stubData() {
V1Secret one = new V1SecretBuilder()
.withMetadata(new V1ObjectMetaBuilder().withName("secret-one").withNamespace("spring-k8s")
.withResourceVersion("1").build())
.addToData(Collections.singletonMap("one.property", "one".getBytes())).build();
V1Secret two = new V1SecretBuilder()
.withMetadata(new V1ObjectMetaBuilder().withName("secret-two").withNamespace("spring-k8s")
.withResourceVersion("1").build())
.addToData(Collections.singletonMap("property", "two".getBytes())).build();
V1Secret three = new V1SecretBuilder()
.withMetadata(new V1ObjectMetaBuilder().withName("secret-three").withNamespace("spring-k8s")
.withResourceVersion("1").build())
.addToData(Collections.singletonMap("property", "three".getBytes())).build();
V1SecretList allSecrets = new V1SecretList();
allSecrets.setItems(Arrays.asList(one, two, three));
// the actual stub for CoreV1Api calls
WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/secrets")
.willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(allSecrets))));
}
}

View File

@@ -1,4 +1,5 @@
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.IncludeProfileSpecificSourcesConfigurationStub, \
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.ConfigMapNameAsPrefixConfigurationStub, \
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithPrefixConfigurationStub, \
org.springframework.cloud.kubernetes.client.config.boostrap.stubs..NamedSecretWithPrefixConfigurationStub, \
org.springframework.cloud.kubernetes.client.config.EnableRetryBootstrapConfiguration

View File

@@ -1,6 +1,6 @@
spring:
application:
name: with-prefix
name: named-config-map-with-prefix
cloud:
kubernetes:
config:

View File

@@ -0,0 +1,16 @@
spring:
application:
name: named-secret-with-prefix
cloud:
kubernetes:
client:
namespace: spring-k8s
secrets:
enableApi: true
useNameAsPrefix: true
sources:
- name: secret-one
useNameAsPrefix: false
- name: secret-two
explicitPrefix: two
- name: secret-three

View File

@@ -30,7 +30,7 @@ public abstract class AbstractConfigProperties {
protected String namespace;
// use config map name to prefix properties
// use config map or secret name to prefix properties
protected boolean useNameAsPrefix;
// use profile name to append config map name

View File

@@ -25,8 +25,11 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.getApplicationName;
/**
* Config map configuration properties.
*
@@ -81,13 +84,14 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
* These are the actual name/namespace pairs that are used to create a
* ConfigMapPropertySource.
*/
public List<NormalizedSource> determineSources() {
public List<NormalizedSource> determineSources(Environment environment) {
if (this.sources.isEmpty()) {
if (useNameAsPrefix) {
LOG.warn(
"'spring.cloud.kubernetes.config.useNameAsPrefix' is set to 'true', but 'spring.cloud.kubernetes.config.sources'"
+ " is empty; as such will default 'useNameAsPrefix' to 'false'");
}
String name = getApplicationName(environment, this.name, "Config Map");
return Collections.singletonList(
new NamedConfigMapNormalizedSource(name, namespace, failFast, "", includeProfileSpecificSources));
}

View File

@@ -27,13 +27,10 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.util.CollectionUtils;
import static org.springframework.cloud.kubernetes.commons.config.Constants.APPLICATION_PROPERTIES;
import static org.springframework.cloud.kubernetes.commons.config.Constants.APPLICATION_YAML;
import static org.springframework.cloud.kubernetes.commons.config.Constants.APPLICATION_YML;
import static org.springframework.cloud.kubernetes.commons.config.Constants.PREFIX;
import static org.springframework.cloud.kubernetes.commons.config.Constants.PROPERTY_SOURCE_NAME_SEPARATOR;
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.KEY_VALUE_TO_PROPERTIES;
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.PROPERTIES_TO_MAP;
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.throwingMerger;
@@ -54,10 +51,6 @@ public abstract class ConfigMapPropertySource extends MapPropertySource {
super(sourceData.sourceName(), sourceData.sourceData());
}
protected static String getSourceName(String applicationName, String namespace) {
return PREFIX + PROPERTY_SOURCE_NAME_SEPARATOR + applicationName + PROPERTY_SOURCE_NAME_SEPARATOR + namespace;
}
protected static Map<String, Object> processAllEntries(Map<String, String> input, Environment environment) {
Set<Map.Entry<String, String>> entrySet = input.entrySet();
@@ -80,19 +73,6 @@ public abstract class ConfigMapPropertySource extends MapPropertySource {
return defaultProcessAllEntries(input, environment);
}
/*
* this method will return a SourceData that has a name in the form :
* "configmap.my-configmap.my-configmap-2.namespace" and the "data" from the context
* is appended with prefix. So if incoming is "a=b", the result will be : "prefix.a=b"
*/
protected static SourceData withPrefix(ConfigMapPrefixContext context) {
Map<String, Object> withPrefix = CollectionUtils.newHashMap(context.data().size());
context.data().forEach((key, value) -> withPrefix.put(context.prefix() + "." + key, value));
String propertySourceTokens = String.join(PROPERTY_SOURCE_NAME_SEPARATOR, context.propertySourceNames());
return new SourceData(getSourceName(propertySourceTokens, context.namespace()), withPrefix);
}
private static Map<String, Object> defaultProcessAllEntries(Map<String, String> input, Environment environment) {
return input.entrySet().stream().map(e -> extractProperties(e.getKey(), e.getValue(), environment))

View File

@@ -67,7 +67,7 @@ public abstract class ConfigMapPropertySourceLocator implements PropertySourceLo
CompositePropertySource composite = new CompositePropertySource("composite-configmap");
if (this.properties.isEnableApi()) {
Set<NormalizedSource> sources = new LinkedHashSet<>(this.properties.determineSources());
Set<NormalizedSource> sources = new LinkedHashSet<>(this.properties.determineSources(environment));
LOG.debug("Config Map normalized sources : " + sources);
sources.forEach(s -> composite.addFirstPropertySource(getMapPropertySourceForSingleConfigMap(env, s)));
}

View File

@@ -16,13 +16,17 @@
package org.springframework.cloud.kubernetes.commons.config;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.env.Environment;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import static org.springframework.cloud.kubernetes.commons.config.Constants.FALLBACK_APPLICATION_NAME;
import static org.springframework.cloud.kubernetes.commons.config.Constants.PROPERTY_SOURCE_NAME_SEPARATOR;
import static org.springframework.cloud.kubernetes.commons.config.Constants.SPRING_APPLICATION_NAME;
/**
@@ -49,21 +53,21 @@ public final class ConfigUtils {
/**
* @param explicitPrefix value of
* 'spring.cloud.kubernetes.config.sources.explicitPrefix'
* 'spring.cloud.kubernetes.config|secrets.sources.explicitPrefix'
* @param useNameAsPrefix value of
* 'spring.cloud.kubernetes.config.sources.useNameAsPrefix'
* 'spring.cloud.kubernetes.config|secrets.sources.useNameAsPrefix'
* @param defaultUseNameAsPrefix value of
* 'spring.cloud.kubernetes.config.defaultUseNameAsPrefix'
* 'spring.cloud.kubernetes.config|secrets.defaultUseNameAsPrefix'
* @param normalizedName either the name of
* 'spring.cloud.kubernetes.config.sources.name' or
* 'spring.cloud.kubernetes.config.name'
* 'spring.cloud.kubernetes.config|secrets.sources.name' or
* 'spring.cloud.kubernetes.config|secrets.name'
* @return prefix to use in normalized sources, never null
*/
public static String findPrefix(String explicitPrefix, Boolean useNameAsPrefix, boolean defaultUseNameAsPrefix,
String normalizedName) {
// if explicitPrefix is set, it takes priority over useNameAsPrefix
// (either the one from 'spring.cloud.kubernetes.config' or
// 'spring.cloud.kubernetes.config.sources')
// (either the one from 'spring.cloud.kubernetes.config|secrets' or
// 'spring.cloud.kubernetes.config|secrets.sources')
if (StringUtils.hasText(explicitPrefix)) {
return explicitPrefix;
}
@@ -109,4 +113,21 @@ public final class ConfigUtils {
LOG.warn(message + ". Ignoring.", e);
}
/*
* this method will return a SourceData that has a name in the form :
* "configmap.my-configmap.my-configmap-2.namespace" and the "data" from the context
* is appended with prefix. So if incoming is "a=b", the result will be : "prefix.a=b"
*/
public static SourceData withPrefix(String target, PrefixContext context) {
Map<String, Object> withPrefix = CollectionUtils.newHashMap(context.data().size());
context.data().forEach((key, value) -> withPrefix.put(context.prefix() + "." + key, value));
String propertySourceTokens = String.join(PROPERTY_SOURCE_NAME_SEPARATOR, context.propertySourceNames());
return new SourceData(sourceName(target, propertySourceTokens, context.namespace()), withPrefix);
}
public static String sourceName(String target, String applicationName, String namespace) {
return target + PROPERTY_SOURCE_NAME_SEPARATOR + applicationName + PROPERTY_SOURCE_NAME_SEPARATOR + namespace;
}
}

View File

@@ -48,7 +48,7 @@ public final class LabeledSecretNormalizedSource extends NormalizedSource {
@Override
public String target() {
return "Secret";
return "secret";
}
@Override

View File

@@ -51,7 +51,7 @@ public final class NamedConfigMapNormalizedSource extends NormalizedSource {
@Override
public String target() {
return "Config Map";
return "configmap";
}
@Override

View File

@@ -25,8 +25,15 @@ import java.util.Objects;
*/
public final class NamedSecretNormalizedSource extends NormalizedSource {
public NamedSecretNormalizedSource(String name, String namespace, boolean failFast) {
private final String prefix;
public NamedSecretNormalizedSource(String name, String namespace, boolean failFast, String prefix) {
super(name, namespace, failFast);
this.prefix = prefix;
}
public String prefix() {
return prefix;
}
@Override
@@ -36,7 +43,7 @@ public final class NamedSecretNormalizedSource extends NormalizedSource {
@Override
public String target() {
return "Secret";
return "secret";
}
@Override

View File

@@ -20,10 +20,11 @@ import java.util.Map;
import java.util.Set;
/**
* A holder for data needed to compute prefix based properties, in case of a config map.
* A holder for data needed to compute prefix based properties, in case of a secret or
* config map.
*
* @author wind57
*/
public final record ConfigMapPrefixContext(Map<String, Object> data, String prefix, String namespace,
public final record PrefixContext(Map<String, Object> data, String prefix, String namespace,
Set<String> propertySourceNames) {
}

View File

@@ -94,10 +94,9 @@ public class SecretsConfigProperties extends AbstractConfigProperties {
*/
public List<NormalizedSource> determineSources(Environment environment) {
if (this.sources.isEmpty()) {
List<NormalizedSource> result = new ArrayList<>(2);
String name = getApplicationName(environment, this.name, "Secret");
result.add(new NamedSecretNormalizedSource(name, this.namespace, this.isFailFast()));
result.add(new NamedSecretNormalizedSource(name, this.namespace, this.isFailFast(), ""));
if (!labels.isEmpty()) {
result.add(new LabeledSecretNormalizedSource(this.namespace, this.labels, this.isFailFast()));
@@ -105,9 +104,8 @@ public class SecretsConfigProperties extends AbstractConfigProperties {
return result;
}
return this.sources.stream()
.flatMap(s -> s.normalize(this.name, this.namespace, this.labels, this.isFailFast(), environment))
.collect(Collectors.toList());
return this.sources.stream().flatMap(s -> s.normalize(this.name, this.namespace, this.labels, this.failFast,
this.useNameAsPrefix, environment)).collect(Collectors.toList());
}
public static class Source {
@@ -127,14 +125,18 @@ public class SecretsConfigProperties extends AbstractConfigProperties {
*/
private Map<String, String> labels = Collections.emptyMap();
public Source() {
}
/**
* An explicit prefix to be used for properties.
*/
private String explicitPrefix;
@Deprecated
public Source(String name, String namespace, Map<String, String> labels) {
this.name = name;
this.namespace = namespace;
this.labels = labels;
/**
* Use secret name as prefix for properties. Can't be a primitive, we need to know
* if it was explicitly set or not
*/
private Boolean useNameAsPrefix;
public Source() {
}
public String getName() {
@@ -161,12 +163,29 @@ public class SecretsConfigProperties extends AbstractConfigProperties {
return this.labels;
}
public String getExplicitPrefix() {
return explicitPrefix;
}
public void setExplicitPrefix(String explicitPrefix) {
this.explicitPrefix = explicitPrefix;
}
public Boolean getUseNameAsPrefix() {
return useNameAsPrefix;
}
public void setUseNameAsPrefix(Boolean useNameAsPrefix) {
this.useNameAsPrefix = useNameAsPrefix;
}
public boolean isEmpty() {
return !StringUtils.hasLength(this.name) && !StringUtils.hasLength(this.namespace);
}
private Stream<NormalizedSource> normalize(String defaultName, String defaultNamespace,
Map<String, String> defaultLabels, boolean failFast, Environment environment) {
Map<String, String> defaultLabels, boolean failFast, boolean defaultUseNameAsPrefix,
Environment environment) {
Stream.Builder<NormalizedSource> normalizedSources = Stream.builder();
@@ -175,8 +194,12 @@ public class SecretsConfigProperties extends AbstractConfigProperties {
Map<String, String> normalizedLabels = this.labels.isEmpty() ? defaultLabels : this.labels;
String secretName = getApplicationName(environment, normalizedName, "Secret");
String prefix = ConfigUtils.findPrefix(this.explicitPrefix, this.useNameAsPrefix, defaultUseNameAsPrefix,
normalizedName);
NormalizedSource nameBasedSource = new NamedSecretNormalizedSource(secretName, normalizedNamespace,
failFast);
failFast, prefix);
normalizedSources.add(nameBasedSource);
if (!normalizedLabels.isEmpty()) {

View File

@@ -18,8 +18,6 @@ package org.springframework.cloud.kubernetes.commons.config;
import org.springframework.core.env.MapPropertySource;
import static org.springframework.cloud.kubernetes.commons.config.Constants.PROPERTY_SOURCE_NAME_SEPARATOR;
/**
* Kubernetes property source for secrets.
*
@@ -32,10 +30,6 @@ public class SecretsPropertySource extends MapPropertySource {
super(sourceData.sourceName(), sourceData.sourceData());
}
protected static String getSourceName(String name, String namespace) {
return "secrets" + PROPERTY_SOURCE_NAME_SEPARATOR + name + PROPERTY_SOURCE_NAME_SEPARATOR + namespace;
}
@Override
public String toString() {
return getClass().getSimpleName() + " {name='" + this.name + "'}";

View File

@@ -23,10 +23,12 @@ import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.mock.env.MockEnvironment;
/**
* @author wind57
*/
public class ConfigMapConfigPropertiesTests {
class ConfigMapConfigPropertiesTests {
/**
* <pre>
@@ -41,13 +43,13 @@ public class ConfigMapConfigPropertiesTests {
* a config as above will result in a NormalizedSource where prefix is empty
*/
@Test
public void testUseNameAsPrefixUnsetEmptySources() {
void testUseNameAsPrefixUnsetEmptySources() {
ConfigMapConfigProperties properties = new ConfigMapConfigProperties();
properties.setSources(Collections.emptyList());
properties.setName("config-map-a");
properties.setNamespace("spring-k8s");
List<NormalizedSource> sources = properties.determineSources();
List<NormalizedSource> sources = properties.determineSources(new MockEnvironment());
Assertions.assertEquals(sources.size(), 1, "empty sources must generate a List with a single NormalizedSource");
Assertions.assertEquals(((NamedConfigMapNormalizedSource) sources.get(0)).prefix(), "",
@@ -69,14 +71,14 @@ public class ConfigMapConfigPropertiesTests {
* "useNameAsPrefix: true", because sources are empty
*/
@Test
public void testUseNameAsPrefixSetEmptySources() {
void testUseNameAsPrefixSetEmptySources() {
ConfigMapConfigProperties properties = new ConfigMapConfigProperties();
properties.setSources(Collections.emptyList());
properties.setUseNameAsPrefix(true);
properties.setName("config-map-a");
properties.setNamespace("spring-k8s");
List<NormalizedSource> sources = properties.determineSources();
List<NormalizedSource> sources = properties.determineSources(new MockEnvironment());
Assertions.assertEquals(sources.size(), 1, "empty sources must generate a List with a single NormalizedSource");
Assertions.assertEquals(((NamedConfigMapNormalizedSource) sources.get(0)).prefix(), "",
@@ -100,7 +102,7 @@ public class ConfigMapConfigPropertiesTests {
* the config map name
*/
@Test
public void testUseNameAsPrefixUnsetNonEmptySources() {
void testUseNameAsPrefixUnsetNonEmptySources() {
ConfigMapConfigProperties properties = new ConfigMapConfigProperties();
properties.setUseNameAsPrefix(true);
properties.setNamespace("spring-k8s");
@@ -109,7 +111,7 @@ public class ConfigMapConfigPropertiesTests {
one.setName("config-map-one");
properties.setSources(Collections.singletonList(one));
List<NormalizedSource> sources = properties.determineSources();
List<NormalizedSource> sources = properties.determineSources(new MockEnvironment());
Assertions.assertEquals(sources.size(), 1, "a single NormalizedSource is expected");
Assertions.assertEquals(((NamedConfigMapNormalizedSource) sources.get(0)).prefix(), "config-map-one");
@@ -137,7 +139,7 @@ public class ConfigMapConfigPropertiesTests {
* 'spring.cloud.kubernetes.config.useNameAsPrefix' will be taken.
*/
@Test
public void testUseNameAsPrefixSetNonEmptySources() {
void testUseNameAsPrefixSetNonEmptySources() {
ConfigMapConfigProperties properties = new ConfigMapConfigProperties();
properties.setUseNameAsPrefix(true);
properties.setNamespace("spring-k8s");
@@ -155,7 +157,7 @@ public class ConfigMapConfigPropertiesTests {
properties.setSources(Arrays.asList(one, two, three));
List<NormalizedSource> sources = properties.determineSources();
List<NormalizedSource> sources = properties.determineSources(new MockEnvironment());
Assertions.assertEquals(sources.size(), 3, "3 NormalizedSources are expected");
Assertions.assertEquals(((NamedConfigMapNormalizedSource) sources.get(0)).prefix(), "");
@@ -185,7 +187,7 @@ public class ConfigMapConfigPropertiesTests {
*
*/
@Test
public void testMultipleCases() {
void testMultipleCases() {
ConfigMapConfigProperties properties = new ConfigMapConfigProperties();
properties.setUseNameAsPrefix(false);
properties.setNamespace("spring-k8s");
@@ -209,7 +211,7 @@ public class ConfigMapConfigPropertiesTests {
properties.setSources(Arrays.asList(one, two, three, four));
List<NormalizedSource> sources = properties.determineSources();
List<NormalizedSource> sources = properties.determineSources(new MockEnvironment());
Assertions.assertEquals(sources.size(), 4, "4 NormalizedSources are expected");
Assertions.assertEquals(((NamedConfigMapNormalizedSource) sources.get(0)).prefix(), "one");
@@ -233,13 +235,13 @@ public class ConfigMapConfigPropertiesTests {
* added is not a breaking change for the already existing functionality)
*/
@Test
public void testUseIncludeProfileSpecificSourcesNoChanges() {
void testUseIncludeProfileSpecificSourcesNoChanges() {
ConfigMapConfigProperties properties = new ConfigMapConfigProperties();
properties.setSources(Collections.emptyList());
properties.setName("config-map-a");
properties.setNamespace("spring-k8s");
List<NormalizedSource> sources = properties.determineSources();
List<NormalizedSource> sources = properties.determineSources(new MockEnvironment());
Assertions.assertEquals(sources.size(), 1, "empty sources must generate a List with a single NormalizedSource");
Assertions.assertTrue(((NamedConfigMapNormalizedSource) sources.get(0)).profileSpecificSources());
@@ -263,14 +265,14 @@ public class ConfigMapConfigPropertiesTests {
* and must be propagated to the normalized source.
*/
@Test
public void testUseIncludeProfileSpecificSourcesDefaultChanged() {
void testUseIncludeProfileSpecificSourcesDefaultChanged() {
ConfigMapConfigProperties properties = new ConfigMapConfigProperties();
properties.setSources(Collections.emptyList());
properties.setName("config-map-a");
properties.setNamespace("spring-k8s");
properties.setIncludeProfileSpecificSources(false);
List<NormalizedSource> sources = properties.determineSources();
List<NormalizedSource> sources = properties.determineSources(new MockEnvironment());
Assertions.assertEquals(sources.size(), 1, "empty sources must generate a List with a single NormalizedSource");
Assertions.assertFalse(((NamedConfigMapNormalizedSource) sources.get(0)).profileSpecificSources());
@@ -300,7 +302,7 @@ public class ConfigMapConfigPropertiesTests {
* </pre>
*/
@Test
public void testUseIncludeProfileSpecificSourcesDefaultChangedSourceOverride() {
void testUseIncludeProfileSpecificSourcesDefaultChangedSourceOverride() {
ConfigMapConfigProperties properties = new ConfigMapConfigProperties();
properties.setSources(Collections.emptyList());
properties.setName("config-map-a");
@@ -320,7 +322,7 @@ public class ConfigMapConfigPropertiesTests {
properties.setSources(Arrays.asList(one, two, three));
List<NormalizedSource> sources = properties.determineSources();
List<NormalizedSource> sources = properties.determineSources(new MockEnvironment());
Assertions.assertEquals(sources.size(), 3);
Assertions.assertTrue(((NamedConfigMapNormalizedSource) sources.get(0)).profileSpecificSources());

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2013-2022 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.commons.config;
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* @author wind57
*/
class ConfigMapPropertySourceTests {
@Test
void testWithPrefix() {
ConfigMapPrefixContext context = new ConfigMapPrefixContext(Map.of("a", "b", "c", "d"), "prefix", "namespace",
Set.of("name1", "name2"));
SourceData result = ConfigMapPropertySource.withPrefix(context);
Assertions.assertEquals(result.sourceName().length(), 31);
Assertions.assertTrue(result.sourceName().contains("name2"));
Assertions.assertTrue(result.sourceName().contains("name1"));
Assertions.assertTrue(result.sourceName().contains("configmap"));
Assertions.assertTrue(result.sourceName().contains("namespace"));
Assertions.assertEquals(result.sourceData().get("prefix.a"), "b");
Assertions.assertEquals(result.sourceData().get("prefix.c"), "d");
}
}

View File

@@ -16,40 +16,43 @@
package org.springframework.cloud.kubernetes.commons.config;
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* @author wind57
*/
public class ConfigUtilsTests {
class ConfigUtilsTests {
@Test
public void testExplicitPrefixSet() {
void testExplicitPrefixSet() {
String result = ConfigUtils.findPrefix("explicitPrefix", null, false, "irrelevant");
Assertions.assertEquals(result, "explicitPrefix");
}
@Test
public void testUseNameAsPrefixTrue() {
void testUseNameAsPrefixTrue() {
String result = ConfigUtils.findPrefix("", Boolean.TRUE, false, "name-to-use");
Assertions.assertEquals(result, "name-to-use");
}
@Test
public void testUseNameAsPrefixFalse() {
void testUseNameAsPrefixFalse() {
String result = ConfigUtils.findPrefix("", Boolean.FALSE, false, "name-not-to-use");
Assertions.assertEquals(result, "");
}
@Test
public void testDefaultUseNameAsPrefixTrue() {
void testDefaultUseNameAsPrefixTrue() {
String result = ConfigUtils.findPrefix("", null, true, "name-to-use");
Assertions.assertEquals(result, "name-to-use");
}
@Test
public void testNoMatch() {
void testNoMatch() {
String result = ConfigUtils.findPrefix("", null, false, "name-not-to-use");
Assertions.assertEquals(result, "");
}
@@ -66,7 +69,7 @@ public class ConfigUtilsTests {
* above will generate "true" for a normalized source
*/
@Test
public void testUseIncludeProfileSpecificSourcesOnlyDefaultSet() {
void testUseIncludeProfileSpecificSourcesOnlyDefaultSet() {
Assertions.assertTrue(ConfigUtils.includeProfileSpecificSources(true, null));
}
@@ -82,7 +85,7 @@ public class ConfigUtilsTests {
* above will generate "false" for a normalized source
*/
@Test
public void testUseIncludeProfileSpecificSourcesOnlyDefaultNotSet() {
void testUseIncludeProfileSpecificSourcesOnlyDefaultNotSet() {
Assertions.assertFalse(ConfigUtils.includeProfileSpecificSources(false, null));
}
@@ -101,8 +104,25 @@ public class ConfigUtilsTests {
* above will generate "false" for a normalized source
*/
@Test
public void testUseIncludeProfileSpecificSourcesSourcesOverridesDefault() {
void testUseIncludeProfileSpecificSourcesSourcesOverridesDefault() {
Assertions.assertFalse(ConfigUtils.includeProfileSpecificSources(true, false));
}
@Test
void testWithPrefix() {
PrefixContext context = new PrefixContext(Map.of("a", "b", "c", "d"), "prefix", "namespace",
Set.of("name1", "name2"));
SourceData result = ConfigUtils.withPrefix("configmap", context);
Assertions.assertEquals(result.sourceName().length(), 31);
Assertions.assertTrue(result.sourceName().contains("name2"));
Assertions.assertTrue(result.sourceName().contains("name1"));
Assertions.assertTrue(result.sourceName().contains("configmap"));
Assertions.assertTrue(result.sourceName().contains("namespace"));
Assertions.assertEquals(result.sourceData().get("prefix.a"), "b");
Assertions.assertEquals(result.sourceData().get("prefix.c"), "d");
}
}

View File

@@ -53,7 +53,7 @@ class LabeledSecretNormalizedSourceTests {
@Test
void testTarget() {
LabeledSecretNormalizedSource source = new LabeledSecretNormalizedSource("namespace", labels, false);
Assertions.assertEquals(source.target(), "Secret");
Assertions.assertEquals(source.target(), "secret");
}
@Test

View File

@@ -46,7 +46,7 @@ class NamedConfigMapNormalizedSourceTests {
void testTarget() {
NamedConfigMapNormalizedSource one = new NamedConfigMapNormalizedSource("name", "namespace", false, "prefix",
true);
Assertions.assertEquals(one.target(), "Config Map");
Assertions.assertEquals(one.target(), "configmap");
}
@Test

View File

@@ -26,8 +26,8 @@ class NamedSecretNormalizedSourceTests {
@Test
void testEqualsAndHashCode() {
NamedSecretNormalizedSource left = new NamedSecretNormalizedSource("name", "namespace", false);
NamedSecretNormalizedSource right = new NamedSecretNormalizedSource("name", "namespace", true);
NamedSecretNormalizedSource left = new NamedSecretNormalizedSource("name", "namespace", false, "");
NamedSecretNormalizedSource right = new NamedSecretNormalizedSource("name", "namespace", true, "");
Assertions.assertEquals(left.hashCode(), right.hashCode());
Assertions.assertEquals(left, right);
@@ -35,22 +35,23 @@ class NamedSecretNormalizedSourceTests {
@Test
void testType() {
NamedSecretNormalizedSource source = new NamedSecretNormalizedSource("name", "namespace", false);
NamedSecretNormalizedSource source = new NamedSecretNormalizedSource("name", "namespace", false, "");
Assertions.assertSame(source.type(), NormalizedSourceType.NAMED_SECRET);
}
@Test
void testTarget() {
NamedSecretNormalizedSource source = new NamedSecretNormalizedSource("name", "namespace", false);
Assertions.assertEquals(source.target(), "Secret");
NamedSecretNormalizedSource source = new NamedSecretNormalizedSource("name", "namespace", false, "");
Assertions.assertEquals(source.target(), "secret");
}
@Test
void testConstructorFields() {
NamedSecretNormalizedSource source = new NamedSecretNormalizedSource("name", "namespace", false);
NamedSecretNormalizedSource source = new NamedSecretNormalizedSource("name", "namespace", false, "prefix");
Assertions.assertEquals(source.name().get(), "name");
Assertions.assertEquals(source.namespace().get(), "namespace");
Assertions.assertFalse(source.failFast());
Assertions.assertEquals("prefix", source.prefix());
}
}

View File

@@ -109,7 +109,196 @@ class SecretsConfigPropertiesTests {
NormalizedSource fiveResult = iterator.next();
Assertions.assertEquals(((LabeledSecretNormalizedSource) fiveResult).labels(),
Collections.singletonMap("three", "3"));
}
/**
* <pre>
* spring:
* cloud:
* kubernetes:
* secrets:
* name: secret-a
* namespace: spring-k8s
* </pre>
*
* a config as above will result in a NormalizedSource where prefix is empty
*/
@Test
void testUseNameAsPrefixUnsetEmptySources() {
SecretsConfigProperties properties = new SecretsConfigProperties();
properties.setSources(Collections.emptyList());
properties.setName("secret-a");
properties.setNamespace("spring-k8s");
List<NormalizedSource> sources = properties.determineSources(new MockEnvironment());
Assertions.assertEquals(sources.size(), 1, "empty sources must generate a List with a single NormalizedSource");
Assertions.assertEquals(((NamedSecretNormalizedSource) sources.get(0)).prefix(), "",
"empty sources must generate a List with a single NormalizedSource, where prefix is empty");
}
/**
* <pre>
* spring:
* cloud:
* kubernetes:
* secrets:
* useNameAsPrefix: true
* name: secret-a
* namespace: spring-k8s
* </pre>
*
* a config as above will result in a NormalizedSource where prefix is empty, even if
* "useNameAsPrefix: true", because sources are empty
*/
@Test
void testUseNameAsPrefixSetEmptySources() {
SecretsConfigProperties properties = new SecretsConfigProperties();
properties.setSources(Collections.emptyList());
properties.setUseNameAsPrefix(true);
properties.setName("secret-a");
properties.setNamespace("spring-k8s");
List<NormalizedSource> sources = properties.determineSources(new MockEnvironment());
Assertions.assertEquals(sources.size(), 1, "empty sources must generate a List with a single NormalizedSource");
Assertions.assertEquals(((NamedSecretNormalizedSource) sources.get(0)).prefix(), "",
"empty sources must generate a List with a single NormalizedSource, where prefix is empty,"
+ "no matter of 'spring.cloud.kubernetes.secret.useNameAsPrefix' value");
}
/**
* <pre>
* spring:
* cloud:
* kubernetes:
* secrets:
* useNameAsPrefix: true
* namespace: spring-k8s
* sources:
* - name: secret-one
* </pre>
*
* a config as above will result in a NormalizedSource where prefix will be equal to
* the secret name
*/
@Test
void testUseNameAsPrefixUnsetNonEmptySources() {
SecretsConfigProperties properties = new SecretsConfigProperties();
properties.setUseNameAsPrefix(true);
properties.setNamespace("spring-k8s");
SecretsConfigProperties.Source one = new SecretsConfigProperties.Source();
one.setName("secret-one");
properties.setSources(Collections.singletonList(one));
List<NormalizedSource> sources = properties.determineSources(new MockEnvironment());
Assertions.assertEquals(sources.size(), 1, "a single NormalizedSource is expected");
Assertions.assertEquals(((NamedSecretNormalizedSource) sources.get(0)).prefix(), "secret-one");
}
/**
* <pre>
* spring:
* cloud:
* kubernetes:
* secrets:
* useNameAsPrefix: true
* namespace: spring-k8s
* sources:
* - name: secret-one
* useNameAsPrefix: false
* - name: secret-two
* useNameAsPrefix: true
* - name: secret-three
* </pre>
*
* this test proves that 'spring.cloud.kubernetes.secrets.sources[].useNameAsPrefix'
* will override 'spring.cloud.kubernetes.secrets.useNameAsPrefix'. For the last entry
* in sources, since there is no explicit 'useNameAsPrefix', the one from
* 'spring.cloud.kubernetes.secrets.useNameAsPrefix' will be taken.
*/
@Test
void testUseNameAsPrefixSetNonEmptySources() {
SecretsConfigProperties properties = new SecretsConfigProperties();
properties.setUseNameAsPrefix(true);
properties.setNamespace("spring-k8s");
SecretsConfigProperties.Source one = new SecretsConfigProperties.Source();
one.setName("secret-one");
one.setUseNameAsPrefix(false);
SecretsConfigProperties.Source two = new SecretsConfigProperties.Source();
two.setName("secret-two");
two.setUseNameAsPrefix(true);
SecretsConfigProperties.Source three = new SecretsConfigProperties.Source();
three.setName("secret-three");
properties.setSources(Arrays.asList(one, two, three));
List<NormalizedSource> sources = properties.determineSources(new MockEnvironment());
Assertions.assertEquals(sources.size(), 3, "3 NormalizedSources are expected");
Assertions.assertEquals(((NamedSecretNormalizedSource) sources.get(0)).prefix(), "");
Assertions.assertEquals(((NamedSecretNormalizedSource) sources.get(1)).prefix(), "secret-two");
Assertions.assertEquals(((NamedSecretNormalizedSource) sources.get(2)).prefix(), "secret-three");
}
/**
* <pre>
* spring:
* cloud:
* kubernetes:
* secrets:
* useNameAsPrefix: false
* namespace: spring-k8s
* sources:
* - name: secret-one
* useNameAsPrefix: false
* explicitPrefix: one
* - name: secret-two
* useNameAsPrefix: true
* explicitPrefix: two
* - name: secret-three
* explicitPrefix: three
* - name: secret-four
* </pre>
*
*/
@Test
void testMultipleCases() {
SecretsConfigProperties properties = new SecretsConfigProperties();
properties.setUseNameAsPrefix(false);
properties.setNamespace("spring-k8s");
SecretsConfigProperties.Source one = new SecretsConfigProperties.Source();
one.setNamespace("secret-one");
one.setUseNameAsPrefix(false);
one.setExplicitPrefix("one");
SecretsConfigProperties.Source two = new SecretsConfigProperties.Source();
two.setNamespace("secret-two");
two.setUseNameAsPrefix(true);
two.setExplicitPrefix("two");
SecretsConfigProperties.Source three = new SecretsConfigProperties.Source();
three.setNamespace("secret-three");
three.setExplicitPrefix("three");
SecretsConfigProperties.Source four = new SecretsConfigProperties.Source();
four.setNamespace("secret-four");
properties.setSources(Arrays.asList(one, two, three, four));
List<NormalizedSource> sources = properties.determineSources(new MockEnvironment());
Assertions.assertEquals(sources.size(), 4, "4 NormalizedSources are expected");
Assertions.assertEquals(((NamedSecretNormalizedSource) sources.get(0)).prefix(), "one");
Assertions.assertEquals(((NamedSecretNormalizedSource) sources.get(1)).prefix(), "two");
Assertions.assertEquals(((NamedSecretNormalizedSource) sources.get(2)).prefix(), "three");
Assertions.assertEquals(((NamedSecretNormalizedSource) sources.get(3)).prefix(), "");
}
}

View File

@@ -96,7 +96,7 @@ public class KubernetesConfigServerAutoConfiguration {
List<MapPropertySource> propertySources = new ArrayList<>();
namespaces.forEach(space -> {
NormalizedSource source = new NamedSecretNormalizedSource(applicationName, space, false);
NormalizedSource source = new NamedSecretNormalizedSource(applicationName, space, false, "");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(coreApi, source, space,
springEnv);
propertySources.add(new KubernetesClientSecretsPropertySource(context));

View File

@@ -72,7 +72,7 @@ abstract class ConfigServerIntegrationTest {
assertThat(env.getPropertySources().size()).isEqualTo(2);
assertThat(env.getPropertySources().get(0).getName().equals("configmap.test-cm.default")).isTrue();
assertThat(env.getPropertySources().get(0).getSource().get("app.name")).isEqualTo("test");
assertThat(env.getPropertySources().get(1).getName().equals("secrets.test-cm.default")).isTrue();
assertThat(env.getPropertySources().get(1).getName().equals("secret.test-cm.default")).isTrue();
assertThat(env.getPropertySources().get(1).getSource().get("password")).isEqualTo("p455w0rd");
assertThat(env.getPropertySources().get(1).getSource().get("username")).isEqualTo("user");
}

View File

@@ -117,7 +117,7 @@ class KubernetesEnvironmentRepositoryTests {
kubernetesPropertySourceSuppliers.add((coreApi, applicationName, namespace, springEnv) -> {
List<MapPropertySource> propertySources = new ArrayList<>();
NormalizedSource source = new NamedSecretNormalizedSource(applicationName, "default", false);
NormalizedSource source = new NamedSecretNormalizedSource(applicationName, "default", false, "");
KubernetesClientConfigContext context = new KubernetesClientConfigContext(coreApi, source, "default",
springEnv);
@@ -141,7 +141,7 @@ class KubernetesEnvironmentRepositoryTests {
assertThat(environment.getPropertySources().size()).isEqualTo(2);
environment.getPropertySources().forEach(propertySource -> {
assertThat(propertySource.getName().equals("configmap.application.default")
|| propertySource.getName().equals("secrets.application.default")).isTrue();
|| propertySource.getName().equals("secret.application.default")).isTrue();
if (propertySource.getName().equals("configmap.application.default")) {
assertThat(propertySource.getSource().size()).isEqualTo(3);
assertThat(propertySource.getSource().get("dummy.property.int2")).isEqualTo(1);
@@ -171,17 +171,17 @@ class KubernetesEnvironmentRepositoryTests {
assertThat(environment.getPropertySources().size()).isEqualTo(5);
environment.getPropertySources().forEach(propertySource -> {
assertThat(propertySource.getName().equals("configmap.application.default")
|| propertySource.getName().equals("secrets.application.default")
|| propertySource.getName().equals("secret.application.default")
|| propertySource.getName().equals("configmap.stores.default")
|| propertySource.getName().equals("configmap.stores.dev")
|| propertySource.getName().equals("secrets.stores.default")).isTrue();
|| propertySource.getName().equals("secret.stores.default")).isTrue();
if (propertySource.getName().equals("configmap.application.default")) {
assertThat(propertySource.getSource().size()).isEqualTo(3);
assertThat(propertySource.getSource().get("dummy.property.int2")).isEqualTo(1);
assertThat(propertySource.getSource().get("dummy.property.bool2")).isEqualTo(true);
assertThat(propertySource.getSource().get("dummy.property.string2")).isEqualTo("a");
}
if (propertySource.getName().equals("secrets.application.default")) {
if (propertySource.getName().equals("secret.application.default")) {
assertThat(propertySource.getSource().size()).isEqualTo(2);
assertThat(propertySource.getSource().get("username")).isEqualTo("user");
assertThat(propertySource.getSource().get("password")).isEqualTo("p455w0rd");
@@ -198,7 +198,7 @@ class KubernetesEnvironmentRepositoryTests {
assertThat(propertySource.getSource().get("dummy.property.bool2")).isEqualTo(true);
assertThat(propertySource.getSource().get("dummy.property.string2")).isEqualTo("dev");
}
if (propertySource.getName().equals("secrets.stores.default")) {
if (propertySource.getName().equals("secret.stores.default")) {
assertThat(propertySource.getSource().size()).isEqualTo(2);
assertThat(propertySource.getSource().get("username")).isEqualTo("stores");
assertThat(propertySource.getSource().get("password")).isEqualTo("p455w0rd");
@@ -221,17 +221,17 @@ class KubernetesEnvironmentRepositoryTests {
assertThat(environment.getPropertySources().size()).isEqualTo(5);
environment.getPropertySources().forEach(propertySource -> {
assertThat(propertySource.getName().equals("configmap.application.default")
|| propertySource.getName().equals("secrets.application.default")
|| propertySource.getName().equals("secret.application.default")
|| propertySource.getName().equals("configmap.stores.stores-dev.default")
|| propertySource.getName().equals("configmap.stores.dev")
|| propertySource.getName().equals("secrets.stores.default")).isTrue();
|| propertySource.getName().equals("secret.stores.default")).isTrue();
if (propertySource.getName().equals("configmap.application.default")) {
assertThat(propertySource.getSource().size()).isEqualTo(3);
assertThat(propertySource.getSource().get("dummy.property.int2")).isEqualTo(1);
assertThat(propertySource.getSource().get("dummy.property.bool2")).isEqualTo(true);
assertThat(propertySource.getSource().get("dummy.property.string2")).isEqualTo("a");
}
else if (propertySource.getName().equals("secrets.application.default")) {
else if (propertySource.getName().equals("secret.application.default")) {
assertThat(propertySource.getSource().size()).isEqualTo(2);
assertThat(propertySource.getSource().get("username")).isEqualTo("user");
assertThat(propertySource.getSource().get("password")).isEqualTo("p455w0rd");
@@ -252,7 +252,7 @@ class KubernetesEnvironmentRepositoryTests {
// Currently KubernetesClientSecretsPropertySource does not take into account
// profiles, so that plays no role at the moment
// See https://github.com/spring-cloud/spring-cloud-kubernetes/issues/880
else if (propertySource.getName().equals("secrets.stores.default")) {
else if (propertySource.getName().equals("secret.stores.default")) {
assertThat(propertySource.getSource().size()).isEqualTo(2);
assertThat(propertySource.getSource().get("username")).isEqualTo("stores");
assertThat(propertySource.getSource().get("password")).isEqualTo("p455w0rd");

View File

@@ -57,8 +57,7 @@ public final class Fabric8ConfigMapPropertySource extends ConfigMapPropertySourc
// we need to pass various functions because the code we are interested in
// is protected in ConfigMapPropertySource, and must stay that way.
private static Fabric8ContextToSourceData namedConfigMap() {
return NamedConfigMapContextToSourceDataProvider.of(ConfigMapPropertySource::processAllEntries,
ConfigMapPropertySource::getSourceName, ConfigMapPropertySource::withPrefix).get();
return NamedConfigMapContextToSourceDataProvider.of(ConfigMapPropertySource::processAllEntries).get();
}
}

View File

@@ -51,11 +51,11 @@ public final class Fabric8SecretsPropertySource extends SecretsPropertySource {
}
private static Fabric8ContextToSourceData namedSecret() {
return NamedSecretContextToSourceDataProvider.of(SecretsPropertySource::getSourceName).get();
return new NamedSecretContextToSourceDataProvider().get();
}
private static Fabric8ContextToSourceData labeledSecret() {
return LabeledSecretContextToSourceDataProvider.of(SecretsPropertySource::getSourceName).get();
return new LabeledSecretContextToSourceDataProvider().get();
}
}

View File

@@ -19,8 +19,6 @@ package org.springframework.cloud.kubernetes.fabric8.config;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -29,6 +27,7 @@ import io.fabric8.kubernetes.api.model.Secret;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.kubernetes.commons.config.ConfigUtils;
import org.springframework.cloud.kubernetes.commons.config.LabeledSecretNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.SourceData;
@@ -45,14 +44,7 @@ final class LabeledSecretContextToSourceDataProvider implements Supplier<Fabric8
private static final Log LOG = LogFactory.getLog(LabeledSecretContextToSourceDataProvider.class);
private final BiFunction<String, String, String> sourceNameMapper;
private LabeledSecretContextToSourceDataProvider(BiFunction<String, String, String> sourceNameFunction) {
this.sourceNameMapper = Objects.requireNonNull(sourceNameFunction);
}
static LabeledSecretContextToSourceDataProvider of(BiFunction<String, String, String> sourceNameFunction) {
return new LabeledSecretContextToSourceDataProvider(sourceNameFunction);
LabeledSecretContextToSourceDataProvider() {
}
/*
@@ -99,7 +91,7 @@ final class LabeledSecretContextToSourceDataProvider implements Supplier<Fabric8
onException(source.failFast(), message, e);
}
String propertySourceName = sourceNameMapper.apply(sourceName, namespace);
String propertySourceName = ConfigUtils.sourceName(source.target(), sourceName, namespace);
return new SourceData(propertySourceName, result);
};
}

View File

@@ -22,19 +22,17 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.kubernetes.commons.config.ConfigMapPrefixContext;
import org.springframework.cloud.kubernetes.commons.config.ConfigUtils;
import org.springframework.cloud.kubernetes.commons.config.NamedConfigMapNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.NormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.PrefixContext;
import org.springframework.cloud.kubernetes.commons.config.SourceData;
import org.springframework.core.env.Environment;
import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.getApplicationName;
import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.onException;
import static org.springframework.cloud.kubernetes.commons.config.Constants.PROPERTY_SOURCE_NAME_SEPARATOR;
import static org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigUtils.getConfigMapData;
@@ -51,24 +49,14 @@ final class NamedConfigMapContextToSourceDataProvider implements Supplier<Fabric
private final BiFunction<Map<String, String>, Environment, Map<String, Object>> entriesProcessor;
private final BiFunction<String, String, String> sourceNameMapper;
private final Function<ConfigMapPrefixContext, SourceData> withPrefix;
private NamedConfigMapContextToSourceDataProvider(
BiFunction<Map<String, String>, Environment, Map<String, Object>> entriesProcessor,
BiFunction<String, String, String> sourceNameMapper,
Function<ConfigMapPrefixContext, SourceData> withPrefix) {
BiFunction<Map<String, String>, Environment, Map<String, Object>> entriesProcessor) {
this.entriesProcessor = Objects.requireNonNull(entriesProcessor);
this.sourceNameMapper = Objects.requireNonNull(sourceNameMapper);
this.withPrefix = Objects.requireNonNull(withPrefix);
}
static NamedConfigMapContextToSourceDataProvider of(
BiFunction<Map<String, String>, Environment, Map<String, Object>> entriesProcessor,
BiFunction<String, String, String> sourceNameMapper,
Function<ConfigMapPrefixContext, SourceData> withPrefix) {
return new NamedConfigMapContextToSourceDataProvider(entriesProcessor, sourceNameMapper, withPrefix);
BiFunction<Map<String, String>, Environment, Map<String, Object>> entriesProcessor) {
return new NamedConfigMapContextToSourceDataProvider(entriesProcessor);
}
/*
@@ -85,7 +73,7 @@ final class NamedConfigMapContextToSourceDataProvider implements Supplier<Fabric
NamedConfigMapNormalizedSource source = (NamedConfigMapNormalizedSource) context.normalizedSource();
String namespace = context.namespace();
String initialConfigMapName = appName(context.environment(), source).get();
String initialConfigMapName = source.name().orElseThrow();
String currentConfigMapName = initialConfigMapName;
Set<String> propertySourceNames = new LinkedHashSet<>();
propertySourceNames.add(initialConfigMapName);
@@ -110,9 +98,9 @@ final class NamedConfigMapContextToSourceDataProvider implements Supplier<Fabric
}
if (!"".equals(source.prefix())) {
ConfigMapPrefixContext prefixContext = new ConfigMapPrefixContext(result, source.prefix(),
namespace, propertySourceNames);
return withPrefix.apply(prefixContext);
PrefixContext prefixContext = new PrefixContext(result, source.prefix(), namespace,
propertySourceNames);
return ConfigUtils.withPrefix(source.target(), prefixContext);
}
}
@@ -123,13 +111,9 @@ final class NamedConfigMapContextToSourceDataProvider implements Supplier<Fabric
}
String names = String.join(PROPERTY_SOURCE_NAME_SEPARATOR, propertySourceNames);
return new SourceData(sourceNameMapper.apply(names, namespace), result);
return new SourceData(ConfigUtils.sourceName(source.target(), names, namespace), result);
};
}
private Supplier<String> appName(Environment environment, NormalizedSource normalizedSource) {
return () -> getApplicationName(environment, normalizedSource.name().orElse(null), normalizedSource.target());
}
}

View File

@@ -17,16 +17,18 @@
package org.springframework.cloud.kubernetes.fabric8.config;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.Set;
import java.util.function.Supplier;
import io.fabric8.kubernetes.api.model.Secret;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.kubernetes.commons.config.ConfigUtils;
import org.springframework.cloud.kubernetes.commons.config.NamedSecretNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.PrefixContext;
import org.springframework.cloud.kubernetes.commons.config.SourceData;
import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.onException;
@@ -41,14 +43,7 @@ final class NamedSecretContextToSourceDataProvider implements Supplier<Fabric8Co
private static final Log LOG = LogFactory.getLog(LabeledSecretContextToSourceDataProvider.class);
private final BiFunction<String, String, String> sourceNameMapper;
private NamedSecretContextToSourceDataProvider(BiFunction<String, String, String> sourceNameFunction) {
this.sourceNameMapper = Objects.requireNonNull(sourceNameFunction);
}
static NamedSecretContextToSourceDataProvider of(BiFunction<String, String, String> sourceNameFunction) {
return new NamedSecretContextToSourceDataProvider(sourceNameFunction);
NamedSecretContextToSourceDataProvider() {
}
@Override
@@ -56,6 +51,8 @@ final class NamedSecretContextToSourceDataProvider implements Supplier<Fabric8Co
return context -> {
NamedSecretNormalizedSource source = (NamedSecretNormalizedSource) context.normalizedSource();
Set<String> propertySourceNames = new LinkedHashSet<>();
propertySourceNames.add(source.name().orElseThrow());
Map<String, Object> result = new HashMap<>();
// error should never be thrown here, since we always expect a name
@@ -73,6 +70,12 @@ final class NamedSecretContextToSourceDataProvider implements Supplier<Fabric8Co
}
else {
result = dataFromSecret(secret, namespace);
if (!"".equals(source.prefix())) {
PrefixContext prefixContext = new PrefixContext(result, source.prefix(), namespace,
propertySourceNames);
return ConfigUtils.withPrefix(source.target(), prefixContext);
}
}
}
@@ -82,7 +85,7 @@ final class NamedSecretContextToSourceDataProvider implements Supplier<Fabric8Co
onException(source.failFast(), message, e);
}
String sourceName = sourceNameMapper.apply(secretName, namespace);
String sourceName = ConfigUtils.sourceName(source.target(), secretName, namespace);
return new SourceData(sourceName, result);
};
}

View File

@@ -49,7 +49,7 @@ class Fabric8SecretsPropertySourceMockTests {
final String namespace = "default";
final String path = String.format("/api/v1/namespaces/%s/secrets/%s", namespace, name);
NamedSecretNormalizedSource named = new NamedSecretNormalizedSource(name, namespace, true);
NamedSecretNormalizedSource named = new NamedSecretNormalizedSource(name, namespace, true, "");
Fabric8ConfigContext context = new Fabric8ConfigContext(client, named, "default", new MockEnvironment());
mockServer.expect().withPath(path).andReturn(500, "Internal Server Error").once();
@@ -77,7 +77,7 @@ class Fabric8SecretsPropertySourceMockTests {
final String namespace = "default";
final String path = String.format("/api/v1/namespaces/%s/secrets/%s", namespace, name);
NamedSecretNormalizedSource named = new NamedSecretNormalizedSource(name, namespace, false);
NamedSecretNormalizedSource named = new NamedSecretNormalizedSource(name, namespace, false, "");
Fabric8ConfigContext context = new Fabric8ConfigContext(client, named, "default", new MockEnvironment());
mockServer.expect().withPath(path).andReturn(500, "Internal Server Error").once();

View File

@@ -33,7 +33,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.cloud.kubernetes.commons.config.LabeledSecretNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.NormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySource;
import org.springframework.cloud.kubernetes.commons.config.SourceData;
import org.springframework.mock.env.MockEnvironment;
@@ -96,10 +95,10 @@ class LabeledSecretContextToSourceDataProviderTests {
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE,
new MockEnvironment());
Fabric8ContextToSourceData data = LabeledSecretContextToSourceDataProvider.of(Dummy::sourceName).get();
Fabric8ContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals("secrets.test-secret.default", sourceData.sourceName());
Assertions.assertEquals("secret.test-secret.default", sourceData.sourceName());
Assertions.assertEquals(Map.of("secretName", "secretValue"), sourceData.sourceData());
}
@@ -129,10 +128,10 @@ class LabeledSecretContextToSourceDataProviderTests {
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE,
new MockEnvironment());
Fabric8ContextToSourceData data = LabeledSecretContextToSourceDataProvider.of(Dummy::sourceName).get();
Fabric8ContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.red-secret.red-secret-again.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.red-secret.red-secret-again.default");
Assertions.assertEquals(sourceData.sourceData().size(), 2);
Assertions.assertEquals(sourceData.sourceData().get("colorOne"), "really-red");
Assertions.assertEquals(sourceData.sourceData().get("colorTwo"), "really-red-again");
@@ -154,10 +153,10 @@ class LabeledSecretContextToSourceDataProviderTests {
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE,
new MockEnvironment());
Fabric8ContextToSourceData data = LabeledSecretContextToSourceDataProvider.of(Dummy::sourceName).get();
Fabric8ContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.color.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.color.default");
Assertions.assertEquals(sourceData.sourceData(), Collections.emptyMap());
}
@@ -180,24 +179,11 @@ class LabeledSecretContextToSourceDataProviderTests {
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE,
new MockEnvironment());
Fabric8ContextToSourceData data = LabeledSecretContextToSourceDataProvider.of(Dummy::sourceName).get();
Fabric8ContextToSourceData data = new LabeledSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals("secrets.test-secret.default", sourceData.sourceName());
Assertions.assertEquals("secret.test-secret.default", sourceData.sourceName());
Assertions.assertEquals(Map.of("secretName", "secretValue"), sourceData.sourceData());
}
// needed only to allow access to the super methods
private final static class Dummy extends SecretsPropertySource {
private Dummy() {
super(SourceData.emptyRecord("dummy-name"));
}
private static String sourceName(String name, String namespace) {
return getSourceName(name, namespace);
}
}
}

View File

@@ -29,7 +29,6 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.kubernetes.commons.config.ConfigMapPrefixContext;
import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySource;
import org.springframework.cloud.kubernetes.commons.config.NamedConfigMapNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.NormalizedSource;
@@ -82,8 +81,7 @@ class NamedConfigMapContextToSourceDataProviderTests {
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE,
new MockEnvironment());
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries).get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.blue.default");
@@ -106,8 +104,7 @@ class NamedConfigMapContextToSourceDataProviderTests {
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE,
new MockEnvironment());
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries).get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.red.default");
@@ -138,8 +135,7 @@ class NamedConfigMapContextToSourceDataProviderTests {
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE, env);
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries).get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.red.red-with-profile.default");
@@ -175,8 +171,7 @@ class NamedConfigMapContextToSourceDataProviderTests {
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE, env);
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries).get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.red.red-with-profile.default");
@@ -216,8 +211,7 @@ class NamedConfigMapContextToSourceDataProviderTests {
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE, env);
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries).get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.red.red-with-taste.red-with-shape.default");
@@ -228,22 +222,22 @@ class NamedConfigMapContextToSourceDataProviderTests {
}
// this test makes sure that even if NormalizedSource has no name (which is a valid
// case for config maps),
// it will default to "application" and such a config map will be read.
// when reading config maps and creating normalized sources, we will always be
// providing a name
// for the config map; even if one is not provided explicitly.
@Test
void matchWithoutName() {
void matchWithName() {
ConfigMap configMap = new ConfigMapBuilder().withNewMetadata().withName("application").endMetadata()
.addToData("color", "red").build();
mockClient.configMaps().inNamespace(NAMESPACE).create(configMap);
NormalizedSource normalizedSource = new NamedConfigMapNormalizedSource(null, NAMESPACE, true, "", false);
NormalizedSource normalizedSource = new NamedConfigMapNormalizedSource("application", NAMESPACE, true, "",
false);
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE,
new MockEnvironment());
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries).get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.application.default");
@@ -270,8 +264,7 @@ class NamedConfigMapContextToSourceDataProviderTests {
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE,
new MockEnvironment());
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider
.of(Dummy::processEntries, Dummy::sourceName, Dummy::prefix).get();
Fabric8ContextToSourceData data = NamedConfigMapContextToSourceDataProvider.of(Dummy::processEntries).get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "configmap.red.default");
@@ -285,18 +278,10 @@ class NamedConfigMapContextToSourceDataProviderTests {
super(SourceData.emptyRecord("dummy-name"));
}
private static String sourceName(String name, String namespace) {
return getSourceName(name, namespace);
}
private static Map<String, Object> processEntries(Map<String, String> map, Environment environment) {
return processAllEntries(map, environment);
}
private static SourceData prefix(ConfigMapPrefixContext context) {
return withPrefix(context);
}
}
}

View File

@@ -32,7 +32,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.cloud.kubernetes.commons.config.NamedSecretNormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.NormalizedSource;
import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySource;
import org.springframework.cloud.kubernetes.commons.config.SourceData;
import org.springframework.mock.env.MockEnvironment;
@@ -77,14 +76,14 @@ class NamedSecretContextToSourceDataProviderTests {
mockClient.secrets().inNamespace(NAMESPACE).create(secret);
NormalizedSource normalizedSource = new NamedSecretNormalizedSource("red", NAMESPACE, true);
NormalizedSource normalizedSource = new NamedSecretNormalizedSource("red", NAMESPACE, true, "");
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE,
new MockEnvironment());
Fabric8ContextToSourceData data = NamedSecretContextToSourceDataProvider.of(Dummy::sourceName).get();
Fabric8ContextToSourceData data = new NamedSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.red.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.red.default");
Assertions.assertEquals(sourceData.sourceData(), Map.of("color", "really-red"));
}
@@ -109,14 +108,14 @@ class NamedSecretContextToSourceDataProviderTests {
mockClient.secrets().inNamespace(NAMESPACE).create(blue);
mockClient.secrets().inNamespace(NAMESPACE).create(yellow);
NormalizedSource normalizedSource = new NamedSecretNormalizedSource("red", NAMESPACE, true);
NormalizedSource normalizedSource = new NamedSecretNormalizedSource("red", NAMESPACE, true, "");
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE,
new MockEnvironment());
Fabric8ContextToSourceData data = NamedSecretContextToSourceDataProvider.of(Dummy::sourceName).get();
Fabric8ContextToSourceData data = new NamedSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.red.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.red.default");
Assertions.assertEquals(sourceData.sourceData().size(), 1);
Assertions.assertEquals(sourceData.sourceData().get("color"), "really-red");
@@ -133,14 +132,14 @@ class NamedSecretContextToSourceDataProviderTests {
mockClient.secrets().inNamespace(NAMESPACE).create(pink);
NormalizedSource normalizedSource = new NamedSecretNormalizedSource("blue", NAMESPACE, true);
NormalizedSource normalizedSource = new NamedSecretNormalizedSource("blue", NAMESPACE, true, "");
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE,
new MockEnvironment());
Fabric8ContextToSourceData data = NamedSecretContextToSourceDataProvider.of(Dummy::sourceName).get();
Fabric8ContextToSourceData data = new NamedSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.blue.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.blue.default");
Assertions.assertEquals(sourceData.sourceData(), Collections.emptyMap());
}
@@ -159,28 +158,15 @@ class NamedSecretContextToSourceDataProviderTests {
mockClient.secrets().inNamespace(NAMESPACE).create(secret);
// different namespace
NormalizedSource normalizedSource = new NamedSecretNormalizedSource("red", NAMESPACE + "nope", true);
NormalizedSource normalizedSource = new NamedSecretNormalizedSource("red", NAMESPACE + "nope", true, "");
Fabric8ConfigContext context = new Fabric8ConfigContext(mockClient, normalizedSource, NAMESPACE,
new MockEnvironment());
Fabric8ContextToSourceData data = NamedSecretContextToSourceDataProvider.of(Dummy::sourceName).get();
Fabric8ContextToSourceData data = new NamedSecretContextToSourceDataProvider().get();
SourceData sourceData = data.apply(context);
Assertions.assertEquals(sourceData.sourceName(), "secrets.red.default");
Assertions.assertEquals(sourceData.sourceName(), "secret.red.default");
Assertions.assertEquals(sourceData.sourceData(), Map.of("color", "really-red"));
}
// needed only to allow access to the super methods
private static final class Dummy extends SecretsPropertySource {
private Dummy() {
super(SourceData.emptyRecord("dummy-name"));
}
private static String sourceName(String name, String namespace) {
return getSourceName(name, namespace);
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2013-2021 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix.properties.One;
import org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix.properties.Three;
import org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix.properties.Two;
@SpringBootApplication
@EnableConfigurationProperties({ One.class, Two.class, Three.class })
public class NamedConfigMapWithPrefixApp {
public static void main(String[] args) {
SpringApplication.run(NamedConfigMapWithPrefixApp.class, args);
}
}

View File

@@ -14,33 +14,29 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.fabric8.config;
package org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.kubernetes.fabric8.config.with_prefix.WithPrefixApp;
import org.springframework.test.context.junit.jupiter.SpringExtension;
/**
* @author wind57
*/
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WithPrefixApp.class,
properties = { "spring.cloud.bootstrap.name=config-map-name-as-prefix", "spring.main.cloud-platform=KUBERNETES",
"spring.cloud.bootstrap.enabled=true" })
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedConfigMapWithPrefixApp.class,
properties = { "spring.cloud.bootstrap.name=named-config-map-with-prefix",
"spring.main.cloud-platform=KUBERNETES", "spring.cloud.bootstrap.enabled=true" })
@AutoConfigureWebTestClient
@EnableKubernetesMockClient(crud = true, https = false)
class BootstrapConfigMapWithPrefixTests extends ConfigMapWithPrefixTests {
class NamedConfigMapWithPrefixBootstrapTests extends NamedConfigMapWithPrefixTests {
private static KubernetesClient mockClient;
@BeforeAll
public static void setUpBeforeClass() {
static void setUpBeforeClass() {
setUpBeforeClass(mockClient);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2021 the original author or authors.
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,33 +14,29 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.fabric8.config;
package org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.kubernetes.fabric8.config.with_prefix.WithPrefixApp;
import org.springframework.test.context.junit.jupiter.SpringExtension;
/**
* @author wind57
*/
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WithPrefixApp.class,
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedConfigMapWithPrefixApp.class,
properties = { "spring.application.name=config-map-name-as-prefix", "spring.main.cloud-platform=KUBERNETES",
"spring.config.import=kubernetes:,classpath:./config-map-name-as-prefix.yaml" })
"spring.config.import=kubernetes:,classpath:./named-config-map-with-prefix.yaml" })
@AutoConfigureWebTestClient
@EnableKubernetesMockClient(crud = true, https = false)
class ConfigDataConfigMapWithPrefixTests extends ConfigMapWithPrefixTests {
class NamedConfigMapWithPrefixConfigDataTests extends NamedConfigMapWithPrefixTests {
private static KubernetesClient mockClient;
@BeforeAll
public static void setUpBeforeClass() {
static void setUpBeforeClass() {
setUpBeforeClass(mockClient);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2021 the original author or authors.
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.fabric8.config;
package org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix;
import java.util.HashMap;
import java.util.Map;
@@ -24,32 +24,23 @@ import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.kubernetes.fabric8.config.with_prefix.WithPrefixApp;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.reactive.server.WebTestClient;
/**
* @author wind57
* @author Ryan Baxter
*/
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WithPrefixApp.class,
properties = { "spring.cloud.bootstrap.name=config-map-name-as-prefix",
"spring.main.cloud-platform=KUBERNETES" })
@AutoConfigureWebTestClient
abstract class ConfigMapWithPrefixTests {
abstract class NamedConfigMapWithPrefixTests {
private static KubernetesClient mockClient;
@Autowired
private WebTestClient webClient;
public static void setUpBeforeClass(KubernetesClient mockClient) {
ConfigMapWithPrefixTests.mockClient = mockClient;
static void setUpBeforeClass(KubernetesClient mockClient) {
NamedConfigMapWithPrefixTests.mockClient = mockClient;
// Configure the kubernetes master url to point to the mock server
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, mockClient.getConfiguration().getMasterUrl());
System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true");
@@ -72,7 +63,7 @@ abstract class ConfigMapWithPrefixTests {
}
private static void createConfigmap(String name, Map<String, String> data) {
static void createConfigmap(String name, Map<String, String> data) {
mockClient.configMaps().inNamespace("spring-k8s")
.create(new ConfigMapBuilder().withNewMetadata().withName(name).endMetadata().addToData(data).build());
}
@@ -87,9 +78,9 @@ abstract class ConfigMapWithPrefixTests {
* </pre>
*/
@Test
public void testOne() {
this.webClient.get().uri("/prefix/one").exchange().expectStatus().isOk().expectBody(String.class)
.value(Matchers.equalTo("one"));
void testOne() {
this.webClient.get().uri("/named-config-map/prefix/one").exchange().expectStatus().isOk()
.expectBody(String.class).value(Matchers.equalTo("one"));
}
/**
@@ -102,9 +93,9 @@ abstract class ConfigMapWithPrefixTests {
* </pre>
*/
@Test
public void testTwo() {
this.webClient.get().uri("/prefix/two").exchange().expectStatus().isOk().expectBody(String.class)
.value(Matchers.equalTo("two"));
void testTwo() {
this.webClient.get().uri("/named-config-map/prefix/two").exchange().expectStatus().isOk()
.expectBody(String.class).value(Matchers.equalTo("two"));
}
/**
@@ -117,9 +108,9 @@ abstract class ConfigMapWithPrefixTests {
* </pre>
*/
@Test
public void testThree() {
this.webClient.get().uri("/prefix/three").exchange().expectStatus().isOk().expectBody(String.class)
.value(Matchers.equalTo("three"));
void testThree() {
this.webClient.get().uri("/named-config-map/prefix/three").exchange().expectStatus().isOk()
.expectBody(String.class).value(Matchers.equalTo("three"));
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2013-2021 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix.controller;
import org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix.properties.One;
import org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix.properties.Three;
import org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix.properties.Two;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class NamedConfigMapWithPrefixController {
private final One one;
private final Two two;
private final Three three;
public NamedConfigMapWithPrefixController(One one, Two two, Three three) {
this.one = one;
this.two = two;
this.three = three;
}
@GetMapping("/named-config-map/prefix/one")
public String one() {
return one.getProperty();
}
@GetMapping("/named-config-map/prefix/two")
public String two() {
return two.getProperty();
}
@GetMapping("/named-config-map/prefix/three")
public String three() {
return three.getProperty();
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2013-2021 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("one")
public class One {
private String property;
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.fabric8.config.with_prefix.properties;
package org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2013-2021 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.fabric8.config.named_config_map_with_prefix.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("two")
public class Two {
private String property;
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
}

View File

@@ -14,21 +14,21 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.fabric8.config.with_prefix;
package org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.kubernetes.fabric8.config.with_prefix.properties.One;
import org.springframework.cloud.kubernetes.fabric8.config.with_prefix.properties.Three;
import org.springframework.cloud.kubernetes.fabric8.config.with_prefix.properties.Two;
import org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix.properties.One;
import org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix.properties.Three;
import org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix.properties.Two;
@SpringBootApplication
@EnableConfigurationProperties({ One.class, Two.class, Three.class })
public class WithPrefixApp {
public class NamedSecretWithPrefixApp {
public static void main(String[] args) {
SpringApplication.run(WithPrefixApp.class, args);
SpringApplication.run(NamedSecretWithPrefixApp.class, args);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2013-2021 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
import org.junit.jupiter.api.BeforeAll;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author wind57
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedSecretWithPrefixApp.class,
properties = { "spring.cloud.bootstrap.name=named-secret-with-prefix", "spring.main.cloud-platform=KUBERNETES",
"spring.cloud.bootstrap.enabled=true" })
@EnableKubernetesMockClient(crud = true, https = false)
class NamedSecretWithPrefixBootstrapTests extends NamedSecretWithPrefixTests {
private static KubernetesClient mockClient;
@BeforeAll
static void setUpBeforeClass() {
setUpBeforeClass(mockClient);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2013-2022 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
import org.junit.jupiter.api.BeforeAll;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author wind57
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NamedSecretWithPrefixApp.class,
properties = { "spring.application.name=named-secret-with-prefix", "spring.main.cloud-platform=KUBERNETES",
"spring.config.import=kubernetes:,classpath:./named-secret-with-prefix.yaml" })
@EnableKubernetesMockClient(crud = true, https = false)
class NamedSecretWithPrefixConfigDataTests extends NamedSecretWithPrefixTests {
private static KubernetesClient mockClient;
@BeforeAll
static void setUpBeforeClass() {
setUpBeforeClass(mockClient);
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright 2013-2021 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collections;
import java.util.Map;
import io.fabric8.kubernetes.api.model.SecretBuilder;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.reactive.server.WebTestClient;
/**
* @author wind57
*/
abstract class NamedSecretWithPrefixTests {
private static KubernetesClient mockClient;
@Autowired
private WebTestClient webClient;
static void setUpBeforeClass(KubernetesClient mockClient) {
NamedSecretWithPrefixTests.mockClient = mockClient;
// Configure the kubernetes master url to point to the mock server
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, mockClient.getConfiguration().getMasterUrl());
System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true");
System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false");
System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, "false");
System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test");
System.setProperty(Config.KUBERNETES_HTTP2_DISABLE, "true");
Map<String, String> one = Collections.singletonMap("one.property",
Base64.getEncoder().encodeToString("one".getBytes(StandardCharsets.UTF_8)));
createSecret("secret-one", one);
Map<String, String> two = Collections.singletonMap("property",
Base64.getEncoder().encodeToString("two".getBytes(StandardCharsets.UTF_8)));
createSecret("secret-two", two);
Map<String, String> three = Collections.singletonMap("property",
Base64.getEncoder().encodeToString("three".getBytes(StandardCharsets.UTF_8)));
createSecret("secret-three", three);
}
private static void createSecret(String name, Map<String, String> data) {
mockClient.secrets().inNamespace("spring-k8s")
.create(new SecretBuilder().withNewMetadata().withName(name).endMetadata().addToData(data).build());
}
/**
* <pre>
* 'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
* 'spring.cloud.kubernetes.secrets.sources[0].useNameAsPrefix=false'
* ("one.property", "one")
*
* As such: @ConfigurationProperties("one")
* </pre>
*/
@Test
void testOne() {
this.webClient.get().uri("/named-secret/prefix/one").exchange().expectStatus().isOk().expectBody(String.class)
.value(Matchers.equalTo("one"));
}
/**
* <pre>
* 'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
* 'spring.cloud.kubernetes.secrets.sources[1].explicitPrefix=two'
* ("property", "two")
*
* As such: @ConfigurationProperties("two")
* </pre>
*/
@Test
void testTwo() {
this.webClient.get().uri("/named-secret/prefix/two").exchange().expectStatus().isOk().expectBody(String.class)
.value(Matchers.equalTo("two"));
}
/**
* <pre>
* 'spring.cloud.kubernetes.secrets.useNameAsPrefix=true'
* 'spring.cloud.kubernetes.secrets.sources[2].name=secret-three'
* ("property", "three")
*
* As such: @ConfigurationProperties(prefix = "secret-three")
* </pre>
*/
@Test
void testThree() {
this.webClient.get().uri("/named-secret/prefix/three").exchange().expectStatus().isOk().expectBody(String.class)
.value(Matchers.equalTo("three"));
}
}

View File

@@ -14,16 +14,16 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.fabric8.config.with_prefix.controller;
package org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix.controller;
import org.springframework.cloud.kubernetes.fabric8.config.with_prefix.properties.One;
import org.springframework.cloud.kubernetes.fabric8.config.with_prefix.properties.Three;
import org.springframework.cloud.kubernetes.fabric8.config.with_prefix.properties.Two;
import org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix.properties.One;
import org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix.properties.Three;
import org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix.properties.Two;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Controller {
public class NamedSecretWithPrefixController {
private final One one;
@@ -31,23 +31,23 @@ public class Controller {
private final Three three;
public Controller(One one, Two two, Three three) {
public NamedSecretWithPrefixController(One one, Two two, Three three) {
this.one = one;
this.two = two;
this.three = three;
}
@GetMapping("/prefix/one")
@GetMapping("/named-secret/prefix/one")
public String one() {
return one.getProperty();
}
@GetMapping("/prefix/two")
@GetMapping("/named-secret/prefix/two")
public String two() {
return two.getProperty();
}
@GetMapping("/prefix/three")
@GetMapping("/named-secret/prefix/three")
public String three() {
return three.getProperty();
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.fabric8.config.with_prefix.properties;
package org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2013-2021 the original author or authors.
*
* 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 org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "secret-three")
public class Three {
private String property;
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.fabric8.config.with_prefix.properties;
package org.springframework.cloud.kubernetes.fabric8.config.named_secret_with_prefix.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -1,6 +1,6 @@
spring:
application:
name: with-prefix
name: named-config-map-with-prefix
cloud:
kubernetes:
config:

View File

@@ -0,0 +1,15 @@
spring:
application:
name: named-secret-with-prefix
cloud:
kubernetes:
secrets:
enableApi: true
useNameAsPrefix: true
namespace: spring-k8s
sources:
- name: secret-one
useNameAsPrefix: false
- name: secret-two
explicitPrefix: two
- name: secret-three