Skip to content

Commit af466f9

Browse files
committed
feat: add a DependentResource implementation that's also an EventSource
The benefit of this change is multi-fold: - simplifies AbstractDependentResource which doesn't have to handle cases it should not be concerned about - allows to share more code with AbstractSimpleDependentResource - enforces that the same name is used for the DependentResource and EventSource even in the standalone mode when using one of the provided implementations
1 parent 5b1e333 commit af466f9

File tree

11 files changed

+185
-177
lines changed

11 files changed

+185
-177
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@
1414
public interface EventSourceInitializer<P extends HasMetadata> {
1515

1616
/**
17-
* Prepares a list of {@link EventSource} implementations to be registered by the SDK.
17+
* Prepares a map of {@link EventSource} implementations keyed by the name with which they need to
18+
* be registered by the SDK.
1819
*
1920
* @param context a {@link EventSourceContext} providing access to information useful to event
2021
* sources
21-
* @return list of event sources to register
22+
* @return a map of event sources to register
2223
*/
2324
Map<String, EventSource> prepareEventSources(EventSourceContext<P> context);
2425

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import io.fabric8.kubernetes.api.model.HasMetadata;
44

5-
@SuppressWarnings("rawtypes")
65
public class UpdateControl<T extends HasMetadata> extends BaseControl<UpdateControl<T>> {
76

87
private final T resource;
@@ -32,8 +31,7 @@ public static <T extends HasMetadata> UpdateControl<T> updateResource(T customRe
3231
return new UpdateControl<>(customResource, false, true);
3332
}
3433

35-
public static <T extends HasMetadata> UpdateControl<T> updateStatus(
36-
T customResource) {
34+
public static <T extends HasMetadata> UpdateControl<T> updateStatus(T customResource) {
3735
return new UpdateControl<>(customResource, true, false);
3836
}
3937

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,4 @@ public interface EventSourceProvider<P extends HasMetadata> {
1010
* @return the initiated event source.
1111
*/
1212
EventSource initEventSource(EventSourceContext<P> context);
13-
14-
EventSource getEventSource();
1513
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java

Lines changed: 8 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
import io.javaoperatorsdk.operator.api.reconciler.Context;
88
import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter;
99
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
10-
import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider;
11-
import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationCacheFiller;
12-
import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationEventFilter;
1310
import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult;
1411
import io.javaoperatorsdk.operator.processing.event.ResourceID;
1512

@@ -68,89 +65,20 @@ public ReconcileResult<R> reconcile(P primary, Context<P> context) {
6865

6966
protected R handleCreate(R desired, P primary, Context<P> context) {
7067
ResourceID resourceID = ResourceID.fromResource(primary);
71-
R created = null;
72-
try {
73-
prepareEventFiltering(desired, resourceID);
74-
created = creator.create(desired, primary, context);
75-
cacheAfterCreate(resourceID, created);
76-
return created;
77-
} catch (RuntimeException e) {
78-
cleanupAfterEventFiltering(desired, resourceID, created);
79-
throw e;
80-
}
81-
}
82-
83-
private void cleanupAfterEventFiltering(R desired, ResourceID resourceID, R created) {
84-
if (isFilteringEventSource()) {
85-
eventSourceAsRecentOperationEventFilter()
86-
.cleanupOnCreateOrUpdateEventFiltering(resourceID, created);
87-
}
88-
}
89-
90-
private void cacheAfterCreate(ResourceID resourceID, R created) {
91-
if (isRecentOperationCacheFiller()) {
92-
eventSourceAsRecentOperationCacheFiller().handleRecentResourceCreate(resourceID, created);
93-
}
68+
R created = creator.create(desired, primary, context);
69+
cacheAfterCreate(resourceID, created);
70+
return created;
9471
}
9572

96-
private void cacheAfterUpdate(R actual, ResourceID resourceID, R updated) {
97-
if (isRecentOperationCacheFiller()) {
98-
eventSourceAsRecentOperationCacheFiller().handleRecentResourceUpdate(resourceID, updated,
99-
actual);
100-
}
101-
}
73+
protected abstract void cacheAfterCreate(ResourceID resourceID, R created);
10274

103-
private void prepareEventFiltering(R desired, ResourceID resourceID) {
104-
if (isFilteringEventSource()) {
105-
eventSourceAsRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(resourceID,
106-
desired);
107-
}
108-
}
75+
protected abstract void cacheAfterUpdate(R actual, ResourceID resourceID, R updated);
10976

11077
protected R handleUpdate(R actual, R desired, P primary, Context<P> context) {
11178
ResourceID resourceID = ResourceID.fromResource(primary);
112-
R updated = null;
113-
try {
114-
prepareEventFiltering(desired, resourceID);
115-
updated = updater.update(actual, desired, primary, context);
116-
cacheAfterUpdate(actual, resourceID, updated);
117-
return updated;
118-
} catch (RuntimeException e) {
119-
cleanupAfterEventFiltering(desired, resourceID, updated);
120-
throw e;
121-
}
122-
}
123-
124-
@SuppressWarnings("unchecked")
125-
private RecentOperationEventFilter<R> eventSourceAsRecentOperationEventFilter() {
126-
return (RecentOperationEventFilter<R>) ((EventSourceProvider<P>) this).getEventSource();
127-
}
128-
129-
@SuppressWarnings("unchecked")
130-
private RecentOperationCacheFiller<R> eventSourceAsRecentOperationCacheFiller() {
131-
return (RecentOperationCacheFiller<R>) ((EventSourceProvider<P>) this).getEventSource();
132-
}
133-
134-
@SuppressWarnings("unchecked")
135-
// this cannot be done in constructor since event source might be initialized later
136-
protected boolean isFilteringEventSource() {
137-
if (this instanceof EventSourceProvider) {
138-
final var eventSource = ((EventSourceProvider<P>) this).getEventSource();
139-
return eventSource instanceof RecentOperationEventFilter;
140-
} else {
141-
return false;
142-
}
143-
}
144-
145-
@SuppressWarnings("unchecked")
146-
// this cannot be done in constructor since event source might be initialized later
147-
protected boolean isRecentOperationCacheFiller() {
148-
if (this instanceof EventSourceProvider) {
149-
final var eventSource = ((EventSourceProvider<P>) this).getEventSource();
150-
return eventSource instanceof RecentOperationCacheFiller;
151-
} else {
152-
return false;
153-
}
79+
R updated = updater.update(actual, desired, primary, context);
80+
cacheAfterUpdate(actual, resourceID, updated);
81+
return updated;
15482
}
15583

15684
protected R desired(P primary, Context<P> context) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package io.javaoperatorsdk.operator.processing.dependent;
2+
3+
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
import io.javaoperatorsdk.operator.OperatorException;
5+
import io.javaoperatorsdk.operator.api.reconciler.Context;
6+
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
7+
import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider;
8+
import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationCacheFiller;
9+
import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationEventFilter;
10+
import io.javaoperatorsdk.operator.processing.event.EventHandler;
11+
import io.javaoperatorsdk.operator.processing.event.ResourceID;
12+
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
13+
14+
public abstract class AbstractEventSourceHolderDependentResource<R, P extends HasMetadata, T extends EventSource>
15+
extends AbstractDependentResource<R, P> implements EventSource, EventSourceProvider<P> {
16+
private T eventSource;
17+
private boolean isFilteringEventSource;
18+
private boolean isCacheFillerEventSource;
19+
20+
@Override
21+
public void start() throws OperatorException {
22+
eventSource.start();
23+
}
24+
25+
@Override
26+
public void stop() throws OperatorException {
27+
eventSource.stop();
28+
}
29+
30+
public EventSource initEventSource(EventSourceContext<P> context) {
31+
// some sub-classes (e.g. KubernetesDependentResource) can have their event source created
32+
// before this method is called in the managed case, so only create the event source if it
33+
// hasn't already been set
34+
if (eventSource == null) {
35+
eventSource = createEventSource(context);
36+
}
37+
38+
// but we still need to record which interfaces the event source implements even if it has
39+
// already been set before this method is called
40+
isFilteringEventSource = eventSource instanceof RecentOperationEventFilter;
41+
isCacheFillerEventSource = eventSource instanceof RecentOperationCacheFiller;
42+
return this;
43+
}
44+
45+
protected abstract T createEventSource(EventSourceContext<P> context);
46+
47+
protected void setEventSource(T eventSource) {
48+
this.eventSource = eventSource;
49+
}
50+
51+
@Override
52+
public void setEventHandler(EventHandler handler) {
53+
eventSource.setEventHandler(handler);
54+
}
55+
56+
protected T eventSource() {
57+
return eventSource;
58+
}
59+
60+
protected R handleCreate(R desired, P primary, Context<P> context) {
61+
ResourceID resourceID = ResourceID.fromResource(primary);
62+
R created = null;
63+
try {
64+
prepareEventFiltering(desired, resourceID);
65+
created = super.handleCreate(desired, primary, context);
66+
return created;
67+
} catch (RuntimeException e) {
68+
cleanupAfterEventFiltering(desired, resourceID, created);
69+
throw e;
70+
}
71+
}
72+
73+
protected R handleUpdate(R actual, R desired, P primary, Context<P> context) {
74+
ResourceID resourceID = ResourceID.fromResource(primary);
75+
R updated = null;
76+
try {
77+
prepareEventFiltering(desired, resourceID);
78+
updated = super.handleUpdate(actual, desired, primary, context);
79+
return updated;
80+
} catch (RuntimeException e) {
81+
cleanupAfterEventFiltering(desired, resourceID, updated);
82+
throw e;
83+
}
84+
}
85+
86+
87+
protected void cacheAfterCreate(ResourceID resourceID, R created) {
88+
if (isCacheFillerEventSource) {
89+
recentOperationCacheFiller().handleRecentResourceCreate(resourceID, created);
90+
}
91+
}
92+
93+
protected void cacheAfterUpdate(R actual, ResourceID resourceID, R updated) {
94+
if (isCacheFillerEventSource) {
95+
recentOperationCacheFiller().handleRecentResourceUpdate(resourceID, updated, actual);
96+
}
97+
}
98+
99+
private void prepareEventFiltering(R desired, ResourceID resourceID) {
100+
if (isFilteringEventSource) {
101+
recentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(resourceID, desired);
102+
}
103+
}
104+
105+
private void cleanupAfterEventFiltering(R desired, ResourceID resourceID, R created) {
106+
if (isFilteringEventSource) {
107+
recentOperationEventFilter().cleanupOnCreateOrUpdateEventFiltering(resourceID, created);
108+
}
109+
}
110+
111+
@SuppressWarnings("unchecked")
112+
private RecentOperationEventFilter<R> recentOperationEventFilter() {
113+
return (RecentOperationEventFilter<R>) eventSource;
114+
}
115+
116+
@SuppressWarnings("unchecked")
117+
private RecentOperationCacheFiller<R> recentOperationCacheFiller() {
118+
return (RecentOperationCacheFiller<R>) eventSource;
119+
}
120+
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractCachingDependentResource.java

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,20 @@
33
import java.util.Optional;
44

55
import io.fabric8.kubernetes.api.model.HasMetadata;
6-
import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider;
7-
import io.javaoperatorsdk.operator.processing.dependent.AbstractDependentResource;
6+
import io.javaoperatorsdk.operator.processing.dependent.AbstractEventSourceHolderDependentResource;
87
import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource;
9-
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
108

119
public abstract class AbstractCachingDependentResource<R, P extends HasMetadata>
12-
extends AbstractDependentResource<R, P>
13-
implements EventSourceProvider<P> {
14-
15-
protected ExternalResourceCachingEventSource<R, P> eventSource;
10+
extends
11+
AbstractEventSourceHolderDependentResource<R, P, ExternalResourceCachingEventSource<R, P>> {
1612
private final Class<R> resourceType;
1713

1814
protected AbstractCachingDependentResource(Class<R> resourceType) {
1915
this.resourceType = resourceType;
2016
}
2117

2218
public Optional<R> fetchResource(P primaryResource) {
23-
return eventSource.getAssociated(primaryResource);
24-
}
25-
26-
@Override
27-
public EventSource getEventSource() {
28-
return eventSource;
19+
return eventSource().getAssociated(primaryResource);
2920
}
3021

3122
@Override
@@ -35,6 +26,6 @@ public Class<R> resourceType() {
3526

3627
@Override
3728
public Optional<R> getResource(P primaryResource) {
38-
return eventSource.getAssociated(primaryResource);
29+
return eventSource().getAssociated(primaryResource);
3930
}
4031
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,13 @@ public final void delete(P primary, Context<P> context) {
5959
protected abstract void deleteResource(P primary, Context<P> context);
6060

6161
@Override
62-
protected R handleCreate(R desired, P primary, Context<P> context) {
63-
var res = this.creator.create(desired, primary, context);
64-
cache.put(ResourceID.fromResource(primary), res);
65-
return res;
62+
protected void cacheAfterCreate(ResourceID resourceID, R created) {
63+
cache.put(resourceID, created);
6664
}
6765

6866
@Override
69-
protected R handleUpdate(R actual, R desired, P primary, Context<P> context) {
70-
var res = updater.update(actual, desired, primary, context);
71-
cache.put(ResourceID.fromResource(primary), res);
72-
return res;
67+
protected void cacheAfterUpdate(R actual, ResourceID resourceID, R updated) {
68+
cache.put(resourceID, updated);
7369
}
7470

7571
public Matcher.Result<R> match(R actualResource, P primary, Context<P> context) {

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java

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

33
import io.fabric8.kubernetes.api.model.HasMetadata;
44
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
5-
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
5+
import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource;
66
import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource;
77

88
public abstract class PerResourcePollingDependentResource<R, P extends HasMetadata>
@@ -17,9 +17,9 @@ public PerResourcePollingDependentResource(Class<R> resourceType, long pollingPe
1717
}
1818

1919
@Override
20-
public EventSource initEventSource(EventSourceContext<P> context) {
21-
eventSource = new PerResourcePollingEventSource<>(this, context.getPrimaryCache(),
20+
protected ExternalResourceCachingEventSource<R, P> createEventSource(
21+
EventSourceContext<P> context) {
22+
return new PerResourcePollingEventSource<>(this, context.getPrimaryCache(),
2223
getPollingPeriod(), resourceType());
23-
return eventSource;
2424
}
2525
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java

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

66
import io.fabric8.kubernetes.api.model.HasMetadata;
77
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
8+
import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource;
89
import io.javaoperatorsdk.operator.processing.event.ResourceID;
9-
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
1010
import io.javaoperatorsdk.operator.processing.event.source.polling.PollingEventSource;
1111

1212
public abstract class PollingDependentResource<R, P extends HasMetadata>
@@ -21,8 +21,8 @@ public PollingDependentResource(Class<R> resourceType, long pollingPeriod) {
2121
}
2222

2323
@Override
24-
public EventSource initEventSource(EventSourceContext<P> context) {
25-
eventSource = new PollingEventSource<>(this, getPollingPeriod(), resourceType());
26-
return eventSource;
24+
protected ExternalResourceCachingEventSource<R, P> createEventSource(
25+
EventSourceContext<P> context) {
26+
return new PollingEventSource<>(this, getPollingPeriod(), resourceType());
2727
}
2828
}

0 commit comments

Comments
 (0)