Skip to content

Commit 635a29f

Browse files
committed
showing code to possibly remove the previous annotation
Signed-off-by: Steve Hawkins <shawkins@redhat.com>
1 parent c310e6b commit 635a29f

12 files changed

Lines changed: 165 additions & 134 deletions

File tree

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

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -447,19 +447,6 @@ default Set<Class<? extends HasMetadata>> defaultNonSSAResource() {
447447
return defaultNonSSAResources();
448448
}
449449

450-
/**
451-
* If a javaoperatorsdk.io/previous annotation should be used so that the operator sdk can detect
452-
* events from its own updates of dependent resources and then filter them.
453-
*
454-
* <p>Disable this if you want to react to your own dependent resource updates
455-
*
456-
* @return if special annotation should be used for dependent resource to filter events
457-
* @since 4.5.0
458-
*/
459-
default boolean previousAnnotationForDependentResourcesEventFiltering() {
460-
return true;
461-
}
462-
463450
/**
464451
* For dependent resources, the framework can add an annotation to filter out events resulting
465452
* directly from the framework's operation. There are, however, some resources that do not follow

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

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -331,13 +331,6 @@ public Set<Class<? extends HasMetadata>> defaultNonSSAResources() {
331331
defaultNonSSAResource, ConfigurationService::defaultNonSSAResources);
332332
}
333333

334-
@Override
335-
public boolean previousAnnotationForDependentResourcesEventFiltering() {
336-
return overriddenValueOrDefault(
337-
previousAnnotationForDependentResources,
338-
ConfigurationService::previousAnnotationForDependentResourcesEventFiltering);
339-
}
340-
341334
@Override
342335
public boolean parseResourceVersionsForEventFilteringAndCaching() {
343336
return overriddenValueOrDefault(

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

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import io.fabric8.kubernetes.client.dsl.base.PatchContext;
3232
import io.fabric8.kubernetes.client.dsl.base.PatchType;
3333
import io.javaoperatorsdk.operator.OperatorException;
34+
import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationCacheFiller;
3435
import io.javaoperatorsdk.operator.processing.event.ResourceID;
3536

3637
import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getUID;
@@ -48,6 +49,16 @@
4849
*/
4950
public class PrimaryUpdateAndCacheUtils {
5051

52+
private static final RecentOperationCacheFiller<?> DUMMY_CACHE_FILLER =
53+
new RecentOperationCacheFiller<>() {
54+
@Override
55+
public void handleRecentResourceCreate(ResourceID resourceID, Object resource) {}
56+
57+
@Override
58+
public void handleRecentResourceUpdate(
59+
ResourceID resourceID, Object resource, Object previousVersionOfResource) {}
60+
};
61+
5162
public static final int DEFAULT_MAX_RETRY = 10;
5263
public static final int DEFAULT_RESOURCE_CACHE_TIMEOUT_MILLIS = 10000;
5364
public static final int DEFAULT_RESOURCE_CACHE_POLL_PERIOD_MILLIS = 50;
@@ -143,6 +154,24 @@ public static <P extends HasMetadata> P updateAndCacheResource(
143154
DEFAULT_RESOURCE_CACHE_POLL_PERIOD_MILLIS);
144155
}
145156

