From 3436ed5a2c82ff16a13ea9d0d2c00cfa25041bf7 Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Mon, 8 Nov 2021 10:29:27 -0500 Subject: [PATCH] Pass ApiClient to SharedInformer (#903) * Pass ApiClient to SharedInformer. Fixes #885 --- .../client/KubernetesClientUtils.java | 6 +++++ ...ientEventBasedConfigMapChangeDetector.java | 26 +++++++------------ ...ClientEventBasedSecretsChangeDetector.java | 26 +++++++------------ ...ientConfigReloadAutoConfigurationTest.java | 3 +-- .../CoreTestClientViaSystemProperties.java | 6 ++--- .../pom.xml | 25 ++++++++++++++++++ .../skaffold.yaml | 2 +- 7 files changed, 54 insertions(+), 40 deletions(-) diff --git a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientUtils.java b/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientUtils.java index a48c3e99..8f86e3db 100644 --- a/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientUtils.java +++ b/spring-cloud-kubernetes-client-autoconfig/src/main/java/org/springframework/cloud/kubernetes/client/KubernetesClientUtils.java @@ -31,6 +31,12 @@ public final class KubernetesClientUtils { private KubernetesClientUtils() { } + public static ApiClient createApiClientForInformerClient() { + ApiClient apiClient = kubernetesApiClient(); + apiClient.setReadTimeout(0); + return apiClient; + } + public static ApiClient kubernetesApiClient() { try { // Assume we are running in a cluster diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedConfigMapChangeDetector.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedConfigMapChangeDetector.java index 67126eec..e34d3bef 100644 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedConfigMapChangeDetector.java +++ b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedConfigMapChangeDetector.java @@ -16,20 +16,16 @@ package org.springframework.cloud.kubernetes.client.config.reload; -import java.util.concurrent.TimeUnit; - import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import io.kubernetes.client.informer.ResourceEventHandler; import io.kubernetes.client.informer.SharedIndexInformer; import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.models.V1ConfigMap; import io.kubernetes.client.openapi.models.V1ConfigMapList; import io.kubernetes.client.util.CallGeneratorParams; -import okhttp3.OkHttpClient; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -42,7 +38,7 @@ import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationC import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy; import org.springframework.core.env.ConfigurableEnvironment; -import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.kubernetesApiClient; +import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.createApiClientForInformerClient; /** * @author Ryan Baxter @@ -69,7 +65,7 @@ public class KubernetesClientEventBasedConfigMapChangeDetector extends Configura super(environment, properties, strategy); this.propertySourceLocator = propertySourceLocator; this.coreV1Api = coreV1Api; - this.factory = new SharedInformerFactory(); + this.factory = new SharedInformerFactory(createApiClientForInformerClient()); this.kubernetesClientProperties = kubernetesClientProperties; } @@ -80,7 +76,12 @@ public class KubernetesClientEventBasedConfigMapChangeDetector extends Configura super(environment, properties, strategy); this.propertySourceLocator = propertySourceLocator; this.coreV1Api = coreV1Api; - this.factory = new SharedInformerFactory(); + // We need to pass an APIClient to the SharedInformerFactory because if we use the default + // constructor it will use the configured default APIClient but that may not contain + // an APIClient configured within the cluster and does not contain the necessary + // certificate authorities for the cluster. This results in SSL errors. + // See https://github.com/spring-cloud/spring-cloud-kubernetes/issues/885 + this.factory = new SharedInformerFactory(createApiClientForInformerClient()); this.kubernetesNamespaceProvider = kubernetesNamespaceProvider; } @@ -92,16 +93,7 @@ public class KubernetesClientEventBasedConfigMapChangeDetector extends Configura super(environment, properties, strategy); this.propertySourceLocator = propertySourceLocator; this.kubernetesClientProperties = kubernetesClientProperties; - try { - ApiClient apiClient = kubernetesApiClient(); - OkHttpClient httpClient = apiClient.getHttpClient().newBuilder().readTimeout(0, TimeUnit.SECONDS).build(); - apiClient.setHttpClient(httpClient); - this.coreV1Api = new CoreV1Api(apiClient); - } - catch (Exception e) { - LOG.error("Failed to create Kubernetes API client. Event based ConfigMap monitoring will not work", e); - } - this.factory = new SharedInformerFactory(); + this.factory = new SharedInformerFactory(createApiClientForInformerClient()); } private String getNamespace() { diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedSecretsChangeDetector.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedSecretsChangeDetector.java index 6cc67f12..7d17f865 100644 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedSecretsChangeDetector.java +++ b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientEventBasedSecretsChangeDetector.java @@ -16,19 +16,15 @@ package org.springframework.cloud.kubernetes.client.config.reload; -import java.util.concurrent.TimeUnit; - import javax.annotation.PostConstruct; import io.kubernetes.client.informer.ResourceEventHandler; import io.kubernetes.client.informer.SharedIndexInformer; import io.kubernetes.client.informer.SharedInformerFactory; -import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.models.V1Secret; import io.kubernetes.client.openapi.models.V1SecretList; import io.kubernetes.client.util.CallGeneratorParams; -import okhttp3.OkHttpClient; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -41,7 +37,7 @@ import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationC import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy; import org.springframework.core.env.ConfigurableEnvironment; -import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.kubernetesApiClient; +import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.createApiClientForInformerClient; /** * @author Ryan Baxter @@ -67,7 +63,7 @@ public class KubernetesClientEventBasedSecretsChangeDetector extends Configurati KubernetesClientProperties kubernetesClientProperties) { super(environment, properties, strategy); this.propertySourceLocator = propertySourceLocator; - this.factory = new SharedInformerFactory(); + this.factory = new SharedInformerFactory(createApiClientForInformerClient()); this.coreV1Api = coreV1Api; this.kubernetesClientProperties = kubernetesClientProperties; } @@ -78,7 +74,12 @@ public class KubernetesClientEventBasedSecretsChangeDetector extends Configurati KubernetesNamespaceProvider kubernetesNamespaceProvider) { super(environment, properties, strategy); this.propertySourceLocator = propertySourceLocator; - this.factory = new SharedInformerFactory(); + // We need to pass an APIClient to the SharedInformerFactory because if we use the default + // constructor it will use the configured default APIClient but that may not contain + // an APIClient configured within the cluster and does not contain the necessary + // certificate authorities for the cluster. This results in SSL errors. + // See https://github.com/spring-cloud/spring-cloud-kubernetes/issues/885 + this.factory = new SharedInformerFactory(createApiClientForInformerClient()); this.coreV1Api = coreV1Api; this.kubernetesNamespaceProvider = kubernetesNamespaceProvider; } @@ -90,17 +91,8 @@ public class KubernetesClientEventBasedSecretsChangeDetector extends Configurati KubernetesClientProperties kubernetesClientProperties) { super(environment, properties, strategy); this.propertySourceLocator = propertySourceLocator; - this.factory = new SharedInformerFactory(); + this.factory = new SharedInformerFactory(createApiClientForInformerClient()); this.kubernetesClientProperties = kubernetesClientProperties; - try { - ApiClient apiClient = kubernetesApiClient(); - OkHttpClient httpClient = apiClient.getHttpClient().newBuilder().readTimeout(0, TimeUnit.SECONDS).build(); - apiClient.setHttpClient(httpClient); - this.coreV1Api = new CoreV1Api(apiClient); - } - catch (Exception e) { - LOG.error("Failed to create Kubernetes API client. Event based ConfigMap monitoring will not work", e); - } } private String getNamespace() { diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientConfigReloadAutoConfigurationTest.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientConfigReloadAutoConfigurationTest.java index 8e4ff41e..3bf99275 100644 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientConfigReloadAutoConfigurationTest.java +++ b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload/KubernetesClientConfigReloadAutoConfigurationTest.java @@ -207,15 +207,14 @@ public class KubernetesClientConfigReloadAutoConfigurationTest { return properties; } - @ConditionalOnMissingBean(ApiClient.class) @Bean ApiClient apiClient() { ApiClient apiClient = new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build(); apiClient.setDebugging(true); + apiClient.setReadTimeout(0); return apiClient; } - @ConditionalOnMissingBean(CoreV1Api.class) @Bean CoreV1Api coreApi(ApiClient apiClient) { return new CoreV1Api(apiClient); diff --git a/spring-cloud-kubernetes-fabric8-config/src/test/java/org/springframework/cloud/kubernetes/fabric8/config/CoreTestClientViaSystemProperties.java b/spring-cloud-kubernetes-fabric8-config/src/test/java/org/springframework/cloud/kubernetes/fabric8/config/CoreTestClientViaSystemProperties.java index 93ad572d..115f892b 100644 --- a/spring-cloud-kubernetes-fabric8-config/src/test/java/org/springframework/cloud/kubernetes/fabric8/config/CoreTestClientViaSystemProperties.java +++ b/spring-cloud-kubernetes-fabric8-config/src/test/java/org/springframework/cloud/kubernetes/fabric8/config/CoreTestClientViaSystemProperties.java @@ -30,9 +30,9 @@ import static org.assertj.core.api.Assertions.assertThat; @ExtendWith(SpringExtension.class) @SpringBootTest(classes = TestApplication.class, - properties = { "spring.application.name=testapp", "spring.cloud.kubernetes.client.namespace=testns", - "spring.cloud.kubernetes.client.trustCerts=true", "spring.cloud.kubernetes.config.namespace=testns", - "spring.cloud.kubernetes.secrets.enableApi=true" }) + properties = { "spring.application.name=testapp", "spring.cloud.kubernetes.client.namespace=testns", + "spring.cloud.kubernetes.client.trustCerts=true", "spring.cloud.kubernetes.config.namespace=testns", + "spring.cloud.kubernetes.secrets.enableApi=true" }) public class CoreTestClientViaSystemProperties { @Autowired diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-config-it/pom.xml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-config-it/pom.xml index 2416bdab..8b67034d 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-config-it/pom.xml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-config-it/pom.xml @@ -63,6 +63,31 @@ + + skaffold + + + + org.springframework.boot + spring-boot-maven-plugin + + + ${env.IMAGE} + + build-image + + + + package + + build-image + + + + + + + imagename diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-config-it/skaffold.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-config-it/skaffold.yaml index 27f72f02..8e04873e 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-config-it/skaffold.yaml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-config-it/skaffold.yaml @@ -6,7 +6,7 @@ build: artifacts: - image: springcloud/spring-cloud-kubernetes-client-config-it custom: - buildCommand: "../../mvnw clean install" + buildCommand: "../../mvnw clean install -Pskaffold" dependencies: paths: - src