All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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();
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy