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 d908f52ebe..130c446900 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 @@ -161,7 +161,7 @@ protected

ControllerConfiguration

configFor(Reconcile Constants.NO_VALUE_SET), null, Utils.instantiate(annotation.itemStore(), ItemStore.class, context), dependentFieldManager, - this, informerListLimit); + this, informerListLimit, annotation.reconcileResourcesMarkedForDeletion()); ResourceEventFilter

answer = deprecatedEventFilter(annotation); config.setEventFilter(answer != null ? answer : ResourceEventFilters.passthrough()); 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 13ddd995ad..0adcc318dd 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 @@ -20,6 +20,9 @@ public interface ControllerConfiguration

extends ResourceConfiguration

{ + boolean DEFAULT_RECONCILER_RESOURCES_MARKED_FOR_DELETION = false; + + @SuppressWarnings("rawtypes") RateLimiter DEFAULT_RATE_LIMITER = LinearRateLimiter.deactivatedRateLimiter(); /** @@ -140,4 +143,8 @@ default String fieldManager() { return getName(); } + default boolean reconcileResourcesMarkedForDeletion() { + return DEFAULT_RECONCILER_RESOURCES_MARKED_FOR_DELETION; + } + } 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 328d912109..aa3b509194 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 @@ -41,6 +41,7 @@ public class ControllerConfigurationOverrider { private String name; private String fieldManager; private Long informerListLimit; + private Boolean reconcileResourcesMarkedForDeletion; private ControllerConfigurationOverrider(ControllerConfiguration original) { this.finalizer = original.getFinalizerName(); @@ -59,6 +60,7 @@ private ControllerConfigurationOverrider(ControllerConfiguration original) { this.fieldManager = original.fieldManager(); this.informerListLimit = original.getInformerListLimit().orElse(null); this.itemStore = original.getItemStore().orElse(null); + this.reconcileResourcesMarkedForDeletion = original.reconcileResourcesMarkedForDeletion(); } public ControllerConfigurationOverrider withFinalizer(String finalizer) { @@ -179,6 +181,12 @@ public ControllerConfigurationOverrider withFieldManager( return this; } + public ControllerConfigurationOverrider withReconcileResourcesMarkedForDeletion( + boolean reconcileResourcesMarkedForDeletion) { + this.reconcileResourcesMarkedForDeletion = reconcileResourcesMarkedForDeletion; + return this; + } + /** * Sets a max page size limit when starting the informer. This will result in pagination while @@ -216,7 +224,7 @@ public ControllerConfiguration build() { reconciliationMaxInterval, onAddFilter, onUpdateFilter, genericFilter, original.getDependentResources(), namespaces, finalizer, labelSelector, configurations, itemStore, fieldManager, - original.getConfigurationService(), informerListLimit); + original.getConfigurationService(), informerListLimit, reconcileResourcesMarkedForDeletion); overridden.setEventFilter(customResourcePredicate); return overridden; } 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 307e75080f..1e188b0b62 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 @@ -33,6 +33,7 @@ public class ResolvedControllerConfiguration

private final ItemStore

itemStore; private final ConfigurationService configurationService; private final String fieldManager; + private final boolean reconcileResourcesMarkedForDeletion; private ResourceEventFilter

eventFilter; private List dependentResources; @@ -47,7 +48,7 @@ public ResolvedControllerConfiguration(Class

resourceClass, ControllerConfigu other.getFinalizerName(), other.getLabelSelector(), Collections.emptyMap(), other.getItemStore().orElse(null), other.fieldManager(), other.getConfigurationService(), - other.getInformerListLimit().orElse(null)); + other.getInformerListLimit().orElse(null), other.reconcileResourcesMarkedForDeletion()); } public static Duration getMaxReconciliationInterval(long interval, TimeUnit timeUnit) { @@ -76,11 +77,12 @@ public ResolvedControllerConfiguration(Class

resourceClass, String name, Set namespaces, String finalizer, String labelSelector, Map configurations, ItemStore

itemStore, String fieldManager, - ConfigurationService configurationService, Long informerListLimit) { + ConfigurationService configurationService, Long informerListLimit, + Boolean reconcileResourcesMarkedForDeletion) { this(resourceClass, name, generationAware, associatedReconcilerClassName, retry, rateLimiter, maxReconciliationInterval, onAddFilter, onUpdateFilter, genericFilter, namespaces, finalizer, labelSelector, configurations, itemStore, fieldManager, - configurationService, informerListLimit); + configurationService, informerListLimit, reconcileResourcesMarkedForDeletion); setDependentResources(dependentResources); } @@ -92,7 +94,8 @@ protected ResolvedControllerConfiguration(Class

resourceClass, String name, Set namespaces, String finalizer, String labelSelector, Map configurations, ItemStore

itemStore, String fieldManager, - ConfigurationService configurationService, Long informerListLimit) { + ConfigurationService configurationService, Long informerListLimit, + boolean reconcileResourcesMarkedForDeletion) { super(resourceClass, namespaces, labelSelector, onAddFilter, onUpdateFilter, genericFilter, itemStore, informerListLimit); this.configurationService = configurationService; @@ -107,13 +110,14 @@ protected ResolvedControllerConfiguration(Class

resourceClass, String name, this.finalizer = ControllerConfiguration.ensureValidFinalizerName(finalizer, getResourceTypeName()); this.fieldManager = fieldManager; + this.reconcileResourcesMarkedForDeletion = reconcileResourcesMarkedForDeletion; } protected ResolvedControllerConfiguration(Class

resourceClass, String name, Class reconcilerClas, ConfigurationService configurationService) { this(resourceClass, name, false, getAssociatedReconcilerClassName(reconcilerClas), null, null, null, null, null, null, null, - null, null, null, null, null, configurationService, null); + null, null, null, null, null, configurationService, null, false); } @Override @@ -195,4 +199,9 @@ public Optional> getItemStore() { public String fieldManager() { return fieldManager; } + + @Override + public boolean reconcileResourcesMarkedForDeletion() { + return reconcileResourcesMarkedForDeletion; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java index c064e669e0..a315fd8206 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java @@ -19,6 +19,7 @@ import io.javaoperatorsdk.operator.processing.retry.Retry; import static io.javaoperatorsdk.operator.api.config.ControllerConfiguration.CONTROLLER_NAME_AS_FIELD_MANAGER; +import static io.javaoperatorsdk.operator.api.config.ControllerConfiguration.DEFAULT_RECONCILER_RESOURCES_MARKED_FOR_DELETION; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_LONG_VALUE_SET; @Inherited @@ -166,4 +167,11 @@ MaxReconciliationInterval maxReconciliationInterval() default @MaxReconciliation * the informer cache. */ long informerListLimit() default NO_LONG_VALUE_SET; + + /** + * if true and reconciler not implements {@link Cleaner} interface executes reconciliation even if + * controller is marked for deletion, thus when waiting for other finalizer removal. This allows + * to manage corner cases when not all resources will need a finalizer. + */ + boolean reconcileResourcesMarkedForDeletion() default DEFAULT_RECONCILER_RESOURCES_MARKED_FOR_DELETION; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java index ed3eb38521..685473775f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java @@ -75,7 +75,7 @@ private PostExecutionControl

handleDispatch(ExecutionScope

executionScope) originalResource.getMetadata().getNamespace()); final var markedForDeletion = originalResource.isMarkedForDeletion(); - if (markedForDeletion && shouldNotDispatchToCleanupWhenMarkedForDeletion(originalResource)) { + if (markedForDeletion && shouldNotDispatchWhenMarkedForDeletion(originalResource)) { log.debug( "Skipping cleanup of resource {} because finalizer(s) {} don't allow processing yet", getName(originalResource), @@ -85,21 +85,22 @@ private PostExecutionControl

handleDispatch(ExecutionScope

executionScope) Context

context = new DefaultContext<>(executionScope.getRetryInfo(), controller, originalResource); - if (markedForDeletion) { + if (markedForDeletion && controller.useFinalizer()) { return handleCleanup(resourceForExecution, context); } else { return handleReconcile(executionScope, resourceForExecution, originalResource, context); } } - private boolean shouldNotDispatchToCleanupWhenMarkedForDeletion(P resource) { + private boolean shouldNotDispatchWhenMarkedForDeletion(P resource) { var alreadyRemovedFinalizer = controller.useFinalizer() && !resource.hasFinalizer(configuration().getFinalizerName()); if (alreadyRemovedFinalizer) { log.warn("This should not happen. Marked for deletion & already removed finalizer: {}", ResourceID.fromResource(resource)); } - return !controller.useFinalizer() || alreadyRemovedFinalizer; + return !controller.getConfiguration().reconcileResourcesMarkedForDeletion() && + (!controller.useFinalizer() || alreadyRemovedFinalizer); } private PostExecutionControl

handleReconcile( 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 c8ec839b59..eb80388be4 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 @@ -145,7 +145,8 @@ public ControllerConfig(String finalizer, boolean generationAware, null, null, null, - null, null, null, finalizer, null, null, null, new BaseConfigurationService(), null); + null, null, null, finalizer, null, null, null, new BaseConfigurationService(), null, + false); 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 64f0993139..aacf28af84 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 @@ -199,7 +199,7 @@ public TestConfiguration(boolean generationAware, OnAddFilter