157+
// TODO: where does this belong
158+
public static <P extends HasMetadata> P updateAndCacheSecondaryResource(
159+
P resourceToUpdate,
160+
Context<?> context,
161+
RecentOperationCacheFiller<P> cacheFiller,
162+
UnaryOperator<P> updateMethod) {
163+
return updateAndCacheResource(
164+
resourceToUpdate,
165+
context,
166+
cacheFiller == null ? (RecentOperationCacheFiller<P>) DUMMY_CACHE_FILLER : cacheFiller,
167+
null,
168+
o -> o,
169+
updateMethod,
170+
0,
171+
DEFAULT_RESOURCE_CACHE_TIMEOUT_MILLIS,
172+
DEFAULT_RESOURCE_CACHE_POLL_PERIOD_MILLIS);
173+
}
174+
146175
/**
147176
* Modifies the primary using the specified modification function, then uses the modified resource
148177
* for the request to update with provided update method. As the {@code resourceVersion} field of
@@ -156,7 +185,6 @@ public static <P extends HasMetadata> P updateAndCacheResource(
156185
* @param resourceToUpdate original resource to update
157186
* @param context of reconciliation
158187
* @param modificationFunction modifications to make on primary
159-
* @param updateMethod the update method implementation
160188
* @param maxRetry maximum number of retries before giving up
161189
* @param cachePollTimeoutMillis maximum amount of milliseconds to wait for the updated resource
162190
* to appear in cache
@@ -172,24 +200,45 @@ public static <P extends HasMetadata> P updateAndCacheResource(
172200
int maxRetry,
173201
long cachePollTimeoutMillis,
174202
long cachePollPeriodMillis) {
203+
return updateAndCacheResource(
204+
resourceToUpdate,
205+
context,
206+
context.eventSourceRetriever().getControllerEventSource(),
207+
context.getPrimaryCache(),
208+
modificationFunction,
209+
updateMethod,
210+
maxRetry,
211+
cachePollPeriodMillis,
212+
cachePollTimeoutMillis);
213+
}
214+
215+
private static <P extends HasMetadata> P updateAndCacheResource(
216+
P resourceToUpdate,
217+
Context<?> context,
218+
RecentOperationCacheFiller<P> cacheFiller,
219+
IndexedResourceCache<P> cache,
220+
UnaryOperator<P> modificationFunction,
221+
UnaryOperator<P> updateMethod,
222+
int maxRetry,
223+
long cachePollTimeoutMillis,
224+
long cachePollPeriodMillis) {
175225

226+
ResourceID id = ResourceID.fromResource(resourceToUpdate);
176227
if (log.isDebugEnabled()) {
177-
log.debug("Update and cache: {}", ResourceID.fromResource(resourceToUpdate));
228+
log.debug("Update and cache: {}", id);
178229
}
179230
P modified = null;
180231
int retryIndex = 0;
181232
while (true) {
182233
try {
234+
cacheFiller.startModifying(id);
183235
modified = modificationFunction.apply(resourceToUpdate);
184236
modified
185237
.getMetadata()
186238
.setResourceVersion(resourceToUpdate.getMetadata().getResourceVersion());
187239
var updated = updateMethod.apply(modified);
188-
context
189-
.eventSourceRetriever()
190-
.getControllerEventSource()
191-
.handleRecentResourceUpdate(
192-
ResourceID.fromResource(resourceToUpdate), updated, resourceToUpdate);
240+
cacheFiller.handleRecentResourceUpdate(
241+
ResourceID.fromResource(resourceToUpdate), updated, resourceToUpdate);
193242
return updated;
194243
} catch (KubernetesClientException e) {
195244
log.trace("Exception during patch for resource: {}", resourceToUpdate);
@@ -219,20 +268,26 @@ public static <P extends HasMetadata> P updateAndCacheResource(
219268
e.getCode());
220269
resourceToUpdate =
221270
pollLocalCache(
222-
context, resourceToUpdate, cachePollTimeoutMillis, cachePollPeriodMillis);
271+
context, resourceToUpdate, cachePollTimeoutMillis, cachePollPeriodMillis, cache);
272+
} finally {
273+
cacheFiller.doneModifying(id);
223274
}
224275
}
225276
}
226277

227278
private static <P extends HasMetadata> P pollLocalCache(
228-
Context<P> context, P staleResource, long timeoutMillis, long pollDelayMillis) {
279+
Context<?> context,
280+
P staleResource,
281+
long timeoutMillis,
282+
long pollDelayMillis,
283+
IndexedResourceCache<P> cache) {
229284
try {
230285
var resourceId = ResourceID.fromResource(staleResource);
231286
var startTime = LocalTime.now();
232287
final var timeoutTime = startTime.plus(timeoutMillis, ChronoUnit.MILLIS);
233288
while (timeoutTime.isAfter(LocalTime.now())) {
234289
log.debug("Polling cache for resource: {}", resourceId);
235-
var cachedResource = context.getPrimaryCache().get(resourceId).orElseThrow();
290+
var cachedResource = cache.get(resourceId).orElseThrow();
236291
if (!cachedResource
237292
.getMetadata()
238293
.getResourceVersion()

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919

2020
public interface RecentOperationCacheFiller<R> {
2121

22+
default void startModifying(ResourceID id) {}
23+
24+
default void doneModifying(ResourceID id) {}
25+
2226
void handleRecentResourceCreate(ResourceID resourceID, R resource);
2327

2428
void handleRecentResourceUpdate(ResourceID resourceID, R resource, R previousVersionOfResource);

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ protected AbstractEventSourceHolderDependentResource(Class<R> resourceType, Stri
6565
* that multiple event sources would be created and only one started and registered. Note that
6666
* this method does not start the event source, so no blocking IO is involved.
6767
*/
68+
@Override
6869
public synchronized Optional<T> eventSource(EventSourceContext<P> context) {
6970
// some sub-classes (e.g. KubernetesDependentResource) can have their event source created
7071
// before this method is called in the managed case, so only create the event source if it
@@ -123,13 +124,15 @@ public Optional<T> eventSource() {
123124
return Optional.ofNullable(eventSource);
124125
}
125126

127+
@Override
126128
protected void onCreated(P primary, R created, Context<P> context) {
127129
if (isCacheFillerEventSource) {
128130
recentOperationCacheFiller()
129131
.handleRecentResourceCreate(ResourceID.fromResource(primary), created);
130132
}
131133
}
132134

135+
@Override
133136
protected void onUpdated(P primary, R updated, R actual, Context<P> context) {
134137
if (isCacheFillerEventSource) {
135138
recentOperationCacheFiller()
@@ -138,7 +141,7 @@ protected void onUpdated(P primary, R updated, R actual, Context<P> context) {
138141
}
139142

140143
@SuppressWarnings("unchecked")
141-
private RecentOperationCacheFiller<R> recentOperationCacheFiller() {
144+
protected RecentOperationCacheFiller<R> recentOperationCacheFiller() {
142145
return (RecentOperationCacheFiller<R>) eventSource;
143146
}
144147
}

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import io.fabric8.kubernetes.api.model.HasMetadata;
2323
import io.javaoperatorsdk.operator.api.reconciler.Context;
24+
import io.javaoperatorsdk.operator.api.reconciler.PrimaryUpdateAndCacheUtils;
2425
import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationCacheFiller;
2526
import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever;
2627
import io.javaoperatorsdk.operator.processing.event.ResourceID;
@@ -93,7 +94,12 @@ private void handleExplicitStateDelete(P primary, R secondary, Context<P> contex
9394
@SuppressWarnings({"rawtypes", "unchecked", "unused"})
9495
protected void handleExplicitStateCreation(P primary, R created, Context<P> context) {
9596
var resource = dependentResourceWithExplicitState.stateResource(primary, created);
96-
var stateResource = context.getClient().resource(resource).create();
97+
var stateResource =
98+
PrimaryUpdateAndCacheUtils.updateAndCacheSecondaryResource(
99+
resource,
100+
context,
101+
(RecentOperationCacheFiller) externalStateEventSource,
102+
toCreate -> context.getClient().resource(toCreate).create());
97103
if (externalStateEventSource != null) {
98104
((RecentOperationCacheFiller) externalStateEventSource)
99105
.handleRecentResourceCreate(ResourceID.fromResource(primary), stateResource);

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

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import io.javaoperatorsdk.operator.api.reconciler.Context;
3232
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
3333
import io.javaoperatorsdk.operator.api.reconciler.Ignore;
34+
import io.javaoperatorsdk.operator.api.reconciler.PrimaryUpdateAndCacheUtils;
3435
import io.javaoperatorsdk.operator.api.reconciler.dependent.GarbageCollected;
3536
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ConfiguredDependentResource;
3637
import io.javaoperatorsdk.operator.processing.GroupVersionKind;
@@ -55,7 +56,6 @@ public abstract class KubernetesDependentResource<R extends HasMetadata, P exten
5556
private final boolean garbageCollected = this instanceof GarbageCollected;
5657
private KubernetesDependentResourceConfig<R> kubernetesDependentResourceConfig;
5758
private volatile Boolean useSSA;
58-
private volatile Boolean usePreviousAnnotationForEventFiltering;
5959

6060
public KubernetesDependentResource() {}
6161

@@ -72,6 +72,25 @@ public void configureWith(KubernetesDependentResourceConfig<R> config) {
7272
this.kubernetesDependentResourceConfig = config;
7373
}
7474

75+
@Override
76+
protected R handleCreate(R desired, P primary, Context<P> context) {
77+
return PrimaryUpdateAndCacheUtils.updateAndCacheSecondaryResource(
78+
desired,
79+
context,
80+
recentOperationCacheFiller(),
81+
toCreate -> KubernetesDependentResource.super.handleCreate(toCreate, primary, context));
82+
}
83+
84+
@Override
85+
protected R handleUpdate(R actual, R desired, P primary, Context<P> context) {
86+
return PrimaryUpdateAndCacheUtils.updateAndCacheSecondaryResource(
87+
desired,
88+
context,
89+
recentOperationCacheFiller(),
90+
toUpdate ->
91+
KubernetesDependentResource.super.handleUpdate(actual, toUpdate, primary, context));
92+
}
93+
7594
@SuppressWarnings("unused")
7695
public R create(R desired, P primary, Context<P> context) {
7796
if (useSSA(context)) {
@@ -158,14 +177,6 @@ protected void addMetadata(
158177
} else {
159178
annotations.remove(InformerEventSource.PREVIOUS_ANNOTATION_KEY);
160179
}
161-
} else if (usePreviousAnnotation(context)) { // set a new one
162-
eventSource()
163-
.orElseThrow()
164-
.addPreviousAnnotation(
165-
Optional.ofNullable(actualResource)
166-
.map(r -> r.getMetadata().getResourceVersion())
167-
.orElse(null),
168-
target);
169180
}
170181
addReferenceHandlingMetadata(target, primary);
171182
}
@@ -181,22 +192,6 @@ protected boolean useSSA(Context<P> context) {
181192
return useSSA;
182193
}
183194

184-
private boolean usePreviousAnnotation(Context<P> context) {
185-
if (usePreviousAnnotationForEventFiltering == null) {
186-
usePreviousAnnotationForEventFiltering =
187-
context
188-
.getControllerConfiguration()
189-
.getConfigurationService()
190-
.previousAnnotationForDependentResourcesEventFiltering()
191-
&& !context
192-
.getControllerConfiguration()
193-
.getConfigurationService()
194-
.withPreviousAnnotationForDependentResourcesBlocklist()
195-
.contains(this.resourceType());
196-
}
197-
return usePreviousAnnotationForEventFiltering;
198-
}
199-
200195
@Override
201196
protected void handleDelete(P primary, R secondary, Context<P> context) {
202197
if (secondary != null) {

0 commit comments

Comments
 (0)