diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/AnnotationControllerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/AnnotationControllerConfiguration.java
deleted file mode 100644
index 4e4f945515..0000000000
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/AnnotationControllerConfiguration.java
+++ /dev/null
@@ -1,259 +0,0 @@
-package io.javaoperatorsdk.operator.api.config;
-
-import java.lang.annotation.Annotation;
-import java.time.Duration;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.function.UnaryOperator;
-import java.util.stream.Collectors;
-
-import io.fabric8.kubernetes.api.model.HasMetadata;
-import io.javaoperatorsdk.operator.OperatorException;
-import io.javaoperatorsdk.operator.ReconcilerUtils;
-import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
-import io.javaoperatorsdk.operator.api.reconciler.Constants;
-import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
-import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
-import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
-import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
-import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition;
-import io.javaoperatorsdk.operator.processing.event.rate.RateLimiter;
-import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter;
-import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilters;
-import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter;
-import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter;
-import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter;
-import io.javaoperatorsdk.operator.processing.retry.Retry;
-
-import static io.javaoperatorsdk.operator.api.reconciler.Constants.DEFAULT_NAMESPACES_SET;
-
-@SuppressWarnings("rawtypes")
-public class AnnotationControllerConfiguration
- implements io.javaoperatorsdk.operator.api.config.ControllerConfiguration
{
-
- protected final Reconciler
reconciler;
- private final ControllerConfiguration annotation;
- private List specs;
- private Class resourceClass;
-
- public AnnotationControllerConfiguration(Reconciler
reconciler) {
- this.reconciler = reconciler;
- this.annotation = reconciler.getClass().getAnnotation(ControllerConfiguration.class);
- if (annotation == null) {
- throw new OperatorException(
- "Missing mandatory @" + ControllerConfiguration.class.getSimpleName() +
- " annotation for reconciler: " + reconciler);
- }
- }
-
- @Override
- public String getName() {
- return ReconcilerUtils.getNameFor(reconciler);
- }
-
- @Override
- public String getFinalizerName() {
- if (annotation == null || annotation.finalizerName().isBlank()) {
- return ReconcilerUtils.getDefaultFinalizerName(getResourceClass());
- } else {
- final var finalizer = annotation.finalizerName();
- if (ReconcilerUtils.isFinalizerValid(finalizer)) {
- return finalizer;
- } else {
- throw new IllegalArgumentException(
- finalizer
- + " is not a valid finalizer. See https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#finalizers for details");
- }
- }
- }
-
- @Override
- public boolean isGenerationAware() {
- return valueOrDefault(
- annotation, ControllerConfiguration::generationAwareEventProcessing, true);
- }
-
- @Override
- public Set getNamespaces() {
- return Set.of(valueOrDefault(annotation, ControllerConfiguration::namespaces,
- DEFAULT_NAMESPACES_SET.toArray(String[]::new)));
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public Optional> cachePruneFunction() {
- return Optional.ofNullable(
- Utils.instantiate(annotation.cachePruneFunction(), UnaryOperator.class,
- Utils.contextFor(this, null, null)));
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public Class getResourceClass() {
- if (resourceClass == null) {
- resourceClass =
- (Class
) Utils.getFirstTypeArgumentFromSuperClassOrInterface(reconciler.getClass(),
- Reconciler.class);
- }
- return resourceClass;
- }
-
- @Override
- public String getLabelSelector() {
- return valueOrDefault(annotation, ControllerConfiguration::labelSelector, "");
- }
-
- @Override
- public String getAssociatedReconcilerClassName() {
- return reconciler.getClass().getCanonicalName();
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public ResourceEventFilter
getEventFilter() {
- ResourceEventFilter
answer = null;
-
- Class>[] filterTypes =
- (Class>[]) valueOrDefault(annotation,
- ControllerConfiguration::eventFilters, new Object[] {});
- for (var filterType : filterTypes) {
- try {
- ResourceEventFilter filter = filterType.getConstructor().newInstance();
-
- if (answer == null) {
- answer = filter;
- } else {
- answer = answer.and(filter);
- }
- } catch (Exception e) {
- throw new IllegalArgumentException(e);
- }
- }
- return answer != null ? answer : ResourceEventFilters.passthrough();
- }
-
- @Override
- public Optional maxReconciliationInterval() {
- final var newConfig = annotation.maxReconciliationInterval();
- if (newConfig != null && newConfig.interval() > 0) {
- return Optional.of(Duration.of(newConfig.interval(), newConfig.timeUnit().toChronoUnit()));
- }
- return Optional.empty();
- }
-
- @Override
- public RateLimiter getRateLimiter() {
- final Class extends RateLimiter> rateLimiterClass = annotation.rateLimiter();
- return Utils.instantiateAndConfigureIfNeeded(rateLimiterClass, RateLimiter.class,
- Utils.contextFor(this, null, null), this::configureFromAnnotatedReconciler);
- }
-
- @Override
- public Retry getRetry() {
- final Class extends Retry> retryClass = annotation.retry();
- return Utils.instantiateAndConfigureIfNeeded(retryClass, Retry.class,
- Utils.contextFor(this, null, null), this::configureFromAnnotatedReconciler);
- }
-
-
- @SuppressWarnings("unchecked")
- private void configureFromAnnotatedReconciler(Object instance) {
- if (instance instanceof AnnotationConfigurable) {
- AnnotationConfigurable configurable = (AnnotationConfigurable) instance;
- final Class extends Annotation> configurationClass =
- (Class extends Annotation>) Utils.getFirstTypeArgumentFromSuperClassOrInterface(
- instance.getClass(), AnnotationConfigurable.class);
- final var configAnnotation = reconciler.getClass().getAnnotation(configurationClass);
- if (configAnnotation != null) {
- configurable.initFrom(configAnnotation);
- }
- }
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public Optional> onAddFilter() {
- return Optional.ofNullable(
- Utils.instantiate(annotation.onAddFilter(), OnAddFilter.class,
- Utils.contextFor(this, null, null)));
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Optional> onUpdateFilter() {
- return Optional.ofNullable(
- Utils.instantiate(annotation.onUpdateFilter(), OnUpdateFilter.class,
- Utils.contextFor(this, null, null)));
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Optional> genericFilter() {
- return Optional.ofNullable(
- Utils.instantiate(annotation.genericFilter(), GenericFilter.class,
- Utils.contextFor(this, null, null)));
- }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- @Override
- public List getDependentResources() {
- if (specs == null) {
- final var dependents =
- valueOrDefault(annotation, ControllerConfiguration::dependents, new Dependent[] {});
- if (dependents.length == 0) {
- specs = Collections.emptyList();
- return specs;
- }
-
- final var specsMap = new LinkedHashMap(dependents.length);
- for (Dependent dependent : dependents) {
- final Class extends DependentResource> dependentType = dependent.type();
-
- final var name = getName(dependent, dependentType);
- var spec = specsMap.get(name);
- if (spec != null) {
- throw new IllegalArgumentException(
- "A DependentResource named '" + name + "' already exists: " + spec);
- }
-
- var eventSourceName = dependent.useEventSourceWithName();
- eventSourceName = Constants.NO_VALUE_SET.equals(eventSourceName) ? null : eventSourceName;
- final var context = Utils.contextFor(this, dependentType, null);
- spec = new DependentResourceSpec(dependentType, name,
- Set.of(dependent.dependsOn()),
- Utils.instantiate(dependent.readyPostcondition(), Condition.class, context),
- Utils.instantiate(dependent.reconcilePrecondition(), Condition.class, context),
- Utils.instantiate(dependent.deletePostcondition(), Condition.class, context),
- eventSourceName);
- specsMap.put(name, spec);
- }
-
- specs = specsMap.values().stream().collect(Collectors.toUnmodifiableList());
- }
- return specs;
- }
-
- private String getName(Dependent dependent, Class extends DependentResource> dependentType) {
- var name = dependent.name();
- if (name.isBlank()) {
- name = DependentResource.defaultNameFor(dependentType);
- }
- return name;
- }
-
- public static T valueOrDefault(
- ControllerConfiguration controllerConfiguration,
- Function mapper,
- T defaultValue) {
- if (controllerConfiguration == null) {
- return defaultValue;
- } else {
- return mapper.apply(controllerConfiguration);
- }
- }
-
-}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/BaseConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/BaseConfigurationService.java
index 1e4b535202..db91ee22af 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/BaseConfigurationService.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/BaseConfigurationService.java
@@ -1,13 +1,40 @@
package io.javaoperatorsdk.operator.api.config;
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.javaoperatorsdk.operator.OperatorException;
+import io.javaoperatorsdk.operator.ReconcilerUtils;
+import io.javaoperatorsdk.operator.api.config.Utils.Configurator;
+import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
+import io.javaoperatorsdk.operator.api.reconciler.Constants;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
+import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
+import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
+import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition;
+import io.javaoperatorsdk.operator.processing.event.rate.RateLimiter;
+import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter;
+import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilters;
+import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter;
+import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter;
+import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter;
+import io.javaoperatorsdk.operator.processing.retry.Retry;
import com.fasterxml.jackson.databind.ObjectMapper;
+import static io.javaoperatorsdk.operator.api.reconciler.Constants.DEFAULT_NAMESPACES_SET;
+
public class BaseConfigurationService extends AbstractConfigurationService {
private static final String LOGGER_NAME = "Default ConfigurationService implementation";
@@ -67,8 +94,140 @@ public ControllerConfiguration getConfigurationFor(
return config;
}
- protected ControllerConfiguration configFor(Reconciler reconciler) {
- return new AnnotationControllerConfiguration<>(reconciler);
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ protected ControllerConfiguration
configFor(Reconciler
reconciler) {
+ final var annotation = reconciler.getClass().getAnnotation(
+ io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration.class);
+ if (annotation == null) {
+ throw new OperatorException(
+ "Missing mandatory @"
+ + io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration.class
+ .getSimpleName()
+ +
+ " annotation for reconciler: " + reconciler);
+ }
+
+ final var resourceClass = (Class
) Utils.getFirstTypeArgumentFromSuperClassOrInterface(
+ reconciler.getClass(), Reconciler.class);
+ final var name = ReconcilerUtils.getNameFor(reconciler);
+ final var generationAware = valueOrDefault(
+ annotation,
+ io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration::generationAwareEventProcessing,
+ true);
+ final var associatedReconcilerClass =
+ ResolvedControllerConfiguration.getAssociatedReconcilerClassName(reconciler.getClass());
+
+ final Class extends Retry> retryClass = annotation.retry();
+ final var retry = Utils.instantiateAndConfigureIfNeeded(retryClass, Retry.class,
+ Utils.contextFor(name, null, null), configuratorFor(Retry.class, reconciler));
+
+ final Class extends RateLimiter> rateLimiterClass = annotation.rateLimiter();
+ final var rateLimiter = Utils.instantiateAndConfigureIfNeeded(rateLimiterClass,
+ RateLimiter.class,
+ Utils.contextFor(name, null, null), configuratorFor(RateLimiter.class, reconciler));
+
+ final var reconciliationInterval = annotation.maxReconciliationInterval();
+ long interval = -1;
+ TimeUnit timeUnit = null;
+ if (reconciliationInterval != null && reconciliationInterval.interval() > 0) {
+ interval = reconciliationInterval.interval();
+ timeUnit = reconciliationInterval.timeUnit();
+ }
+
+ final var config = new ResolvedControllerConfiguration
(
+ resourceClass, name, generationAware,
+ associatedReconcilerClass, retry, rateLimiter,
+ ResolvedControllerConfiguration.getMaxReconciliationInterval(interval, timeUnit),
+ Utils.instantiate(annotation.onAddFilter(), OnAddFilter.class,
+ Utils.contextFor(name, null, null)),
+ Utils.instantiate(annotation.onUpdateFilter(), OnUpdateFilter.class,
+ Utils.contextFor(name, null, null)),
+ Utils.instantiate(annotation.genericFilter(), GenericFilter.class,
+ Utils.contextFor(name, null, null)),
+ Utils.instantiate(annotation.cachePruneFunction(), UnaryOperator.class,
+ Utils.contextFor(name, null, null)),
+ Set.of(valueOrDefault(annotation,
+ io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration::namespaces,
+ DEFAULT_NAMESPACES_SET.toArray(String[]::new))),
+ valueOrDefault(annotation,
+ io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration::finalizerName,
+ Constants.NO_VALUE_SET),
+ valueOrDefault(annotation,
+ io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration::labelSelector,
+ Constants.NO_VALUE_SET),
+ null);
+
+ ResourceEventFilter
answer = deprecatedEventFilter(annotation);
+ config.setEventFilter(answer != null ? answer : ResourceEventFilters.passthrough());
+
+ List specs = dependentResources(annotation, config);
+ config.setDependentResources(specs);
+
+ return config;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static ResourceEventFilter
deprecatedEventFilter(
+ io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration annotation) {
+ ResourceEventFilter
answer = null;
+
+ Class>[] filterTypes =
+ (Class>[]) valueOrDefault(annotation,
+ io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration::eventFilters,
+ new Object[] {});
+ for (var filterType : filterTypes) {
+ try {
+ ResourceEventFilter filter = filterType.getConstructor().newInstance();
+
+ if (answer == null) {
+ answer = filter;
+ } else {
+ answer = answer.and(filter);
+ }
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+ return answer;
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private static List dependentResources(
+ io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration annotation,
+ ControllerConfiguration> parent) {
+ final var dependents =
+ valueOrDefault(annotation,
+ io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration::dependents,
+ new Dependent[] {});
+ if (dependents.length == 0) {
+ return Collections.emptyList();
+ }
+
+ final var specsMap = new LinkedHashMap(dependents.length);
+ for (Dependent dependent : dependents) {
+ final Class extends DependentResource> dependentType = dependent.type();
+
+ final var dependentName = getName(dependent.name(), dependentType);
+ var spec = specsMap.get(dependentName);
+ if (spec != null) {
+ throw new IllegalArgumentException(
+ "A DependentResource named '" + dependentName + "' already exists: " + spec);
+ }
+
+ final var name = parent.getName();
+
+ var eventSourceName = dependent.useEventSourceWithName();
+ eventSourceName = Constants.NO_VALUE_SET.equals(eventSourceName) ? null : eventSourceName;
+ final var context = Utils.contextFor(name, dependentType, null);
+ spec = new DependentResourceSpec(dependentType, dependentName,
+ Set.of(dependent.dependsOn()),
+ Utils.instantiate(dependent.readyPostcondition(), Condition.class, context),
+ Utils.instantiate(dependent.reconcilePrecondition(), Condition.class, context),
+ Utils.instantiate(dependent.deletePostcondition(), Condition.class, context),
+ eventSourceName);
+ specsMap.put(dependentName, spec);
+ }
+ return specsMap.values().stream().collect(Collectors.toUnmodifiableList());
}
protected boolean createIfNeeded() {
@@ -79,4 +238,43 @@ protected boolean createIfNeeded() {
public boolean checkCRDAndValidateLocalModel() {
return Utils.shouldCheckCRDAndValidateLocalModel();
}
+
+ private static T valueOrDefault(
+ io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration controllerConfiguration,
+ Function mapper,
+ T defaultValue) {
+ if (controllerConfiguration == null) {
+ return defaultValue;
+ } else {
+ return mapper.apply(controllerConfiguration);
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ private static String getName(String name, Class extends DependentResource> dependentType) {
+ if (name.isBlank()) {
+ name = DependentResource.defaultNameFor(dependentType);
+ }
+ return name;
+ }
+
+ @SuppressWarnings("unused")
+ private static Configurator configuratorFor(Class instanceType,
+ Reconciler> reconciler) {
+ return instance -> configureFromAnnotatedReconciler(instance, reconciler);
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private static void configureFromAnnotatedReconciler(Object instance, Reconciler> reconciler) {
+ if (instance instanceof AnnotationConfigurable) {
+ AnnotationConfigurable configurable = (AnnotationConfigurable) instance;
+ final Class extends Annotation> configurationClass =
+ (Class extends Annotation>) Utils.getFirstTypeArgumentFromSuperClassOrInterface(
+ instance.getClass(), AnnotationConfigurable.class);
+ final var configAnnotation = reconciler.getClass().getAnnotation(configurationClass);
+ if (configAnnotation != null) {
+ configurable.initFrom(configAnnotation);
+ }
+ }
+ }
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java
index 74c40ed9a8..b2640777a7 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java
@@ -17,19 +17,37 @@
import io.javaoperatorsdk.operator.processing.retry.GradualRetry;
import io.javaoperatorsdk.operator.processing.retry.Retry;
-public interface ControllerConfiguration extends ResourceConfiguration {
+public interface ControllerConfiguration extends ResourceConfiguration
{
@SuppressWarnings("rawtypes")
RateLimiter DEFAULT_RATE_LIMITER = LinearRateLimiter.deactivatedRateLimiter();
default String getName() {
- return ReconcilerUtils.getDefaultReconcilerName(getAssociatedReconcilerClassName());
+ return ensureValidName(null, getAssociatedReconcilerClassName());
}
default String getFinalizerName() {
return ReconcilerUtils.getDefaultFinalizerName(getResourceClass());
}
+ static String ensureValidName(String name, String reconcilerClassName) {
+ return name != null ? name : ReconcilerUtils.getDefaultReconcilerName(reconcilerClassName);
+ }
+
+ static String ensureValidFinalizerName(String finalizer, String resourceTypeName) {
+ if (finalizer != null && !finalizer.isBlank()) {
+ if (ReconcilerUtils.isFinalizerValid(finalizer)) {
+ return finalizer;
+ } else {
+ throw new IllegalArgumentException(
+ finalizer
+ + " is not a valid finalizer. See https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#finalizers for details");
+ }
+ } else {
+ return ReconcilerUtils.getDefaultFinalizerName(resourceTypeName);
+ }
+ }
+
default boolean isGenerationAware() {
return true;
}
@@ -70,8 +88,12 @@ default RateLimiter getRateLimiter() {
*
*
* @return filter
+ * @deprecated use {@link ResourceConfiguration#onAddFilter()},
+ * {@link ResourceConfiguration#onUpdateFilter()} or
+ * {@link ResourceConfiguration#genericFilter()} instead
*/
- default ResourceEventFilter getEventFilter() {
+ @Deprecated(forRemoval = true)
+ default ResourceEventFilter getEventFilter() {
return ResourceEventFilters.passthrough();
}
@@ -91,8 +113,8 @@ default ConfigurationService getConfigurationService() {
@SuppressWarnings("unchecked")
@Override
- default Class getResourceClass() {
- return (Class) Utils.getFirstTypeArgumentFromSuperClassOrInterface(getClass(),
+ default Class getResourceClass() {
+ return (Class
) Utils.getFirstTypeArgumentFromSuperClassOrInterface(getClass(),
ControllerConfiguration.class);
}
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java
index 31de28631d..789de127f5 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java
@@ -179,25 +179,14 @@ public ControllerConfigurationOverrider replacingNamedDependentResourceConfig
}
public ControllerConfiguration build() {
- return new DefaultControllerConfiguration<>(
- original.getAssociatedReconcilerClassName(),
- original.getName(),
- original.getResourceTypeName(),
- finalizer,
- generationAware,
- namespaces,
- retry,
- labelSelector,
- customResourcePredicate,
- original.getResourceClass(),
- reconciliationMaxInterval,
- onAddFilter,
- onUpdateFilter,
- genericFilter,
- rateLimiter,
+ final var overridden = new ResolvedControllerConfiguration<>(
+ original.getResourceClass(), original.getName(),
+ generationAware, original.getAssociatedReconcilerClassName(), retry, rateLimiter,
+ reconciliationMaxInterval, onAddFilter, onUpdateFilter, genericFilter, cachePruneFunction,
original.getDependentResources(),
- cachePruneFunction,
- configurations);
+ namespaces, finalizer, labelSelector, configurations);
+ overridden.setEventFilter(customResourcePredicate);
+ return overridden;
}
public static ControllerConfigurationOverrider override(
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultControllerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultControllerConfiguration.java
deleted file mode 100644
index 6dd99ecbe2..0000000000
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultControllerConfiguration.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package io.javaoperatorsdk.operator.api.config;
-
-import java.time.Duration;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.UnaryOperator;
-
-import io.fabric8.kubernetes.api.model.HasMetadata;
-import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfigurationProvider;
-import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
-import io.javaoperatorsdk.operator.processing.event.rate.LinearRateLimiter;
-import io.javaoperatorsdk.operator.processing.event.rate.RateLimiter;
-import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter;
-import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter;
-import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter;
-import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter;
-import io.javaoperatorsdk.operator.processing.retry.Retry;
-
-@SuppressWarnings("rawtypes")
-public class DefaultControllerConfiguration
- extends DefaultResourceConfiguration
- implements ControllerConfiguration, DependentResourceConfigurationProvider {
-
- private final String associatedControllerClassName;
- private final String name;
- private final String crdName;
- private final String finalizer;
- private final boolean generationAware;
- private final Retry retry;
- private final ResourceEventFilter resourceEventFilter;
- private final List dependents;
- private final Duration reconciliationMaxInterval;
- private final RateLimiter rateLimiter;
- private final Map configurations;
-
- // NOSONAR constructor is meant to provide all information
- public DefaultControllerConfiguration(
- String associatedControllerClassName,
- String name,
- String crdName,
- String finalizer,
- boolean generationAware,
- Set namespaces,
- Retry retry,
- String labelSelector,
- ResourceEventFilter resourceEventFilter,
- Class resourceClass,
- Duration reconciliationMaxInterval,
- OnAddFilter onAddFilter,
- OnUpdateFilter onUpdateFilter,
- GenericFilter genericFilter,
- RateLimiter rateLimiter,
- List dependents,
- UnaryOperator cachePruneFunction) {
- this(associatedControllerClassName, name, crdName, finalizer, generationAware, namespaces,
- retry, labelSelector, resourceEventFilter, resourceClass, reconciliationMaxInterval,
- onAddFilter, onUpdateFilter, genericFilter, rateLimiter, dependents, cachePruneFunction,
- null);
- }
-
- DefaultControllerConfiguration(
- String associatedControllerClassName,
- String name,
- String crdName,
- String finalizer,
- boolean generationAware,
- Set namespaces,
- Retry retry,
- String labelSelector,
- ResourceEventFilter resourceEventFilter,
- Class resourceClass,
- Duration reconciliationMaxInterval,
- OnAddFilter onAddFilter,
- OnUpdateFilter onUpdateFilter,
- GenericFilter genericFilter,
- RateLimiter rateLimiter,
- List dependents,
- UnaryOperator cachePruneFunction,
- Map configurations) {
- super(labelSelector, resourceClass, onAddFilter, onUpdateFilter, genericFilter, namespaces,
- cachePruneFunction);
- this.associatedControllerClassName = associatedControllerClassName;
- this.name = name;
- this.crdName = crdName;
- this.finalizer = finalizer;
- this.generationAware = generationAware;
- this.reconciliationMaxInterval = reconciliationMaxInterval;
- this.retry =
- retry == null
- ? ControllerConfiguration.super.getRetry()
- : retry;
- this.resourceEventFilter = resourceEventFilter;
- this.rateLimiter =
- rateLimiter != null ? rateLimiter : LinearRateLimiter.deactivatedRateLimiter();
- this.dependents = dependents != null ? dependents : Collections.emptyList();
- this.configurations = configurations != null ? configurations : Collections.emptyMap();
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public String getResourceTypeName() {
- return crdName;
- }
-
- @Override
- public String getFinalizerName() {
- return finalizer;
- }
-
- @Override
- public boolean isGenerationAware() {
- return generationAware;
- }
-
- @Override
- public String getAssociatedReconcilerClassName() {
- return associatedControllerClassName;
- }
-
- @Override
- public Retry getRetry() {
- return retry;
- }
-
- @Override
- public ResourceEventFilter getEventFilter() {
- return resourceEventFilter;
- }
-
- @Override
- public List getDependentResources() {
- return dependents;
- }
-
- @Override
- public Optional maxReconciliationInterval() {
- return Optional.ofNullable(reconciliationMaxInterval);
- }
-
- @Override
- public RateLimiter getRateLimiter() {
- return rateLimiter;
- }
-
- @Override
- public Object getConfigurationFor(DependentResourceSpec spec) {
- return configurations.get(spec);
- }
-}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java
index 8e42284a25..bb9f365d58 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java
@@ -5,52 +5,41 @@
import java.util.function.UnaryOperator;
import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.javaoperatorsdk.operator.ReconcilerUtils;
import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter;
import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter;
import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter;
-import static io.javaoperatorsdk.operator.api.reconciler.Constants.DEFAULT_NAMESPACES_SET;
-
public class DefaultResourceConfiguration
implements ResourceConfiguration {
- private final String labelSelector;
- private final Set namespaces;
private final Class resourceClass;
+ private final String resourceTypeName;
private final OnAddFilter onAddFilter;
private final OnUpdateFilter onUpdateFilter;
private final GenericFilter genericFilter;
+ private final String labelSelector;
+ private final Set namespaces;
private final UnaryOperator cachePruneFunction;
- public DefaultResourceConfiguration(String labelSelector, Class resourceClass,
- OnAddFilter onAddFilter,
- OnUpdateFilter onUpdateFilter, GenericFilter genericFilter, String... namespaces) {
- this(labelSelector, resourceClass, onAddFilter, onUpdateFilter, genericFilter,
- namespaces == null || namespaces.length == 0 ? DEFAULT_NAMESPACES_SET
- : Set.of(namespaces),
- null);
- }
-
- public DefaultResourceConfiguration(String labelSelector, Class resourceClass,
- OnAddFilter onAddFilter,
- OnUpdateFilter onUpdateFilter,
- GenericFilter genericFilter,
- Set namespaces,
+ protected DefaultResourceConfiguration(Class resourceClass,
+ Set namespaces, String labelSelector, OnAddFilter onAddFilter,
+ OnUpdateFilter onUpdateFilter, GenericFilter genericFilter,
UnaryOperator cachePruneFunction) {
- this.labelSelector = labelSelector;
this.resourceClass = resourceClass;
+ this.resourceTypeName = ReconcilerUtils.getResourceTypeName(resourceClass);
this.onAddFilter = onAddFilter;
this.onUpdateFilter = onUpdateFilter;
this.genericFilter = genericFilter;
- this.namespaces =
- namespaces == null || namespaces.isEmpty() ? DEFAULT_NAMESPACES_SET
- : namespaces;
+
+ this.namespaces = ResourceConfiguration.ensureValidNamespaces(namespaces);
+ this.labelSelector = ResourceConfiguration.ensureValidLabelSelector(labelSelector);
this.cachePruneFunction = cachePruneFunction;
}
@Override
public String getResourceTypeName() {
- return ResourceConfiguration.super.getResourceTypeName();
+ return resourceTypeName;
}
@Override
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ResolvedControllerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ResolvedControllerConfiguration.java
new file mode 100644
index 0000000000..b1f653cb75
--- /dev/null
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ResolvedControllerConfiguration.java
@@ -0,0 +1,169 @@
+package io.javaoperatorsdk.operator.api.config;
+
+import java.time.Duration;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.function.UnaryOperator;
+
+import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfigurationProvider;
+import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
+import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
+import io.javaoperatorsdk.operator.processing.event.rate.RateLimiter;
+import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter;
+import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter;
+import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter;
+import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter;
+import io.javaoperatorsdk.operator.processing.retry.Retry;
+
+@SuppressWarnings("rawtypes")
+public class ResolvedControllerConfiguration
+ extends DefaultResourceConfiguration
+ implements io.javaoperatorsdk.operator.api.config.ControllerConfiguration
,
+ DependentResourceConfigurationProvider {
+
+ private final String name;
+ private final boolean generationAware;
+ private final String associatedReconcilerClassName;
+ private final Retry retry;
+ private final RateLimiter rateLimiter;
+ private final Optional maxReconciliationInterval;
+ private final String finalizer;
+ private final Map configurations;
+
+ private ResourceEventFilter eventFilter;
+ private List dependentResources;
+
+ public ResolvedControllerConfiguration(Class resourceClass, ControllerConfiguration
other) {
+ this(resourceClass, other.getName(), other.isGenerationAware(),
+ other.getAssociatedReconcilerClassName(), other.getRetry(), other.getRateLimiter(),
+ other.maxReconciliationInterval().orElse(null),
+ other.onAddFilter().orElse(null), other.onUpdateFilter().orElse(null),
+ other.genericFilter().orElse(null), other.cachePruneFunction().orElse(null),
+ other.getDependentResources(), other.getNamespaces(),
+ other.getFinalizerName(), other.getLabelSelector(), Collections.emptyMap());
+ }
+
+ public static Duration getMaxReconciliationInterval(long interval, TimeUnit timeUnit) {
+ return interval > 0 ? Duration.of(interval, timeUnit.toChronoUnit()) : null;
+ }
+
+ public static String getAssociatedReconcilerClassName(
+ Class extends Reconciler> reconcilerClass) {
+ return reconcilerClass.getCanonicalName();
+ }
+
+ protected Retry ensureRetry(Retry given) {
+ return given == null ? ControllerConfiguration.super.getRetry() : given;
+ }
+
+ protected RateLimiter ensureRateLimiter(RateLimiter given) {
+ return given == null ? ControllerConfiguration.super.getRateLimiter() : given;
+ }
+
+ public ResolvedControllerConfiguration(Class
resourceClass, String name,
+ boolean generationAware, String associatedReconcilerClassName, Retry retry,
+ RateLimiter rateLimiter, Duration maxReconciliationInterval,
+ OnAddFilter
onAddFilter, OnUpdateFilter
onUpdateFilter,
+ GenericFilter
genericFilter, UnaryOperator
cachePruneFunction,
+ List dependentResources,
+ Set namespaces, String finalizer, String labelSelector,
+ Map configurations) {
+ this(resourceClass, name, generationAware, associatedReconcilerClassName, retry, rateLimiter,
+ maxReconciliationInterval, onAddFilter, onUpdateFilter, genericFilter, cachePruneFunction,
+ namespaces, finalizer, labelSelector, configurations);
+ setDependentResources(dependentResources);
+ }
+
+ protected ResolvedControllerConfiguration(Class resourceClass, String name,
+ boolean generationAware, String associatedReconcilerClassName, Retry retry,
+ RateLimiter rateLimiter, Duration maxReconciliationInterval,
+ OnAddFilter
onAddFilter, OnUpdateFilter
onUpdateFilter, GenericFilter
genericFilter,
+ UnaryOperator
cachePruneFunction,
+ Set namespaces, String finalizer, String labelSelector,
+ Map configurations) {
+ super(resourceClass, namespaces, labelSelector, onAddFilter, onUpdateFilter, genericFilter,
+ cachePruneFunction);
+ this.name = ControllerConfiguration.ensureValidName(name, associatedReconcilerClassName);
+ this.generationAware = generationAware;
+ this.associatedReconcilerClassName = associatedReconcilerClassName;
+ this.retry = ensureRetry(retry);
+ this.rateLimiter = ensureRateLimiter(rateLimiter);
+ this.maxReconciliationInterval = Optional.ofNullable(maxReconciliationInterval);
+ this.configurations = configurations != null ? configurations : Collections.emptyMap();
+
+ this.finalizer =
+ ControllerConfiguration.ensureValidFinalizerName(finalizer, getResourceTypeName());
+ }
+
+ protected ResolvedControllerConfiguration(Class resourceClass, String name,
+ Class extends Reconciler> reconcilerClas) {
+ this(resourceClass, name, false, getAssociatedReconcilerClassName(reconcilerClas), null, null,
+ null, null, null, null, null,
+ null, null, null, null);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getFinalizerName() {
+ return finalizer;
+ }
+
+ @Override
+ public boolean isGenerationAware() {
+ return generationAware;
+ }
+
+ @Override
+ public String getAssociatedReconcilerClassName() {
+ return associatedReconcilerClassName;
+ }
+
+ @Override
+ public Retry getRetry() {
+ return retry;
+ }
+
+ @Override
+ public RateLimiter getRateLimiter() {
+ return rateLimiter;
+ }
+
+ @Override
+ public List getDependentResources() {
+ return dependentResources;
+ }
+
+ protected void setDependentResources(List dependentResources) {
+ this.dependentResources = dependentResources == null ? Collections.emptyList()
+ : Collections.unmodifiableList(dependentResources);
+ }
+
+ @Override
+ public Optional maxReconciliationInterval() {
+ return maxReconciliationInterval;
+ }
+
+ @Override
+ public ResourceEventFilter getEventFilter() {
+ return eventFilter;
+ }
+
+ @Deprecated(forRemoval = true)
+ protected void setEventFilter(ResourceEventFilter
eventFilter) {
+ this.eventFilter = eventFilter;
+ }
+
+ @Override
+ public Object getConfigurationFor(DependentResourceSpec spec) {
+ return configurations.get(spec);
+ }
+}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ResourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ResourceConfiguration.java
index 6a6574182a..85f3bc3b36 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ResourceConfiguration.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ResourceConfiguration.java
@@ -1,5 +1,6 @@
package io.javaoperatorsdk.operator.api.config;
+import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
@@ -47,6 +48,11 @@ default String getLabelSelector() {
return null;
}
+ static String ensureValidLabelSelector(String labelSelector) {
+ // might want to implement validation here?
+ return labelSelector;
+ }
+
@SuppressWarnings("unchecked")
default Class getResourceClass() {
return (Class) Utils.getFirstTypeArgumentFromSuperClassOrInterface(getClass(),
@@ -90,6 +96,14 @@ static void failIfNotValid(Set namespaces) {
+ Constants.WATCH_CURRENT_NAMESPACE + "'");
}
+ static Set ensureValidNamespaces(Collection namespaces) {
+ if (namespaces != null && !namespaces.isEmpty()) {
+ return Set.copyOf(namespaces);
+ } else {
+ return Constants.DEFAULT_NAMESPACES_SET;
+ }
+ }
+
/**
* Computes the effective namespaces based on the set specified by the user, in particular
* retrieves the current namespace from the client when the user specified that they wanted to
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java
index 00927b7f14..5838eb9b97 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java
@@ -227,6 +227,13 @@ public interface Configurator {
public static String contextFor(ControllerConfiguration> controllerConfiguration,
Class extends DependentResource> dependentType,
Class extends Annotation> configurationAnnotation) {
+ return contextFor(controllerConfiguration.getName(), dependentType, configurationAnnotation);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static String contextFor(String reconcilerName,
+ Class extends DependentResource> dependentType,
+ Class extends Annotation> configurationAnnotation) {
final var annotationName =
configurationAnnotation != null ? configurationAnnotation.getSimpleName()
: io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration.class
@@ -235,7 +242,7 @@ public static String contextFor(ControllerConfiguration> controllerConfigurati
if (dependentType != null) {
context += "DependentResource: " + dependentType.getName() + ", ";
}
- context += "reconciler: " + controllerConfiguration.getName();
+ context += "reconciler: " + reconcilerName;
return context;
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java
index 03e37863df..e26597dde5 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java
@@ -30,7 +30,6 @@ class DefaultInformerConfiguration extends
private final SecondaryToPrimaryMapper secondaryToPrimaryMapper;
private final boolean followControllerNamespaceChanges;
private final OnDeleteFilter onDeleteFilter;
- private final UnaryOperator cachePruneFunction;
protected DefaultInformerConfiguration(String labelSelector,
Class resourceClass,
@@ -42,7 +41,7 @@ protected DefaultInformerConfiguration(String labelSelector,
OnDeleteFilter onDeleteFilter,
GenericFilter genericFilter,
UnaryOperator cachePruneFunction) {
- super(labelSelector, resourceClass, onAddFilter, onUpdateFilter, genericFilter, namespaces,
+ super(resourceClass, namespaces, labelSelector, onAddFilter, onUpdateFilter, genericFilter,
cachePruneFunction);
this.followControllerNamespaceChanges = followControllerNamespaceChanges;
@@ -51,7 +50,6 @@ protected DefaultInformerConfiguration(String labelSelector,
Objects.requireNonNullElse(secondaryToPrimaryMapper,
Mappers.fromOwnerReference());
this.onDeleteFilter = onDeleteFilter;
- this.cachePruneFunction = cachePruneFunction;
}
@Override
@@ -69,14 +67,10 @@ public Optional> onDeleteFilter() {
}
@Override
+ @SuppressWarnings("unchecked")
public PrimaryToSecondaryMapper
getPrimaryToSecondaryMapper() {
return (PrimaryToSecondaryMapper
) primaryToSecondaryMapper;
}
-
- @Override
- public Optional> cachePruneFunction() {
- return Optional.ofNullable(this.cachePruneFunction);
- }
}
/**
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ControllerManagerTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ControllerManagerTest.java
index 94af637b38..1cc98403f8 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ControllerManagerTest.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ControllerManagerTest.java
@@ -3,11 +3,14 @@
import org.junit.jupiter.api.Test;
import io.fabric8.kubernetes.api.model.HasMetadata;
-import io.fabric8.kubernetes.client.CustomResource;
-import io.javaoperatorsdk.operator.api.config.DefaultControllerConfiguration;
+import io.javaoperatorsdk.operator.api.config.ResolvedControllerConfiguration;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
import io.javaoperatorsdk.operator.processing.Controller;
-import io.javaoperatorsdk.operator.sample.simple.*;
+import io.javaoperatorsdk.operator.sample.simple.DuplicateCRController;
+import io.javaoperatorsdk.operator.sample.simple.TestCustomReconciler;
+import io.javaoperatorsdk.operator.sample.simple.TestCustomReconcilerOtherV1;
+import io.javaoperatorsdk.operator.sample.simple.TestCustomResource;
+import io.javaoperatorsdk.operator.sample.simple.TestCustomResourceOtherV1;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -46,19 +49,17 @@ private void checkException(
});
final var msg = exception.getMessage();
assertTrue(
- msg.contains("Cannot register controller '" + duplicated.getControllerName() + "'")
- && msg.contains(registered.getControllerName())
+ msg.contains("Cannot register controller '" + duplicated.getName() + "'")
+ && msg.contains(registered.getName())
&& msg.contains(registered.getResourceTypeName()));
}
private static class TestControllerConfiguration
- extends DefaultControllerConfiguration {
+ extends ResolvedControllerConfiguration {
private final Reconciler controller;
public TestControllerConfiguration(Reconciler controller, Class crClass) {
- super(null, getControllerName(controller),
- CustomResource.getCRDName(crClass), null, false, null, null, null, null, crClass,
- null, null, null, null, null, null, null);
+ super(crClass, getControllerName(controller), controller.getClass());
this.controller = controller;
}
@@ -66,9 +67,5 @@ static String getControllerName(
Reconciler controller) {
return controller.getClass().getSimpleName() + "Controller";
}
-
- private String getControllerName() {
- return getControllerName(controller);
- }
}
}
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java
index 766ef6d824..98c071e942 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java
@@ -28,6 +28,7 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
class ControllerConfigurationOverriderTest {
+ private final BaseConfigurationService configurationService = new BaseConfigurationService();
@Test
void overridingNSShouldPreserveUntouchedDependents() {
@@ -118,7 +119,7 @@ private Object extractDependentKubernetesResourceConfig(
private io.javaoperatorsdk.operator.api.config.ControllerConfiguration> createConfiguration(
Reconciler> reconciler) {
- return new AnnotationControllerConfiguration<>(reconciler);
+ return configurationService.configFor(reconciler);
}
@ControllerConfiguration(namespaces = "foo")
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceConfigurationResolverTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceConfigurationResolverTest.java
index 983215bcb9..3187b32645 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceConfigurationResolverTest.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceConfigurationResolverTest.java
@@ -8,8 +8,9 @@
import org.junit.jupiter.api.Test;
import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.Service;
-import io.javaoperatorsdk.operator.api.config.AnnotationControllerConfiguration;
+import io.javaoperatorsdk.operator.api.config.BaseConfigurationService;
import io.javaoperatorsdk.operator.api.config.ControllerConfigurationOverrider;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
@@ -30,9 +31,27 @@
class DependentResourceConfigurationResolverTest {
+ // subclass to expose configFor method to this test class
+ private final static class TestConfigurationService extends BaseConfigurationService {
+
+ @Override
+ protected io.javaoperatorsdk.operator.api.config.ControllerConfiguration
configFor(
+ Reconciler
reconciler) {
+ return super.configFor(reconciler);
+ }
+ }
+
+ private final TestConfigurationService configurationService = new TestConfigurationService();
+
+ private
io.javaoperatorsdk.operator.api.config.ControllerConfiguration
configFor(
+ Reconciler
reconciler) {
+ // ensure that a new configuration is created each time
+ return configurationService.configFor(reconciler);
+ }
+
@Test
void controllerConfigurationProvidedShouldBeReturnedIfAvailable() {
- final var cfg = new AnnotationControllerConfiguration<>(new CustomAnnotationReconciler());
+ final var cfg = configFor(new CustomAnnotationReconciler());
final var customConfig = DependentResourceConfigurationResolver
.extractConfigurationFromConfigured(CustomAnnotatedDep.class, cfg);
assertTrue(customConfig instanceof CustomConfig);
@@ -51,7 +70,7 @@ void controllerConfigurationProvidedShouldBeReturnedIfAvailable() {
@Test
void getConverterShouldWork() {
- final var cfg = new AnnotationControllerConfiguration<>(new CustomAnnotationReconciler());
+ final var cfg = configFor(new CustomAnnotationReconciler());
var converter = DependentResourceConfigurationResolver.getConverter(CustomAnnotatedDep.class);
assertNull(converter);
assertNull(DependentResourceConfigurationResolver.getConverter(ChildCustomAnnotatedDep.class));
@@ -77,7 +96,7 @@ void getConverterShouldWork() {
@SuppressWarnings("rawtypes")
@Test
void registerConverterShouldWork() {
- final var cfg = new AnnotationControllerConfiguration<>(new CustomAnnotationReconciler());
+ final var cfg = configFor(new CustomAnnotationReconciler());
var converter = DependentResourceConfigurationResolver.getConverter(ConfigMapDep.class);
assertNull(converter);
DependentResourceConfigurationResolver.extractConfigurationFromConfigured(ConfigMapDep.class,
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/ResourceEventFilterTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/ResourceEventFilterTest.java
index df73d79164..26994cee1a 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/ResourceEventFilterTest.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/ResourceEventFilterTest.java
@@ -8,9 +8,10 @@
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.MockKubernetesClient;
+import io.javaoperatorsdk.operator.ReconcilerUtils;
import io.javaoperatorsdk.operator.TestUtils;
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
-import io.javaoperatorsdk.operator.api.config.DefaultControllerConfiguration;
+import io.javaoperatorsdk.operator.api.config.ResolvedControllerConfiguration;
import io.javaoperatorsdk.operator.processing.Controller;
import io.javaoperatorsdk.operator.processing.event.EventHandler;
import io.javaoperatorsdk.operator.processing.event.EventSourceManager;
@@ -25,7 +26,8 @@
import static org.mockito.Mockito.verify;
class ResourceEventFilterTest {
- public static final String FINALIZER = "finalizer";
+ public static final String FINALIZER =
+ ReconcilerUtils.getDefaultFinalizerName(TestCustomResource.class);
private EventHandler eventHandler;
@@ -129,23 +131,21 @@ public TestControllerConfig(String finalizer, boolean generationAware,
}
private static class ControllerConfig extends
- DefaultControllerConfiguration {
+ ResolvedControllerConfiguration {
public ControllerConfig(String finalizer, boolean generationAware,
ResourceEventFilter eventFilter, Class customResourceClass) {
- super(
+ super(customResourceClass,
+ "test",
+ generationAware,
null,
- "testController",
null,
- finalizer,
- generationAware,
null,
null,
null,
- eventFilter,
- customResourceClass,
null,
- null, null, null, null, null, null);
+ null, null, null, finalizer, null, null);
+ setEventFilter(eventFilter);
}
}
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSourceTest.java
index 27b43656be..5a171195e1 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSourceTest.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSourceTest.java
@@ -7,8 +7,9 @@
import org.junit.jupiter.api.Test;
import io.javaoperatorsdk.operator.MockKubernetesClient;
+import io.javaoperatorsdk.operator.ReconcilerUtils;
import io.javaoperatorsdk.operator.TestUtils;
-import io.javaoperatorsdk.operator.api.config.DefaultControllerConfiguration;
+import io.javaoperatorsdk.operator.api.config.ResolvedControllerConfiguration;
import io.javaoperatorsdk.operator.processing.Controller;
import io.javaoperatorsdk.operator.processing.event.EventHandler;
import io.javaoperatorsdk.operator.processing.event.EventSourceManager;
@@ -19,12 +20,17 @@
import io.javaoperatorsdk.operator.sample.simple.TestCustomResource;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
class ControllerResourceEventSourceTest extends
AbstractEventSourceTestBase, EventHandler> {
- public static final String FINALIZER = "finalizer";
+ public static final String FINALIZER =
+ ReconcilerUtils.getDefaultFinalizerName(TestCustomResource.class);
private final TestController testController = new TestController(true);
@@ -171,24 +177,27 @@ public boolean useFinalizer() {
}
private static class TestConfiguration extends
- DefaultControllerConfiguration {
+ ResolvedControllerConfiguration {
public TestConfiguration(boolean generationAware, OnAddFilter onAddFilter,
OnUpdateFilter onUpdateFilter,
GenericFilter genericFilter) {
super(
+ TestCustomResource.class,
+ "test",
+ generationAware,
null,
- "testController",
null,
- FINALIZER,
- generationAware,
null,
null,
+ onAddFilter,
+ onUpdateFilter,
+ genericFilter,
null,
null,
- TestCustomResource.class,
null,
- onAddFilter, onUpdateFilter, genericFilter, null, null, null);
+ FINALIZER,
+ null, null);
}
}
}
diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationControllerConfiguration.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationControllerConfiguration.java
deleted file mode 100644
index 47eee2a249..0000000000
--- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationControllerConfiguration.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package io.javaoperatorsdk.operator.config.runtime;
-
-import io.fabric8.kubernetes.api.model.HasMetadata;
-import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
-
-public class AnnotationControllerConfiguration
- extends io.javaoperatorsdk.operator.api.config.AnnotationControllerConfiguration {
-
- public AnnotationControllerConfiguration(Reconciler reconciler) {
- super(reconciler);
- }
-
- @Override
- public Class getResourceClass() {
- return RuntimeControllerMetadata.getResourceClass(reconciler);
- }
-}
diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/DefaultConfigurationService.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/DefaultConfigurationService.java
index 34e0b3f1d7..49f0ed2b67 100644
--- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/DefaultConfigurationService.java
+++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/DefaultConfigurationService.java
@@ -4,6 +4,7 @@
import io.javaoperatorsdk.operator.api.config.BaseConfigurationService;
import io.javaoperatorsdk.operator.api.config.ConfigurationServiceProvider;
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
+import io.javaoperatorsdk.operator.api.config.ResolvedControllerConfiguration;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
public class DefaultConfigurationService extends BaseConfigurationService {
@@ -46,6 +47,8 @@ public void setCreateIfNeeded(boolean createIfNeeded) {
@Override
protected ControllerConfiguration configFor(Reconciler reconciler) {
- return new AnnotationControllerConfiguration<>(reconciler);
+ final var other = super.configFor(reconciler);
+ return new ResolvedControllerConfiguration<>(
+ RuntimeControllerMetadata.getResourceClass(reconciler), other);
}
}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/runtime/AnnotationControllerConfigurationTest.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/BaseConfigurationServiceTest.java
similarity index 90%
rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/config/runtime/AnnotationControllerConfigurationTest.java
rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/config/BaseConfigurationServiceTest.java
index bbc49ebf33..22af954661 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/runtime/AnnotationControllerConfigurationTest.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/BaseConfigurationServiceTest.java
@@ -1,4 +1,4 @@
-package io.javaoperatorsdk.operator.config.runtime;
+package io.javaoperatorsdk.operator.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -14,8 +14,10 @@
import org.junit.jupiter.api.Test;
import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.OperatorException;
import io.javaoperatorsdk.operator.api.config.AnnotationConfigurable;
+import io.javaoperatorsdk.operator.api.config.BaseConfigurationService;
import io.javaoperatorsdk.operator.api.config.dependent.ConfigurationConverter;
import io.javaoperatorsdk.operator.api.config.dependent.Configured;
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfigurationResolver;
@@ -48,11 +50,29 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-class AnnotationControllerConfigurationTest {
+class BaseConfigurationServiceTest {
+
+ // subclass to expose configFor method to this test class
+ private final static class TestConfigurationService extends BaseConfigurationService {
+
+ @Override
+ protected io.javaoperatorsdk.operator.api.config.ControllerConfiguration
configFor(
+ Reconciler
reconciler) {
+ return super.configFor(reconciler);
+ }
+ }
+
+ private final TestConfigurationService configurationService = new TestConfigurationService();
+
+ private
io.javaoperatorsdk.operator.api.config.ControllerConfiguration
configFor(
+ Reconciler
reconciler) {
+ // ensure that a new configuration is created each time
+ return configurationService.configFor(reconciler);
+ }
@Test
void defaultValuesShouldBeConsistent() {
- final var configuration = new AnnotationControllerConfiguration<>(new SelectorReconciler());
+ final var configuration = configFor(new SelectorReconciler());
final var annotated = extractDependentKubernetesResourceConfig(configuration, 1);
final var unannotated = extractDependentKubernetesResourceConfig(configuration, 0);
@@ -71,11 +91,11 @@ private KubernetesDependentResourceConfig extractDependentKubernetesResourceConf
@Test
@SuppressWarnings("rawtypes")
void getDependentResources() {
- var configuration = new AnnotationControllerConfiguration<>(new NoDepReconciler());
+ var configuration = configFor(new NoDepReconciler());
var dependents = configuration.getDependentResources();
assertTrue(dependents.isEmpty());
- configuration = new AnnotationControllerConfiguration<>(new OneDepReconciler());
+ configuration = configFor(new OneDepReconciler());
dependents = configuration.getDependentResources();
assertFalse(dependents.isEmpty());
assertEquals(1, dependents.size());
@@ -92,7 +112,7 @@ void getDependentResources() {
assertEquals(1, config.namespaces().size());
assertEquals(Set.of(OneDepReconciler.CONFIGURED_NS), config.namespaces());
- configuration = new AnnotationControllerConfiguration<>(new NamedDepReconciler());
+ configuration = configFor(new NamedDepReconciler());
dependents = configuration.getDependentResources();
assertFalse(dependents.isEmpty());
assertEquals(1, dependents.size());
@@ -107,7 +127,7 @@ void getDependentResources() {
@Test
void missingAnnotationThrowsException() {
Assertions.assertThrows(OperatorException.class,
- () -> new AnnotationControllerConfiguration<>(new MissingAnnotationReconciler()));
+ () -> configFor(new MissingAnnotationReconciler()));
}
@SuppressWarnings("rawtypes")
@@ -125,13 +145,12 @@ private Optional findByNameOptional(
@Test
void tryingToAddDuplicatedDependentsWithoutNameShouldFail() {
- var configuration = new AnnotationControllerConfiguration<>(new DuplicatedDepReconciler());
- assertThrows(IllegalArgumentException.class, configuration::getDependentResources);
+ assertThrows(IllegalArgumentException.class, () -> configFor(new DuplicatedDepReconciler()));
}
@Test
void addingDuplicatedDependentsWithNameShouldWork() {
- var config = new AnnotationControllerConfiguration<>(new NamedDuplicatedDepReconciler());
+ var config = configFor(new NamedDuplicatedDepReconciler());
var dependents = config.getDependentResources();
assertEquals(2, dependents.size());
assertTrue(findByNameOptional(dependents, NamedDuplicatedDepReconciler.NAME).isPresent()
@@ -141,13 +160,13 @@ && findByNameOptional(dependents, DependentResource.defaultNameFor(ReadOnlyDepen
@Test
void maxIntervalCanBeConfigured() {
- var config = new AnnotationControllerConfiguration<>(new MaxIntervalReconciler());
+ var config = configFor(new MaxIntervalReconciler());
assertEquals(50, config.maxReconciliationInterval().map(Duration::getSeconds).orElseThrow());
}
@Test
void checkDefaultRateAndRetryConfigurations() {
- var config = new AnnotationControllerConfiguration<>(new NoDepReconciler());
+ var config = configFor(new NoDepReconciler());
final var retry = assertInstanceOf(GenericRetry.class, config.getRetry());
assertEquals(GradualRetry.DEFAULT_MAX_ATTEMPTS, retry.getMaxAttempts());
assertEquals(GradualRetry.DEFAULT_MULTIPLIER, retry.getIntervalMultiplier());
@@ -161,7 +180,7 @@ void checkDefaultRateAndRetryConfigurations() {
@Test
void configuringRateAndRetryViaAnnotationsShouldWork() {
var config =
- new AnnotationControllerConfiguration<>(new ConfigurableRateLimitAndRetryReconciler());
+ configFor(new ConfigurableRateLimitAndRetryReconciler());
final var retry = config.getRetry();
final var testRetry = assertInstanceOf(TestRetry.class, retry);
assertEquals(12, testRetry.getValue());
@@ -173,7 +192,7 @@ void configuringRateAndRetryViaAnnotationsShouldWork() {
@Test
void checkingRetryingGraduallyWorks() {
- var config = new AnnotationControllerConfiguration<>(new CheckRetryingGraduallyConfiguration());
+ var config = configFor(new CheckRetryingGraduallyConfiguration());
final var retry = config.getRetry();
final var genericRetry = assertInstanceOf(GenericRetry.class, retry);
assertEquals(CheckRetryingGraduallyConfiguration.INITIAL_INTERVAL,
@@ -186,13 +205,13 @@ void checkingRetryingGraduallyWorks() {
@Test
void controllerConfigurationOnSuperClassShouldWork() {
- var config = new AnnotationControllerConfiguration<>(new ControllerConfigurationOnSuperClass());
+ var config = configFor(new ControllerConfigurationOnSuperClass());
assertNotNull(config.getName());
}
@Test
void configuringFromCustomAnnotationsShouldWork() {
- var config = new AnnotationControllerConfiguration<>(new CustomAnnotationReconciler());
+ var config = configFor(new CustomAnnotationReconciler());
assertEquals(CustomAnnotatedDep.PROVIDED_VALUE, getValue(config, 0));
assertEquals(CustomConfigConverter.CONVERTER_PROVIDED_DEFAULT, getValue(config, 1));
}