Fix 508 (#856)
* moved code + tests added * started * checkstyle * trigger build one more time * fabric8 changes + tests * checkstyle * checkstyle * fix same mapping controller entries * started work on k8s-client * prepare test appliations * minor rename * change to be able to read easier * k8s client fix + tests * documentation * trigger build * more changes * rename property and everything related to it * rename property and everything related to it
This commit is contained in:
@@ -353,7 +353,7 @@ Notice that `spring.cloud.kubernetes.config.useNameAsPrefix` has a _lower_ prior
|
||||
This allows you to set a "default" strategy for all sources, at the same time allowing to override only a few.
|
||||
|
||||
If using the config map name is not an option, you can specify a different strategy, called : `explicitPrefix`. Since this is an _explicit_ prefix that
|
||||
you select, it can only be supplied to the `sources` level. At the same time it has a higher priority than `useNameASPrefix`. Let's suppose we have a third config map with these entries:
|
||||
you select, it can only be supplied to the `sources` level. At the same time it has a higher priority than `useNameAsPrefix`. Let's suppose we have a third config map with these entries:
|
||||
|
||||
|
||||
====
|
||||
@@ -400,6 +400,50 @@ will result in three properties being generated:
|
||||
|
||||
- `config-map-three.greetings.message` equal to `Say Hello from three`.
|
||||
|
||||
By default, besides reading the config map that is specified in the `sources` configuration, Spring will also try to read
|
||||
all properties from "profile aware" sources. The easiest way to explain this is via an example. Let's suppose your application
|
||||
enables a profile called "dev" and you have a configuration like the one below:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: spring-k8s
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
namespace: default-namespace
|
||||
sources:
|
||||
- name: config-map-one
|
||||
----
|
||||
====
|
||||
|
||||
Besides reading the `config-map-one`, Spring will also try to read `config-map-one-dev`; in this particular order. Each active profile
|
||||
generates such a profile aware config map.
|
||||
|
||||
Though your application should not be impacted by such a config map, it can be disabled if needed:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: spring-k8s
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
includeProfileSpecificSources: false
|
||||
namespace: default-namespace
|
||||
sources:
|
||||
- name: config-map-one
|
||||
includeProfileSpecificSources: false
|
||||
----
|
||||
====
|
||||
|
||||
Notice that just like before, there are two levels where you can specify this property: for all config maps or
|
||||
for individual ones; the latter having a higher priority.
|
||||
|
||||
NOTE: You should check the security configuration section. To access config maps from inside a pod you need to have the correct
|
||||
Kubernetes service accounts, roles and role bindings.
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-test-support</artifactId>
|
||||
@@ -86,6 +87,18 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
@@ -39,18 +39,25 @@ public class KubernetesClientConfigMapPropertySource extends ConfigMapPropertySo
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesClientConfigMapPropertySource.class);
|
||||
|
||||
@Deprecated
|
||||
public KubernetesClientConfigMapPropertySource(CoreV1Api coreV1Api, String name, String namespace,
|
||||
Environment environment, String prefix) {
|
||||
super(getName(name, namespace), getData(coreV1Api, name, namespace, environment, prefix));
|
||||
Environment environment) {
|
||||
super(getName(name, namespace), getData(coreV1Api, name, namespace, environment, "", true));
|
||||
}
|
||||
|
||||
public KubernetesClientConfigMapPropertySource(CoreV1Api coreV1Api, String name, String namespace,
|
||||
Environment environment, String prefix, boolean includeProfileSpecificSources) {
|
||||
super(getName(name, namespace),
|
||||
getData(coreV1Api, name, namespace, environment, prefix, includeProfileSpecificSources));
|
||||
}
|
||||
|
||||
private static Map<String, Object> getData(CoreV1Api coreV1Api, String name, String namespace,
|
||||
Environment environment, String prefix) {
|
||||
Environment environment, String prefix, boolean includeProfileSpecificSources) {
|
||||
|
||||
try {
|
||||
Set<String> names = new HashSet<>();
|
||||
names.add(name);
|
||||
if (environment != null) {
|
||||
if (environment != null && includeProfileSpecificSources) {
|
||||
for (String activeProfile : environment.getActiveProfiles()) {
|
||||
names.add(name + "-" + activeProfile);
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ public class KubernetesClientConfigMapPropertySourceLocator extends ConfigMapPro
|
||||
}
|
||||
|
||||
return new KubernetesClientConfigMapPropertySource(coreV1Api, name, namespace, environment,
|
||||
normalizedSource.getPrefix());
|
||||
normalizedSource.getPrefix(), normalizedSource.isIncludeProfileSpecificSources());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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.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.client.config.applications.include_profile_specific_sources.IncludeProfileSpecificSourcesApp;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
/**
|
||||
* The stub data for this test is in : IncludeProfileSpecificSourcesConfigurationStub
|
||||
*
|
||||
* @author wind57
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = IncludeProfileSpecificSourcesApp.class,
|
||||
properties = { "spring.cloud.bootstrap.name=include-profile-specific-sources", "include.profile.specific.sources=true" })
|
||||
@AutoConfigureWebTestClient
|
||||
@ActiveProfiles("dev")
|
||||
class KubernetesClientConfigMapIncludeProfileSpecificSourcesTests {
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() {
|
||||
WireMock.reset();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterAll() {
|
||||
WireMock.shutdownServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 'spring.cloud.kubernetes.config.includeProfileSpecificSources=false'
|
||||
* 'spring.cloud.kubernetes.config.sources[0].includeProfileSpecificSources=true'
|
||||
* 'spring.cloud.kubernetes.config.sources[0].name=config-map-one'
|
||||
*
|
||||
* We do not define config-map 'config-map-one', but we do define 'config-map-one-dev'.
|
||||
*
|
||||
* As such: @ConfigurationProperties("one") must be resolved from 'config-map-one-dev'
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testOne() {
|
||||
this.webClient.get().uri("/profile-specific/one").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
.value(Matchers.equalTo("one"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 'spring.cloud.kubernetes.config.includeProfileSpecificSources=false'
|
||||
* 'spring.cloud.kubernetes.config.sources[1].includeProfileSpecificSources=false'
|
||||
* 'spring.cloud.kubernetes.config.sources[1].name=config-map-two'
|
||||
*
|
||||
* We define config-map 'config-map-two', but we also define 'config-map-two-dev'.
|
||||
* This tests proves that data will be read from 'config-map-two' _only_, even if 'config-map-two-dev'
|
||||
* also exists. This happens because of the 'includeProfileSpecificSources=false' property defined at the source level.
|
||||
* If this would be incorrect, the value we read from '/profile-specific/two' would have been 'twoDev' and _not_ 'two',
|
||||
* simply because 'config-map-two-dev' would override the property value.
|
||||
*
|
||||
* As such: @ConfigurationProperties("two") must be resolved from 'config-map-two'
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testTwo() {
|
||||
this.webClient.get().uri("/profile-specific/two").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
.value(Matchers.equalTo("two"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 'spring.cloud.kubernetes.config.includeProfileSpecificSources=false'
|
||||
* 'spring.cloud.kubernetes.config.sources[2].name=config-map-three'
|
||||
*
|
||||
* We define config-map 'config-map-three', but we also define 'config-map-three-dev'.
|
||||
* This tests proves that data will be read from 'config-map-three' _only_, even if 'config-map-three-dev'
|
||||
* also exists. This happens because the 'includeProfileSpecificSources' property is not defined at the source level,
|
||||
* but it is defaulted from the root level, where we set it to false.
|
||||
* If this would be incorrect, the value we read from '/profile-specific/three' would have been 'threeDev' and _not_ 'three',
|
||||
* simply because 'config-map-three-dev' would override the property value.
|
||||
*
|
||||
* As such: @ConfigurationProperties("three") must be resolved from 'config-map-three'
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testThree() {
|
||||
this.webClient.get().uri("/profile-specific/three").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
.value(Matchers.equalTo("three"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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.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.client.config.applications.config_map_name_as_prefix.WithPrefixApp;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
/**
|
||||
* The stub data for this test is in : ConfigMapNameAsPrefixConfigurationStub
|
||||
*
|
||||
* @author wind57
|
||||
*/
|
||||
@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" })
|
||||
@AutoConfigureWebTestClient
|
||||
public class KubernetesClientConfigMapNameAsPrefixTests {
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() {
|
||||
WireMock.reset();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterAll() {
|
||||
WireMock.shutdownServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 'spring.cloud.kubernetes.config.useNameAsPrefix=true'
|
||||
* 'spring.cloud.kubernetes.config.sources[0].useNameAsPrefix=false'
|
||||
* ("one.property", "one")
|
||||
*
|
||||
* As such: @ConfigurationProperties("one")
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testOne() {
|
||||
this.webClient.get().uri("/prefix/one").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
.value(Matchers.equalTo("one"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 'spring.cloud.kubernetes.config.useNameAsPrefix=true'
|
||||
* 'spring.cloud.kubernetes.config.sources[1].explicitPrefix=two'
|
||||
* ("property", "two")
|
||||
*
|
||||
* As such: @ConfigurationProperties("two")
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testTwo() {
|
||||
this.webClient.get().uri("/prefix/two").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
.value(Matchers.equalTo("two"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 'spring.cloud.kubernetes.config.useNameAsPrefix=true'
|
||||
* 'spring.cloud.kubernetes.config.sources[2].name=config-map-three'
|
||||
* ("property", "three")
|
||||
*
|
||||
* As such: @ConfigurationProperties(prefix = "config-map-three")
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testThree() {
|
||||
this.webClient.get().uri("/prefix/three").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
.value(Matchers.equalTo("three"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -63,8 +63,6 @@ class KubernetesClientConfigMapPropertySourceLocatorTests {
|
||||
+ "logging.level.org.springframework.cloud.kubernetes=TRACE")
|
||||
.build());
|
||||
|
||||
private static final String API = "/api/v1/namespaces/default/configmaps";
|
||||
|
||||
private static WireMockServer wireMockServer;
|
||||
|
||||
@BeforeAll
|
||||
@@ -92,7 +90,7 @@ class KubernetesClientConfigMapPropertySourceLocatorTests {
|
||||
@Test
|
||||
void locateWithoutSources() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API)
|
||||
stubFor(get("/api/v1/namespaces/default/configmaps")
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST))));
|
||||
ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties();
|
||||
configMapConfigProperties.setName("bootstrap-640");
|
||||
@@ -107,7 +105,7 @@ class KubernetesClientConfigMapPropertySourceLocatorTests {
|
||||
@Test
|
||||
void locateWithSources() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API)
|
||||
stubFor(get("/api/v1/namespaces/default/configmaps")
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST))));
|
||||
ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties();
|
||||
configMapConfigProperties.setName("fake-name");
|
||||
@@ -135,7 +133,7 @@ class KubernetesClientConfigMapPropertySourceLocatorTests {
|
||||
@Test
|
||||
void testLocateWithoutNamespaceDeprecatedConstructor() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API)
|
||||
stubFor(get("/api/v1/namespaces/default/configmaps")
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST))));
|
||||
ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties();
|
||||
configMapConfigProperties.setName("bootstrap-640");
|
||||
@@ -157,7 +155,7 @@ class KubernetesClientConfigMapPropertySourceLocatorTests {
|
||||
@Test
|
||||
void testLocateWithoutNamespace() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API)
|
||||
stubFor(get("/api/v1/namespaces/default/configmaps")
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST))));
|
||||
ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties();
|
||||
configMapConfigProperties.setName("bootstrap-640");
|
||||
|
||||
@@ -65,8 +65,6 @@ class KubernetesClientConfigMapPropertySourceTests {
|
||||
"dummy:\n property:\n string2: \"a\"\n int2: 1\n bool2: true\n")
|
||||
.build());
|
||||
|
||||
private static final String API = "/api/v1/namespaces/default/configmaps";
|
||||
|
||||
private static WireMockServer wireMockServer;
|
||||
|
||||
@BeforeAll
|
||||
@@ -94,11 +92,11 @@ class KubernetesClientConfigMapPropertySourceTests {
|
||||
@Test
|
||||
public void propertiesFile() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API)
|
||||
stubFor(get("/api/v1/namespaces/default/configmaps")
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST))));
|
||||
KubernetesClientConfigMapPropertySource propertySource = new KubernetesClientConfigMapPropertySource(api,
|
||||
"bootstrap-640", "default", new MockEnvironment(), "");
|
||||
verify(getRequestedFor(urlEqualTo(API)));
|
||||
"bootstrap-640", "default", new MockEnvironment(), "", true);
|
||||
verify(getRequestedFor(urlEqualTo("/api/v1/namespaces/default/configmaps")));
|
||||
assertThat(propertySource.containsProperty("spring.cloud.kubernetes.configuration.watcher.refreshDelay"))
|
||||
.isTrue();
|
||||
assertThat(propertySource.getProperty("spring.cloud.kubernetes.configuration.watcher.refreshDelay"))
|
||||
@@ -111,10 +109,11 @@ class KubernetesClientConfigMapPropertySourceTests {
|
||||
@Test
|
||||
public void yamlFile() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(YAML_CONFIGMAP_LIST))));
|
||||
stubFor(get("/api/v1/namespaces/default/configmaps")
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(YAML_CONFIGMAP_LIST))));
|
||||
KubernetesClientConfigMapPropertySource propertySource = new KubernetesClientConfigMapPropertySource(api,
|
||||
"bootstrap-641", "default", new MockEnvironment(), "");
|
||||
verify(getRequestedFor(urlEqualTo(API)));
|
||||
"bootstrap-641", "default", new MockEnvironment(), "", true);
|
||||
verify(getRequestedFor(urlEqualTo("/api/v1/namespaces/default/configmaps")));
|
||||
assertThat(propertySource.containsProperty("dummy.property.string2")).isTrue();
|
||||
assertThat(propertySource.getProperty("dummy.property.string2")).isEqualTo("a");
|
||||
assertThat(propertySource.containsProperty("dummy.property.int2")).isTrue();
|
||||
@@ -127,11 +126,11 @@ class KubernetesClientConfigMapPropertySourceTests {
|
||||
@Test
|
||||
public void propertiesFileWithPrefix() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API)
|
||||
stubFor(get("/api/v1/namespaces/default/configmaps")
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST))));
|
||||
KubernetesClientConfigMapPropertySource propertySource = new KubernetesClientConfigMapPropertySource(api,
|
||||
"bootstrap-640", "default", new MockEnvironment(), "prefix");
|
||||
verify(getRequestedFor(urlEqualTo(API)));
|
||||
"bootstrap-640", "default", new MockEnvironment(), "prefix", true);
|
||||
verify(getRequestedFor(urlEqualTo("/api/v1/namespaces/default/configmaps")));
|
||||
assertThat(propertySource.containsProperty("prefix.spring.cloud.kubernetes.configuration.watcher.refreshDelay"))
|
||||
.isTrue();
|
||||
assertThat(propertySource.getProperty("prefix.spring.cloud.kubernetes.configuration.watcher.refreshDelay"))
|
||||
|
||||
@@ -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.config_map_name_as_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;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableConfigurationProperties({ One.class, Two.class, Three.class })
|
||||
public class WithPrefixApp {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WithPrefixApp.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.config_map_name_as_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.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class Controller {
|
||||
|
||||
private final One one;
|
||||
|
||||
private final Two two;
|
||||
|
||||
private final Three three;
|
||||
|
||||
public Controller(One one, Two two, Three three) {
|
||||
this.one = one;
|
||||
this.two = two;
|
||||
this.three = three;
|
||||
}
|
||||
|
||||
@GetMapping("/prefix/one")
|
||||
public String one() {
|
||||
return one.getProperty();
|
||||
}
|
||||
|
||||
@GetMapping("/prefix/two")
|
||||
public String two() {
|
||||
return two.getProperty();
|
||||
}
|
||||
|
||||
@GetMapping("/prefix/three")
|
||||
public String three() {
|
||||
return three.getProperty();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.config_map_name_as_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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.config_map_name_as_prefix.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties(prefix = "config-map-three")
|
||||
public class Three {
|
||||
|
||||
private String property;
|
||||
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(String property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.config_map_name_as_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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.include_profile_specific_sources;
|
||||
|
||||
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.include_profile_specific_sources.properties.One;
|
||||
import org.springframework.cloud.kubernetes.client.config.applications.include_profile_specific_sources.properties.Three;
|
||||
import org.springframework.cloud.kubernetes.client.config.applications.include_profile_specific_sources.properties.Two;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableConfigurationProperties({ One.class, Two.class, Three.class })
|
||||
public class IncludeProfileSpecificSourcesApp {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(IncludeProfileSpecificSourcesApp.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.client.config.applications.include_profile_specific_sources.controller;
|
||||
|
||||
import org.springframework.cloud.kubernetes.client.config.applications.include_profile_specific_sources.properties.One;
|
||||
import org.springframework.cloud.kubernetes.client.config.applications.include_profile_specific_sources.properties.Three;
|
||||
import org.springframework.cloud.kubernetes.client.config.applications.include_profile_specific_sources.properties.Two;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class IncludeProfileSpecificSourcesController {
|
||||
|
||||
private final One one;
|
||||
|
||||
private final Two two;
|
||||
|
||||
private final Three three;
|
||||
|
||||
public IncludeProfileSpecificSourcesController(One one, Two two, Three three) {
|
||||
this.one = one;
|
||||
this.two = two;
|
||||
this.three = three;
|
||||
}
|
||||
|
||||
@GetMapping("/profile-specific/one")
|
||||
public String one() {
|
||||
return one.getProperty();
|
||||
}
|
||||
|
||||
@GetMapping("/profile-specific/two")
|
||||
public String two() {
|
||||
return two.getProperty();
|
||||
}
|
||||
|
||||
@GetMapping("/profile-specific/three")
|
||||
public String three() {
|
||||
return three.getProperty();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.include_profile_specific_sources.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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.include_profile_specific_sources.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("three")
|
||||
public class Three {
|
||||
|
||||
private String property;
|
||||
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(String property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.include_profile_specific_sources.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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.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.V1ConfigMap;
|
||||
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.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("config.map.name.as.prefix.stub")
|
||||
public class ConfigMapNameAsPrefixConfigurationStub {
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
private void stubData() {
|
||||
V1ConfigMap one = new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("config-map-one").withNamespace("spring-k8s")
|
||||
.withResourceVersion("1").build())
|
||||
.addToData(Collections.singletonMap("one.property", "one")).build();
|
||||
|
||||
V1ConfigMap two = new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("config-map-two").withNamespace("spring-k8s")
|
||||
.withResourceVersion("1").build())
|
||||
.addToData(Collections.singletonMap("property", "two")).build();
|
||||
|
||||
V1ConfigMap three = new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("config-map-three").withNamespace("spring-k8s")
|
||||
.withResourceVersion("1").build())
|
||||
.addToData(Collections.singletonMap("property", "three")).build();
|
||||
|
||||
V1ConfigMapList allConfigMaps = new V1ConfigMapList();
|
||||
allConfigMaps.setItems(Arrays.asList(one, two, three));
|
||||
|
||||
// the actual stub for CoreV1Api calls
|
||||
WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/configmaps")
|
||||
.willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(allConfigMaps))));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.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.V1ConfigMap;
|
||||
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.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.
|
||||
*
|
||||
* @author wind57
|
||||
*/
|
||||
@Order(0)
|
||||
@Configuration
|
||||
@ConditionalOnProperty("include.profile.specific.sources")
|
||||
class IncludeProfileSpecificSourcesConfigurationStub {
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
private void stubData() {
|
||||
V1ConfigMap one = new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("config-map-one-dev").withNamespace("spring-k8s")
|
||||
.withResourceVersion("1").build())
|
||||
.addToData(Collections.singletonMap("one.property", "one")).build();
|
||||
|
||||
V1ConfigMap two = new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("config-map-two").withNamespace("spring-k8s")
|
||||
.withResourceVersion("1").build())
|
||||
.addToData(Collections.singletonMap("two.property", "two")).build();
|
||||
|
||||
V1ConfigMap twoDev = new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("config-map-two-dev").withNamespace("spring-k8s")
|
||||
.withResourceVersion("1").build())
|
||||
.addToData(Collections.singletonMap("two.property", "twoDev")).build();
|
||||
|
||||
V1ConfigMap three = new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("config-map-three").withNamespace("spring-k8s")
|
||||
.withResourceVersion("1").build())
|
||||
.addToData(Collections.singletonMap("three.property", "three")).build();
|
||||
|
||||
V1ConfigMap threeDev = new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("config-map-three-dev").withNamespace("spring-k8s")
|
||||
.withResourceVersion("1").build())
|
||||
.addToData(Collections.singletonMap("three.property", "threeDev")).build();
|
||||
|
||||
V1ConfigMapList allConfigMaps = new V1ConfigMapList();
|
||||
allConfigMaps.setItems(Arrays.asList(one, two, twoDev, three, threeDev));
|
||||
|
||||
// the actual stub for CoreV1Api calls
|
||||
WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/configmaps")
|
||||
.willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(allConfigMaps))));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.IncludeProfileSpecificSourcesConfigurationStub, \
|
||||
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.ConfigMapNameAsPrefixConfigurationStub
|
||||
@@ -0,0 +1,14 @@
|
||||
spring:
|
||||
application:
|
||||
name: include-profile-specific-sources
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
includeProfileSpecificSources: false
|
||||
namespace: spring-k8s
|
||||
sources:
|
||||
- name: config-map-one
|
||||
includeProfileSpecificSources: true
|
||||
- name: config-map-two
|
||||
includeProfileSpecificSources: false
|
||||
- name: config-map-three
|
||||
@@ -29,8 +29,12 @@ public abstract class AbstractConfigProperties {
|
||||
|
||||
protected String namespace;
|
||||
|
||||
// use config map name to prefix properties
|
||||
protected boolean useNameAsPrefix;
|
||||
|
||||
// use profile name to append config map name
|
||||
protected boolean includeProfileSpecificSources = true;
|
||||
|
||||
public abstract String getConfigurationTarget();
|
||||
|
||||
public boolean isEnabled() {
|
||||
@@ -65,4 +69,11 @@ public abstract class AbstractConfigProperties {
|
||||
this.useNameAsPrefix = useNameAsPrefix;
|
||||
}
|
||||
|
||||
public boolean isIncludeProfileSpecificSources() {
|
||||
return includeProfileSpecificSources;
|
||||
}
|
||||
|
||||
public void setIncludeProfileSpecificSources(boolean includeProfileSpecificSources) {
|
||||
this.includeProfileSpecificSources = includeProfileSpecificSources;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,10 +82,11 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
"'spring.cloud.kubernetes.config.useNameAsPrefix' is set to 'true', but 'spring.cloud.kubernetes.config.sources'"
|
||||
+ " is empty; as such will default 'useNameAsPrefix' to 'false'");
|
||||
}
|
||||
return Collections.singletonList(new NormalizedSource(name, namespace, ""));
|
||||
return Collections.singletonList(new NormalizedSource(name, namespace, "", includeProfileSpecificSources));
|
||||
}
|
||||
|
||||
return sources.stream().map(s -> s.normalize(name, namespace, useNameAsPrefix)).collect(Collectors.toList());
|
||||
return sources.stream().map(s -> s.normalize(name, namespace, useNameAsPrefix, includeProfileSpecificSources))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,6 +115,12 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
*/
|
||||
private Boolean useNameAsPrefix;
|
||||
|
||||
/**
|
||||
* Use profile name to append to a config map name. Can't be a primitive, we need to
|
||||
* know if it was explicitly set or not
|
||||
*/
|
||||
protected Boolean includeProfileSpecificSources;
|
||||
|
||||
/**
|
||||
* An explicit prefix to be used for properties.
|
||||
*/
|
||||
@@ -160,6 +167,14 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
this.explicitPrefix = explicitPrefix;
|
||||
}
|
||||
|
||||
public Boolean getIncludeProfileSpecificSources() {
|
||||
return includeProfileSpecificSources;
|
||||
}
|
||||
|
||||
public void setIncludeProfileSpecificSources(Boolean includeProfileSpecificSources) {
|
||||
this.includeProfileSpecificSources = includeProfileSpecificSources;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return !StringUtils.hasLength(this.name) && !StringUtils.hasLength(this.namespace);
|
||||
}
|
||||
@@ -169,15 +184,18 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
public NormalizedSource normalize(String defaultName, String defaultNamespace) {
|
||||
String normalizedName = StringUtils.hasLength(this.name) ? this.name : defaultName;
|
||||
String normalizedNamespace = StringUtils.hasLength(this.namespace) ? this.namespace : defaultNamespace;
|
||||
return new NormalizedSource(normalizedName, normalizedNamespace, "");
|
||||
return new NormalizedSource(normalizedName, normalizedNamespace, "", true);
|
||||
}
|
||||
|
||||
public NormalizedSource normalize(String defaultName, String defaultNamespace, boolean defaultUseNameAsPrefix) {
|
||||
public NormalizedSource normalize(String defaultName, String defaultNamespace, boolean defaultUseNameAsPrefix,
|
||||
boolean defaultIncludeProfileSpecificSources) {
|
||||
String normalizedName = StringUtils.hasLength(this.name) ? this.name : defaultName;
|
||||
String normalizedNamespace = StringUtils.hasLength(this.namespace) ? this.namespace : defaultNamespace;
|
||||
String prefix = ConfigUtils.findPrefix(this.explicitPrefix, useNameAsPrefix, defaultUseNameAsPrefix,
|
||||
normalizedName);
|
||||
return new NormalizedSource(normalizedName, normalizedNamespace, prefix);
|
||||
boolean includeProfileSpecificSources = ConfigUtils.includeProfileSpecificSources(defaultIncludeProfileSpecificSources,
|
||||
this.includeProfileSpecificSources);
|
||||
return new NormalizedSource(normalizedName, normalizedNamespace, prefix, includeProfileSpecificSources);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -207,18 +225,22 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
|
||||
private final String prefix;
|
||||
|
||||
private final boolean includeProfileSpecificSources;
|
||||
|
||||
// not used, but not removed because of potential compatibility reasons
|
||||
@Deprecated
|
||||
NormalizedSource(String name, String namespace) {
|
||||
this.name = name;
|
||||
this.namespace = namespace;
|
||||
this.prefix = "";
|
||||
this.includeProfileSpecificSources = true;
|
||||
}
|
||||
|
||||
NormalizedSource(String name, String namespace, String prefix) {
|
||||
NormalizedSource(String name, String namespace, String prefix, boolean includeProfileSpecificSources) {
|
||||
this.name = name;
|
||||
this.namespace = namespace;
|
||||
this.prefix = Objects.requireNonNull(prefix);
|
||||
this.includeProfileSpecificSources = includeProfileSpecificSources;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -233,6 +255,10 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public boolean isIncludeProfileSpecificSources() {
|
||||
return includeProfileSpecificSources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{ config-map name : '" + name + "', namespace : '" + namespace + "', prefix : '" + prefix + "' }";
|
||||
|
||||
@@ -84,4 +84,19 @@ public final class ConfigUtils {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param defaultIncludeProfileSpecificSources value of
|
||||
* 'spring.cloud.kubernetes.config.includeProfileSpecificSources'
|
||||
* @param includeProfileSpecificSources value of
|
||||
* 'spring.cloud.kubernetes.config.sources.includeProfileSpecificSources'
|
||||
* @return useProfileNameAsPrefix to be used in normalized sources
|
||||
*/
|
||||
public static boolean includeProfileSpecificSources(boolean defaultIncludeProfileSpecificSources,
|
||||
Boolean includeProfileSpecificSources) {
|
||||
if (includeProfileSpecificSources != null) {
|
||||
return includeProfileSpecificSources;
|
||||
}
|
||||
return defaultIncludeProfileSpecificSources;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -218,4 +218,114 @@ public class ConfigMapConfigPropertiesTests {
|
||||
Assertions.assertEquals(sources.get(3).getPrefix(), "");
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* spring:
|
||||
* cloud:
|
||||
* kubernetes:
|
||||
* config:
|
||||
* name: config-map-a
|
||||
* namespace: spring-k8s
|
||||
* </pre>
|
||||
*
|
||||
* a config as above will result in a NormalizedSource where includeProfileSpecificSources
|
||||
* will be true (this test proves that the change we added is not a breaking change
|
||||
* for the already existing functionality)
|
||||
*/
|
||||
@Test
|
||||
public void testUseIncludeProfileSpecificSourcesNoChanges() {
|
||||
ConfigMapConfigProperties properties = new ConfigMapConfigProperties();
|
||||
properties.setSources(Collections.emptyList());
|
||||
properties.setName("config-map-a");
|
||||
properties.setNamespace("spring-k8s");
|
||||
|
||||
List<ConfigMapConfigProperties.NormalizedSource> sources = properties.determineSources();
|
||||
Assertions.assertEquals(sources.size(), 1, "empty sources must generate a List with a single NormalizedSource");
|
||||
|
||||
Assertions.assertTrue(sources.get(0).isIncludeProfileSpecificSources());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* spring:
|
||||
* cloud:
|
||||
* kubernetes:
|
||||
* config:
|
||||
* includeProfileSpecificSources: false
|
||||
* name: config-map-a
|
||||
* namespace: spring-k8s
|
||||
* </pre>
|
||||
*
|
||||
* a config as above will result in a NormalizedSource where includeProfileSpecificSources
|
||||
* will be false. Even if we did not define any sources explicitly, one will still be
|
||||
* created, by default. That one might "flatMap" into multiple other, because of
|
||||
* multiple profiles. As such this setting still matters and must be propagated to the
|
||||
* normalized source.
|
||||
*/
|
||||
@Test
|
||||
public void testUseIncludeProfileSpecificSourcesDefaultChanged() {
|
||||
ConfigMapConfigProperties properties = new ConfigMapConfigProperties();
|
||||
properties.setSources(Collections.emptyList());
|
||||
properties.setName("config-map-a");
|
||||
properties.setNamespace("spring-k8s");
|
||||
properties.setIncludeProfileSpecificSources(false);
|
||||
|
||||
List<ConfigMapConfigProperties.NormalizedSource> sources = properties.determineSources();
|
||||
Assertions.assertEquals(sources.size(), 1, "empty sources must generate a List with a single NormalizedSource");
|
||||
|
||||
Assertions.assertFalse(sources.get(0).isIncludeProfileSpecificSources());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* spring:
|
||||
* cloud:
|
||||
* kubernetes:
|
||||
* config:
|
||||
* includeProfileSpecificSources: false
|
||||
* name: config-map-a
|
||||
* namespace: spring-k8s
|
||||
* sources:
|
||||
* - name: one
|
||||
* includeProfileSpecificSources: true
|
||||
* - name: two
|
||||
* - name: three
|
||||
* includeProfileSpecificSources: false
|
||||
* </pre>
|
||||
*
|
||||
* <pre>
|
||||
* source "one" will have "includeProfileSpecificSources = true".
|
||||
* source "two" will have "includeProfileSpecificSources = false".
|
||||
* source "three" will have "includeProfileSpecificSources = false".
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testUseIncludeProfileSpecificSourcesDefaultChangedSourceOverride() {
|
||||
ConfigMapConfigProperties properties = new ConfigMapConfigProperties();
|
||||
properties.setSources(Collections.emptyList());
|
||||
properties.setName("config-map-a");
|
||||
properties.setNamespace("spring-k8s");
|
||||
properties.setIncludeProfileSpecificSources(false);
|
||||
|
||||
ConfigMapConfigProperties.Source one = new ConfigMapConfigProperties.Source();
|
||||
one.setName("config-map-one");
|
||||
one.setIncludeProfileSpecificSources(true);
|
||||
|
||||
ConfigMapConfigProperties.Source two = new ConfigMapConfigProperties.Source();
|
||||
two.setName("config-map-two");
|
||||
|
||||
ConfigMapConfigProperties.Source three = new ConfigMapConfigProperties.Source();
|
||||
three.setName("config-map-three");
|
||||
three.setIncludeProfileSpecificSources(false);
|
||||
|
||||
properties.setSources(Arrays.asList(one, two, three));
|
||||
|
||||
List<ConfigMapConfigProperties.NormalizedSource> sources = properties.determineSources();
|
||||
Assertions.assertEquals(sources.size(), 3);
|
||||
|
||||
Assertions.assertTrue(sources.get(0).isIncludeProfileSpecificSources());
|
||||
Assertions.assertFalse(sources.get(1).isIncludeProfileSpecificSources());
|
||||
Assertions.assertFalse(sources.get(2).isIncludeProfileSpecificSources());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -54,4 +54,55 @@ public class ConfigUtilsTests {
|
||||
Assertions.assertEquals(result, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* spring:
|
||||
* cloud:
|
||||
* kubernetes:
|
||||
* config:
|
||||
* includeProfileSpecificSources: true
|
||||
* </pre>
|
||||
*
|
||||
* above will generate "true" for a normalized source
|
||||
*/
|
||||
@Test
|
||||
public void testUseIncludeProfileSpecificSourcesOnlyDefaultSet() {
|
||||
Assertions.assertTrue(ConfigUtils.includeProfileSpecificSources(true, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* spring:
|
||||
* cloud:
|
||||
* kubernetes:
|
||||
* config:
|
||||
* includeProfileSpecificSources: true
|
||||
* </pre>
|
||||
*
|
||||
* above will generate "false" for a normalized source
|
||||
*/
|
||||
@Test
|
||||
public void testUseIncludeProfileSpecificSourcesOnlyDefaultNotSet() {
|
||||
Assertions.assertFalse(ConfigUtils.includeProfileSpecificSources(false, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* spring:
|
||||
* cloud:
|
||||
* kubernetes:
|
||||
* config:
|
||||
* includeProfileSpecificSources: true
|
||||
* sources:
|
||||
* - name: one
|
||||
* includeProfileSpecificSources: false
|
||||
* </pre>
|
||||
*
|
||||
* above will generate "false" for a normalized source
|
||||
*/
|
||||
@Test
|
||||
public void testUseIncludeProfileSpecificSourcesSourcesOverridesDefault() {
|
||||
Assertions.assertFalse(ConfigUtils.includeProfileSpecificSources(true, false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class Fabric8ConfigMapPropertySource extends ConfigMapPropertySource {
|
||||
private static final Log LOG = LogFactory.getLog(Fabric8ConfigMapPropertySource.class);
|
||||
|
||||
public Fabric8ConfigMapPropertySource(KubernetesClient client, String name) {
|
||||
this(client, name, null, null, "");
|
||||
this(client, name, null, null, "", true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,27 +52,27 @@ public class Fabric8ConfigMapPropertySource extends ConfigMapPropertySource {
|
||||
* discouraged.
|
||||
*/
|
||||
@Deprecated
|
||||
public Fabric8ConfigMapPropertySource(KubernetesClient client, String applicationName, String namespace,
|
||||
public Fabric8ConfigMapPropertySource(KubernetesClient client, String name, String namespace,
|
||||
Environment environment) {
|
||||
super(getName(applicationName, getApplicationNamespace(client, namespace)),
|
||||
getData(client, applicationName, getApplicationNamespace(client, namespace), environment, ""));
|
||||
super(getName(name, getApplicationNamespace(client, namespace)),
|
||||
getData(client, name, getApplicationNamespace(client, namespace), environment, "", true));
|
||||
}
|
||||
|
||||
public Fabric8ConfigMapPropertySource(KubernetesClient client, String applicationName, String namespace,
|
||||
Environment environment, String prefix) {
|
||||
super(getName(applicationName, getApplicationNamespace(client, namespace)),
|
||||
getData(client, applicationName, getApplicationNamespace(client, namespace), environment, prefix));
|
||||
public Fabric8ConfigMapPropertySource(KubernetesClient client, String name, String namespace,
|
||||
Environment environment, String prefix, boolean includeProfileSpecificSources) {
|
||||
super(getName(name, getApplicationNamespace(client, namespace)), getData(client, name,
|
||||
getApplicationNamespace(client, namespace), environment, prefix, includeProfileSpecificSources));
|
||||
}
|
||||
|
||||
private static Map<String, Object> getData(KubernetesClient client, String applicationName, String namespace,
|
||||
Environment environment, String prefix) {
|
||||
private static Map<String, Object> getData(KubernetesClient client, String name, String namespace,
|
||||
Environment environment, String prefix, boolean includeProfileSpecificSources) {
|
||||
try {
|
||||
Map<String, String> data = getConfigMapData(client, namespace, applicationName);
|
||||
Map<String, String> data = getConfigMapData(client, namespace, name);
|
||||
Map<String, Object> result = new HashMap<>(processAllEntries(data, environment));
|
||||
|
||||
if (environment != null) {
|
||||
if (environment != null && includeProfileSpecificSources) {
|
||||
for (String activeProfile : environment.getActiveProfiles()) {
|
||||
String mapNameWithProfile = applicationName + "-" + activeProfile;
|
||||
String mapNameWithProfile = name + "-" + activeProfile;
|
||||
Map<String, String> dataWithProfile = getConfigMapData(client, namespace, mapNameWithProfile);
|
||||
result.putAll(processAllEntries(dataWithProfile, environment));
|
||||
}
|
||||
@@ -88,8 +88,7 @@ public class Fabric8ConfigMapPropertySource extends ConfigMapPropertySource {
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.warn("Can't read configMap with name: [" + applicationName + "] in namespace: [" + namespace
|
||||
+ "]. Ignoring.", e);
|
||||
LOG.warn("Can't read configMap with name: [" + name + "] in namespace: [" + namespace + "]. Ignoring.", e);
|
||||
}
|
||||
|
||||
return Collections.emptyMap();
|
||||
|
||||
@@ -69,7 +69,7 @@ public class Fabric8ConfigMapPropertySourceLocator extends ConfigMapPropertySour
|
||||
String namespace = getApplicationNamespace(this.client, normalizedSource.getNamespace(), configurationTarget,
|
||||
provider);
|
||||
return new Fabric8ConfigMapPropertySource(this.client, applicationName, namespace, environment,
|
||||
normalizedSource.getPrefix());
|
||||
normalizedSource.getPrefix(), normalizedSource.isIncludeProfileSpecificSources());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
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.include_profile_specific_sources.IncludeProfileSpecificSourcesApp;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = IncludeProfileSpecificSourcesApp.class,
|
||||
properties = { "spring.cloud.bootstrap.name=include-profile-specific-sources" })
|
||||
@AutoConfigureWebTestClient
|
||||
@EnableKubernetesMockClient(crud = true, https = false)
|
||||
@ActiveProfiles("dev")
|
||||
class ConfigMapWithIncludeProfileSpecificSourcesTests {
|
||||
|
||||
private static KubernetesClient mockClient;
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
@BeforeAll
|
||||
public static void setUpBeforeClass() {
|
||||
|
||||
// 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 = new HashMap<>();
|
||||
one.put("one.property", "one");
|
||||
createConfigmap("config-map-one-dev", one);
|
||||
|
||||
Map<String, String> two = new HashMap<>();
|
||||
two.put("two.property", "two");
|
||||
createConfigmap("config-map-two", two);
|
||||
|
||||
Map<String, String> twoDev = new HashMap<>();
|
||||
twoDev.put("two.property", "twoDev");
|
||||
createConfigmap("config-map-two-dev", twoDev);
|
||||
|
||||
Map<String, String> three = new HashMap<>();
|
||||
three.put("three.property", "three");
|
||||
createConfigmap("config-map-three", three);
|
||||
|
||||
Map<String, String> threeDev = new HashMap<>();
|
||||
threeDev.put("three.property", "threeDev");
|
||||
createConfigmap("config-map-three-dev", threeDev);
|
||||
|
||||
}
|
||||
|
||||
private static void createConfigmap(String name, Map<String, String> data) {
|
||||
mockClient.configMaps().inNamespace("spring-k8s").createNew().withNewMetadata().withName(name).endMetadata()
|
||||
.addToData(data).done();
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 'spring.cloud.kubernetes.config.includeProfileSpecificSources=false'
|
||||
* 'spring.cloud.kubernetes.config.sources[0].includeProfileSpecificSources=true'
|
||||
* 'spring.cloud.kubernetes.config.sources[0].name=config-map-one'
|
||||
*
|
||||
* We do not define config-map 'config-map-one', but we do define 'config-map-one-dev'.
|
||||
*
|
||||
* As such: @ConfigurationProperties("one") must be resolved from 'config-map-one-dev'
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testOne() {
|
||||
this.webClient.get().uri("/profile-specific/one").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
.value(Matchers.equalTo("one"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 'spring.cloud.kubernetes.config.includeProfileSpecificSources=false'
|
||||
* 'spring.cloud.kubernetes.config.sources[1].includeProfileSpecificSources=false'
|
||||
* 'spring.cloud.kubernetes.config.sources[1].name=config-map-two'
|
||||
*
|
||||
* We define config-map 'config-map-two', but we also define 'config-map-two-dev'.
|
||||
* This tests proves that data will be read from 'config-map-two' _only_, even if 'config-map-two-dev'
|
||||
* also exists. This happens because of the 'includeProfileSpecificSources=false' property defined at the source level.
|
||||
* If this would be incorrect, the value we read from '/profile-specific/two' would have been 'twoDev' and _not_ 'two',
|
||||
* simply because 'config-map-two-dev' would override the property value.
|
||||
*
|
||||
* As such: @ConfigurationProperties("two") must be resolved from 'config-map-two'
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testTwo() {
|
||||
this.webClient.get().uri("/profile-specific/two").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
.value(Matchers.equalTo("two"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 'spring.cloud.kubernetes.config.includeProfileSpecificSources=false'
|
||||
* 'spring.cloud.kubernetes.config.sources[2].name=config-map-three'
|
||||
*
|
||||
* We define config-map 'config-map-three', but we also define 'config-map-three-dev'.
|
||||
* This tests proves that data will be read from 'config-map-three' _only_, even if 'config-map-three-dev'
|
||||
* also exists. This happens because the 'includeProfileSpecificSources' property is not defined at the source level,
|
||||
* but it is defaulted from the root level, where we set it to false.
|
||||
* If this would be incorrect, the value we read from '/profile-specific/three' would have been 'threeDev' and _not_ 'three',
|
||||
* simply because 'config-map-three-dev' would override the property value.
|
||||
*
|
||||
* As such: @ConfigurationProperties("three") must be resolved from 'config-map-three'
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testThree() {
|
||||
this.webClient.get().uri("/profile-specific/three").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
.value(Matchers.equalTo("three"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,10 +39,10 @@ import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WithPrefixApp.class,
|
||||
properties = { "spring.cloud.bootstrap.name=same-key-with-prefix" })
|
||||
properties = { "spring.cloud.bootstrap.name=config-map-name-as-prefix" })
|
||||
@AutoConfigureWebTestClient
|
||||
@EnableKubernetesMockClient(crud = true, https = false)
|
||||
public class ConfigMapWithPrefixTests {
|
||||
class ConfigMapWithPrefixTests {
|
||||
|
||||
private static KubernetesClient mockClient;
|
||||
|
||||
@@ -62,21 +62,20 @@ public class ConfigMapWithPrefixTests {
|
||||
|
||||
Map<String, String> one = new HashMap<>();
|
||||
one.put("one.property", "one");
|
||||
createConfigmap(mockClient, "config-map-one", one);
|
||||
createConfigmap("config-map-one", one);
|
||||
|
||||
Map<String, String> two = new HashMap<>();
|
||||
two.put("property", "two");
|
||||
createConfigmap(mockClient, "config-map-two", two);
|
||||
createConfigmap("config-map-two", two);
|
||||
|
||||
Map<String, String> three = new HashMap<>();
|
||||
three.put("property", "three");
|
||||
createConfigmap(mockClient, "config-map-three", three);
|
||||
createConfigmap("config-map-three", three);
|
||||
|
||||
}
|
||||
|
||||
private static void createConfigmap(KubernetesClient client, String name, Map<String, String> data) {
|
||||
|
||||
client.configMaps().inNamespace("spring-k8s").createNew().withNewMetadata().withName(name).endMetadata()
|
||||
private static void createConfigmap(String name, Map<String, String> data) {
|
||||
mockClient.configMaps().inNamespace("spring-k8s").createNew().withNewMetadata().withName(name).endMetadata()
|
||||
.addToData(data).done();
|
||||
}
|
||||
|
||||
@@ -91,7 +90,7 @@ public class ConfigMapWithPrefixTests {
|
||||
*/
|
||||
@Test
|
||||
public void testOne() {
|
||||
this.webClient.get().uri("/one").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
this.webClient.get().uri("/prefix/one").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
.value(Matchers.equalTo("one"));
|
||||
}
|
||||
|
||||
@@ -106,7 +105,7 @@ public class ConfigMapWithPrefixTests {
|
||||
*/
|
||||
@Test
|
||||
public void testTwo() {
|
||||
this.webClient.get().uri("/two").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
this.webClient.get().uri("/prefix/two").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
.value(Matchers.equalTo("two"));
|
||||
}
|
||||
|
||||
@@ -121,7 +120,7 @@ public class ConfigMapWithPrefixTests {
|
||||
*/
|
||||
@Test
|
||||
public void testThree() {
|
||||
this.webClient.get().uri("/three").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
this.webClient.get().uri("/prefix/three").exchange().expectStatus().isOk().expectBody(String.class)
|
||||
.value(Matchers.equalTo("three"));
|
||||
}
|
||||
|
||||
|
||||
@@ -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.include_profile_specific_sources;
|
||||
|
||||
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.include_profile_specific_sources.properties.One;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.include_profile_specific_sources.properties.Three;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.include_profile_specific_sources.properties.Two;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableConfigurationProperties({ One.class, Two.class, Three.class })
|
||||
public class IncludeProfileSpecificSourcesApp {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(IncludeProfileSpecificSourcesApp.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.include_profile_specific_sources.controller;
|
||||
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.include_profile_specific_sources.properties.One;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.include_profile_specific_sources.properties.Three;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.include_profile_specific_sources.properties.Two;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class IncludeProfileSpecificSourcesController {
|
||||
|
||||
private final One one;
|
||||
|
||||
private final Two two;
|
||||
|
||||
private final Three three;
|
||||
|
||||
public IncludeProfileSpecificSourcesController(One one, Two two, Three three) {
|
||||
this.one = one;
|
||||
this.two = two;
|
||||
this.three = three;
|
||||
}
|
||||
|
||||
@GetMapping("/profile-specific/one")
|
||||
public String one() {
|
||||
return one.getProperty();
|
||||
}
|
||||
|
||||
@GetMapping("/profile-specific/two")
|
||||
public String two() {
|
||||
return two.getProperty();
|
||||
}
|
||||
|
||||
@GetMapping("/profile-specific/three")
|
||||
public String three() {
|
||||
return three.getProperty();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.include_profile_specific_sources.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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.include_profile_specific_sources.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("three")
|
||||
public class Three {
|
||||
|
||||
private String property;
|
||||
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(String property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.include_profile_specific_sources.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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -37,17 +37,17 @@ public class Controller {
|
||||
this.three = three;
|
||||
}
|
||||
|
||||
@GetMapping("/one")
|
||||
@GetMapping("/prefix/one")
|
||||
public String one() {
|
||||
return one.getProperty();
|
||||
}
|
||||
|
||||
@GetMapping("/two")
|
||||
@GetMapping("/prefix/two")
|
||||
public String two() {
|
||||
return two.getProperty();
|
||||
}
|
||||
|
||||
@GetMapping("/three")
|
||||
@GetMapping("/prefix/three")
|
||||
public String three() {
|
||||
return three.getProperty();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
spring:
|
||||
application:
|
||||
name: with-prefix
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
useNameAsPrefix: true
|
||||
namespace: spring-k8s
|
||||
sources:
|
||||
- name: config-map-one
|
||||
useNameAsPrefix: false
|
||||
- name: config-map-two
|
||||
explicitPrefix: two
|
||||
- name: config-map-three
|
||||
@@ -0,0 +1,14 @@
|
||||
spring:
|
||||
application:
|
||||
name: include-profile-specific-sources
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
includeProfileSpecificSources: false
|
||||
namespace: spring-k8s
|
||||
sources:
|
||||
- name: config-map-one
|
||||
includeProfileSpecificSources: true
|
||||
- name: config-map-two
|
||||
includeProfileSpecificSources: false
|
||||
- name: config-map-three
|
||||
Reference in New Issue
Block a user