Refactor Config Module And Add A New Config Module Using Kubernetes Client (#664)
* Deprecate KubernetesAutoServiceRegistration * Document service registry in kubernetes. Fixes #348 * Refactoring config module to extract common code Renamed config module to be specific to fabric8 * Kubernetes client config module * Fixing test to avoid 503 error * Accounting for missing invocation * Adding code to deal with potential 503 error * Fixing class used in polling change listener * Formatting changes
This commit is contained in:
@@ -14,7 +14,7 @@ The link:./spring-cloud-kubernetes-config[Spring Cloud Kubernetes Config] projec
|
||||
during application bootstrapping and triggers hot reloading of beans or Spring context when changes are detected on
|
||||
observed `ConfigMap` instances.
|
||||
|
||||
The default behavior is to create a `ConfigMapPropertySource` based on a Kubernetes `ConfigMap` that has a `metadata.name` value of either the name of
|
||||
The default behavior is to create a `Fabric8ConfigMapPropertySource` based on a Kubernetes `ConfigMap` that has a `metadata.name` value of either the name of
|
||||
your Spring application (as defined by its `spring.application.name` property) or a custom name defined within the
|
||||
`bootstrap.properties` file under the following key: `spring.cloud.kubernetes.config.name`.
|
||||
|
||||
@@ -300,7 +300,7 @@ Kubernetes has the notion of https://kubernetes.io/docs/concepts/configuration/s
|
||||
sensitive data such as passwords, OAuth tokens, and so on. This project provides integration with `Secrets` to make secrets
|
||||
accessible by Spring Boot applications. You can explicitly enable or disable This feature by setting the `spring.cloud.kubernetes.secrets.enabled` property.
|
||||
|
||||
When enabled, the `SecretsPropertySource` looks up Kubernetes for `Secrets` from the following sources:
|
||||
When enabled, the `Fabric8SecretsPropertySource` looks up Kubernetes for `Secrets` from the following sources:
|
||||
|
||||
. Reading recursively from secrets mounts
|
||||
. Named after the application (as defined by `spring.application.name`)
|
||||
|
||||
3
pom.xml
3
pom.xml
@@ -90,8 +90,9 @@
|
||||
<module>spring-cloud-kubernetes-commons</module>
|
||||
<module>spring-cloud-kubernetes-test-support</module>
|
||||
<module>spring-cloud-kubernetes-client-autoconfig</module>
|
||||
<module>spring-cloud-kubernetes-client-config</module>
|
||||
<module>spring-cloud-kubernetes-fabric8-autoconfig</module>
|
||||
<module>spring-cloud-kubernetes-config</module>
|
||||
<module>spring-cloud-kubernetes-fabric8-config</module>
|
||||
<module>spring-cloud-kubernetes-discovery</module>
|
||||
<module>spring-cloud-starter-kubernetes</module>
|
||||
<module>spring-cloud-starter-kubernetes-config</module>
|
||||
|
||||
@@ -20,9 +20,6 @@ import java.io.IOException;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.actuate.autoconfigure.info.ConditionalOnEnabledInfoContributor;
|
||||
@@ -37,6 +34,8 @@ import org.springframework.cloud.kubernetes.commons.PodUtils;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.kubernetesApiClient;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@@ -45,36 +44,11 @@ import org.springframework.context.annotation.Configuration;
|
||||
@AutoConfigureAfter(KubernetesCommonsAutoConfiguration.class)
|
||||
public class KubernetesClientAutoConfiguration {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesClientAutoConfiguration.class);
|
||||
|
||||
private ApiClient kubernetesApiClient() throws IOException {
|
||||
try {
|
||||
// Assume we are running in a cluster
|
||||
ApiClient apiClient = ClientBuilder.cluster().build();
|
||||
io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient);
|
||||
LOG.info("Created API client in the cluster.");
|
||||
return apiClient;
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.info(
|
||||
"Could not create the Kubernetes ApiClient in a cluster environment, trying to use a \"standard\" configuration instead.",
|
||||
e);
|
||||
try {
|
||||
ApiClient apiClient = ClientBuilder.standard().build();
|
||||
io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient);
|
||||
return apiClient;
|
||||
}
|
||||
catch (IOException e1) {
|
||||
LOG.warn("Could not create a Kubernetes ApiClient from either a cluster or standard environment", e1);
|
||||
throw e1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public CoreV1Api coreApi() throws IOException {
|
||||
kubernetesApiClient();
|
||||
ApiClient apiClient = kubernetesApiClient();
|
||||
io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient);
|
||||
return new CoreV1Api();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public final class KubernetesClientUtils {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesClientUtils.class);
|
||||
|
||||
private KubernetesClientUtils() {
|
||||
}
|
||||
|
||||
public static ApiClient kubernetesApiClient() throws IOException {
|
||||
try {
|
||||
// Assume we are running in a cluster
|
||||
ApiClient apiClient = ClientBuilder.cluster().build();
|
||||
LOG.info("Created API client in the cluster.");
|
||||
return apiClient;
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.info(
|
||||
"Could not create the Kubernetes ApiClient in a cluster environment, trying to use a \"standard\" configuration instead.",
|
||||
e);
|
||||
try {
|
||||
ApiClient apiClient = ClientBuilder.standard().build();
|
||||
return apiClient;
|
||||
}
|
||||
catch (IOException e1) {
|
||||
LOG.warn("Could not create a Kubernetes ApiClient from either a cluster or standard environment", e1);
|
||||
throw e1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,19 +22,19 @@ import org.springframework.cloud.kubernetes.client.KubernetesClientPodUtils;
|
||||
import org.springframework.cloud.kubernetes.commons.profile.AbstractKubernetesProfileEnvironmentPostProcessor;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import static io.kubernetes.client.util.Config.ENV_SERVICE_HOST;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
* @author Thomas Vitale
|
||||
*/
|
||||
public class KubernetesClientProfileEnvironmentPostProcessor extends AbstractKubernetesProfileEnvironmentPostProcessor {
|
||||
|
||||
protected static final String KUBERNETES_SERVICE_ENV_VAR = "KUBERNETES_SERVICE_HOST";
|
||||
|
||||
@Override
|
||||
protected boolean isInsideKubernetes(Environment environment) {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
KubernetesClientPodUtils utils = new KubernetesClientPodUtils(api, environment.getProperty(NAMESPACE_PROPERTY));
|
||||
return environment.containsProperty(KUBERNETES_SERVICE_ENV_VAR) || utils.isInsideKubernetes();
|
||||
return environment.containsProperty(ENV_SERVICE_HOST) || utils.isInsideKubernetes();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
91
spring-cloud-kubernetes-client-config/pom.xml
Normal file
91
spring-cloud-kubernetes-client-config/pom.xml
Normal file
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>spring-cloud-kubernetes</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-cloud-kubernetes-client-config</artifactId>
|
||||
|
||||
<properties>
|
||||
<wiremock.version>2.26.3</wiremock.version>
|
||||
</properties>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-client-autoconfig</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.kubernetes</groupId>
|
||||
<artifactId>client-java</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.kubernetes</groupId>
|
||||
<artifactId>client-java-extended</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-actuator</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-rsa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-test-support</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.tomakehurst</groupId>
|
||||
<artifactId>wiremock-jre8</artifactId>
|
||||
<version>${wiremock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration;
|
||||
import org.springframework.cloud.kubernetes.commons.ConditionalOnKubernetesEnabled;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesCommonsAutoConfiguration;
|
||||
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.KubernetesBootstrapConfiguration;
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnKubernetesEnabled
|
||||
@AutoConfigureAfter(KubernetesBootstrapConfiguration.class)
|
||||
public class KubernetesClientBootstrapConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import({ KubernetesCommonsAutoConfiguration.class, KubernetesClientAutoConfiguration.class })
|
||||
protected static class KubernetesPropertySourceConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "spring.cloud.kubernetes.config.enabled", matchIfMissing = true)
|
||||
public KubernetesClientConfigMapPropertySourceLocator configMapPropertySourceLocator(
|
||||
ConfigMapConfigProperties properties, CoreV1Api coreV1Api,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
return new KubernetesClientConfigMapPropertySourceLocator(coreV1Api, properties,
|
||||
kubernetesClientProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "spring.cloud.kubernetes.secrets.enabled", matchIfMissing = true)
|
||||
public KubernetesClientSecretsPropertySourceLocator secretsPropertySourceLocator(
|
||||
SecretsConfigProperties properties, CoreV1Api coreV1Api,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
return new KubernetesClientSecretsPropertySourceLocator(coreV1Api, kubernetesClientProperties, properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class KubernetesClientConfigMapPropertySource extends ConfigMapPropertySource {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesClientConfigMapPropertySource.class);
|
||||
|
||||
public KubernetesClientConfigMapPropertySource(CoreV1Api coreV1Api, String name, String namespace,
|
||||
Environment environment) {
|
||||
super(getName(name, namespace), asObjectMap(getData(coreV1Api, name, namespace, environment)));
|
||||
}
|
||||
|
||||
private static Map<String, Object> getData(CoreV1Api coreV1Api, String name, String namespace,
|
||||
Environment environment) {
|
||||
|
||||
try {
|
||||
List<String> names = new ArrayList<>();
|
||||
names.add(name);
|
||||
if (environment != null) {
|
||||
for (String activeProfile : environment.getActiveProfiles()) {
|
||||
names.add(name + "-" + activeProfile);
|
||||
}
|
||||
}
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
coreV1Api.listNamespacedConfigMap(namespace, null, null, null, null, null, null, null, null, null)
|
||||
.getItems().stream().filter(cm -> names.contains(cm.getMetadata().getName()))
|
||||
.forEach(map -> result.putAll(processAllEntries(map.getData(), environment)));
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (ApiException e) {
|
||||
LOG.warn("Unable to get ConfigMap " + name + " in namespace " + namespace, e);
|
||||
}
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigUtils.getNamespace;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class KubernetesClientConfigMapPropertySourceLocator extends ConfigMapPropertySourceLocator {
|
||||
|
||||
private CoreV1Api coreV1Api;
|
||||
|
||||
private KubernetesClientProperties kubernetesClientProperties;
|
||||
|
||||
public KubernetesClientConfigMapPropertySourceLocator(CoreV1Api coreV1Api, ConfigMapConfigProperties properties,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
super(properties);
|
||||
this.coreV1Api = coreV1Api;
|
||||
this.kubernetesClientProperties = kubernetesClientProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MapPropertySource getMapPropertySource(String name,
|
||||
ConfigMapConfigProperties.NormalizedSource normalizedSource, String configurationTarget,
|
||||
ConfigurableEnvironment environment) {
|
||||
return new KubernetesClientConfigMapPropertySource(coreV1Api, name,
|
||||
getNamespace(normalizedSource, kubernetesClientProperties), environment);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public final class KubernetesClientConfigUtils {
|
||||
|
||||
private KubernetesClientConfigUtils() {
|
||||
}
|
||||
|
||||
public static String getNamespace(ConfigMapConfigProperties.NormalizedSource normalizedSource,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
if (!StringUtils.hasText(normalizedSource.getNamespace())) {
|
||||
return kubernetesClientProperties.getNamespace();
|
||||
}
|
||||
else {
|
||||
return normalizedSource.getNamespace();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getNamespace(SecretsConfigProperties.NormalizedSource normalizedSource,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
if (!StringUtils.hasText(normalizedSource.getNamespace())) {
|
||||
return kubernetesClientProperties.getNamespace();
|
||||
}
|
||||
else {
|
||||
return normalizedSource.getNamespace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1Secret;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class KubernetesClientSecretsPropertySource extends SecretsPropertySource {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesClientSecretsPropertySource.class);
|
||||
|
||||
private CoreV1Api coreV1Api;
|
||||
|
||||
public KubernetesClientSecretsPropertySource(CoreV1Api coreV1Api, String name, String namespace,
|
||||
Environment environment, Map<String, String> labels) {
|
||||
super(getSourceName(name, namespace), getSourceData(coreV1Api, environment, name, namespace, labels));
|
||||
|
||||
}
|
||||
|
||||
private static Map<String, Object> getSourceData(CoreV1Api api, Environment env, String name, String namespace,
|
||||
Map<String, String> labels) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
// Read for secrets api (named)
|
||||
if (StringUtils.hasText(name)) {
|
||||
Optional<V1Secret> secret;
|
||||
if (!StringUtils.hasText(namespace)) {
|
||||
|
||||
// There could technically be more than one, just return the first
|
||||
secret = api.listSecretForAllNamespaces(null, null, null, null, null, null, null, null, null)
|
||||
.getItems().stream().filter(s -> name.equals(s.getMetadata().getName())).findFirst();
|
||||
}
|
||||
else {
|
||||
secret = api.listNamespacedSecret(namespace, null, null, null, null, null, null, null, null, null)
|
||||
.getItems().stream().filter(s -> name.equals(s.getMetadata().getName())).findFirst();
|
||||
}
|
||||
|
||||
secret.ifPresent(s -> putAll(s, result));
|
||||
}
|
||||
|
||||
// Read for secrets api (label)
|
||||
if (labels != null && !labels.isEmpty()) {
|
||||
if (!StringUtils.hasText(namespace)) {
|
||||
api.listSecretForAllNamespaces(null, null, null, createLabelsSelector(labels), null, null, null,
|
||||
null, null).getItems().forEach(s -> putAll(s, result));
|
||||
}
|
||||
else {
|
||||
api.listNamespacedSecret(namespace, null, null, null, null, createLabelsSelector(labels), null,
|
||||
null, null, null).getItems().forEach(s -> putAll(s, result));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.warn("Can't read secret with name: [" + name + "] or labels [" + labels + "] in namespace:[" + namespace
|
||||
+ "] (cause: " + e.getMessage() + "). Ignoring", e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String createLabelsSelector(Map<String, String> labels) {
|
||||
StringBuilder selectorString = new StringBuilder();
|
||||
for (String key : labels.keySet()) {
|
||||
if (selectorString.length() != 0) {
|
||||
selectorString.append(",");
|
||||
}
|
||||
selectorString.append(key + "=" + labels.get(key));
|
||||
}
|
||||
return selectorString.toString();
|
||||
}
|
||||
|
||||
private static void putAll(V1Secret secret, Map<String, Object> result) {
|
||||
Map<String, String> secretData = new HashMap<>();
|
||||
secret.getData().forEach((key, value) -> secretData.put(key, Base64.getEncoder().encodeToString(value)));
|
||||
if (secret != null) {
|
||||
putAll(secretData, result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySourceLocator;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigUtils.getNamespace;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.getApplicationName;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class KubernetesClientSecretsPropertySourceLocator extends SecretsPropertySourceLocator {
|
||||
|
||||
private CoreV1Api coreV1Api;
|
||||
|
||||
private KubernetesClientProperties kubernetesClientProperties;
|
||||
|
||||
public KubernetesClientSecretsPropertySourceLocator(CoreV1Api coreV1Api,
|
||||
KubernetesClientProperties kubernetesClientProperties, SecretsConfigProperties secretsConfigProperties) {
|
||||
super(secretsConfigProperties);
|
||||
this.coreV1Api = coreV1Api;
|
||||
this.kubernetesClientProperties = kubernetesClientProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MapPropertySource getPropertySource(ConfigurableEnvironment environment,
|
||||
SecretsConfigProperties.NormalizedSource normalizedSource, String configurationTarget) {
|
||||
return new KubernetesClientSecretsPropertySource(coreV1Api,
|
||||
getApplicationName(environment, normalizedSource.getName(), configurationTarget),
|
||||
getNamespace(normalizedSource, kubernetesClientProperties), environment, normalizedSource.getLabels());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config.reload;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
|
||||
import org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration;
|
||||
import org.springframework.cloud.context.refresh.ContextRefresher;
|
||||
import org.springframework.cloud.context.restart.RestartEndpoint;
|
||||
import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySource;
|
||||
import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySource;
|
||||
import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.commons.ConditionalOnKubernetesEnabled;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadAutoConfiguration;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.PollingConfigMapChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.PollingSecretsChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.condition.EventReloadDetectionMode;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.condition.PollingReloadDetectionMode;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnKubernetesEnabled
|
||||
@ConditionalOnClass(EndpointAutoConfiguration.class)
|
||||
@AutoConfigureAfter({ InfoEndpointAutoConfiguration.class, RefreshEndpointAutoConfiguration.class,
|
||||
RefreshAutoConfiguration.class, ConfigReloadAutoConfiguration.class })
|
||||
@EnableConfigurationProperties(ConfigReloadProperties.class)
|
||||
public class KubernetesClientConfigReloadAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Configuration reload must be enabled explicitly.
|
||||
*/
|
||||
@ConditionalOnProperty("spring.cloud.kubernetes.reload.enabled")
|
||||
@ConditionalOnClass({ RestartEndpoint.class, ContextRefresher.class })
|
||||
@EnableScheduling
|
||||
@EnableAsync
|
||||
protected static class ConfigReloadAutoConfigurationBeans {
|
||||
|
||||
/**
|
||||
* Polling configMap ConfigurationChangeDetector.
|
||||
* @param properties config reload properties
|
||||
* @param strategy configuration update strategy
|
||||
* @param configMapPropertySourceLocator configMap property source locator
|
||||
* @return a bean that listen to configuration changes and fire a reload.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(KubernetesClientConfigMapPropertySourceLocator.class)
|
||||
@Conditional(PollingReloadDetectionMode.class)
|
||||
public ConfigurationChangeDetector configMapPropertyChangePollingWatcher(ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
KubernetesClientConfigMapPropertySourceLocator configMapPropertySourceLocator,
|
||||
AbstractEnvironment environment) {
|
||||
|
||||
return new PollingConfigMapChangeDetector(environment, properties, strategy,
|
||||
KubernetesClientConfigMapPropertySource.class, configMapPropertySourceLocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Polling secrets ConfigurationChangeDetector.
|
||||
* @param properties config reload properties
|
||||
* @param strategy configuration update strategy
|
||||
* @param secretsPropertySourceLocator secrets property source locator
|
||||
* @return a bean that listen to configuration changes and fire a reload.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(KubernetesClientSecretsPropertySourceLocator.class)
|
||||
@Conditional(PollingReloadDetectionMode.class)
|
||||
public ConfigurationChangeDetector secretsPropertyChangePollingWatcher(ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
KubernetesClientSecretsPropertySourceLocator secretsPropertySourceLocator,
|
||||
AbstractEnvironment environment) {
|
||||
|
||||
return new PollingSecretsChangeDetector(environment, properties, strategy,
|
||||
KubernetesClientSecretsPropertySource.class, secretsPropertySourceLocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Based configMap ConfigurationChangeDetector.
|
||||
* @param properties config reload properties
|
||||
* @param strategy configuration update strategy
|
||||
* @param configMapPropertySourceLocator configMap property source locator
|
||||
* @return a bean that listen to configMap change events and fire a reload.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(KubernetesClientConfigMapPropertySourceLocator.class)
|
||||
@Conditional(EventReloadDetectionMode.class)
|
||||
public ConfigurationChangeDetector configMapPropertyChangeEventWatcher(ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
KubernetesClientConfigMapPropertySourceLocator configMapPropertySourceLocator,
|
||||
AbstractEnvironment environment, CoreV1Api coreV1Api,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
|
||||
return new KubernetesClientEventBasedConfigMapChangeDetector(coreV1Api, environment, properties, strategy,
|
||||
configMapPropertySourceLocator, kubernetesClientProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Based secrets ConfigurationChangeDetector.
|
||||
* @param properties config reload properties
|
||||
* @param strategy configuration update strategy
|
||||
* @param secretsPropertySourceLocator secrets property source locator
|
||||
* @return a bean that listen to secrets change events and fire a reload.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(KubernetesClientSecretsPropertySourceLocator.class)
|
||||
@Conditional(EventReloadDetectionMode.class)
|
||||
public ConfigurationChangeDetector secretsPropertyChangeEventWatcher(ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
KubernetesClientSecretsPropertySourceLocator secretsPropertySourceLocator,
|
||||
AbstractEnvironment environment, CoreV1Api coreV1Api,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
|
||||
return new KubernetesClientEventBasedSecretsChangeDetector(coreV1Api, environment, properties, strategy,
|
||||
secretsPropertySourceLocator, kubernetesClientProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config.reload;
|
||||
|
||||
import java.io.IOException;
|
||||
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;
|
||||
|
||||
import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySource;
|
||||
import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.kubernetesApiClient;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class KubernetesClientEventBasedConfigMapChangeDetector extends ConfigurationChangeDetector {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesClientEventBasedConfigMapChangeDetector.class);
|
||||
|
||||
private CoreV1Api coreV1Api = null;
|
||||
|
||||
private KubernetesClientConfigMapPropertySourceLocator propertySourceLocator;
|
||||
|
||||
private SharedInformerFactory factory;
|
||||
|
||||
private KubernetesClientProperties kubernetesClientProperties;
|
||||
|
||||
public KubernetesClientEventBasedConfigMapChangeDetector(CoreV1Api coreV1Api, ConfigurableEnvironment environment,
|
||||
ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy,
|
||||
KubernetesClientConfigMapPropertySourceLocator propertySourceLocator,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
super(environment, properties, strategy);
|
||||
this.propertySourceLocator = propertySourceLocator;
|
||||
this.coreV1Api = coreV1Api;
|
||||
this.factory = new SharedInformerFactory();
|
||||
this.kubernetesClientProperties = kubernetesClientProperties;
|
||||
}
|
||||
|
||||
public KubernetesClientEventBasedConfigMapChangeDetector(ConfigurableEnvironment environment,
|
||||
ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy,
|
||||
KubernetesClientConfigMapPropertySourceLocator propertySourceLocator,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
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 (IOException e) {
|
||||
LOG.error("Failed to create Kubernetes API client. Event based ConfigMap monitoring will not work", e);
|
||||
}
|
||||
this.factory = new SharedInformerFactory();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void watch() {
|
||||
if (coreV1Api != null && this.properties.isMonitoringConfigMaps()) {
|
||||
SharedIndexInformer<V1ConfigMap> configMapInformer = factory.sharedIndexInformerFor(
|
||||
(CallGeneratorParams params) -> coreV1Api.listNamespacedConfigMapCall(
|
||||
kubernetesClientProperties.getNamespace(), null, null, null, null, null, null,
|
||||
params.resourceVersion, params.timeoutSeconds, params.watch, null),
|
||||
V1ConfigMap.class, V1ConfigMapList.class);
|
||||
configMapInformer.addEventHandler(new ResourceEventHandler<V1ConfigMap>() {
|
||||
@Override
|
||||
public void onAdd(V1ConfigMap obj) {
|
||||
LOG.info("CongifMap " + obj.getMetadata().getName() + " was added.");
|
||||
onEvent(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(V1ConfigMap oldObj, V1ConfigMap newObj) {
|
||||
LOG.info("ConfigMap " + newObj.getMetadata().getName() + " was added.");
|
||||
onEvent(newObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDelete(V1ConfigMap obj, boolean deletedFinalStateUnknown) {
|
||||
LOG.info("ConfigMap " + obj.getMetadata() + " was deleted.");
|
||||
onEvent(obj);
|
||||
}
|
||||
});
|
||||
factory.startAllRegisteredInformers();
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void unwatch() {
|
||||
factory.stopAllRegisteredInformers();
|
||||
}
|
||||
|
||||
private void onEvent(V1ConfigMap configMap) {
|
||||
boolean changed = changed(locateMapPropertySources(this.propertySourceLocator, this.environment),
|
||||
findPropertySources(KubernetesClientConfigMapPropertySource.class));
|
||||
if (changed) {
|
||||
LOG.info("Configuration change detected, reloading properties.");
|
||||
reloadProperties();
|
||||
}
|
||||
else {
|
||||
LOG.warn("Configuration change was not detected.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config.reload;
|
||||
|
||||
import java.io.IOException;
|
||||
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;
|
||||
|
||||
import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySource;
|
||||
import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.kubernetesApiClient;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class KubernetesClientEventBasedSecretsChangeDetector extends ConfigurationChangeDetector {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesClientEventBasedSecretsChangeDetector.class);
|
||||
|
||||
private CoreV1Api coreV1Api;
|
||||
|
||||
private KubernetesClientSecretsPropertySourceLocator propertySourceLocator;
|
||||
|
||||
private SharedInformerFactory factory;
|
||||
|
||||
private KubernetesClientProperties kubernetesClientProperties;
|
||||
|
||||
public KubernetesClientEventBasedSecretsChangeDetector(CoreV1Api coreV1Api, ConfigurableEnvironment environment,
|
||||
ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy,
|
||||
KubernetesClientSecretsPropertySourceLocator propertySourceLocator,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
super(environment, properties, strategy);
|
||||
this.propertySourceLocator = propertySourceLocator;
|
||||
this.factory = new SharedInformerFactory();
|
||||
this.coreV1Api = coreV1Api;
|
||||
this.kubernetesClientProperties = kubernetesClientProperties;
|
||||
}
|
||||
|
||||
public KubernetesClientEventBasedSecretsChangeDetector(ConfigurableEnvironment environment,
|
||||
ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy,
|
||||
KubernetesClientSecretsPropertySourceLocator propertySourceLocator,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
super(environment, properties, strategy);
|
||||
this.propertySourceLocator = propertySourceLocator;
|
||||
this.factory = new SharedInformerFactory();
|
||||
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 (IOException e) {
|
||||
LOG.error("Failed to create Kubernetes API client. Event based ConfigMap monitoring will not work", e);
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void watch() {
|
||||
if (coreV1Api != null && this.properties.isMonitoringSecrets()) {
|
||||
SharedIndexInformer<V1Secret> configMapInformer = factory.sharedIndexInformerFor(
|
||||
(CallGeneratorParams params) -> coreV1Api.listNamespacedSecretCall(
|
||||
kubernetesClientProperties.getNamespace(), null, null, null, null, null, null,
|
||||
params.resourceVersion, params.timeoutSeconds, params.watch, null),
|
||||
V1Secret.class, V1SecretList.class);
|
||||
configMapInformer.addEventHandler(new ResourceEventHandler<V1Secret>() {
|
||||
@Override
|
||||
public void onAdd(V1Secret obj) {
|
||||
LOG.info("Secret " + obj.getMetadata().getName() + " was added.");
|
||||
onEvent(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(V1Secret oldObj, V1Secret newObj) {
|
||||
LOG.info("Secret " + newObj.getMetadata().getName() + " was added.");
|
||||
onEvent(newObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDelete(V1Secret obj, boolean deletedFinalStateUnknown) {
|
||||
LOG.info("Secret " + obj.getMetadata() + " was deleted.");
|
||||
onEvent(obj);
|
||||
}
|
||||
});
|
||||
factory.startAllRegisteredInformers();
|
||||
}
|
||||
}
|
||||
|
||||
private void onEvent(V1Secret secret) {
|
||||
boolean changed = changed(locateMapPropertySources(this.propertySourceLocator, this.environment),
|
||||
findPropertySources(KubernetesClientSecretsPropertySource.class));
|
||||
if (changed) {
|
||||
this.log.info("Detected change in secrets");
|
||||
reloadProperties();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.kubernetes.client.config.reload.KubernetesClientConfigReloadAutoConfiguration
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.kubernetes.client.config.KubernetesClientBootstrapConfiguration
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.openapi.Configuration;
|
||||
import io.kubernetes.client.openapi.JSON;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMapBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMapList;
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
class KubernetesClientConfigMapPropertySourceLocatorTests {
|
||||
|
||||
private static final V1ConfigMapList PROPERTIES_CONFIGMAP_LIST = new V1ConfigMapList()
|
||||
.addItemsItem(
|
||||
new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("bootstrap-640").withNamespace("default")
|
||||
.withResourceVersion("1").build())
|
||||
.addToData("application.properties",
|
||||
"spring.cloud.kubernetes.configuration.watcher.refreshDelay=0\n"
|
||||
+ "logging.level.org.springframework.cloud.kubernetes=TRACE")
|
||||
.build());
|
||||
|
||||
private static final String API = "/api/v1/namespaces/default/configmaps";
|
||||
|
||||
private static WireMockServer wireMockServer;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
wireMockServer = new WireMockServer(options().dynamicPort());
|
||||
|
||||
wireMockServer.start();
|
||||
WireMock.configureFor("localhost", wireMockServer.port());
|
||||
|
||||
ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build();
|
||||
client.setDebugging(true);
|
||||
Configuration.setDefaultApiClient(client);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
wireMockServer.stop();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() {
|
||||
WireMock.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
void locateWithoutSources() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API)
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST))));
|
||||
ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties();
|
||||
configMapConfigProperties.setName("bootstrap-640");
|
||||
KubernetesClientProperties kubernetesClientProperties = new KubernetesClientProperties();
|
||||
kubernetesClientProperties.setNamespace("default");
|
||||
PropertySource propertySource = new KubernetesClientConfigMapPropertySourceLocator(api,
|
||||
configMapConfigProperties, kubernetesClientProperties).locate(new MockEnvironment());
|
||||
assertThat(propertySource.containsProperty("spring.cloud.kubernetes.configuration.watcher.refreshDelay"))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void locateWithSources() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API)
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST))));
|
||||
ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties();
|
||||
configMapConfigProperties.setName("fake-name");
|
||||
ConfigMapConfigProperties.Source source1 = new ConfigMapConfigProperties.Source();
|
||||
source1.setName("bootstrap-640");
|
||||
source1.setNamespace("default");
|
||||
List<ConfigMapConfigProperties.Source> sources = new ArrayList<>();
|
||||
sources.add(source1);
|
||||
configMapConfigProperties.setSources(sources);
|
||||
KubernetesClientProperties kubernetesClientProperties = new KubernetesClientProperties();
|
||||
kubernetesClientProperties.setNamespace("dev");
|
||||
PropertySource propertySource = new KubernetesClientConfigMapPropertySourceLocator(api,
|
||||
configMapConfigProperties, kubernetesClientProperties).locate(new MockEnvironment());
|
||||
assertThat(propertySource.containsProperty("spring.cloud.kubernetes.configuration.watcher.refreshDelay"))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.openapi.Configuration;
|
||||
import io.kubernetes.client.openapi.JSON;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMapBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMapList;
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
class KubernetesClientConfigMapPropertySourceTests {
|
||||
|
||||
private static final V1ConfigMapList PROPERTIES_CONFIGMAP_LIST = new V1ConfigMapList()
|
||||
.addItemsItem(
|
||||
new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("bootstrap-640").withNamespace("default")
|
||||
.withResourceVersion("1").build())
|
||||
.addToData("application.properties",
|
||||
"spring.cloud.kubernetes.configuration.watcher.refreshDelay=0\n"
|
||||
+ "logging.level.org.springframework.cloud.kubernetes=TRACE")
|
||||
.build());
|
||||
|
||||
private static final V1ConfigMapList YAML_CONFIGMAP_LIST = new V1ConfigMapList()
|
||||
.addItemsItem(new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("bootstrap-641").withNamespace("default")
|
||||
.withResourceVersion("1").build())
|
||||
.addToData("application.yaml",
|
||||
"dummy:\n property:\n string2: \"a\"\n int2: 1\n bool2: true\n")
|
||||
.build());
|
||||
|
||||
private static final String API = "/api/v1/namespaces/default/configmaps";
|
||||
|
||||
private static WireMockServer wireMockServer;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
wireMockServer = new WireMockServer(options().dynamicPort());
|
||||
|
||||
wireMockServer.start();
|
||||
WireMock.configureFor("localhost", wireMockServer.port());
|
||||
|
||||
ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build();
|
||||
client.setDebugging(true);
|
||||
Configuration.setDefaultApiClient(client);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
wireMockServer.stop();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() {
|
||||
WireMock.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertiesFile() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API)
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST))));
|
||||
KubernetesClientConfigMapPropertySource propertySource = new KubernetesClientConfigMapPropertySource(api,
|
||||
"bootstrap-640", "default", new MockEnvironment());
|
||||
verify(getRequestedFor(urlEqualTo(API)));
|
||||
assertThat(propertySource.containsProperty("spring.cloud.kubernetes.configuration.watcher.refreshDelay"))
|
||||
.isTrue();
|
||||
assertThat(propertySource.getProperty("spring.cloud.kubernetes.configuration.watcher.refreshDelay"))
|
||||
.isEqualTo("0");
|
||||
assertThat(propertySource.containsProperty("logging.level.org.springframework.cloud.kubernetes")).isTrue();
|
||||
assertThat(propertySource.getProperty("logging.level.org.springframework.cloud.kubernetes")).isEqualTo("TRACE");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void yamlFile() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(YAML_CONFIGMAP_LIST))));
|
||||
KubernetesClientConfigMapPropertySource propertySource = new KubernetesClientConfigMapPropertySource(api,
|
||||
"bootstrap-641", "default", new MockEnvironment());
|
||||
verify(getRequestedFor(urlEqualTo(API)));
|
||||
assertThat(propertySource.containsProperty("dummy.property.string2")).isTrue();
|
||||
assertThat(propertySource.getProperty("dummy.property.string2")).isEqualTo("a");
|
||||
assertThat(propertySource.containsProperty("dummy.property.int2")).isTrue();
|
||||
assertThat(propertySource.getProperty("dummy.property.int2")).isEqualTo(1);
|
||||
assertThat(propertySource.containsProperty("dummy.property.bool2")).isTrue();
|
||||
assertThat(propertySource.getProperty("dummy.property.bool2")).isEqualTo(true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.openapi.Configuration;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
class KubernetesClientSecretsPropertySourceLocatorTests {
|
||||
|
||||
private static final String LIST_API = "/api/v1/secrets";
|
||||
|
||||
private static final String LIST_API_WITH_LABEL = "/api/v1/secrets?labelSelector=spring.cloud.kubernetes.secret%3Dtrue";
|
||||
|
||||
private static final String LIST_BODY = "{\n" + "\t\"kind\": \"SecretList\",\n" + "\t\"apiVersion\": \"v1\",\n"
|
||||
+ "\t\"metadata\": {\n" + "\t\t\"selfLink\": \"/api/v1/secrets\",\n"
|
||||
+ "\t\t\"resourceVersion\": \"163035\"\n" + "\t},\n" + "\t\"items\": [{\n" + "\t\t\t\"metadata\": {\n"
|
||||
+ "\t\t\t\t\"name\": \"db-secret\",\n" + "\t\t\t\t\"namespace\": \"default\",\n"
|
||||
+ "\t\t\t\t\"selfLink\": \"/api/v1/namespaces/default/secrets/db-secret\",\n"
|
||||
+ "\t\t\t\t\"uid\": \"59ba8e6a-a2d4-416c-b016-22597c193f23\",\n"
|
||||
+ "\t\t\t\t\"resourceVersion\": \"1462\",\n" + "\t\t\t\t\"creationTimestamp\": \"2020-10-28T14:45:02Z\",\n"
|
||||
+ "\t\t\t\t\"labels\": {\n" + "\t\t\t\t\t\"spring.cloud.kubernetes.secret\": \"true\"\n" + "\t\t\t\t}\n"
|
||||
+ "\t\t\t},\n" + "\t\t\t\"data\": {\n" + "\t\t\t\t\"password\": \"cDQ1NXcwcmQ=\",\n"
|
||||
+ "\t\t\t\t\"username\": \"dXNlcg==\"\n" + "\t\t\t},\n" + "\t\t\t\"type\": \"Opaque\"\n" + "\t\t},\n"
|
||||
+ "\t\t{\n" + "\t\t\t\"metadata\": {\n" + "\t\t\t\t\"name\": \"rabbit-password\",\n"
|
||||
+ "\t\t\t\t\"namespace\": \"default\",\n"
|
||||
+ "\t\t\t\t\"selfLink\": \"/api/v1/namespaces/default/secrets/rabbit-password\",\n"
|
||||
+ "\t\t\t\t\"uid\": \"bc211cb4-e7ff-4556-b26e-c54911301740\",\n"
|
||||
+ "\t\t\t\t\"resourceVersion\": \"162708\",\n"
|
||||
+ "\t\t\t\t\"creationTimestamp\": \"2020-10-29T19:47:36Z\",\n" + "\t\t\t\t\"labels\": {\n"
|
||||
+ "\t\t\t\t\t\"spring.cloud.kubernetes.secret\": \"true\"\n" + "\t\t\t\t},\n"
|
||||
+ "\t\t\t\t\"annotations\": {\n"
|
||||
+ "\t\t\t\t\t\"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"data\\\":{\\\"spring.rabbitmq.password\\\":\\\"password\\\"},\\\"kind\\\":\\\"Secret\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"spring.cloud.kubernetes.secret\\\":\\\"true\\\"},\\\"name\\\":\\\"rabbit-password\\\",\\\"namespace\\\":\\\"default\\\"},\\\"type\\\":\\\"Opaque\\\"}\\n\"\n"
|
||||
+ "\t\t\t\t}\n" + "\t\t\t},\n" + "\t\t\t\"data\": {\n"
|
||||
+ "\t\t\t\t\"spring.rabbitmq.password\": \"cGFzc3dvcmQ=\"\n" + "\t\t\t},\n" + "\t\t\t\"type\": \"Opaque\"\n"
|
||||
+ "\t\t}\n" + "\t]\n" + "}";
|
||||
|
||||
private static WireMockServer wireMockServer;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
wireMockServer = new WireMockServer(options().dynamicPort());
|
||||
|
||||
wireMockServer.start();
|
||||
WireMock.configureFor("localhost", wireMockServer.port());
|
||||
|
||||
ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build();
|
||||
client.setDebugging(true);
|
||||
Configuration.setDefaultApiClient(client);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
wireMockServer.stop();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() {
|
||||
WireMock.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLocateWithSources() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(LIST_API).willReturn(aResponse().withStatus(200).withBody(LIST_BODY)));
|
||||
SecretsConfigProperties secretsConfigProperties = new SecretsConfigProperties();
|
||||
SecretsConfigProperties.Source source1 = new SecretsConfigProperties.Source();
|
||||
source1.setName("db-secret");
|
||||
source1.setNamespace("");
|
||||
SecretsConfigProperties.Source source2 = new SecretsConfigProperties.Source();
|
||||
source2.setName("rabbit-password");
|
||||
source2.setNamespace("");
|
||||
List<SecretsConfigProperties.Source> sources = new ArrayList<>();
|
||||
sources.add(source1);
|
||||
sources.add(source2);
|
||||
secretsConfigProperties.setName("app");
|
||||
secretsConfigProperties.setNamespace("");
|
||||
secretsConfigProperties.setSources(sources);
|
||||
secretsConfigProperties.setEnableApi(true);
|
||||
PropertySource propertySource = new KubernetesClientSecretsPropertySourceLocator(api,
|
||||
new KubernetesClientProperties(), secretsConfigProperties).locate(new MockEnvironment());
|
||||
assertThat(propertySource.containsProperty("password")).isTrue();
|
||||
assertThat(propertySource.getProperty("password")).isEqualTo("p455w0rd");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLocateWithOutSources() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(LIST_API).willReturn(aResponse().withStatus(200).withBody(LIST_BODY)));
|
||||
SecretsConfigProperties secretsConfigProperties = new SecretsConfigProperties();
|
||||
secretsConfigProperties.setName("db-secret");
|
||||
secretsConfigProperties.setNamespace("");
|
||||
secretsConfigProperties.setEnableApi(true);
|
||||
PropertySource propertySource = new KubernetesClientSecretsPropertySourceLocator(api,
|
||||
new KubernetesClientProperties(), secretsConfigProperties).locate(new MockEnvironment());
|
||||
assertThat(propertySource.containsProperty("password")).isTrue();
|
||||
assertThat(propertySource.getProperty("password")).isEqualTo("p455w0rd");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.openapi.Configuration;
|
||||
import io.kubernetes.client.openapi.JSON;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1SecretBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1SecretList;
|
||||
import io.kubernetes.client.openapi.models.V1SecretListBuilder;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
class KubernetesClientSecretsPropertySourceTests {
|
||||
|
||||
private static final String API = "/api/v1/namespaces/default/secrets";
|
||||
|
||||
private static final V1SecretList SECRET_LIST = new V1SecretListBuilder().addToItems(new V1SecretBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("db-secret").withResourceVersion("0")
|
||||
.withNamespace("default").build())
|
||||
.addToData("password", "p455w0rd".getBytes()).addToData("username", "user".getBytes()).build()).build();
|
||||
|
||||
private static final String LIST_API = "/api/v1/secrets";
|
||||
|
||||
private static final String LIST_API_WITH_LABEL = "/api/v1/secrets?labelSelector=spring.cloud.kubernetes.secret%3Dtrue";
|
||||
|
||||
private static final String LIST_BODY = "{\n" + "\t\"kind\": \"SecretList\",\n" + "\t\"apiVersion\": \"v1\",\n"
|
||||
+ "\t\"metadata\": {\n" + "\t\t\"selfLink\": \"/api/v1/secrets\",\n"
|
||||
+ "\t\t\"resourceVersion\": \"163035\"\n" + "\t},\n" + "\t\"items\": [{\n" + "\t\t\t\"metadata\": {\n"
|
||||
+ "\t\t\t\t\"name\": \"db-secret\",\n" + "\t\t\t\t\"namespace\": \"default\",\n"
|
||||
+ "\t\t\t\t\"selfLink\": \"/api/v1/namespaces/default/secrets/db-secret\",\n"
|
||||
+ "\t\t\t\t\"uid\": \"59ba8e6a-a2d4-416c-b016-22597c193f23\",\n"
|
||||
+ "\t\t\t\t\"resourceVersion\": \"1462\",\n" + "\t\t\t\t\"creationTimestamp\": \"2020-10-28T14:45:02Z\",\n"
|
||||
+ "\t\t\t\t\"labels\": {\n" + "\t\t\t\t\t\"spring.cloud.kubernetes.secret\": \"true\"\n" + "\t\t\t\t}\n"
|
||||
+ "\t\t\t},\n" + "\t\t\t\"data\": {\n" + "\t\t\t\t\"password\": \"cDQ1NXcwcmQ=\",\n"
|
||||
+ "\t\t\t\t\"username\": \"dXNlcg==\"\n" + "\t\t\t},\n" + "\t\t\t\"type\": \"Opaque\"\n" + "\t\t},\n"
|
||||
+ "\t\t{\n" + "\t\t\t\"metadata\": {\n" + "\t\t\t\t\"name\": \"rabbit-password\",\n"
|
||||
+ "\t\t\t\t\"namespace\": \"default\",\n"
|
||||
+ "\t\t\t\t\"selfLink\": \"/api/v1/namespaces/default/secrets/rabbit-password\",\n"
|
||||
+ "\t\t\t\t\"uid\": \"bc211cb4-e7ff-4556-b26e-c54911301740\",\n"
|
||||
+ "\t\t\t\t\"resourceVersion\": \"162708\",\n"
|
||||
+ "\t\t\t\t\"creationTimestamp\": \"2020-10-29T19:47:36Z\",\n" + "\t\t\t\t\"labels\": {\n"
|
||||
+ "\t\t\t\t\t\"spring.cloud.kubernetes.secret\": \"true\"\n" + "\t\t\t\t},\n"
|
||||
+ "\t\t\t\t\"annotations\": {\n"
|
||||
+ "\t\t\t\t\t\"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"data\\\":{\\\"spring.rabbitmq.password\\\":\\\"password\\\"},\\\"kind\\\":\\\"Secret\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"spring.cloud.kubernetes.secret\\\":\\\"true\\\"},\\\"name\\\":\\\"rabbit-password\\\",\\\"namespace\\\":\\\"default\\\"},\\\"type\\\":\\\"Opaque\\\"}\\n\"\n"
|
||||
+ "\t\t\t\t}\n" + "\t\t\t},\n" + "\t\t\t\"data\": {\n"
|
||||
+ "\t\t\t\t\"spring.rabbitmq.password\": \"cGFzc3dvcmQ=\"\n" + "\t\t\t},\n" + "\t\t\t\"type\": \"Opaque\"\n"
|
||||
+ "\t\t}\n" + "\t]\n" + "}";
|
||||
|
||||
private static WireMockServer wireMockServer;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
wireMockServer = new WireMockServer(options().dynamicPort());
|
||||
|
||||
wireMockServer.start();
|
||||
WireMock.configureFor("localhost", wireMockServer.port());
|
||||
|
||||
ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build();
|
||||
client.setDebugging(true);
|
||||
Configuration.setDefaultApiClient(client);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
wireMockServer.stop();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() {
|
||||
WireMock.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void secretsTest() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(SECRET_LIST))));
|
||||
KubernetesClientSecretsPropertySource propertySource = new KubernetesClientSecretsPropertySource(api,
|
||||
"db-secret", "default", new MockEnvironment(), new HashMap<>());
|
||||
assertThat(propertySource.containsProperty("password")).isTrue();
|
||||
assertThat(propertySource.getProperty("password")).isEqualTo("p455w0rd");
|
||||
assertThat(propertySource.containsProperty("username")).isTrue();
|
||||
assertThat(propertySource.getProperty("username")).isEqualTo("user");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void secretsNullNamespaceTest() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(LIST_API).willReturn(aResponse().withStatus(200).withBody(LIST_BODY)));
|
||||
KubernetesClientSecretsPropertySource propertySource = new KubernetesClientSecretsPropertySource(api,
|
||||
"db-secret", null, new MockEnvironment(), new HashMap<>());
|
||||
assertThat(propertySource.containsProperty("password")).isTrue();
|
||||
assertThat(propertySource.getProperty("password")).isEqualTo("p455w0rd");
|
||||
assertThat(propertySource.containsProperty("username")).isTrue();
|
||||
assertThat(propertySource.getProperty("username")).isEqualTo("user");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void secretLabelsTest() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(LIST_API_WITH_LABEL).willReturn(aResponse().withStatus(200).withBody(LIST_BODY)));
|
||||
Map<String, String> labels = new HashMap<>();
|
||||
labels.put("spring.cloud.kubernetes.secret", "true");
|
||||
KubernetesClientSecretsPropertySource propertySource = new KubernetesClientSecretsPropertySource(api, null,
|
||||
null, new MockEnvironment(), labels);
|
||||
assertThat(propertySource.containsProperty("spring.rabbitmq.password")).isTrue();
|
||||
assertThat(propertySource.getProperty("spring.rabbitmq.password")).isEqualTo("password");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config.reload;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import com.google.gson.Gson;
|
||||
import io.kubernetes.client.informer.EventType;
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.openapi.JSON;
|
||||
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.openapi.models.V1ListMeta;
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import io.kubernetes.client.util.Watch;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySource;
|
||||
import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.mock.env.MockPropertySource;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.mockito.Mockito.atLeast;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
class KubernetesClientEventBasedConfigMapChangeDetectorTests {
|
||||
|
||||
private static WireMockServer wireMockServer;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
wireMockServer = new WireMockServer(options().dynamicPort());
|
||||
wireMockServer.start();
|
||||
WireMock.configureFor("localhost", wireMockServer.port());
|
||||
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
wireMockServer.stop();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() {
|
||||
WireMock.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
void watch() throws Exception {
|
||||
Map<String, String> data = new HashMap<>();
|
||||
data.put("application.properties", "spring.cloud.kubernetes.configuration.watcher.refreshDelay=0\n"
|
||||
+ "logging.level.org.springframework.cloud.kubernetes=TRACE");
|
||||
Map<String, String> updateData = new HashMap<>();
|
||||
updateData.put("application.properties", "spring.cloud.kubernetes.configuration.watcher.refreshDelay=1\n"
|
||||
+ "logging.level.org.springframework.cloud.kubernetes=TRACE");
|
||||
V1ConfigMap applicationConfig = new V1ConfigMap().kind("ConfigMap")
|
||||
.metadata(new V1ObjectMeta().namespace("default").name("bar1")).data(data);
|
||||
V1ConfigMapList configMapList = new V1ConfigMapList().metadata(new V1ListMeta().resourceVersion("0"))
|
||||
.items(Arrays.asList(applicationConfig));
|
||||
stubFor(get(urlMatching("^/api/v1/namespaces/default/configmaps.*")).inScenario("watch")
|
||||
.whenScenarioStateIs(STARTED).withQueryParam("watch", equalTo("false"))
|
||||
.willReturn(aResponse().withStatus(200).withBody(new Gson().toJson(configMapList)))
|
||||
.willSetStateTo("update"));
|
||||
|
||||
Watch.Response<V1ConfigMap> watchResponse = new Watch.Response<>(EventType.MODIFIED.name(), new V1ConfigMap()
|
||||
.kind("ConfigMap").metadata(new V1ObjectMeta().namespace("default").name("bar1")).data(updateData));
|
||||
stubFor(get(urlMatching("^/api/v1/namespaces/default/configmaps.*")).inScenario("watch")
|
||||
.whenScenarioStateIs("update").withQueryParam("watch", equalTo("true"))
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(watchResponse)))
|
||||
.willSetStateTo("add"));
|
||||
|
||||
stubFor(get(urlMatching("^/api/v1/namespaces/default/configmaps.*")).inScenario("watch")
|
||||
.whenScenarioStateIs("add").withQueryParam("watch", equalTo("true"))
|
||||
.willReturn(aResponse().withStatus(200)
|
||||
.withBody(new JSON().serialize(new Watch.Response<>(EventType.ADDED.name(),
|
||||
new V1ConfigMap().kind("ConfigMap")
|
||||
.metadata(new V1ObjectMeta().namespace("default").name("bar3"))
|
||||
.putDataItem("application.properties", "debug=true")))))
|
||||
.willSetStateTo("delete"));
|
||||
|
||||
stubFor(get(urlMatching("^/api/v1/namespaces/default/configmaps.*")).inScenario("watch")
|
||||
.whenScenarioStateIs("delete").withQueryParam("watch", equalTo("true"))
|
||||
.willReturn(aResponse().withStatus(200)
|
||||
.withBody(new JSON().serialize(new Watch.Response<>(EventType.DELETED.name(),
|
||||
new V1ConfigMap().kind("ConfigMap")
|
||||
.metadata(new V1ObjectMeta().namespace("default").name("bar1"))
|
||||
.putDataItem("application.properties", "debug=true")))))
|
||||
.willSetStateTo("done"));
|
||||
|
||||
stubFor(get(urlMatching("^/api/v1/namespaces/default/configmaps.*")).inScenario("watch")
|
||||
.whenScenarioStateIs("done").withQueryParam("watch", equalTo("true"))
|
||||
.willReturn(aResponse().withStatus(200)));
|
||||
ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build();
|
||||
OkHttpClient httpClient = apiClient.getHttpClient().newBuilder().readTimeout(0, TimeUnit.SECONDS).build();
|
||||
apiClient.setHttpClient(httpClient);
|
||||
CoreV1Api coreV1Api = new CoreV1Api(apiClient);
|
||||
ConfigurationUpdateStrategy strategy = mock(ConfigurationUpdateStrategy.class);
|
||||
when(strategy.getName()).thenReturn("strategy");
|
||||
KubernetesMockEnvironment environment = new KubernetesMockEnvironment(
|
||||
mock(KubernetesClientConfigMapPropertySource.class)).withProperty("debug", "true");
|
||||
KubernetesClientConfigMapPropertySourceLocator locator = mock(
|
||||
KubernetesClientConfigMapPropertySourceLocator.class);
|
||||
when(locator.locate(environment)).thenReturn(new MockPropertySource().withProperty("debug", "false"));
|
||||
KubernetesClientProperties kubernetesClientProperties = new KubernetesClientProperties();
|
||||
kubernetesClientProperties.setNamespace("default");
|
||||
KubernetesClientEventBasedConfigMapChangeDetector changeDetector = new KubernetesClientEventBasedConfigMapChangeDetector(
|
||||
coreV1Api, environment, new ConfigReloadProperties(), strategy, locator, kubernetesClientProperties);
|
||||
|
||||
Thread controllerThread = new Thread(changeDetector::watch);
|
||||
controllerThread.setDaemon(true);
|
||||
controllerThread.start();
|
||||
await().timeout(Duration.ofSeconds(5))
|
||||
.until(() -> Mockito.mockingDetails(strategy).getInvocations().size() > 4);
|
||||
verify(strategy, atLeast(3)).reload();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config.reload;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import com.google.gson.Gson;
|
||||
import io.kubernetes.client.informer.EventType;
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.openapi.JSON;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1ListMeta;
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
||||
import io.kubernetes.client.openapi.models.V1Secret;
|
||||
import io.kubernetes.client.openapi.models.V1SecretList;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import io.kubernetes.client.util.Watch;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySource;
|
||||
import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.mock.env.MockPropertySource;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.mockito.Mockito.atLeast;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
class KubernetesClientEventBasedSecretsChangeDetectorTests {
|
||||
|
||||
private static WireMockServer wireMockServer;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
wireMockServer = new WireMockServer(options().dynamicPort());
|
||||
wireMockServer.start();
|
||||
WireMock.configureFor("localhost", wireMockServer.port());
|
||||
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
wireMockServer.stop();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() {
|
||||
WireMock.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
void watch() {
|
||||
|
||||
V1Secret dbPassword = new V1Secret().kind("Secret").metadata(new V1ObjectMeta().name("db-password"))
|
||||
.putStringDataItem("password", Base64.getEncoder().encodeToString("p455w0rd".getBytes()))
|
||||
.putStringDataItem("username", Base64.getEncoder().encodeToString("user".getBytes()));
|
||||
V1Secret dbPasswordUpdated = new V1Secret().kind("Secret").metadata(new V1ObjectMeta().name("db-password"))
|
||||
.putStringDataItem("password", Base64.getEncoder().encodeToString("p455w0rd2".getBytes()))
|
||||
.putStringDataItem("username", Base64.getEncoder().encodeToString("user".getBytes()));
|
||||
V1SecretList secretList = new V1SecretList().kind("SecretList").metadata(new V1ListMeta().resourceVersion("0"))
|
||||
.items(Arrays.asList(dbPassword));
|
||||
|
||||
stubFor(get(urlMatching("^/api/v1/namespaces/default/secrets.*")).inScenario("watch")
|
||||
.whenScenarioStateIs(STARTED).withQueryParam("watch", equalTo("false"))
|
||||
.willReturn(aResponse().withStatus(200).withBody(new Gson().toJson(secretList)))
|
||||
.willSetStateTo("update"));
|
||||
|
||||
Watch.Response<V1Secret> watchResponse = new Watch.Response<>(EventType.MODIFIED.name(), dbPasswordUpdated);
|
||||
stubFor(get(urlMatching("/api/v1/namespaces/default/secrets.*")).inScenario("watch")
|
||||
.whenScenarioStateIs("update").withQueryParam("watch", equalTo("true"))
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(watchResponse)))
|
||||
.willSetStateTo("add"));
|
||||
|
||||
stubFor(get(urlMatching("/api/v1/namespaces/default/secrets.*")).inScenario("watch").whenScenarioStateIs("add")
|
||||
.withQueryParam("watch", equalTo("true"))
|
||||
.willReturn(aResponse().withStatus(200)
|
||||
.withBody(new JSON().serialize(new Watch.Response<>(EventType.ADDED.name(),
|
||||
new V1Secret().kind("Secret").metadata(new V1ObjectMeta().name("rabbit-password"))
|
||||
.putDataItem("rabbit-pw", Base64.getEncoder().encode("password".getBytes()))))))
|
||||
.willSetStateTo("delete"));
|
||||
|
||||
stubFor(get(urlMatching("/api/v1/namespaces/default/secrets.*")).inScenario("watch")
|
||||
.whenScenarioStateIs("delete").withQueryParam("watch", equalTo("true"))
|
||||
.willReturn(aResponse().withStatus(200)
|
||||
.withBody(new JSON().serialize(new Watch.Response<>(EventType.DELETED.name(),
|
||||
new V1Secret().kind("Secret").metadata(new V1ObjectMeta().name("rabbit-password"))
|
||||
.putDataItem("rabbit-pw", Base64.getEncoder().encode("password".getBytes()))))))
|
||||
.willSetStateTo("done"));
|
||||
|
||||
stubFor(get(urlMatching("/api/v1/namespaces/default/secrets.*")).inScenario("watch").whenScenarioStateIs("done")
|
||||
.withQueryParam("watch", equalTo("true")).willReturn(aResponse().withStatus(200)));
|
||||
|
||||
ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build();
|
||||
OkHttpClient httpClient = apiClient.getHttpClient().newBuilder().readTimeout(0, TimeUnit.SECONDS).build();
|
||||
apiClient.setHttpClient(httpClient);
|
||||
CoreV1Api coreV1Api = new CoreV1Api(apiClient);
|
||||
ConfigurationUpdateStrategy strategy = mock(ConfigurationUpdateStrategy.class);
|
||||
when(strategy.getName()).thenReturn("strategy");
|
||||
KubernetesMockEnvironment environment = new KubernetesMockEnvironment(
|
||||
mock(KubernetesClientSecretsPropertySource.class)).withProperty("db-password", "p455w0rd");
|
||||
KubernetesClientSecretsPropertySourceLocator locator = mock(KubernetesClientSecretsPropertySourceLocator.class);
|
||||
when(locator.locate(environment)).thenReturn(new MockPropertySource().withProperty("db-password", "p455w0rd2"));
|
||||
ConfigReloadProperties properties = new ConfigReloadProperties();
|
||||
properties.setMonitoringSecrets(true);
|
||||
KubernetesClientProperties kubernetesClientProperties = new KubernetesClientProperties();
|
||||
kubernetesClientProperties.setNamespace("default");
|
||||
KubernetesClientEventBasedSecretsChangeDetector changeDetector = new KubernetesClientEventBasedSecretsChangeDetector(
|
||||
coreV1Api, environment, properties, strategy, locator, kubernetesClientProperties);
|
||||
|
||||
Thread controllerThread = new Thread(changeDetector::watch);
|
||||
controllerThread.setDaemon(true);
|
||||
controllerThread.start();
|
||||
|
||||
await().timeout(Duration.ofSeconds(300))
|
||||
.until(() -> Mockito.mockingDetails(strategy).getInvocations().size() > 4);
|
||||
verify(strategy, atLeast(3)).reload();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config.reload;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySource;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class KubernetesMockEnvironment extends AbstractEnvironment {
|
||||
|
||||
private PropertySource propertySource = mock(KubernetesClientSecretsPropertySource.class);
|
||||
|
||||
private Map<String, Object> map = new HashMap<>();
|
||||
|
||||
public KubernetesMockEnvironment(PropertySource mockPropertySource) {
|
||||
this.propertySource = mockPropertySource;
|
||||
this.getPropertySources().addLast(this.propertySource);
|
||||
when(propertySource.getSource()).thenReturn(map);
|
||||
}
|
||||
|
||||
public void setProperty(String key, String value) {
|
||||
map.put(key, value);
|
||||
when(propertySource.getProperty(eq(key))).thenReturn(value);
|
||||
}
|
||||
|
||||
public KubernetesMockEnvironment withProperty(String key, String value) {
|
||||
this.setProperty(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,6 +26,14 @@
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.commons.config;
|
||||
|
||||
/**
|
||||
* Abstraction over configuration properties.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.commons.config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -137,7 +137,7 @@ public class ConfigMapConfigProperties extends AbstractConfigProperties {
|
||||
|
||||
}
|
||||
|
||||
static class NormalizedSource {
|
||||
public static class NormalizedSource {
|
||||
|
||||
private final String name;
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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.commons.config;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.KEY_VALUE_TO_PROPERTIES;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.PROPERTIES_TO_MAP;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.throwingMerger;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.yamlParserGenerator;
|
||||
|
||||
/**
|
||||
* A {@link MapPropertySource} that uses Kubernetes config maps.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
* @author Ali Shahbour
|
||||
* @author Michael Moudatsos
|
||||
*/
|
||||
public abstract class ConfigMapPropertySource extends MapPropertySource {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(ConfigMapPropertySource.class);
|
||||
|
||||
protected static final String APPLICATION_YML = "application.yml";
|
||||
|
||||
protected static final String APPLICATION_YAML = "application.yaml";
|
||||
|
||||
protected static final String APPLICATION_PROPERTIES = "application.properties";
|
||||
|
||||
protected static final String PREFIX = "configmap";
|
||||
|
||||
public ConfigMapPropertySource(String name, Map<String, Object> source) {
|
||||
super(name, source);
|
||||
}
|
||||
|
||||
protected static Environment createEnvironmentWithActiveProfiles(String[] activeProfiles) {
|
||||
StandardEnvironment environment = new StandardEnvironment();
|
||||
environment.setActiveProfiles(activeProfiles);
|
||||
return environment;
|
||||
}
|
||||
|
||||
protected static String getName(String name, String namespace) {
|
||||
return new StringBuilder().append(PREFIX).append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR).append(name)
|
||||
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR).append(namespace).toString();
|
||||
}
|
||||
|
||||
protected static Map<String, Object> processAllEntries(Map<String, String> input, Environment environment) {
|
||||
|
||||
Set<Entry<String, String>> entrySet = input.entrySet();
|
||||
if (entrySet.size() == 1) {
|
||||
// we handle the case where the configmap contains a single "file"
|
||||
// in this case we don't care what the name of t he file is
|
||||
Entry<String, String> singleEntry = entrySet.iterator().next();
|
||||
String propertyName = singleEntry.getKey();
|
||||
String propertyValue = singleEntry.getValue();
|
||||
if (propertyName.endsWith(".yml") || propertyName.endsWith(".yaml")) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("The single property with name: [" + propertyName + "] will be treated as a yaml file");
|
||||
}
|
||||
|
||||
return yamlParserGenerator(environment).andThen(PROPERTIES_TO_MAP).apply(propertyValue);
|
||||
}
|
||||
else if (propertyName.endsWith(".properties")) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("The single property with name: [" + propertyName
|
||||
+ "] will be treated as a properties file");
|
||||
}
|
||||
|
||||
return KEY_VALUE_TO_PROPERTIES.andThen(PROPERTIES_TO_MAP).apply(propertyValue);
|
||||
}
|
||||
else {
|
||||
return defaultProcessAllEntries(input, environment);
|
||||
}
|
||||
}
|
||||
|
||||
return defaultProcessAllEntries(input, environment);
|
||||
}
|
||||
|
||||
protected static Map<String, Object> defaultProcessAllEntries(Map<String, String> input, Environment environment) {
|
||||
|
||||
return input.entrySet().stream().map(e -> extractProperties(e.getKey(), e.getValue(), environment))
|
||||
.filter(m -> !m.isEmpty()).flatMap(m -> m.entrySet().stream())
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, throwingMerger(), LinkedHashMap::new));
|
||||
}
|
||||
|
||||
protected static Map<String, Object> extractProperties(String resourceName, String content,
|
||||
Environment environment) {
|
||||
|
||||
if (resourceName.equals(APPLICATION_YAML) || resourceName.equals(APPLICATION_YML)) {
|
||||
return yamlParserGenerator(environment).andThen(PROPERTIES_TO_MAP).apply(content);
|
||||
}
|
||||
else if (resourceName.equals(APPLICATION_PROPERTIES)) {
|
||||
return KEY_VALUE_TO_PROPERTIES.andThen(PROPERTIES_TO_MAP).apply(content);
|
||||
}
|
||||
|
||||
return new LinkedHashMap<String, Object>() {
|
||||
{
|
||||
put(resourceName, content);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected static Map<String, Object> asObjectMap(Map<String, Object> source) {
|
||||
return source.entrySet().stream()
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, throwingMerger(), LinkedHashMap::new));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.commons.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@@ -22,26 +22,23 @@ import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import io.fabric8.kubernetes.api.builder.Function;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapConfigProperties.NormalizedSource;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties.NormalizedSource;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationName;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationNamespace;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.KEY_VALUE_TO_PROPERTIES;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.PROPERTIES_TO_MAP;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.yamlParserGenerator;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.getApplicationName;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.KEY_VALUE_TO_PROPERTIES;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.PROPERTIES_TO_MAP;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.yamlParserGenerator;
|
||||
|
||||
/**
|
||||
* A {@link PropertySourceLocator} that uses config maps.
|
||||
@@ -49,17 +46,13 @@ import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.ya
|
||||
* @author Ioannis Canellos
|
||||
* @author Michael Moudatsos
|
||||
*/
|
||||
@Order(0)
|
||||
public class ConfigMapPropertySourceLocator implements PropertySourceLocator {
|
||||
public abstract class ConfigMapPropertySourceLocator implements PropertySourceLocator {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(ConfigMapPropertySourceLocator.class);
|
||||
|
||||
private final KubernetesClient client;
|
||||
protected final ConfigMapConfigProperties properties;
|
||||
|
||||
private final ConfigMapConfigProperties properties;
|
||||
|
||||
public ConfigMapPropertySourceLocator(KubernetesClient client, ConfigMapConfigProperties properties) {
|
||||
this.client = client;
|
||||
public ConfigMapPropertySourceLocator(ConfigMapConfigProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@@ -68,7 +61,7 @@ public class ConfigMapPropertySourceLocator implements PropertySourceLocator {
|
||||
if (environment instanceof ConfigurableEnvironment) {
|
||||
ConfigurableEnvironment env = (ConfigurableEnvironment) environment;
|
||||
|
||||
List<ConfigMapConfigProperties.NormalizedSource> sources = this.properties.determineSources();
|
||||
List<NormalizedSource> sources = this.properties.determineSources();
|
||||
CompositePropertySource composite = new CompositePropertySource("composite-configmap");
|
||||
if (this.properties.isEnableApi()) {
|
||||
sources.forEach(s -> composite.addFirstPropertySource(getMapPropertySourceForSingleConfigMap(env, s)));
|
||||
@@ -85,12 +78,13 @@ public class ConfigMapPropertySourceLocator implements PropertySourceLocator {
|
||||
NormalizedSource normalizedSource) {
|
||||
|
||||
String configurationTarget = this.properties.getConfigurationTarget();
|
||||
return new ConfigMapPropertySource(this.client,
|
||||
getApplicationName(environment, normalizedSource.getName(), configurationTarget),
|
||||
getApplicationNamespace(this.client, normalizedSource.getNamespace(), configurationTarget),
|
||||
environment);
|
||||
return getMapPropertySource(getApplicationName(environment, normalizedSource.getName(), configurationTarget),
|
||||
normalizedSource, configurationTarget, environment);
|
||||
}
|
||||
|
||||
protected abstract MapPropertySource getMapPropertySource(String name, NormalizedSource normalizedSource,
|
||||
String configurationTarget, ConfigurableEnvironment environment);
|
||||
|
||||
private void addPropertySourcesFromPaths(Environment environment, CompositePropertySource composite) {
|
||||
this.properties.getPaths().stream().map(Paths::get).peek(p -> {
|
||||
if (!Files.exists(p)) {
|
||||
@@ -14,17 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.commons.config;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.config.Constants.FALLBACK_APPLICATION_NAME;
|
||||
import static org.springframework.cloud.kubernetes.config.Constants.SPRING_APPLICATION_NAME;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.Constants.FALLBACK_APPLICATION_NAME;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.Constants.SPRING_APPLICATION_NAME;
|
||||
|
||||
/**
|
||||
* Utility class that works with configuration properties.
|
||||
@@ -36,7 +35,6 @@ public final class ConfigUtils {
|
||||
private static final Log LOG = LogFactory.getLog(ConfigUtils.class);
|
||||
|
||||
private ConfigUtils() {
|
||||
throw new IllegalStateException("Can't instantiate a utility class");
|
||||
}
|
||||
|
||||
public static String getApplicationName(Environment env, String configName, String configurationTarget) {
|
||||
@@ -50,15 +48,4 @@ public final class ConfigUtils {
|
||||
return configName;
|
||||
}
|
||||
|
||||
public static String getApplicationNamespace(KubernetesClient client, String configNamespace,
|
||||
String configurationTarget) {
|
||||
if (StringUtils.isEmpty(configNamespace)) {
|
||||
LOG.debug(configurationTarget + " namespace has not been set, taking it from client (ns="
|
||||
+ client.getNamespace() + ")");
|
||||
configNamespace = client.getNamespace();
|
||||
}
|
||||
|
||||
return configNamespace;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,13 +14,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.commons.config;
|
||||
|
||||
final class Constants {
|
||||
public final class Constants {
|
||||
|
||||
static final String SPRING_APPLICATION_NAME = "spring.application.name";
|
||||
static final String FALLBACK_APPLICATION_NAME = "application";
|
||||
static final String PROPERTY_SOURCE_NAME_SEPARATOR = ".";
|
||||
/**
|
||||
* Spring application name property.
|
||||
*/
|
||||
public static final String SPRING_APPLICATION_NAME = "spring.application.name";
|
||||
|
||||
/**
|
||||
* Default application name.
|
||||
*/
|
||||
public static final String FALLBACK_APPLICATION_NAME = "application";
|
||||
|
||||
/**
|
||||
* Property separator.
|
||||
*/
|
||||
public static final String PROPERTY_SOURCE_NAME_SEPARATOR = ".";
|
||||
|
||||
private Constants() {
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.commons.config;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.ConditionalOnKubernetesEnabled;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnKubernetesEnabled
|
||||
@EnableConfigurationProperties({ ConfigMapConfigProperties.class, SecretsConfigProperties.class })
|
||||
public class KubernetesBootstrapConfiguration {
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.commons.config;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -42,7 +42,10 @@ import static org.springframework.beans.factory.config.YamlProcessor.MatchStatus
|
||||
*/
|
||||
public final class PropertySourceUtils {
|
||||
|
||||
static final Function<String, Properties> KEY_VALUE_TO_PROPERTIES = s -> {
|
||||
/**
|
||||
* Function to convert a String to Properties.
|
||||
*/
|
||||
public static final Function<String, Properties> KEY_VALUE_TO_PROPERTIES = s -> {
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
properties.load(new ByteArrayInputStream(s.getBytes()));
|
||||
@@ -52,7 +55,11 @@ public final class PropertySourceUtils {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
};
|
||||
static final Function<Properties, Map<String, Object>> PROPERTIES_TO_MAP = p -> p.entrySet().stream()
|
||||
|
||||
/**
|
||||
* Function to convert Properties to a Map.
|
||||
*/
|
||||
public static final Function<Properties, Map<String, Object>> PROPERTIES_TO_MAP = p -> p.entrySet().stream()
|
||||
.collect(Collectors.toMap(e -> String.valueOf(e.getKey()), Map.Entry::getValue, throwingMerger(),
|
||||
java.util.LinkedHashMap::new));
|
||||
|
||||
@@ -60,7 +67,12 @@ public final class PropertySourceUtils {
|
||||
throw new IllegalStateException("Can't instantiate a utility class");
|
||||
}
|
||||
|
||||
static Function<String, Properties> yamlParserGenerator(Environment environment) {
|
||||
/**
|
||||
* Function to convert String into Properties with an environment.
|
||||
* @param environment Environment.
|
||||
* @return properties.
|
||||
*/
|
||||
public static Function<String, Properties> yamlParserGenerator(Environment environment) {
|
||||
return s -> {
|
||||
YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
|
||||
yamlFactory.setDocumentMatchers(properties -> {
|
||||
@@ -77,7 +89,12 @@ public final class PropertySourceUtils {
|
||||
};
|
||||
}
|
||||
|
||||
static <T> BinaryOperator<T> throwingMerger() {
|
||||
/**
|
||||
* Throws IllegalStateException.
|
||||
* @param <T> Throwable.
|
||||
* @return IllegalStateException.
|
||||
*/
|
||||
public static <T> BinaryOperator<T> throwingMerger() {
|
||||
return (u, v) -> {
|
||||
throw new IllegalStateException(String.format("Duplicate key %s", u));
|
||||
};
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.commons.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -169,7 +169,7 @@ public class SecretsConfigProperties extends AbstractConfigProperties {
|
||||
|
||||
}
|
||||
|
||||
static class NormalizedSource {
|
||||
public static class NormalizedSource {
|
||||
|
||||
private final String name;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.commons.config;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
/**
|
||||
* Kubernetes property source for secrets.
|
||||
*
|
||||
* @author l burgazzoli
|
||||
* @author Haytham Mohamed
|
||||
*/
|
||||
public class SecretsPropertySource extends MapPropertySource {
|
||||
|
||||
private static final String PREFIX = "secrets";
|
||||
|
||||
public SecretsPropertySource(String name, Map<String, Object> source) {
|
||||
super(name, source);
|
||||
}
|
||||
|
||||
protected static String getSourceName(String name, String namespace) {
|
||||
return new StringBuilder().append(PREFIX).append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR).append(name)
|
||||
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR).append(namespace).toString();
|
||||
}
|
||||
|
||||
protected static void putAll(Map<String, String> data, Map<String, Object> result) {
|
||||
if (data != null) {
|
||||
data.forEach((k, v) -> result.put(k, new String(Base64.getDecoder().decode(v)).trim()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + " {name='" + this.name + "'}";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.commons.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@@ -24,38 +24,29 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationName;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigUtils.getApplicationNamespace;
|
||||
|
||||
/**
|
||||
* Kubernetes {@link PropertySourceLocator} for secrets.
|
||||
*
|
||||
* @author l burgazzoli
|
||||
* @author Haytham Mohamed
|
||||
*/
|
||||
@Order(1)
|
||||
public class SecretsPropertySourceLocator implements PropertySourceLocator {
|
||||
public abstract class SecretsPropertySourceLocator implements PropertySourceLocator {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(SecretsPropertySourceLocator.class);
|
||||
|
||||
private final KubernetesClient client;
|
||||
protected final SecretsConfigProperties properties;
|
||||
|
||||
private final SecretsConfigProperties properties;
|
||||
|
||||
public SecretsPropertySourceLocator(KubernetesClient client, SecretsConfigProperties properties) {
|
||||
this.client = client;
|
||||
public SecretsPropertySourceLocator(SecretsConfigProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@@ -83,17 +74,17 @@ public class SecretsPropertySourceLocator implements PropertySourceLocator {
|
||||
SecretsConfigProperties.NormalizedSource normalizedSource) {
|
||||
|
||||
String configurationTarget = this.properties.getConfigurationTarget();
|
||||
return new SecretsPropertySource(this.client, environment,
|
||||
getApplicationName(environment, normalizedSource.getName(), configurationTarget),
|
||||
getApplicationNamespace(this.client, normalizedSource.getNamespace(), configurationTarget),
|
||||
normalizedSource.getLabels());
|
||||
return getPropertySource(environment, normalizedSource, configurationTarget);
|
||||
}
|
||||
|
||||
private void putPathConfig(CompositePropertySource composite) {
|
||||
protected abstract MapPropertySource getPropertySource(ConfigurableEnvironment environment,
|
||||
SecretsConfigProperties.NormalizedSource normalizedSource, String configurationTarget);
|
||||
|
||||
protected void putPathConfig(CompositePropertySource composite) {
|
||||
this.properties.getPaths().stream().map(Paths::get).filter(Files::exists).forEach(p -> putAll(p, composite));
|
||||
}
|
||||
|
||||
private void putAll(Path path, CompositePropertySource composite) {
|
||||
protected void putAll(Path path, CompositePropertySource composite) {
|
||||
try {
|
||||
|
||||
Files.walk(path).filter(Files::isRegularFile).forEach(p -> readFile(p, composite));
|
||||
@@ -103,7 +94,7 @@ public class SecretsPropertySourceLocator implements PropertySourceLocator {
|
||||
}
|
||||
}
|
||||
|
||||
private void readFile(Path path, CompositePropertySource composite) {
|
||||
protected void readFile(Path path, CompositePropertySource composite) {
|
||||
try {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put(path.getFileName().toString(), new String(Files.readAllBytes(path)).trim());
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.commons.config.reload;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
|
||||
import org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration;
|
||||
import org.springframework.cloud.context.refresh.ContextRefresher;
|
||||
import org.springframework.cloud.context.restart.RestartEndpoint;
|
||||
import org.springframework.cloud.kubernetes.commons.ConditionalOnKubernetesEnabled;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnKubernetesEnabled
|
||||
@ConditionalOnClass(EndpointAutoConfiguration.class)
|
||||
@AutoConfigureAfter({ InfoEndpointAutoConfiguration.class, RefreshEndpointAutoConfiguration.class,
|
||||
RefreshAutoConfiguration.class })
|
||||
public class ConfigReloadAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Configuration reload must be enabled explicitly.
|
||||
*/
|
||||
@ConditionalOnProperty("spring.cloud.kubernetes.reload.enabled")
|
||||
@ConditionalOnClass({ RestartEndpoint.class, ContextRefresher.class })
|
||||
protected static class ConfigReloadAutoConfigurationBeans {
|
||||
|
||||
/**
|
||||
* @param properties config reload properties
|
||||
* @param ctx application context
|
||||
* @param restarter restart endpoint
|
||||
* @param refresher context refresher
|
||||
* @return provides the action to execute when the configuration changes.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ConfigurationUpdateStrategy configurationUpdateStrategy(ConfigReloadProperties properties,
|
||||
ConfigurableApplicationContext ctx, @Autowired(required = false) RestartEndpoint restarter,
|
||||
ContextRefresher refresher) {
|
||||
switch (properties.getStrategy()) {
|
||||
case RESTART_CONTEXT:
|
||||
Assert.notNull(restarter, "Restart endpoint is not enabled");
|
||||
return new ConfigurationUpdateStrategy(properties.getStrategy().name(), () -> {
|
||||
wait(properties);
|
||||
restarter.restart();
|
||||
});
|
||||
case REFRESH:
|
||||
return new ConfigurationUpdateStrategy(properties.getStrategy().name(), refresher::refresh);
|
||||
case SHUTDOWN:
|
||||
return new ConfigurationUpdateStrategy(properties.getStrategy().name(), () -> {
|
||||
wait(properties);
|
||||
ctx.close();
|
||||
});
|
||||
}
|
||||
throw new IllegalStateException("Unsupported configuration update strategy: " + properties.getStrategy());
|
||||
}
|
||||
|
||||
private static void wait(ConfigReloadProperties properties) {
|
||||
final long waitMillis = ThreadLocalRandom.current().nextLong(properties.getMaxWaitForRestart().toMillis());
|
||||
try {
|
||||
Thread.sleep(waitMillis);
|
||||
}
|
||||
catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.reload;
|
||||
package org.springframework.cloud.kubernetes.commons.config.reload;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.reload;
|
||||
package org.springframework.cloud.kubernetes.commons.config.reload;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
@@ -23,9 +23,6 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -51,25 +48,15 @@ public abstract class ConfigurationChangeDetector {
|
||||
|
||||
protected ConfigReloadProperties properties;
|
||||
|
||||
protected KubernetesClient kubernetesClient;
|
||||
|
||||
protected ConfigurationUpdateStrategy strategy;
|
||||
|
||||
public ConfigurationChangeDetector(ConfigurableEnvironment environment, ConfigReloadProperties properties,
|
||||
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy) {
|
||||
ConfigurationUpdateStrategy strategy) {
|
||||
this.environment = environment;
|
||||
this.properties = properties;
|
||||
this.kubernetesClient = kubernetesClient;
|
||||
this.strategy = strategy;
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
// Ensure the kubernetes client is cleaned up from spare threads when shutting
|
||||
// down
|
||||
this.kubernetesClient.close();
|
||||
}
|
||||
|
||||
public void reloadProperties() {
|
||||
this.log.info("Reloading using strategy: " + this.strategy.getName());
|
||||
this.strategy.reload();
|
||||
@@ -81,7 +68,7 @@ public abstract class ConfigurationChangeDetector {
|
||||
* @param right right map property sources
|
||||
* @return {@code true} if source has changed
|
||||
*/
|
||||
protected boolean changed(MapPropertySource left, MapPropertySource right) {
|
||||
public boolean changed(MapPropertySource left, MapPropertySource right) {
|
||||
if (left == right) {
|
||||
return false;
|
||||
}
|
||||
@@ -93,7 +80,7 @@ public abstract class ConfigurationChangeDetector {
|
||||
return !Objects.equals(leftMap, rightMap);
|
||||
}
|
||||
|
||||
protected boolean changed(List<? extends MapPropertySource> left, List<? extends MapPropertySource> right) {
|
||||
public boolean changed(List<? extends MapPropertySource> left, List<? extends MapPropertySource> right) {
|
||||
|
||||
if (left.size() != right.size()) {
|
||||
this.log.warn("The current number of ConfigMap PropertySources does not match "
|
||||
@@ -132,7 +119,7 @@ public abstract class ConfigurationChangeDetector {
|
||||
* @param sourceClass class for which property sources will be found
|
||||
* @return finds all registered property sources of the given type
|
||||
*/
|
||||
protected <S extends PropertySource<?>> List<S> findPropertySources(Class<S> sourceClass) {
|
||||
public <S extends PropertySource<?>> List<S> findPropertySources(Class<S> sourceClass) {
|
||||
List<S> managedSources = new LinkedList<>();
|
||||
|
||||
LinkedList<PropertySource<?>> sources = toLinkedList(this.environment.getPropertySources());
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.reload;
|
||||
package org.springframework.cloud.kubernetes.commons.config.reload;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -14,18 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.reload;
|
||||
package org.springframework.cloud.kubernetes.commons.config.reload;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySource;
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
@@ -42,14 +40,16 @@ public class PollingConfigMapChangeDetector extends ConfigurationChangeDetector
|
||||
|
||||
protected Log log = LogFactory.getLog(getClass());
|
||||
|
||||
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
|
||||
private PropertySourceLocator propertySourceLocator;
|
||||
|
||||
private Class propertySourceClass;
|
||||
|
||||
public PollingConfigMapChangeDetector(AbstractEnvironment environment, ConfigReloadProperties properties,
|
||||
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy,
|
||||
ConfigMapPropertySourceLocator configMapPropertySourceLocator) {
|
||||
super(environment, properties, kubernetesClient, strategy);
|
||||
|
||||
this.configMapPropertySourceLocator = configMapPropertySourceLocator;
|
||||
ConfigurationUpdateStrategy strategy, Class propertySourceClass,
|
||||
PropertySourceLocator propertySourceLocator) {
|
||||
super(environment, properties, strategy);
|
||||
this.propertySourceLocator = propertySourceLocator;
|
||||
this.propertySourceClass = propertySourceClass;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
@@ -66,12 +66,10 @@ public class PollingConfigMapChangeDetector extends ConfigurationChangeDetector
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Polling for changes in config maps");
|
||||
}
|
||||
List<? extends MapPropertySource> currentConfigMapSources = findPropertySources(
|
||||
ConfigMapPropertySource.class);
|
||||
List<? extends MapPropertySource> currentConfigMapSources = findPropertySources(propertySourceClass);
|
||||
|
||||
if (!currentConfigMapSources.isEmpty()) {
|
||||
changedConfigMap = changed(
|
||||
locateMapPropertySources(this.configMapPropertySourceLocator, this.environment),
|
||||
changedConfigMap = changed(locateMapPropertySources(this.propertySourceLocator, this.environment),
|
||||
currentConfigMapSources);
|
||||
}
|
||||
}
|
||||
@@ -14,18 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.reload;
|
||||
package org.springframework.cloud.kubernetes.commons.config.reload;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.kubernetes.config.SecretsPropertySource;
|
||||
import org.springframework.cloud.kubernetes.config.SecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
@@ -42,14 +40,16 @@ public class PollingSecretsChangeDetector extends ConfigurationChangeDetector {
|
||||
|
||||
protected Log log = LogFactory.getLog(getClass());
|
||||
|
||||
private final SecretsPropertySourceLocator secretsPropertySourceLocator;
|
||||
private final PropertySourceLocator propertySourceLocator;
|
||||
|
||||
private Class propertySourceClass;
|
||||
|
||||
public PollingSecretsChangeDetector(AbstractEnvironment environment, ConfigReloadProperties properties,
|
||||
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy,
|
||||
SecretsPropertySourceLocator secretsPropertySourceLocator) {
|
||||
super(environment, properties, kubernetesClient, strategy);
|
||||
|
||||
this.secretsPropertySourceLocator = secretsPropertySourceLocator;
|
||||
ConfigurationUpdateStrategy strategy, Class propertySourceClass,
|
||||
PropertySourceLocator propertySourceLocator) {
|
||||
super(environment, properties, strategy);
|
||||
this.propertySourceClass = propertySourceClass;
|
||||
this.propertySourceLocator = propertySourceLocator;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
@@ -66,10 +66,10 @@ public class PollingSecretsChangeDetector extends ConfigurationChangeDetector {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Polling for changes in secrets");
|
||||
}
|
||||
List<MapPropertySource> currentSecretSources = locateMapPropertySources(this.secretsPropertySourceLocator,
|
||||
List<MapPropertySource> currentSecretSources = locateMapPropertySources(this.propertySourceLocator,
|
||||
this.environment);
|
||||
if (currentSecretSources != null && !currentSecretSources.isEmpty()) {
|
||||
List<SecretsPropertySource> propertySources = findPropertySources(SecretsPropertySource.class);
|
||||
List<MapPropertySource> propertySources = findPropertySources(this.propertySourceClass);
|
||||
changedSecrets = changed(currentSecretSources, propertySources);
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.reload.condition;
|
||||
package org.springframework.cloud.kubernetes.commons.config.reload.condition;
|
||||
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadProperties.ReloadDetectionMode;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
@@ -38,7 +38,7 @@ public class EventReloadDetectionMode implements Condition {
|
||||
}
|
||||
else {
|
||||
if (environment.getProperty("spring.cloud.kubernetes.reload.mode")
|
||||
.equalsIgnoreCase(ReloadDetectionMode.EVENT.name())) {
|
||||
.equalsIgnoreCase(ConfigReloadProperties.ReloadDetectionMode.EVENT.name())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.reload.condition;
|
||||
package org.springframework.cloud.kubernetes.commons.config.reload.condition;
|
||||
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadProperties.ReloadDetectionMode;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
@@ -38,7 +38,7 @@ public class PollingReloadDetectionMode implements Condition {
|
||||
}
|
||||
else {
|
||||
if (environment.getProperty("spring.cloud.kubernetes.reload.mode")
|
||||
.equalsIgnoreCase(ReloadDetectionMode.POLLING.name())) {
|
||||
.equalsIgnoreCase(ConfigReloadProperties.ReloadDetectionMode.POLLING.name())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,5 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.kubernetes.commons.KubernetesCommonsAutoConfiguration
|
||||
org.springframework.cloud.kubernetes.commons.KubernetesCommonsAutoConfiguration,\
|
||||
org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadAutoConfiguration
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.kubernetes.commons.config.KubernetesBootstrapConfiguration
|
||||
|
||||
@@ -1,180 +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.config;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.ConfigMap;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.KEY_VALUE_TO_PROPERTIES;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.PROPERTIES_TO_MAP;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.throwingMerger;
|
||||
import static org.springframework.cloud.kubernetes.config.PropertySourceUtils.yamlParserGenerator;
|
||||
|
||||
/**
|
||||
* A {@link MapPropertySource} that uses Kubernetes config maps.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
* @author Ali Shahbour
|
||||
* @author Michael Moudatsos
|
||||
*/
|
||||
public class ConfigMapPropertySource extends MapPropertySource {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(ConfigMapPropertySource.class);
|
||||
|
||||
private static final String APPLICATION_YML = "application.yml";
|
||||
|
||||
private static final String APPLICATION_YAML = "application.yaml";
|
||||
|
||||
private static final String APPLICATION_PROPERTIES = "application.properties";
|
||||
|
||||
private static final String PREFIX = "configmap";
|
||||
|
||||
public ConfigMapPropertySource(KubernetesClient client, String name) {
|
||||
this(client, name, null, (Environment) null);
|
||||
}
|
||||
|
||||
public ConfigMapPropertySource(KubernetesClient client, String name, String namespace, String[] profiles) {
|
||||
this(client, name, namespace, createEnvironmentWithActiveProfiles(profiles));
|
||||
}
|
||||
|
||||
private static Environment createEnvironmentWithActiveProfiles(String[] activeProfiles) {
|
||||
StandardEnvironment environment = new StandardEnvironment();
|
||||
environment.setActiveProfiles(activeProfiles);
|
||||
return environment;
|
||||
}
|
||||
|
||||
public ConfigMapPropertySource(KubernetesClient client, String name, String namespace, Environment environment) {
|
||||
super(getName(client, name, namespace), asObjectMap(getData(client, name, namespace, environment)));
|
||||
}
|
||||
|
||||
private static String getName(KubernetesClient client, String name, String namespace) {
|
||||
return new StringBuilder().append(PREFIX).append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR).append(name)
|
||||
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR)
|
||||
.append(namespace == null || namespace.isEmpty() ? client.getNamespace() : namespace).toString();
|
||||
}
|
||||
|
||||
private static Map<String, Object> getData(KubernetesClient client, String name, String namespace,
|
||||
Environment environment) {
|
||||
try {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
ConfigMap map = StringUtils.isEmpty(namespace) ? client.configMaps().withName(name).get()
|
||||
: client.configMaps().inNamespace(namespace).withName(name).get();
|
||||
|
||||
if (map != null) {
|
||||
result.putAll(processAllEntries(map.getData(), environment));
|
||||
}
|
||||
|
||||
if (environment != null) {
|
||||
for (String activeProfile : environment.getActiveProfiles()) {
|
||||
|
||||
String mapNameWithProfile = name + "-" + activeProfile;
|
||||
|
||||
ConfigMap mapWithProfile = StringUtils.isEmpty(namespace)
|
||||
? client.configMaps().withName(mapNameWithProfile).get()
|
||||
: client.configMaps().inNamespace(namespace).withName(mapNameWithProfile).get();
|
||||
|
||||
if (mapWithProfile != null) {
|
||||
result.putAll(processAllEntries(mapWithProfile.getData(), environment));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.warn("Can't read configMap with name: [" + name + "] in namespace:[" + namespace + "]. Ignoring.", e);
|
||||
}
|
||||
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
private static Map<String, Object> processAllEntries(Map<String, String> input, Environment environment) {
|
||||
|
||||
Set<Entry<String, String>> entrySet = input.entrySet();
|
||||
if (entrySet.size() == 1) {
|
||||
// we handle the case where the configmap contains a single "file"
|
||||
// in this case we don't care what the name of t he file is
|
||||
Entry<String, String> singleEntry = entrySet.iterator().next();
|
||||
String propertyName = singleEntry.getKey();
|
||||
String propertyValue = singleEntry.getValue();
|
||||
if (propertyName.endsWith(".yml") || propertyName.endsWith(".yaml")) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("The single property with name: [" + propertyName + "] will be treated as a yaml file");
|
||||
}
|
||||
|
||||
return yamlParserGenerator(environment).andThen(PROPERTIES_TO_MAP).apply(propertyValue);
|
||||
}
|
||||
else if (propertyName.endsWith(".properties")) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("The single property with name: [" + propertyName
|
||||
+ "] will be treated as a properties file");
|
||||
}
|
||||
|
||||
return KEY_VALUE_TO_PROPERTIES.andThen(PROPERTIES_TO_MAP).apply(propertyValue);
|
||||
}
|
||||
else {
|
||||
return defaultProcessAllEntries(input, environment);
|
||||
}
|
||||
}
|
||||
|
||||
return defaultProcessAllEntries(input, environment);
|
||||
}
|
||||
|
||||
private static Map<String, Object> defaultProcessAllEntries(Map<String, String> input, Environment environment) {
|
||||
|
||||
return input.entrySet().stream().map(e -> extractProperties(e.getKey(), e.getValue(), environment))
|
||||
.filter(m -> !m.isEmpty()).flatMap(m -> m.entrySet().stream())
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, throwingMerger(), LinkedHashMap::new));
|
||||
}
|
||||
|
||||
private static Map<String, Object> extractProperties(String resourceName, String content, Environment environment) {
|
||||
|
||||
if (resourceName.equals(APPLICATION_YAML) || resourceName.equals(APPLICATION_YML)) {
|
||||
return yamlParserGenerator(environment).andThen(PROPERTIES_TO_MAP).apply(content);
|
||||
}
|
||||
else if (resourceName.equals(APPLICATION_PROPERTIES)) {
|
||||
return KEY_VALUE_TO_PROPERTIES.andThen(PROPERTIES_TO_MAP).apply(content);
|
||||
}
|
||||
|
||||
return new LinkedHashMap<String, Object>() {
|
||||
{
|
||||
put(resourceName, content);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Map<String, Object> asObjectMap(Map<String, Object> source) {
|
||||
return source.entrySet().stream().collect(
|
||||
Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, throwingMerger(), LinkedHashMap::new));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.kubernetes.config.reload.ConfigReloadAutoConfiguration
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.kubernetes.config.BootstrapConfiguration
|
||||
@@ -22,9 +22,9 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.bus.BusProperties;
|
||||
import org.springframework.cloud.bus.event.RefreshRemoteApplicationEvent;
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySourceLocator;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
@@ -43,10 +43,10 @@ public class BusEventBasedConfigMapWatcherChangeDetector extends ConfigMapWatche
|
||||
|
||||
public BusEventBasedConfigMapWatcherChangeDetector(AbstractEnvironment environment,
|
||||
ConfigReloadProperties properties, KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy,
|
||||
ConfigMapPropertySourceLocator configMapPropertySourceLocator, BusProperties busProperties,
|
||||
Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator, BusProperties busProperties,
|
||||
ConfigurationWatcherConfigurationProperties k8SConfigurationProperties,
|
||||
ThreadPoolTaskExecutor threadPoolTaskExecutor) {
|
||||
super(environment, properties, kubernetesClient, strategy, configMapPropertySourceLocator,
|
||||
super(environment, properties, kubernetesClient, strategy, fabric8ConfigMapPropertySourceLocator,
|
||||
k8SConfigurationProperties, threadPoolTaskExecutor);
|
||||
|
||||
this.busProperties = busProperties;
|
||||
|
||||
@@ -22,9 +22,9 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.bus.BusProperties;
|
||||
import org.springframework.cloud.bus.event.RefreshRemoteApplicationEvent;
|
||||
import org.springframework.cloud.kubernetes.config.SecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8SecretsPropertySourceLocator;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
@@ -43,10 +43,10 @@ public class BusEventBasedSecretsWatcherChangeDetector extends SecretsWatcherCha
|
||||
|
||||
public BusEventBasedSecretsWatcherChangeDetector(AbstractEnvironment environment, ConfigReloadProperties properties,
|
||||
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy,
|
||||
SecretsPropertySourceLocator secretsPropertySourceLocator, BusProperties busProperties,
|
||||
Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator, BusProperties busProperties,
|
||||
ConfigurationWatcherConfigurationProperties k8SConfigurationProperties,
|
||||
ThreadPoolTaskExecutor threadPoolTaskExecutor) {
|
||||
super(environment, properties, kubernetesClient, strategy, secretsPropertySourceLocator,
|
||||
super(environment, properties, kubernetesClient, strategy, fabric8SecretsPropertySourceLocator,
|
||||
k8SConfigurationProperties, threadPoolTaskExecutor);
|
||||
|
||||
this.busProperties = busProperties;
|
||||
|
||||
@@ -26,10 +26,10 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.config.reload.EventBasedConfigMapChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.reload.EventBasedConfigMapChangeDetector;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
@@ -47,10 +47,10 @@ public abstract class ConfigMapWatcherChangeDetector extends EventBasedConfigMap
|
||||
|
||||
public ConfigMapWatcherChangeDetector(AbstractEnvironment environment, ConfigReloadProperties properties,
|
||||
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy,
|
||||
ConfigMapPropertySourceLocator configMapPropertySourceLocator,
|
||||
Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator,
|
||||
ConfigurationWatcherConfigurationProperties k8SConfigurationProperties,
|
||||
ThreadPoolTaskExecutor threadPoolTaskExecutor) {
|
||||
super(environment, properties, kubernetesClient, strategy, configMapPropertySourceLocator);
|
||||
super(environment, properties, kubernetesClient, strategy, fabric8ConfigMapPropertySourceLocator);
|
||||
this.executorService = Executors.newScheduledThreadPool(k8SConfigurationProperties.getThreadPoolSize(),
|
||||
threadPoolTaskExecutor);
|
||||
this.k8SConfigurationProperties = k8SConfigurationProperties;
|
||||
|
||||
@@ -23,11 +23,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.bus.BusProperties;
|
||||
import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration;
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.SecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.discovery.reactive.KubernetesReactiveDiscoveryClient;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8SecretsPropertySourceLocator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
@@ -53,27 +53,28 @@ public class ConfigurationWatcherAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ConfigMapWatcherChangeDetector.class)
|
||||
public ConfigMapWatcherChangeDetector httpBasedConfigMapWatchChangeDetector(AbstractEnvironment environment,
|
||||
KubernetesClient kubernetesClient, ConfigMapPropertySourceLocator configMapPropertySourceLocator,
|
||||
SecretsPropertySourceLocator secretsPropertySourceLocator, ConfigReloadProperties properties,
|
||||
KubernetesClient kubernetesClient,
|
||||
Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator,
|
||||
Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator, ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
ConfigurationWatcherConfigurationProperties k8SConfigurationProperties,
|
||||
ThreadPoolTaskExecutor threadFactory, WebClient webClient,
|
||||
KubernetesReactiveDiscoveryClient kubernetesReactiveDiscoveryClient) {
|
||||
return new HttpBasedConfigMapWatchChangeDetector(environment, properties, kubernetesClient, strategy,
|
||||
configMapPropertySourceLocator, k8SConfigurationProperties, threadFactory, webClient,
|
||||
fabric8ConfigMapPropertySourceLocator, k8SConfigurationProperties, threadFactory, webClient,
|
||||
kubernetesReactiveDiscoveryClient);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(SecretsWatcherChangeDetector.class)
|
||||
public SecretsWatcherChangeDetector httpBasedSecretsWatchChangeDetector(AbstractEnvironment environment,
|
||||
KubernetesClient kubernetesClient, SecretsPropertySourceLocator secretsPropertySourceLocator,
|
||||
KubernetesClient kubernetesClient, Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator,
|
||||
ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy,
|
||||
ConfigurationWatcherConfigurationProperties k8SConfigurationProperties,
|
||||
ThreadPoolTaskExecutor threadFactory, WebClient webClient,
|
||||
KubernetesReactiveDiscoveryClient kubernetesReactiveDiscoveryClient) {
|
||||
return new HttpBasedSecretsWatchChangeDetector(environment, properties, kubernetesClient, strategy,
|
||||
secretsPropertySourceLocator, k8SConfigurationProperties, threadFactory, webClient,
|
||||
fabric8SecretsPropertySourceLocator, k8SConfigurationProperties, threadFactory, webClient,
|
||||
kubernetesReactiveDiscoveryClient);
|
||||
}
|
||||
|
||||
@@ -86,24 +87,24 @@ public class ConfigurationWatcherAutoConfiguration {
|
||||
@ConditionalOnMissingBean(ConfigMapWatcherChangeDetector.class)
|
||||
public ConfigMapWatcherChangeDetector busConfigMapChangeWatcher(BusProperties busProperties,
|
||||
AbstractEnvironment environment, KubernetesClient kubernetesClient,
|
||||
ConfigMapPropertySourceLocator configMapPropertySourceLocator, ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator,
|
||||
ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy,
|
||||
ConfigurationWatcherConfigurationProperties k8SConfigurationProperties,
|
||||
ThreadPoolTaskExecutor threadFactory) {
|
||||
return new BusEventBasedConfigMapWatcherChangeDetector(environment, properties, kubernetesClient, strategy,
|
||||
configMapPropertySourceLocator, busProperties, k8SConfigurationProperties, threadFactory);
|
||||
fabric8ConfigMapPropertySourceLocator, busProperties, k8SConfigurationProperties, threadFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(SecretsWatcherChangeDetector.class)
|
||||
public SecretsWatcherChangeDetector busSecretsChangeWatcher(BusProperties busProperties,
|
||||
AbstractEnvironment environment, KubernetesClient kubernetesClient,
|
||||
SecretsPropertySourceLocator secretsPropertySourceLocator, ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator,
|
||||
ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy,
|
||||
ConfigurationWatcherConfigurationProperties k8SConfigurationProperties,
|
||||
ThreadPoolTaskExecutor threadFactory) {
|
||||
return new BusEventBasedSecretsWatcherChangeDetector(environment, properties, kubernetesClient, strategy,
|
||||
secretsPropertySourceLocator, busProperties, k8SConfigurationProperties, threadFactory);
|
||||
fabric8SecretsPropertySourceLocator, busProperties, k8SConfigurationProperties, threadFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@ import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.discovery.reactive.KubernetesReactiveDiscoveryClient;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySourceLocator;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
@@ -57,11 +57,11 @@ public class HttpBasedConfigMapWatchChangeDetector extends ConfigMapWatcherChang
|
||||
|
||||
public HttpBasedConfigMapWatchChangeDetector(AbstractEnvironment environment, ConfigReloadProperties properties,
|
||||
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy,
|
||||
ConfigMapPropertySourceLocator configMapPropertySourceLocator,
|
||||
Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator,
|
||||
ConfigurationWatcherConfigurationProperties k8SConfigurationProperties,
|
||||
ThreadPoolTaskExecutor threadPoolTaskExecutor, WebClient webClient,
|
||||
KubernetesReactiveDiscoveryClient k8sReactiveDiscoveryClient) {
|
||||
super(environment, properties, kubernetesClient, strategy, configMapPropertySourceLocator,
|
||||
super(environment, properties, kubernetesClient, strategy, fabric8ConfigMapPropertySourceLocator,
|
||||
k8SConfigurationProperties, threadPoolTaskExecutor);
|
||||
this.webClient = webClient;
|
||||
this.kubernetesReactiveDiscoveryClient = k8sReactiveDiscoveryClient;
|
||||
|
||||
@@ -25,10 +25,10 @@ import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.config.SecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.discovery.reactive.KubernetesReactiveDiscoveryClient;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8SecretsPropertySourceLocator;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
@@ -53,11 +53,11 @@ public class HttpBasedSecretsWatchChangeDetector extends SecretsWatcherChangeDet
|
||||
|
||||
public HttpBasedSecretsWatchChangeDetector(AbstractEnvironment environment, ConfigReloadProperties properties,
|
||||
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy,
|
||||
SecretsPropertySourceLocator secretsPropertySourceLocator,
|
||||
Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator,
|
||||
ConfigurationWatcherConfigurationProperties k8SConfigurationProperties,
|
||||
ThreadPoolTaskExecutor threadPoolTaskExecutor, WebClient webClient,
|
||||
KubernetesReactiveDiscoveryClient k8sReactiveDiscoveryClient) {
|
||||
super(environment, properties, kubernetesClient, strategy, secretsPropertySourceLocator,
|
||||
super(environment, properties, kubernetesClient, strategy, fabric8SecretsPropertySourceLocator,
|
||||
k8SConfigurationProperties, threadPoolTaskExecutor);
|
||||
this.webClient = webClient;
|
||||
this.kubernetesReactiveDiscoveryClient = k8sReactiveDiscoveryClient;
|
||||
|
||||
@@ -26,10 +26,10 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.kubernetes.config.SecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.config.reload.EventBasedSecretsChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8SecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.reload.EventBasedSecretsChangeDetector;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
@@ -47,10 +47,10 @@ public abstract class SecretsWatcherChangeDetector extends EventBasedSecretsChan
|
||||
|
||||
public SecretsWatcherChangeDetector(AbstractEnvironment environment, ConfigReloadProperties properties,
|
||||
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy,
|
||||
SecretsPropertySourceLocator secretsPropertySourceLocator,
|
||||
Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator,
|
||||
ConfigurationWatcherConfigurationProperties k8SConfigurationProperties,
|
||||
ThreadPoolTaskExecutor threadPoolTaskExecutor) {
|
||||
super(environment, properties, kubernetesClient, strategy, secretsPropertySourceLocator);
|
||||
super(environment, properties, kubernetesClient, strategy, fabric8SecretsPropertySourceLocator);
|
||||
this.executorService = Executors.newScheduledThreadPool(k8SConfigurationProperties.getThreadPoolSize(),
|
||||
threadPoolTaskExecutor);
|
||||
this.k8SConfigurationProperties = k8SConfigurationProperties;
|
||||
|
||||
@@ -28,9 +28,9 @@ import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.cloud.bus.BusProperties;
|
||||
import org.springframework.cloud.bus.event.RefreshRemoteApplicationEvent;
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySourceLocator;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
@@ -52,7 +52,7 @@ public class BusEventBasedConfigMapWatcherChangeDetectorTests {
|
||||
private ConfigurationUpdateStrategy updateStrategy;
|
||||
|
||||
@Mock
|
||||
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
|
||||
private Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator;
|
||||
|
||||
@Mock
|
||||
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||
@@ -73,7 +73,7 @@ public class BusEventBasedConfigMapWatcherChangeDetectorTests {
|
||||
configurationWatcherConfigurationProperties = new ConfigurationWatcherConfigurationProperties();
|
||||
busProperties = new BusProperties();
|
||||
changeDetector = new BusEventBasedConfigMapWatcherChangeDetector(mockEnvironment, configReloadProperties,
|
||||
client, updateStrategy, configMapPropertySourceLocator, busProperties,
|
||||
client, updateStrategy, fabric8ConfigMapPropertySourceLocator, busProperties,
|
||||
configurationWatcherConfigurationProperties, threadPoolTaskExecutor);
|
||||
changeDetector.setApplicationEventPublisher(applicationEventPublisher);
|
||||
}
|
||||
|
||||
@@ -28,9 +28,9 @@ import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.cloud.bus.BusProperties;
|
||||
import org.springframework.cloud.bus.event.RefreshRemoteApplicationEvent;
|
||||
import org.springframework.cloud.kubernetes.config.SecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8SecretsPropertySourceLocator;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
@@ -52,7 +52,7 @@ public class BusEventBasedSecretsWatcherChangeDetectorTests {
|
||||
private ConfigurationUpdateStrategy updateStrategy;
|
||||
|
||||
@Mock
|
||||
private SecretsPropertySourceLocator secretsPropertySourceLocator;
|
||||
private Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator;
|
||||
|
||||
@Mock
|
||||
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||
@@ -73,7 +73,7 @@ public class BusEventBasedSecretsWatcherChangeDetectorTests {
|
||||
configurationWatcherConfigurationProperties = new ConfigurationWatcherConfigurationProperties();
|
||||
busProperties = new BusProperties();
|
||||
changeDetector = new BusEventBasedSecretsWatcherChangeDetector(mockEnvironment, configReloadProperties, client,
|
||||
updateStrategy, secretsPropertySourceLocator, busProperties,
|
||||
updateStrategy, fabric8SecretsPropertySourceLocator, busProperties,
|
||||
configurationWatcherConfigurationProperties, threadPoolTaskExecutor);
|
||||
changeDetector.setApplicationEventPublisher(applicationEventPublisher);
|
||||
}
|
||||
|
||||
@@ -38,11 +38,11 @@ import reactor.core.publisher.Flux;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.discovery.KubernetesServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.discovery.reactive.KubernetesReactiveDiscoveryClient;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySourceLocator;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -74,7 +74,7 @@ public class HttpBasedConfigMapWatchChangeDetectorTests {
|
||||
private ConfigurationUpdateStrategy updateStrategy;
|
||||
|
||||
@Mock
|
||||
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
|
||||
private Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator;
|
||||
|
||||
@Mock
|
||||
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||
@@ -103,7 +103,7 @@ public class HttpBasedConfigMapWatchChangeDetectorTests {
|
||||
configurationWatcherConfigurationProperties = new ConfigurationWatcherConfigurationProperties();
|
||||
WebClient webClient = WebClient.builder().build();
|
||||
changeDetector = new HttpBasedConfigMapWatchChangeDetector(mockEnvironment, configReloadProperties, client,
|
||||
updateStrategy, configMapPropertySourceLocator, configurationWatcherConfigurationProperties,
|
||||
updateStrategy, fabric8ConfigMapPropertySourceLocator, configurationWatcherConfigurationProperties,
|
||||
threadPoolTaskExecutor, webClient, reactiveDiscoveryClient);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,11 +38,11 @@ import reactor.core.publisher.Flux;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.config.SecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.discovery.KubernetesServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.discovery.reactive.KubernetesReactiveDiscoveryClient;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8SecretsPropertySourceLocator;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -74,7 +74,7 @@ public class HttpBasedSecretsWatchChangeDetectorTests {
|
||||
private ConfigurationUpdateStrategy updateStrategy;
|
||||
|
||||
@Mock
|
||||
private SecretsPropertySourceLocator secretsPropertySourceLocator;
|
||||
private Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator;
|
||||
|
||||
@Mock
|
||||
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||
@@ -103,7 +103,7 @@ public class HttpBasedSecretsWatchChangeDetectorTests {
|
||||
configurationWatcherConfigurationProperties = new ConfigurationWatcherConfigurationProperties();
|
||||
WebClient webClient = WebClient.builder().build();
|
||||
changeDetector = new HttpBasedSecretsWatchChangeDetector(mockEnvironment, configReloadProperties, client,
|
||||
updateStrategy, secretsPropertySourceLocator, configurationWatcherConfigurationProperties,
|
||||
updateStrategy, fabric8SecretsPropertySourceLocator, configurationWatcherConfigurationProperties,
|
||||
threadPoolTaskExecutor, webClient, reactiveDiscoveryClient);
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,13 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-config</artifactId>
|
||||
<artifactId>spring-cloud-kubernetes-fabric8-config</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-client-config</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-config</artifactId>
|
||||
<name>Spring Cloud Kubernetes :: Config</name>
|
||||
<artifactId>spring-cloud-kubernetes-fabric8-config</artifactId>
|
||||
<name>Spring Cloud Kubernetes :: Fabric8 Config</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -14,17 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.ConfigMap;
|
||||
import io.fabric8.kubernetes.api.model.Secret;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesCommonsAutoConfiguration;
|
||||
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.KubernetesBootstrapConfiguration;
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties;
|
||||
import org.springframework.cloud.kubernetes.fabric8.Fabric8AutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -38,11 +41,11 @@ import org.springframework.context.annotation.Import;
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnProperty(value = "spring.cloud.kubernetes.enabled", matchIfMissing = true)
|
||||
@ConditionalOnClass({ ConfigMap.class, Secret.class })
|
||||
public class BootstrapConfiguration {
|
||||
@AutoConfigureAfter(KubernetesBootstrapConfiguration.class)
|
||||
public class Fabric8BootstrapConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import({ KubernetesCommonsAutoConfiguration.class, Fabric8AutoConfiguration.class })
|
||||
@EnableConfigurationProperties({ ConfigMapConfigProperties.class, SecretsConfigProperties.class })
|
||||
protected static class KubernetesPropertySourceConfiguration {
|
||||
|
||||
@Autowired
|
||||
@@ -50,14 +53,15 @@ public class BootstrapConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "spring.cloud.kubernetes.config.enabled", matchIfMissing = true)
|
||||
public ConfigMapPropertySourceLocator configMapPropertySourceLocator(ConfigMapConfigProperties properties) {
|
||||
return new ConfigMapPropertySourceLocator(this.client, properties);
|
||||
public Fabric8ConfigMapPropertySourceLocator configMapPropertySourceLocator(
|
||||
ConfigMapConfigProperties properties) {
|
||||
return new Fabric8ConfigMapPropertySourceLocator(this.client, properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "spring.cloud.kubernetes.secrets.enabled", matchIfMissing = true)
|
||||
public SecretsPropertySourceLocator secretsPropertySourceLocator(SecretsConfigProperties properties) {
|
||||
return new SecretsPropertySourceLocator(this.client, properties);
|
||||
public Fabric8SecretsPropertySourceLocator secretsPropertySourceLocator(SecretsConfigProperties properties) {
|
||||
return new Fabric8SecretsPropertySourceLocator(this.client, properties);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.fabric8.config;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.ConfigMap;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A {@link MapPropertySource} that uses Kubernetes config maps.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
* @author Ali Shahbour
|
||||
* @author Michael Moudatsos
|
||||
*/
|
||||
public class Fabric8ConfigMapPropertySource extends ConfigMapPropertySource {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(Fabric8ConfigMapPropertySource.class);
|
||||
|
||||
public Fabric8ConfigMapPropertySource(KubernetesClient client, String name) {
|
||||
this(client, name, null, (Environment) null);
|
||||
}
|
||||
|
||||
public Fabric8ConfigMapPropertySource(KubernetesClient client, String name, String namespace,
|
||||
Environment environment) {
|
||||
super(getName(name, getNamespace(client, namespace)),
|
||||
asObjectMap(getData(client, name, getNamespace(client, namespace), environment)));
|
||||
}
|
||||
|
||||
private static String getNamespace(KubernetesClient client, String namespace) {
|
||||
return StringUtils.isEmpty(namespace) ? client.getNamespace() : namespace;
|
||||
}
|
||||
|
||||
private static Map<String, Object> getData(KubernetesClient client, String name, String namespace,
|
||||
Environment environment) {
|
||||
try {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
ConfigMap map = StringUtils.isEmpty(namespace) ? client.configMaps().withName(name).get()
|
||||
: client.configMaps().inNamespace(namespace).withName(name).get();
|
||||
|
||||
if (map != null) {
|
||||
result.putAll(processAllEntries(map.getData(), environment));
|
||||
}
|
||||
|
||||
if (environment != null) {
|
||||
for (String activeProfile : environment.getActiveProfiles()) {
|
||||
|
||||
String mapNameWithProfile = name + "-" + activeProfile;
|
||||
|
||||
ConfigMap mapWithProfile = StringUtils.isEmpty(namespace)
|
||||
? client.configMaps().withName(mapNameWithProfile).get()
|
||||
: client.configMaps().inNamespace(namespace).withName(mapNameWithProfile).get();
|
||||
|
||||
if (mapWithProfile != null) {
|
||||
result.putAll(processAllEntries(mapWithProfile.getData(), environment));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.warn("Can't read configMap with name: [" + name + "] in namespace:[" + namespace + "]. Ignoring.", e);
|
||||
}
|
||||
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.fabric8.config;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
|
||||
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties.NormalizedSource;
|
||||
import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigUtils.getApplicationNamespace;
|
||||
|
||||
/**
|
||||
* A {@link PropertySourceLocator} that uses config maps.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
* @author Michael Moudatsos
|
||||
*/
|
||||
@Order(0)
|
||||
public class Fabric8ConfigMapPropertySourceLocator extends ConfigMapPropertySourceLocator {
|
||||
|
||||
private final KubernetesClient client;
|
||||
|
||||
public Fabric8ConfigMapPropertySourceLocator(KubernetesClient client, ConfigMapConfigProperties properties) {
|
||||
super(properties);
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MapPropertySource getMapPropertySource(String name, NormalizedSource normalizedSource,
|
||||
String configurationTarget, ConfigurableEnvironment environment) {
|
||||
return new Fabric8ConfigMapPropertySource(this.client, name,
|
||||
getApplicationNamespace(this.client, normalizedSource.getNamespace(), configurationTarget),
|
||||
environment);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.fabric8.config;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Utility class that works with configuration properties.
|
||||
*
|
||||
* @author Ioannis Canellos
|
||||
*/
|
||||
public final class Fabric8ConfigUtils {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(Fabric8ConfigUtils.class);
|
||||
|
||||
private Fabric8ConfigUtils() {
|
||||
}
|
||||
|
||||
public static String getApplicationNamespace(KubernetesClient client, String configNamespace,
|
||||
String configurationTarget) {
|
||||
if (StringUtils.isEmpty(configNamespace)) {
|
||||
LOG.debug(configurationTarget + " namespace has not been set, taking it from client (ns="
|
||||
+ client.getNamespace() + ")");
|
||||
configNamespace = client.getNamespace();
|
||||
}
|
||||
|
||||
return configNamespace;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,9 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -25,8 +24,8 @@ import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -35,20 +34,15 @@ import org.springframework.util.StringUtils;
|
||||
* @author l burgazzoli
|
||||
* @author Haytham Mohamed
|
||||
*/
|
||||
public class SecretsPropertySource extends MapPropertySource {
|
||||
public class Fabric8SecretsPropertySource extends SecretsPropertySource {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(SecretsPropertySource.class);
|
||||
private static final Log LOG = LogFactory.getLog(Fabric8SecretsPropertySource.class);
|
||||
|
||||
private static final String PREFIX = "secrets";
|
||||
|
||||
public SecretsPropertySource(KubernetesClient client, Environment env, String name, String namespace,
|
||||
public Fabric8SecretsPropertySource(KubernetesClient client, Environment env, String name, String namespace,
|
||||
Map<String, String> labels) {
|
||||
super(getSourceName(client, env, name, namespace), getSourceData(client, env, name, namespace, labels));
|
||||
}
|
||||
|
||||
private static String getSourceName(KubernetesClient client, Environment env, String name, String namespace) {
|
||||
return new StringBuilder().append(PREFIX).append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR).append(name)
|
||||
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR).append(namespace).toString();
|
||||
super(getSourceName(name, namespace), getSourceData(client, env, name, namespace, labels));
|
||||
}
|
||||
|
||||
private static Map<String, Object> getSourceData(KubernetesClient client, Environment env, String name,
|
||||
@@ -85,18 +79,10 @@ public class SecretsPropertySource extends MapPropertySource {
|
||||
return result;
|
||||
}
|
||||
|
||||
// *****************************
|
||||
// Helpers
|
||||
// *****************************
|
||||
private static void putAll(Secret secret, Map<String, Object> result) {
|
||||
if (secret != null && secret.getData() != null) {
|
||||
secret.getData().forEach((k, v) -> result.put(k, new String(Base64.getDecoder().decode(v)).trim()));
|
||||
if (secret != null) {
|
||||
putAll(secret.getData(), result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + " {name='" + this.name + "'}";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.fabric8.config;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
|
||||
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySourceLocator;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.getApplicationName;
|
||||
|
||||
/**
|
||||
* Kubernetes {@link PropertySourceLocator} for secrets.
|
||||
*
|
||||
* @author l burgazzoli
|
||||
* @author Haytham Mohamed
|
||||
*/
|
||||
@Order(1)
|
||||
public class Fabric8SecretsPropertySourceLocator extends SecretsPropertySourceLocator {
|
||||
|
||||
private final KubernetesClient client;
|
||||
|
||||
public Fabric8SecretsPropertySourceLocator(KubernetesClient client, SecretsConfigProperties properties) {
|
||||
super(properties);
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MapPropertySource getPropertySource(ConfigurableEnvironment environment,
|
||||
SecretsConfigProperties.NormalizedSource normalizedSource, String configurationTarget) {
|
||||
return new Fabric8SecretsPropertySource(this.client, environment,
|
||||
getApplicationName(environment, normalizedSource.getName(), configurationTarget), Fabric8ConfigUtils
|
||||
.getApplicationNamespace(this.client, normalizedSource.getNamespace(), configurationTarget),
|
||||
normalizedSource.getLabels());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.reload;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.reload;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@@ -33,10 +33,17 @@ import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
|
||||
import org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration;
|
||||
import org.springframework.cloud.context.refresh.ContextRefresher;
|
||||
import org.springframework.cloud.context.restart.RestartEndpoint;
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.SecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.reload.condition.EventReloadDetectionMode;
|
||||
import org.springframework.cloud.kubernetes.config.reload.condition.PollingReloadDetectionMode;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.PollingConfigMapChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.PollingSecretsChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.condition.EventReloadDetectionMode;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.condition.PollingReloadDetectionMode;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySource;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8SecretsPropertySource;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8SecretsPropertySourceLocator;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
@@ -79,68 +86,72 @@ public class ConfigReloadAutoConfiguration {
|
||||
* Polling configMap ConfigurationChangeDetector.
|
||||
* @param properties config reload properties
|
||||
* @param strategy configuration update strategy
|
||||
* @param configMapPropertySourceLocator configMap property source locator
|
||||
* @param fabric8ConfigMapPropertySourceLocator configMap property source locator
|
||||
* @return a bean that listen to configuration changes and fire a reload.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(ConfigMapPropertySourceLocator.class)
|
||||
@ConditionalOnBean(Fabric8ConfigMapPropertySourceLocator.class)
|
||||
@Conditional(PollingReloadDetectionMode.class)
|
||||
public ConfigurationChangeDetector configMapPropertyChangePollingWatcher(ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy, ConfigMapPropertySourceLocator configMapPropertySourceLocator) {
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator) {
|
||||
|
||||
return new PollingConfigMapChangeDetector(this.environment, properties, this.kubernetesClient, strategy,
|
||||
configMapPropertySourceLocator);
|
||||
return new PollingConfigMapChangeDetector(this.environment, properties, strategy,
|
||||
Fabric8ConfigMapPropertySource.class, fabric8ConfigMapPropertySourceLocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Polling secrets ConfigurationChangeDetector.
|
||||
* @param properties config reload properties
|
||||
* @param strategy configuration update strategy
|
||||
* @param secretsPropertySourceLocator secrets property source locator
|
||||
* @param fabric8SecretsPropertySourceLocator secrets property source locator
|
||||
* @return a bean that listen to configuration changes and fire a reload.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(SecretsPropertySourceLocator.class)
|
||||
@ConditionalOnBean(Fabric8SecretsPropertySourceLocator.class)
|
||||
@Conditional(PollingReloadDetectionMode.class)
|
||||
public ConfigurationChangeDetector secretsPropertyChangePollingWatcher(ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy, SecretsPropertySourceLocator secretsPropertySourceLocator) {
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator) {
|
||||
|
||||
return new PollingSecretsChangeDetector(this.environment, properties, this.kubernetesClient, strategy,
|
||||
secretsPropertySourceLocator);
|
||||
return new PollingSecretsChangeDetector(this.environment, properties, strategy,
|
||||
Fabric8SecretsPropertySource.class, fabric8SecretsPropertySourceLocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Based configMap ConfigurationChangeDetector.
|
||||
* @param properties config reload properties
|
||||
* @param strategy configuration update strategy
|
||||
* @param configMapPropertySourceLocator configMap property source locator
|
||||
* @param fabric8ConfigMapPropertySourceLocator configMap property source locator
|
||||
* @return a bean that listen to configMap change events and fire a reload.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(ConfigMapPropertySourceLocator.class)
|
||||
@ConditionalOnBean(Fabric8ConfigMapPropertySourceLocator.class)
|
||||
@Conditional(EventReloadDetectionMode.class)
|
||||
public ConfigurationChangeDetector configMapPropertyChangeEventWatcher(ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy, ConfigMapPropertySourceLocator configMapPropertySourceLocator) {
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator) {
|
||||
|
||||
return new EventBasedConfigMapChangeDetector(this.environment, properties, this.kubernetesClient, strategy,
|
||||
configMapPropertySourceLocator);
|
||||
fabric8ConfigMapPropertySourceLocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Based secrets ConfigurationChangeDetector.
|
||||
* @param properties config reload properties
|
||||
* @param strategy configuration update strategy
|
||||
* @param secretsPropertySourceLocator secrets property source locator
|
||||
* @param fabric8SecretsPropertySourceLocator secrets property source locator
|
||||
* @return a bean that listen to secrets change events and fire a reload.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(SecretsPropertySourceLocator.class)
|
||||
@ConditionalOnBean(Fabric8SecretsPropertySourceLocator.class)
|
||||
@Conditional(EventReloadDetectionMode.class)
|
||||
public ConfigurationChangeDetector secretsPropertyChangeEventWatcher(ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy, SecretsPropertySourceLocator secretsPropertySourceLocator) {
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator) {
|
||||
|
||||
return new EventBasedSecretsChangeDetector(this.environment, properties, this.kubernetesClient, strategy,
|
||||
secretsPropertySourceLocator);
|
||||
fabric8SecretsPropertySourceLocator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.reload;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.reload;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@@ -25,10 +25,17 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.SecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.config.reload.condition.EventReloadDetectionMode;
|
||||
import org.springframework.cloud.kubernetes.config.reload.condition.PollingReloadDetectionMode;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.PollingConfigMapChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.PollingSecretsChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.condition.EventReloadDetectionMode;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.condition.PollingReloadDetectionMode;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySource;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8SecretsPropertySource;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8SecretsPropertySourceLocator;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
@@ -62,77 +69,90 @@ public class ConfigReloadDefaultAutoConfiguration {
|
||||
private KubernetesClient kubernetesClient;
|
||||
|
||||
@Autowired
|
||||
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
|
||||
private Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator;
|
||||
|
||||
@Autowired
|
||||
private SecretsPropertySourceLocator secretsPropertySourceLocator;
|
||||
private Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator;
|
||||
|
||||
private static void wait(ConfigReloadProperties properties) {
|
||||
final long waitMillis = ThreadLocalRandom.current().nextLong(properties.getMaxWaitForRestart().toMillis());
|
||||
try {
|
||||
Thread.sleep(waitMillis);
|
||||
}
|
||||
catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Polling configMap ConfigurationChangeDetector.
|
||||
* @param properties config reload properties
|
||||
* @param strategy configuration update strategy
|
||||
* @param configMapPropertySourceLocator configMap property source locator
|
||||
* @param fabric8ConfigMapPropertySourceLocator configMap property source locator
|
||||
* @return a bean that listen to configuration changes and fire a reload.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(ConfigMapPropertySourceLocator.class)
|
||||
@ConditionalOnBean(Fabric8ConfigMapPropertySourceLocator.class)
|
||||
@Conditional(PollingReloadDetectionMode.class)
|
||||
public ConfigurationChangeDetector configMapPropertyChangePollingWatcher(ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy, ConfigMapPropertySourceLocator configMapPropertySourceLocator) {
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator) {
|
||||
|
||||
return new PollingConfigMapChangeDetector(this.environment, properties, this.kubernetesClient, strategy,
|
||||
configMapPropertySourceLocator);
|
||||
return new PollingConfigMapChangeDetector(this.environment, properties, strategy,
|
||||
Fabric8ConfigMapPropertySource.class, fabric8ConfigMapPropertySourceLocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Polling secrets ConfigurationChangeDetector.
|
||||
* @param properties config reload properties
|
||||
* @param strategy configuration update strategy
|
||||
* @param secretsPropertySourceLocator secrets property source locator
|
||||
* @param fabric8SecretsPropertySourceLocator secrets property source locator
|
||||
* @return a bean that listen to configuration changes and fire a reload.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(SecretsPropertySourceLocator.class)
|
||||
@ConditionalOnBean(Fabric8SecretsPropertySourceLocator.class)
|
||||
@Conditional(PollingReloadDetectionMode.class)
|
||||
public ConfigurationChangeDetector secretsPropertyChangePollingWatcher(ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy, SecretsPropertySourceLocator secretsPropertySourceLocator) {
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator) {
|
||||
|
||||
return new PollingSecretsChangeDetector(this.environment, properties, this.kubernetesClient, strategy,
|
||||
secretsPropertySourceLocator);
|
||||
return new PollingSecretsChangeDetector(this.environment, properties, strategy,
|
||||
Fabric8SecretsPropertySource.class, fabric8SecretsPropertySourceLocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Based configMap ConfigurationChangeDetector.
|
||||
* @param properties config reload properties
|
||||
* @param strategy configuration update strategy
|
||||
* @param configMapPropertySourceLocator configMap property source locator
|
||||
* @param fabric8ConfigMapPropertySourceLocator configMap property source locator
|
||||
* @return a bean that listen to configMap change events and fire a reload.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(ConfigMapPropertySourceLocator.class)
|
||||
@ConditionalOnBean(Fabric8ConfigMapPropertySourceLocator.class)
|
||||
@Conditional(EventReloadDetectionMode.class)
|
||||
public ConfigurationChangeDetector configMapPropertyChangeEventWatcher(ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy, ConfigMapPropertySourceLocator configMapPropertySourceLocator) {
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator) {
|
||||
|
||||
return new EventBasedConfigMapChangeDetector(this.environment, properties, this.kubernetesClient, strategy,
|
||||
configMapPropertySourceLocator);
|
||||
fabric8ConfigMapPropertySourceLocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Based secrets ConfigurationChangeDetector.
|
||||
* @param properties config reload properties
|
||||
* @param strategy configuration update strategy
|
||||
* @param secretsPropertySourceLocator secrets property source locator
|
||||
* @param fabric8SecretsPropertySourceLocator secrets property source locator
|
||||
* @return a bean that listen to secrets change events and fire a reload.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(SecretsPropertySourceLocator.class)
|
||||
@ConditionalOnBean(Fabric8SecretsPropertySourceLocator.class)
|
||||
@Conditional(EventReloadDetectionMode.class)
|
||||
public ConfigurationChangeDetector secretsPropertyChangeEventWatcher(ConfigReloadProperties properties,
|
||||
ConfigurationUpdateStrategy strategy, SecretsPropertySourceLocator secretsPropertySourceLocator) {
|
||||
ConfigurationUpdateStrategy strategy,
|
||||
Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator) {
|
||||
|
||||
return new EventBasedSecretsChangeDetector(this.environment, properties, this.kubernetesClient, strategy,
|
||||
secretsPropertySourceLocator);
|
||||
fabric8SecretsPropertySourceLocator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,15 +174,6 @@ public class ConfigReloadDefaultAutoConfiguration {
|
||||
throw new IllegalStateException("Unsupported configuration update strategy: " + properties.getStrategy());
|
||||
}
|
||||
|
||||
private static void wait(ConfigReloadProperties properties) {
|
||||
final long waitMillis = ThreadLocalRandom.current().nextLong(properties.getMaxWaitForRestart().toMillis());
|
||||
try {
|
||||
Thread.sleep(waitMillis);
|
||||
}
|
||||
catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.reload;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.reload;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -28,8 +28,11 @@ import io.fabric8.kubernetes.client.KubernetesClientException;
|
||||
import io.fabric8.kubernetes.client.Watch;
|
||||
import io.fabric8.kubernetes.client.Watcher;
|
||||
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySource;
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySource;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySourceLocator;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
|
||||
/**
|
||||
@@ -42,19 +45,28 @@ import org.springframework.core.env.AbstractEnvironment;
|
||||
*/
|
||||
public class EventBasedConfigMapChangeDetector extends ConfigurationChangeDetector {
|
||||
|
||||
private final ConfigMapPropertySourceLocator configMapPropertySourceLocator;
|
||||
private final Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator;
|
||||
|
||||
private final Map<String, Watch> watches;
|
||||
|
||||
private KubernetesClient kubernetesClient;
|
||||
|
||||
public EventBasedConfigMapChangeDetector(AbstractEnvironment environment, ConfigReloadProperties properties,
|
||||
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy,
|
||||
ConfigMapPropertySourceLocator configMapPropertySourceLocator) {
|
||||
super(environment, properties, kubernetesClient, strategy);
|
||||
|
||||
this.configMapPropertySourceLocator = configMapPropertySourceLocator;
|
||||
Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator) {
|
||||
super(environment, properties, strategy);
|
||||
this.kubernetesClient = kubernetesClient;
|
||||
this.fabric8ConfigMapPropertySourceLocator = fabric8ConfigMapPropertySourceLocator;
|
||||
this.watches = new HashMap<>();
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
// Ensure the kubernetes client is cleaned up from spare threads when shutting
|
||||
// down
|
||||
this.kubernetesClient.close();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void watch() {
|
||||
boolean activated = false;
|
||||
@@ -107,8 +119,9 @@ public class EventBasedConfigMapChangeDetector extends ConfigurationChangeDetect
|
||||
}
|
||||
|
||||
protected void onEvent(ConfigMap configMap) {
|
||||
boolean changed = changed(locateMapPropertySources(this.configMapPropertySourceLocator, this.environment),
|
||||
findPropertySources(ConfigMapPropertySource.class));
|
||||
boolean changed = changed(
|
||||
locateMapPropertySources(this.fabric8ConfigMapPropertySourceLocator, this.environment),
|
||||
findPropertySources(Fabric8ConfigMapPropertySource.class));
|
||||
if (changed) {
|
||||
this.log.info("Detected change in config maps");
|
||||
reloadProperties();
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.reload;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.reload;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -28,8 +28,11 @@ import io.fabric8.kubernetes.client.KubernetesClientException;
|
||||
import io.fabric8.kubernetes.client.Watch;
|
||||
import io.fabric8.kubernetes.client.Watcher;
|
||||
|
||||
import org.springframework.cloud.kubernetes.config.SecretsPropertySource;
|
||||
import org.springframework.cloud.kubernetes.config.SecretsPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8SecretsPropertySource;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8SecretsPropertySourceLocator;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
|
||||
/**
|
||||
@@ -42,19 +45,28 @@ import org.springframework.core.env.AbstractEnvironment;
|
||||
*/
|
||||
public class EventBasedSecretsChangeDetector extends ConfigurationChangeDetector {
|
||||
|
||||
private SecretsPropertySourceLocator secretsPropertySourceLocator;
|
||||
private Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator;
|
||||
|
||||
private Map<String, Watch> watches;
|
||||
|
||||
private KubernetesClient kubernetesClient;
|
||||
|
||||
public EventBasedSecretsChangeDetector(AbstractEnvironment environment, ConfigReloadProperties properties,
|
||||
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy,
|
||||
SecretsPropertySourceLocator secretsPropertySourceLocator) {
|
||||
super(environment, properties, kubernetesClient, strategy);
|
||||
|
||||
this.secretsPropertySourceLocator = secretsPropertySourceLocator;
|
||||
Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator) {
|
||||
super(environment, properties, strategy);
|
||||
this.kubernetesClient = kubernetesClient;
|
||||
this.fabric8SecretsPropertySourceLocator = fabric8SecretsPropertySourceLocator;
|
||||
this.watches = new HashMap<>();
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
// Ensure the kubernetes client is cleaned up from spare threads when shutting
|
||||
// down
|
||||
this.kubernetesClient.close();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void watch() {
|
||||
boolean activated = false;
|
||||
@@ -107,8 +119,8 @@ public class EventBasedSecretsChangeDetector extends ConfigurationChangeDetector
|
||||
}
|
||||
|
||||
protected void onEvent(Secret secret) {
|
||||
boolean changed = changed(locateMapPropertySources(this.secretsPropertySourceLocator, this.environment),
|
||||
findPropertySources(SecretsPropertySource.class));
|
||||
boolean changed = changed(locateMapPropertySources(this.fabric8SecretsPropertySourceLocator, this.environment),
|
||||
findPropertySources(Fabric8SecretsPropertySource.class));
|
||||
if (changed) {
|
||||
this.log.info("Detected change in secrets");
|
||||
reloadProperties();
|
||||
@@ -0,0 +1,4 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.kubernetes.fabric8.config.reload.ConfigReloadAutoConfiguration
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.kubernetes.fabric8.config.Fabric8BootstrapConfiguration
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@@ -31,12 +31,11 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example.App;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.example.App;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.assertj.core.util.Lists.newArrayList;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.createFileWithContent;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class,
|
||||
@@ -86,10 +85,11 @@ public class ConfigMapsFromFilePathsTests {
|
||||
System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test");
|
||||
System.setProperty(Config.KUBERNETES_HTTP2_DISABLE, "true");
|
||||
Files.createDirectories(Paths.get(FILES_ROOT_PATH + "/" + FILES_SUB_PATH));
|
||||
createFileWithContent(FIRST_FILE_NAME_FULL_PATH, "bean.greeting=Hello from path!");
|
||||
createFileWithContent(SECOND_FILE_NAME_FULL_PATH, "bean.farewell=Bye from path!");
|
||||
createFileWithContent(UNUSED_FILE_NAME_FULL_PATH, "bean.morning=Morning from path!");
|
||||
createFileWithContent(FIRST_FILE_NAME_DUPLICATED_FULL_PATH, "bean.bonjour=Bonjour from path!");
|
||||
ConfigMapTestUtil.createFileWithContent(FIRST_FILE_NAME_FULL_PATH, "bean.greeting=Hello from path!");
|
||||
ConfigMapTestUtil.createFileWithContent(SECOND_FILE_NAME_FULL_PATH, "bean.farewell=Bye from path!");
|
||||
ConfigMapTestUtil.createFileWithContent(UNUSED_FILE_NAME_FULL_PATH, "bean.morning=Morning from path!");
|
||||
ConfigMapTestUtil.createFileWithContent(FIRST_FILE_NAME_DUPLICATED_FULL_PATH,
|
||||
"bean.bonjour=Bonjour from path!");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@@ -33,12 +33,11 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example.App;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.example.App;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.assertj.core.util.Lists.newArrayList;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class,
|
||||
@@ -76,7 +75,8 @@ public class ConfigMapsMixedTests {
|
||||
System.setProperty(Config.KUBERNETES_HTTP2_DISABLE, "true");
|
||||
|
||||
Files.createDirectories(Paths.get(FILES_ROOT_PATH));
|
||||
ConfigMapTestUtil.createFileWithContent(FILE_NAME_FULL_PATH, readResourceFile("application-path.yaml"));
|
||||
ConfigMapTestUtil.createFileWithContent(FILE_NAME_FULL_PATH,
|
||||
ConfigMapTestUtil.readResourceFile("application-path.yaml"));
|
||||
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
data.put("bean.morning", "Buenos Dias ConfigMap, %s");
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
|
||||
import static org.springframework.cloud.kubernetes.fabric8.config.ConfigMapTestUtil.readResourceFile;
|
||||
|
||||
/**
|
||||
* @author Charles Moulliard
|
||||
@@ -74,8 +74,8 @@ public class ConfigMapsTest {
|
||||
.addToData("application.properties", readResourceFile("application.properties")).build())
|
||||
.once();
|
||||
|
||||
ConfigMapPropertySource cmps = new ConfigMapPropertySource(this.server.getClient().inNamespace(namespace),
|
||||
configMapName);
|
||||
Fabric8ConfigMapPropertySource cmps = new Fabric8ConfigMapPropertySource(
|
||||
this.server.getClient().inNamespace(namespace), configMapName);
|
||||
|
||||
assertThat(cmps.getProperty("dummy.property.string1")).isEqualTo("a");
|
||||
assertThat(cmps.getProperty("dummy.property.int1")).isEqualTo("1");
|
||||
@@ -91,8 +91,8 @@ public class ConfigMapsTest {
|
||||
.addToData("application.yaml", readResourceFile("application.yaml")).build())
|
||||
.once();
|
||||
|
||||
ConfigMapPropertySource cmps = new ConfigMapPropertySource(this.server.getClient().inNamespace(namespace),
|
||||
configMapName);
|
||||
Fabric8ConfigMapPropertySource cmps = new Fabric8ConfigMapPropertySource(
|
||||
this.server.getClient().inNamespace(namespace), configMapName);
|
||||
|
||||
assertThat(cmps.getProperty("dummy.property.string2")).isEqualTo("a");
|
||||
assertThat(cmps.getProperty("dummy.property.int2")).isEqualTo(1);
|
||||
@@ -108,8 +108,8 @@ public class ConfigMapsTest {
|
||||
.addToData("adhoc.yml", readResourceFile("adhoc.yml")).build())
|
||||
.once();
|
||||
|
||||
ConfigMapPropertySource cmps = new ConfigMapPropertySource(this.server.getClient().inNamespace(namespace),
|
||||
configMapName);
|
||||
Fabric8ConfigMapPropertySource cmps = new Fabric8ConfigMapPropertySource(
|
||||
this.server.getClient().inNamespace(namespace), configMapName);
|
||||
|
||||
assertThat(cmps.getProperty("dummy.property.string3")).isEqualTo("a");
|
||||
assertThat(cmps.getProperty("dummy.property.int3")).isEqualTo(1);
|
||||
@@ -125,7 +125,7 @@ public class ConfigMapsTest {
|
||||
.addToData("application.properties", "somevalue").build())
|
||||
.once();
|
||||
|
||||
new ConfigMapPropertySource(this.server.getClient().inNamespace(namespace), configMapName);
|
||||
new Fabric8ConfigMapPropertySource(this.server.getClient().inNamespace(namespace), configMapName);
|
||||
|
||||
// no exception is thrown for unparseable content
|
||||
}
|
||||
@@ -139,7 +139,7 @@ public class ConfigMapsTest {
|
||||
.addToData("application.yaml", "somevalue").build())
|
||||
.once();
|
||||
|
||||
new ConfigMapPropertySource(this.server.getClient().inNamespace(namespace), configMapName);
|
||||
new Fabric8ConfigMapPropertySource(this.server.getClient().inNamespace(namespace), configMapName);
|
||||
|
||||
// no exception is thrown for unparseable content
|
||||
}
|
||||
@@ -155,8 +155,8 @@ public class ConfigMapsTest {
|
||||
.addToData("adhoc.properties", readResourceFile("adhoc.properties")).build())
|
||||
.once();
|
||||
|
||||
ConfigMapPropertySource cmps = new ConfigMapPropertySource(this.server.getClient().inNamespace(namespace),
|
||||
configMapName);
|
||||
Fabric8ConfigMapPropertySource cmps = new Fabric8ConfigMapPropertySource(
|
||||
this.server.getClient().inNamespace(namespace), configMapName);
|
||||
|
||||
// application.properties should be read correctly
|
||||
assertThat(cmps.getProperty("dummy.property.string1")).isEqualTo("a");
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -31,7 +31,7 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example.App;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.example.App;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -30,13 +30,13 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example.App;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.example.App;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
|
||||
import static org.springframework.cloud.kubernetes.fabric8.config.ConfigMapTestUtil.readResourceFile;
|
||||
|
||||
/**
|
||||
* @author Ali Shahbour
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -30,13 +30,11 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example.App;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.example.App;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
|
||||
|
||||
/**
|
||||
* Tests reading property from YAML document specified by profile expression.
|
||||
*/
|
||||
@@ -68,7 +66,7 @@ public class ConfigMapsWithProfileExpressionTests {
|
||||
System.setProperty(Config.KUBERNETES_HTTP2_DISABLE, "true");
|
||||
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
data.put("application.yml", readResourceFile("application-with-profiles.yaml"));
|
||||
data.put("application.yml", ConfigMapTestUtil.readResourceFile("application-with-profiles.yaml"));
|
||||
server.expect().withPath("/api/v1/namespaces/test/configmaps/" + APPLICATION_NAME)
|
||||
.andReturn(200, new ConfigMapBuilder().withNewMetadata().withName(APPLICATION_NAME).endMetadata()
|
||||
.addToData(data).build())
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -30,11 +30,11 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example.App;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.example.App;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
|
||||
import static org.springframework.cloud.kubernetes.fabric8.config.ConfigMapTestUtil.readResourceFile;
|
||||
|
||||
/**
|
||||
* @author Charles Moulliard
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -30,13 +30,11 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example.App;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.example.App;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
|
||||
|
||||
/**
|
||||
* @author Charles Moulliard
|
||||
*/
|
||||
@@ -73,7 +71,7 @@ public class ConfigMapsWithProfilesTests {
|
||||
System.setProperty(Config.KUBERNETES_HTTP2_DISABLE, "true");
|
||||
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
data.put("application.yml", readResourceFile("application-with-profiles.yaml"));
|
||||
data.put("application.yml", ConfigMapTestUtil.readResourceFile("application-with-profiles.yaml"));
|
||||
server.expect().withPath("/api/v1/namespaces/test/configmaps/" + APPLICATION_NAME)
|
||||
.andReturn(200, new ConfigMapBuilder().withNewMetadata().withName(APPLICATION_NAME).endMetadata()
|
||||
.addToData(data).build())
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -30,13 +30,11 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example.App;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.example.App;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = {
|
||||
"spring.application.name=configmap-without-profile-example", "spring.cloud.kubernetes.reload.enabled=false" })
|
||||
@@ -67,7 +65,7 @@ public class ConfigMapsWithoutProfilesTests {
|
||||
System.setProperty(Config.KUBERNETES_HTTP2_DISABLE, "true");
|
||||
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
data.put("application.yml", readResourceFile("application-without-profiles.yaml"));
|
||||
data.put("application.yml", ConfigMapTestUtil.readResourceFile("application-without-profiles.yaml"));
|
||||
server.expect().withPath("/api/v1/namespaces/test/configmaps/" + APPLICATION_NAME)
|
||||
.andReturn(200, new ConfigMapBuilder().withNewMetadata().withName(APPLICATION_NAME).endMetadata()
|
||||
.addToData(data).build())
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example.App;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.example.App;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
@@ -41,7 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class)
|
||||
@TestPropertySource("classpath:/application-secrets.properties")
|
||||
public class SecretsPropertySourceTest {
|
||||
public class Fabric8SecretsPropertySourceTest {
|
||||
|
||||
private static final String NAMESPACE = "test";
|
||||
|
||||
@@ -51,7 +51,7 @@ public class SecretsPropertySourceTest {
|
||||
public static KubernetesServer server = new KubernetesServer(false, true);
|
||||
|
||||
@Autowired
|
||||
private SecretsPropertySourceLocator propertySourceLocator;
|
||||
private Fabric8SecretsPropertySourceLocator propertySourceLocator;
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
@@ -27,7 +27,7 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example.App;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.example.App;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.junit.After;
|
||||
@@ -23,7 +23,7 @@ import org.junit.Test;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
|
||||
import org.springframework.cloud.kubernetes.config.reload.ConfigReloadAutoConfiguration;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.reload.ConfigReloadAutoConfiguration;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -124,7 +124,7 @@ public class KubernetesConfigConfigurationTest {
|
||||
|
||||
private void setup(String... env) {
|
||||
this.context = new SpringApplicationBuilder(PropertyPlaceholderAutoConfiguration.class,
|
||||
KubernetesClientTestConfiguration.class, BootstrapConfiguration.class,
|
||||
KubernetesClientTestConfiguration.class, Fabric8BootstrapConfiguration.class,
|
||||
ConfigReloadAutoConfiguration.class, RefreshAutoConfiguration.class)
|
||||
.web(org.springframework.boot.WebApplicationType.NONE).properties(env).run();
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -31,7 +31,7 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example2.ExampleApp;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.example2.ExampleApp;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
@@ -33,7 +33,7 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.config.example3.MultiSecretsApp;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.example3.MultiSecretsApp;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.example;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.example;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.example;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.example;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.example;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.example;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.example;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.example;
|
||||
|
||||
/**
|
||||
* @author Charles Moulliard
|
||||
@@ -14,11 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.example2;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.example2;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.example.App;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@@ -27,7 +28,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
public class ExampleApp {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(org.springframework.cloud.kubernetes.config.example.App.class, args);
|
||||
SpringApplication.run(App.class, args);
|
||||
}
|
||||
|
||||
@RestController
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.example2;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.example2;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.example3;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.example3;
|
||||
|
||||
/**
|
||||
* @author Haytham Mohamed
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.example3;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.example3;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@@ -14,17 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.reload;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.reload;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationChangeDetector;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
@@ -33,7 +35,7 @@ import org.springframework.core.env.MapPropertySource;
|
||||
*/
|
||||
public class ConfigurationChangeDetectorTest {
|
||||
|
||||
private final ConfigurationChangeDetectorStub stub = new ConfigurationChangeDetectorStub(null, null, null, null);
|
||||
private final ConfigurationChangeDetectorStub stub = new ConfigurationChangeDetectorStub(null, null, null);
|
||||
|
||||
@Test
|
||||
public void testChangedTwoNulls() {
|
||||
@@ -122,8 +124,8 @@ public class ConfigurationChangeDetectorTest {
|
||||
private static final class ConfigurationChangeDetectorStub extends ConfigurationChangeDetector {
|
||||
|
||||
private ConfigurationChangeDetectorStub(ConfigurableEnvironment environment, ConfigReloadProperties properties,
|
||||
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy) {
|
||||
super(environment, properties, kubernetesClient, strategy);
|
||||
ConfigurationUpdateStrategy strategy) {
|
||||
super(environment, properties, strategy);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.config.reload;
|
||||
package org.springframework.cloud.kubernetes.fabric8.config.reload;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -29,8 +29,10 @@ import io.fabric8.kubernetes.client.dsl.Resource;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.cloud.bootstrap.config.BootstrapPropertySource;
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySource;
|
||||
import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySource;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigMapPropertySourceLocator;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -59,14 +61,16 @@ public class EventBasedConfigurationChangeDetectorTests {
|
||||
when(mixedOperation.withName(eq("myconfigmap"))).thenReturn(resource);
|
||||
when(k8sClient.configMaps()).thenReturn(mixedOperation);
|
||||
|
||||
ConfigMapPropertySource configMapPropertySource = new ConfigMapPropertySource(k8sClient, "myconfigmap");
|
||||
env.getPropertySources().addFirst(new BootstrapPropertySource(configMapPropertySource));
|
||||
Fabric8ConfigMapPropertySource fabric8ConfigMapPropertySource = new Fabric8ConfigMapPropertySource(k8sClient,
|
||||
"myconfigmap");
|
||||
env.getPropertySources().addFirst(new BootstrapPropertySource(fabric8ConfigMapPropertySource));
|
||||
|
||||
ConfigurationUpdateStrategy configurationUpdateStrategy = mock(ConfigurationUpdateStrategy.class);
|
||||
ConfigMapPropertySourceLocator configMapLocator = mock(ConfigMapPropertySourceLocator.class);
|
||||
Fabric8ConfigMapPropertySourceLocator configMapLocator = mock(Fabric8ConfigMapPropertySourceLocator.class);
|
||||
EventBasedConfigMapChangeDetector detector = new EventBasedConfigMapChangeDetector(env, configReloadProperties,
|
||||
k8sClient, configurationUpdateStrategy, configMapLocator);
|
||||
List<ConfigMapPropertySource> sources = detector.findPropertySources(ConfigMapPropertySource.class);
|
||||
List<Fabric8ConfigMapPropertySource> sources = detector
|
||||
.findPropertySources(Fabric8ConfigMapPropertySource.class);
|
||||
assertThat(sources.size()).isEqualTo(1);
|
||||
assertThat(sources.get(0).getProperty("foo")).isEqualTo("bar");
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user