Skip to content

Commit 525413e

Browse files
committed
additional sample
Signed-off-by: Attila Mészáros <a_meszaros@apple.com>
1 parent f5fbfbc commit 525413e

File tree

10 files changed

+160
-14
lines changed

10 files changed

+160
-14
lines changed

docs/content/en/docs/documentation/reconciler.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ updated via `PrimaryUpdateAndCacheUtils`.
211211

212212
See related integration test [here](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache).
213213

214-
### Trigger reconciliation even for `Delete` events
214+
### Trigger reconciliation for all events
215215

216216
TLDR; We provide an execution mode where `reconcile` method is called on every event from event source.
217217

@@ -258,3 +258,4 @@ In this mode:
258258
- you cannot use managed dependent resources since those manage the finalizers and other logic related to the normal
259259
execution mode.
260260

261+
See also [sample](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/finalizerhandling) for selectively adding finalizers for resources;

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

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,25 +241,28 @@ private static <P extends HasMetadata> P pollLocalCache(
241241
* Adds finalizer to the primary resource from the context using JSON Patch. Retries conflicts and
242242
* unprocessable content (HTTP 422), see {@link
243243
* PrimaryUpdateAndCacheUtils#conflictRetryingPatch(KubernetesClient, HasMetadata, UnaryOperator,
244-
* Predicate)} for details on retry.
244+
* Predicate)} for details on retry. It does not add finalizer if there is already a finalizer or
245+
* resource is marked for deletion.
245246
*
246247
* @return updated resource from the server response
247248
*/
248-
@SuppressWarnings("unchecked")
249249
public static <P extends HasMetadata> P addFinalizer(Context<P> context, String finalizer) {
250250
return addFinalizer(context.getClient(), context.getPrimaryResource(), finalizer);
251251
}
252252

