Skip to content

Commit f8671c1

Browse files
authored
Merge pull request spring-cloud#2164 from wind57/fix-issue-2148-reload
fix-2148: reload issue
2 parents 638784e + 73d8f91 commit f8671c1

File tree

9 files changed

+697
-37
lines changed

9 files changed

+697
-37
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
/*
2+
* Copyright 2013-present 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.commons.config.reload;
18+
19+
import java.util.List;
20+
import java.util.Map;
21+
22+
import com.github.tomakehurst.wiremock.WireMockServer;
23+
import com.github.tomakehurst.wiremock.client.WireMock;
24+
import io.kubernetes.client.openapi.ApiClient;
25+
import io.kubernetes.client.openapi.JSON;
26+
import io.kubernetes.client.openapi.apis.CoreV1Api;
27+
import io.kubernetes.client.openapi.models.V1ConfigMapList;
28+
import io.kubernetes.client.openapi.models.V1ConfigMapListBuilder;
29+
import io.kubernetes.client.openapi.models.V1SecretList;
30+
import io.kubernetes.client.openapi.models.V1SecretListBuilder;
31+
import io.kubernetes.client.util.ClientBuilder;
32+
import org.junit.jupiter.api.AfterAll;
33+
import org.junit.jupiter.api.BeforeAll;
34+
import org.junit.jupiter.api.Test;
35+
36+
import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigContext;
37+
import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySource;
38+
import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySource;
39+
import org.springframework.cloud.kubernetes.commons.config.MountConfigMapPropertySource;
40+
import org.springframework.cloud.kubernetes.commons.config.MountSecretPropertySource;
41+
import org.springframework.cloud.kubernetes.commons.config.NamedConfigMapNormalizedSource;
42+
import org.springframework.cloud.kubernetes.commons.config.NamedSecretNormalizedSource;
43+
import org.springframework.cloud.kubernetes.commons.config.SourceData;
44+
import org.springframework.core.env.MapPropertySource;
45+
import org.springframework.mock.env.MockEnvironment;
46+
47+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
48+
import static com.github.tomakehurst.wiremock.client.WireMock.get;
49+
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
50+
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
51+
import static org.assertj.core.api.Assertions.assertThat;
52+
53+
/**
54+
* @author wind57
55+
*/
56+
class KubernetesClientConfigReloadUtilTests {
57+
58+
private static final V1ConfigMapList CONFIGMAP_LIST = new V1ConfigMapListBuilder().build();
59+
60+
private static final V1SecretList SECRET_LIST = new V1SecretListBuilder().build();
61+
62+
private static WireMockServer wireMockServer;
63+
64+
private static ApiClient apiClient;
65+
66+
@BeforeAll
67+
static void beforeAll() {
68+
wireMockServer = new WireMockServer(options().dynamicPort());
69+
wireMockServer.start();
70+
WireMock.configureFor("localhost", wireMockServer.port());
71+
72+
apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build();
73+
74+
stubFor(get("/api/v1/namespaces/default/configmaps")
75+
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(CONFIGMAP_LIST))));
76+
77+
stubFor(get("/api/v1/namespaces/default/secrets")
78+
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(SECRET_LIST))));
79+
80+
}
81+
82+
@AfterAll
83+
static void afterAll() {
84+
wireMockServer.stop();
85+
}
86+
87+
/**
88+
* isInstance configmap matches.
89+
*/
90+
@Test
91+
void testIsInstanceConfigMapPasses() {
92+
93+
MockEnvironment environment = new MockEnvironment();
94+
KubernetesClientConfigMapPropertySource configMapPropertySource = configMapPropertySource();
95+
environment.getPropertySources().addFirst(configMapPropertySource);
96+
97+
List<MapPropertySource> propertySources = ConfigReloadUtil
98+
.findPropertySources(KubernetesClientConfigMapPropertySource.class, environment);
99+
100+
assertThat(propertySources).hasSize(1);
101+
}
102+
103+
/**
104+
* isInstance secret matches.
105+
*/
106+
@Test
107+
void testIsInstanceSecretPasses() {
108+
109+
MockEnvironment environment = new MockEnvironment();
110+
KubernetesClientSecretsPropertySource secretsPropertySource = secretsPropertySource();
111+
environment.getPropertySources().addFirst(secretsPropertySource);
112+
113+
List<MapPropertySource> propertySources = ConfigReloadUtil
114+
.findPropertySources(KubernetesClientSecretsPropertySource.class, environment);
115+
116+
assertThat(propertySources).hasSize(1);
117+
}
118+
119+
/**
120+
* <pre>
121+
* - environment contains KubernetesClientConfigMapPropertySource
122+
* - environment contains MountSecretPropertySource
123+
* - we search for KubernetesClientConfigMapPropertySource
124+
*
125+
* - the result is a single PropertySource of type KubernetesClientConfigMapPropertySource,
126+
* the MountSecretPropertySource is not taken.
127+
* </pre>
128+
*/
129+
@Test
130+
void testMountSecretPropertySourceNotTaken() {
131+
MockEnvironment environment = new MockEnvironment();
132+
KubernetesClientConfigMapPropertySource configMapPropertySource = configMapPropertySource();
133+
MountSecretPropertySource mountSecretPropertySource = new MountSecretPropertySource(
134+
new SourceData("mountSecretPropertySource", Map.of("a", "b")));
135+
136+
// both are present in environment
137+
environment.getPropertySources().addFirst(configMapPropertySource);
138+
environment.getPropertySources().addFirst(mountSecretPropertySource);
139+
140+
List<MapPropertySource> propertySources = ConfigReloadUtil
141+
.findPropertySources(KubernetesClientConfigMapPropertySource.class, environment);
142+
143+
// the mount secret one is not taken
144+
assertThat(propertySources).hasSize(1);
145+
assertThat(propertySources.get(0)).isInstanceOf(KubernetesClientConfigMapPropertySource.class);
146+
147+
}
148+
149+
/**
150+
* <pre>
151+
* - environment contains KubernetesClientSecretsPropertySource
152+
* - environment contains MountConfigMapPropertySource
153+
* - we search for KubernetesClientSecretsPropertySource
154+
*
155+
* - the result is a single PropertySource of type KubernetesClientSecretsPropertySource,
156+
* the MountConfigMapPropertySource is not taken.
157+
* </pre>
158+
*/
159+
@Test
160+
void testMountConfigMapPropertySourceNotTaken() {
161+
MockEnvironment environment = new MockEnvironment();
162+
KubernetesClientSecretsPropertySource secretsPropertySource = secretsPropertySource();
163+
MountConfigMapPropertySource mountConfigMapPropertySource = new MountConfigMapPropertySource(
164+
"mountConfigMapPropertySource", Map.of("a", "b"));
165+
166+
// both are present in environment
167+
environment.getPropertySources().addFirst(secretsPropertySource);
168+
environment.getPropertySources().addFirst(mountConfigMapPropertySource);
169+
170+
List<MapPropertySource> propertySources = ConfigReloadUtil
171+
.findPropertySources(KubernetesClientSecretsPropertySource.class, environment);
172+
173+
// the mount configmap one is not taken
174+
assertThat(propertySources).hasSize(1);
175+
assertThat(propertySources.get(0)).isInstanceOf(KubernetesClientSecretsPropertySource.class);
176+
177+
}
178+
179+
/**
180+
* <pre>
181+
* - environment contains KubernetesClientConfigMapPropertySource
182+
* - environment contains MountConfigMapPropertySource
183+
* - we search for KubernetesClientConfigMapPropertySource
184+
*
185+
* - the result is two PropertySources: KubernetesClientConfigMapPropertySource
186+
* and MountConfigMapPropertySource.
187+
* </pre>
188+
*/
189+
@Test
190+
void testMountConfigMapPropertySourceTaken() {
191+
MockEnvironment environment = new MockEnvironment();
192+
KubernetesClientConfigMapPropertySource configMapPropertySource = configMapPropertySource();
193+
MountConfigMapPropertySource mountConfigMapPropertySource = new MountConfigMapPropertySource(
194+
"mountConfigMapPropertySource", Map.of("a", "b"));
195+
196+
// both are present in environment
197+
environment.getPropertySources().addFirst(configMapPropertySource);
198+
environment.getPropertySources().addFirst(mountConfigMapPropertySource);
199+
200+
List<MapPropertySource> propertySources = ConfigReloadUtil
201+
.findPropertySources(KubernetesClientConfigMapPropertySource.class, environment);
202+
203+
// both are taken
204+
assertThat(propertySources).hasSize(2);
205+
assertThat(propertySources.get(0)).isInstanceOf(MountConfigMapPropertySource.class);
206+
assertThat(propertySources.get(1)).isInstanceOf(KubernetesClientConfigMapPropertySource.class);
207+
}
208+
209+
/**
210+
* <pre>
211+
* - environment contains KubernetesClientSecretsPropertySource
212+
* - environment contains MountSecretPropertySource
213+
* - we search for KubernetesClientSecretsPropertySource
214+
*
215+
* - the result is two PropertySources: KubernetesClientSecretsPropertySource
216+
* and MountSecretPropertySource.
217+
* </pre>
218+
*/
219+
@Test
220+
void testMountSecretPropertySourceTaken() {
221+
MockEnvironment environment = new MockEnvironment();
222+
KubernetesClientSecretsPropertySource secretsPropertySource = secretsPropertySource();
223+
MountSecretPropertySource mountSecretPropertySource = new MountSecretPropertySource(
224+
new SourceData("mountSecretPropertySource", Map.of("a", "b")));
225+
226+
// both are present in environment
227+
environment.getPropertySources().addFirst(secretsPropertySource);
228+
environment.getPropertySources().addFirst(mountSecretPropertySource);
229+
230+
List<MapPropertySource> propertySources = ConfigReloadUtil
231+
.findPropertySources(KubernetesClientSecretsPropertySource.class, environment);
232+
233+
// both are taken
234+
assertThat(propertySources).hasSize(2);
235+
assertThat(propertySources.get(0)).isInstanceOf(MountSecretPropertySource.class);
236+
assertThat(propertySources.get(1)).isInstanceOf(KubernetesClientSecretsPropertySource.class);
237+
}
238+
239+
private KubernetesClientConfigMapPropertySource configMapPropertySource() {
240+
CoreV1Api api = new CoreV1Api(apiClient);
241+
NamedConfigMapNormalizedSource namedSecretNormalizedSource = new NamedConfigMapNormalizedSource("configmap",
242+
"default", true, true);
243+
MockEnvironment environment = new MockEnvironment();
244+
245+
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, namedSecretNormalizedSource,
246+
"default", environment);
247+
248+
return new KubernetesClientConfigMapPropertySource(context);
249+
}
250+
251+
private KubernetesClientSecretsPropertySource secretsPropertySource() {
252+
CoreV1Api api = new CoreV1Api(apiClient);
253+
NamedSecretNormalizedSource namedSecretNormalizedSource = new NamedSecretNormalizedSource("secret", "default",
254+
true, true);
255+
MockEnvironment environment = new MockEnvironment();
256+
257+
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, namedSecretNormalizedSource,
258+
"default", environment);
259+
260+
return new KubernetesClientSecretsPropertySource(context);
261+
}
262+
263+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2013-present 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.commons.config;
18+
19+
import java.util.Map;
20+
21+
import org.springframework.core.env.MapPropertySource;
22+
23+
/**
24+
* Kubernetes property source for configmaps.
25+
*
26+
* @author wind57
27+
*/
28+
public class ConfigMapPropertySource extends MapPropertySource {
29+
30+
public ConfigMapPropertySource(String name, Map<String, Object> source) {
31+
super(name, source);
32+
}
33+
34+
}

spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/MountConfigMapPropertySource.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@
1818

1919
import java.util.Map;
2020

21-
import org.springframework.core.env.MapPropertySource;
22-
2321
/**
2422
* @author wind57
2523
*/
26-
public final class MountConfigMapPropertySource extends MapPropertySource {
24+
public final class MountConfigMapPropertySource extends ConfigMapPropertySource {
2725

2826
public MountConfigMapPropertySource(String name, Map<String, Object> source) {
2927
super(name, source);

spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/SourceDataEntriesProcessor.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import org.apache.commons.logging.LogFactory;
3131

3232
import org.springframework.core.env.Environment;
33-
import org.springframework.core.env.MapPropertySource;
3433

3534
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.KEY_VALUE_TO_PROPERTIES;
3635
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.PROPERTIES_TO_MAP;
@@ -44,7 +43,7 @@
4443
* @author Ali Shahbour
4544
* @author Michael Moudatsos
4645
*/
47-
public class SourceDataEntriesProcessor extends MapPropertySource {
46+
public class SourceDataEntriesProcessor extends ConfigMapPropertySource {
4847

4948
private static final Log LOG = LogFactory.getLog(SourceDataEntriesProcessor.class);
5049

spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/reload/ConfigReloadUtil.java

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626

2727
import org.springframework.cloud.bootstrap.config.BootstrapPropertySource;
2828
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
29+
import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySource;
2930
import org.springframework.cloud.kubernetes.commons.config.MountConfigMapPropertySource;
3031
import org.springframework.cloud.kubernetes.commons.config.MountSecretPropertySource;
32+
import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySource;
3133
import org.springframework.core.env.CompositePropertySource;
3234
import org.springframework.core.env.ConfigurableEnvironment;
3335
import org.springframework.core.env.MapPropertySource;
@@ -89,10 +91,9 @@ public static boolean reload(PropertySourceLocator locator, ConfigurableEnvironm
8991
* @deprecated this method will not be public in the next major release.
9092
*/
9193
@Deprecated(forRemoval = false)
92-
@SuppressWarnings("unchecked")
93-
public static <S extends PropertySource<?>> List<S> findPropertySources(Class<S> sourceClass,
94+
public static <S extends MapPropertySource> List<MapPropertySource> findPropertySources(Class<S> sourceClass,
9495
ConfigurableEnvironment environment) {
95-
List<S> managedSources = new ArrayList<>();
96+
List<MapPropertySource> managedSources = new ArrayList<>();
9697

9798
List<PropertySource<?>> sources = environment.getPropertySources()
9899
.stream()
@@ -108,27 +109,27 @@ public static <S extends PropertySource<?>> List<S> findPropertySources(Class<S>
108109
else if (sourceClass.isInstance(source)) {
109110
managedSources.add(sourceClass.cast(source));
110111
}
111-
else if (source instanceof MountConfigMapPropertySource mountConfigMapPropertySource) {
112-
// we know that the type is correct here
113-
managedSources.add((S) mountConfigMapPropertySource);
112+
else if (source instanceof MountConfigMapPropertySource mountConfigMapPropertySource
113+
&& ConfigMapPropertySource.class.isAssignableFrom(sourceClass)) {
114+
managedSources.add(mountConfigMapPropertySource);
114115
}
115-
else if (source instanceof MountSecretPropertySource mountSecretPropertySource) {
116-
// we know that the type is correct here
117-
managedSources.add((S) mountSecretPropertySource);
116+
else if (source instanceof MountSecretPropertySource mountSecretPropertySource
117+
&& SecretsPropertySource.class.isAssignableFrom(sourceClass)) {
118+
managedSources.add(mountSecretPropertySource);
118119
}
119120
else if (source instanceof BootstrapPropertySource<?> bootstrapPropertySource) {
120121
PropertySource<?> propertySource = bootstrapPropertySource.getDelegate();
121122
LOG.debug(() -> "bootstrap delegate class : " + propertySource.getClass());
122123
if (sourceClass.isInstance(propertySource)) {
123124
sources.add(propertySource);
124125
}
125-
else if (propertySource instanceof MountConfigMapPropertySource mountConfigMapPropertySource) {
126-
// we know that the type is correct here
127-
managedSources.add((S) mountConfigMapPropertySource);
126+
else if (propertySource instanceof MountConfigMapPropertySource mountConfigMapPropertySource
127+
&& ConfigMapPropertySource.class.isAssignableFrom(sourceClass)) {
128+
managedSources.add(mountConfigMapPropertySource);
128129
}
129-
else if (propertySource instanceof MountSecretPropertySource mountSecretPropertySource) {
130-
// we know that the type is correct here
131-
managedSources.add((S) mountSecretPropertySource);
130+
else if (propertySource instanceof MountSecretPropertySource mountSecretPropertySource
131+
&& SecretsPropertySource.class.isAssignableFrom(sourceClass)) {
132+
managedSources.add(mountSecretPropertySource);
132133
}
133134
}
134135
}

0 commit comments

Comments
 (0)