Skip to content

Commit 5a9bbe2

Browse files
csvirimetacosmscrocquesel
authored
feat: separate interface for cleanup part of reconciler (#1035)
Co-authored-by: Chris Laprun <[email protected]> Co-authored-by: Sébastien CROCQUESEL <[email protected]>
1 parent 392c365 commit 5a9bbe2

File tree

82 files changed

+604
-348
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+604
-348
lines changed

docs/documentation/features.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,13 @@ execution.
3737
[Kubernetes finalizers](https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers/)
3838
make sure that a reconciliation happens when a custom resource is instructed to be deleted. Typical case when it's
3939
useful, when an operator is down (pod not running). Without a finalizer the reconciliation - thus the cleanup -
40-
i.e. [`Reconciler.cleanup(...)`](https://github.com/java-operator-sdk/java-operator-sdk/blob/b91221bb54af19761a617bf18eef381e8ceb3b4c/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Reconciler.java#L31)
40+
i.e. [`Cleaner.cleanup(...)`](https://github.com/java-operator-sdk/java-operator-sdk/blob/b82c1f106968cb3eb18835c5e9cd1e4d5c40362e/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Cleaner.java#L28-L28)
4141
would not happen if a custom resource is deleted.
4242

43+
To use finalizers the reconciler have to implement [`Cleaner<P>`](https://github.com/java-operator-sdk/java-operator-sdk/blob/b82c1f106968cb3eb18835c5e9cd1e4d5c40362e/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Cleaner.java) interface.
44+
In other words, finalizer is added if the `Reconciler` implements `Cleaner` interface. If not, no
45+
finalizer is added and/or removed.
46+
4347
Finalizers are automatically added by the framework as the first step, thus after a custom resource is created, but
4448
before the first reconciliation. The finalizer is added via a separate Kubernetes API call. As a result of this update,
4549
the finalizer will be present. The subsequent event will be received, which will trigger the first reconciliation.
@@ -50,7 +54,6 @@ in some specific corner cases, when there would be a long waiting period for som
5054

5155
The name of the finalizers can be specified, in case it is not, a name will be generated.
5256

53-
Automatic finalizer handling can be turned off, so when configured no finalizer will be added or removed.
5457
See [`@ControllerConfiguration`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java)
5558
annotation for more details.
5659

@@ -66,7 +69,7 @@ When automatic finalizer handling is turned off, the `Reconciler.cleanup(...)` m
6669
case when a delete event received. So it does not make sense to implement this method and turn off finalizer at the same
6770
time.
6871

69-
## The `reconcile` and `cleanup` Methods of [`Reconciler`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Reconciler.java)
72+
## The `reconcile` and [`cleanup`](https://github.com/java-operator-sdk/java-operator-sdk/blob/b82c1f106968cb3eb18835c5e9cd1e4d5c40362e/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Cleaner.java) Methods on a [`Reconciler`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Reconciler.java)
7073

7174
The lifecycle of a custom resource can be clearly separated into two phases from the perspective of an operator. When a
7275
custom resource is created or update, or on the other hand when the custom resource is deleted - or rather marked for
@@ -75,9 +78,8 @@ deletion in case a finalizer is used.
7578
This separation-related logic is automatically handled by the framework. The framework will always call `reconcile`
7679
method, unless the custom resource is
7780
[marked from deletion](https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers/#how-finalizers-work)
78-
. From the point when the custom resource is marked from deletion, only the `cleanup` method is called.
79-
80-
If there is **no finalizer** in place (see Finalizer Support section), the `cleanup` method is **not called**.
81+
. From the point when the custom resource is marked from deletion, only the `cleanup` method is called, of course
82+
only if the reconciler implements the `Cleaner` interface.
8183

8284
### Using [`UpdateControl`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/UpdateControl.java) and [`DeleteControl`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DeleteControl.java)
8385

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public void setApiVersion(String s) {
4242
throw new UnsupportedOperationException();
4343
}
4444
};
45-
return Constants.NO_FINALIZER.equals(finalizer) || validator.isFinalizerValid(finalizer);
45+
return validator.isFinalizerValid(finalizer);
4646
}
4747

4848
public static String getResourceTypeNameWithVersion(Class<? extends HasMetadata> resourceClass) {

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/AnnotationControllerConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public String getName() {
3939
}
4040

4141
@Override
42-
public String getFinalizer() {
42+
public String getFinalizerName() {
4343
if (annotation == null || annotation.finalizerName().isBlank()) {
4444
return ReconcilerUtils.getDefaultFinalizerName(getResourceClass());
4545
} else {

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import io.fabric8.kubernetes.api.model.HasMetadata;
99
import io.javaoperatorsdk.operator.ReconcilerUtils;
1010
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
11-
import io.javaoperatorsdk.operator.api.reconciler.Constants;
1211
import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter;
1312
import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilters;
1413

@@ -18,7 +17,7 @@ default String getName() {
1817
return ReconcilerUtils.getDefaultReconcilerName(getAssociatedReconcilerClassName());
1918
}
2019

21-
default String getFinalizer() {
20+
default String getFinalizerName() {
2221
return ReconcilerUtils.getDefaultFinalizerName(getResourceClass());
2322
}
2423

@@ -32,10 +31,6 @@ default RetryConfiguration getRetryConfiguration() {
3231
return RetryConfiguration.DEFAULT;
3332
}
3433

35-
default boolean useFinalizer() {
36-
return !Constants.NO_FINALIZER.equals(getFinalizer());
37-
}
38-
3934
/**
4035
* Allow controllers to filter events before they are passed to the
4136
* {@link io.javaoperatorsdk.operator.processing.event.EventHandler}.

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class ControllerConfigurationOverrider<R extends HasMetadata> {
2525
private final List<DependentResourceSpec<?, ?>> dependentResourceSpecs;
2626

2727
private ControllerConfigurationOverrider(ControllerConfiguration<R> original) {
28-
finalizer = original.getFinalizer();
28+
finalizer = original.getFinalizerName();
2929
generationAware = original.isGenerationAware();
3030
namespaces = new HashSet<>(original.getNamespaces());
3131
retry = original.getRetryConfiguration();

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultControllerConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public String getResourceTypeName() {
6666
}
6767

6868
@Override
69-
public String getFinalizer() {
69+
public String getFinalizerName() {
7070
return finalizer;
7171
}
7272

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package io.javaoperatorsdk.operator.api.reconciler;
2+
3+
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
5+
public interface Cleaner<P extends HasMetadata> {
6+
7+
/**
8+
* Note that this method turns on automatic finalizer usage.
9+
*
10+
* The implementation should delete the associated component(s). This method is called when an
11+
* object is marked for deletion. After it's executed the custom resource finalizer is
12+
* automatically removed by the framework; unless the return value is
13+
* {@link DeleteControl#noFinalizerRemoval()}, which indicates that the controller has determined
14+
* that the resource should not be deleted yet. This is usually a corner case, when a cleanup is
15+
* tried again eventually.
16+
*
17+
* <p>
18+
* It's important for implementations of this method to be idempotent, since it can be called
19+
* several times.
20+
*
21+
* @param resource the resource that is marked for deletion
22+
* @param context the context with which the operation is executed
23+
* @return {@link DeleteControl#defaultDelete()} - so the finalizer is automatically removed after
24+
* the call. {@link DeleteControl#noFinalizerRemoval()} if you don't want to remove the
25+
* finalizer to indicate that the resource should not be deleted after all, in which case
26+
* the controller should restore the resource's state appropriately.
27+
*/
28+
DeleteControl cleanup(P resource, Context<P> context);
29+
30+
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ public final class Constants {
44

55
public static final String EMPTY_STRING = "";
66
public static final String WATCH_CURRENT_NAMESPACE = "JOSDK_WATCH_CURRENT";
7-
public static final String NO_FINALIZER = "JOSDK_NO_FINALIZER";
87
public static final long NO_RECONCILIATION_MAX_INTERVAL = -1L;
98

109
private Constants() {}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import io.fabric8.kubernetes.api.model.HasMetadata;
66
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
7-
import io.javaoperatorsdk.operator.api.reconciler.dependent.ManagedDependentResourceContext;
7+
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedDependentResourceContext;
88

99
public interface Context<P extends HasMetadata> {
1010

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
String name() default Constants.EMPTY_STRING;
1616

1717
/**
18-
* Optional finalizer name, if it is not provided, one will be automatically generated. If the
19-
* provided value is the value specified by {@link Constants#NO_FINALIZER}, then no finalizer will
20-
* be added to custom resources.
18+
* Optional finalizer name, if it is not provided, one will be automatically generated. Note that
19+
* finalizers are only added when Reconciler implement {@link Cleaner} interface, or at least one
20+
* managed dependent resource implement
21+
* {@link io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter} interface.
2122
*
2223
* @return the finalizer name
2324
*/

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import io.fabric8.kubernetes.api.model.HasMetadata;
66
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
7-
import io.javaoperatorsdk.operator.api.reconciler.dependent.ManagedDependentResourceContext;
7+
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedDependentResourceContext;
88
import io.javaoperatorsdk.operator.processing.Controller;
99

1010
public class DefaultContext<P extends HasMetadata> implements Context<P> {

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Reconciler.java

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,4 @@ public interface Reconciler<R extends HasMetadata> {
1515
*/
1616
UpdateControl<R> reconcile(R resource, Context<R> context) throws Exception;
1717

18-
/**
19-
* Note that this method is used in combination with finalizers. If automatic finalizer handling
20-
* is turned off for the controller, this method is not called.
21-
*
22-
* The implementation should delete the associated component(s). This method is called when an
23-
* object is marked for deletion. After it's executed the custom resource finalizer is
24-
* automatically removed by the framework; unless the return value is
25-
* {@link DeleteControl#noFinalizerRemoval()}, which indicates that the controller has determined
26-
* that the resource should not be deleted yet. This is usually a corner case, when a cleanup is
27-
* tried again eventually.
28-
*
29-
* <p>
30-
* It's important for implementations of this method to be idempotent, since it can be called
31-
* several times.
32-
*
33-
* @param resource the resource that is marked for deletion
34-
* @param context the context with which the operation is executed
35-
* @return {@link DeleteControl#defaultDelete()} - so the finalizer is automatically removed after
36-
* the call. {@link DeleteControl#noFinalizerRemoval()} if you don't want to remove the
37-
* finalizer to indicate that the resource should not be deleted after all, in which case
38-
* the controller should restore the resource's state appropriately.
39-
*/
40-
default DeleteControl cleanup(R resource, Context<R> context) {
41-
return DeleteControl.defaultDelete();
42-
}
4318
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
import io.fabric8.kubernetes.api.model.HasMetadata;
44
import io.javaoperatorsdk.operator.api.reconciler.Context;
55

6+
/**
7+
* DependentResource can implement this interface to denote it requires explicit logic to clean up
8+
* resources.
9+
*
10+
* @param <P> primary resource type
11+
*/
612
@FunctionalInterface
713
public interface Deleter<P extends HasMetadata> {
814
void delete(P primary, Context<P> context);

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,5 @@
88
public interface DependentResource<R, P extends HasMetadata> {
99
ReconcileResult<R> reconcile(P primary, Context<P> context);
1010

11-
default void cleanup(P primary, Context<P> context) {}
12-
1311
Optional<R> getResource(P primaryResource);
1412
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/ReconcileResult.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
public class ReconcileResult<R> {
66

7-
private R resource;
8-
private Operation operation;
7+
private final R resource;
8+
private final Operation operation;
99

1010
public static <T> ReconcileResult<T> resourceCreated(T resource) {
1111
return new ReconcileResult<>(resource, Operation.CREATED);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.javaoperatorsdk.operator.api.reconciler.dependent;
1+
package io.javaoperatorsdk.operator.api.reconciler.dependent.managed;
22

33
public interface DependentResourceConfigurator<C> {
44
void configureWith(C config);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.javaoperatorsdk.operator.api.reconciler.dependent;
1+
package io.javaoperatorsdk.operator.api.reconciler.dependent.managed;
22

33
import io.fabric8.kubernetes.client.KubernetesClient;
44

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.javaoperatorsdk.operator.api.reconciler.dependent;
1+
package io.javaoperatorsdk.operator.api.reconciler.dependent.managed;
22

33
import java.util.Collections;
44
import java.util.List;
@@ -7,6 +7,7 @@
77
import java.util.stream.Collectors;
88

99
import io.javaoperatorsdk.operator.OperatorException;
10+
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
1011

1112
/**
1213
* Contextual information related to {@link DependentResource} either to retrieve the actual

0 commit comments

Comments
 (0)