Skip to content

Commit 0c00b75

Browse files
committed
dirty
1 parent dca7b19 commit 0c00b75

File tree

3 files changed

+327
-44
lines changed

3 files changed

+327
-44
lines changed

spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySourceLocatorTests.java

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -54,28 +54,54 @@ class KubernetesClientSecretsPropertySourceLocatorTests {
5454

5555
private static final String LIST_API = "/api/v1/namespaces/default/secrets";
5656

57-
private static final String LIST_BODY = "{\n" + "\t\"kind\": \"SecretList\",\n" + "\t\"apiVersion\": \"v1\",\n"
58-
+ "\t\"metadata\": {\n" + "\t\t\"selfLink\": \"/api/v1/secrets\",\n"
59-
+ "\t\t\"resourceVersion\": \"163035\"\n" + "\t},\n" + "\t\"items\": [{\n" + "\t\t\t\"metadata\": {\n"
60-
+ "\t\t\t\t\"name\": \"db-secret\",\n" + "\t\t\t\t\"namespace\": \"default\",\n"
61-
+ "\t\t\t\t\"selfLink\": \"/api/v1/namespaces/default/secrets/db-secret\",\n"
62-
+ "\t\t\t\t\"uid\": \"59ba8e6a-a2d4-416c-b016-22597c193f23\",\n"
63-
+ "\t\t\t\t\"resourceVersion\": \"1462\",\n" + "\t\t\t\t\"creationTimestamp\": \"2020-10-28T14:45:02Z\",\n"
64-
+ "\t\t\t\t\"labels\": {\n" + "\t\t\t\t\t\"spring.cloud.kubernetes.secret\": \"true\"\n" + "\t\t\t\t}\n"
65-
+ "\t\t\t},\n" + "\t\t\t\"data\": {\n" + "\t\t\t\t\"password\": \"cDQ1NXcwcmQ=\",\n"
66-
+ "\t\t\t\t\"username\": \"dXNlcg==\"\n" + "\t\t\t},\n" + "\t\t\t\"type\": \"Opaque\"\n" + "\t\t},\n"
67-
+ "\t\t{\n" + "\t\t\t\"metadata\": {\n" + "\t\t\t\t\"name\": \"rabbit-password\",\n"
68-
+ "\t\t\t\t\"namespace\": \"default\",\n"
69-
+ "\t\t\t\t\"selfLink\": \"/api/v1/namespaces/default/secrets/rabbit-password\",\n"
70-
+ "\t\t\t\t\"uid\": \"bc211cb4-e7ff-4556-b26e-c54911301740\",\n"
71-
+ "\t\t\t\t\"resourceVersion\": \"162708\",\n"
72-
+ "\t\t\t\t\"creationTimestamp\": \"2020-10-29T19:47:36Z\",\n" + "\t\t\t\t\"labels\": {\n"
73-
+ "\t\t\t\t\t\"spring.cloud.kubernetes.secret\": \"true\"\n" + "\t\t\t\t},\n"
74-
+ "\t\t\t\t\"annotations\": {\n"
75-
+ "\t\t\t\t\t\"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"data\\\":{\\\"spring.rabbitmq.password\\\":\\\"password\\\"},\\\"kind\\\":\\\"Secret\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"spring.cloud.kubernetes.secret\\\":\\\"true\\\"},\\\"name\\\":\\\"rabbit-password\\\",\\\"namespace\\\":\\\"default\\\"},\\\"type\\\":\\\"Opaque\\\"}\\n\"\n"
76-
+ "\t\t\t\t}\n" + "\t\t\t},\n" + "\t\t\t\"data\": {\n"
77-
+ "\t\t\t\t\"spring.rabbitmq.password\": \"cGFzc3dvcmQ=\"\n" + "\t\t\t},\n" + "\t\t\t\"type\": \"Opaque\"\n"
78-
+ "\t\t}\n" + "\t]\n" + "}";
57+
private static final String LIST_BODY = """
58+
{
59+
\t"kind": "SecretList",
60+
\t"apiVersion": "v1",
61+
\t"metadata": {
62+
\t\t"selfLink": "/api/v1/secrets",
63+
\t\t"resourceVersion": "163035"
64+
\t},
65+
\t"items": [{
66+
\t\t\t"metadata": {
67+
\t\t\t\t"name": "db-secret",
68+
\t\t\t\t"namespace": "default",
69+
\t\t\t\t"selfLink": "/api/v1/namespaces/default/secrets/db-secret",
70+
\t\t\t\t"uid": "59ba8e6a-a2d4-416c-b016-22597c193f23",
71+
\t\t\t\t"resourceVersion": "1462",
72+
\t\t\t\t"creationTimestamp": "2020-10-28T14:45:02Z",
73+
\t\t\t\t"labels": {
74+
\t\t\t\t\t"spring.cloud.kubernetes.secret": "true"
75+
\t\t\t\t}
76+
\t\t\t},
77+
\t\t\t"data": {
78+
\t\t\t\t"password": "cDQ1NXcwcmQ=",
79+
\t\t\t\t"username": "dXNlcg=="
80+
\t\t\t},
81+
\t\t\t"type": "Opaque"
82+
\t\t},
83+
\t\t{
84+
\t\t\t"metadata": {
85+
\t\t\t\t"name": "rabbit-password",
86+
\t\t\t\t"namespace": "default",
87+
\t\t\t\t"selfLink": "/api/v1/namespaces/default/secrets/rabbit-password",
88+
\t\t\t\t"uid": "bc211cb4-e7ff-4556-b26e-c54911301740",
89+
\t\t\t\t"resourceVersion": "162708",
90+
\t\t\t\t"creationTimestamp": "2020-10-29T19:47:36Z",
91+
\t\t\t\t"labels": {
92+
\t\t\t\t\t"spring.cloud.kubernetes.secret": "true"
93+
\t\t\t\t},
94+
\t\t\t\t"annotations": {
95+
\t\t\t\t\t"kubectl.kubernetes.io/last-applied-configuration": "{\\"apiVersion\\":\\"v1\\",\\"data\\":{\\"spring.rabbitmq.password\\":\\"password\\"},\\"kind\\":\\"Secret\\",\\"metadata\\":{\\"annotations\\":{},\\"labels\\":{\\"spring.cloud.kubernetes.secret\\":\\"true\\"},\\"name\\":\\"rabbit-password\\",\\"namespace\\":\\"default\\"},\\"type\\":\\"Opaque\\"}\\n"
96+
\t\t\t\t}
97+
\t\t\t},
98+
\t\t\t"data": {
99+
\t\t\t\t"spring.rabbitmq.password": "cGFzc3dvcmQ="
100+
\t\t\t},
101+
\t\t\t"type": "Opaque"
102+
\t\t}
103+
\t]
104+
}""";
79105

80106
private static WireMockServer wireMockServer;
81107

spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientSecretsPropertySourceTests.java

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -80,28 +80,54 @@ class KubernetesClientSecretsPropertySourceTests {
8080

8181
private static final String LIST_API_WITH_LABEL = "/api/v1/namespaces/default/secrets";
8282

83-
private static final String LIST_BODY = "{\n" + "\t\"kind\": \"SecretList\",\n" + "\t\"apiVersion\": \"v1\",\n"
84-
+ "\t\"metadata\": {\n" + "\t\t\"selfLink\": \"/api/v1/secrets\",\n"
85-
+ "\t\t\"resourceVersion\": \"163035\"\n" + "\t},\n" + "\t\"items\": [{\n" + "\t\t\t\"metadata\": {\n"
86-
+ "\t\t\t\t\"name\": \"db-secret\",\n" + "\t\t\t\t\"namespace\": \"default\",\n"
87-
+ "\t\t\t\t\"selfLink\": \"/api/v1/namespaces/default/secrets/db-secret\",\n"
88-
+ "\t\t\t\t\"uid\": \"59ba8e6a-a2d4-416c-b016-22597c193f23\",\n"
89-
+ "\t\t\t\t\"resourceVersion\": \"1462\",\n" + "\t\t\t\t\"creationTimestamp\": \"2020-10-28T14:45:02Z\",\n"
90-
+ "\t\t\t\t\"labels\": {\n" + "\t\t\t\t\t\"spring.cloud.kubernetes.secret\": \"true\"\n" + "\t\t\t\t}\n"
91-
+ "\t\t\t},\n" + "\t\t\t\"data\": {\n" + "\t\t\t\t\"password\": \"cDQ1NXcwcmQ=\",\n"
92-
+ "\t\t\t\t\"username\": \"dXNlcg==\"\n" + "\t\t\t},\n" + "\t\t\t\"type\": \"Opaque\"\n" + "\t\t},\n"
93-
+ "\t\t{\n" + "\t\t\t\"metadata\": {\n" + "\t\t\t\t\"name\": \"rabbit-password\",\n"
94-
+ "\t\t\t\t\"namespace\": \"default\",\n"
95-
+ "\t\t\t\t\"selfLink\": \"/api/v1/namespaces/default/secrets/rabbit-password\",\n"
96-
+ "\t\t\t\t\"uid\": \"bc211cb4-e7ff-4556-b26e-c54911301740\",\n"
97-
+ "\t\t\t\t\"resourceVersion\": \"162708\",\n"
98-
+ "\t\t\t\t\"creationTimestamp\": \"2020-10-29T19:47:36Z\",\n" + "\t\t\t\t\"labels\": {\n"
99-
+ "\t\t\t\t\t\"spring.cloud.kubernetes.secret\": \"true\"\n" + "\t\t\t\t},\n"
100-
+ "\t\t\t\t\"annotations\": {\n"
101-
+ "\t\t\t\t\t\"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"data\\\":{\\\"spring.rabbitmq.password\\\":\\\"password\\\"},\\\"kind\\\":\\\"Secret\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"spring.cloud.kubernetes.secret\\\":\\\"true\\\"},\\\"name\\\":\\\"rabbit-password\\\",\\\"namespace\\\":\\\"default\\\"},\\\"type\\\":\\\"Opaque\\\"}\\n\"\n"
102-
+ "\t\t\t\t}\n" + "\t\t\t},\n" + "\t\t\t\"data\": {\n"
103-
+ "\t\t\t\t\"spring.rabbitmq.password\": \"cGFzc3dvcmQ=\"\n" + "\t\t\t},\n" + "\t\t\t\"type\": \"Opaque\"\n"
104-
+ "\t\t}\n" + "\t]\n" + "}";
83+
private static final String LIST_BODY = """
84+
{
85+
\t"kind": "SecretList",
86+
\t"apiVersion": "v1",
87+
\t"metadata": {
88+
\t\t"selfLink": "/api/v1/secrets",
89+
\t\t"resourceVersion": "163035"
90+
\t},
91+
\t"items": [{
92+
\t\t\t"metadata": {
93+
\t\t\t\t"name": "db-secret",
94+
\t\t\t\t"namespace": "default",
95+
\t\t\t\t"selfLink": "/api/v1/namespaces/default/secrets/db-secret",
96+
\t\t\t\t"uid": "59ba8e6a-a2d4-416c-b016-22597c193f23",
97+
\t\t\t\t"resourceVersion": "1462",
98+
\t\t\t\t"creationTimestamp": "2020-10-28T14:45:02Z",
99+
\t\t\t\t"labels": {
100+
\t\t\t\t\t"spring.cloud.kubernetes.secret": "true"
101+
\t\t\t\t}
102+
\t\t\t},
103+
\t\t\t"data": {
104+
\t\t\t\t"password": "cDQ1NXcwcmQ=",
105+
\t\t\t\t"username": "dXNlcg=="
106+
\t\t\t},
107+
\t\t\t"type": "Opaque"
108+
\t\t},
109+
\t\t{
110+
\t\t\t"metadata": {
111+
\t\t\t\t"name": "rabbit-password",
112+
\t\t\t\t"namespace": "default",
113+
\t\t\t\t"selfLink": "/api/v1/namespaces/default/secrets/rabbit-password",
114+
\t\t\t\t"uid": "bc211cb4-e7ff-4556-b26e-c54911301740",
115+
\t\t\t\t"resourceVersion": "162708",
116+
\t\t\t\t"creationTimestamp": "2020-10-29T19:47:36Z",
117+
\t\t\t\t"labels": {
118+
\t\t\t\t\t"spring.cloud.kubernetes.secret": "true"
119+
\t\t\t\t},
120+
\t\t\t\t"annotations": {
121+
\t\t\t\t\t"kubectl.kubernetes.io/last-applied-configuration": "{\\"apiVersion\\":\\"v1\\",\\"data\\":{\\"spring.rabbitmq.password\\":\\"password\\"},\\"kind\\":\\"Secret\\",\\"metadata\\":{\\"annotations\\":{},\\"labels\\":{\\"spring.cloud.kubernetes.secret\\":\\"true\\"},\\"name\\":\\"rabbit-password\\",\\"namespace\\":\\"default\\"},\\"type\\":\\"Opaque\\"}\\n"
122+
\t\t\t\t}
123+
\t\t\t},
124+
\t\t\t"data": {
125+
\t\t\t\t"spring.rabbitmq.password": "cGFzc3dvcmQ="
126+
\t\t\t},
127+
\t\t\t"type": "Opaque"
128+
\t\t}
129+
\t]
130+
}""";
105131

106132
private static WireMockServer wireMockServer;
107133

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
/*
2+
* Copyright 2013-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.kubernetes.client.config.reload_it;
18+
19+
import java.time.Duration;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.Set;
23+
24+
import com.github.tomakehurst.wiremock.WireMockServer;
25+
import com.github.tomakehurst.wiremock.client.WireMock;
26+
import io.kubernetes.client.openapi.ApiClient;
27+
import io.kubernetes.client.openapi.Configuration;
28+
import io.kubernetes.client.openapi.JSON;
29+
import io.kubernetes.client.openapi.apis.CoreV1Api;
30+
import io.kubernetes.client.openapi.models.V1ConfigMap;
31+
import io.kubernetes.client.openapi.models.V1ConfigMapBuilder;
32+
import io.kubernetes.client.openapi.models.V1ConfigMapList;
33+
import io.kubernetes.client.util.ClientBuilder;
34+
35+
import org.awaitility.Awaitility;
36+
import org.junit.jupiter.api.AfterAll;
37+
import org.junit.jupiter.api.BeforeAll;
38+
import org.junit.jupiter.api.Test;
39+
import org.junit.jupiter.api.extension.ExtendWith;
40+
import org.springframework.boot.test.context.SpringBootTest;
41+
import org.springframework.boot.test.context.TestConfiguration;
42+
import org.springframework.boot.test.system.CapturedOutput;
43+
import org.springframework.boot.test.system.OutputCaptureExtension;
44+
import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySource;
45+
import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator;
46+
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
47+
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties;
48+
import org.springframework.cloud.kubernetes.commons.config.RetryProperties;
49+
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
50+
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
51+
import org.springframework.cloud.kubernetes.commons.config.reload.PollingConfigMapChangeDetector;
52+
import org.springframework.context.annotation.Bean;
53+
import org.springframework.context.annotation.Primary;
54+
import org.springframework.core.env.AbstractEnvironment;
55+
import org.springframework.core.env.PropertySource;
56+
import org.springframework.mock.env.MockEnvironment;
57+
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
58+
59+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
60+
import static com.github.tomakehurst.wiremock.client.WireMock.get;
61+
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
62+
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
63+
64+
/**
65+
* set 'spring.cloud.kubernetes.reload.enabled=false' so that auto-configuration does not
66+
* kick in, as we create our own config for the test here.
67+
*
68+
* @author wind57
69+
*/
70+
@SpringBootTest(
71+
properties = { "spring.main.cloud-platform=kubernetes", "spring.main.allow-bean-definition-overriding=true",
72+
"spring.cloud.kubernetes.reload.enabled=false",
73+
"logging.level.org.springframework.cloud.kubernetes.commons.config=debug" },
74+
classes = { PollingReloadConfigMapTest.TestConfig.class })
75+
@ExtendWith(OutputCaptureExtension.class)
76+
class PollingReloadConfigMapTest {
77+
78+
private static WireMockServer wireMockServer;
79+
80+
private static final boolean FAIL_FAST = false;
81+
82+
private static final String CONFIG_MAP_NAME = "mine";
83+
84+
private static final String NAMESPACE = "spring-k8s";
85+
86+
private static final boolean[] strategyCalled = new boolean[] { false };
87+
88+
private static CoreV1Api coreV1Api;
89+
90+
@BeforeAll
91+
static void setup() {
92+
wireMockServer = new WireMockServer(options().dynamicPort());
93+
94+
wireMockServer.start();
95+
WireMock.configureFor("localhost", wireMockServer.port());
96+
97+
ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build();
98+
client.setDebugging(true);
99+
Configuration.setDefaultApiClient(client);
100+
coreV1Api = new CoreV1Api();
101+
102+
String path = "/api/v1/namespaces/spring-k8s/configmaps";
103+
V1ConfigMap configMapOne = configMap(CONFIG_MAP_NAME, Map.of());
104+
V1ConfigMapList listOne = new V1ConfigMapList().addItemsItem(configMapOne);
105+
106+
// needed so that our environment is populated with 'something'
107+
// this call is done in the method that returns the AbstractEnvironment
108+
stubFor(get(path).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listOne)))
109+
.inScenario("my-test").willSetStateTo("go-to-fail"));
110+
111+
stubFor(get(path).willReturn(aResponse().withStatus(500).withBody("Internal Server Error"))
112+
.inScenario("my-test").whenScenarioStateIs("go-to-fail").willSetStateTo("go-to-ok"));
113+
114+
V1ConfigMap configMapTwo = configMap(CONFIG_MAP_NAME, Map.of("a", "b"));
115+
V1ConfigMapList listTwo = new V1ConfigMapList().addItemsItem(configMapTwo);
116+
stubFor(get(path).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listTwo)))
117+
.inScenario("my-test").whenScenarioStateIs("go-to-ok"));
118+
119+
}
120+
121+
@AfterAll
122+
static void after() {
123+
wireMockServer.stop();
124+
}
125+
126+
/**
127+
* <pre>
128+
* - we have a PropertySource in the environment
129+
* - first polling cycle tries to read the sources from k8s and fails
130+
* - second polling cycle reads sources from k8s and finds a change
131+
* </pre>
132+
*/
133+
@Test
134+
void test(CapturedOutput output) {
135+
// we fail while reading 'configMapOne'
136+
Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(1)).until(() -> {
137+
boolean one = output.getOut().contains("failure in reading named sources");
138+
boolean two = output.getOut()
139+
.contains("there was an error while reading config maps/secrets, no reload will happen");
140+
boolean three = output.getOut()
141+
.contains("reloadable condition was not satisfied, reload will not be triggered");
142+
boolean updateStrategyNotCalled = !strategyCalled[0];
143+
return one && two && three && updateStrategyNotCalled;
144+
});
145+
146+
// it passes while reading 'configMapTwo'
147+
Awaitility.await()
148+
.atMost(Duration.ofSeconds(10))
149+
.pollInterval(Duration.ofSeconds(1))
150+
.until(() -> strategyCalled[0]);
151+
}
152+
153+
private static V1ConfigMap configMap(String name, Map<String, String> data) {
154+
return new V1ConfigMapBuilder().withNewMetadata().withName(name).endMetadata()
155+
.withData(data).build();
156+
}
157+
158+
@TestConfiguration
159+
static class TestConfig {
160+
161+
@Bean
162+
@Primary
163+
PollingConfigMapChangeDetector pollingConfigMapChangeDetector(AbstractEnvironment environment,
164+
ConfigReloadProperties configReloadProperties, ConfigurationUpdateStrategy configurationUpdateStrategy,
165+
KubernetesClientConfigMapPropertySourceLocator kubernetesClientConfigMapPropertySourceLocator) {
166+
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
167+
scheduler.initialize();
168+
return new PollingConfigMapChangeDetector(environment, configReloadProperties, configurationUpdateStrategy,
169+
KubernetesClientConfigMapPropertySource.class, kubernetesClientConfigMapPropertySourceLocator, scheduler);
170+
}
171+
172+
@Bean
173+
@Primary
174+
AbstractEnvironment environment() {
175+
MockEnvironment mockEnvironment = new MockEnvironment();
176+
mockEnvironment.setProperty("spring.cloud.kubernetes.client.namespace", NAMESPACE);
177+
178+
// simulate that environment already has a Fabric8ConfigMapPropertySource,
179+
// otherwise we can't properly test reload functionality
180+
ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties(true, List.of(),
181+
List.of(), Map.of(), true, CONFIG_MAP_NAME, NAMESPACE, false, true, true, RetryProperties.DEFAULT);
182+
KubernetesNamespaceProvider namespaceProvider = new KubernetesNamespaceProvider(mockEnvironment);
183+
184+
PropertySource<?> propertySource = new KubernetesClientConfigMapPropertySourceLocator(coreV1Api,
185+
configMapConfigProperties, namespaceProvider)
186+
.locate(mockEnvironment);
187+
188+
mockEnvironment.getPropertySources().addFirst(propertySource);
189+
return mockEnvironment;
190+
}
191+
192+
@Bean
193+
@Primary
194+
ConfigReloadProperties configReloadProperties() {
195+
return new ConfigReloadProperties(true, true, false, ConfigReloadProperties.ReloadStrategy.REFRESH,
196+
ConfigReloadProperties.ReloadDetectionMode.POLLING, Duration.ofMillis(2000), Set.of("non-default"),
197+
false, Duration.ofSeconds(2));
198+
}
199+
200+
@Bean
201+
@Primary
202+
ConfigMapConfigProperties configMapConfigProperties() {
203+
return new ConfigMapConfigProperties(true, List.of(), List.of(), Map.of(), true, CONFIG_MAP_NAME, NAMESPACE,
204+
false, true, FAIL_FAST, RetryProperties.DEFAULT);
205+
}
206+
207+
@Bean
208+
@Primary
209+
KubernetesNamespaceProvider namespaceProvider(AbstractEnvironment environment) {
210+
return new KubernetesNamespaceProvider(environment);
211+
}
212+
213+
@Bean
214+
@Primary
215+
ConfigurationUpdateStrategy configurationUpdateStrategy() {
216+
return new ConfigurationUpdateStrategy("to-console", () -> {
217+
strategyCalled[0] = true;
218+
});
219+
}
220+
221+
@Bean
222+
@Primary
223+
KubernetesClientConfigMapPropertySourceLocator kubernetesClientConfigMapPropertySourceLocator(
224+
ConfigMapConfigProperties configMapConfigProperties, KubernetesNamespaceProvider namespaceProvider) {
225+
return new KubernetesClientConfigMapPropertySourceLocator(coreV1Api, configMapConfigProperties,
226+
namespaceProvider);
227+
}
228+
229+
}
230+
231+
}

0 commit comments

Comments
 (0)