|
16 | 16 |
|
17 | 17 | package org.springframework.cloud.kubernetes.client.discovery; |
18 | 18 |
|
| 19 | +import java.util.ArrayList; |
| 20 | +import java.util.List; |
| 21 | + |
19 | 22 | import io.kubernetes.client.informer.SharedIndexInformer; |
20 | 23 | import io.kubernetes.client.informer.SharedInformerFactory; |
21 | 24 | import io.kubernetes.client.informer.cache.Lister; |
|
37 | 40 | import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration; |
38 | 41 | import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration; |
39 | 42 | import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; |
40 | | -import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException; |
41 | 43 | import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; |
42 | 44 | import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration; |
43 | 45 | import org.springframework.cloud.kubernetes.commons.discovery.conditionals.ConditionalOnBlockingOrReactiveDiscoveryEnabled; |
44 | 46 | import org.springframework.cloud.kubernetes.commons.discovery.conditionals.ConditionalOnKubernetesDiscoveryEnabled; |
45 | 47 | import org.springframework.context.annotation.Bean; |
46 | | -import org.springframework.context.annotation.Conditional; |
47 | 48 | import org.springframework.context.annotation.Configuration; |
48 | 49 | import org.springframework.core.log.LogAccessor; |
49 | 50 |
|
50 | 51 | import static io.kubernetes.client.util.Namespaces.NAMESPACE_ALL; |
51 | | -import static io.kubernetes.client.util.Namespaces.NAMESPACE_DEFAULT; |
52 | 52 | import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.getApplicationNamespace; |
53 | 53 |
|
54 | 54 | /** |
| 55 | + * This one uses: 'ConditionalOnBlockingOrReactiveDiscoveryEnabled' because beans it |
| 56 | + * contains are specific to both clients. |
| 57 | + * |
55 | 58 | * @author wind57 |
56 | 59 | */ |
57 | 60 | @Configuration(proxyBeanMethods = false) |
58 | 61 | @ConditionalOnDiscoveryEnabled |
59 | 62 | @ConditionalOnKubernetesDiscoveryEnabled |
60 | 63 | @ConditionalOnBlockingOrReactiveDiscoveryEnabled |
61 | 64 | @ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) |
62 | | -@Conditional(ConditionalOnSelectiveNamespacesMissing.class) |
63 | 65 | @AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class }) |
64 | 66 | @AutoConfigureAfter({ KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class }) |
65 | 67 | final class KubernetesClientInformerAutoConfiguration { |
66 | 68 |
|
67 | 69 | private static final LogAccessor LOG = new LogAccessor( |
68 | 70 | LogFactory.getLog(KubernetesClientInformerAutoConfiguration.class)); |
69 | 71 |
|
| 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. |
70 | 74 | @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) { |
76 | 77 |
|
77 | | - @Bean |
78 | | - String kubernetesClientNamespace(KubernetesDiscoveryProperties properties, KubernetesNamespaceProvider provider) { |
79 | | - String namespace; |
80 | 78 | if (properties.allNamespaces()) { |
81 | | - namespace = NAMESPACE_ALL; |
82 | 79 | LOG.debug(() -> "serviceSharedInformer will use all-namespaces"); |
| 80 | + return List.of(NAMESPACE_ALL); |
83 | 81 | } |
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; |
94 | 87 | } |
95 | 88 |
|
96 | | - return namespace; |
| 89 | + String namespace = getApplicationNamespace(null, "kubernetes client discovery", provider); |
| 90 | + LOG.debug(() -> "using namespace : " + namespace); |
| 91 | + return List.of(namespace); |
97 | 92 | } |
98 | 93 |
|
99 | 94 | @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) { |
106 | 97 |
|
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; |
109 | 104 | } |
110 | 105 |
|
111 | 106 | @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 | + } |
115 | 124 |
|
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 | + } |
118 | 139 |
|
119 | | - return sharedInformerFactory.sharedIndexInformerFor(servicesApi, V1Endpoints.class, 0L, |
120 | | - kubernetesClientNamespace); |
| 140 | + return serviceListers; |
121 | 141 | } |
122 | 142 |
|
123 | 143 | @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; |
128 | 160 | } |
129 | 161 |
|
130 | 162 | @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; |
135 | 178 | } |
136 | 179 |
|
137 | 180 | } |
0 commit comments