Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

Expand Down Expand Up @@ -45,6 +46,7 @@
import org.springframework.core.log.LogAccessor;

import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.createApiClientForInformerClient;
import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.labelSelector;
import static org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigUtils.namespaces;

/**
Expand Down Expand Up @@ -73,6 +75,8 @@ public class KubernetesClientEventBasedConfigMapChangeDetector extends Configura

private final boolean monitoringConfigMaps;

private final Map<String, String> configMapsLabels;

private final ResourceEventHandler<V1ConfigMap> handler = new ResourceEventHandler<>() {

@Override
Expand Down Expand Up @@ -113,6 +117,7 @@ public KubernetesClientEventBasedConfigMapChangeDetector(CoreV1Api coreV1Api, Co
this.apiClient = createApiClientForInformerClient();
this.enableReloadFiltering = properties.enableReloadFiltering();
this.monitoringConfigMaps = properties.monitoringConfigMaps();
this.configMapsLabels = properties.configMapsLabels();
namespaces = namespaces(kubernetesNamespaceProvider, properties, "configmap");
}

Expand All @@ -122,13 +127,19 @@ void inform() {
if (monitoringConfigMaps) {
LOG.info(() -> "Kubernetes event-based configMap change detector activated");

String filter;
Map<String, String> labelSelector;

if (enableReloadFiltering) {
filter = ConfigReloadProperties.RELOAD_LABEL_FILTER + "=true";
LOG.warn(() -> "enable reload filtering is deprecated and will be removed in the next major release");
LOG.warn(() -> "use spring.cloud.kubernetes.reload.config-maps-labels instead");
if (!configMapsLabels.isEmpty()) {
LOG.warn(() -> "spring.cloud.kubernetes.reload.config-maps-labels is not empty, but "
+ "spring.cloud.kubernetes.reload.enable-reload-filtering is enabled and will override the former");
}
labelSelector = Map.of(ConfigReloadProperties.RELOAD_LABEL_FILTER, "true");
}
else {
filter = null;
labelSelector = configMapsLabels;
}

namespaces.forEach(namespace -> {
Expand All @@ -141,10 +152,10 @@ void inform() {
.timeoutSeconds(params.timeoutSeconds)
.resourceVersion(params.resourceVersion)
.watch(params.watch)
.labelSelector(filter)
.labelSelector(labelSelector(labelSelector))
.buildCall(null), V1ConfigMap.class, V1ConfigMapList.class);

LOG.debug(() -> "added configmap informer for namespace : " + namespace + " with filter : " + filter);
LOG.debug(() -> "configmap informer for namespace : " + namespace + " with filter : " + labelSelector);

informer.addEventHandler(handler);
informers.add(informer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.springframework.core.log.LogAccessor;

import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.createApiClientForInformerClient;
import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.labelSelector;
import static org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigUtils.namespaces;

/**
Expand Down Expand Up @@ -75,6 +76,8 @@ public class KubernetesClientEventBasedSecretsChangeDetector extends Configurati

private final boolean monitoringSecrets;

private final Map<String, String> secretsLabels;

private final ResourceEventHandler<V1Secret> handler = new ResourceEventHandler<>() {

@Override
Expand Down Expand Up @@ -116,20 +119,27 @@ public KubernetesClientEventBasedSecretsChangeDetector(CoreV1Api coreV1Api, Conf
this.apiClient = createApiClientForInformerClient();
this.enableReloadFiltering = properties.enableReloadFiltering();
this.monitoringSecrets = properties.monitoringSecrets();
this.secretsLabels = properties.secretsLabels();
namespaces = namespaces(kubernetesNamespaceProvider, properties, "secret");
}

@PostConstruct
void inform() {
LOG.info(() -> "Kubernetes event-based secrets change detector activated");

String filter;
Map<String, String> labelSelector;

if (enableReloadFiltering) {
filter = ConfigReloadProperties.RELOAD_LABEL_FILTER + "=true";
LOG.warn(() -> "enable reload filtering is deprecated and will be removed in the next major release");
LOG.warn(() -> "use spring.cloud.kubernetes.secrets-labels instead");
if (!secretsLabels.isEmpty()) {
LOG.warn(() -> "spring.cloud.kubernetes.reload.secrets-labels is not empty, but "
+ "spring.cloud.kubernetes.reload.enable-reload-filtering is enabled and will override the former");
}
labelSelector = Map.of(ConfigReloadProperties.RELOAD_LABEL_FILTER, "true");
}
else {
filter = null;
labelSelector = secretsLabels;
}

if (monitoringSecrets) {
Expand All @@ -143,10 +153,10 @@ void inform() {
.timeoutSeconds(params.timeoutSeconds)
.resourceVersion(params.resourceVersion)
.watch(params.watch)
.labelSelector(filter)
.labelSelector(labelSelector(labelSelector))
.buildCall(null), V1Secret.class, V1SecretList.class);

LOG.debug(() -> "added secret informer for namespace : " + namespace + " with filter : " + filter);
LOG.debug(() -> "secret informer for namespace : " + namespace + " with filter : " + secretsLabels);

informer.addEventHandler(handler);
informers.add(informer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,21 @@
package org.springframework.cloud.kubernetes.commons.config.reload;

import java.time.Duration;
import java.util.Map;
import java.util.Set;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.ConstructorBinding;
import org.springframework.boot.context.properties.bind.DefaultValue;

/**
* General configuration for the configuration reload.
*
* @param enabled Enables the Kubernetes configuration reload on change.
* @param monitoringConfigMaps Enables monitoring on secrets to detect changes.
* @param configMapsLabels Labels for which to watch config maps.
* @param monitoringSecrets Monitor secrets or not.
* @param secretsLabels Labels for which to watch secrets for.
* @param strategy Sets reload strategy for Kubernetes configuration reload on change.
* @param mode Sets the detection mode for Kubernetes configuration reload.
* @param period Sets the polling period to use when the detection mode is POLLING.
Expand All @@ -44,22 +48,54 @@
* @author Nicola Ferraro
*/
@ConfigurationProperties(prefix = "spring.cloud.kubernetes.reload")
public record ConfigReloadProperties(boolean enabled, @DefaultValue("true") boolean monitoringConfigMaps,
boolean monitoringSecrets, @DefaultValue("REFRESH") ReloadStrategy strategy,
@DefaultValue("EVENT") ReloadDetectionMode mode, @DefaultValue("15000ms") Duration period,
@DefaultValue Set<String> namespaces, boolean enableReloadFiltering,
@DefaultValue("2s") Duration maxWaitForRestart) {
public record ConfigReloadProperties(boolean enabled, boolean monitoringConfigMaps,
Map<String, String> configMapsLabels, boolean monitoringSecrets, Map<String, String> secretsLabels,
ReloadStrategy strategy, ReloadDetectionMode mode, Duration period, Set<String> namespaces,
boolean enableReloadFiltering, Duration maxWaitForRestart) {

@ConstructorBinding
public ConfigReloadProperties(boolean enabled, @DefaultValue("true") boolean monitoringConfigMaps,
@DefaultValue Map<String, String> configMapsLabels, boolean monitoringSecrets,
@DefaultValue Map<String, String> secretsLabels, @DefaultValue("REFRESH") ReloadStrategy strategy,
@DefaultValue("EVENT") ReloadDetectionMode mode, @DefaultValue("15000ms") Duration period,
@DefaultValue Set<String> namespaces, boolean enableReloadFiltering,
@DefaultValue("2s") Duration maxWaitForRestart) {

this.enabled = enabled;
this.monitoringConfigMaps = monitoringConfigMaps;
this.configMapsLabels = configMapsLabels;
this.monitoringSecrets = monitoringSecrets;
this.secretsLabels = secretsLabels;
this.strategy = strategy;
this.mode = mode;
this.period = period;
this.namespaces = namespaces;
this.enableReloadFiltering = enableReloadFiltering;
this.maxWaitForRestart = maxWaitForRestart;
}

@Deprecated(forRemoval = true)
public ConfigReloadProperties(boolean enabled, @DefaultValue("true") boolean monitoringConfigMaps,
boolean monitoringSecrets, @DefaultValue("REFRESH") ReloadStrategy strategy,
@DefaultValue("EVENT") ReloadDetectionMode mode, @DefaultValue("15000ms") Duration period,
@DefaultValue Set<String> namespaces, boolean enableReloadFiltering,
@DefaultValue("2s") Duration maxWaitForRestart) {

this(enabled, monitoringConfigMaps, Map.of(), monitoringSecrets, Map.of(), strategy, mode, period, namespaces,
enableReloadFiltering, maxWaitForRestart);
}

/**
* default instance.
*/
public static ConfigReloadProperties DEFAULT = new ConfigReloadProperties(false, true, false,
ReloadStrategy.REFRESH, ReloadDetectionMode.EVENT, Duration.ofMillis(15000), Set.of(), false,
public static final ConfigReloadProperties DEFAULT = new ConfigReloadProperties(false, true, Map.of(), false,
Map.of(), ReloadStrategy.REFRESH, ReloadDetectionMode.EVENT, Duration.ofMillis(15000), Set.of(), false,
Duration.ofSeconds(2));

/**
* label for filtering sources.
*/
@Deprecated(forRemoval = true)
public static final String RELOAD_LABEL_FILTER = "spring.cloud.kubernetes.config.informer.enabled";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,38 @@
package org.springframework.cloud.kubernetes.commons.config;

import java.time.Duration;
import java.util.Map;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
import org.springframework.context.annotation.Configuration;

import static org.assertj.core.api.Assertions.assertThat;

/**
* @author wind57
*
* Tests binding, since we moved from a class to a record
*/
class ConfigReloadPropertiesTests {

@Test
void testDefaults() {
new ApplicationContextRunner().withUserConfiguration(Config.class).run(context -> {
ConfigReloadProperties properties = context.getBean(ConfigReloadProperties.class);
Assertions.assertThat(properties).isNotNull();
Assertions.assertThat(properties.enabled()).isFalse();
Assertions.assertThat(properties.monitoringConfigMaps()).isTrue();
Assertions.assertThat(properties.monitoringSecrets()).isFalse();
Assertions.assertThat(ConfigReloadProperties.ReloadStrategy.REFRESH).isEqualTo(properties.strategy());
Assertions.assertThat(ConfigReloadProperties.ReloadDetectionMode.EVENT).isEqualTo(properties.mode());
Assertions.assertThat(Duration.ofMillis(15000)).isEqualTo(properties.period());
Assertions.assertThat(properties.namespaces().isEmpty()).isTrue();
Assertions.assertThat(Duration.ofSeconds(2)).isEqualTo(properties.maxWaitForRestart());
assertThat(properties).isNotNull();
assertThat(properties.enabled()).isFalse();
assertThat(properties.monitoringConfigMaps()).isTrue();
assertThat(properties.configMapsLabels()).isEmpty();
assertThat(properties.monitoringSecrets()).isFalse();
assertThat(properties.secretsLabels()).isEmpty();
assertThat(ConfigReloadProperties.ReloadStrategy.REFRESH).isEqualTo(properties.strategy());
assertThat(ConfigReloadProperties.ReloadDetectionMode.EVENT).isEqualTo(properties.mode());
assertThat(Duration.ofMillis(15000)).isEqualTo(properties.period());
assertThat(properties.namespaces().isEmpty()).isTrue();
assertThat(properties.enableReloadFiltering()).isFalse();
assertThat(Duration.ofSeconds(2)).isEqualTo(properties.maxWaitForRestart());
});
}

Expand All @@ -54,22 +57,28 @@ void testNonDefaults() {
new ApplicationContextRunner().withUserConfiguration(Config.class)
.withPropertyValues("spring.cloud.kubernetes.reload.enabled=true",
"spring.cloud.kubernetes.reload.monitoring-config-maps=false",
"spring.cloud.kubernetes.reload.config-maps-labels[aa]=bb",
"spring.cloud.kubernetes.reload.monitoring-secrets=true",
"spring.cloud.kubernetes.reload.secrets-labels[cc]=dd",
"spring.cloud.kubernetes.reload.strategy=SHUTDOWN", "spring.cloud.kubernetes.reload.mode=POLLING",
"spring.cloud.kubernetes.reload.period=1000ms", "spring.cloud.kubernetes.reload.namespaces[0]=a",
"spring.cloud.kubernetes.reload.namespaces[1]=b",
"spring.cloud.kubernetes.reload.enable-reload-filtering=true",
"spring.cloud.kubernetes.reload.max-wait-for-restart=5s")
.run(context -> {
ConfigReloadProperties properties = context.getBean(ConfigReloadProperties.class);
Assertions.assertThat(properties).isNotNull();
Assertions.assertThat(properties.enabled()).isTrue();
Assertions.assertThat(properties.monitoringConfigMaps()).isFalse();
Assertions.assertThat(properties.monitoringSecrets()).isTrue();
Assertions.assertThat(ConfigReloadProperties.ReloadStrategy.SHUTDOWN).isEqualTo(properties.strategy());
Assertions.assertThat(ConfigReloadProperties.ReloadDetectionMode.POLLING).isEqualTo(properties.mode());
Assertions.assertThat(Duration.ofMillis(1000)).isEqualTo(properties.period());
Assertions.assertThat(properties.namespaces()).containsExactlyInAnyOrder("a", "b");
Assertions.assertThat(Duration.ofSeconds(5)).isEqualTo(properties.maxWaitForRestart());
assertThat(properties).isNotNull();
assertThat(properties.enabled()).isTrue();
assertThat(properties.monitoringConfigMaps()).isFalse();
assertThat(properties.configMapsLabels()).containsExactlyInAnyOrderEntriesOf(Map.of("aa", "bb"));
assertThat(properties.monitoringSecrets()).isTrue();
assertThat(properties.secretsLabels()).containsExactlyInAnyOrderEntriesOf(Map.of("cc", "dd"));
assertThat(ConfigReloadProperties.ReloadStrategy.SHUTDOWN).isEqualTo(properties.strategy());
assertThat(ConfigReloadProperties.ReloadDetectionMode.POLLING).isEqualTo(properties.mode());
assertThat(Duration.ofMillis(1000)).isEqualTo(properties.period());
assertThat(properties.namespaces()).containsExactlyInAnyOrder("a", "b");
assertThat(properties.enableReloadFiltering()).isTrue();
assertThat(Duration.ofSeconds(5)).isEqualTo(properties.maxWaitForRestart());
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ public class Fabric8EventBasedConfigMapChangeDetector extends ConfigurationChang

private final boolean monitorConfigMaps;

private final Map<String, String> configMapsLabels;

public Fabric8EventBasedConfigMapChangeDetector(AbstractEnvironment environment, ConfigReloadProperties properties,
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy,
Fabric8ConfigMapPropertySourceLocator fabric8ConfigMapPropertySourceLocator,
Expand All @@ -80,6 +82,7 @@ public Fabric8EventBasedConfigMapChangeDetector(AbstractEnvironment environment,
this.fabric8ConfigMapPropertySourceLocator = fabric8ConfigMapPropertySourceLocator;
this.enableReloadFiltering = properties.enableReloadFiltering();
this.monitorConfigMaps = properties.monitoringConfigMaps();
this.configMapsLabels = properties.configMapsLabels();
namespaces = namespaces(kubernetesClient, namespaceProvider, properties, "configmap");
}

Expand All @@ -92,10 +95,16 @@ private void inform() {
Map<String, String> labelSelector;

if (enableReloadFiltering) {
LOG.warn(() -> "enable reload filtering is deprecated and will be removed in the next major release");
LOG.warn(() -> "use spring.cloud.kubernetes.reload.config-maps-labels instead");
if (!configMapsLabels.isEmpty()) {
LOG.warn(() -> "spring.cloud.kubernetes.reload.config-maps-labels is not empty, but "
+ "spring.cloud.kubernetes.reload.enable-reload-filtering is enabled and will override the former");
}
labelSelector = Map.of(ConfigReloadProperties.RELOAD_LABEL_FILTER, "true");
}
else {
labelSelector = Map.of();
labelSelector = configMapsLabels;
}

namespaces.forEach(namespace -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ public class Fabric8EventBasedSecretsChangeDetector extends ConfigurationChangeD

private final boolean monitorSecrets;

private final Map<String, String> secretsLabels;

public Fabric8EventBasedSecretsChangeDetector(AbstractEnvironment environment, ConfigReloadProperties properties,
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy,
Fabric8SecretsPropertySourceLocator fabric8SecretsPropertySourceLocator,
Expand All @@ -80,6 +82,7 @@ public Fabric8EventBasedSecretsChangeDetector(AbstractEnvironment environment, C
this.fabric8SecretsPropertySourceLocator = fabric8SecretsPropertySourceLocator;
this.enableReloadFiltering = properties.enableReloadFiltering();
this.monitorSecrets = properties.monitoringSecrets();
secretsLabels = properties.configMapsLabels();
namespaces = namespaces(kubernetesClient, namespaceProvider, properties, "secrets");
}

Expand All @@ -100,10 +103,16 @@ private void inform() {
Map<String, String> labelSelector;

if (enableReloadFiltering) {
LOG.warn(() -> "enable reload filtering is deprecated and will be removed in the next major release");
LOG.warn(() -> "use spring.cloud.kubernetes.secrets-labels instead");
if (!secretsLabels.isEmpty()) {
LOG.warn(() -> "spring.cloud.kubernetes.reload.secrets-labels is not empty, but "
+ "spring.cloud.kubernetes.reload.enable-reload-filtering is enabled and will override the former");
}
labelSelector = Map.of(ConfigReloadProperties.RELOAD_LABEL_FILTER, "true");
}
else {
labelSelector = Map.of();
labelSelector = secretsLabels;
}

namespaces.forEach(namespace -> {
Expand Down
Loading