fix 1207 for kubernetes native client (#1208)

This commit is contained in:
erabii
2023-02-04 03:05:28 +02:00
committed by GitHub
parent 7c73c5b941
commit 450616d3fa
17 changed files with 763 additions and 172 deletions

View File

@@ -65,6 +65,11 @@
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-kubernetes-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8-standalone</artifactId>

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2019-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.discovery;
import io.kubernetes.client.informer.SharedInformerFactory;
import io.kubernetes.client.openapi.models.V1Endpoints;
import io.kubernetes.client.openapi.models.V1EndpointsList;
import io.kubernetes.client.openapi.models.V1Service;
import io.kubernetes.client.openapi.models.V1ServiceList;
import io.kubernetes.client.spring.extended.controller.annotation.GroupVersionResource;
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesInformer;
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesInformers;
@KubernetesInformers({
@KubernetesInformer(apiTypeClass = V1Service.class, apiListTypeClass = V1ServiceList.class,
groupVersionResource = @GroupVersionResource(apiGroup = "", apiVersion = "v1",
resourcePlural = "services")),
@KubernetesInformer(apiTypeClass = V1Endpoints.class, apiListTypeClass = V1EndpointsList.class,
groupVersionResource = @GroupVersionResource(apiGroup = "", apiVersion = "v1",
resourcePlural = "endpoints")) })
public class CatalogSharedInformerFactory extends SharedInformerFactory {
// TODO: optimization to ease memory pressure from continuous list&watch.
}

View File

@@ -1,132 +0,0 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.discovery;
import io.kubernetes.client.informer.SharedInformer;
import io.kubernetes.client.informer.SharedInformerFactory;
import io.kubernetes.client.informer.cache.Lister;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.models.V1Endpoints;
import io.kubernetes.client.openapi.models.V1EndpointsList;
import io.kubernetes.client.openapi.models.V1Service;
import io.kubernetes.client.openapi.models.V1ServiceList;
import io.kubernetes.client.spring.extended.controller.annotation.GroupVersionResource;
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesInformer;
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesInformers;
import io.kubernetes.client.spring.extended.controller.config.KubernetesInformerAutoConfiguration;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.cloud.CloudPlatform;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.CommonsClientAutoConfiguration;
import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
import org.springframework.cloud.client.ConditionalOnDiscoveryHealthIndicatorEnabled;
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;
import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.PodUtils;
import org.springframework.cloud.kubernetes.commons.discovery.ConditionalOnKubernetesDiscoveryEnabled;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@Configuration(proxyBeanMethods = false)
@ConditionalOnKubernetesDiscoveryEnabled
@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES)
@AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class,
// So that CatalogSharedInformerFactory can be processed in prior to the default
// factory
KubernetesInformerAutoConfiguration.class })
@AutoConfigureAfter({ KubernetesClientAutoConfiguration.class })
@EnableConfigurationProperties(KubernetesDiscoveryProperties.class)
public class KubernetesDiscoveryClientAutoConfiguration {
@ConditionalOnClass({ HealthIndicator.class })
@ConditionalOnDiscoveryEnabled
@ConditionalOnDiscoveryHealthIndicatorEnabled
@Configuration
public static class KubernetesDiscoveryClientHealthIndicatorConfiguration {
@Bean
public KubernetesDiscoveryClientHealthIndicatorInitializer indicatorInitializer(
ApplicationEventPublisher applicationEventPublisher, PodUtils podUtils) {
return new KubernetesDiscoveryClientHealthIndicatorInitializer(podUtils, applicationEventPublisher);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBlockingDiscoveryEnabled
public static class KubernetesInformerDiscoveryConfiguration {
@Bean
@ConditionalOnMissingBean
public SpringCloudKubernetesInformerFactoryProcessor discoveryInformerConfigurer(
KubernetesNamespaceProvider kubernetesNamespaceProvider, ApiClient apiClient,
CatalogSharedInformerFactory sharedInformerFactory, Environment environment) {
// Injecting KubernetesDiscoveryProperties here would cause it to be
// initialize too early
// Instead get the all-namespaces property value from the Environment directly
boolean allNamespaces = environment.getProperty("spring.cloud.kubernetes.discovery.all-namespaces",
Boolean.class, false);
return new SpringCloudKubernetesInformerFactoryProcessor(kubernetesNamespaceProvider, apiClient,
sharedInformerFactory, allNamespaces);
}
@Bean
@ConditionalOnMissingBean
public CatalogSharedInformerFactory catalogSharedInformerFactory(ApiClient apiClient) {
return new CatalogSharedInformerFactory();
}
@Bean
@ConditionalOnMissingBean
public KubernetesInformerDiscoveryClient kubernetesInformerDiscoveryClient(
KubernetesNamespaceProvider kubernetesNamespaceProvider,
CatalogSharedInformerFactory sharedInformerFactory, Lister<V1Service> serviceLister,
Lister<V1Endpoints> endpointsLister, SharedInformer<V1Service> serviceInformer,
SharedInformer<V1Endpoints> endpointsInformer, KubernetesDiscoveryProperties properties) {
return new KubernetesInformerDiscoveryClient(kubernetesNamespaceProvider.getNamespace(),
sharedInformerFactory, serviceLister, endpointsLister, serviceInformer, endpointsInformer,
properties);
}
@KubernetesInformers({
@KubernetesInformer(apiTypeClass = V1Service.class, apiListTypeClass = V1ServiceList.class,
groupVersionResource = @GroupVersionResource(apiGroup = "", apiVersion = "v1",
resourcePlural = "services")),
@KubernetesInformer(apiTypeClass = V1Endpoints.class, apiListTypeClass = V1EndpointsList.class,
groupVersionResource = @GroupVersionResource(apiGroup = "", apiVersion = "v1",
resourcePlural = "endpoints")) })
class CatalogSharedInformerFactory extends SharedInformerFactory {
// TODO: optimization to ease memory pressure from continuous list&watch.
}
}
}

View File

@@ -23,7 +23,7 @@ import org.springframework.context.annotation.Import;
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty("spring.cloud.config.discovery.enabled")
@Import({ KubernetesClientAutoConfiguration.class, KubernetesDiscoveryClientAutoConfiguration.class })
@Import({ KubernetesClientAutoConfiguration.class, KubernetesInformerDiscoveryClientAutoConfiguration.class })
public class KubernetesDiscoveryClientConfigClientBootstrapConfiguration {
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2013-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.discovery;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
/**
* @author wind57
*/
@EnableConfigurationProperties(KubernetesDiscoveryProperties.class)
public class KubernetesDiscoveryPropertiesAutoConfiguration {
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright 2013-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.discovery;
import io.kubernetes.client.informer.SharedInformer;
import io.kubernetes.client.informer.cache.Lister;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.models.V1Endpoints;
import io.kubernetes.client.openapi.models.V1Service;
import io.kubernetes.client.spring.extended.controller.config.KubernetesInformerAutoConfiguration;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.cloud.CloudPlatform;
import org.springframework.cloud.client.CommonsClientAutoConfiguration;
import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
import org.springframework.cloud.client.ConditionalOnDiscoveryHealthIndicatorEnabled;
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;
import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.PodUtils;
import org.springframework.cloud.kubernetes.commons.discovery.ConditionalOnKubernetesDiscoveryEnabled;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* @author wind57
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnKubernetesDiscoveryEnabled
@ConditionalOnBlockingDiscoveryEnabled
@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES)
@AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class,
// So that CatalogSharedInformerFactory can be processed prior to the default
// factory
KubernetesInformerAutoConfiguration.class })
@AutoConfigureAfter({ KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class })
public class KubernetesInformerDiscoveryClientAutoConfiguration {
@Bean
@ConditionalOnClass({ HealthIndicator.class })
@ConditionalOnDiscoveryHealthIndicatorEnabled
public KubernetesDiscoveryClientHealthIndicatorInitializer indicatorInitializer(
ApplicationEventPublisher applicationEventPublisher, PodUtils<?> podUtils) {
return new KubernetesDiscoveryClientHealthIndicatorInitializer(podUtils, applicationEventPublisher);
}
@Bean
@ConditionalOnMissingBean
public KubernetesInformerDiscoveryClient kubernetesInformerDiscoveryClient(
KubernetesNamespaceProvider kubernetesNamespaceProvider, CatalogSharedInformerFactory sharedInformerFactory,
Lister<V1Service> serviceLister, Lister<V1Endpoints> endpointsLister,
SharedInformer<V1Service> serviceInformer, SharedInformer<V1Endpoints> endpointsInformer,
KubernetesDiscoveryProperties properties) {
return new KubernetesInformerDiscoveryClient(kubernetesNamespaceProvider.getNamespace(), sharedInformerFactory,
serviceLister, endpointsLister, serviceInformer, endpointsInformer, properties);
}
@Bean
@ConditionalOnMissingBean
public CatalogSharedInformerFactory catalogSharedInformerFactory() {
return new CatalogSharedInformerFactory();
}
@Bean
@ConditionalOnMissingBean
public SpringCloudKubernetesInformerFactoryProcessor discoveryInformerConfigurer(
KubernetesNamespaceProvider kubernetesNamespaceProvider, ApiClient apiClient,
CatalogSharedInformerFactory sharedInformerFactory, Environment environment) {
// Injecting KubernetesDiscoveryProperties here would cause it to be
// initialized too early.
// Instead, get the all-namespaces property value from the Environment directly
boolean allNamespaces = environment.getProperty("spring.cloud.kubernetes.discovery.all-namespaces",
Boolean.class, false);
return new SpringCloudKubernetesInformerFactoryProcessor(kubernetesNamespaceProvider, apiClient,
sharedInformerFactory, allNamespaces);
}
}

View File

@@ -43,7 +43,7 @@ import org.springframework.core.ResolvableType;
/**
* @author Ryan Baxter
*/
class SpringCloudKubernetesInformerFactoryProcessor extends KubernetesInformerFactoryProcessor {
public class SpringCloudKubernetesInformerFactoryProcessor extends KubernetesInformerFactoryProcessor {
private static final Logger log = LoggerFactory.getLogger(SpringCloudKubernetesInformerFactoryProcessor.class);
@@ -58,7 +58,7 @@ class SpringCloudKubernetesInformerFactoryProcessor extends KubernetesInformerFa
private final KubernetesNamespaceProvider kubernetesNamespaceProvider;
@Autowired
SpringCloudKubernetesInformerFactoryProcessor(KubernetesNamespaceProvider kubernetesNamespaceProvider,
public SpringCloudKubernetesInformerFactoryProcessor(KubernetesNamespaceProvider kubernetesNamespaceProvider,
ApiClient apiClient, SharedInformerFactory sharedInformerFactory, boolean allNamespaces) {
super();
this.apiClient = apiClient;

View File

@@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.cloud.CloudPlatform;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration;
import org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryPropertiesAutoConfiguration;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.discovery.ConditionalOnKubernetesCatalogEnabled;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
@@ -39,13 +40,13 @@ import org.springframework.core.env.Environment;
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnKubernetesCatalogEnabled
@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES)
@AutoConfigureAfter({ KubernetesClientAutoConfiguration.class })
@AutoConfigureAfter({ KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class })
class KubernetesCatalogWatchAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnKubernetesCatalogEnabled
KubernetesCatalogWatch kubernetesCatalogWatch(CoreV1Api coreV1Api, ApiClient apiClient,
KubernetesDiscoveryProperties properties, Environment environment) {
return new KubernetesCatalogWatch(coreV1Api, apiClient, properties,

View File

@@ -36,7 +36,7 @@ import org.springframework.util.Assert;
*/
public class KubernetesInformerReactiveDiscoveryClient implements ReactiveDiscoveryClient {
private KubernetesInformerDiscoveryClient kubernetesDiscoveryClient;
private final KubernetesInformerDiscoveryClient kubernetesDiscoveryClient;
public KubernetesInformerReactiveDiscoveryClient(KubernetesNamespaceProvider kubernetesNamespaceProvider,
SharedInformerFactory sharedInformerFactory, Lister<V1Service> serviceLister,

View File

@@ -19,13 +19,9 @@ package org.springframework.cloud.kubernetes.client.discovery.reactive;
import io.kubernetes.client.informer.SharedInformer;
import io.kubernetes.client.informer.SharedInformerFactory;
import io.kubernetes.client.informer.cache.Lister;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.models.V1Endpoints;
import io.kubernetes.client.openapi.models.V1EndpointsList;
import io.kubernetes.client.openapi.models.V1Service;
import io.kubernetes.client.openapi.models.V1ServiceList;
import io.kubernetes.client.spring.extended.controller.annotation.GroupVersionResource;
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesInformer;
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesInformers;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
@@ -43,12 +39,15 @@ import org.springframework.cloud.client.discovery.health.DiscoveryClientHealthIn
import org.springframework.cloud.client.discovery.health.reactive.ReactiveDiscoveryClientHealthIndicator;
import org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryClientAutoConfiguration;
import org.springframework.cloud.kubernetes.client.KubernetesClientPodUtils;
import org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryClientAutoConfiguration;
import org.springframework.cloud.kubernetes.client.discovery.CatalogSharedInformerFactory;
import org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryPropertiesAutoConfiguration;
import org.springframework.cloud.kubernetes.client.discovery.SpringCloudKubernetesInformerFactoryProcessor;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.discovery.ConditionalOnKubernetesDiscoveryEnabled;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* @author Ryan Baxter
@@ -56,15 +55,28 @@ import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnKubernetesDiscoveryEnabled
@ConditionalOnReactiveDiscoveryEnabled
@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES)
@ConditionalOnKubernetesDiscoveryEnabled
@AutoConfigureBefore({ SimpleReactiveDiscoveryClientAutoConfiguration.class,
ReactiveCommonsClientAutoConfiguration.class })
@AutoConfigureAfter({ ReactiveCompositeDiscoveryClientAutoConfiguration.class,
KubernetesDiscoveryClientAutoConfiguration.class })
KubernetesDiscoveryPropertiesAutoConfiguration.class })
public class KubernetesInformerReactiveDiscoveryClientAutoConfiguration {
@Bean
@ConditionalOnClass(name = "org.springframework.boot.actuate.health.ReactiveHealthIndicator")
@ConditionalOnDiscoveryHealthIndicatorEnabled
public ReactiveDiscoveryClientHealthIndicator kubernetesReactiveDiscoveryClientHealthIndicator(
KubernetesInformerReactiveDiscoveryClient client, DiscoveryClientHealthIndicatorProperties properties,
KubernetesClientPodUtils podUtils) {
ReactiveDiscoveryClientHealthIndicator healthIndicator = new ReactiveDiscoveryClientHealthIndicator(client,
properties);
InstanceRegisteredEvent<?> event = new InstanceRegisteredEvent<>(podUtils.currentPod(), null);
healthIndicator.onApplicationEvent(event);
return healthIndicator;
}
@Bean
@ConditionalOnMissingBean
public KubernetesInformerReactiveDiscoveryClient kubernetesReactiveDiscoveryClient(
@@ -77,29 +89,23 @@ public class KubernetesInformerReactiveDiscoveryClientAutoConfiguration {
}
@Bean
@ConditionalOnClass(name = "org.springframework.boot.actuate.health.ReactiveHealthIndicator")
@ConditionalOnDiscoveryHealthIndicatorEnabled
public ReactiveDiscoveryClientHealthIndicator kubernetesReactiveDiscoveryClientHealthIndicator(
KubernetesInformerReactiveDiscoveryClient client, DiscoveryClientHealthIndicatorProperties properties,
KubernetesClientPodUtils podUtils) {
ReactiveDiscoveryClientHealthIndicator healthIndicator = new ReactiveDiscoveryClientHealthIndicator(client,
properties);
InstanceRegisteredEvent event = new InstanceRegisteredEvent(podUtils.currentPod(), null);
healthIndicator.onApplicationEvent(event);
return healthIndicator;
@ConditionalOnMissingBean
public CatalogSharedInformerFactory catalogSharedInformerFactory() {
return new CatalogSharedInformerFactory();
}
@KubernetesInformers({
@KubernetesInformer(apiTypeClass = V1Service.class, apiListTypeClass = V1ServiceList.class,
groupVersionResource = @GroupVersionResource(apiGroup = "", apiVersion = "v1",
resourcePlural = "services")),
@KubernetesInformer(apiTypeClass = V1Endpoints.class, apiListTypeClass = V1EndpointsList.class,
groupVersionResource = @GroupVersionResource(apiGroup = "", apiVersion = "v1",
resourcePlural = "endpoints")) })
class CatalogSharedInformerFactory extends SharedInformerFactory {
// TODO: optimization to ease memory pressure from continuous list&watch.
@Bean
@ConditionalOnMissingBean
public SpringCloudKubernetesInformerFactoryProcessor discoveryInformerConfigurer(
KubernetesNamespaceProvider kubernetesNamespaceProvider, ApiClient apiClient,
CatalogSharedInformerFactory sharedInformerFactory, Environment environment) {
// Injecting KubernetesDiscoveryProperties here would cause it to be
// initialized too early.
// Instead, get the all-namespaces property value from the Environment directly
boolean allNamespaces = environment.getProperty("spring.cloud.kubernetes.discovery.all-namespaces",
Boolean.class, false);
return new SpringCloudKubernetesInformerFactoryProcessor(kubernetesNamespaceProvider, apiClient,
sharedInformerFactory, allNamespaces);
}
}

View File

@@ -1,3 +1,4 @@
org.springframework.cloud.kubernetes.client.discovery.catalog.KubernetesCatalogWatchAutoConfiguration
org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryClientAutoConfiguration
org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClientAutoConfiguration
org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryPropertiesAutoConfiguration
org.springframework.cloud.kubernetes.client.discovery.reactive.KubernetesInformerReactiveDiscoveryClientAutoConfiguration

View File

@@ -50,7 +50,7 @@ import static org.mockito.Mockito.when;
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty("spring.cloud.config.discovery.enabled")
@Import({ KubernetesClientAutoConfiguration.class, KubernetesDiscoveryClientAutoConfiguration.class })
@Import({ KubernetesClientAutoConfiguration.class, KubernetesInformerDiscoveryClientAutoConfiguration.class })
public class KubernetesDiscoveryClientConfigClientBootstrapConfigurationTests {
private AnnotationConfigApplicationContext context;
@@ -83,13 +83,13 @@ public class KubernetesDiscoveryClientConfigClientBootstrapConfigurationTests {
TestPropertyValues.of(env).applyTo(parent);
parent.register(UtilAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
EnvironmentKnobbler.class, KubernetesCommonsAutoConfiguration.class,
KubernetesClientAutoConfiguration.class, KubernetesDiscoveryClientAutoConfiguration.class,
KubernetesClientAutoConfiguration.class, KubernetesInformerDiscoveryClientAutoConfiguration.class,
DiscoveryClientConfigServiceBootstrapConfiguration.class, ConfigClientProperties.class);
parent.refresh();
this.context = new AnnotationConfigApplicationContext();
this.context.setParent(parent);
this.context.register(PropertyPlaceholderAutoConfiguration.class, KubernetesCommonsAutoConfiguration.class,
KubernetesDiscoveryClientAutoConfiguration.class);
KubernetesInformerDiscoveryClientAutoConfiguration.class);
this.context.refresh();
}

View File

@@ -0,0 +1,220 @@
/*
* Copyright 2013-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.discovery;
import java.io.StringReader;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.util.Config;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
import org.testcontainers.k3s.K3sContainer;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer;
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test various conditionals for
* {@link KubernetesInformerDiscoveryClientAutoConfiguration}
*
* @author wind57
*/
class KubernetesInformerDiscoveryClientAutoConfigurationApplicationContextTests {
private ApplicationContextRunner applicationContextRunner;
private static K3sContainer container;
@AfterAll
static void afterAll() {
container.stop();
}
@Test
void discoveryEnabledDefault() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false");
applicationContextRunner.run(context -> {
assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class);
assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void discoveryEnabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.enabled=true");
applicationContextRunner.run(context -> {
assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class);
assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void discoveryDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.enabled=false");
applicationContextRunner.run(context -> {
assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class);
assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class);
assertThat(context).doesNotHaveBean(CatalogSharedInformerFactory.class);
assertThat(context).doesNotHaveBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void kubernetesDiscoveryEnabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.kubernetes.discovery.enabled=true");
applicationContextRunner.run(context -> {
assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class);
assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void kubernetesDiscoveryDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.kubernetes.discovery.enabled=false");
applicationContextRunner.run(context -> {
assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class);
assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class);
assertThat(context).doesNotHaveBean(CatalogSharedInformerFactory.class);
assertThat(context).doesNotHaveBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void kubernetesDiscoveryBlockingEnabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.blocking.enabled=true");
applicationContextRunner.run(context -> {
assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class);
assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void kubernetesDiscoveryBlockingDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.blocking.enabled=false");
applicationContextRunner.run(context -> {
assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class);
assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class);
assertThat(context).doesNotHaveBean(CatalogSharedInformerFactory.class);
assertThat(context).doesNotHaveBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void kubernetesDiscoveryHealthIndicatorEnabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.client.health-indicator.enabled=true");
applicationContextRunner.run(context -> {
assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class);
assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void kubernetesDiscoveryHealthIndicatorDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.client.health-indicator.enabled=false");
applicationContextRunner.run(context -> {
assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class);
assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void kubernetesDiscoveryHealthIndicatorEnabledHealthIndicatorMissing() {
setupWithFilteredClassLoader(HealthIndicator.class, "spring.main.cloud-platform=KUBERNETES",
"spring.cloud.config.enabled=false", "spring.cloud.discovery.client.health-indicator.enabled=true");
applicationContextRunner.run(context -> {
assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class);
assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
/**
* reactive is disabled and should not impact blocking in any way
*/
@Test
void reactiveDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.reactive.enabled=false");
applicationContextRunner.run(context -> {
assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class);
assertThat(context).hasSingleBean(KubernetesInformerDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
private void setup(String... properties) {
applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(KubernetesInformerDiscoveryClientAutoConfiguration.class,
KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class))
.withUserConfiguration(ApiClientConfig.class).withPropertyValues(properties);
}
private void setupWithFilteredClassLoader(Class<?> cls, String... properties) {
applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(KubernetesInformerDiscoveryClientAutoConfiguration.class,
KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(cls)).withUserConfiguration(ApiClientConfig.class)
.withPropertyValues(properties);
}
@Configuration
static class ApiClientConfig {
@Bean
@Primary
ApiClient apiClient() throws Exception {
container = Commons.container();
container.start();
return Config.fromConfig(new StringReader(container.getKubeConfigYaml()));
}
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright 2013-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.discovery.catalog;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration;
import org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryPropertiesAutoConfiguration;
import org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClient;
import org.springframework.cloud.kubernetes.client.discovery.reactive.KubernetesInformerReactiveDiscoveryClient;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test various conditionals for {@link KubernetesCatalogWatch}
*
* @author wind57
*/
class KubernetesCatalogWatchAutoConfigurationApplicationContextTests {
private ApplicationContextRunner applicationContextRunner;
@Test
void discoveryEnabledDefault() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false");
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(KubernetesCatalogWatch.class));
}
@Test
void discoveryEnabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.enabled=true");
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(KubernetesCatalogWatch.class));
}
@Test
void discoveryDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.enabled=false");
applicationContextRunner.run(context -> assertThat(context).doesNotHaveBean(KubernetesCatalogWatch.class));
}
@Test
void kubernetesDiscoveryEnabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.kubernetes.discovery.enabled=true");
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(KubernetesCatalogWatch.class));
}
// disabling discovery has no impact on the catalog watch.
@Test
void kubernetesDiscoveryDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.kubernetes.discovery.enabled=false");
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(KubernetesCatalogWatch.class));
}
/**
* both blocking and reactive configs are disabled, should not influence catalog
* watcher in any way.
*/
@Test
void disableBlockingAndReactive() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.blocking.enabled=false", "spring.cloud.discovery.reactive.enabled=false");
applicationContextRunner.run(context -> {
assertThat(context).hasSingleBean(KubernetesCatalogWatch.class);
assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class);
assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class);
});
}
/**
* both blocking and reactive configs are disabled, should not influence catalog
* watcher in any way.
*/
@Test
void disableKubernetesDiscovery() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.kubernetes.discovery.enabled=false");
applicationContextRunner.run(context -> {
assertThat(context).hasSingleBean(KubernetesCatalogWatch.class);
assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class);
assertThat(context).doesNotHaveBean(KubernetesInformerDiscoveryClient.class);
});
}
private void setup(String... properties) {
applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(KubernetesCatalogWatchAutoConfiguration.class,
KubernetesClientAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class))
.withPropertyValues(properties);
}
}

View File

@@ -0,0 +1,194 @@
/*
* Copyright 2013-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.client.discovery.reactive;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.cloud.client.discovery.health.reactive.ReactiveDiscoveryClientHealthIndicator;
import org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryClientAutoConfiguration;
import org.springframework.cloud.commons.util.UtilAutoConfiguration;
import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration;
import org.springframework.cloud.kubernetes.client.discovery.CatalogSharedInformerFactory;
import org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryPropertiesAutoConfiguration;
import org.springframework.cloud.kubernetes.client.discovery.SpringCloudKubernetesInformerFactoryProcessor;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test various conditionals for
* {@link KubernetesInformerReactiveDiscoveryClientAutoConfiguration}
*
* @author wind57
*/
class KubernetesInformerReactiveDiscoveryClientAutoConfigurationApplicationContextTests {
private ApplicationContextRunner applicationContextRunner;
@Test
void discoveryEnabledDefault() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false");
applicationContextRunner.run(context -> {
// simple from commons and ours
assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2);
assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void discoveryEnabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.enabled=true");
applicationContextRunner.run(context -> {
// simple from commons and ours
assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2);
assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void discoveryDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.enabled=false");
applicationContextRunner.run(context -> {
// simple from commons and ours
assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class);
assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class);
assertThat(context).doesNotHaveBean(CatalogSharedInformerFactory.class);
assertThat(context).doesNotHaveBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void kubernetesDiscoveryEnabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.kubernetes.discovery.enabled=true");
applicationContextRunner.run(context -> {
// simple from commons and ours
assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2);
assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void kubernetesDiscoveryDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.kubernetes.discovery.enabled=false");
applicationContextRunner.run(context -> {
// only ours as the "simple" one from commons is not picked-up
assertThat(context).hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class);
assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class);
assertThat(context).doesNotHaveBean(CatalogSharedInformerFactory.class);
assertThat(context).doesNotHaveBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void kubernetesReactiveDiscoveryEnabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.reactive.enabled=true");
applicationContextRunner.run(context -> {
// simple from commons and ours
assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2);
assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void kubernetesReactiveDiscoveryDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.reactive.enabled=false");
applicationContextRunner.run(context -> {
assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class);
assertThat(context).doesNotHaveBean(KubernetesInformerReactiveDiscoveryClient.class);
assertThat(context).doesNotHaveBean(CatalogSharedInformerFactory.class);
assertThat(context).doesNotHaveBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
/**
* blocking is disabled, and it should not impact reactive in any way.
*/
@Test
void blockingDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.blocking.enabled=false");
applicationContextRunner.run(context -> {
// simple from commons and ours
assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).size().isEqualTo(2);
assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void healthDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.client.health-indicator.enabled=false");
applicationContextRunner.run(context -> {
// simple from commons
assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class);
assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
@Test
void healthEnabledClassNotPresent() {
setupWithFilteredClassLoader("org.springframework.boot.actuate.health.ReactiveHealthIndicator",
"spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false",
"spring.cloud.discovery.client.health-indicator.enabled=false");
applicationContextRunner.run(context -> {
// simple from commons
assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class);
assertThat(context).hasSingleBean(KubernetesInformerReactiveDiscoveryClient.class);
assertThat(context).hasSingleBean(CatalogSharedInformerFactory.class);
assertThat(context).hasSingleBean(SpringCloudKubernetesInformerFactoryProcessor.class);
});
}
private void setup(String... properties) {
applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
KubernetesInformerReactiveDiscoveryClientAutoConfiguration.class,
KubernetesClientAutoConfiguration.class, SimpleReactiveDiscoveryClientAutoConfiguration.class,
UtilAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class))
.withPropertyValues(properties);
}
private void setupWithFilteredClassLoader(String name, String... properties) {
applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
KubernetesInformerReactiveDiscoveryClientAutoConfiguration.class,
KubernetesClientAutoConfiguration.class, SimpleReactiveDiscoveryClientAutoConfiguration.class,
UtilAutoConfiguration.class, KubernetesDiscoveryPropertiesAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(name)).withPropertyValues(properties);
}
}

View File

@@ -0,0 +1,15 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
<logger name="org.testcontainers" level="INFO"/>
<logger name="com.github.dockerjava" level="WARN"/>
<logger name="io.fabric8.kubernetes.client" level="ERROR"/>
</configuration>

View File

@@ -38,13 +38,13 @@ import org.springframework.core.env.Environment;
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnKubernetesCatalogEnabled
@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES)
@AutoConfigureAfter({ Fabric8AutoConfiguration.class })
public class KubernetesCatalogWatchAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnKubernetesCatalogEnabled
public KubernetesCatalogWatch kubernetesCatalogWatch(KubernetesClient client,
KubernetesDiscoveryProperties properties, Environment environment) {
return new KubernetesCatalogWatch(client, properties, new KubernetesNamespaceProvider(environment));