Skip to content

Commit

Permalink
Merge branch 'main' into fabric8-leader-election
Browse files Browse the repository at this point in the history
  • Loading branch information
wind57 committed Nov 9, 2024
2 parents 8fe3240 + 0355d7a commit 5e157bc
Show file tree
Hide file tree
Showing 20 changed files with 129 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
= `PropertySource` Reload

WARNING: This functionality has been deprecated in the 2020.0 release. Please see
the xref:spring-cloud-kubernetes-configuration-watcher.adoc#spring-cloud-kubernetes-configuration-watcher[null] controller for an alternative way
to achieve the same functionality.
the xref:spring-cloud-kubernetes-configuration-watcher.adoc#spring-cloud-kubernetes-configuration-watcher[Spring Cloud Kubernetes Configuration Watcher]
controller for an alternative way to achieve the same functionality.

Some applications may need to detect changes on external property sources and update their internal status to reflect the new configuration.
The reload feature of Spring Cloud Kubernetes is able to trigger an application reload when a related `ConfigMap` or
Expand Down
2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"dependencies": {
"antora": "3.2.0-alpha.4",
"@antora/atlas-extension": "1.0.0-alpha.2",
"@antora/collector-extension": "1.0.0-beta.3",
"@antora/collector-extension": "1.0.0-beta.4",
"@asciidoctor/tabs": "1.0.0-beta.6",
"@springio/antora-extensions": "1.11.1",
"@springio/asciidoctor-extensions": "1.0.0-alpha.14"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ private static List<StrippedSourceContainer> strippedConfigMaps(CoreV1Api coreV1
private static List<StrippedSourceContainer> strippedSecrets(CoreV1Api coreV1Api, String namespace) {
List<StrippedSourceContainer> strippedSecrets = KubernetesClientSecretsCache.byNamespace(coreV1Api, namespace);
if (strippedSecrets.isEmpty()) {
LOG.debug("No configmaps in namespace '" + namespace + "'");
LOG.debug("No secrets in namespace '" + namespace + "'");
}
return strippedSecrets;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ public PropertySource<?> locate(Environment environment) {
if (this.properties.enableApi()) {
Set<NormalizedSource> sources = new LinkedHashSet<>(this.properties.determineSources(environment));
LOG.debug("Config Map normalized sources : " + sources);
sources.forEach(s -> composite.addFirstPropertySource(getMapPropertySource(s, env)));
sources.forEach(s -> {
MapPropertySource propertySource = getMapPropertySource(s, env);
LOG.debug("Adding config map property source " + propertySource.getName());
composite.addFirstPropertySource(propertySource);
});
}

addPropertySourcesFromPaths(environment, composite);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public final class ConfigUtils {
|| sourceName.endsWith("-" + activeProfile + ".yaml")
|| sourceName.endsWith("-" + activeProfile + ".properties");

private static final ApplicationListener<?> NO_OP = (e) -> { };
private static final ApplicationListener<?> NO_OP = (e) -> {
};

private ConfigUtils() {
}
Expand Down Expand Up @@ -209,7 +210,7 @@ public static MultipleSourcesContainer processNamedData(List<StrippedSourceConta
sourceNames.forEach(sourceName -> {
StrippedSourceContainer stripped = hashByName.get(sourceName);
if (stripped != null) {
LOG.debug("Found source with name : '" + sourceName + " in namespace: '" + namespace + "'");
LOG.debug("Found source with name : '" + sourceName + "' in namespace: '" + namespace + "'");
foundSourceNames.add(sourceName);
// see if data is a single yaml/properties file and if it needs decoding
Map<String, String> rawData = stripped.data();
Expand All @@ -228,6 +229,9 @@ public static MultipleSourcesContainer processNamedData(List<StrippedSourceConta
environment, includeDefaultProfileData));
}
}
else {
LOG.warn("sourceName : " + sourceName + " was requested, but not found in namespace : " + namespace);
}
});

return new MultipleSourcesContainer(foundSourceNames, data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ public final SourceData compute(Map<String, String> labels, ConfigUtils.Prefix p
data = dataSupplier(labels, profiles);

// need this check because when there is no data, the name of the property
// source
// is using provided labels,
// source is using provided labels,
// unlike when the data is present: when we use secret names
if (data.names().isEmpty()) {
String names = labels.keySet()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
package org.springframework.cloud.kubernetes.commons.config;

import java.util.LinkedHashSet;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.onException;
import static org.springframework.cloud.kubernetes.commons.config.Constants.PROPERTY_SOURCE_NAME_SEPARATOR;

Expand All @@ -31,6 +33,8 @@
*/
public abstract class NamedSourceData {

private static final Log LOG = LogFactory.getLog(NamedSourceData.class);

public final SourceData compute(String sourceName, ConfigUtils.Prefix prefix, String target, boolean profileSources,
boolean failFast, String namespace, String[] activeProfiles) {

Expand All @@ -51,7 +55,9 @@ public final SourceData compute(String sourceName, ConfigUtils.Prefix prefix, St
data = dataSupplier(sourceNames);

if (data.names().isEmpty()) {
return new SourceData(ConfigUtils.sourceName(target, sourceName, namespace), Map.of());
String emptySourceName = ConfigUtils.sourceName(target, sourceName, namespace);
LOG.debug("Will return empty source with name : " + emptySourceName);
return SourceData.emptyRecord(emptySourceName);
}

if (prefix != ConfigUtils.Prefix.DEFAULT) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
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;

/**
Expand Down Expand Up @@ -87,8 +88,11 @@ public PropertySource<?> locate(Environment environment) {
putPathConfig(composite);

if (this.properties.enableApi()) {
uniqueSources
.forEach(s -> composite.addPropertySource(getSecretsPropertySourceForSingleSecret(env, s)));
uniqueSources.forEach(s -> {
MapPropertySource propertySource = getSecretsPropertySourceForSingleSecret(env, s);
LOG.debug("Adding secret property source " + propertySource.getName());
composite.addFirstPropertySource(propertySource);
});
}

cache.discardAll();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package org.springframework.cloud.kubernetes.commons.config;

import java.util.Collections;
import java.util.Map;

/**
Expand All @@ -25,10 +24,10 @@
*
* @author wind57
*/
public final record SourceData(String sourceName, Map<String, Object> sourceData) {
public record SourceData(String sourceName, Map<String, Object> sourceData) {

public static SourceData emptyRecord(String sourceName) {
return new SourceData(sourceName, Collections.emptyMap());
return new SourceData(sourceName, Map.of());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class SourceDataEntriesProcessor extends MapPropertySource {

private static final Log LOG = LogFactory.getLog(SourceDataEntriesProcessor.class);

private static Predicate<String> ENDS_IN_EXTENSION = x -> x.endsWith(".yml") || x.endsWith(".yaml")
private static final Predicate<String> ENDS_IN_EXTENSION = x -> x.endsWith(".yml") || x.endsWith(".yaml")
|| x.endsWith(".properties");

public SourceDataEntriesProcessor(SourceData sourceData) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,31 @@ private ConfigReloadUtil() {

private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(ConfigReloadUtil.class));

public static boolean reload(String target, String eventSourceType, PropertySourceLocator locator,
/**
* used for the event based reloading.
*/
public static boolean reload(String target, String sourceAsString, PropertySourceLocator locator,
ConfigurableEnvironment environment, Class<? extends MapPropertySource> existingSourcesType) {
LOG.debug(() -> "onEvent " + target + ": " + eventSourceType);
LOG.debug(() -> "onEvent " + target + ": " + sourceAsString);

return reload(locator, environment, existingSourcesType);
}

/**
* used for the poll based reloading.
*/
public static boolean reload(PropertySourceLocator locator, ConfigurableEnvironment environment,
Class<? extends MapPropertySource> existingSourcesType) {

List<? extends MapPropertySource> sourceFromK8s = locateMapPropertySources(locator, environment);
List<? extends MapPropertySource> existingSources = findPropertySources(existingSourcesType, environment);

if (existingSources.isEmpty()) {
LOG.debug(() -> "no existingSources found, reload will not happen");
return false;
}

List<? extends MapPropertySource> sourceFromK8s = locateMapPropertySources(locator, environment);

boolean changed = changed(sourceFromK8s, existingSources);
if (changed) {
LOG.info("Detected change in config maps/secrets");
Expand All @@ -67,7 +85,9 @@ public static boolean reload(String target, String eventSourceType, PropertySour
* @param <S> property source type
* @param sourceClass class for which property sources will be found
* @return finds all registered property sources of the given type
* @deprecated this method will not be public in the next major release.
*/
@Deprecated(forRemoval = false)
public static <S extends PropertySource<?>> List<S> findPropertySources(Class<S> sourceClass,
ConfigurableEnvironment environment) {
List<S> managedSources = new ArrayList<>();
Expand Down Expand Up @@ -141,25 +161,25 @@ else if (propertySource instanceof CompositePropertySource source) {
return result;
}

static boolean changed(List<? extends MapPropertySource> left, List<? extends MapPropertySource> right) {
if (left.size() != right.size()) {
static boolean changed(List<? extends MapPropertySource> k8sSources, List<? extends MapPropertySource> appSources) {
if (k8sSources.size() != appSources.size()) {
if (LOG.isDebugEnabled()) {
LOG.debug("left size: " + left.size());
left.forEach(item -> LOG.debug(item.toString()));
LOG.debug("k8s property sources size: " + k8sSources.size());
k8sSources.forEach(item -> LOG.debug(item.toString()));

LOG.debug("right size: " + right.size());
right.forEach(item -> LOG.debug(item.toString()));
LOG.debug("app property sources size size: " + appSources.size());
appSources.forEach(item -> LOG.debug(item.toString()));
}
LOG.warn(() -> "The current number of ConfigMap PropertySources does not match "
LOG.warn(() -> "The current number of PropertySources does not match "
+ "the ones loaded from Kubernetes - No reload will take place");
return false;
}

for (int i = 0; i < left.size(); i++) {
MapPropertySource leftPropertySource = left.get(i);
MapPropertySource rightPropertySource = right.get(i);
if (changed(leftPropertySource, rightPropertySource)) {
LOG.debug(() -> "found change in : " + leftPropertySource);
for (int i = 0; i < k8sSources.size(); i++) {
MapPropertySource k8sSource = k8sSources.get(i);
MapPropertySource appSource = appSources.get(i);
if (changed(k8sSource, appSource)) {
LOG.debug(() -> "found change in : " + k8sSource);
return true;
}
}
Expand All @@ -169,20 +189,20 @@ static boolean changed(List<? extends MapPropertySource> left, List<? extends Ma

/**
* Determines if two property sources are different.
* @param left left map property sources
* @param right right map property sources
* @param k8sSource left map property sources
* @param appSource right map property sources
* @return {@code true} if source has changed
*/
static boolean changed(MapPropertySource left, MapPropertySource right) {
if (left == right) {
static boolean changed(MapPropertySource k8sSource, MapPropertySource appSource) {
if (k8sSource == appSource) {
return false;
}
if (left == null || right == null) {
if (k8sSource == null || appSource == null) {
return true;
}
Map<String, Object> leftMap = left.getSource();
Map<String, Object> rightMap = right.getSource();
return !Objects.equals(leftMap, rightMap);
Map<String, Object> k8sMap = k8sSource.getSource();
Map<String, Object> appMap = appSource.getSource();
return !Objects.equals(k8sMap, appMap);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package org.springframework.cloud.kubernetes.commons.config.reload;

import java.time.Duration;
import java.util.List;

import jakarta.annotation.PostConstruct;
import org.apache.commons.logging.Log;
Expand All @@ -29,10 +28,6 @@
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.PeriodicTrigger;

import static org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadUtil.changed;
import static org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadUtil.findPropertySources;
import static org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadUtil.locateMapPropertySources;

/**
* A change detector that periodically retrieves configmaps and fire a reload when
* something changes.
Expand Down Expand Up @@ -75,23 +70,13 @@ private void init() {
}

private void executeCycle() {

boolean changedConfigMap = false;
if (monitorConfigMaps) {
log.debug("Polling for changes in config maps");
List<? extends MapPropertySource> currentConfigMapSources = findPropertySources(propertySourceClass,
environment);

if (!currentConfigMapSources.isEmpty()) {
changedConfigMap = changed(locateMapPropertySources(this.propertySourceLocator, this.environment),
currentConfigMapSources);
boolean changedConfigMap = ConfigReloadUtil.reload(propertySourceLocator, environment, propertySourceClass);
if (changedConfigMap) {
log.info("Detected change in config maps");
reloadProperties();
}
}

if (changedConfigMap) {
log.info("Detected change in config maps");
reloadProperties();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package org.springframework.cloud.kubernetes.commons.config.reload;

import java.time.Duration;
import java.util.List;

import jakarta.annotation.PostConstruct;
import org.apache.commons.logging.Log;
Expand All @@ -29,10 +28,6 @@
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.PeriodicTrigger;

import static org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadUtil.changed;
import static org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadUtil.findPropertySources;
import static org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadUtil.locateMapPropertySources;

/**
* A change detector that periodically retrieves secrets and fires a reload when something
* changes.
Expand Down Expand Up @@ -75,23 +70,13 @@ private void init() {
}

private void executeCycle() {

boolean changedSecrets = false;
if (monitorSecrets) {
log.debug("Polling for changes in secrets");
List<MapPropertySource> currentSecretSources = locateMapPropertySources(this.propertySourceLocator,
this.environment);
if (!currentSecretSources.isEmpty()) {
List<? extends MapPropertySource> propertySources = findPropertySources(propertySourceClass,
environment);
changedSecrets = changed(currentSecretSources, propertySources);
boolean changedSecrets = ConfigReloadUtil.reload(propertySourceLocator, environment, propertySourceClass);
if (changedSecrets) {
log.info("Detected change in secrets");
reloadProperties();
}
}

if (changedSecrets) {
log.info("Detected change in secrets");
reloadProperties();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.1</version>
<version>3.5.2</version>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.5.1</version>
<version>3.5.2</version>
</plugin>
</plugins>
</build>
Expand Down
Loading

0 comments on commit 5e157bc

Please sign in to comment.