Skip to content

Commit d35c8b1

Browse files
committed
code improvements handling delete event too
1 parent f3a3b05 commit d35c8b1

File tree

8 files changed

+41
-48
lines changed

8 files changed

+41
-48
lines changed

operator-framework/src/main/java/com/github/containersolutions/operator/ControllerUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
class ControllerUtils {
1010

1111
static String getDefaultFinalizer(ResourceController controller) {
12-
return getAnnotation(controller).defaultFinalizer();
12+
return getAnnotation(controller).finalizerName();
1313
}
1414

1515
static <R extends CustomResource> Class<R> getCustomResourceClass(ResourceController controller) {

operator-framework/src/main/java/com/github/containersolutions/operator/api/Controller.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@
2323

2424
Class<? extends CustomResourceDoneable<? extends CustomResource>> customResourceDoneableClass();
2525

26-
String defaultFinalizer() default DEFAULT_FINALIZER;
26+
String finalizerName() default DEFAULT_FINALIZER;
2727

2828
}

operator-framework/src/main/java/com/github/containersolutions/operator/api/ResourceController.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ public interface ResourceController<R extends CustomResource> {
1010
* The implementation should delete the associated component(s). Note that this is method is called when an object
1111
* is marked for deletion. After its executed the default finalizer is automatically removed by the framework;
1212
* unless the return value is false - note that this is almost never the case.
13+
* Its important to have the implementation also idempotent, in the current implementation to cover all edge cases
14+
* actually will be executed mostly twice.
1315
*
1416
* @param resource
1517
* @return true - so the finalizer is automatically removed after the call.

operator-framework/src/main/java/com/github/containersolutions/operator/processing/EventDispatcher.java

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -32,44 +32,38 @@ public EventDispatcher(ResourceController controller,
3232

3333
public void handleEvent(Watcher.Action action, CustomResource resource) {
3434
log.info("Handling event {} for resource {}", action, resource.getMetadata());
35-
if (action == Watcher.Action.MODIFIED || action == Watcher.Action.ADDED) {
36-
// Its interesting problem if we should call delete if received event after object is marked for deletion
37-
// but there is not our finalizer. Since it can happen that there are multiple finalizers, also other events after
38-
// we called delete and remove finalizers already. But also it can happen that we did not manage to put
39-
// finalizer into the resource before marked for delete. So for now we will call delete every time, since delete
40-
// operation should be idempotent too, and this way we cover the corner case.
41-
if (markedForDeletion(resource)) {
42-
boolean removeFinalizer = controller.deleteResource(resource);
43-
if (removeFinalizer && hasDefaultFinalizer(resource)) {
44-
log.debug("Removing finalizer on {}: {}", resource.getMetadata().getName(), resource.getMetadata());
45-
removeDefaultFinalizer(resource);
46-
}
47-
} else {
48-
Optional<CustomResource> updateResult = controller.createOrUpdateResource(resource);
49-
if (updateResult.isPresent()) {
50-
log.debug("Updating resource: {} with version: {}", resource.getMetadata().getName(),
51-
resource.getMetadata().getResourceVersion());
52-
log.trace("Resource before update: {}", resource);
53-
CustomResource updatedResource = updateResult.get();
54-
addFinalizerIfNotPresent(updatedResource);
55-
replace(updatedResource);
56-
log.trace("Resource after update: {}", resource);
57-
// We always add the default finalizer if missing and not marked for deletion.
58-
} else if (!hasDefaultFinalizer(resource) && !markedForDeletion(resource)) {
59-
log.debug("Adding finalizer for resource: {} version: {}", resource.getMetadata().getName(),
60-
resource.getMetadata().getResourceVersion());
61-
addFinalizerIfNotPresent(resource);
62-
replace(resource);
63-
}
64-
}
65-
}
6635
if (Watcher.Action.ERROR == action) {
6736
log.error("Received error for resource: {}", resource.getMetadata().getName());
6837
return;
6938
}
70-
if (Watcher.Action.DELETED == action) {
71-
log.debug("Resource deleted: {}", resource.getMetadata().getName());
72-
return;
39+
// Its interesting problem if we should call delete if received event after object is marked for deletion
40+
// but there is not our finalizer. Since it can happen that there are multiple finalizers, also other events after
41+
// we called delete and remove finalizers already. But also it can happen that we did not manage to put
42+
// finalizer into the resource before marked for delete. So for now we will call delete every time, since delete
43+
// operation should be idempotent too, and this way we cover the corner case.
44+
if (markedForDeletion(resource) || action == Watcher.Action.DELETED) {
45+
boolean removeFinalizer = controller.deleteResource(resource);
46+
if (removeFinalizer && hasDefaultFinalizer(resource)) {
47+
log.debug("Removing finalizer on {}: {}", resource.getMetadata().getName(), resource.getMetadata());
48+
removeDefaultFinalizer(resource);
49+
}
50+
} else {
51+
Optional<CustomResource> updateResult = controller.createOrUpdateResource(resource);
52+
if (updateResult.isPresent()) {
53+
log.debug("Updating resource: {} with version: {}", resource.getMetadata().getName(),
54+
resource.getMetadata().getResourceVersion());
55+
log.trace("Resource before update: {}", resource);
56+
CustomResource updatedResource = updateResult.get();
57+
addFinalizerIfNotPresent(updatedResource);
58+
replace(updatedResource);
59+
log.trace("Resource after update: {}", resource);
60+
// We always add the default finalizer if missing and not marked for deletion.
61+
} else if (!hasDefaultFinalizer(resource) && !markedForDeletion(resource)) {
62+
log.debug("Adding finalizer for resource: {} version: {}", resource.getMetadata().getName(),
63+
resource.getMetadata().getResourceVersion());
64+
addFinalizerIfNotPresent(resource);
65+
replace(resource);
66+
}
7367
}
7468
}
7569

operator-framework/src/main/java/com/github/containersolutions/operator/processing/EventScheduler.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,12 @@ void scheduleEvent(CustomResourceEvent event) {
7676
log.debug("Scheduling event: {}", event);
7777
try {
7878
lock.lock();
79-
if (event.getAction() == Action.DELETED) {
80-
// we might want to have a state check here that only an event is scheduled for delete.
81-
log.debug("Received delete action for event: {}", event);
82-
return;
83-
}
84-
if (eventStore.processedNewerVersionBefore(event)) {
79+
if (eventStore.receivedMoreRecentEventBefore(event)) {
8580
log.debug("Skipping event processing since was processed event with newer version before. {}", event);
8681
return;
8782
}
88-
eventStore.updateLatestResourceVersionProcessed(event);
83+
eventStore.updateLatestResourceVersionReceived(event);
84+
8985
if (eventStore.containsOlderVersionOfNotScheduledEvent(event)) {
9086
log.debug("Replacing event which is not scheduled yet, since incoming event is more recent. new Event:{}", event);
9187
eventStore.addOrReplaceEventAsNotScheduledYet(event);
@@ -97,6 +93,7 @@ void scheduleEvent(CustomResourceEvent event) {
9793
eventStore.addOrReplaceEventAsNotScheduledYet(event);
9894
return;
9995
}
96+
10097
Optional<Long> nextBackOff = event.nextBackOff();
10198
if (!nextBackOff.isPresent()) {
10299
log.warn("Event limited max retry limit ({}), will be discarded. {}", MAX_RETRY_COUNT, event);

operator-framework/src/main/java/com/github/containersolutions/operator/processing/EventStore.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public CustomResourceEvent removeEventUnderProcessing(String uid) {
4242
return eventsUnderProcessing.remove(uid);
4343
}
4444

45-
public void updateLatestResourceVersionProcessed(CustomResourceEvent event) {
45+
public void updateLatestResourceVersionReceived(CustomResourceEvent event) {
4646
Long current = lastResourceVersion.get(event.resourceUid());
4747
long received = Long.parseLong(event.getResource().getMetadata().getResourceVersion());
4848
if (current == null || received > current) {
@@ -53,7 +53,7 @@ public void updateLatestResourceVersionProcessed(CustomResourceEvent event) {
5353
}
5454
}
5555

56-
public boolean processedNewerVersionBefore(CustomResourceEvent customResourceEvent) {
56+
public boolean receivedMoreRecentEventBefore(CustomResourceEvent customResourceEvent) {
5757
Long lastVersionProcessed = lastResourceVersion.get(customResourceEvent.resourceUid());
5858
if (lastVersionProcessed == null) {
5959
return false;

operator-framework/src/test/java/com/github/containersolutions/operator/EventDispatcherTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
class EventDispatcherTest {
2626

2727
private CustomResource testCustomResource;
28-
private EventDispatcher<CustomResource> eventDispatcher;
28+
private EventDispatcher eventDispatcher;
2929
private ResourceController<CustomResource> resourceController = mock(ResourceController.class);
3030
private CustomResourceOperationsImpl<CustomResource, CustomResourceList<CustomResource>,
3131
CustomResourceDoneable<CustomResource>> resourceOperation = mock(CustomResourceOperationsImpl.class);

operator-framework/src/test/java/com/github/containersolutions/operator/EventSchedulerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ class EventSchedulerTest {
2525

2626
public static final int INVOCATION_DURATION = 80;
2727
@SuppressWarnings("unchecked")
28-
private EventDispatcher<CustomResource> eventDispatcher = mock(EventDispatcher.class);
28+
private EventDispatcher eventDispatcher = mock(EventDispatcher.class);
2929

30-
private EventScheduler<CustomResource> eventScheduler = new EventScheduler(eventDispatcher);
30+
private EventScheduler eventScheduler = new EventScheduler(eventDispatcher);
3131

3232
private List<EventProcessingDetail> eventProcessingList = Collections.synchronizedList(new ArrayList<>());
3333

0 commit comments

Comments
 (0)