Pass ApiClient to SharedInformer (#903)

* Pass ApiClient to SharedInformer.  Fixes #885
This commit is contained in:
Ryan Baxter
2021-11-08 10:29:27 -05:00
committed by GitHub
parent 5911a6731d
commit 3436ed5a2c
7 changed files with 54 additions and 40 deletions

View File

@@ -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

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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);

View File

@@ -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

View File

@@ -63,6 +63,31 @@
</build>
<profiles>
<profile>
<id>skaffold</id>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<name>${env.IMAGE}</name>
</image>
<goal>build-image</goal>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>build-image</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>imagename</id>
<activation>

View File

@@ -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