Issue #635 - Decouples configMap and secret property source locators by making the… (#639)

* Decouples configMap and secret property source locators by making them optional dependencies for reload auto config as they could be enabled/disabled through config independent of each other. Fixes #635

* make ConfigurationChangeDetector conditional. only required if one of configMaps or secrets are enabled. Add Null checks for event/polling for the existence of an appropriate PropertySourceLocator

* Add ConditionalOnBean for propertyChangeWatcher to be consistent with configuration. Add tests

* remove sop

* fix checkstyle errors

* add additional classes to SpringApplicationBuilder and context

* introduce AnyNestedCondition to allow for the propertyChangeWatcher to be registered when either secrets or config or both are enabled.
This commit is contained in:
Krishnakumar Iyer
2020-09-23 15:57:49 -04:00
committed by GitHub
parent ca8b89bf38
commit 1043636b49
4 changed files with 91 additions and 18 deletions

View File

@@ -24,6 +24,8 @@ 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.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -36,6 +38,7 @@ import org.springframework.cloud.kubernetes.config.ConfigMapPropertySourceLocato
import org.springframework.cloud.kubernetes.config.SecretsPropertySourceLocator;
import org.springframework.context.ConfigurableApplicationContext;
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;
@@ -71,32 +74,28 @@ public class ConfigReloadAutoConfiguration {
@Autowired
private KubernetesClient kubernetesClient;
@Autowired
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
@Autowired
private SecretsPropertySourceLocator secretsPropertySourceLocator;
/**
* @param properties config reload properties
* @param strategy configuration update strategy
* @return a bean that listen to configuration changes and fire a reload.
*/
@Bean
@ConditionalOnMissingBean
@Conditional(OnConfigEnabledOrSecretsEnabled.class)
public ConfigurationChangeDetector propertyChangeWatcher(
ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy) {
ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy,
@Autowired(
required = false) ConfigMapPropertySourceLocator configMapPropertySourceLocator,
@Autowired(
required = false) SecretsPropertySourceLocator secretsPropertySourceLocator) {
switch (properties.getMode()) {
case POLLING:
return new PollingConfigurationChangeDetector(this.environment,
properties, this.kubernetesClient, strategy,
this.configMapPropertySourceLocator,
this.secretsPropertySourceLocator);
configMapPropertySourceLocator, secretsPropertySourceLocator);
case EVENT:
return new EventBasedConfigurationChangeDetector(this.environment,
properties, this.kubernetesClient, strategy,
this.configMapPropertySourceLocator,
this.secretsPropertySourceLocator);
configMapPropertySourceLocator, secretsPropertySourceLocator);
}
throw new IllegalStateException(
"Unsupported configuration reload mode: " + properties.getMode());
@@ -147,6 +146,24 @@ public class ConfigReloadAutoConfiguration {
}
}
private static class OnConfigEnabledOrSecretsEnabled extends AnyNestedCondition {
OnConfigEnabledOrSecretsEnabled() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnBean(ConfigMapPropertySourceLocator.class)
static class configEnabled {
}
@ConditionalOnBean(SecretsPropertySourceLocator.class)
static class secretsEnabled {
}
}
}
}

View File

