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 1283896a42..9680bc7e8d 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 @@ -213,8 +213,9 @@ public

RegisteredController

register(Reconciler

re controllerManager.add(controller); - final var watchedNS = configuration.watchAllNamespaces() ? "[all namespaces]" - : configuration.getEffectiveNamespaces(); + final var informerConfig = configuration.getInformerConfig(); + final var watchedNS = informerConfig.watchAllNamespaces() ? "[all namespaces]" + : informerConfig.getEffectiveNamespaces(configuration); log.info( "Registered reconciler: '{}' for resource: '{}' for namespace(s): {}", 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 20beef7f90..4204cb6faf 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 @@ -280,7 +280,7 @@ private

ResolvedControllerConfiguration

controllerCon .buildForController(); return new ResolvedControllerConfiguration

( - resourceClass, name, generationAware, + name, generationAware, associatedReconcilerClass, retry, rateLimiter, ResolvedControllerConfiguration.getMaxReconciliationInterval(interval, timeUnit), valueOrDefaultFromAnnotation(annotation, diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java index 0bd1607213..ff06ad338f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java @@ -364,7 +364,7 @@ default ExecutorServiceManager getExecutorServiceManager() { * SSA based create/update can be still used with the legacy matching, just overriding the match * method of Kubernetes Dependent Resource. * - * @return if SSA should be used for dependent resources + * @return {@code true} if SSA should be used for dependent resources, {@code false} otherwise * @since 4.4.0 */ default boolean ssaBasedCreateUpdateMatchForDependentResources() { @@ -395,6 +395,8 @@ default Set> defaultNonSSAResource() { * * @return if special annotation should be used for dependent resource to filter events * @since 4.5.0 + * + * @return if special annotation should be used for dependent resource to filter events */ default boolean previousAnnotationForDependentResourcesEventFiltering() { return true; @@ -411,6 +413,8 @@ default boolean previousAnnotationForDependentResourcesEventFiltering() { * * @return if resource version should be parsed (as integer) * @since 4.5.0 + * + * @return if resource version should be parsed (as integer) */ default boolean parseResourceVersionsForEventFilteringAndCaching() { return false; 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 aa74d7ea1a..e03cf5626e 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 @@ -14,7 +14,7 @@ import io.javaoperatorsdk.operator.processing.retry.GenericRetry; import io.javaoperatorsdk.operator.processing.retry.Retry; -public interface ControllerConfiguration

extends ResourceConfiguration

{ +public interface ControllerConfiguration

extends Informable

{ @SuppressWarnings("rawtypes") RateLimiter DEFAULT_RATE_LIMITER = LinearRateLimiter.deactivatedRateLimiter(); @@ -74,19 +74,9 @@ default Optional maxReconciliationInterval() { ConfigurationService getConfigurationService(); - @SuppressWarnings("unchecked") - @Override - default Class

getResourceClass() { - // note that this implementation at the end not used within the boundaries of the core - // framework, should be removed in the future, (and marked as an API changed, or behavior - // change) - return (Class

) Utils.getFirstTypeArgumentFromSuperClassOrInterface(getClass(), - ControllerConfiguration.class); - } - @SuppressWarnings("unused") default Set getEffectiveNamespaces() { - return ResourceConfiguration.super.getEffectiveNamespaces(this); + return getInformerConfig().getEffectiveNamespaces(this); } /** 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 423867107a..3d3eef5990 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 @@ -35,15 +35,8 @@ public class ControllerConfigurationOverrider { private ControllerConfigurationOverrider(ControllerConfiguration original) { this.finalizer = original.getFinalizerName(); this.generationAware = original.isGenerationAware(); - this.config = InformerConfiguration.builder(original.getResourceClass()) - .withName(name) - .withNamespaces(original.getNamespaces()) - .withLabelSelector(original.getLabelSelector()) - .withOnAddFilter(original.onAddFilter().orElse(null)) - .withOnUpdateFilter(original.onUpdateFilter().orElse(null)) - .withGenericFilter(original.genericFilter().orElse(null)) - .withInformerListLimit(original.getInformerListLimit().orElse(null)) - .withItemStore(original.getItemStore().orElse(null)); + final var informerConfig = original.getInformerConfig(); + this.config = InformerConfiguration.builder(informerConfig); this.retry = original.getRetry(); this.reconciliationMaxInterval = original.maxReconciliationInterval().orElse(null); this.original = original; @@ -194,7 +187,7 @@ public ControllerConfigurationOverrider replacingNamedDependentResourceConfig } public ControllerConfiguration build() { - return new ResolvedControllerConfiguration<>(original.getResourceClass(), + return new ResolvedControllerConfiguration<>( name, generationAware, original.getAssociatedReconcilerClassName(), retry, rateLimiter, reconciliationMaxInterval, 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 deleted file mode 100644 index c0d725f746..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.javaoperatorsdk.operator.api.config; - - -import io.fabric8.kubernetes.api.model.GenericKubernetesResource; -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.ReconcilerUtils; -import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; - -public class DefaultResourceConfiguration - implements ResourceConfiguration { - - private final Class resourceClass; - private final String resourceTypeName; - private final InformerConfiguration informerConfig; - - protected DefaultResourceConfiguration(Class resourceClass, - InformerConfiguration informerConfig) { - this.resourceClass = resourceClass; - this.resourceTypeName = resourceClass.isAssignableFrom(GenericKubernetesResource.class) - // in general this is irrelevant now for secondary resources it is used just by controller - // where GenericKubernetesResource now does not apply - ? GenericKubernetesResource.class.getSimpleName() - : ReconcilerUtils.getResourceTypeName(resourceClass); - this.informerConfig = informerConfig; - } - - @Override - public String getResourceTypeName() { - return resourceTypeName; - } - - @Override - public Class getResourceClass() { - return resourceClass; - } - - @Override - public InformerConfiguration getInformerConfig() { - return informerConfig; - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Informable.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Informable.java new file mode 100644 index 0000000000..5b58836483 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Informable.java @@ -0,0 +1,18 @@ +package io.javaoperatorsdk.operator.api.config; + + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; + +public interface Informable { + + default String getResourceTypeName() { + return getInformerConfig().getResourceTypeName(); + } + + InformerConfiguration getInformerConfig(); + + default Class getResourceClass() { + return getInformerConfig().getResourceClass(); + } +} 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 index 9bb7efb5cf..7e8415f584 100644 --- 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 @@ -16,9 +16,9 @@ @SuppressWarnings("rawtypes") public class ResolvedControllerConfiguration

- extends DefaultResourceConfiguration

implements io.javaoperatorsdk.operator.api.config.ControllerConfiguration

{ + private final InformerConfiguration

informerConfig; private final String name; private final boolean generationAware; private final String associatedReconcilerClassName; @@ -31,8 +31,8 @@ public class ResolvedControllerConfiguration

private final String fieldManager; private WorkflowSpec workflowSpec; - public ResolvedControllerConfiguration(Class

resourceClass, ControllerConfiguration

other) { - this(resourceClass, other.getName(), other.isGenerationAware(), + public ResolvedControllerConfiguration(ControllerConfiguration

other) { + this(other.getName(), other.isGenerationAware(), other.getAssociatedReconcilerClassName(), other.getRetry(), other.getRateLimiter(), other.maxReconciliationInterval().orElse(null), other.getFinalizerName(), Collections.emptyMap(), @@ -42,7 +42,7 @@ public ResolvedControllerConfiguration(Class

resourceClass, ControllerConfigu other.getWorkflowSpec().orElse(null)); } - public ResolvedControllerConfiguration(Class

resourceClass, String name, + public ResolvedControllerConfiguration(String name, boolean generationAware, String associatedReconcilerClassName, Retry retry, RateLimiter rateLimiter, Duration maxReconciliationInterval, String finalizer, @@ -51,19 +51,19 @@ public ResolvedControllerConfiguration(Class

resourceClass, String name, ConfigurationService configurationService, InformerConfiguration

informerConfig, WorkflowSpec workflowSpec) { - this(resourceClass, name, generationAware, associatedReconcilerClassName, retry, rateLimiter, + this(name, generationAware, associatedReconcilerClassName, retry, rateLimiter, maxReconciliationInterval, finalizer, configurations, fieldManager, configurationService, informerConfig); setWorkflowSpec(workflowSpec); } - protected ResolvedControllerConfiguration(Class

resourceClass, String name, + protected ResolvedControllerConfiguration(String name, boolean generationAware, String associatedReconcilerClassName, Retry retry, RateLimiter rateLimiter, Duration maxReconciliationInterval, String finalizer, Map configurations, String fieldManager, ConfigurationService configurationService, InformerConfiguration

informerConfig) { - super(resourceClass, informerConfig); + this.informerConfig = informerConfig; this.configurationService = configurationService; this.name = ControllerConfiguration.ensureValidName(name, associatedReconcilerClassName); this.generationAware = generationAware; @@ -79,11 +79,16 @@ protected ResolvedControllerConfiguration(Class

resourceClass, String name, protected ResolvedControllerConfiguration(Class

resourceClass, String name, Class reconcilerClas, ConfigurationService configurationService) { - this(resourceClass, name, false, getAssociatedReconcilerClassName(reconcilerClas), null, null, + this(name, false, getAssociatedReconcilerClassName(reconcilerClas), null, null, null, null, null, null, configurationService, InformerConfiguration.builder(resourceClass).buildForController()); } + @Override + public InformerConfiguration

getInformerConfig() { + return informerConfig; + } + public static Duration getMaxReconciliationInterval(long interval, TimeUnit timeUnit) { return interval > 0 ? Duration.of(interval, timeUnit.toChronoUnit()) : null; } 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 deleted file mode 100644 index cac44c93db..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ResourceConfiguration.java +++ /dev/null @@ -1,161 +0,0 @@ -package io.javaoperatorsdk.operator.api.config; - -import java.util.Collection; -import java.util.Collections; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.client.informers.cache.ItemStore; -import io.javaoperatorsdk.operator.OperatorException; -import io.javaoperatorsdk.operator.ReconcilerUtils; -import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.Constants; -import io.javaoperatorsdk.operator.processing.event.source.cache.BoundedItemStore; -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; -import static io.javaoperatorsdk.operator.api.reconciler.Constants.WATCH_CURRENT_NAMESPACE_SET; - -public interface ResourceConfiguration { - - default String getResourceTypeName() { - return ReconcilerUtils.getResourceTypeName(getResourceClass()); - } - - InformerConfiguration getInformerConfig(); - - default Optional> onAddFilter() { - return Optional.ofNullable(getInformerConfig().getOnAddFilter()); - } - - default Optional> onUpdateFilter() { - return Optional.ofNullable(getInformerConfig().getOnUpdateFilter()); - } - - default Optional> genericFilter() { - return Optional.ofNullable(getInformerConfig().getGenericFilter()); - } - - /** - * Retrieves the label selector that is used to filter which resources are actually watched by the - * associated event source. See the official documentation on the - * topic - * for more details on syntax. - * - * @return the label selector filtering watched resources - */ - default String getLabelSelector() { - return getInformerConfig().getLabelSelector(); - } - - static String ensureValidLabelSelector(String labelSelector) { - // might want to implement validation here? - return labelSelector; - } - - @SuppressWarnings("unchecked") - default Class getResourceClass() { - return (Class) Utils.getFirstTypeArgumentFromSuperClassOrInterface(getClass(), - ResourceConfiguration.class); - } - - default Set getNamespaces() { - return getInformerConfig().getNamespaces(); - } - - default boolean watchAllNamespaces() { - return allNamespacesWatched(getNamespaces()); - } - - static boolean allNamespacesWatched(Set namespaces) { - failIfNotValid(namespaces); - return DEFAULT_NAMESPACES_SET.equals(namespaces); - } - - default boolean watchCurrentNamespace() { - return currentNamespaceWatched(getNamespaces()); - } - - static boolean currentNamespaceWatched(Set namespaces) { - failIfNotValid(namespaces); - return WATCH_CURRENT_NAMESPACE_SET.equals(namespaces); - } - - static void failIfNotValid(Set namespaces) { - if (namespaces != null && !namespaces.isEmpty()) { - final var present = namespaces.contains(Constants.WATCH_CURRENT_NAMESPACE) - || namespaces.contains(Constants.WATCH_ALL_NAMESPACES); - if (!present || namespaces.size() == 1) { - return; - } - } - throw new IllegalArgumentException( - "Must specify namespaces. To watch all namespaces, use only '" - + Constants.WATCH_ALL_NAMESPACES - + "'. To watch only the namespace in which the operator is deployed, use only '" - + Constants.WATCH_CURRENT_NAMESPACE + "'"); - } - - static Set ensureValidNamespaces(Collection namespaces) { - if (namespaces != null && !namespaces.isEmpty()) { - return namespaces.stream().map(String::trim).collect(Collectors.toSet()); - } 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 - * watch the current namespace only. - * - * @return a Set of namespace names the associated controller will watch - */ - default Set getEffectiveNamespaces(ControllerConfiguration controllerConfiguration) { - var targetNamespaces = getNamespaces(); - if (watchCurrentNamespace()) { - final String namespace = - controllerConfiguration.getConfigurationService().getKubernetesClient().getConfiguration() - .getNamespace(); - if (namespace == null) { - throw new OperatorException( - "Couldn't retrieve the currently connected namespace. Make sure it's correctly set in your ~/.kube/config file, using, e.g. 'kubectl config set-context --namespace='"); - } - targetNamespaces = Collections.singleton(namespace); - } - return targetNamespaces; - } - - /** - * Replaces the item store in informer. See underlying method - * in fabric8 client informer implementation. - * - *

- * The main goal, is to be able to use limited caches or provide any custom implementation. - *

- * - *

- * See {@link BoundedItemStore} and CaffeineBoundedCache - *

- * - * @return Optional {@link ItemStore} implementation. If present this item store will be used by - * the informers. - */ - default Optional> getItemStore() { - return Optional.ofNullable(getInformerConfig().getItemStore()); - } - - /** - * The maximum amount of items to return for a single list call when starting an informer. If this - * is a not null it will result in paginating for the initial load of the informer cache. - */ - default Optional getInformerListLimit() { - return Optional.ofNullable(getInformerConfig().getInformerListLimit()); - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/Informer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/Informer.java index 363200bea5..57da4f41a6 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/Informer.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/Informer.java @@ -13,7 +13,7 @@ import io.javaoperatorsdk.operator.processing.event.source.filter.OnDeleteFilter; import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter; -import static io.javaoperatorsdk.operator.api.config.informer.InformerEventSourceConfiguration.DEFAULT_FOLLOW_CONTROLLER_NAMESPACES_ON_CHANGE; +import static io.javaoperatorsdk.operator.api.reconciler.Constants.DEFAULT_FOLLOW_CONTROLLER_NAMESPACES_ON_CHANGE; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_LONG_VALUE_SET; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_VALUE_SET; 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 0cb6892ebe..8d7b232889 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 @@ -1,12 +1,19 @@ package io.javaoperatorsdk.operator.api.config.informer; +import java.util.Collection; +import java.util.Collections; import java.util.Set; +import java.util.stream.Collectors; +import io.fabric8.kubernetes.api.model.GenericKubernetesResource; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.informers.cache.ItemStore; -import io.javaoperatorsdk.operator.api.config.ResourceConfiguration; +import io.javaoperatorsdk.operator.OperatorException; +import io.javaoperatorsdk.operator.ReconcilerUtils; +import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; import io.javaoperatorsdk.operator.api.config.Utils; import io.javaoperatorsdk.operator.api.reconciler.Constants; +import io.javaoperatorsdk.operator.processing.event.source.cache.BoundedItemStore; 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.OnDeleteFilter; @@ -18,6 +25,8 @@ @SuppressWarnings("unused") public class InformerConfiguration { private final Builder builder = new Builder(); + private final Class resourceClass; + private final String resourceTypeName; private String name; private Set namespaces; private Boolean followControllerNamespacesOnChange; @@ -29,11 +38,12 @@ public class InformerConfiguration { private ItemStore itemStore; private Long informerListLimit; - public InformerConfiguration(String name, Set namespaces, + protected InformerConfiguration(Class resourceClass, String name, Set namespaces, boolean followControllerNamespacesOnChange, String labelSelector, OnAddFilter onAddFilter, OnUpdateFilter onUpdateFilter, OnDeleteFilter onDeleteFilter, GenericFilter genericFilter, ItemStore itemStore, Long informerListLimit) { + this(resourceClass); this.name = name; this.namespaces = namespaces; this.followControllerNamespacesOnChange = followControllerNamespacesOnChange; @@ -46,28 +56,80 @@ public InformerConfiguration(String name, Set namespaces, this.informerListLimit = informerListLimit; } - private InformerConfiguration() {} - - @SuppressWarnings({"rawtypes", "unchecked"}) - public static InformerConfiguration.Builder builder() { - return new InformerConfiguration().builder; + private InformerConfiguration(Class resourceClass) { + this.resourceClass = resourceClass; + this.resourceTypeName = resourceClass.isAssignableFrom(GenericKubernetesResource.class) + // in general this is irrelevant now for secondary resources it is used just by controller + // where GenericKubernetesResource now does not apply + ? GenericKubernetesResource.class.getSimpleName() + : ReconcilerUtils.getResourceTypeName(resourceClass); } @SuppressWarnings({"rawtypes", "unchecked"}) public static InformerConfiguration.Builder builder( Class resourceClass) { - return new InformerConfiguration().builder; + return new InformerConfiguration(resourceClass).builder; } @SuppressWarnings({"rawtypes", "unchecked"}) public static InformerConfiguration.Builder builder( InformerConfiguration original) { - return new InformerConfiguration(original.name, original.namespaces, + return new InformerConfiguration(original.resourceClass, original.name, original.namespaces, original.followControllerNamespacesOnChange, original.labelSelector, original.onAddFilter, original.onUpdateFilter, original.onDeleteFilter, original.genericFilter, original.itemStore, original.informerListLimit).builder; } + public static String ensureValidLabelSelector(String labelSelector) { + // might want to implement validation here? + return labelSelector; + } + + public static boolean allNamespacesWatched(Set namespaces) { + failIfNotValid(namespaces); + return DEFAULT_NAMESPACES_SET.equals(namespaces); + } + + public static boolean currentNamespaceWatched(Set namespaces) { + failIfNotValid(namespaces); + return WATCH_CURRENT_NAMESPACE_SET.equals(namespaces); + } + + public static void failIfNotValid(Set namespaces) { + if (namespaces != null && !namespaces.isEmpty()) { + final var present = namespaces.contains(WATCH_CURRENT_NAMESPACE) + || namespaces.contains(WATCH_ALL_NAMESPACES); + if (!present || namespaces.size() == 1) { + return; + } + } + throw new IllegalArgumentException( + "Must specify namespaces. To watch all namespaces, use only '" + + WATCH_ALL_NAMESPACES + + "'. To watch only the namespace in which the operator is deployed, use only '" + + WATCH_CURRENT_NAMESPACE + "'"); + } + + public static Set ensureValidNamespaces(Collection namespaces) { + if (namespaces != null && !namespaces.isEmpty()) { + return namespaces.stream().map(String::trim).collect(Collectors.toSet()); + } else { + return Constants.DEFAULT_NAMESPACES_SET; + } + } + + public static boolean inheritsNamespacesFromController(Set namespaces) { + return SAME_AS_CONTROLLER_NAMESPACES_SET.equals(namespaces); + } + + public Class getResourceClass() { + return resourceClass; + } + + public String getResourceTypeName() { + return resourceTypeName; + } + public String getName() { return name; } @@ -76,10 +138,64 @@ public Set getNamespaces() { return namespaces; } + public boolean watchAllNamespaces() { + return InformerConfiguration.allNamespacesWatched(getNamespaces()); + } + + public boolean watchCurrentNamespace() { + return InformerConfiguration.currentNamespaceWatched(getNamespaces()); + } + + public boolean inheritsNamespacesFromController() { + return inheritsNamespacesFromController(getNamespaces()); + } + + /** + * 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 + * watch the current namespace only. + * + * @return a Set of namespace names the associated controller will watch + */ + public Set getEffectiveNamespaces(ControllerConfiguration controllerConfiguration) { + if (inheritsNamespacesFromController()) { + return controllerConfiguration.getEffectiveNamespaces(); + } + + var targetNamespaces = getNamespaces(); + if (watchCurrentNamespace()) { + final String namespace = + controllerConfiguration.getConfigurationService().getKubernetesClient().getConfiguration() + .getNamespace(); + if (namespace == null) { + throw new OperatorException( + "Couldn't retrieve the currently connected namespace. Make sure it's correctly set in your ~/.kube/config file, using, e.g. 'kubectl config set-context --namespace='"); + } + targetNamespaces = Collections.singleton(namespace); + } + return targetNamespaces; + } + + /** + * Used in case the watched namespaces are changed dynamically, thus when operator is running (See + * {@link io.javaoperatorsdk.operator.RegisteredController}). If true, changing the target + * namespaces of a controller would result to change target namespaces for the + * InformerEventSource. + * + * @return if namespace changes should be followed + */ public boolean isFollowControllerNamespacesOnChange() { return followControllerNamespacesOnChange; } + /** + * Retrieves the label selector that is used to filter which resources are actually watched by the + * associated informer. See the official documentation on the + * topic + * for more details on syntax. + * + * @return the label selector filtering watched resources + */ public String getLabelSelector() { return labelSelector; } @@ -100,10 +216,31 @@ public GenericFilter getGenericFilter() { return genericFilter; } + /** + * Replaces the item store in informer. See underlying method + * in fabric8 client informer implementation. + * + *

+ * The main goal, is to be able to use limited caches or provide any custom implementation. + *

+ * + *

+ * See {@link BoundedItemStore} and CaffeineBoundedCache + *

+ * + * @return Optional {@link ItemStore} implementation. If present this item store will be used by + * the informers. + */ public ItemStore getItemStore() { return itemStore; } + /** + * The maximum amount of items to return for a single list call when starting an informer. If this + * is a not null it will result in paginating for the initial load of the informer cache. + */ public Long getInformerListLimit() { return informerListLimit; } @@ -116,9 +253,11 @@ public InformerConfiguration buildForController() { // if the informer config uses the default "same as controller" value, reset the namespaces to // the default set for controllers if (namespaces == null || namespaces.isEmpty() - || InformerEventSourceConfiguration.inheritsNamespacesFromController(namespaces)) { + || inheritsNamespacesFromController(namespaces)) { namespaces = Constants.DEFAULT_NAMESPACES_SET; } + // to avoid potential NPE + followControllerNamespacesOnChange = false; return InformerConfiguration.this; } @@ -128,7 +267,7 @@ public InformerConfiguration buildForInformerEventSource() { } if (followControllerNamespacesOnChange == null) { followControllerNamespacesOnChange = - InformerEventSourceConfiguration.DEFAULT_FOLLOW_CONTROLLER_NAMESPACES_ON_CHANGE; + DEFAULT_FOLLOW_CONTROLLER_NAMESPACES_ON_CHANGE; } return InformerConfiguration.this; } @@ -184,7 +323,7 @@ public Builder withName(String name) { public Builder withNamespaces(Set namespaces) { InformerConfiguration.this.namespaces = - ResourceConfiguration.ensureValidNamespaces(namespaces); + ensureValidNamespaces(namespaces); return this; } @@ -239,7 +378,7 @@ public Builder withFollowControllerNamespacesOnChange(boolean followChanges) { public Builder withLabelSelector(String labelSelector) { InformerConfiguration.this.labelSelector = - ResourceConfiguration.ensureValidLabelSelector(labelSelector); + ensureValidLabelSelector(labelSelector); return this; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerEventSourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerEventSourceConfiguration.java index 1e5e1ce666..20e6c7f131 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerEventSourceConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerEventSourceConfiguration.java @@ -2,31 +2,18 @@ import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.function.Consumer; import io.fabric8.kubernetes.api.model.GenericKubernetesResource; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.config.DefaultResourceConfiguration; -import io.javaoperatorsdk.operator.api.config.ResourceConfiguration; -import io.javaoperatorsdk.operator.api.config.Utils; +import io.javaoperatorsdk.operator.api.config.Informable; import io.javaoperatorsdk.operator.processing.GroupVersionKind; import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper; import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; -import io.javaoperatorsdk.operator.processing.event.source.filter.OnDeleteFilter; import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; -import static io.javaoperatorsdk.operator.api.reconciler.Constants.SAME_AS_CONTROLLER_NAMESPACES_SET; - public interface InformerEventSourceConfiguration - extends ResourceConfiguration { - - boolean DEFAULT_FOLLOW_CONTROLLER_NAMESPACES_ON_CHANGE = true; - - static boolean inheritsNamespacesFromController(Set namespaces) { - return SAME_AS_CONTROLLER_NAMESPACES_SET.equals(namespaces); - } + extends Informable { static Builder from( Class resourceClass, Class primaryResourceClass) { @@ -62,10 +49,6 @@ default boolean followControllerNamespaceChanges() { */ SecondaryToPrimaryMapper getSecondaryToPrimaryMapper(); - default Optional> onDeleteFilter() { - return Optional.ofNullable(getInformerConfig().getOnDeleteFilter()); - } -

PrimaryToSecondaryMapper

getPrimaryToSecondaryMapper(); Optional getGroupVersionKind(); @@ -74,39 +57,32 @@ default String name() { return getInformerConfig().getName(); } - @SuppressWarnings("unchecked") - @Override - default Class getResourceClass() { - return (Class) Utils.getFirstTypeArgumentFromSuperClassOrInterface(getClass(), - InformerEventSourceConfiguration.class); - } - - class DefaultInformerEventSourceConfiguration extends - DefaultResourceConfiguration implements InformerEventSourceConfiguration { + class DefaultInformerEventSourceConfiguration + implements InformerEventSourceConfiguration { private final PrimaryToSecondaryMapper primaryToSecondaryMapper; private final SecondaryToPrimaryMapper secondaryToPrimaryMapper; private final GroupVersionKind groupVersionKind; + private final InformerConfiguration informerConfig; protected DefaultInformerEventSourceConfiguration( - Class resourceClass, GroupVersionKind groupVersionKind, PrimaryToSecondaryMapper primaryToSecondaryMapper, SecondaryToPrimaryMapper secondaryToPrimaryMapper, InformerConfiguration informerConfig) { - super(resourceClass, informerConfig); + this.informerConfig = Objects.requireNonNull(informerConfig); this.groupVersionKind = groupVersionKind; this.primaryToSecondaryMapper = primaryToSecondaryMapper; this.secondaryToPrimaryMapper = secondaryToPrimaryMapper; } @Override - public SecondaryToPrimaryMapper getSecondaryToPrimaryMapper() { - return secondaryToPrimaryMapper; + public InformerConfiguration getInformerConfig() { + return informerConfig; } @Override - public Optional> onDeleteFilter() { - return Optional.ofNullable(getInformerConfig().getOnDeleteFilter()); + public SecondaryToPrimaryMapper getSecondaryToPrimaryMapper() { + return secondaryToPrimaryMapper; } @Override @@ -119,19 +95,6 @@ public

PrimaryToSecondaryMapper

getPrimaryToSecondary public Optional getGroupVersionKind() { return Optional.ofNullable(groupVersionKind); } - - public boolean inheritsNamespacesFromController() { - return InformerEventSourceConfiguration.inheritsNamespacesFromController(getNamespaces()); - } - - @Override - public Set getEffectiveNamespaces(ControllerConfiguration controllerConfiguration) { - if (inheritsNamespacesFromController()) { - return controllerConfiguration.getEffectiveNamespaces(); - } else { - return super.getEffectiveNamespaces(controllerConfiguration); - } - } } @@ -223,7 +186,7 @@ public InformerEventSourceConfiguration build() { "If GroupVersionKind is set the resource type must be GenericKubernetesDependentResource"); } - return new DefaultInformerEventSourceConfiguration<>(resourceClass, + return new DefaultInformerEventSourceConfiguration<>( groupVersionKind, primaryToSecondaryMapper, Objects.requireNonNullElse(secondaryToPrimaryMapper, diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java index 594fcddd09..8003d8f836 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java @@ -25,6 +25,7 @@ public final class Constants { public static final String RESOURCE_GVK_KEY = "josdk.resource.gvk"; public static final String CONTROLLER_NAME = "controller.name"; + public static final boolean DEFAULT_FOLLOW_CONTROLLER_NAMESPACES_ON_CHANGE = true; private Constants() {} } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceFactory.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceFactory.java index 105d2b6c75..cc9a1dd6c3 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceFactory.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceFactory.java @@ -6,11 +6,11 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ConfiguredDependentResource; @SuppressWarnings({"rawtypes", "unchecked"}) -public interface DependentResourceFactory> { +public interface DependentResourceFactory, D extends DependentResourceSpec> { DependentResourceFactory DEFAULT = new DependentResourceFactory() {}; - default DependentResource createFrom(DependentResourceSpec spec, C controllerConfiguration) { + default DependentResource createFrom(D spec, C controllerConfiguration) { final var dependentResourceClass = spec.getDependentResourceClass(); return Utils.instantiateAndConfigureIfNeeded(dependentResourceClass, DependentResource.class, @@ -18,8 +18,7 @@ default DependentResource createFrom(DependentResourceSpec spec, C controllerCon (instance) -> configure(instance, spec, controllerConfiguration)); } - default void configure(DependentResource instance, DependentResourceSpec spec, - C controllerConfiguration) { + default void configure(DependentResource instance, D spec, C controllerConfiguration) { if (instance instanceof ConfiguredDependentResource configurable) { final var config = controllerConfiguration.getConfigurationFor(spec); if (config != null) { @@ -27,4 +26,12 @@ default void configure(DependentResource instance, DependentResourceSpec spec, } } } + + default Class associatedResourceType(D spec) { + final var dependentResourceClass = spec.getDependentResourceClass(); + final var dr = Utils.instantiateAndConfigureIfNeeded(dependentResourceClass, + DependentResource.class, + null, null); + return dr != null ? dr.resourceType() : null; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverter.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverter.java index 36625b0689..3bfa8351d3 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverter.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverter.java @@ -43,7 +43,10 @@ private InformerConfiguration createInformerConfig( Class> dependentResourceClass = (Class>) spec.getDependentResourceClass(); - InformerConfiguration.Builder config = InformerConfiguration.builder(); + final var resourceType = controllerConfig.getConfigurationService().dependentResourceFactory() + .associatedResourceType(spec); + + InformerConfiguration.Builder config = InformerConfiguration.builder(resourceType); if (configAnnotation != null) { final var informerConfig = configAnnotation.informer(); final var context = Utils.contextFor(controllerConfig, dependentResourceClass, diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java index 2bb8c7a39a..174ffa0978 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java @@ -173,16 +173,16 @@ public void broadcastOnResourceEvent(ResourceAction action, P resource, P oldRes } public void changeNamespaces(Set namespaces) { - eventSources.controllerEventSource() - .changeNamespaces(namespaces); - executorServiceManager.boundedExecuteAndWaitForAllToComplete(eventSources + eventSources.controllerEventSource().changeNamespaces(namespaces); + final var namespaceChangeables = eventSources .additionalEventSources() .filter(NamespaceChangeable.class::isInstance) .map(NamespaceChangeable.class::cast) - .filter(NamespaceChangeable::allowsNamespaceChanges), e -> { - e.changeNamespaces(namespaces); - return null; - }, + .filter(NamespaceChangeable::allowsNamespaceChanges); + executorServiceManager.boundedExecuteAndWaitForAllToComplete(namespaceChangeables, e -> { + e.changeNamespaces(namespaces); + return null; + }, getEventSourceThreadNamer("changeNamespace")); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerEventSource.java index db457a4e41..07e5bd3fa2 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerEventSource.java @@ -43,11 +43,12 @@ public ControllerEventSource(Controller controller) { .or(onUpdateMarkedForDeletion()); // by default the on add should be processed in all cases regarding internal filters - config.onAddFilter().ifPresent(this::setOnAddFilter); - config.onUpdateFilter() + final var informerConfig = config.getInformerConfig(); + Optional.ofNullable(informerConfig.getOnAddFilter()).ifPresent(this::setOnAddFilter); + Optional.ofNullable(informerConfig.getOnUpdateFilter()) .ifPresentOrElse(filter -> setOnUpdateFilter(filter.and(internalOnUpdateFilter)), () -> setOnUpdateFilter(internalOnUpdateFilter)); - config.genericFilter().ifPresent(this::setGenericFilter); + Optional.ofNullable(informerConfig.getGenericFilter()).ifPresent(this::setGenericFilter); setControllerConfiguration(config); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index db3b9d6601..2568683600 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -106,10 +106,11 @@ private InformerEventSource(InformerEventSourceConfiguration configuration, primaryToSecondaryIndex = NOOPPrimaryToSecondaryIndex.getInstance(); } - onAddFilter = configuration.onAddFilter().orElse(null); - onUpdateFilter = configuration.onUpdateFilter().orElse(null); - onDeleteFilter = configuration.onDeleteFilter().orElse(null); - genericFilter = configuration.genericFilter().orElse(null); + final var informerConfig = configuration.getInformerConfig(); + onAddFilter = informerConfig.getOnAddFilter(); + onUpdateFilter = informerConfig.getOnUpdateFilter(); + onDeleteFilter = informerConfig.getOnDeleteFilter(); + genericFilter = informerConfig.getGenericFilter(); } @Override diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java index 9fc4a7db19..57bbf2a8ce 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java @@ -19,7 +19,8 @@ import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.ReconcilerUtils; import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.config.ResourceConfiguration; +import io.javaoperatorsdk.operator.api.config.Informable; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.health.InformerHealthIndicator; import io.javaoperatorsdk.operator.processing.LifecycleAware; import io.javaoperatorsdk.operator.processing.event.ResourceID; @@ -28,7 +29,7 @@ import static io.javaoperatorsdk.operator.api.reconciler.Constants.WATCH_ALL_NAMESPACES; -class InformerManager> +class InformerManager> implements LifecycleAware, IndexerResourceCache { private static final Logger log = LoggerFactory.getLogger(InformerManager.class); @@ -71,8 +72,9 @@ private void initSources() { if (!sources.isEmpty()) { throw new IllegalStateException("Some sources already initialized."); } - final var targetNamespaces = configuration.getEffectiveNamespaces(controllerConfiguration); - if (ResourceConfiguration.allNamespacesWatched(targetNamespaces)) { + final var targetNamespaces = + configuration.getInformerConfig().getEffectiveNamespaces(controllerConfiguration); + if (InformerConfiguration.allNamespacesWatched(targetNamespaces)) { var source = createEventSourceForNamespace(WATCH_ALL_NAMESPACES); log.debug("Registered {} -> {} for any namespace", this, source); } else { @@ -108,13 +110,14 @@ public void changeNamespaces(Set namespaces) { private InformerWrapper createEventSourceForNamespace(String namespace) { final InformerWrapper source; + final var labelSelector = configuration.getInformerConfig().getLabelSelector(); if (namespace.equals(WATCH_ALL_NAMESPACES)) { final var filteredBySelectorClient = - client.inAnyNamespace().withLabelSelector(configuration.getLabelSelector()); + client.inAnyNamespace().withLabelSelector(labelSelector); source = createEventSource(filteredBySelectorClient, eventHandler, WATCH_ALL_NAMESPACES); } else { source = createEventSource( - client.inNamespace(namespace).withLabelSelector(configuration.getLabelSelector()), + client.inNamespace(namespace).withLabelSelector(labelSelector), eventHandler, namespace); } source.addIndexers(indexers); @@ -124,9 +127,11 @@ private InformerWrapper createEventSourceForNamespace(String namespace) { private InformerWrapper createEventSource( FilterWatchListDeletable, Resource> filteredBySelectorClient, ResourceEventHandler eventHandler, String namespaceIdentifier) { - var informer = configuration.getInformerListLimit().map(filteredBySelectorClient::withLimit) + final var informerConfig = configuration.getInformerConfig(); + var informer = Optional.ofNullable(informerConfig.getInformerListLimit()) + .map(filteredBySelectorClient::withLimit) .orElse(filteredBySelectorClient).runnableInformer(0); - configuration.getItemStore().ifPresent(informer::itemStore); + Optional.ofNullable(informerConfig.getItemStore()).ifPresent(informer::itemStore); var source = new InformerWrapper<>(informer, controllerConfiguration.getConfigurationService(), namespaceIdentifier); source.addEventHandler(eventHandler); @@ -205,11 +210,12 @@ public List byIndex(String indexName, String indexKey) { @Override public String toString() { - final var selector = configuration.getLabelSelector(); + final var informerConfig = configuration.getInformerConfig(); + final var selector = informerConfig.getLabelSelector(); return "InformerManager [" + ReconcilerUtils.getResourceTypeNameWithVersion(configuration.getResourceClass()) + "] watching: " - + configuration.getEffectiveNamespaces(controllerConfiguration) + + informerConfig.getEffectiveNamespaces(controllerConfiguration) + (selector != null ? " selector: " + selector : ""); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java index 54d60e2cdf..f5e899826d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java @@ -17,8 +17,8 @@ import io.fabric8.kubernetes.client.informers.ResourceEventHandler; import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.config.Informable; import io.javaoperatorsdk.operator.api.config.NamespaceChangeable; -import io.javaoperatorsdk.operator.api.config.ResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationCacheFiller; import io.javaoperatorsdk.operator.health.InformerHealthIndicator; import io.javaoperatorsdk.operator.health.InformerWrappingEventSourceHealthIndicator; @@ -27,7 +27,7 @@ import io.javaoperatorsdk.operator.processing.event.source.*; @SuppressWarnings("rawtypes") -public abstract class ManagedInformerEventSource> +public abstract class ManagedInformerEventSource> extends AbstractEventSource implements ResourceEventHandler, Cache, IndexerResourceCache, RecentOperationCacheFiller, NamespaceChangeable, 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 00733b496b..46ef56e1d4 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 @@ -30,7 +30,7 @@ import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfigBuilder; import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition; -import static io.javaoperatorsdk.operator.api.config.informer.InformerEventSourceConfiguration.inheritsNamespacesFromController; +import static io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration.inheritsNamespacesFromController; import static org.junit.jupiter.api.Assertions.*; class ControllerConfigurationOverriderTest { @@ -67,7 +67,7 @@ void overridingNSShouldPreserveUntouchedDependents() { .settingNamespace(namespace) .replacingNamedDependentResourceConfig(externalDRName, stringConfig) .build(); - assertEquals(Set.of(namespace), configuration.getNamespaces()); + assertEquals(Set.of(namespace), configuration.getInformerConfig().getNamespaces()); // check that we still have the proper number of dependent configs dependentResources = configuration.getWorkflowSpec().orElseThrow().getDependentResourceSpecs(); @@ -77,12 +77,11 @@ void overridingNSShouldPreserveUntouchedDependents() { assertEquals(stringConfig, resourceConfig); } - @SuppressWarnings({"unchecked", "rawtypes"}) + @SuppressWarnings({"rawtypes"}) private KubernetesDependentResourceConfig extractFirstDependentKubernetesResourceConfig( io.javaoperatorsdk.operator.api.config.ControllerConfiguration configuration) { - var conf = (KubernetesDependentResourceConfig) extractDependentKubernetesResourceConfig( + return (KubernetesDependentResourceConfig) extractDependentKubernetesResourceConfig( configuration, 0); - return conf; } private io.javaoperatorsdk.operator.api.config.ControllerConfiguration createConfiguration( @@ -93,48 +92,55 @@ private io.javaoperatorsdk.operator.api.config.ControllerConfiguration create @Test void overridingNamespacesShouldWork() { var configuration = createConfiguration(new WatchCurrentReconciler()); - assertEquals(Set.of("foo"), configuration.getNamespaces()); - assertFalse(configuration.watchAllNamespaces()); - assertFalse(configuration.watchCurrentNamespace()); + var informerConfig = configuration.getInformerConfig(); + assertEquals(Set.of("foo"), informerConfig.getNamespaces()); + assertFalse(informerConfig.watchAllNamespaces()); + assertFalse(informerConfig.watchCurrentNamespace()); configuration = ControllerConfigurationOverrider.override(configuration) .addingNamespaces("foo", "bar") .build(); - assertEquals(Set.of("foo", "bar"), configuration.getNamespaces()); - assertFalse(configuration.watchAllNamespaces()); - assertFalse(configuration.watchCurrentNamespace()); + informerConfig = configuration.getInformerConfig(); + assertEquals(Set.of("foo", "bar"), informerConfig.getNamespaces()); + assertFalse(informerConfig.watchAllNamespaces()); + assertFalse(informerConfig.watchCurrentNamespace()); configuration = ControllerConfigurationOverrider.override(configuration) .removingNamespaces("bar") .build(); - assertEquals(Set.of("foo"), configuration.getNamespaces()); - assertFalse(configuration.watchAllNamespaces()); - assertFalse(configuration.watchCurrentNamespace()); + informerConfig = configuration.getInformerConfig(); + assertEquals(Set.of("foo"), informerConfig.getNamespaces()); + assertFalse(informerConfig.watchAllNamespaces()); + assertFalse(informerConfig.watchCurrentNamespace()); configuration = ControllerConfigurationOverrider.override(configuration) .removingNamespaces("foo") .build(); - assertTrue(configuration.watchAllNamespaces()); - assertFalse(configuration.watchCurrentNamespace()); + informerConfig = configuration.getInformerConfig(); + assertTrue(informerConfig.watchAllNamespaces()); + assertFalse(informerConfig.watchCurrentNamespace()); configuration = ControllerConfigurationOverrider.override(configuration) .settingNamespace("foo") .build(); - assertFalse(configuration.watchAllNamespaces()); - assertFalse(configuration.watchCurrentNamespace()); - assertEquals(Set.of("foo"), configuration.getNamespaces()); + informerConfig = configuration.getInformerConfig(); + assertFalse(informerConfig.watchAllNamespaces()); + assertFalse(informerConfig.watchCurrentNamespace()); + assertEquals(Set.of("foo"), informerConfig.getNamespaces()); configuration = ControllerConfigurationOverrider.override(configuration) .watchingOnlyCurrentNamespace() .build(); - assertFalse(configuration.watchAllNamespaces()); - assertTrue(configuration.watchCurrentNamespace()); + informerConfig = configuration.getInformerConfig(); + assertFalse(informerConfig.watchAllNamespaces()); + assertTrue(informerConfig.watchCurrentNamespace()); configuration = ControllerConfigurationOverrider.override(configuration) .watchingAllNamespaces() .build(); - assertTrue(configuration.watchAllNamespaces()); - assertFalse(configuration.watchCurrentNamespace()); + informerConfig = configuration.getInformerConfig(); + assertTrue(informerConfig.watchAllNamespaces()); + assertFalse(informerConfig.watchCurrentNamespace()); } @Test @@ -144,23 +150,24 @@ void itemStorePreserved() { configuration = ControllerConfigurationOverrider.override(configuration) .build(); - assertNotNull(configuration.getItemStore().orElse(null)); + assertNotNull(configuration.getInformerConfig().getItemStore()); } @Test void configuredDependentShouldNotChangeOnParentOverrideEvenWhenInitialConfigIsSame() { var configuration = createConfiguration(new OverriddenNSOnDepReconciler()); // retrieve the config for the first (and unique) dependent - var config = extractFirstDependentKubernetesResourceConfig(configuration); + var kubeDependentConfig = extractFirstDependentKubernetesResourceConfig(configuration); // override the parent NS to match the dependent's configuration = ControllerConfigurationOverrider.override(configuration) .settingNamespace(OverriddenNSDependent.DEP_NS).build(); - assertEquals(Set.of(OverriddenNSDependent.DEP_NS), configuration.getNamespaces()); + assertEquals(Set.of(OverriddenNSDependent.DEP_NS), + configuration.getInformerConfig().getNamespaces()); // check that the DependentResource inherits has its own configured NS - var informerConfig = config.informerConfig(); - assertEquals(Set.of(OverriddenNSDependent.DEP_NS), informerConfig.getNamespaces()); + assertEquals(Set.of(OverriddenNSDependent.DEP_NS), + kubeDependentConfig.informerConfig().getNamespaces()); // override the parent's NS final var newNS = "bar"; @@ -168,9 +175,9 @@ void configuredDependentShouldNotChangeOnParentOverrideEvenWhenInitialConfigIsSa ControllerConfigurationOverrider.override(configuration).settingNamespace(newNS).build(); // check that dependent config is still using its own NS - config = extractFirstDependentKubernetesResourceConfig(configuration); - informerConfig = config.informerConfig(); - assertEquals(Set.of(OverriddenNSDependent.DEP_NS), informerConfig.getNamespaces()); + kubeDependentConfig = extractFirstDependentKubernetesResourceConfig(configuration); + assertEquals(Set.of(OverriddenNSDependent.DEP_NS), + kubeDependentConfig.informerConfig().getNamespaces()); } @SuppressWarnings("unchecked") @@ -182,8 +189,7 @@ void dependentShouldWatchAllNamespacesIfParentDoesAsWell() { // check that the DependentResource inherits the controller's configuration if applicable var informerConfig = config.informerConfig(); - assertTrue( - inheritsNamespacesFromController(informerConfig.getNamespaces())); + assertTrue(inheritsNamespacesFromController(informerConfig.getNamespaces())); } @@ -196,7 +202,7 @@ void shouldBePossibleToForceDependentToWatchAllNamespaces() { // check that the DependentResource inherits the controller's configuration if applicable assertTrue( - ResourceConfiguration + InformerConfiguration .allNamespacesWatched(config.informerConfig().getNamespaces())); // override the NS @@ -207,12 +213,11 @@ void shouldBePossibleToForceDependentToWatchAllNamespaces() { // check that dependent config is still configured to watch all NS config = extractFirstDependentKubernetesResourceConfig(configuration); assertTrue( - ResourceConfiguration + InformerConfiguration .allNamespacesWatched(config.informerConfig().getNamespaces())); } @Test - @SuppressWarnings("unchecked") void overridingNamespacesShouldBePropagatedToDependentsWithDefaultConfig() { var configuration = createConfiguration(new OneDepReconciler()); // retrieve the config for the first (and unique) dependent diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/InformerConfigurationTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/InformerConfigurationTest.java new file mode 100644 index 0000000000..468c67e0d7 --- /dev/null +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/InformerConfigurationTest.java @@ -0,0 +1,83 @@ +package io.javaoperatorsdk.operator.api.config; + +import java.util.Collections; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.Constants; + +import static org.junit.jupiter.api.Assertions.*; + +class InformerConfigurationTest { + + @Test + void allNamespacesWatched() { + assertThrows(IllegalArgumentException.class, + () -> InformerConfiguration.allNamespacesWatched(null)); + assertThrows(IllegalArgumentException.class, () -> InformerConfiguration.allNamespacesWatched( + Set.of(Constants.WATCH_CURRENT_NAMESPACE, Constants.WATCH_ALL_NAMESPACES, "foo"))); + assertThrows(IllegalArgumentException.class, () -> InformerConfiguration.allNamespacesWatched( + Collections.emptySet())); + assertFalse(InformerConfiguration.allNamespacesWatched(Set.of("foo", "bar"))); + assertTrue(InformerConfiguration.allNamespacesWatched(Set.of(Constants.WATCH_ALL_NAMESPACES))); + assertFalse(InformerConfiguration.allNamespacesWatched(Set.of("foo"))); + assertFalse( + InformerConfiguration.allNamespacesWatched(Set.of(Constants.WATCH_CURRENT_NAMESPACE))); + } + + @Test + void currentNamespaceWatched() { + assertThrows(IllegalArgumentException.class, + () -> InformerConfiguration.currentNamespaceWatched(null)); + assertThrows(IllegalArgumentException.class, + () -> InformerConfiguration.currentNamespaceWatched( + Set.of(Constants.WATCH_CURRENT_NAMESPACE, Constants.WATCH_ALL_NAMESPACES, "foo"))); + assertThrows(IllegalArgumentException.class, + () -> InformerConfiguration.currentNamespaceWatched(Collections.emptySet())); + assertFalse(InformerConfiguration.currentNamespaceWatched(Set.of("foo", "bar"))); + assertFalse( + InformerConfiguration.currentNamespaceWatched(Set.of(Constants.WATCH_ALL_NAMESPACES))); + assertFalse(InformerConfiguration.currentNamespaceWatched(Set.of("foo"))); + assertTrue( + InformerConfiguration.currentNamespaceWatched(Set.of(Constants.WATCH_CURRENT_NAMESPACE))); + } + + @Test + void nullLabelSelectorByDefault() { + final var informerConfig = + InformerConfiguration.builder(ConfigMap.class).buildForInformerEventSource(); + assertNull(informerConfig.getLabelSelector()); + } + + @Test + void shouldWatchAllNamespacesByDefaultForControllers() { + final var informerConfig = InformerConfiguration.builder(ConfigMap.class).buildForController(); + assertTrue(informerConfig.watchAllNamespaces()); + } + + @Test + void shouldFollowControllerNamespacesByDefaultForInformerEventSource() { + final var informerConfig = + InformerConfiguration.builder(ConfigMap.class).buildForInformerEventSource(); + assertTrue(informerConfig.isFollowControllerNamespacesOnChange()); + } + + @Test + void failIfNotValid() { + assertThrows(IllegalArgumentException.class, () -> InformerConfiguration.failIfNotValid(null)); + assertThrows(IllegalArgumentException.class, + () -> InformerConfiguration.failIfNotValid(Collections.emptySet())); + assertThrows(IllegalArgumentException.class, () -> InformerConfiguration.failIfNotValid( + Set.of(Constants.WATCH_CURRENT_NAMESPACE, Constants.WATCH_ALL_NAMESPACES, "foo"))); + assertThrows(IllegalArgumentException.class, () -> InformerConfiguration.failIfNotValid( + Set.of(Constants.WATCH_CURRENT_NAMESPACE, "foo"))); + assertThrows(IllegalArgumentException.class, () -> InformerConfiguration.failIfNotValid( + Set.of(Constants.WATCH_ALL_NAMESPACES, "foo"))); + + // should work + InformerConfiguration.failIfNotValid(Set.of("foo", "bar")); + } +} diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/MockControllerConfiguration.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/MockControllerConfiguration.java index 6ae83294bb..afd01d0f90 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/MockControllerConfiguration.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/MockControllerConfiguration.java @@ -1,6 +1,7 @@ package io.javaoperatorsdk.operator.api.config; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import static io.javaoperatorsdk.operator.api.reconciler.Constants.DEFAULT_NAMESPACES_SET; import static org.mockito.ArgumentMatchers.any; @@ -18,9 +19,11 @@ public static ControllerConfiguration forResource( public static ControllerConfiguration forResource( Class resourceType, ConfigurationService configurationService) { final ControllerConfiguration configuration = mock(ControllerConfiguration.class); + final InformerConfiguration informerConfiguration = mock(InformerConfiguration.class); + when(configuration.getInformerConfig()).thenReturn(informerConfiguration); when(configuration.getResourceClass()).thenReturn(resourceType); - when(configuration.getNamespaces()).thenReturn(DEFAULT_NAMESPACES_SET); - when(configuration.getEffectiveNamespaces(any())).thenCallRealMethod(); + when(informerConfiguration.getNamespaces()).thenReturn(DEFAULT_NAMESPACES_SET); + when(informerConfiguration.getEffectiveNamespaces(any())).thenCallRealMethod(); when(configuration.getName()).thenReturn(resourceType.getSimpleName()); when(configuration.getConfigurationService()).thenReturn(configurationService); return configuration; diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ResourceConfigurationTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ResourceConfigurationTest.java deleted file mode 100644 index 5cf8376ea2..0000000000 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ResourceConfigurationTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package io.javaoperatorsdk.operator.api.config; - -import java.util.Collections; -import java.util.Set; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.Constants; - -import static org.junit.jupiter.api.Assertions.*; - -class ResourceConfigurationTest { - - public static final ResourceConfiguration DEFAULT = - () -> InformerConfiguration.builder().buildForInformerEventSource(); - - @Test - void allNamespacesWatched() { - assertThrows(IllegalArgumentException.class, - () -> ResourceConfiguration.allNamespacesWatched(null)); - assertThrows(IllegalArgumentException.class, () -> ResourceConfiguration.allNamespacesWatched( - Set.of(Constants.WATCH_CURRENT_NAMESPACE, Constants.WATCH_ALL_NAMESPACES, "foo"))); - assertThrows(IllegalArgumentException.class, () -> ResourceConfiguration.allNamespacesWatched( - Collections.emptySet())); - assertFalse(ResourceConfiguration.allNamespacesWatched(Set.of("foo", "bar"))); - assertTrue(ResourceConfiguration.allNamespacesWatched(Set.of(Constants.WATCH_ALL_NAMESPACES))); - assertFalse(ResourceConfiguration.allNamespacesWatched(Set.of("foo"))); - assertFalse( - ResourceConfiguration.allNamespacesWatched(Set.of(Constants.WATCH_CURRENT_NAMESPACE))); - } - - @Test - void currentNamespaceWatched() { - assertThrows(IllegalArgumentException.class, - () -> ResourceConfiguration.currentNamespaceWatched(null)); - assertThrows(IllegalArgumentException.class, - () -> ResourceConfiguration.currentNamespaceWatched( - Set.of(Constants.WATCH_CURRENT_NAMESPACE, Constants.WATCH_ALL_NAMESPACES, "foo"))); - assertThrows(IllegalArgumentException.class, - () -> ResourceConfiguration.currentNamespaceWatched(Collections.emptySet())); - assertFalse(ResourceConfiguration.currentNamespaceWatched(Set.of("foo", "bar"))); - assertFalse( - ResourceConfiguration.currentNamespaceWatched(Set.of(Constants.WATCH_ALL_NAMESPACES))); - assertFalse(ResourceConfiguration.currentNamespaceWatched(Set.of("foo"))); - assertTrue( - ResourceConfiguration.currentNamespaceWatched(Set.of(Constants.WATCH_CURRENT_NAMESPACE))); - } - - @Test - void nullLabelSelectorByDefault() { - assertNull(DEFAULT.getLabelSelector()); - } - - // todo: fix me - @Disabled - @Test - void shouldWatchAllNamespacesByDefault() { - assertTrue(DEFAULT.watchAllNamespaces()); - } - - @Test - void failIfNotValid() { - assertThrows(IllegalArgumentException.class, () -> ResourceConfiguration.failIfNotValid(null)); - assertThrows(IllegalArgumentException.class, - () -> ResourceConfiguration.failIfNotValid(Collections.emptySet())); - assertThrows(IllegalArgumentException.class, () -> ResourceConfiguration.failIfNotValid( - Set.of(Constants.WATCH_CURRENT_NAMESPACE, Constants.WATCH_ALL_NAMESPACES, "foo"))); - assertThrows(IllegalArgumentException.class, () -> ResourceConfiguration.failIfNotValid( - Set.of(Constants.WATCH_CURRENT_NAMESPACE, "foo"))); - assertThrows(IllegalArgumentException.class, () -> ResourceConfiguration.failIfNotValid( - Set.of(Constants.WATCH_ALL_NAMESPACES, "foo"))); - - // should work - ResourceConfiguration.failIfNotValid(Set.of("foo", "bar")); - } -} diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventSourceManagerTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventSourceManagerTest.java index e24de96dbb..a7f0dade3b 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventSourceManagerTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventSourceManagerTest.java @@ -168,14 +168,13 @@ void changesNamespacesOnControllerAndInformerEventSources() { when(controllerResourceEventSourceMock.allowsNamespaceChanges()).thenCallRealMethod(); var manager = new EventSourceManager(controller, eventSources); - InformerEventSourceConfiguration informerConfigurationMock = + InformerEventSourceConfiguration eventSourceConfigurationMock = mock(InformerEventSourceConfiguration.class); - when(informerConfigurationMock.followControllerNamespaceChanges()).thenReturn(true); InformerEventSource informerEventSource = mock(InformerEventSource.class); when(informerEventSource.name()).thenReturn("ies"); when(informerEventSource.resourceType()).thenReturn(TestCustomResource.class); - when(informerEventSource.configuration()).thenReturn(informerConfigurationMock); - when(informerEventSource.allowsNamespaceChanges()).thenCallRealMethod(); + when(informerEventSource.configuration()).thenReturn(eventSourceConfigurationMock); + when(informerEventSource.allowsNamespaceChanges()).thenReturn(true); manager.registerEventSource(informerEventSource); manager.changeNamespaces(Set.of(newNamespaces)); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerEventSourceTest.java index 5282fd2138..4ba2a5184c 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerEventSourceTest.java @@ -191,7 +191,6 @@ public TestConfiguration(boolean generationAware, OnAddFilter onUpdateFilter, GenericFilter genericFilter) { super( - TestCustomResource.class, "test", generationAware, null, diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java index 442f53bc98..ce027846f0 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java @@ -16,6 +16,7 @@ import io.javaoperatorsdk.operator.api.config.ConfigurationService; import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; import io.javaoperatorsdk.operator.api.config.InformerStoppedHandler; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.config.informer.InformerEventSourceConfiguration; import io.javaoperatorsdk.operator.processing.event.EventHandler; import io.javaoperatorsdk.operator.processing.event.ResourceID; @@ -44,18 +45,19 @@ class InformerEventSourceTest { private final TemporaryResourceCache temporaryResourceCacheMock = mock(TemporaryResourceCache.class); private final EventHandler eventHandlerMock = mock(EventHandler.class); - private final InformerEventSourceConfiguration informerConfiguration = + private final InformerEventSourceConfiguration informerEventSourceConfiguration = mock(InformerEventSourceConfiguration.class); @BeforeEach void setup() { - when(informerConfiguration.getEffectiveNamespaces(any())) - .thenReturn(DEFAULT_NAMESPACES_SET); - when(informerConfiguration.getSecondaryToPrimaryMapper()) + final var informerConfig = mock(InformerConfiguration.class); + when(informerEventSourceConfiguration.getInformerConfig()).thenReturn(informerConfig); + when(informerConfig.getEffectiveNamespaces(any())).thenReturn(DEFAULT_NAMESPACES_SET); + when(informerEventSourceConfiguration.getSecondaryToPrimaryMapper()) .thenReturn(mock(SecondaryToPrimaryMapper.class)); - when(informerConfiguration.getResourceClass()).thenReturn(Deployment.class); + when(informerEventSourceConfiguration.getResourceClass()).thenReturn(Deployment.class); - informerEventSource = new InformerEventSource<>(informerConfiguration, clientMock); + informerEventSource = new InformerEventSource<>(informerEventSourceConfiguration, clientMock); var mockControllerConfig = mock(ControllerConfiguration.class); when(mockControllerConfig.getConfigurationService()).thenReturn(new BaseConfigurationService()); @@ -63,7 +65,7 @@ void setup() { informerEventSource.setEventHandler(eventHandlerMock); informerEventSource.setControllerConfiguration(mockControllerConfig); SecondaryToPrimaryMapper secondaryToPrimaryMapper = mock(SecondaryToPrimaryMapper.class); - when(informerConfiguration.getSecondaryToPrimaryMapper()) + when(informerEventSourceConfiguration.getSecondaryToPrimaryMapper()) .thenReturn(secondaryToPrimaryMapper); when(secondaryToPrimaryMapper.toPrimaryResourceIDs(any())) .thenReturn(Set.of(ResourceID.fromResource(testDeployment()))); @@ -184,7 +186,7 @@ void informerStoppedHandlerShouldBeCalledWhenInformerStops() { var mockControllerConfig = mock(ControllerConfiguration.class); when(mockControllerConfig.getConfigurationService()).thenReturn(configuration); - informerEventSource = new InformerEventSource<>(informerConfiguration, + informerEventSource = new InformerEventSource<>(informerEventSourceConfiguration, MockKubernetesClient.client(Deployment.class, unused -> { throw exception; })); 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 12573b50f7..1a1214aa78 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 @@ -11,7 +11,6 @@ public class DefaultConfigurationService extends BaseConfigurationService { @Override protected ControllerConfiguration configFor(Reconciler reconciler) { final var other = super.configFor(reconciler); - return new ResolvedControllerConfiguration<>( - RuntimeControllerMetadata.getResourceClass(reconciler), other); + return new ResolvedControllerConfiguration<>(other); } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java index bde573171d..77a3b245b0 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java @@ -71,7 +71,10 @@ public List> prepareE var config = InformerEventSourceConfiguration .from(ConfigMap.class, MultipleSecondaryEventSourceCustomResource.class) .withInformerConfiguration(c -> c - .withNamespaces(context.getControllerConfiguration().getNamespaces()) + // TODO: this shouldn't be needed since this should be the default behavior (tracking + // the controller's namespaces) + .withNamespaces( + context.getControllerConfiguration().getInformerConfig().getNamespaces()) .withLabelSelector("multisecondary")) .withSecondaryToPrimaryMapper(s -> { var name = diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/BaseConfigurationServiceTest.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/BaseConfigurationServiceTest.java index 43309446fb..c83505e597 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/BaseConfigurationServiceTest.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/BaseConfigurationServiceTest.java @@ -112,19 +112,21 @@ void missingAnnotationCreatesDefaultConfig() { var config = configFor(reconciler); assertThat(config.getName()).isEqualTo(ReconcilerUtils.getNameFor(reconciler)); - assertThat(config.getLabelSelector()).isNull(); assertThat(config.getRetry()).isInstanceOf(GenericRetry.class); assertThat(config.getRateLimiter()).isInstanceOf(LinearRateLimiter.class); assertThat(config.maxReconciliationInterval()).hasValue(Duration.ofHours(DEFAULT_INTERVAL)); assertThat(config.fieldManager()).isEqualTo(config.getName()); - assertThat(config.getInformerListLimit()).isEmpty(); - assertThat(config.onAddFilter()).isEmpty(); - assertThat(config.onUpdateFilter()).isEmpty(); - assertThat(config.genericFilter()).isEmpty(); - assertThat(config.getNamespaces()).isEqualTo(Constants.DEFAULT_NAMESPACES_SET); assertThat(config.getFinalizerName()) .isEqualTo(ReconcilerUtils.getDefaultFinalizerName(config.getResourceClass())); - assertThat(config.getItemStore()).isEmpty(); + + final var informerConfig = config.getInformerConfig(); + assertThat(informerConfig.getLabelSelector()).isNull(); + assertNull(informerConfig.getInformerListLimit()); + assertNull(informerConfig.getOnAddFilter()); + assertNull(informerConfig.getOnUpdateFilter()); + assertNull(informerConfig.getGenericFilter()); + assertNull(informerConfig.getItemStore()); + assertThat(informerConfig.getNamespaces()).isEqualTo(Constants.DEFAULT_NAMESPACES_SET); } @SuppressWarnings("rawtypes") diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageDependentsWorkflowReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageDependentsWorkflowReconciler.java index b38f48b912..15343793fd 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageDependentsWorkflowReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageDependentsWorkflowReconciler.java @@ -85,7 +85,7 @@ private void initDependentResources(KubernetesClient client) { Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR) .forEach(dr -> dr.configureWith(new KubernetesDependentResourceConfigBuilder() - .withKubernetesDependentInformerConfig(InformerConfiguration.builder() + .withKubernetesDependentInformerConfig(InformerConfiguration.builder(dr.resourceType()) .withLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR) .buildForInformerEventSource()) .build())); diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java index e7930a3658..580d529a72 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java @@ -96,7 +96,7 @@ private Workflow createDependentResourcesAndWorkflow() { // configure them with our label selector Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR) .forEach(dr -> dr.configureWith(new KubernetesDependentResourceConfigBuilder() - .withKubernetesDependentInformerConfig(InformerConfiguration.builder() + .withKubernetesDependentInformerConfig(InformerConfiguration.builder(dr.resourceType()) .withLabelSelector(SELECTOR + "=true") .buildForInformerEventSource()) .build()));