253253
/**
254254
* Adds finalizer to the resource using JSON Patch. Retries conflicts and unprocessable content
255255
* (HTTP 422), see {@link PrimaryUpdateAndCacheUtils#conflictRetryingPatch(KubernetesClient,
256-
* HasMetadata, UnaryOperator, Predicate)} for details on retry.
256+
* HasMetadata, UnaryOperator, Predicate)} for details on retry. It does not try to add finalizer
257+
* if there is already a finalizer or resource is marked for deletion.
257258
*
258259
* @return updated resource from the server response
259260
*/
260-
@SuppressWarnings("unchecked")
261261
public static <P extends HasMetadata> P addFinalizer(
262262
KubernetesClient client, P resource, String finalizerName) {
263+
if (resource.isMarkedForDeletion() || resource.hasFinalizer(finalizerName)) {
264+
return resource;
265+
}
263266
return conflictRetryingPatch(
264267
client,
265268
resource,
@@ -273,7 +276,8 @@ public static <P extends HasMetadata> P addFinalizer(
273276
/**
274277
* Removes the target finalizer from the primary resource from the Context. Uses JSON Patch and
275278
* handles retries, see {@link PrimaryUpdateAndCacheUtils#conflictRetryingPatch(KubernetesClient,
276-
* HasMetadata, UnaryOperator, Predicate)} for details.
279+
* HasMetadata, UnaryOperator, Predicate)} for details. It does not try to remove finalizer if
280+
* finalizer is not present on the resource.
277281
*
278282
* @return updated resource from the server response
279283
*/
@@ -285,12 +289,16 @@ public static <P extends HasMetadata> P removeFinalizer(
285289
/**
286290
* Removes the target finalizer from target resource. Uses JSON Patch and handles retries, see
287291
* {@link PrimaryUpdateAndCacheUtils#conflictRetryingPatch(KubernetesClient, HasMetadata,
288-
* UnaryOperator, Predicate)} for details.
292+
* UnaryOperator, Predicate)} for details. It does not try to remove finalizer if finalizer is not
293+
* present on the resource.
289294
*
290295
* @return updated resource from the server response
291296
*/
292297
public static <P extends HasMetadata> P removeFinalizer(
293298
KubernetesClient client, P resource, String finalizerName) {
299+
if (!resource.hasFinalizer(finalizerName)) {
300+
return resource;
301+
}
294302
return conflictRetryingPatch(
295303
client,
296304
resource,

operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/onlyreconcile/TriggerReconcilerOnAllEventCustomResource.java renamed to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/eventing/TriggerReconcilerOnAllEventCustomResource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.javaoperatorsdk.operator.baseapi.triggerallevent.onlyreconcile;
1+
package io.javaoperatorsdk.operator.baseapi.triggerallevent.eventing;
22

33
import io.fabric8.kubernetes.api.model.Namespaced;
44
import io.fabric8.kubernetes.client.CustomResource;

operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/onlyreconcile/TriggerReconcilerOnAllEventIT.java renamed to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/eventing/TriggerReconcilerOnAllEventIT.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.javaoperatorsdk.operator.baseapi.triggerallevent.onlyreconcile;
1+
package io.javaoperatorsdk.operator.baseapi.triggerallevent.eventing;
22

33
import java.time.Duration;
44

@@ -9,9 +9,9 @@
99
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
1010
import io.javaoperatorsdk.operator.processing.retry.GenericRetry;
1111

12-
import static io.javaoperatorsdk.operator.baseapi.triggerallevent.onlyreconcile.TriggerReconcilerOnAllEventReconciler.ADDITIONAL_FINALIZER;
13-
import static io.javaoperatorsdk.operator.baseapi.triggerallevent.onlyreconcile.TriggerReconcilerOnAllEventReconciler.FINALIZER;
14-
import static io.javaoperatorsdk.operator.baseapi.triggerallevent.onlyreconcile.TriggerReconcilerOnAllEventReconciler.NO_MORE_EXCEPTION_ANNOTATION_KEY;
12+
import static io.javaoperatorsdk.operator.baseapi.triggerallevent.eventing.TriggerReconcilerOnAllEventReconciler.ADDITIONAL_FINALIZER;
13+
import static io.javaoperatorsdk.operator.baseapi.triggerallevent.eventing.TriggerReconcilerOnAllEventReconciler.FINALIZER;
14+
import static io.javaoperatorsdk.operator.baseapi.triggerallevent.eventing.TriggerReconcilerOnAllEventReconciler.NO_MORE_EXCEPTION_ANNOTATION_KEY;
1515
import static org.assertj.core.api.Assertions.assertThat;
1616
import static org.awaitility.Awaitility.await;
1717

operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/onlyreconcile/TriggerReconcilerOnAllEventReconciler.java renamed to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/eventing/TriggerReconcilerOnAllEventReconciler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.javaoperatorsdk.operator.baseapi.triggerallevent.onlyreconcile;
1+
package io.javaoperatorsdk.operator.baseapi.triggerallevent.eventing;
22

33
import java.util.concurrent.atomic.AtomicInteger;
44

operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/onlyreconcile/TriggerReconcilerOnAllEventSpec.java renamed to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/eventing/TriggerReconcilerOnAllEventSpec.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.javaoperatorsdk.operator.baseapi.triggerallevent.onlyreconcile;
1+
package io.javaoperatorsdk.operator.baseapi.triggerallevent.eventing;
22

33
public class TriggerReconcilerOnAllEventSpec {
44

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package io.javaoperatorsdk.operator.baseapi.triggerallevent.finalizerhandling;
2+
3+
import java.time.Duration;
4+
5+
import org.junit.jupiter.api.Test;
6+
import org.junit.jupiter.api.extension.RegisterExtension;
7+
8+
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
9+
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
10+
11+
import static org.assertj.core.api.Assertions.assertThat;
12+
import static org.awaitility.Awaitility.await;
13+
14+
/**
15+
* The test showcases how manage finalizers only on some of the custom resources using
16+
* `triggerReconcilerOnAllEvent` mode.
17+
*/
18+
public class SelectiveFinalizerHandlingIT {
19+
20+
public static final String TEST_RESOURCE2 = "test2";
21+
public static final String TEST_RESOURCE1 = "test1";
22+
23+
@RegisterExtension
24+
LocallyRunOperatorExtension extension =
25+
LocallyRunOperatorExtension.builder()
26+
.withReconciler(SelectiveFinalizerHandlingReconciler.class)
27+
.build();
28+
29+
@Test
30+
void addFinalizerOnlyOnSomeOfTheResources() {
31+
var resource1 = extension.create(testResource(TEST_RESOURCE1, true));
32+
var resource2 = extension.create(testResource(TEST_RESOURCE2, false));
33+
34+
await()
35+
.pollDelay(Duration.ofMillis(100))
36+
.untilAsserted(
37+
() -> {
38+
var res1 =
39+
extension.get(
40+
SelectiveFinalizerHandlingReconcilerCustomResource.class, TEST_RESOURCE1);
41+
var res2 =
42+
extension.get(
43+
SelectiveFinalizerHandlingReconcilerCustomResource.class, TEST_RESOURCE2);
44+
45+
assertThat(res1.getFinalizers()).isNotEmpty();
46+
assertThat(res2.getFinalizers()).isEmpty();
47+
});
48+
49+
extension.delete(resource1);
50+
extension.delete(resource2);
51+
52+
await()
53+
.untilAsserted(
54+
() -> {
55+
var res1 =
56+
extension.get(
57+
SelectiveFinalizerHandlingReconcilerCustomResource.class, TEST_RESOURCE1);
58+
var res2 =
59+
extension.get(
60+
SelectiveFinalizerHandlingReconcilerCustomResource.class, TEST_RESOURCE2);
61+
62+
assertThat(res1).isNull();
63+
assertThat(res2).isNull();
64+
});
65+
}
66+
67+
SelectiveFinalizerHandlingReconcilerCustomResource testResource(
68+
String name, boolean addFinalizer) {
69+
var resource = new SelectiveFinalizerHandlingReconcilerCustomResource();
70+
resource.setMetadata(new ObjectMetaBuilder().withName(name).build());
71+
resource.setSpec(new SelectiveFinalizerHandlingReconcilerSpec());
72+
resource.getSpec().setUseFinalizer(addFinalizer);
73+
74+
return resource;
75+
}
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.javaoperatorsdk.operator.baseapi.triggerallevent.finalizerhandling;
2+
3+
import io.javaoperatorsdk.operator.api.reconciler.Context;
4+
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
5+
import io.javaoperatorsdk.operator.api.reconciler.PrimaryUpdateAndCacheUtils;
6+
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
7+
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
8+
9+
@ControllerConfiguration(triggerReconcilerOnAllEvent = true)
10+
public class SelectiveFinalizerHandlingReconciler
11+
implements Reconciler<SelectiveFinalizerHandlingReconcilerCustomResource> {
12+
13+
public static final String FINALIZER = "finalizer.test/finalizer";
14+
15+
@Override
16+
public UpdateControl<SelectiveFinalizerHandlingReconcilerCustomResource> reconcile(
17+
SelectiveFinalizerHandlingReconcilerCustomResource resource,
18+
Context<SelectiveFinalizerHandlingReconcilerCustomResource> context) {
19+
20+
if (context.isPrimaryResourceDeleted()) {
21+
return UpdateControl.noUpdate();
22+
}
23+
24+
if (resource.getSpec().getUseFinalizer()) {
25+
PrimaryUpdateAndCacheUtils.addFinalizer(context, FINALIZER);
26+
}
27+
28+
if (resource.isMarkedForDeletion()) {
29+
PrimaryUpdateAndCacheUtils.removeFinalizer(context, FINALIZER);
30+
}
31+
32+
return UpdateControl.noUpdate();
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.javaoperatorsdk.operator.baseapi.triggerallevent.finalizerhandling;
2+
3+
import io.fabric8.kubernetes.api.model.Namespaced;
4+
import io.fabric8.kubernetes.client.CustomResource;
5+
import io.fabric8.kubernetes.model.annotation.Group;
6+
import io.fabric8.kubernetes.model.annotation.ShortNames;
7+
import io.fabric8.kubernetes.model.annotation.Version;
8+
9+
@Group("sample.javaoperatorsdk")
10+
@Version("v1")
11+
@ShortNames("saf")
12+
public class SelectiveFinalizerHandlingReconcilerCustomResource
13+
extends CustomResource<SelectiveFinalizerHandlingReconcilerSpec, Void> implements Namespaced {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.javaoperatorsdk.operator.baseapi.triggerallevent.finalizerhandling;
2+
3+
public class SelectiveFinalizerHandlingReconcilerSpec {
4+
5+
private Boolean useFinalizer;
6+
7+
public Boolean getUseFinalizer() {
8+
return useFinalizer;
9+
}
10+
11+
public void setUseFinalizer(Boolean useFinalizer) {
12+
this.useFinalizer = useFinalizer;
13+
}
14+
}

0 commit comments

Comments
 (0)