@@ -66,7 +66,8 @@ public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDe
public void watch() {
boolean activated = false;
if (this.properties.isMonitoringConfigMaps()) {
if (this.properties.isMonitoringConfigMaps()
&& this.configMapPropertySourceLocator != null) {
try {
String name = "config-maps-watch";
this.watches.put(name, this.kubernetesClient.configMaps()
@@ -91,7 +92,8 @@ public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDe
}
}
if (this.properties.isMonitoringSecrets()) {
if (this.properties.isMonitoringSecrets()
&& this.secretsPropertySourceLocator != null) {
try {
activated = false;
String name = "secrets-watch";

View File

@@ -68,7 +68,8 @@ public class PollingConfigurationChangeDetector extends ConfigurationChangeDetec
public void executeCycle() {
boolean changedConfigMap = false;
if (this.properties.isMonitoringConfigMaps()) {
if (this.properties.isMonitoringConfigMaps()
&& this.configMapPropertySourceLocator != null) {
List<? extends MapPropertySource> currentConfigMapSources = findPropertySources(
ConfigMapPropertySource.class);
@@ -81,7 +82,8 @@ public class PollingConfigurationChangeDetector extends ConfigurationChangeDetec
}
boolean changedSecrets = false;
if (this.properties.isMonitoringSecrets()) {
if (this.properties.isMonitoringSecrets()
&& this.secretsPropertySourceLocator != null) {
List<MapPropertySource> currentSecretSources = locateMapPropertySources(
this.secretsPropertySourceLocator, this.environment);
if (currentSecretSources != null && !currentSecretSources.isEmpty()) {

View File

@@ -22,6 +22,8 @@ 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.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -51,13 +53,31 @@ public class KubernetesConfigConfigurationTest {
}
@Test
public void kubernetesWhenKubernetesConfigDisabled() throws Exception {
public void kubernetesWhenKubernetesConfigAndSecretDisabled() throws Exception {
setup("spring.cloud.kubernetes.config.enabled=false",
"spring.cloud.kubernetes.secrets.enabled=false");
assertThat(this.context.containsBean("configMapPropertySourceLocator")).isFalse();
assertThat(this.context.containsBean("secretsPropertySourceLocator")).isFalse();
}
@Test
public void kubernetesWhenKubernetesConfigEnabledButSecretDisabled()
throws Exception {
setup("spring.cloud.kubernetes.config.enabled=true",
"spring.cloud.kubernetes.secrets.enabled=false");
assertThat(this.context.containsBean("configMapPropertySourceLocator")).isTrue();
assertThat(this.context.containsBean("secretsPropertySourceLocator")).isFalse();
}
@Test
public void kubernetesWhenKubernetesConfigDisabledButSecretEnabled()
throws Exception {
setup("spring.cloud.kubernetes.config.enabled=false",
"spring.cloud.kubernetes.secrets.enabled=true");
assertThat(this.context.containsBean("configMapPropertySourceLocator")).isFalse();
assertThat(this.context.containsBean("secretsPropertySourceLocator")).isTrue();
}
@Test
public void kubernetesDefaultEnabled() throws Exception {
setup("spring.cloud.kubernetes.enabled=true");
@@ -65,10 +85,42 @@ public class KubernetesConfigConfigurationTest {
assertThat(this.context.containsBean("secretsPropertySourceLocator")).isTrue();
}
@Test
public void kubernetesReloadEnabled() throws Exception {
setup("spring.cloud.kubernetes.enabled=true",
"spring.cloud.kubernetes.reload.enabled=true");
assertThat(this.context.containsBean("configMapPropertySourceLocator")).isTrue();
assertThat(this.context.containsBean("secretsPropertySourceLocator")).isTrue();
assertThat(this.context.containsBean("propertyChangeWatcher")).isTrue();
}
@Test
public void kubernetesReloadEnabledButSecretDisabled() throws Exception {
setup("spring.cloud.kubernetes.enabled=true",
"spring.cloud.kubernetes.config.enabled=true",
"spring.cloud.kubernetes.secrets.enabled=false",
"spring.cloud.kubernetes.reload.enabled=true");
assertThat(this.context.containsBean("configMapPropertySourceLocator")).isTrue();
assertThat(this.context.containsBean("secretsPropertySourceLocator")).isFalse();
assertThat(this.context.containsBean("propertyChangeWatcher")).isTrue();
}
@Test
public void kubernetesReloadEnabledButSecretAndConfigDisabled() throws Exception {
setup("spring.cloud.kubernetes.enabled=true",
"spring.cloud.kubernetes.config.enabled=false",
"spring.cloud.kubernetes.secrets.enabled=false",
"spring.cloud.kubernetes.reload.enabled=true");
assertThat(this.context.containsBean("configMapPropertySourceLocator")).isFalse();
assertThat(this.context.containsBean("secretsPropertySourceLocator")).isFalse();
assertThat(this.context.containsBean("propertyChangeWatcher")).isFalse();
}
private void setup(String... env) {
this.context = new SpringApplicationBuilder(
PropertyPlaceholderAutoConfiguration.class,
KubernetesClientTestConfiguration.class, BootstrapConfiguration.class)
KubernetesClientTestConfiguration.class, BootstrapConfiguration.class,
ConfigReloadAutoConfiguration.class, RefreshAutoConfiguration.class)
.web(org.springframework.boot.WebApplicationType.NONE)
.properties(env).run();
}