Skip to content

Commit a75f090

Browse files
authored
Merge pull request #2069 from wind57/simplify_k8s_client_discovery_to_drop_selective_namespaces
Simplify k8s client discovery to drop selective namespaces (6)
2 parents b8d7de3 + 77d4e39 commit a75f090

File tree

15 files changed

+373
-958
lines changed

15 files changed

+373
-958
lines changed

spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesMissing.java

Lines changed: 0 additions & 62 deletions
This file was deleted.

spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/ConditionalOnSelectiveNamespacesPresent.java

Lines changed: 0 additions & 62 deletions
This file was deleted.

spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerAutoConfiguration.java

Lines changed: 90 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.cloud.kubernetes.client.discovery;
1818

19+
import java.util.ArrayList;
20+
import java.util.List;
21+
1922
import io.kubernetes.client.informer.SharedIndexInformer;
2023
import io.kubernetes.client.informer.SharedInformerFactory;
2124
import io.kubernetes.client.informer.cache.Lister;
@@ -37,101 +40,141 @@
3740
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;
3841
import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration;
3942
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
40-
import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException;
4143
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
4244
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration;
4345
import org.springframework.cloud.kubernetes.commons.discovery.conditionals.ConditionalOnBlockingOrReactiveDiscoveryEnabled;
4446
import org.springframework.cloud.kubernetes.commons.discovery.conditionals.ConditionalOnKubernetesDiscoveryEnabled;
4547
import org.springframework.context.annotation.Bean;
46-
import org.springframework.context.annotation.Conditional;
4748
import org.springframework.context.annotation.Configuration;
4849
import org.springframework.core.log.LogAccessor;
4950

5051
import static io.kubernetes.client.util.Namespaces.NAMESPACE_ALL;
51-
import static io.kubernetes.client.util.Namespaces.NAMESPACE_DEFAULT;
5252
import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.getApplicationNamespace;
5353

