Skip to content

Commit 693fcf0

Browse files
committed
Merge branch 'main' into drop_old_leader_election_implementation
2 parents dd4678c + 5e00f3c commit 693fcf0

File tree

20 files changed

+618
-226
lines changed

20 files changed

+618
-226
lines changed

spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedConfigMapChangeDetector.java

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ public class KubernetesClientEventBasedConfigMapChangeDetector extends Configura
7171

7272
private final boolean enableReloadFiltering;
7373

74+
private final boolean monitoringConfigMaps;
75+
7476
private final ResourceEventHandler<V1ConfigMap> handler = new ResourceEventHandler<>() {
7577

7678
@Override
@@ -110,35 +112,40 @@ public KubernetesClientEventBasedConfigMapChangeDetector(CoreV1Api coreV1Api, Co
110112
this.coreV1Api = coreV1Api;
111113
this.apiClient = createApiClientForInformerClient();
112114
this.enableReloadFiltering = properties.enableReloadFiltering();
115+
this.monitoringConfigMaps = properties.monitoringConfigMaps();
113116
namespaces = namespaces(kubernetesNamespaceProvider, properties, "configmap");
114117
}
115118

116119
@PostConstruct
117120
void inform() {
118121
LOG.info(() -> "Kubernetes event-based configMap change detector activated");
119-
120-
namespaces.forEach(namespace -> {
121-
SharedIndexInformer<V1ConfigMap> informer;
122-
String[] filter = new String[1];
123-
124-
if (enableReloadFiltering) {
125-
filter[0] = ConfigReloadProperties.RELOAD_LABEL_FILTER + "=true";
126-
}
127-
SharedInformerFactory factory = new SharedInformerFactory(apiClient);
128-
factories.add(factory);
129-
informer = factory
130-
.sharedIndexInformerFor((CallGeneratorParams params) -> coreV1Api.listNamespacedConfigMap(namespace)
131-
.timeoutSeconds(params.timeoutSeconds)
132-
.resourceVersion(params.resourceVersion)
133-
.watch(params.watch)
134-
.buildCall(null), V1ConfigMap.class, V1ConfigMapList.class);
135-
136-
LOG.debug(() -> "added configmap informer for namespace : " + namespace + " with filter : " + filter[0]);
137-
138-
informer.addEventHandler(handler);
139-
informers.add(informer);
140-
factory.startAllRegisteredInformers();
141-
});
122+
if (monitoringConfigMaps) {
123+
LOG.info(() -> "Kubernetes event-based configMap change detector activated");
124+
125+
namespaces.forEach(namespace -> {
126+
SharedIndexInformer<V1ConfigMap> informer;
127+
String[] filter = new String[1];
128+
129+
if (enableReloadFiltering) {
130+
filter[0] = ConfigReloadProperties.RELOAD_LABEL_FILTER + "=true";
131+
}
132+
SharedInformerFactory factory = new SharedInformerFactory(apiClient);
133+
factories.add(factory);
134+
informer = factory
135+
.sharedIndexInformerFor((CallGeneratorParams params) -> coreV1Api.listNamespacedConfigMap(namespace)
136+
.timeoutSeconds(params.timeoutSeconds)
137+
.resourceVersion(params.resourceVersion)
138+
.watch(params.watch)
139+
.buildCall(null), V1ConfigMap.class, V1ConfigMapList.class);
140+
141+
LOG.debug(
142+
() -> "added configmap informer for namespace : " + namespace + " with filter : " + filter[0]);
143+
144+
informer.addEventHandler(handler);
145+
informers.add(informer);
146+
factory.startAllRegisteredInformers();
147+
});
148+
}
142149

143150
}
144151

spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedSecretsChangeDetector.java

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public class KubernetesClientEventBasedSecretsChangeDetector extends Configurati
7373

7474
private final boolean enableReloadFiltering;
7575

76+
private final boolean monitoringSecrets;
77+
7678
private final ResourceEventHandler<V1Secret> handler = new ResourceEventHandler<>() {
7779

7880
@Override
@@ -113,35 +115,38 @@ public KubernetesClientEventBasedSecretsChangeDetector(CoreV1Api coreV1Api, Conf
113115
this.coreV1Api = coreV1Api;
114116
this.apiClient = createApiClientForInformerClient();
115117
this.enableReloadFiltering = properties.enableReloadFiltering();
118+
this.monitoringSecrets = properties.monitoringSecrets();
116119
namespaces = namespaces(kubernetesNamespaceProvider, properties, "secret");
117120
}
118121

119122
@PostConstruct
120123
void inform() {
121124
LOG.info(() -> "Kubernetes event-based secrets change detector activated");
122125

123-
namespaces.forEach(namespace -> {
124-
SharedIndexInformer<V1Secret> informer;
125-
String[] filter = new String[1];
126-
127-
if (enableReloadFiltering) {
128-
filter[0] = ConfigReloadProperties.RELOAD_LABEL_FILTER + "=true";
129-
}
130-
SharedInformerFactory factory = new SharedInformerFactory(apiClient);
131-
factories.add(factory);
132-
informer = factory
133-
.sharedIndexInformerFor((CallGeneratorParams params) -> coreV1Api.listNamespacedSecret(namespace)
134-
.timeoutSeconds(params.timeoutSeconds)
135-
.resourceVersion(params.resourceVersion)
136-
.watch(params.watch)
137-
.buildCall(null), V1Secret.class, V1SecretList.class);
138-
139-
LOG.debug(() -> "added secret informer for namespace : " + namespace + " with filter : " + filter[0]);
140-
141-
informer.addEventHandler(handler);
142-
informers.add(informer);
143-
factory.startAllRegisteredInformers();
144-
});
126+
if (monitoringSecrets) {
127+
namespaces.forEach(namespace -> {
128+
SharedIndexInformer<V1Secret> informer;
129+
String[] filter = new String[1];
130+
131+
if (enableReloadFiltering) {
132+
filter[0] = ConfigReloadProperties.RELOAD_LABEL_FILTER + "=true";
133+
}
134+
SharedInformerFactory factory = new SharedInformerFactory(apiClient);
135+
factories.add(factory);
136+
informer = factory
137+
.sharedIndexInformerFor((CallGeneratorParams params) -> coreV1Api.listNamespacedSecret(namespace)
138+
.timeoutSeconds(params.timeoutSeconds)
139+
.resourceVersion(params.resourceVersion)
140+
.watch(params.watch)
141+
.buildCall(null), V1Secret.class, V1SecretList.class);
142+
143+
LOG.debug(() -> "added secret informer for namespace : " + namespace + " with filter : " + filter[0]);
144+
145+
informer.addEventHandler(handler);
146+
informers.add(informer);
147+
factory.startAllRegisteredInformers();
148+
});
149+
}
145150

146151
}
147152

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

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,13 @@
1616

1717
package org.springframework.cloud.kubernetes.client.config.reload;
1818

19-
import java.io.IOException;
20-
import java.lang.reflect.Modifier;
21-
import java.time.OffsetDateTime;
2219
import java.util.HashMap;
2320
import java.util.List;
2421
import java.util.Map;
2522
import java.util.concurrent.TimeUnit;
2623

2724
import com.github.tomakehurst.wiremock.WireMockServer;
2825
import com.github.tomakehurst.wiremock.client.WireMock;
29-
import com.google.gson.Gson;
30-
import com.google.gson.GsonBuilder;
31-
import com.google.gson.TypeAdapter;
32-
import com.google.gson.stream.JsonReader;
33-
import com.google.gson.stream.JsonWriter;
3426
import io.kubernetes.client.informer.EventType;
3527
import io.kubernetes.client.openapi.ApiClient;
3628
import io.kubernetes.client.openapi.JSON;
@@ -93,10 +85,6 @@ public void afterEach() {
9385

9486
@Test
9587
void watch() {
96-
GsonBuilder builder = new GsonBuilder();
97-
builder.excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT, Modifier.VOLATILE)
98-
.registerTypeAdapter(OffsetDateTime.class, new GsonOffsetDateTimeAdapter());
99-
Gson gson = builder.create();
10088

10189
Map<String, String> data = new HashMap<>();
10290
data.put(Constants.APPLICATION_PROPERTIES, "spring.cloud.kubernetes.configuration.watcher.refreshDelay=0\n"
@@ -113,7 +101,7 @@ void watch() {
113101
stubFor(get(urlMatching("^/api/v1/namespaces/default/configmaps.*")).inScenario("watch")
114102
.whenScenarioStateIs(STARTED)
115103
.withQueryParam("watch", equalTo("false"))
116-
.willReturn(aResponse().withStatus(200).withBody(gson.toJson(configMapList)))
104+
.willReturn(aResponse().withStatus(200).withBody(JSON.serialize(configMapList)))
117105
.willSetStateTo("update"));
118106

119107
Watch.Response<V1ConfigMap> watchResponse = new Watch.Response<>(EventType.MODIFIED.name(),
@@ -180,21 +168,4 @@ void watch() {
180168
Awaitilities.awaitUntil(10, 1000, () -> howMany[0] >= 4);
181169
}
182170

183-
// This is needed when using JDK17 because GSON uses reflection to construct an
184-
// OffsetDateTime but that constructor
185-
// is protected.
186-
public final static class GsonOffsetDateTimeAdapter extends TypeAdapter<OffsetDateTime> {
187-
188-
@Override
189-
public void write(JsonWriter jsonWriter, OffsetDateTime localDateTime) throws IOException {
190-
jsonWriter.value(OffsetDateTime.now().toString());
191-
}
192-
193-
@Override
194-
public OffsetDateTime read(JsonReader jsonReader) {
195-
return OffsetDateTime.now();
196-
}
197-
198-
}
199-
200171
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
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+
21+
import com.github.tomakehurst.wiremock.WireMockServer;
22+
import com.github.tomakehurst.wiremock.client.WireMock;
23+
import io.kubernetes.client.openapi.ApiClient;
24+
import io.kubernetes.client.openapi.JSON;
25+
import io.kubernetes.client.openapi.apis.CoreV1Api;
26+
import io.kubernetes.client.openapi.models.V1ConfigMapList;
27+
import io.kubernetes.client.openapi.models.V1ConfigMapListBuilder;
28+
import io.kubernetes.client.openapi.models.V1SecretList;
29+
import io.kubernetes.client.openapi.models.V1SecretListBuilder;
30+
import io.kubernetes.client.util.ClientBuilder;
31+
import org.junit.jupiter.api.AfterAll;
32+
import org.junit.jupiter.api.BeforeAll;
33+
import org.junit.jupiter.api.Test;
34+
35+
import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigContext;
36+
import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySource;
37+
import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySource;
38+
import org.springframework.cloud.kubernetes.commons.config.NamedConfigMapNormalizedSource;
39+
import org.springframework.cloud.kubernetes.commons.config.NamedSecretNormalizedSource;
40+
import org.springframework.cloud.kubernetes.commons.config.ReadType;
41+
import org.springframework.core.env.MapPropertySource;
42+
import org.springframework.mock.env.MockEnvironment;
43+
44+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
45+
import static com.github.tomakehurst.wiremock.client.WireMock.get;
46+
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
47+
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
48+
import static org.assertj.core.api.Assertions.assertThat;
49+
50+
/**
51+
* @author wind57
52+
*/
53+
class KubernetesClientConfigReloadUtilTests {
54+
55+
private static final V1ConfigMapList CONFIGMAP_LIST = new V1ConfigMapListBuilder().build();
56+
57+
private static final V1SecretList SECRET_LIST = new V1SecretListBuilder().build();
58+
59+
private static WireMockServer wireMockServer;
60+
61+
private static ApiClient apiClient;
62+
63+
@BeforeAll
64+
static void beforeAll() {
65+
wireMockServer = new WireMockServer(options().dynamicPort());
66+
wireMockServer.start();
67+
WireMock.configureFor("localhost", wireMockServer.port());
68+
69+
apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build();
70+
71+
stubFor(get("/api/v1/namespaces/default/configmaps")
72+
.willReturn(aResponse().withStatus(200).withBody(JSON.serialize(CONFIGMAP_LIST))));
73+
74+
stubFor(get("/api/v1/namespaces/default/secrets")
75+
.willReturn(aResponse().withStatus(200).withBody(JSON.serialize(SECRET_LIST))));
76+
77+
}
78+
79+
@AfterAll
80+
static void afterAll() {
81+
wireMockServer.stop();
82+
}
83+
84+
/**
85+
* isInstance configmap matches.
86+
*/
87+
@Test
88+
void testIsInstanceConfigMapPasses() {
89+
90+
MockEnvironment environment = new MockEnvironment();
91+
KubernetesClientConfigMapPropertySource configMapPropertySource = configMapPropertySource();
92+
environment.getPropertySources().addFirst(configMapPropertySource);
93+
94+
List<MapPropertySource> propertySources = ConfigReloadUtil
95+
.findPropertySources(KubernetesClientConfigMapPropertySource.class, environment);
96+
97+
assertThat(propertySources).hasSize(1);
98+
}
99+
100+
/**
101+
* isInstance secret matches.
102+
*/
103+
@Test
104+
void testIsInstanceSecretPasses() {
105+
106+
MockEnvironment environment = new MockEnvironment();
107+
KubernetesClientSecretsPropertySource secretsPropertySource = secretsPropertySource();
108+
environment.getPropertySources().addFirst(secretsPropertySource);
109+
110+
List<MapPropertySource> propertySources = ConfigReloadUtil
111+
.findPropertySources(KubernetesClientSecretsPropertySource.class, environment);
112+
113+
assertThat(propertySources).hasSize(1);
114+
}
115+
116+
private KubernetesClientConfigMapPropertySource configMapPropertySource() {
117+
CoreV1Api api = new CoreV1Api(apiClient);
118+
NamedConfigMapNormalizedSource namedSecretNormalizedSource = new NamedConfigMapNormalizedSource("configmap",
119+
"default", true, true);
120+
MockEnvironment environment = new MockEnvironment();
121+
122+
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, namedSecretNormalizedSource,
123+
"default", environment, false, ReadType.BATCH);
124+
125+
return new KubernetesClientConfigMapPropertySource(context);
126+
}
127+
128+
private KubernetesClientSecretsPropertySource secretsPropertySource() {
129+
CoreV1Api api = new CoreV1Api(apiClient);
130+
NamedSecretNormalizedSource namedSecretNormalizedSource = new NamedSecretNormalizedSource("secret", "default",
131+
true, true);
132+
MockEnvironment environment = new MockEnvironment();
133+
134+
KubernetesClientConfigContext context = new KubernetesClientConfigContext(api, namedSecretNormalizedSource,
135+
"default", environment, false, ReadType.BATCH);
136+
137+
return new KubernetesClientSecretsPropertySource(context);
138+
}
139+
140+
}
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/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

0 commit comments

Comments
 (0)