org.zodic.kubernetes.confcenter.reload.EventBasedConfigurationChangeDetector Maven / Gradle / Ivy
package org.zodic.kubernetes.confcenter.reload;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.PreDestroy;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.Watch;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.kubernetes.client.WatcherException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.zodiac.sdk.toolkit.util.collection.CollUtil;
import org.zodic.kubernetes.confcenter.ConfigMapPropertySource;
import org.zodic.kubernetes.confcenter.ConfigMapPropertySourceLocator;
import org.zodic.kubernetes.confcenter.SecretsPropertySource;
import org.zodic.kubernetes.confcenter.SecretsPropertySourceLocator;
public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDetector implements InitializingBean {
private final AtomicBoolean watched = new AtomicBoolean();
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
private SecretsPropertySourceLocator secretsPropertySourceLocator;
private Map watches;
public EventBasedConfigurationChangeDetector(AbstractEnvironment environment, ConfigReloadInfo configReloadInfo,
KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy,
ConfigMapPropertySourceLocator configMapPropertySourceLocator,
SecretsPropertySourceLocator secretsPropertySourceLocator) {
super(environment, configReloadInfo, kubernetesClient, strategy);
this.configMapPropertySourceLocator = configMapPropertySourceLocator;
this.secretsPropertySourceLocator = secretsPropertySourceLocator;
this.watches = CollUtil.map();
}
@Override
public void afterPropertiesSet() throws Exception {
watch();
}
public void watch() {
if (watched.compareAndSet(false, true)) {
boolean activated = false;
if (this.configReloadInfo.isMonitoringConfigMaps()) {
try {
String name = "config-maps-watch";
this.watches.put(name, this.kubernetesClient.configMaps().watch(new Watcher() {
@Override
public void eventReceived(Action action, ConfigMap configMap) {
onEvent(configMap);
}
@Override
public void onClose(WatcherException cause) {}
}));
activated = true;
log.info("Added new Kubernetes watch: {} .", name);
} catch (Exception e) {
log.error(
"Error while establishing a connection to watch config maps: configuration may remain stale", e);
}
}
if (this.configReloadInfo.isMonitoringSecrets()) {
try {
activated = false;
String name = "secrets-watch";
this.watches.put(name, this.kubernetesClient.secrets().watch(new Watcher() {
@Override
public void eventReceived(Action action, Secret secret) {
onEvent(secret);
}
@Override
public void onClose(WatcherException cause) {}
}));
activated = true;
log.info("Added new Kubernetes watch: {} .", name);
} catch (Exception e) {
this.log.error("Error while establishing a connection to watch secrets: configuration may remain stale",
e);
}
}
if (activated) {
log.info("Kubernetes event-based configuration change detector activated");
}
}
}
@PreDestroy
public void unwatch() {
if (this.watches != null) {
for (Map.Entry entry : this.watches.entrySet()) {
try {
this.log.debug("Closing the watch " + entry.getKey());
entry.getValue().close();
} catch (Exception e) {
this.log.error("Error while closing the watch connection", e);
}
}
}
}
private void onEvent(ConfigMap configMap) {
boolean changed = changed(locateMapPropertySources(this.configMapPropertySourceLocator, this.environment),
findPropertySources(ConfigMapPropertySource.class));
if (changed) {
this.log.info("Detected change in config maps");
reloadProperties();
}
}
private void onEvent(Secret secret) {
MapPropertySource currentSecretSource = findPropertySource(SecretsPropertySource.class);
if (currentSecretSource != null) {
MapPropertySource newSecretSource = this.secretsPropertySourceLocator.locatePropertySource(this.environment);
if (changed(currentSecretSource, newSecretSource)) {
this.log.info("Detected change in secrets");
reloadProperties();
}
}
}
}