5454
/**
55+
* This one uses: 'ConditionalOnBlockingOrReactiveDiscoveryEnabled' because beans it
56+
* contains are specific to both clients.
57+
*
5558
* @author wind57
5659
*/
5760
@Configuration(proxyBeanMethods = false)
5861
@ConditionalOnDiscoveryEnabled
5962
@ConditionalOnKubernetesDiscoveryEnabled
6063
@ConditionalOnBlockingOrReactiveDiscoveryEnabled
6164
@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES)
62-
@Conditional(ConditionalOnSelectiveNamespacesMissing.class)
6365
@AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class })
6466
@AutoConfigureAfter({ KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class })
6567
final class KubernetesClientInformerAutoConfiguration {
6668

6769
private static final LogAccessor LOG = new LogAccessor(
6870
LogFactory.getLog(KubernetesClientInformerAutoConfiguration.class));
6971

72+
// we rely on the order of namespaces to enable listers, as such provide a bean of
73+
// namespaces as a list, instead of the incoming Set.
7074
@Bean
71-
@ConditionalOnMissingBean
72-
SharedInformerFactory sharedInformerFactory(ApiClient client) {
73-
LOG.debug(() -> "registering sharedInformerFactory for non-selective namespaces");
74-
return new SharedInformerFactory(client);
75-
}
75+
List<String> k8sClientDiscoveryNamespaces(KubernetesDiscoveryProperties properties,
76+
KubernetesNamespaceProvider provider) {
7677

77-
@Bean
78-
String kubernetesClientNamespace(KubernetesDiscoveryProperties properties, KubernetesNamespaceProvider provider) {
79-
String namespace;
8078
if (properties.allNamespaces()) {
81-
namespace = NAMESPACE_ALL;
8279
LOG.debug(() -> "serviceSharedInformer will use all-namespaces");
80+
return List.of(NAMESPACE_ALL);
8381
}
84-
else {
85-
try {
86-
namespace = getApplicationNamespace(null, "kubernetes client discovery", provider);
87-
}
88-
catch (NamespaceResolutionFailedException ex) {
89-
LOG.warn(() -> "failed to resolve namespace, defaulting to :" + NAMESPACE_DEFAULT
90-
+ ". This will fail in a future release.");
91-
namespace = NAMESPACE_DEFAULT;
92-
}
93-
LOG.debug("serviceSharedInformer will use namespace : " + namespace);
82+
83+
if (properties.namespaces() != null && !properties.namespaces().isEmpty()) {
84+
List<String> selectiveNamespaces = properties.namespaces().stream().sorted().toList();
85+
LOG.debug(() -> "serviceSharedInformers will use selective namespaces : " + selectiveNamespaces);
86+
return selectiveNamespaces;
9487
}
9588

96-
return namespace;
89+
String namespace = getApplicationNamespace(null, "kubernetes client discovery", provider);
90+
LOG.debug(() -> "using namespace : " + namespace);
91+
return List.of(namespace);
9792
}
9893

9994
@Bean
100-
@ConditionalOnMissingBean(value = V1Service.class, parameterizedContainer = SharedIndexInformer.class)
101-
SharedIndexInformer<V1Service> servicesSharedIndexInformer(SharedInformerFactory sharedInformerFactory,
102-
ApiClient apiClient, String kubernetesClientNamespace) {
103-
104-
GenericKubernetesApi<V1Service, V1ServiceList> servicesApi = new GenericKubernetesApi<>(V1Service.class,
105-
V1ServiceList.class, "", "v1", "services", apiClient);
95+
@ConditionalOnMissingBean(value = SharedInformerFactory.class, parameterizedContainer = List.class)
96+
List<SharedInformerFactory> sharedInformerFactories(ApiClient apiClient, List<String> selectiveNamespaces) {
10697

107-
return sharedInformerFactory.sharedIndexInformerFor(servicesApi, V1Service.class, 0L,
108-
kubernetesClientNamespace);
98+
int howManyNamespaces = selectiveNamespaces.size();
99+
List<SharedInformerFactory> sharedInformerFactories = new ArrayList<>(howManyNamespaces);
100+
for (int i = 0; i < howManyNamespaces; ++i) {
101+
sharedInformerFactories.add(new SharedInformerFactory(apiClient));
102+
}
103+
return sharedInformerFactories;
109104
}
110105

111106
@Bean
112-
@ConditionalOnMissingBean(value = V1Endpoints.class, parameterizedContainer = SharedIndexInformer.class)
113-
SharedIndexInformer<V1Endpoints> endpointsSharedIndexInformer(SharedInformerFactory sharedInformerFactory,
114-
ApiClient apiClient, String kubernetesClientNamespace) {
107+
@ConditionalOnMissingBean(value = V1Service.class,
108+
parameterizedContainer = { List.class, SharedIndexInformer.class })
109+
List<SharedIndexInformer<V1Service>> serviceSharedIndexInformers(
110+
List<SharedInformerFactory> sharedInformerFactories, List<String> selectiveNamespaces,
111+
ApiClient apiClient) {
112+
113+
int howManyNamespaces = selectiveNamespaces.size();
114+
List<SharedIndexInformer<V1Service>> serviceSharedIndexedInformers = new ArrayList<>(howManyNamespaces);
115+
for (int i = 0; i < howManyNamespaces; ++i) {
116+
GenericKubernetesApi<V1Service, V1ServiceList> servicesApi = new GenericKubernetesApi<>(V1Service.class,
117+
V1ServiceList.class, "", "v1", "services", apiClient);
118+
SharedIndexInformer<V1Service> sharedIndexInformer = sharedInformerFactories.get(i)
119+
.sharedIndexInformerFor(servicesApi, V1Service.class, 0L, selectiveNamespaces.get(i));
120+
serviceSharedIndexedInformers.add(sharedIndexInformer);
121+
}
122+
return serviceSharedIndexedInformers;
123+
}
115124

116-
GenericKubernetesApi<V1Endpoints, V1EndpointsList> servicesApi = new GenericKubernetesApi<>(V1Endpoints.class,
117-
V1EndpointsList.class, "", "v1", "endpoints", apiClient);
125+
@Bean
126+
@ConditionalOnMissingBean(value = V1Service.class, parameterizedContainer = { List.class, Lister.class })
127+
List<Lister<V1Service>> serviceListers(List<String> selectiveNamespaces,
128+
List<SharedIndexInformer<V1Service>> serviceSharedIndexInformers) {
129+
130+
int howManyNamespaces = selectiveNamespaces.size();
131+
List<Lister<V1Service>> serviceListers = new ArrayList<>(howManyNamespaces);
132+
133+
for (int i = 0; i < howManyNamespaces; ++i) {
134+
String namespace = selectiveNamespaces.get(i);
135+
Lister<V1Service> lister = new Lister<>(serviceSharedIndexInformers.get(i).getIndexer(), namespace);
136+
LOG.debug(() -> "registering lister (for services) in namespace : " + namespace);
137+
serviceListers.add(lister);
138+
}
118139

119-
return sharedInformerFactory.sharedIndexInformerFor(servicesApi, V1Endpoints.class, 0L,
120-
kubernetesClientNamespace);
140+
return serviceListers;
121141
}
122142

123143
@Bean
124-
@ConditionalOnMissingBean(value = V1Service.class, parameterizedContainer = Lister.class)
125-
Lister<V1Service> servicesLister(SharedIndexInformer<V1Service> servicesSharedIndexInformer,
126-
String kubernetesClientNamespace) {
127-
return new Lister<>(servicesSharedIndexInformer.getIndexer(), kubernetesClientNamespace);
144+
@ConditionalOnMissingBean(value = V1Endpoints.class,
145+
parameterizedContainer = { List.class, SharedIndexInformer.class })
146+
List<SharedIndexInformer<V1Endpoints>> endpointsSharedIndexInformers(
147+
List<SharedInformerFactory> sharedInformerFactories, List<String> selectiveNamespaces,
148+
ApiClient apiClient) {
149+
150+
int howManyNamespaces = selectiveNamespaces.size();
151+
List<SharedIndexInformer<V1Endpoints>> endpointsSharedIndexedInformers = new ArrayList<>(howManyNamespaces);
152+
for (int i = 0; i < howManyNamespaces; ++i) {
153+
GenericKubernetesApi<V1Endpoints, V1EndpointsList> endpointsApi = new GenericKubernetesApi<>(
154+
V1Endpoints.class, V1EndpointsList.class, "", "v1", "endpoints", apiClient);
155+
SharedIndexInformer<V1Endpoints> sharedIndexInformer = sharedInformerFactories.get(i)
156+
.sharedIndexInformerFor(endpointsApi, V1Endpoints.class, 0L, selectiveNamespaces.get(i));
157+
endpointsSharedIndexedInformers.add(sharedIndexInformer);
158+
}
159+
return endpointsSharedIndexedInformers;
128160
}
129161

130162
@Bean
131-
@ConditionalOnMissingBean(value = V1Endpoints.class, parameterizedContainer = Lister.class)
132-
Lister<V1Endpoints> endpointsLister(SharedIndexInformer<V1Endpoints> endpointsSharedIndexInformer,
133-
String kubernetesClientNamespace) {
134-
return new Lister<>(endpointsSharedIndexInformer.getIndexer(), kubernetesClientNamespace);
163+
@ConditionalOnMissingBean(value = V1Endpoints.class, parameterizedContainer = { List.class, Lister.class })
164+
List<Lister<V1Endpoints>> endpointsListers(List<String> selectiveNamespaces,
165+
List<SharedIndexInformer<V1Endpoints>> serviceSharedIndexInformers) {
166+
167+
int howManyNamespaces = selectiveNamespaces.size();
168+
List<Lister<V1Endpoints>> endpointsListers = new ArrayList<>(howManyNamespaces);
169+
170+
for (int i = 0; i < howManyNamespaces; ++i) {
171+
String namespace = selectiveNamespaces.get(i);
172+
Lister<V1Endpoints> lister = new Lister<>(serviceSharedIndexInformers.get(i).getIndexer());
173+
LOG.debug(() -> "registering lister (for endpoints) in namespace : " + namespace);
174+
endpointsListers.add(lister);
175+
}
176+
177+
return endpointsListers;
135178
}
136179

137180
}

spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerDiscoveryClientAutoConfiguration.java

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,24 @@
2525
import io.kubernetes.client.openapi.apis.CoreV1Api;
2626
import io.kubernetes.client.openapi.models.V1Endpoints;
2727
import io.kubernetes.client.openapi.models.V1Service;
28+
import org.apache.commons.logging.LogFactory;
2829

2930
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3031
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
3132
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3233
import org.springframework.cloud.client.CommonsClientAutoConfiguration;
3334
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;
3435
import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration;
35-
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthConfiguration;
36+
import org.springframework.cloud.kubernetes.commons.PodUtils;
37+
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer;
3638
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
3739
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration;
3840
import org.springframework.cloud.kubernetes.commons.discovery.conditionals.ConditionalOnSpringCloudKubernetesBlockingDiscovery;
41+
import org.springframework.cloud.kubernetes.commons.discovery.conditionals.ConditionalOnSpringCloudKubernetesBlockingDiscoveryHealthInitializer;
42+
import org.springframework.context.ApplicationEventPublisher;
3943
import org.springframework.context.annotation.Bean;
40-
import org.springframework.context.annotation.Conditional;
4144
import org.springframework.context.annotation.Configuration;
42-
import org.springframework.context.annotation.Import;
45+
import org.springframework.core.log.LogAccessor;
4346

4447
/**
4548
* @author wind57
@@ -48,29 +51,15 @@
4851
@ConditionalOnSpringCloudKubernetesBlockingDiscovery
4952
@AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class })
5053
@AutoConfigureAfter({ KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class,
51-
KubernetesClientInformerAutoConfiguration.class,
52-
KubernetesClientInformerSelectiveNamespacesAutoConfiguration.class,
5354
KubernetesClientDiscoveryClientSpelAutoConfiguration.class })
54-
@Import(KubernetesDiscoveryClientHealthConfiguration.class)
5555
final class KubernetesClientInformerDiscoveryClientAutoConfiguration {
5656

57-
@Bean
58-
@ConditionalOnMissingBean
59-
@Conditional(ConditionalOnSelectiveNamespacesMissing.class)
60-
KubernetesClientInformerDiscoveryClient kubernetesClientInformerDiscoveryClient(
61-
SharedInformerFactory sharedInformerFactory, Lister<V1Service> serviceLister,
62-
Lister<V1Endpoints> endpointsLister, SharedInformer<V1Service> serviceInformer,
63-
SharedInformer<V1Endpoints> endpointsInformer, KubernetesDiscoveryProperties properties,
64-
CoreV1Api coreV1Api, Predicate<V1Service> predicate) {
65-
return new KubernetesClientInformerDiscoveryClient(List.of(sharedInformerFactory), List.of(serviceLister),
66-
List.of(endpointsLister), List.of(serviceInformer), List.of(endpointsInformer), properties, coreV1Api,
67-
predicate);
68-
}
57+
private static final LogAccessor LOG = new LogAccessor(
58+
LogFactory.getLog(KubernetesClientInformerDiscoveryClientAutoConfiguration.class));
6959

7060
@Bean
7161
@ConditionalOnMissingBean
72-
@Conditional(ConditionalOnSelectiveNamespacesPresent.class)
73-
KubernetesClientInformerDiscoveryClient selectiveNamespacesKubernetesInformerDiscoveryClient(
62+
KubernetesClientInformerDiscoveryClient kubernetesClientInformerDiscoveryClient(
7463
List<SharedInformerFactory> sharedInformerFactories, List<Lister<V1Service>> serviceListers,
7564
List<Lister<V1Endpoints>> endpointsListers, List<SharedInformer<V1Service>> serviceInformers,
7665
List<SharedInformer<V1Endpoints>> endpointsInformers, KubernetesDiscoveryProperties properties,
@@ -79,4 +68,12 @@ KubernetesClientInformerDiscoveryClient selectiveNamespacesKubernetesInformerDis
7968
serviceInformers, endpointsInformers, properties, coreV1Api, predicate);
8069
}
8170

71+
@Bean
72+
@ConditionalOnSpringCloudKubernetesBlockingDiscoveryHealthInitializer
73+
KubernetesDiscoveryClientHealthIndicatorInitializer indicatorInitializer(
74+
ApplicationEventPublisher applicationEventPublisher, PodUtils<?> podUtils) {
75+
LOG.debug(() -> "Will publish InstanceRegisteredEvent from blocking implementation");
76+
return new KubernetesDiscoveryClientHealthIndicatorInitializer(podUtils, applicationEventPublisher);
77+
}
78+
8279
}

0 commit comments

Comments
 (0)