diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java index 22072bb696..8c2201f73c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java @@ -16,6 +16,7 @@ import io.javaoperatorsdk.operator.api.config.ConfigurationServiceOverrider; import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; import io.javaoperatorsdk.operator.api.config.ControllerConfigurationOverrider; +import io.javaoperatorsdk.operator.api.config.UpdatableConfigurationService; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.processing.Controller; import io.javaoperatorsdk.operator.processing.LifecycleAware; @@ -26,7 +27,7 @@ public class Operator implements LifecycleAware { private final ControllerManager controllerManager; private final LeaderElectionManager leaderElectionManager; - private final ConfigurationService configurationService; + private final UpdatableConfigurationService configurationService; private volatile boolean started = false; public Operator() { @@ -45,7 +46,7 @@ public Operator() { * @param configurationService a {@link ConfigurationService} providing the configuration for the * operator */ - public Operator(ConfigurationService configurationService) { + public Operator(UpdatableConfigurationService configurationService) { this.configurationService = configurationService; final var executorServiceManager = configurationService.getExecutorServiceManager(); @@ -65,7 +66,7 @@ public Operator(Consumer overrider) { this(initConfigurationService(null, overrider)); } - private static ConfigurationService initConfigurationService( + private static UpdatableConfigurationService initConfigurationService( KubernetesClient client, Consumer overrider) { // initialize the client if the user didn't provide one if (client == null) { @@ -82,7 +83,7 @@ private static ConfigurationService initConfigurationService( overrider = o -> o.withKubernetesClient(kubernetesClient); } - return ConfigurationService.newOverriddenConfigurationService(overrider); + return UpdatableConfigurationService.newOverriddenConfigurationService(overrider); } /** @@ -209,6 +210,12 @@ public

RegisteredController

register( + configurationService.getKnownReconcilerNames()); } + // update the reconciler's configuration in the ConfigurationService if needed + final var existing = configurationService.getConfigurationFor(reconciler); + if (!configuration.equals(existing)) { + configurationService.replace(configuration); + } + final var controller = new Controller<>(reconciler, configuration, getKubernetesClient()); controllerManager.add(controller); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/AbstractConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/AbstractConfigurationService.java index 5abe6a7d03..1b2ea8f544 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/AbstractConfigurationService.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/AbstractConfigurationService.java @@ -14,7 +14,7 @@ * An abstract implementation of {@link ConfigurationService} meant to ease custom implementations */ @SuppressWarnings("rawtypes") -public class AbstractConfigurationService implements ConfigurationService { +public class AbstractConfigurationService implements UpdatableConfigurationService { private final Map configurations = new ConcurrentHashMap<>(); private final Version version; private KubernetesClient client; @@ -71,7 +71,7 @@ public AbstractConfigurationService( protected void init( Cloner cloner, ExecutorServiceManager executorServiceManager, KubernetesClient client) { this.client = client; - this.cloner = cloner != null ? cloner : ConfigurationService.super.getResourceCloner(); + this.cloner = cloner != null ? cloner : UpdatableConfigurationService.super.getResourceCloner(); this.executorServiceManager = executorServiceManager; } @@ -79,7 +79,8 @@ protected void register(ControllerConfiguration confi put(config, true); } - protected void replace(ControllerConfiguration config) { + @Override + public void replace(ControllerConfiguration config) { put(config, false); } @@ -162,7 +163,7 @@ public Cloner getResourceCloner() { public KubernetesClient getKubernetesClient() { // lazy init to avoid needing initializing a client when not needed (in tests, in particular) if (client == null) { - client = ConfigurationService.super.getKubernetesClient(); + client = UpdatableConfigurationService.super.getKubernetesClient(); } return client; } @@ -171,7 +172,7 @@ public KubernetesClient getKubernetesClient() { public ExecutorServiceManager getExecutorServiceManager() { // lazy init to avoid initializing thread pools for nothing in an overriding scenario if (executorServiceManager == null) { - executorServiceManager = ConfigurationService.super.getExecutorServiceManager(); + executorServiceManager = UpdatableConfigurationService.super.getExecutorServiceManager(); } return executorServiceManager; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/UpdatableConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/UpdatableConfigurationService.java new file mode 100644 index 0000000000..de1b4a27cb --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/UpdatableConfigurationService.java @@ -0,0 +1,20 @@ +package io.javaoperatorsdk.operator.api.config; + +import java.util.function.Consumer; + +import io.fabric8.kubernetes.api.model.HasMetadata; + +public interface UpdatableConfigurationService extends ConfigurationService { + void replace(ControllerConfiguration config); + + static UpdatableConfigurationService newOverriddenConfigurationService( + Consumer overrider) { + final var baseConfiguration = new BaseConfigurationService(); + if (overrider != null) { + final var toOverride = new ConfigurationServiceOverrider(baseConfiguration); + overrider.accept(toOverride); + return (UpdatableConfigurationService) toOverride.build(); + } + return baseConfiguration; + } +} diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/OperatorTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/OperatorTest.java index 9bdd54ca8d..fc7989076b 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/OperatorTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/OperatorTest.java @@ -1,5 +1,7 @@ package io.javaoperatorsdk.operator; +import java.util.Set; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -51,6 +53,15 @@ void shouldBePossibleToRetrieveRegisteredControllerByName() { assertEquals(maybeController.get(), registeredControllers.stream().findFirst().orElseThrow()); } + @Test + void overriddenConfigurationShouldBeUpdatedInConfigurationService() { + final var reconciler = new FooReconciler(); + operator.register(new FooReconciler(), override -> override.settingNamespace("test")); + final var config = operator.getConfigurationService().getConfigurationFor(reconciler); + final var namespaces = config.getInformerConfig().getNamespaces(); + assertEquals(Set.of("test"), namespaces); + } + @ControllerConfiguration private static class FooReconciler implements Reconciler {