From 7b75ee12bcd240d3ba4bd002bd4a65b66d234856 Mon Sep 17 00:00:00 2001 From: csviri Date: Wed, 2 Mar 2022 14:08:52 +0100 Subject: [PATCH 01/17] feat: Dependent Resources for External Resources --- .../dependent/AbstractDependentResource.java | 62 ++++++++++++++- .../api/reconciler/dependent/Creator.java | 6 +- .../api/reconciler/dependent/Deleter.java | 1 + .../dependent/EventSourceProvider.java | 7 +- .../dependent/RecentOperationCacheFiller.java | 8 ++ .../dependent/RecentOperationEventFilter.java | 9 +++ .../api/reconciler/dependent/Updater.java | 6 +- .../dependent/DependentResourceManager.java | 2 +- .../AbstractExternalDependentResource.java | 25 ++++++ .../PerResourcePollingDependentResource.java | 4 + .../external/PollingDependentResource.java | 21 +++++ .../KubernetesDependentResource.java | 34 +++----- .../event/source/CachingEventSource.java | 54 +++---------- .../event/source/ConcurrentHashMapCache.java | 38 +++++++++ .../source/informer/InformerEventSource.java | 12 ++- .../informer/ManagedInformerEventSource.java | 3 +- .../source/polling/PollingEventSource.java | 14 ++-- .../KubernetesDependentResourceTest.java | 77 ------------------- .../informer/InformerEventSourceTest.java | 12 +-- ...CreateUpdateEventFilterTestReconciler.java | 10 +-- .../StandaloneDependentTestReconciler.java | 2 +- .../dependent/SchemaDependentResource.java | 16 +++- .../WebPageReconcilerDependentResources.java | 11 +-- 23 files changed, 248 insertions(+), 186 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationCacheFiller.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationEventFilter.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ConcurrentHashMapCache.java delete mode 100644 operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceTest.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java index 456e9339de..3249eceb1f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java @@ -40,13 +40,13 @@ public void reconcile(P primary, Context context) { if (maybeActual.isEmpty()) { if (creatable) { log.debug("Creating dependent {} for primary {}", desired, primary); - creator.create(desired, primary, context); + handleCreate(desired, primary, context); } } else { final var actual = maybeActual.get(); if (updatable && !updater.match(actual, desired, context)) { log.debug("Updating dependent {} for primary {}", desired, primary); - updater.update(actual, desired, primary, context); + handleUpdate(actual, desired, primary, context); } else { log.debug("Update skipped for dependent {} as it matched the existing one", desired); } @@ -58,6 +58,64 @@ public void reconcile(P primary, Context context) { } } + public R handleCreate(R desired, P primary, Context context) { + R created = null; + try { + if (isRecentOperationEventFilter()) { + getRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(desired); + } + created = creator.create(desired, primary, context); + if (isRecentOperationCacheFiller()) { + getRecentOperationCacheFiller().handleRecentResourceCreate(created); + } + return created; + } catch (RuntimeException e) { + if (isRecentOperationEventFilter()) { + getRecentOperationEventFilter() + .cleanupOnCreateOrUpdateEventFiltering(created == null ? desired : created); + } + throw e; + } + } + + public R handleUpdate(R actual, R desired, P primary, Context context) { + R updated = null; + try { + if (isRecentOperationEventFilter()) { + getRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(desired); + } + updated = updater.update(actual, desired, primary, context); + if (isRecentOperationCacheFiller()) { + getRecentOperationCacheFiller().handleRecentResourceCreate(updated); + } + return updated; + } catch (RuntimeException e) { + if (isRecentOperationEventFilter()) { + getRecentOperationEventFilter() + .cleanupOnCreateOrUpdateEventFiltering(updated == null ? desired : updated); + } + throw e; + } + } + + private boolean isRecentOperationEventFilter() { + return this instanceof EventSourceProvider && + ((EventSourceProvider

) this).getEventSource() instanceof RecentOperationEventFilter; + } + + private RecentOperationEventFilter getRecentOperationEventFilter() { + return (RecentOperationEventFilter) ((EventSourceProvider

) this).getEventSource(); + } + + private boolean isRecentOperationCacheFiller() { + return this instanceof RecentOperationCacheFiller && + ((EventSourceProvider

) this).getEventSource() instanceof RecentOperationCacheFiller; + } + + private RecentOperationCacheFiller getRecentOperationCacheFiller() { + return (RecentOperationCacheFiller) ((EventSourceProvider

) this).getEventSource(); + } + @Override public void delete(P primary, Context context) { if (isDeletable(primary, context)) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Creator.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Creator.java index f685a5edb4..b8a6056499 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Creator.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Creator.java @@ -4,9 +4,9 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; @SuppressWarnings("rawtypes") +@FunctionalInterface public interface Creator { - Creator NOOP = (desired, primary, context) -> { - }; + Creator NOOP = (desired, primary, context) -> null; - void create(R desired, P primary, Context context); + R create(R desired, P primary, Context context); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java index 7649460934..e612fc1c66 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java @@ -4,6 +4,7 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; @SuppressWarnings("rawtypes") +@FunctionalInterface public interface Deleter

{ Deleter NOOP = (primary, context) -> { }; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/EventSourceProvider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/EventSourceProvider.java index c9a2ca35a2..cc1514fac0 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/EventSourceProvider.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/EventSourceProvider.java @@ -5,6 +5,11 @@ import io.javaoperatorsdk.operator.processing.event.source.EventSource; public interface EventSourceProvider

{ + /** + * @param context - event source context where the event source is initialized + * @return the initiated event source. + */ + EventSource initEventSource(EventSourceContext

context); - EventSource eventSource(EventSourceContext

context); + EventSource getEventSource(); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationCacheFiller.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationCacheFiller.java new file mode 100644 index 0000000000..167f1bbf7d --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationCacheFiller.java @@ -0,0 +1,8 @@ +package io.javaoperatorsdk.operator.api.reconciler.dependent; + +public interface RecentOperationCacheFiller { + + void handleRecentResourceCreate(R resource); + + void handleRecentResourceUpdate(R resource, String previousResourceVersion); +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationEventFilter.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationEventFilter.java new file mode 100644 index 0000000000..d891f7f1f9 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationEventFilter.java @@ -0,0 +1,9 @@ +package io.javaoperatorsdk.operator.api.reconciler.dependent; + +public interface RecentOperationEventFilter extends RecentOperationCacheFiller { + + void prepareForCreateOrUpdateEventFiltering(R resource); + + void cleanupOnCreateOrUpdateEventFiltering(R resource); + +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Updater.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Updater.java index 6984f788f8..2cb0ca6ce6 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Updater.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Updater.java @@ -6,11 +6,11 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; @SuppressWarnings("rawtypes") +@FunctionalInterface public interface Updater { - Updater NOOP = (actual, desired, primary, context) -> { - }; + Updater NOOP = (actual, desired, primary, context) -> null; - void update(R actual, R desired, P primary, Context context); + R update(R actual, R desired, P primary, Context context); default boolean match(R actualResource, R desiredResource, Context context) { return Objects.equals(actualResource, desiredResource); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java index 3f46e12ca5..1d869d3b43 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java @@ -54,7 +54,7 @@ public List prepareEventSources(EventSourceContext

context) { final var dependentResource = createAndConfigureFrom(drc, context.getClient()); if (dependentResource instanceof EventSourceProvider) { EventSourceProvider provider = (EventSourceProvider) dependentResource; - sources.add(provider.eventSource(context)); + sources.add(provider.initEventSource(context)); } return dependentResource; }) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java new file mode 100644 index 0000000000..77121b2d52 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java @@ -0,0 +1,25 @@ +package io.javaoperatorsdk.operator.processing.dependent.external; + +import java.util.Optional; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.ConcurrentHashMapCache; + +public class AbstractExternalDependentResource + extends AbstractDependentResource { + + private final ConcurrentHashMapCache cache = new ConcurrentHashMapCache<>(); + + @Override + public Optional getResource(HasMetadata primaryResource) { + return cache.get(ResourceID.fromResource(primaryResource)); + } + + public void delete(P primary, Context context) { + super.delete(primary, context); + cache.remove(ResourceID.fromResource(primary)); + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java new file mode 100644 index 0000000000..1131552fd7 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java @@ -0,0 +1,4 @@ +package io.javaoperatorsdk.operator.processing.dependent.external; + +public class PerResourcePollingDependentResource { +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java new file mode 100644 index 0000000000..638c70ea93 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java @@ -0,0 +1,21 @@ +package io.javaoperatorsdk.operator.processing.dependent.external; + +import java.util.Optional; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource; +import io.javaoperatorsdk.operator.processing.event.source.polling.PollingEventSource; + +public class PollingDependentResource + extends AbstractDependentResource { + + PollingEventSource pollingEventSource; + + + @Override + public Optional getResource(P primaryResource) { + return pollingEventSource.getAssociated(primaryResource); + } + + +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 8ce3560fdc..c8552039b9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -91,30 +91,13 @@ public void configureWith( this.addOwnerReference = addOwnerReference; } - public void create(R target, P primary, Context context) { - var resourceID = ResourceID.fromResource(target); - try { - informerEventSource.prepareForCreateOrUpdateEventFiltering(resourceID); - var created = prepare(target, primary, "Creating").create(target); - informerEventSource.handleRecentResourceCreate(created); - } catch (RuntimeException e) { - informerEventSource.cleanupOnCreateOrUpdateEventFiltering(resourceID); - throw e; - } + public R create(R target, P primary, Context context) { + return prepare(target, primary, "Creating").create(target); } - public void update(R actual, R target, P primary, Context context) { - var resourceID = ResourceID.fromResource(target); - try { - var updatedActual = processor.replaceSpecOnActual(actual, target, context); - informerEventSource.prepareForCreateOrUpdateEventFiltering(resourceID); - var updated = prepare(target, primary, "Updating").replace(updatedActual); - informerEventSource.handleRecentResourceUpdate(updated, - actual.getMetadata().getResourceVersion()); - } catch (RuntimeException e) { - informerEventSource.cleanupOnCreateOrUpdateEventFiltering(resourceID); - throw e; - } + public R update(R actual, R target, P primary, Context context) { + var updatedActual = processor.replaceSpecOnActual(actual, target, context); + return prepare(target, primary, "Updating").replace(updatedActual); } public boolean match(R actualResource, R desiredResource, Context context) { @@ -143,7 +126,7 @@ protected NonNamespaceOperation, Resource> prepa } @Override - public EventSource eventSource(EventSourceContext

context) { + public EventSource initEventSource(EventSourceContext

context) { if (informerEventSource == null) { configureWith(context.getConfigurationService(), null, null, KubernetesDependent.ADD_OWNER_REFERENCE_DEFAULT); @@ -173,4 +156,9 @@ public Optional getResource(P primaryResource) { public void setKubernetesClient(KubernetesClient kubernetesClient) { this.client = kubernetesClient; } + + @Override + public EventSource getEventSource() { + return informerEventSource; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSource.java index aac04115a3..aadd701749 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSource.java @@ -1,8 +1,6 @@ package io.javaoperatorsdk.operator.processing.event.source; -import java.util.Map; import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; import java.util.stream.Stream; @@ -20,20 +18,20 @@ * an event if the resource is new or not equals to the one in the cache, and if accepted by the * filter if one is present. * - * @param represents the type of resources (usually external non-kubernetes ones) being handled. + * @param represents the type of resources (usually external non-kubernetes ones) being handled. */ -public abstract class CachingEventSource - extends AbstractResourceEventSource implements Cache { +public abstract class CachingEventSource + extends AbstractResourceEventSource implements Cache { - protected UpdatableCache cache; + protected UpdatableCache cache; - protected CachingEventSource(Class resourceClass) { + protected CachingEventSource(Class resourceClass) { super(resourceClass); cache = initCache(); } @Override - public Optional get(ResourceID resourceID) { + public Optional get(ResourceID resourceID) { return cache.get(resourceID); } @@ -48,7 +46,7 @@ public Stream keys() { } @Override - public Stream list(Predicate predicate) { + public Stream list(Predicate predicate) { return cache.list(predicate); } @@ -64,7 +62,7 @@ protected void handleDelete(ResourceID relatedResourceID) { } } - protected void handleEvent(T value, ResourceID relatedResourceID) { + protected void handleEvent(R value, ResourceID relatedResourceID) { if (!isRunning()) { return; } @@ -75,45 +73,17 @@ protected void handleEvent(T value, ResourceID relatedResourceID) { } } - protected UpdatableCache initCache() { - return new MapCache<>(); + protected UpdatableCache initCache() { + return new ConcurrentHashMapCache<>(); } - public Optional getCachedValue(ResourceID resourceID) { + public Optional getCachedValue(ResourceID resourceID) { return cache.get(resourceID); } @Override - public Optional getAssociated(P primary) { + public Optional getAssociated(P primary) { return cache.get(ResourceID.fromResource(primary)); } - protected static class MapCache implements UpdatableCache { - private final Map cache = new ConcurrentHashMap<>(); - - @Override - public Optional get(ResourceID resourceID) { - return Optional.ofNullable(cache.get(resourceID)); - } - - @Override - public Stream keys() { - return cache.keySet().stream(); - } - - @Override - public Stream list(Predicate predicate) { - return cache.values().stream().filter(predicate); - } - - @Override - public T remove(ResourceID key) { - return cache.remove(key); - } - - @Override - public void put(ResourceID key, T resource) { - cache.put(key, resource); - } - } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ConcurrentHashMapCache.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ConcurrentHashMapCache.java new file mode 100644 index 0000000000..76dc615fcb --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ConcurrentHashMapCache.java @@ -0,0 +1,38 @@ +package io.javaoperatorsdk.operator.processing.event.source; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import io.javaoperatorsdk.operator.processing.event.ResourceID; + +public class ConcurrentHashMapCache implements UpdatableCache { + private final Map cache = new ConcurrentHashMap<>(); + + @Override + public Optional get(ResourceID resourceID) { + return Optional.ofNullable(cache.get(resourceID)); + } + + @Override + public Stream keys() { + return cache.keySet().stream(); + } + + @Override + public Stream list(Predicate predicate) { + return cache.values().stream().filter(predicate); + } + + @Override + public T remove(ResourceID key) { + return cache.remove(key); + } + + @Override + public void put(ResourceID key, T resource) { + cache.put(key, resource); + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index 2f8705b63a..c6ac2e1734 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -10,6 +10,7 @@ import io.fabric8.kubernetes.client.informers.ResourceEventHandler; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationEventFilter; import io.javaoperatorsdk.operator.processing.event.Event; import io.javaoperatorsdk.operator.processing.event.EventHandler; import io.javaoperatorsdk.operator.processing.event.ResourceID; @@ -63,7 +64,7 @@ */ public class InformerEventSource extends ManagedInformerEventSource> - implements ResourceCache, ResourceEventHandler { + implements ResourceCache, ResourceEventHandler, RecentOperationEventFilter { private static final Logger log = LoggerFactory.getLogger(InformerEventSource.class); @@ -216,7 +217,9 @@ private synchronized void handleRecentResourceOperationAndStopEventRecording(R r } } - public synchronized void prepareForCreateOrUpdateEventFiltering(ResourceID resourceID) { + @Override + public synchronized void prepareForCreateOrUpdateEventFiltering(R resource) { + var resourceID = ResourceID.fromResource(resource); log.info("Starting event recording for: {}", resourceID); eventRecorder.startEventRecording(resourceID); } @@ -225,9 +228,10 @@ public synchronized void prepareForCreateOrUpdateEventFiltering(ResourceID resou * Mean to be called to clean up in case of an exception from the client. Usually in a catch * block. * - * @param resourceID of the resource + * @param resource handled by the informer */ - public synchronized void cleanupOnCreateOrUpdateEventFiltering(ResourceID resourceID) { + public synchronized void cleanupOnCreateOrUpdateEventFiltering(R resource) { + var resourceID = ResourceID.fromResource(resource); log.info("Stopping event recording for: {}", resourceID); eventRecorder.stopEventRecording(resourceID); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java index 47de996914..d3b6440cd4 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java @@ -13,6 +13,7 @@ import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.kubernetes.client.informers.ResourceEventHandler; import io.javaoperatorsdk.operator.api.config.ResourceConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationCacheFiller; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.CachingEventSource; import io.javaoperatorsdk.operator.processing.event.source.ResourceCache; @@ -20,7 +21,7 @@ public abstract class ManagedInformerEventSource> extends CachingEventSource - implements ResourceEventHandler, ResourceCache { + implements ResourceEventHandler, ResourceCache, RecentOperationCacheFiller { private static final Logger log = LoggerFactory.getLogger(ManagedInformerEventSource.class); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java index 4702bd8c38..d2afca946d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java @@ -37,19 +37,19 @@ * cache. * * - * @param type of the polled resource + * @param type of the polled resource * @param

primary resource type */ -public class PollingEventSource extends CachingEventSource { +public class PollingEventSource extends CachingEventSource { private static final Logger log = LoggerFactory.getLogger(PollingEventSource.class); private final Timer timer = new Timer(); - private final Supplier> supplierToPoll; + private final Supplier> supplierToPoll; private final long period; - public PollingEventSource(Supplier> supplier, - long period, Class resourceClass) { + public PollingEventSource(Supplier> supplier, + long period, Class resourceClass) { super(resourceClass); this.supplierToPoll = supplier; this.period = period; @@ -77,7 +77,7 @@ protected void getStateAndFillCache() { cache.keys().filter(e -> !values.containsKey(e)).forEach(super::handleDelete); } - public void put(ResourceID key, T resource) { + public void put(ResourceID key, R resource) { cache.put(key, resource); } @@ -94,7 +94,7 @@ public void stop() throws OperatorException { * @return related resource */ @Override - public Optional getAssociated(P primary) { + public Optional getAssociated(P primary) { return getCachedValue(ResourceID.fromResource(primary)); } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceTest.java deleted file mode 100644 index e73244f7c6..0000000000 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceTest.java +++ /dev/null @@ -1,77 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent.kubernetes; - -import static org.mockito.Mockito.*; - -class KubernetesDependentResourceTest { - - // private InformerEventSource informerEventSourceMock = mock(InformerEventSource.class); - // private AssociatedSecondaryResourceIdentifier associatedResourceIdentifierMock = - // mock(AssociatedSecondaryResourceIdentifier.class); - // private ResourceMatcher resourceMatcherMock = mock(ResourceMatcher.class); - // private KubernetesDependentResource.ClientFacade clientFacadeMock = - // mock(KubernetesDependentResource.ClientFacade.class); - // - // KubernetesDependentResource kubernetesDependentResource = - // new KubernetesDependentResource() { - // { - // this.informerEventSource = informerEventSourceMock; - // this.resourceMatcher = resourceMatcherMock; - // this.clientFacade = clientFacadeMock; - // this.resourceUpdatePreProcessor = mock(ResourceUpdatePreProcessor.class); - // } - // - // @Override - // protected Object desired(HasMetadata primary, Context context) { - // return testResource(); - // } - // }; - // - // @BeforeEach - // public void setup() { - // InformerConfiguration informerConfigurationMock = mock(InformerConfiguration.class); - // when(informerEventSourceMock.getConfiguration()).thenReturn(informerConfigurationMock); - // when(informerConfigurationMock.getAssociatedResourceIdentifier()) - // .thenReturn(associatedResourceIdentifierMock); - // when(associatedResourceIdentifierMock.associatedSecondaryID(any())) - // .thenReturn(ResourceID.fromResource(testResource())); - // } - // - // @Test - // void updateCallsInformerJustUpdatedHandler() { - // when(resourceMatcherMock.match(any(), any(), any())).thenReturn(false); - // when(clientFacadeMock.replaceResource(any(), any(), any())).thenReturn(testResource()); - // when(informerEventSourceMock.getAssociated(any())).thenReturn(Optional.of(testResource())); - // - // kubernetesDependentResource.reconcile(primaryResource(), null); - // - // verify(informerEventSourceMock, times(1)).handleRecentResourceUpdate(any(), any()); - // } - // - // @Test - // void createCallsInformerJustUpdatedHandler() { - // when(clientFacadeMock.createResource(any(), any(), any())).thenReturn(testResource()); - // when(informerEventSourceMock.getAssociated(any())).thenReturn(Optional.empty()); - // - // kubernetesDependentResource.reconcile(primaryResource(), null); - // - // verify(informerEventSourceMock, times(1)).handleRecentResourceAdd(any()); - // } - // - // TestCustomResource primaryResource() { - // TestCustomResource testCustomResource = new TestCustomResource(); - // testCustomResource.setMetadata(new ObjectMeta()); - // testCustomResource.getMetadata().setName("test"); - // testCustomResource.getMetadata().setNamespace("default"); - // return testCustomResource; - // } - // - // ConfigMap testResource() { - // ConfigMap configMap = new ConfigMap(); - // configMap.setMetadata(new ObjectMeta()); - // configMap.getMetadata().setName("test"); - // configMap.getMetadata().setNamespace("default"); - // configMap.getMetadata().setResourceVersion("0"); - // return configMap; - // } - -} diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java index 1c901034e0..311ba0a3f8 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java @@ -96,7 +96,7 @@ void notPropagatesEventIfAfterUpdateReceivedJustTheRelatedEvent() { informerEventSource - .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment)); + .prepareForCreateOrUpdateEventFiltering(testDeployment); informerEventSource.onUpdate(prevTestDeployment, testDeployment); informerEventSource.handleRecentResourceUpdate(testDeployment, PREV_RESOURCE_VERSION); @@ -110,7 +110,7 @@ void notPropagatesEventIfAfterCreateReceivedJustTheRelatedEvent() { var testDeployment = testDeployment(); informerEventSource - .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment)); + .prepareForCreateOrUpdateEventFiltering(testDeployment); informerEventSource.onAdd(testDeployment); informerEventSource.handleRecentResourceCreate(testDeployment); @@ -127,7 +127,7 @@ void propagatesEventIfNewEventReceivedAfterTheCurrentTargetEvent() { nextTestDeployment.getMetadata().setResourceVersion(NEXT_RESOURCE_VERSION); informerEventSource - .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment)); + .prepareForCreateOrUpdateEventFiltering(testDeployment); informerEventSource.onUpdate(prevTestDeployment, testDeployment); informerEventSource.onUpdate(testDeployment, nextTestDeployment); informerEventSource.handleRecentResourceUpdate(testDeployment, PREV_RESOURCE_VERSION); @@ -145,7 +145,7 @@ void notPropagatesEventIfMoreReceivedButTheLastIsTheUpdated() { prevPrevTestDeployment.getMetadata().setResourceVersion("-1"); informerEventSource - .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment)); + .prepareForCreateOrUpdateEventFiltering(testDeployment); informerEventSource.onUpdate(prevPrevTestDeployment, prevTestDeployment); informerEventSource.onUpdate(prevTestDeployment, testDeployment); informerEventSource.handleRecentResourceUpdate(testDeployment, PREV_RESOURCE_VERSION); @@ -159,7 +159,7 @@ void putsResourceOnTempCacheIfNoEventRecorded() { var testDeployment = testDeployment(); informerEventSource - .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment)); + .prepareForCreateOrUpdateEventFiltering(testDeployment); informerEventSource.handleRecentResourceUpdate(testDeployment, PREV_RESOURCE_VERSION); verify(eventHandlerMock, times(0)).handleEvent(any()); @@ -175,7 +175,7 @@ void putsResourceOnTempCacheIfNoEventRecordedWithSameResourceVersion() { prevPrevTestDeployment.getMetadata().setResourceVersion("-1"); informerEventSource - .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment)); + .prepareForCreateOrUpdateEventFiltering(testDeployment); informerEventSource.onUpdate(prevPrevTestDeployment, prevTestDeployment); informerEventSource.handleRecentResourceUpdate(testDeployment, PREV_RESOURCE_VERSION); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java index ae41eacb68..db193fe12d 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java @@ -11,7 +11,6 @@ import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.junit.KubernetesClientAware; -import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; @@ -42,8 +41,7 @@ public UpdateControl reconcile( if (configMap == null) { var configMapToCreate = createConfigMap(resource); try { - informerEventSource.prepareForCreateOrUpdateEventFiltering( - ResourceID.fromResource(configMapToCreate)); + informerEventSource.prepareForCreateOrUpdateEventFiltering(configMapToCreate); configMap = client .configMaps() @@ -52,7 +50,7 @@ public UpdateControl reconcile( informerEventSource.handleRecentResourceCreate(configMap); } catch (RuntimeException e) { informerEventSource - .cleanupOnCreateOrUpdateEventFiltering(ResourceID.fromResource(configMapToCreate)); + .cleanupOnCreateOrUpdateEventFiltering(configMapToCreate); throw e; } } else { @@ -61,7 +59,7 @@ public UpdateControl reconcile( configMap.getData().put(CONFIG_MAP_TEST_DATA_KEY, resource.getSpec().getValue()); try { informerEventSource - .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(configMap)); + .prepareForCreateOrUpdateEventFiltering(configMap); var newConfigMap = client .configMaps() @@ -71,7 +69,7 @@ public UpdateControl reconcile( newConfigMap, configMap.getMetadata().getResourceVersion()); } catch (RuntimeException e) { informerEventSource - .cleanupOnCreateOrUpdateEventFiltering(ResourceID.fromResource(configMap)); + .cleanupOnCreateOrUpdateEventFiltering(configMap); throw e; } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java index b6efb0f579..63c72c9641 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java @@ -33,7 +33,7 @@ public StandaloneDependentTestReconciler() { @Override public List prepareEventSources( EventSourceContext context) { - return List.of(deploymentDependent.eventSource(context)); + return List.of(deploymentDependent.initEventSource(context)); } @Override diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java index 0a97684e0d..e39ff7cf38 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java @@ -38,6 +38,7 @@ public class SchemaDependentResource private MySQLDbConfig dbConfig; private int pollPeriod = 500; + private PerResourcePollingEventSource perResourcePollingEventSource; @Override public void configureWith(ResourcePollerConfig config) { @@ -46,13 +47,20 @@ public void configureWith(ResourcePollerConfig config) { } @Override - public EventSource eventSource(EventSourceContext context) { + public EventSource initEventSource(EventSourceContext context) { if (dbConfig == null) { dbConfig = MySQLDbConfig.loadFromEnvironmentVars(); } - return new PerResourcePollingEventSource<>( + perResourcePollingEventSource = new PerResourcePollingEventSource<>( new SchemaPollingResourceSupplier(dbConfig), context.getPrimaryCache(), pollPeriod, Schema.class); + + return perResourcePollingEventSource; + } + + @Override + public EventSource getEventSource() { + return perResourcePollingEventSource; } @Override @@ -61,12 +69,12 @@ public Schema desired(MySQLSchema primary, Context context) { } @Override - public void create(Schema target, MySQLSchema mySQLSchema, Context context) { + public Schema create(Schema target, MySQLSchema mySQLSchema, Context context) { try (Connection connection = getConnection()) { Secret secret = context.getSecondaryResource(Secret.class).orElseThrow(); var username = decode(secret.getData().get(MYSQL_SECRET_USERNAME)); var password = decode(secret.getData().get(MYSQL_SECRET_PASSWORD)); - final var schema = SchemaService.createSchemaAndRelatedUser( + return SchemaService.createSchemaAndRelatedUser( connection, target.getName(), target.getCharacterSet(), username, password); diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconcilerDependentResources.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconcilerDependentResources.java index a313a0bf3d..a0c7e25296 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconcilerDependentResources.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconcilerDependentResources.java @@ -45,9 +45,9 @@ public WebPageReconcilerDependentResources(KubernetesClient kubernetesClient) { @Override public List prepareEventSources(EventSourceContext context) { return List.of( - configMapDR.eventSource(context), - deploymentDR.eventSource(context), - serviceDR.eventSource(context)); + configMapDR.initEventSource(context), + deploymentDR.initEventSource(context), + serviceDR.initEventSource(context)); } @Override @@ -180,8 +180,8 @@ protected ConfigMap desired(WebPage webPage, Context context) { } @Override - public void update(ConfigMap actual, ConfigMap target, WebPage primary, Context context) { - super.update(actual, target, primary, context); + public ConfigMap update(ConfigMap actual, ConfigMap target, WebPage primary, Context context) { + var res = super.update(actual, target, primary, context); var ns = actual.getMetadata().getNamespace(); log.info("Restarting pods because HTML has changed in {}", ns); kubernetesClient @@ -189,6 +189,7 @@ public void update(ConfigMap actual, ConfigMap target, WebPage primary, Context .inNamespace(ns) .withLabel("app", deploymentName(primary)) .delete(); + return res; } @Override From 026ccb7790b7aed6e5720119208f91f1a7a20d1f Mon Sep 17 00:00:00 2001 From: csviri Date: Wed, 2 Mar 2022 15:44:12 +0100 Subject: [PATCH 02/17] fix: unified interfaces --- .../dependent/AbstractDependentResource.java | 19 ++++--- .../dependent/RecentOperationCacheFiller.java | 6 ++- .../dependent/RecentOperationEventFilter.java | 6 ++- .../AbstractExternalDependentResource.java | 14 +++++ .../processing/event/EventProcessor.java | 5 +- .../ExternalResourceCachingEventSource.java | 54 +++++++++++++++++++ .../event/source/CachingEventSource.java | 22 -------- .../inbound/CachingInboundEventSource.java | 5 +- .../source/informer/InformerEventSource.java | 20 ++++--- .../informer/ManagedInformerEventSource.java | 10 ++-- .../PerResourcePollingEventSource.java | 3 +- .../source/polling/PollingEventSource.java | 5 +- .../processing/event/EventProcessorTest.java | 3 +- ...ternalResourceCachingEventSourceTest.java} | 13 ++--- .../informer/InformerEventSourceTest.java | 38 ++++++++----- ...CreateUpdateEventFilterTestReconciler.java | 19 ++++--- 16 files changed, 164 insertions(+), 78 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ExternalResourceCachingEventSource.java rename operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/{CachingEventSourceTest.java => ExternalResourceCachingEventSourceTest.java} (81%) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java index 3249eceb1f..a3bb869c26 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java @@ -5,6 +5,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.event.ResourceID; public abstract class AbstractDependentResource implements DependentResource { @@ -58,41 +59,43 @@ public void reconcile(P primary, Context context) { } } - public R handleCreate(R desired, P primary, Context context) { + protected R handleCreate(R desired, P primary, Context context) { + ResourceID resourceID = ResourceID.fromResource(primary); R created = null; try { if (isRecentOperationEventFilter()) { - getRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(desired); + getRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(resourceID, desired); } created = creator.create(desired, primary, context); if (isRecentOperationCacheFiller()) { - getRecentOperationCacheFiller().handleRecentResourceCreate(created); + getRecentOperationCacheFiller().handleRecentResourceCreate(resourceID, created); } return created; } catch (RuntimeException e) { if (isRecentOperationEventFilter()) { getRecentOperationEventFilter() - .cleanupOnCreateOrUpdateEventFiltering(created == null ? desired : created); + .cleanupOnCreateOrUpdateEventFiltering(resourceID, created == null ? desired : created); } throw e; } } - public R handleUpdate(R actual, R desired, P primary, Context context) { + protected R handleUpdate(R actual, R desired, P primary, Context context) { + ResourceID resourceID = ResourceID.fromResource(primary); R updated = null; try { if (isRecentOperationEventFilter()) { - getRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(desired); + getRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(resourceID, desired); } updated = updater.update(actual, desired, primary, context); if (isRecentOperationCacheFiller()) { - getRecentOperationCacheFiller().handleRecentResourceCreate(updated); + getRecentOperationCacheFiller().handleRecentResourceUpdate(resourceID, updated, actual); } return updated; } catch (RuntimeException e) { if (isRecentOperationEventFilter()) { getRecentOperationEventFilter() - .cleanupOnCreateOrUpdateEventFiltering(updated == null ? desired : updated); + .cleanupOnCreateOrUpdateEventFiltering(resourceID, updated == null ? desired : updated); } throw e; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationCacheFiller.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationCacheFiller.java index 167f1bbf7d..7e27537d49 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationCacheFiller.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationCacheFiller.java @@ -1,8 +1,10 @@ package io.javaoperatorsdk.operator.api.reconciler.dependent; +import io.javaoperatorsdk.operator.processing.event.ResourceID; + public interface RecentOperationCacheFiller { - void handleRecentResourceCreate(R resource); + void handleRecentResourceCreate(ResourceID resourceID, R resource); - void handleRecentResourceUpdate(R resource, String previousResourceVersion); + void handleRecentResourceUpdate(ResourceID resourceID, R resource, R previousResourceVersion); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationEventFilter.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationEventFilter.java index d891f7f1f9..5bb9a13f5f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationEventFilter.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationEventFilter.java @@ -1,9 +1,11 @@ package io.javaoperatorsdk.operator.api.reconciler.dependent; +import io.javaoperatorsdk.operator.processing.event.ResourceID; + public interface RecentOperationEventFilter extends RecentOperationCacheFiller { - void prepareForCreateOrUpdateEventFiltering(R resource); + void prepareForCreateOrUpdateEventFiltering(ResourceID resourceID, R resource); - void cleanupOnCreateOrUpdateEventFiltering(R resource); + void cleanupOnCreateOrUpdateEventFiltering(ResourceID resourceID, R resource); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java index 77121b2d52..c4e2ae79be 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java @@ -22,4 +22,18 @@ public void delete(P primary, Context context) { super.delete(primary, context); cache.remove(ResourceID.fromResource(primary)); } + + @Override + protected R handleCreate(R desired, P primary, Context context) { + var res = this.creator.create(desired, primary, context); + cache.put(ResourceID.fromResource(primary), res); + return res; + } + + @Override + protected R handleUpdate(R actual, R desired, P primary, Context context) { + var res = updater.update(actual, desired, primary, context); + cache.put(ResourceID.fromResource(primary), res); + return res; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java index 81e637a2f6..9ea6df7332 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java @@ -208,8 +208,9 @@ void eventProcessingFinished( cleanupForDeletedEvent(executionScope.getCustomResourceID()); } else { postExecutionControl.getUpdatedCustomResource().ifPresent(r -> { - eventSourceManager.getControllerResourceEventSource().handleRecentResourceUpdate(r, - executionScope.getResource().getMetadata().getResourceVersion()); + eventSourceManager.getControllerResourceEventSource().handleRecentResourceUpdate( + ResourceID.fromResource(r), r, + executionScope.getResource()); }); if (eventMarker.eventPresent(resourceID)) { submitReconciliationExecution(resourceID); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ExternalResourceCachingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ExternalResourceCachingEventSource.java new file mode 100644 index 0000000000..5ffa9b2166 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ExternalResourceCachingEventSource.java @@ -0,0 +1,54 @@ +package io.javaoperatorsdk.operator.processing.event; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationCacheFiller; +import io.javaoperatorsdk.operator.processing.event.source.CachingEventSource; + +public class ExternalResourceCachingEventSource + extends CachingEventSource + implements RecentOperationCacheFiller { + + public ExternalResourceCachingEventSource(Class resourceClass) { + super(resourceClass); + } + + public synchronized void handleDelete(ResourceID relatedResourceID) { + if (!isRunning()) { + return; + } + var cachedValue = cache.get(relatedResourceID); + cache.remove(relatedResourceID); + // we only propagate event if the resource was previously in cache + if (cachedValue.isPresent()) { + getEventHandler().handleEvent(new Event(relatedResourceID)); + } + } + + public synchronized void handleEvent(R value, ResourceID relatedResourceID) { + if (!isRunning()) { + return; + } + var cachedValue = cache.get(relatedResourceID); + if (cachedValue.map(v -> !v.equals(value)).orElse(true)) { + cache.put(relatedResourceID, value); + getEventHandler().handleEvent(new Event(relatedResourceID)); + } + } + + @Override + public synchronized void handleRecentResourceCreate(ResourceID resourceID, R resource) { + if (cache.get(resourceID).isEmpty()) { + cache.put(resourceID, resource); + } + } + + @Override + public synchronized void handleRecentResourceUpdate(ResourceID resourceID, R resource, + R previousResourceVersion) { + cache.get(resourceID).ifPresent(r -> { + if (r.equals(previousResourceVersion)) { + cache.put(resourceID, resource); + } + }); + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSource.java index aadd701749..cfc065331d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSource.java @@ -5,7 +5,6 @@ import java.util.stream.Stream; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.processing.event.Event; import io.javaoperatorsdk.operator.processing.event.ResourceID; /** @@ -50,28 +49,7 @@ public Stream list(Predicate predicate) { return cache.list(predicate); } - protected void handleDelete(ResourceID relatedResourceID) { - if (!isRunning()) { - return; - } - var cachedValue = cache.get(relatedResourceID); - cache.remove(relatedResourceID); - // we only propagate event if the resource was previously in cache - if (cachedValue.isPresent()) { - getEventHandler().handleEvent(new Event(relatedResourceID)); - } - } - protected void handleEvent(R value, ResourceID relatedResourceID) { - if (!isRunning()) { - return; - } - var cachedValue = cache.get(relatedResourceID); - if (cachedValue.map(v -> !v.equals(value)).orElse(true)) { - cache.put(relatedResourceID, value); - getEventHandler().handleEvent(new Event(relatedResourceID)); - } - } protected UpdatableCache initCache() { return new ConcurrentHashMapCache<>(); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/inbound/CachingInboundEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/inbound/CachingInboundEventSource.java index 1d60da2a3a..34f37a048b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/inbound/CachingInboundEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/inbound/CachingInboundEventSource.java @@ -1,10 +1,11 @@ package io.javaoperatorsdk.operator.processing.event.source.inbound; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource; import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.CachingEventSource; -public class CachingInboundEventSource extends CachingEventSource { +public class CachingInboundEventSource + extends ExternalResourceCachingEventSource { public CachingInboundEventSource(Class resourceClass) { super(resourceClass); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index c6ac2e1734..6193362897 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -161,14 +161,17 @@ public InformerConfiguration getConfiguration() { } @Override - public void handleRecentResourceUpdate(R resource, String previousResourceVersion) { + public void handleRecentResourceUpdate(ResourceID resourceID, R resource, + R previousResourceVersion) { handleRecentCreateOrUpdate(resource, - () -> super.handleRecentResourceUpdate(resource, previousResourceVersion)); + () -> super.handleRecentResourceUpdate(resourceID, resource, + previousResourceVersion)); } @Override - public void handleRecentResourceCreate(R resource) { - handleRecentCreateOrUpdate(resource, () -> super.handleRecentResourceCreate(resource)); + public void handleRecentResourceCreate(ResourceID resourceID, R resource) { + handleRecentCreateOrUpdate(resource, + () -> super.handleRecentResourceCreate(resourceID, resource)); } private synchronized void handleRecentCreateOrUpdate(R resource, Runnable runnable) { @@ -218,8 +221,8 @@ private synchronized void handleRecentResourceOperationAndStopEventRecording(R r } @Override - public synchronized void prepareForCreateOrUpdateEventFiltering(R resource) { - var resourceID = ResourceID.fromResource(resource); + public synchronized void prepareForCreateOrUpdateEventFiltering(ResourceID resourceID, + R resource) { log.info("Starting event recording for: {}", resourceID); eventRecorder.startEventRecording(resourceID); } @@ -230,8 +233,9 @@ public synchronized void prepareForCreateOrUpdateEventFiltering(R resource) { * * @param resource handled by the informer */ - public synchronized void cleanupOnCreateOrUpdateEventFiltering(R resource) { - var resourceID = ResourceID.fromResource(resource); + @Override + public synchronized void cleanupOnCreateOrUpdateEventFiltering(ResourceID resourceID, + R resource) { log.info("Stopping event recording for: {}", resourceID); eventRecorder.stopEventRecording(resourceID); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java index d3b6440cd4..063207b0e7 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java @@ -69,11 +69,15 @@ public void stop() { manager().stop(); } - public void handleRecentResourceUpdate(R resource, String previousResourceVersion) { - temporaryResourceCache.putUpdatedResource(resource, previousResourceVersion); + @Override + public void handleRecentResourceUpdate(ResourceID resourceID, R resource, + R previousResourceVersion) { + temporaryResourceCache.putUpdatedResource(resource, + previousResourceVersion.getMetadata().getResourceVersion()); } - public void handleRecentResourceCreate(R resource) { + @Override + public void handleRecentResourceCreate(ResourceID resourceID, R resource) { temporaryResourceCache.putAddedResource(resource); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java index 9130d27a45..39c83334b1 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java @@ -12,6 +12,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.OperatorException; +import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.Cache; import io.javaoperatorsdk.operator.processing.event.source.CachingEventSource; @@ -29,7 +30,7 @@ * @param related custom resource */ public class PerResourcePollingEventSource - extends CachingEventSource + extends ExternalResourceCachingEventSource implements ResourceEventAware { private static final Logger log = LoggerFactory.getLogger(PerResourcePollingEventSource.class); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java index d2afca946d..c07771e717 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java @@ -8,8 +8,8 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.OperatorException; +import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource; import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.CachingEventSource; /** *

@@ -40,7 +40,8 @@ * @param type of the polled resource * @param

primary resource type */ -public class PollingEventSource extends CachingEventSource { +public class PollingEventSource + extends ExternalResourceCachingEventSource { private static final Logger log = LoggerFactory.getLogger(PollingEventSource.class); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventProcessorTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventProcessorTest.java index c02a3b0da1..a716a49898 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventProcessorTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventProcessorTest.java @@ -247,7 +247,8 @@ void updatesEventSourceHandlerIfResourceUpdated() { eventProcessorWithRetry.eventProcessingFinished(executionScope, postExecutionControl); - verify(controllerResourceEventSourceMock, times(1)).handleRecentResourceUpdate(any(), any()); + verify(controllerResourceEventSourceMock, times(1)).handleRecentResourceUpdate(any(), any(), + any()); } private ResourceID eventAlreadyUnderProcessing() { diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/ExternalResourceCachingEventSourceTest.java similarity index 81% rename from operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSourceTest.java rename to operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/ExternalResourceCachingEventSourceTest.java index 29cf0a981d..9ed4e25342 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/ExternalResourceCachingEventSourceTest.java @@ -6,17 +6,18 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.processing.event.Event; import io.javaoperatorsdk.operator.processing.event.EventHandler; +import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource; import static io.javaoperatorsdk.operator.processing.event.source.SampleExternalResource.*; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; -class CachingEventSourceTest extends - AbstractEventSourceTestBase, EventHandler> { +class ExternalResourceCachingEventSourceTest extends + AbstractEventSourceTestBase, EventHandler> { @BeforeEach public void setup() { - setUpSource(new SimpleCachingEventSource()); + setUpSource(new SimpleExternalCachingEventSource()); } @Test @@ -65,9 +66,9 @@ public void noEventOnDeleteIfResourceWasNotInCacheBefore() { } - public static class SimpleCachingEventSource - extends CachingEventSource { - public SimpleCachingEventSource() { + public static class SimpleExternalCachingEventSource + extends ExternalResourceCachingEventSource { + public SimpleExternalCachingEventSource() { super(SampleExternalResource.class); } } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java index 311ba0a3f8..4caf9b70d2 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java @@ -96,9 +96,11 @@ void notPropagatesEventIfAfterUpdateReceivedJustTheRelatedEvent() { informerEventSource - .prepareForCreateOrUpdateEventFiltering(testDeployment); + .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment), + testDeployment); informerEventSource.onUpdate(prevTestDeployment, testDeployment); - informerEventSource.handleRecentResourceUpdate(testDeployment, PREV_RESOURCE_VERSION); + informerEventSource.handleRecentResourceUpdate(ResourceID.fromResource(testDeployment), + testDeployment, prevTestDeployment); verify(eventHandlerMock, times(0)).handleEvent(any()); verify(temporaryResourceCacheMock, times(0)).unconditionallyCacheResource(any()); @@ -110,9 +112,11 @@ void notPropagatesEventIfAfterCreateReceivedJustTheRelatedEvent() { var testDeployment = testDeployment(); informerEventSource - .prepareForCreateOrUpdateEventFiltering(testDeployment); + .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment), + testDeployment); informerEventSource.onAdd(testDeployment); - informerEventSource.handleRecentResourceCreate(testDeployment); + informerEventSource.handleRecentResourceCreate(ResourceID.fromResource(testDeployment), + testDeployment); verify(eventHandlerMock, times(0)).handleEvent(any()); verify(temporaryResourceCacheMock, times(0)).unconditionallyCacheResource(any()); @@ -127,10 +131,12 @@ void propagatesEventIfNewEventReceivedAfterTheCurrentTargetEvent() { nextTestDeployment.getMetadata().setResourceVersion(NEXT_RESOURCE_VERSION); informerEventSource - .prepareForCreateOrUpdateEventFiltering(testDeployment); + .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment), + testDeployment); informerEventSource.onUpdate(prevTestDeployment, testDeployment); informerEventSource.onUpdate(testDeployment, nextTestDeployment); - informerEventSource.handleRecentResourceUpdate(testDeployment, PREV_RESOURCE_VERSION); + informerEventSource.handleRecentResourceUpdate(ResourceID.fromResource(testDeployment), + testDeployment, prevTestDeployment); verify(eventHandlerMock, times(1)).handleEvent(any()); verify(temporaryResourceCacheMock, times(0)).unconditionallyCacheResource(any()); @@ -145,10 +151,12 @@ void notPropagatesEventIfMoreReceivedButTheLastIsTheUpdated() { prevPrevTestDeployment.getMetadata().setResourceVersion("-1"); informerEventSource - .prepareForCreateOrUpdateEventFiltering(testDeployment); + .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment), + testDeployment); informerEventSource.onUpdate(prevPrevTestDeployment, prevTestDeployment); informerEventSource.onUpdate(prevTestDeployment, testDeployment); - informerEventSource.handleRecentResourceUpdate(testDeployment, PREV_RESOURCE_VERSION); + informerEventSource.handleRecentResourceUpdate(ResourceID.fromResource(testDeployment), + testDeployment, prevTestDeployment); verify(eventHandlerMock, times(0)).handleEvent(any()); verify(temporaryResourceCacheMock, times(0)).unconditionallyCacheResource(any()); @@ -157,10 +165,14 @@ void notPropagatesEventIfMoreReceivedButTheLastIsTheUpdated() { @Test void putsResourceOnTempCacheIfNoEventRecorded() { var testDeployment = testDeployment(); + var prevTestDeployment = testDeployment(); + prevTestDeployment.getMetadata().setResourceVersion(PREV_RESOURCE_VERSION); informerEventSource - .prepareForCreateOrUpdateEventFiltering(testDeployment); - informerEventSource.handleRecentResourceUpdate(testDeployment, PREV_RESOURCE_VERSION); + .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment), + testDeployment); + informerEventSource.handleRecentResourceUpdate(ResourceID.fromResource(testDeployment), + testDeployment, prevTestDeployment); verify(eventHandlerMock, times(0)).handleEvent(any()); verify(temporaryResourceCacheMock, times(1)).unconditionallyCacheResource(any()); @@ -175,9 +187,11 @@ void putsResourceOnTempCacheIfNoEventRecordedWithSameResourceVersion() { prevPrevTestDeployment.getMetadata().setResourceVersion("-1"); informerEventSource - .prepareForCreateOrUpdateEventFiltering(testDeployment); + .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment), + testDeployment); informerEventSource.onUpdate(prevPrevTestDeployment, prevTestDeployment); - informerEventSource.handleRecentResourceUpdate(testDeployment, PREV_RESOURCE_VERSION); + informerEventSource.handleRecentResourceUpdate(ResourceID.fromResource(testDeployment), + testDeployment, prevTestDeployment); verify(eventHandlerMock, times(0)).handleEvent(any()); verify(temporaryResourceCacheMock, times(1)).unconditionallyCacheResource(any()); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java index db193fe12d..551490b43e 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java @@ -11,6 +11,7 @@ import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.junit.KubernetesClientAware; +import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; @@ -41,35 +42,39 @@ public UpdateControl reconcile( if (configMap == null) { var configMapToCreate = createConfigMap(resource); try { - informerEventSource.prepareForCreateOrUpdateEventFiltering(configMapToCreate); + informerEventSource.prepareForCreateOrUpdateEventFiltering( + ResourceID.fromResource(configMapToCreate), configMapToCreate); configMap = client .configMaps() .inNamespace(resource.getMetadata().getNamespace()) .create(configMapToCreate); - informerEventSource.handleRecentResourceCreate(configMap); + informerEventSource.handleRecentResourceCreate(ResourceID.fromResource(configMapToCreate), + configMap); } catch (RuntimeException e) { informerEventSource - .cleanupOnCreateOrUpdateEventFiltering(configMapToCreate); + .cleanupOnCreateOrUpdateEventFiltering(ResourceID.fromResource(configMapToCreate), + configMapToCreate); throw e; } } else { + ResourceID resourceID = ResourceID.fromResource(configMap); if (!Objects.equals( configMap.getData().get(CONFIG_MAP_TEST_DATA_KEY), resource.getSpec().getValue())) { configMap.getData().put(CONFIG_MAP_TEST_DATA_KEY, resource.getSpec().getValue()); try { informerEventSource - .prepareForCreateOrUpdateEventFiltering(configMap); + .prepareForCreateOrUpdateEventFiltering(resourceID, configMap); var newConfigMap = client .configMaps() .inNamespace(resource.getMetadata().getNamespace()) .replace(configMap); - informerEventSource.handleRecentResourceUpdate( - newConfigMap, configMap.getMetadata().getResourceVersion()); + informerEventSource.handleRecentResourceUpdate(resourceID, + newConfigMap, configMap); } catch (RuntimeException e) { informerEventSource - .cleanupOnCreateOrUpdateEventFiltering(configMap); + .cleanupOnCreateOrUpdateEventFiltering(resourceID, configMap); throw e; } } From 41e97da7999d17623375fed738be1a26ac4ef3fe Mon Sep 17 00:00:00 2001 From: csviri Date: Wed, 2 Mar 2022 16:43:50 +0100 Subject: [PATCH 03/17] fix: external polling event sources --- ...tractExternalCachingDependentResource.java | 36 +++++++++++++++ .../AbstractExternalDependentResource.java | 5 +- .../PerResourcePollingDependentResource.java | 4 -- ...ourcePollingExternalDependentResource.java | 35 ++++++++++++++ .../external/PollingDependentResource.java | 21 --------- .../PollingExternalDependentResource.java | 37 +++++++++++++++ .../PerResourcePollingEventSource.java | 46 +++++++++---------- 7 files changed, 135 insertions(+), 49 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingExternalDependentResource.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java new file mode 100644 index 0000000000..eb01409c6a --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java @@ -0,0 +1,36 @@ +package io.javaoperatorsdk.operator.processing.dependent.external; + +import java.util.Optional; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.config.Utils; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider; +import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; + +public abstract class AbstractExternalCachingDependentResource + extends AbstractDependentResource implements EventSourceProvider

{ + + protected ExternalResourceCachingEventSource eventSource; + + @Override + public EventSource initEventSource(EventSourceContext

context) { + return null; + } + + @Override + public Optional getResource(P primaryResource) { + return eventSource.getAssociated(primaryResource); + } + + @Override + public EventSource getEventSource() { + return eventSource; + } + + protected Class resourceType() { + return (Class) Utils.getFirstTypeArgumentFromExtendedClass(getClass()); + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java index c4e2ae79be..10f299f9f2 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java @@ -7,12 +7,15 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.ConcurrentHashMapCache; +import io.javaoperatorsdk.operator.processing.event.source.UpdatableCache; +/** A base class for external dependent resources which don't have an event source. */ public class AbstractExternalDependentResource extends AbstractDependentResource { - private final ConcurrentHashMapCache cache = new ConcurrentHashMapCache<>(); + private final UpdatableCache cache = new ConcurrentHashMapCache<>(); + // todo do we always want this? this should be just in case it's not a reconciliation @Override public Optional getResource(HasMetadata primaryResource) { return cache.get(ResourceID.fromResource(primaryResource)); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java deleted file mode 100644 index 1131552fd7..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent.external; - -public class PerResourcePollingDependentResource { -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java new file mode 100644 index 0000000000..ea78ecfd2f --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java @@ -0,0 +1,35 @@ +package io.javaoperatorsdk.operator.processing.dependent.external; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; +import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource; + +// todo configure with for polling +public abstract class PerResourcePollingExternalDependentResource + extends AbstractExternalCachingDependentResource + implements PerResourcePollingEventSource.ResourceSupplier { + + public static final int DEFAULT_POLLING_PERIOD = 5000; + private long pollingPeriod; + + public PerResourcePollingExternalDependentResource() { + this(DEFAULT_POLLING_PERIOD); + } + + public PerResourcePollingExternalDependentResource(long pollingPeriod) { + this.pollingPeriod = pollingPeriod; + } + + @Override + public EventSource initEventSource(EventSourceContext

context) { + eventSource = new PerResourcePollingEventSource<>(this, context.getPrimaryCache(), + pollingPeriod, resourceType()); + return eventSource; + } + + public PerResourcePollingExternalDependentResource setPollingPeriod(long pollingPeriod) { + this.pollingPeriod = pollingPeriod; + return this; + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java deleted file mode 100644 index 638c70ea93..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent.external; - -import java.util.Optional; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource; -import io.javaoperatorsdk.operator.processing.event.source.polling.PollingEventSource; - -public class PollingDependentResource - extends AbstractDependentResource { - - PollingEventSource pollingEventSource; - - - @Override - public Optional getResource(P primaryResource) { - return pollingEventSource.getAssociated(primaryResource); - } - - -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingExternalDependentResource.java new file mode 100644 index 0000000000..ff3feb47fd --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingExternalDependentResource.java @@ -0,0 +1,37 @@ +package io.javaoperatorsdk.operator.processing.dependent.external; + +import java.util.Map; +import java.util.function.Supplier; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; +import io.javaoperatorsdk.operator.processing.event.source.polling.PollingEventSource; + +// todo configure with for polling +public abstract class PollingExternalDependentResource + extends AbstractExternalCachingDependentResource implements Supplier> { + + public static final int DEFAULT_POLLING_PERIOD = 5000; + private long pollingPeriod; + + public PollingExternalDependentResource() { + this(DEFAULT_POLLING_PERIOD); + } + + public PollingExternalDependentResource(long pollingPeriod) { + this.pollingPeriod = pollingPeriod; + } + + @Override + public EventSource initEventSource(EventSourceContext

context) { + eventSource = new PollingEventSource<>(this, pollingPeriod, resourceType()); + return eventSource; + } + + public PollingExternalDependentResource setPollingPeriod(long pollingPeriod) { + this.pollingPeriod = pollingPeriod; + return this; + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java index 39c83334b1..af54255f65 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java @@ -26,30 +26,30 @@ *

* For other behavior see {@link CachingEventSource} * - * @param the resource polled by the event source - * @param related custom resource + * @param the resource polled by the event source + * @param

related custom resource */ -public class PerResourcePollingEventSource - extends ExternalResourceCachingEventSource - implements ResourceEventAware { +public class PerResourcePollingEventSource + extends ExternalResourceCachingEventSource + implements ResourceEventAware

{ private static final Logger log = LoggerFactory.getLogger(PerResourcePollingEventSource.class); private final Timer timer = new Timer(); private final Map timerTasks = new ConcurrentHashMap<>(); - private final ResourceSupplier resourceSupplier; - private final Cache resourceCache; - private final Predicate registerPredicate; + private final ResourceSupplier resourceSupplier; + private final Cache

resourceCache; + private final Predicate

registerPredicate; private final long period; - public PerResourcePollingEventSource(ResourceSupplier resourceSupplier, - Cache resourceCache, long period, Class resourceClass) { + public PerResourcePollingEventSource(ResourceSupplier resourceSupplier, + Cache

resourceCache, long period, Class resourceClass) { this(resourceSupplier, resourceCache, period, null, resourceClass); } - public PerResourcePollingEventSource(ResourceSupplier resourceSupplier, - Cache resourceCache, long period, - Predicate registerPredicate, Class resourceClass) { + public PerResourcePollingEventSource(ResourceSupplier resourceSupplier, + Cache

resourceCache, long period, + Predicate

registerPredicate, Class resourceClass) { super(resourceClass); this.resourceSupplier = resourceSupplier; this.resourceCache = resourceCache; @@ -57,7 +57,7 @@ public PerResourcePollingEventSource(ResourceSupplier resourceSupplier, this.registerPredicate = registerPredicate; } - private void pollForResource(R resource) { + private void pollForResource(P resource) { var value = resourceSupplier.getResource(resource); var resourceID = ResourceID.fromResource(resource); if (value.isEmpty()) { @@ -67,7 +67,7 @@ private void pollForResource(R resource) { } } - private Optional getAndCacheResource(ResourceID resourceID) { + private Optional getAndCacheResource(ResourceID resourceID) { var resource = resourceCache.get(resourceID); if (resource.isPresent()) { var value = resourceSupplier.getResource(resource.get()); @@ -78,17 +78,17 @@ private Optional getAndCacheResource(ResourceID resourceID) { } @Override - public void onResourceCreated(R resource) { + public void onResourceCreated(P resource) { checkAndRegisterTask(resource); } @Override - public void onResourceUpdated(R newResource, R oldResource) { + public void onResourceUpdated(P newResource, P oldResource) { checkAndRegisterTask(newResource); } @Override - public void onResourceDeleted(R resource) { + public void onResourceDeleted(P resource) { var resourceID = ResourceID.fromResource(resource); TimerTask task = timerTasks.remove(resourceID); if (task != null) { @@ -102,7 +102,7 @@ public void onResourceDeleted(R resource) { // since events from ResourceEventAware are propagated from the thread of the informer. This is // important // because otherwise there will be a race condition related to the timerTasks. - private void checkAndRegisterTask(R resource) { + private void checkAndRegisterTask(P resource) { var resourceID = ResourceID.fromResource(resource); if (timerTasks.get(resourceID) == null && (registerPredicate == null || registerPredicate.test(resource))) { @@ -132,7 +132,7 @@ public void run() { * @return the related resource for this event source */ @Override - public Optional getAssociated(R primary) { + public Optional getAssociated(P primary) { return getValueFromCacheOrSupplier(ResourceID.fromResource(primary)); } @@ -143,7 +143,7 @@ public Optional getAssociated(R primary) { * supplier. The value provided from the supplier is cached, but no new event is * propagated. */ - public Optional getValueFromCacheOrSupplier(ResourceID resourceID) { + public Optional getValueFromCacheOrSupplier(ResourceID resourceID) { var cachedValue = getCachedValue(resourceID); if (cachedValue.isPresent()) { return cachedValue; @@ -152,8 +152,8 @@ public Optional getValueFromCacheOrSupplier(ResourceID resourceID) { } } - public interface ResourceSupplier { - Optional getResource(R resource); + public interface ResourceSupplier { + Optional getResource(P resource); } @Override From 6a9c4b7e3edbc9d7c443fccb1aa8435a5026d0cf Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 3 Mar 2022 10:05:47 +0100 Subject: [PATCH 04/17] fix: mysql resource migration --- .../AbstractExternalCachingDependentResource.java | 8 ++++++-- .../polling/PerResourcePollingEventSource.java | 6 +++--- .../polling/PerResourcePollingEventSourceTest.java | 14 +++++++------- .../operator/sample/MySQLSchemaReconciler.java | 2 +- .../sample/dependent/SchemaDependentResource.java | 7 +++---- .../dependent/SchemaPollingResourceSupplier.java | 2 +- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java index eb01409c6a..50914a0095 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java @@ -20,8 +20,7 @@ public EventSource initEventSource(EventSourceContext

context) { return null; } - @Override - public Optional getResource(P primaryResource) { + public Optional getSupplierResource(P primaryResource) { return eventSource.getAssociated(primaryResource); } @@ -33,4 +32,9 @@ public EventSource getEventSource() { protected Class resourceType() { return (Class) Utils.getFirstTypeArgumentFromExtendedClass(getClass()); } + + @Override + public Optional getResource(P primaryResource) { + return eventSource.getAssociated(primaryResource); + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java index af54255f65..61169214f3 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java @@ -58,7 +58,7 @@ public PerResourcePollingEventSource(ResourceSupplier resourceSupplier, } private void pollForResource(P resource) { - var value = resourceSupplier.getResource(resource); + var value = resourceSupplier.getSupplierResource(resource); var resourceID = ResourceID.fromResource(resource); if (value.isEmpty()) { super.handleDelete(resourceID); @@ -70,7 +70,7 @@ private void pollForResource(P resource) { private Optional getAndCacheResource(ResourceID resourceID) { var resource = resourceCache.get(resourceID); if (resource.isPresent()) { - var value = resourceSupplier.getResource(resource.get()); + var value = resourceSupplier.getSupplierResource(resource.get()); value.ifPresent(v -> cache.put(resourceID, v)); return value; } @@ -153,7 +153,7 @@ public Optional getValueFromCacheOrSupplier(ResourceID resourceID) { } public interface ResourceSupplier { - Optional getResource(P resource); + Optional getSupplierResource(P resource); } @Override diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSourceTest.java index 8486f705ca..a09416714a 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSourceTest.java @@ -35,7 +35,7 @@ class PerResourcePollingEventSourceTest extends @BeforeEach public void setup() { when(resourceCache.get(any())).thenReturn(Optional.of(testCustomResource)); - when(supplier.getResource(any())) + when(supplier.getSupplierResource(any())) .thenReturn(Optional.of(SampleExternalResource.testResource1())); setUpSource(new PerResourcePollingEventSource<>(supplier, resourceCache, PERIOD, @@ -47,7 +47,7 @@ public void pollsTheResourceAfterAwareOfIt() throws InterruptedException { source.onResourceCreated(testCustomResource); Thread.sleep(3 * PERIOD); - verify(supplier, atLeast(2)).getResource(eq(testCustomResource)); + verify(supplier, atLeast(2)).getSupplierResource(eq(testCustomResource)); verify(eventHandler, times(1)).handleEvent(any()); } @@ -59,31 +59,31 @@ public void registeringTaskOnAPredicate() throws InterruptedException { source.onResourceCreated(testCustomResource); Thread.sleep(2 * PERIOD); - verify(supplier, times(0)).getResource(eq(testCustomResource)); + verify(supplier, times(0)).getSupplierResource(eq(testCustomResource)); testCustomResource.getMetadata().setGeneration(2L); source.onResourceUpdated(testCustomResource, testCustomResource); Thread.sleep(2 * PERIOD); - verify(supplier, atLeast(1)).getResource(eq(testCustomResource)); + verify(supplier, atLeast(1)).getSupplierResource(eq(testCustomResource)); } @Test public void propagateEventOnDeletedResource() throws InterruptedException { source.onResourceCreated(testCustomResource); - when(supplier.getResource(any())) + when(supplier.getSupplierResource(any())) .thenReturn(Optional.of(SampleExternalResource.testResource1())) .thenReturn(Optional.empty()); Thread.sleep(3 * PERIOD); - verify(supplier, atLeast(2)).getResource(eq(testCustomResource)); + verify(supplier, atLeast(2)).getSupplierResource(eq(testCustomResource)); verify(eventHandler, times(2)).handleEvent(any()); } @Test public void getsValueFromCacheOrSupplier() throws InterruptedException { source.onResourceCreated(testCustomResource); - when(supplier.getResource(any())) + when(supplier.getSupplierResource(any())) .thenReturn(Optional.empty()) .thenReturn(Optional.of(SampleExternalResource.testResource1())); diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java index a6923823aa..410f5a59f5 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java @@ -41,7 +41,7 @@ public UpdateControl reconcile(MySQLSchema schema, Context context) Secret secret = context.getSecondaryResource(Secret.class).orElseThrow(); SchemaDependentResource schemaDependentResource = context.managedDependentResourceContext() .getDependentResource(SchemaDependentResource.class); - return schemaDependentResource.getResource(schema).map(s -> { + return schemaDependentResource.getSupplierResource(schema).map(s -> { updateStatusPojo(schema, secret.getMetadata().getName(), secret.getData().get(MYSQL_SECRET_USERNAME)); log.info("Schema {} created - updating CR status", schema.getMetadata().getName()); diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java index e39ff7cf38..bebc6a1213 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java @@ -12,11 +12,11 @@ import io.fabric8.kubernetes.api.model.Secret; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource; import io.javaoperatorsdk.operator.api.reconciler.dependent.Creator; import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceConfigurator; import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider; +import io.javaoperatorsdk.operator.processing.dependent.external.PerResourcePollingExternalDependentResource; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource; import io.javaoperatorsdk.operator.sample.*; @@ -28,7 +28,7 @@ import static java.lang.String.format; public class SchemaDependentResource - extends AbstractDependentResource + extends PerResourcePollingExternalDependentResource implements EventSourceProvider, DependentResourceConfigurator, Creator, @@ -102,9 +102,8 @@ public void delete(MySQLSchema primary, Context context) { } } - // todo this should read the resource from event source? @Override - public Optional getResource(MySQLSchema primaryResource) { + public Optional getSupplierResource(MySQLSchema primaryResource) { try (Connection connection = getConnection()) { var schema = SchemaService.getSchema(connection, primaryResource.getMetadata().getName()).orElse(null); diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaPollingResourceSupplier.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaPollingResourceSupplier.java index acf620e819..e5e029f1a6 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaPollingResourceSupplier.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaPollingResourceSupplier.java @@ -18,7 +18,7 @@ public SchemaPollingResourceSupplier(MySQLDbConfig mySQLDbConfig) { } @Override - public Optional getResource(MySQLSchema resource) { + public Optional getSupplierResource(MySQLSchema resource) { return schemaService.getSchema(resource.getMetadata().getName()); } } From 421b36da1ab72b92c35ebe29a7cab0cbf3b7dfc5 Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 3 Mar 2022 10:19:05 +0100 Subject: [PATCH 05/17] fix: format --- .../processing/event/source/informer/InformerEventSource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index 6193362897..4a23bd9363 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -230,7 +230,7 @@ public synchronized void prepareForCreateOrUpdateEventFiltering(ResourceID resou /** * Mean to be called to clean up in case of an exception from the client. Usually in a catch * block. - * + * * @param resource handled by the informer */ @Override From 8c3e2e19a3244c4ea17afcd9c2e85a7f0f9af930 Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 3 Mar 2022 10:26:11 +0100 Subject: [PATCH 06/17] fix: mysql sample update --- ...ourcePollingExternalDependentResource.java | 6 ++++- .../dependent/SchemaDependentResource.java | 24 +------------------ 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java index ea78ecfd2f..f20f54ac45 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java @@ -11,7 +11,7 @@ public abstract class PerResourcePollingExternalDependentResource { public static final int DEFAULT_POLLING_PERIOD = 5000; - private long pollingPeriod; + protected long pollingPeriod; public PerResourcePollingExternalDependentResource() { this(DEFAULT_POLLING_PERIOD); @@ -32,4 +32,8 @@ public PerResourcePollingExternalDependentResource setPollingPeriod(long p this.pollingPeriod = pollingPeriod; return this; } + + public long getPollingPeriod() { + return pollingPeriod; + } } diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java index bebc6a1213..9bd0a819ec 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java @@ -11,14 +11,11 @@ import io.fabric8.kubernetes.api.model.Secret; import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.dependent.Creator; import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceConfigurator; import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider; import io.javaoperatorsdk.operator.processing.dependent.external.PerResourcePollingExternalDependentResource; -import io.javaoperatorsdk.operator.processing.event.source.EventSource; -import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource; import io.javaoperatorsdk.operator.sample.*; import io.javaoperatorsdk.operator.sample.schema.Schema; import io.javaoperatorsdk.operator.sample.schema.SchemaService; @@ -37,30 +34,11 @@ public class SchemaDependentResource private static final Logger log = LoggerFactory.getLogger(SchemaDependentResource.class); private MySQLDbConfig dbConfig; - private int pollPeriod = 500; - private PerResourcePollingEventSource perResourcePollingEventSource; @Override public void configureWith(ResourcePollerConfig config) { this.dbConfig = config.getMySQLDbConfig(); - this.pollPeriod = config.getPollPeriod(); - } - - @Override - public EventSource initEventSource(EventSourceContext context) { - if (dbConfig == null) { - dbConfig = MySQLDbConfig.loadFromEnvironmentVars(); - } - perResourcePollingEventSource = new PerResourcePollingEventSource<>( - new SchemaPollingResourceSupplier(dbConfig), context.getPrimaryCache(), pollPeriod, - Schema.class); - - return perResourcePollingEventSource; - } - - @Override - public EventSource getEventSource() { - return perResourcePollingEventSource; + setPollingPeriod(config.getPollPeriod()); } @Override From 4ba87d13be28e151bf6220d8036f83aa460d8934 Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 3 Mar 2022 10:53:05 +0100 Subject: [PATCH 07/17] fix: further improvements --- ...tractExternalCachingDependentResource.java | 6 ---- ...tractSimpleExternalDependentResource.java} | 31 ++++++++++++++++--- ...ourcePollingExternalDependentResource.java | 4 ++- .../PollingExternalDependentResource.java | 3 +- .../sample/MySQLSchemaOperatorE2E.java | 2 +- 5 files changed, 32 insertions(+), 14 deletions(-) rename operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/{AbstractExternalDependentResource.java => AbstractSimpleExternalDependentResource.java} (54%) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java index 50914a0095..64667f0506 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java @@ -4,7 +4,6 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.config.Utils; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource; import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider; import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource; @@ -15,11 +14,6 @@ public abstract class AbstractExternalCachingDependentResource eventSource; - @Override - public EventSource initEventSource(EventSourceContext

context) { - return null; - } - public Optional getSupplierResource(P primaryResource) { return eventSource.getAssociated(primaryResource); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java similarity index 54% rename from operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java rename to operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java index 10f299f9f2..f46f627d75 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java @@ -1,6 +1,8 @@ package io.javaoperatorsdk.operator.processing.dependent.external; import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.Context; @@ -9,16 +11,37 @@ import io.javaoperatorsdk.operator.processing.event.source.ConcurrentHashMapCache; import io.javaoperatorsdk.operator.processing.event.source.UpdatableCache; -/** A base class for external dependent resources which don't have an event source. */ -public class AbstractExternalDependentResource +/** A base class for external dependent resources that don't have an event source. */ +public abstract class AbstractSimpleExternalDependentResource extends AbstractDependentResource { private final UpdatableCache cache = new ConcurrentHashMapCache<>(); + private final Set reconciling = ConcurrentHashMap.newKeySet(); - // todo do we always want this? this should be just in case it's not a reconciliation @Override public Optional getResource(HasMetadata primaryResource) { - return cache.get(ResourceID.fromResource(primaryResource)); + var resourceId = ResourceID.fromResource(primaryResource); + if (reconciling.contains(ResourceID.fromResource(primaryResource))) { + var resource = supplyResource(primaryResource); + resource.ifPresent(r -> cache.put(resourceId, r)); + return resource; + } else { + return cache.get(ResourceID.fromResource(primaryResource)); + } + } + + /** Actually read the resource from the target API */ + public abstract Optional supplyResource(HasMetadata primaryResource); + + @Override + public void reconcile(P primary, Context context) { + var resourceId = ResourceID.fromResource(primary); + try { + reconciling.add(resourceId); + super.reconcile(primary, context); + } finally { + reconciling.remove(resourceId); + } } public void delete(P primary, Context context) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java index f20f54ac45..bb60249c2a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java @@ -5,12 +5,13 @@ import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource; +import static io.javaoperatorsdk.operator.processing.dependent.external.PollingExternalDependentResource.DEFAULT_POLLING_PERIOD; + // todo configure with for polling public abstract class PerResourcePollingExternalDependentResource extends AbstractExternalCachingDependentResource implements PerResourcePollingEventSource.ResourceSupplier { - public static final int DEFAULT_POLLING_PERIOD = 5000; protected long pollingPeriod; public PerResourcePollingExternalDependentResource() { @@ -36,4 +37,5 @@ public PerResourcePollingExternalDependentResource setPollingPeriod(long p public long getPollingPeriod() { return pollingPeriod; } + } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingExternalDependentResource.java index ff3feb47fd..b741a86708 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingExternalDependentResource.java @@ -9,12 +9,11 @@ import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.polling.PollingEventSource; -// todo configure with for polling public abstract class PollingExternalDependentResource extends AbstractExternalCachingDependentResource implements Supplier> { public static final int DEFAULT_POLLING_PERIOD = 5000; - private long pollingPeriod; + protected long pollingPeriod; public PollingExternalDependentResource() { this(DEFAULT_POLLING_PERIOD); diff --git a/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java b/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java index 8f9302a81a..ed0ff40489 100644 --- a/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java +++ b/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java @@ -83,7 +83,7 @@ boolean isLocal() { public MySQLSchemaOperatorE2E() throws FileNotFoundException {} @Test - public void test() throws IOException { + void test() throws IOException { // Opening a port-forward if running locally LocalPortForward portForward = null; if (isLocal()) { From 026e0767ff2a65773380e43a2c87f39fc67aaf9f Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 3 Mar 2022 11:05:12 +0100 Subject: [PATCH 08/17] fix: IT robustness --- .../PerResourcePollingExternalDependentResource.java | 1 - .../StandaloneDependentTestReconciler.java | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java index bb60249c2a..b803415822 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java @@ -7,7 +7,6 @@ import static io.javaoperatorsdk.operator.processing.dependent.external.PollingExternalDependentResource.DEFAULT_POLLING_PERIOD; -// todo configure with for polling public abstract class PerResourcePollingExternalDependentResource extends AbstractExternalCachingDependentResource implements PerResourcePollingEventSource.ResourceSupplier { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java index 63c72c9641..12b7f9506e 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java @@ -5,6 +5,7 @@ import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientException; import io.javaoperatorsdk.operator.ReconcilerUtils; import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.api.reconciler.dependent.Creator; @@ -66,6 +67,10 @@ public KubernetesClient getKubernetesClient() { @Override public Optional updateErrorStatus( StandaloneDependentTestCustomResource resource, RetryInfo retryInfo, RuntimeException e) { + // this can happen when a namespace is terminated in test + if (e instanceof KubernetesClientException) { + return Optional.empty(); + } errorOccurred = true; return Optional.empty(); } From 9ce5f6c34a3c21ef4762fa81deb46e272ef9f73f Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 3 Mar 2022 11:21:04 +0100 Subject: [PATCH 09/17] fix: bug in reconcile --- .../api/reconciler/dependent/AbstractDependentResource.java | 2 +- .../external/AbstractSimpleExternalDependentResource.java | 1 + .../io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java index a3bb869c26..e2db4649f6 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java @@ -111,7 +111,7 @@ private RecentOperationEventFilter getRecentOperationEventFilter() { } private boolean isRecentOperationCacheFiller() { - return this instanceof RecentOperationCacheFiller && + return this instanceof EventSourceProvider && ((EventSourceProvider

) this).getEventSource() instanceof RecentOperationCacheFiller; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java index f46f627d75..df43f8d408 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java @@ -11,6 +11,7 @@ import io.javaoperatorsdk.operator.processing.event.source.ConcurrentHashMapCache; import io.javaoperatorsdk.operator.processing.event.source.UpdatableCache; +// todo IT /** A base class for external dependent resources that don't have an event source. */ public abstract class AbstractSimpleExternalDependentResource extends AbstractDependentResource { diff --git a/sample-operators/tomcat-operator/src/test/java/io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java b/sample-operators/tomcat-operator/src/test/java/io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java index 60ef0bc187..dabcbdfa4b 100644 --- a/sample-operators/tomcat-operator/src/test/java/io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java +++ b/sample-operators/tomcat-operator/src/test/java/io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java @@ -23,7 +23,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.notNullValue; -public class TomcatOperatorE2E { +class TomcatOperatorE2E { final static Logger log = LoggerFactory.getLogger(TomcatOperatorE2E.class); @@ -80,7 +80,7 @@ Webapp getWebapp() { } @Test - public void test() { + void test() { var tomcat = getTomcat(); var webapp1 = getWebapp(); var tomcatClient = client.resources(Tomcat.class); From 9b73e8b15ae1599587be2791496eef5083418613 Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 3 Mar 2022 16:09:32 +0100 Subject: [PATCH 10/17] fix: unit test for simple resource --- .../dependent/AbstractDependentResource.java | 37 ++--- .../api/reconciler/dependent/Deleter.java | 2 +- ...stractSimpleExternalDependentResource.java | 34 ++--- .../KubernetesDependentResource.java | 4 +- .../javaoperatorsdk/operator/TestUtils.java | 4 + ...ctSimpleExternalDependentResourceTest.java | 144 ++++++++++++++++++ .../sample/simple/TestCustomResource.java | 1 + .../dependent/SchemaDependentResource.java | 2 +- 8 files changed, 188 insertions(+), 40 deletions(-) create mode 100644 operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResourceTest.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java index e2db4649f6..45b79f2c9f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java @@ -63,17 +63,18 @@ protected R handleCreate(R desired, P primary, Context context) { ResourceID resourceID = ResourceID.fromResource(primary); R created = null; try { - if (isRecentOperationEventFilter()) { - getRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(resourceID, desired); + if (isEventSourceARecentOperationEventFilter()) { + eventSourceAsRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(resourceID, + desired); } created = creator.create(desired, primary, context); - if (isRecentOperationCacheFiller()) { - getRecentOperationCacheFiller().handleRecentResourceCreate(resourceID, created); + if (isEventSourceARecentOperationCacheFiller()) { + eventSourceAsRecentOperationCacheFiller().handleRecentResourceCreate(resourceID, created); } return created; } catch (RuntimeException e) { - if (isRecentOperationEventFilter()) { - getRecentOperationEventFilter() + if (isEventSourceARecentOperationEventFilter()) { + eventSourceAsRecentOperationEventFilter() .cleanupOnCreateOrUpdateEventFiltering(resourceID, created == null ? desired : created); } throw e; @@ -84,45 +85,47 @@ protected R handleUpdate(R actual, R desired, P primary, Context context) { ResourceID resourceID = ResourceID.fromResource(primary); R updated = null; try { - if (isRecentOperationEventFilter()) { - getRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(resourceID, desired); + if (isEventSourceARecentOperationEventFilter()) { + eventSourceAsRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(resourceID, + desired); } updated = updater.update(actual, desired, primary, context); - if (isRecentOperationCacheFiller()) { - getRecentOperationCacheFiller().handleRecentResourceUpdate(resourceID, updated, actual); + if (isEventSourceARecentOperationCacheFiller()) { + eventSourceAsRecentOperationCacheFiller().handleRecentResourceUpdate(resourceID, updated, + actual); } return updated; } catch (RuntimeException e) { - if (isRecentOperationEventFilter()) { - getRecentOperationEventFilter() + if (isEventSourceARecentOperationEventFilter()) { + eventSourceAsRecentOperationEventFilter() .cleanupOnCreateOrUpdateEventFiltering(resourceID, updated == null ? desired : updated); } throw e; } } - private boolean isRecentOperationEventFilter() { + private boolean isEventSourceARecentOperationEventFilter() { return this instanceof EventSourceProvider && ((EventSourceProvider

) this).getEventSource() instanceof RecentOperationEventFilter; } - private RecentOperationEventFilter getRecentOperationEventFilter() { + private RecentOperationEventFilter eventSourceAsRecentOperationEventFilter() { return (RecentOperationEventFilter) ((EventSourceProvider

) this).getEventSource(); } - private boolean isRecentOperationCacheFiller() { + private boolean isEventSourceARecentOperationCacheFiller() { return this instanceof EventSourceProvider && ((EventSourceProvider

) this).getEventSource() instanceof RecentOperationCacheFiller; } - private RecentOperationCacheFiller getRecentOperationCacheFiller() { + private RecentOperationCacheFiller eventSourceAsRecentOperationCacheFiller() { return (RecentOperationCacheFiller) ((EventSourceProvider

) this).getEventSource(); } @Override public void delete(P primary, Context context) { if (isDeletable(primary, context)) { - deleter.delete(primary, context); + deleter.del(primary, context); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java index e612fc1c66..f4b094df18 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java @@ -9,5 +9,5 @@ public interface Deleter

{ Deleter NOOP = (primary, context) -> { }; - void delete(P primary, Context context); + void del(P primary, Context context); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java index df43f8d408..604b80e7d1 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java @@ -1,8 +1,6 @@ package io.javaoperatorsdk.operator.processing.dependent.external; import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.Context; @@ -11,24 +9,25 @@ import io.javaoperatorsdk.operator.processing.event.source.ConcurrentHashMapCache; import io.javaoperatorsdk.operator.processing.event.source.UpdatableCache; -// todo IT /** A base class for external dependent resources that don't have an event source. */ public abstract class AbstractSimpleExternalDependentResource extends AbstractDependentResource { - private final UpdatableCache cache = new ConcurrentHashMapCache<>(); - private final Set reconciling = ConcurrentHashMap.newKeySet(); + // cache serves only to keep the resource readable again until next reconciliation when the + // new resource is read again. + protected final UpdatableCache cache; + + public AbstractSimpleExternalDependentResource() { + this(new ConcurrentHashMapCache<>()); + } + + public AbstractSimpleExternalDependentResource(UpdatableCache cache) { + this.cache = cache; + } @Override public Optional getResource(HasMetadata primaryResource) { - var resourceId = ResourceID.fromResource(primaryResource); - if (reconciling.contains(ResourceID.fromResource(primaryResource))) { - var resource = supplyResource(primaryResource); - resource.ifPresent(r -> cache.put(resourceId, r)); - return resource; - } else { - return cache.get(ResourceID.fromResource(primaryResource)); - } + return cache.get(ResourceID.fromResource(primaryResource)); } /** Actually read the resource from the target API */ @@ -37,12 +36,9 @@ public Optional getResource(HasMetadata primaryResource) { @Override public void reconcile(P primary, Context context) { var resourceId = ResourceID.fromResource(primary); - try { - reconciling.add(resourceId); - super.reconcile(primary, context); - } finally { - reconciling.remove(resourceId); - } + Optional resource = supplyResource(primary); + resource.ifPresentOrElse(r -> cache.put(resourceId, r), () -> cache.remove(resourceId)); + super.reconcile(primary, context); } public void delete(P primary, Context context) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 2149c2d11c..e6b3c50ff9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -44,7 +44,7 @@ public abstract class KubernetesDependentResource) this : GenericKubernetesResourceMatcher.matcherFor(resourceType()); processor = this instanceof ResourceUpdatePreProcessor @@ -104,7 +104,7 @@ public boolean match(R actualResource, R desiredResource, Context context) { return matcher.match(actualResource, desiredResource, context); } - public void delete(P primary, Context context) { + public void del(P primary, Context context) { if (!addOwnerReference) { var resource = getResource(primary); resource.ifPresent(r -> client.resource(r).delete()); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/TestUtils.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/TestUtils.java index 137ed2d11d..e8361c49cf 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/TestUtils.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/TestUtils.java @@ -27,6 +27,10 @@ public static CustomResourceDefinition testCRD(String scope) { .build(); } + public static TestCustomResource testCustomResource1() { + return testCustomResource(new ResourceID("test1", "default")); + } + public static TestCustomResource testCustomResource(ResourceID id) { TestCustomResource resource = new TestCustomResource(); resource.setMetadata( diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResourceTest.java new file mode 100644 index 0000000000..15ffe72a2e --- /dev/null +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResourceTest.java @@ -0,0 +1,144 @@ +package io.javaoperatorsdk.operator.processing.dependent.external; + +import java.util.Optional; +import java.util.function.Supplier; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.TestUtils; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Creator; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Updater; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.SampleExternalResource; +import io.javaoperatorsdk.operator.processing.event.source.UpdatableCache; +import io.javaoperatorsdk.operator.sample.simple.TestCustomResource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + +class AbstractSimpleExternalDependentResourceTest { + + UpdatableCache updatableCacheMock = mock(UpdatableCache.class); + Supplier supplierMock = mock(Supplier.class); + + SimpleExternalDependentResource simpleDependentResource = + new SimpleExternalDependentResource(updatableCacheMock, supplierMock); + + @BeforeEach + void setup() { + when(supplierMock.get()).thenReturn(SampleExternalResource.testResource1()); + } + + @Test + void getsTheResourceFromSupplyIfReconciling() { + simpleDependentResource = new SimpleExternalDependentResource(supplierMock); + + simpleDependentResource.reconcile(TestUtils.testCustomResource1(), null); + + verify(supplierMock, times(1)).get(); + assertThat(simpleDependentResource.getResource(TestUtils.testCustomResource1())) + .isPresent() + .isEqualTo(Optional.of(SampleExternalResource.testResource1())); + } + + @Test + void getResourceReadsTheResourceFromCache() { + simpleDependentResource.getResource(TestUtils.testCustomResource1()); + + verify(supplierMock, times(0)).get(); + verify(updatableCacheMock, times(1)).get(any()); + } + + @Test + void createPutsNewResourceToTheCache() { + when(supplierMock.get()).thenReturn(null); + when(updatableCacheMock.get(any())).thenReturn(Optional.empty()); + + simpleDependentResource.reconcile(TestUtils.testCustomResource1(), null); + + verify(updatableCacheMock, times(1)).put(any(), any()); + } + + @Test + void updatePutsNewResourceToCache() { + var actual = SampleExternalResource.testResource1(); + actual.setValue("changedValue"); + when(supplierMock.get()).thenReturn(actual); + when(updatableCacheMock.get(any())).thenReturn(Optional.of(actual)); + + simpleDependentResource.reconcile(TestUtils.testCustomResource1(), null); + + verify(updatableCacheMock, times(1)) + .put(ResourceID.fromResource(TestUtils.testCustomResource1()), actual); + + verify(updatableCacheMock, times(1)) + .put( + ResourceID.fromResource(TestUtils.testCustomResource1()), + SampleExternalResource.testResource1()); + } + + @Test + void deleteRemovesResourceFromCache() { + simpleDependentResource.delete(TestUtils.testCustomResource1(), null); + verify(updatableCacheMock, times(1)).remove(any()); + } + + private class SimpleExternalDependentResource + extends AbstractSimpleExternalDependentResource + implements Creator, + Updater, + Deleter { + + private Supplier supplier; + + public SimpleExternalDependentResource(Supplier supplier) { + this.supplier = supplier; + } + + public SimpleExternalDependentResource( + UpdatableCache cache, Supplier supplier) { + super(cache); + this.supplier = supplier; + } + + @Override + public Optional supplyResource(HasMetadata primaryResource) { + return Optional.ofNullable(supplier.get()); + } + + @Override + public SampleExternalResource create( + SampleExternalResource desired, TestCustomResource primary, Context context) { + return SampleExternalResource.testResource1(); + } + + @Override + public SampleExternalResource update( + SampleExternalResource actual, + SampleExternalResource desired, + TestCustomResource primary, + Context context) { + return SampleExternalResource.testResource1(); + } + + @Override + public boolean match( + SampleExternalResource actualResource, + SampleExternalResource desiredResource, + Context context) { + return Updater.super.match(actualResource, desiredResource, context); + } + + @Override + public void del(TestCustomResource primary, Context context) {} + + @Override + protected SampleExternalResource desired(TestCustomResource primary, Context context) { + return SampleExternalResource.testResource1(); + } + } +} diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/sample/simple/TestCustomResource.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/sample/simple/TestCustomResource.java index d01bd3c747..59d9d4fb91 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/sample/simple/TestCustomResource.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/sample/simple/TestCustomResource.java @@ -18,4 +18,5 @@ protected TestCustomResourceSpec initSpec() { protected TestCustomResourceStatus initStatus() { return new TestCustomResourceStatus(); } + } diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java index 9bd0a819ec..a8a04aed0e 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java @@ -70,7 +70,7 @@ private Connection getConnection() throws SQLException { } @Override - public void delete(MySQLSchema primary, Context context) { + public void del(MySQLSchema primary, Context context) { try (Connection connection = getConnection()) { var userName = primary.getStatus() != null ? primary.getStatus().getUserName() : null; SchemaService.deleteSchemaAndRelatedUser(connection, primary.getMetadata().getName(), From ebd2b5e670ebe79e5b455513949608d10a7345ed Mon Sep 17 00:00:00 2001 From: csviri Date: Thu, 3 Mar 2022 16:37:19 +0100 Subject: [PATCH 11/17] fix: naming --- ...ava => AbstractCachingDependentResource.java} | 2 +- ...java => AbstractSimpleDependentResource.java} | 6 +++--- ... => PerResourcePollingDependentResource.java} | 12 ++++++------ ...source.java => PollingDependentResource.java} | 10 +++++----- ... => AbstractSimpleDependentResourceTest.java} | 16 ++++++++-------- .../dependent/SchemaDependentResource.java | 4 ++-- 6 files changed, 25 insertions(+), 25 deletions(-) rename operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/{AbstractExternalCachingDependentResource.java => AbstractCachingDependentResource.java} (92%) rename operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/{AbstractSimpleExternalDependentResource.java => AbstractSimpleDependentResource.java} (90%) rename operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/{PerResourcePollingExternalDependentResource.java => PerResourcePollingDependentResource.java} (68%) rename operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/{PollingExternalDependentResource.java => PollingDependentResource.java} (70%) rename operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/{AbstractSimpleExternalDependentResourceTest.java => AbstractSimpleDependentResourceTest.java} (89%) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractCachingDependentResource.java similarity index 92% rename from operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java rename to operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractCachingDependentResource.java index 64667f0506..b785b861a6 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractExternalCachingDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractCachingDependentResource.java @@ -9,7 +9,7 @@ import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource; import io.javaoperatorsdk.operator.processing.event.source.EventSource; -public abstract class AbstractExternalCachingDependentResource +public abstract class AbstractCachingDependentResource extends AbstractDependentResource implements EventSourceProvider

{ protected ExternalResourceCachingEventSource eventSource; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java similarity index 90% rename from operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java rename to operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java index 604b80e7d1..2adefc4ee8 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java @@ -10,18 +10,18 @@ import io.javaoperatorsdk.operator.processing.event.source.UpdatableCache; /** A base class for external dependent resources that don't have an event source. */ -public abstract class AbstractSimpleExternalDependentResource +public abstract class AbstractSimpleDependentResource extends AbstractDependentResource { // cache serves only to keep the resource readable again until next reconciliation when the // new resource is read again. protected final UpdatableCache cache; - public AbstractSimpleExternalDependentResource() { + public AbstractSimpleDependentResource() { this(new ConcurrentHashMapCache<>()); } - public AbstractSimpleExternalDependentResource(UpdatableCache cache) { + public AbstractSimpleDependentResource(UpdatableCache cache) { this.cache = cache; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java similarity index 68% rename from operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java rename to operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java index b803415822..cd06aa4e2e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java @@ -5,19 +5,19 @@ import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource; -import static io.javaoperatorsdk.operator.processing.dependent.external.PollingExternalDependentResource.DEFAULT_POLLING_PERIOD; +import static io.javaoperatorsdk.operator.processing.dependent.external.PollingDependentResource.DEFAULT_POLLING_PERIOD; -public abstract class PerResourcePollingExternalDependentResource - extends AbstractExternalCachingDependentResource +public abstract class PerResourcePollingDependentResource + extends AbstractCachingDependentResource implements PerResourcePollingEventSource.ResourceSupplier { protected long pollingPeriod; - public PerResourcePollingExternalDependentResource() { + public PerResourcePollingDependentResource() { this(DEFAULT_POLLING_PERIOD); } - public PerResourcePollingExternalDependentResource(long pollingPeriod) { + public PerResourcePollingDependentResource(long pollingPeriod) { this.pollingPeriod = pollingPeriod; } @@ -28,7 +28,7 @@ public EventSource initEventSource(EventSourceContext

context) { return eventSource; } - public PerResourcePollingExternalDependentResource setPollingPeriod(long pollingPeriod) { + public PerResourcePollingDependentResource setPollingPeriod(long pollingPeriod) { this.pollingPeriod = pollingPeriod; return this; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java similarity index 70% rename from operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingExternalDependentResource.java rename to operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java index b741a86708..18e0c66b60 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java @@ -9,17 +9,17 @@ import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.polling.PollingEventSource; -public abstract class PollingExternalDependentResource - extends AbstractExternalCachingDependentResource implements Supplier> { +public abstract class PollingDependentResource + extends AbstractCachingDependentResource implements Supplier> { public static final int DEFAULT_POLLING_PERIOD = 5000; protected long pollingPeriod; - public PollingExternalDependentResource() { + public PollingDependentResource() { this(DEFAULT_POLLING_PERIOD); } - public PollingExternalDependentResource(long pollingPeriod) { + public PollingDependentResource(long pollingPeriod) { this.pollingPeriod = pollingPeriod; } @@ -29,7 +29,7 @@ public EventSource initEventSource(EventSourceContext

context) { return eventSource; } - public PollingExternalDependentResource setPollingPeriod(long pollingPeriod) { + public PollingDependentResource setPollingPeriod(long pollingPeriod) { this.pollingPeriod = pollingPeriod; return this; } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java similarity index 89% rename from operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResourceTest.java rename to operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java index 15ffe72a2e..5245da67db 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleExternalDependentResourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java @@ -20,13 +20,13 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; -class AbstractSimpleExternalDependentResourceTest { +class AbstractSimpleDependentResourceTest { UpdatableCache updatableCacheMock = mock(UpdatableCache.class); Supplier supplierMock = mock(Supplier.class); - SimpleExternalDependentResource simpleDependentResource = - new SimpleExternalDependentResource(updatableCacheMock, supplierMock); + SimpleDependentResource simpleDependentResource = + new SimpleDependentResource(updatableCacheMock, supplierMock); @BeforeEach void setup() { @@ -35,7 +35,7 @@ void setup() { @Test void getsTheResourceFromSupplyIfReconciling() { - simpleDependentResource = new SimpleExternalDependentResource(supplierMock); + simpleDependentResource = new SimpleDependentResource(supplierMock); simpleDependentResource.reconcile(TestUtils.testCustomResource1(), null); @@ -87,19 +87,19 @@ void deleteRemovesResourceFromCache() { verify(updatableCacheMock, times(1)).remove(any()); } - private class SimpleExternalDependentResource - extends AbstractSimpleExternalDependentResource + private class SimpleDependentResource + extends AbstractSimpleDependentResource implements Creator, Updater, Deleter { private Supplier supplier; - public SimpleExternalDependentResource(Supplier supplier) { + public SimpleDependentResource(Supplier supplier) { this.supplier = supplier; } - public SimpleExternalDependentResource( + public SimpleDependentResource( UpdatableCache cache, Supplier supplier) { super(cache); this.supplier = supplier; diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java index a8a04aed0e..9e1e919f76 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java @@ -15,7 +15,7 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceConfigurator; import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider; -import io.javaoperatorsdk.operator.processing.dependent.external.PerResourcePollingExternalDependentResource; +import io.javaoperatorsdk.operator.processing.dependent.external.PerResourcePollingDependentResource; import io.javaoperatorsdk.operator.sample.*; import io.javaoperatorsdk.operator.sample.schema.Schema; import io.javaoperatorsdk.operator.sample.schema.SchemaService; @@ -25,7 +25,7 @@ import static java.lang.String.format; public class SchemaDependentResource - extends PerResourcePollingExternalDependentResource + extends PerResourcePollingDependentResource implements EventSourceProvider, DependentResourceConfigurator, Creator, From 706eeb072f803a9cba6228578e430630c6aa3006 Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 4 Mar 2022 10:29:09 +0100 Subject: [PATCH 12/17] fix: merge issue fixes --- .../dependent/DesiredEqualsMatcher.java | 19 +++++++++++++++++++ .../api/reconciler/dependent/Updater.java | 2 +- .../AbstractSimpleDependentResource.java | 13 +++++++++++++ .../AbstractSimpleDependentResourceTest.java | 8 -------- 4 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredEqualsMatcher.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredEqualsMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredEqualsMatcher.java new file mode 100644 index 0000000000..a64c2ea90f --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredEqualsMatcher.java @@ -0,0 +1,19 @@ +package io.javaoperatorsdk.operator.api.reconciler.dependent; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.Context; + +public class DesiredEqualsMatcher implements Matcher { + + private final AbstractDependentResource abstractDependentResource; + + public DesiredEqualsMatcher(AbstractDependentResource abstractDependentResource) { + this.abstractDependentResource = abstractDependentResource; + } + + @Override + public Result match(R actualResource, P primary, Context context) { + var desired = abstractDependentResource.desired(primary, context); + return Result.computed(actualResource.equals(desired), desired); + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Updater.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Updater.java index 339f7a3e3b..3a108ddbfb 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Updater.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Updater.java @@ -8,7 +8,7 @@ public interface Updater { Updater NOOP = new Updater() { @Override - public R update(Object actual, Object desired, HasMetadata primary, Context context) { + public Object update(Object actual, Object desired, HasMetadata primary, Context context) { return null; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java index 2adefc4ee8..55ef049191 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java @@ -5,6 +5,8 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DesiredEqualsMatcher; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Matcher; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.ConcurrentHashMapCache; import io.javaoperatorsdk.operator.processing.event.source.UpdatableCache; @@ -16,6 +18,7 @@ public abstract class AbstractSimpleDependentResource // cache serves only to keep the resource readable again until next reconciliation when the // new resource is read again. protected final UpdatableCache cache; + protected Matcher matcher; public AbstractSimpleDependentResource() { this(new ConcurrentHashMapCache<>()); @@ -23,6 +26,7 @@ public AbstractSimpleDependentResource() { public AbstractSimpleDependentResource(UpdatableCache cache) { this.cache = cache; + initMatcher(); } @Override @@ -59,4 +63,13 @@ protected R handleUpdate(R actual, R desired, P primary, Context context) { cache.put(ResourceID.fromResource(primary), res); return res; } + + public Matcher.Result match(R actualResource, P primary, Context context) { + return matcher.match(actualResource, primary, context); + } + + protected void initMatcher() { + matcher = new DesiredEqualsMatcher<>(this); + } + } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java index 5245da67db..6cce688bf1 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java @@ -125,14 +125,6 @@ public SampleExternalResource update( return SampleExternalResource.testResource1(); } - @Override - public boolean match( - SampleExternalResource actualResource, - SampleExternalResource desiredResource, - Context context) { - return Updater.super.match(actualResource, desiredResource, context); - } - @Override public void del(TestCustomResource primary, Context context) {} From af5b2e068905b5c8c24607a005c142cb952d29cb Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Fri, 4 Mar 2022 14:50:59 +0100 Subject: [PATCH 13/17] refactor: simplify --- .../dependent/AbstractDependentResource.java | 78 +++++++++++-------- .../dependent/DesiredEqualsMatcher.java | 2 +- ...CreateUpdateEventFilterTestReconciler.java | 10 +-- 3 files changed, 50 insertions(+), 40 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java index a4fb61197f..239273ee3d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java @@ -14,6 +14,8 @@ public abstract class AbstractDependentResource private final boolean creatable = this instanceof Creator; private final boolean updatable = this instanceof Updater; private final boolean deletable = this instanceof Deleter; + private final boolean filteringEventSource; + private final boolean cachingEventSource; protected Creator creator; protected Updater updater; protected Deleter

deleter; @@ -21,6 +23,14 @@ public abstract class AbstractDependentResource @SuppressWarnings("unchecked") public AbstractDependentResource() { init(Creator.NOOP, Updater.NOOP, Deleter.NOOP); + if (this instanceof EventSourceProvider) { + final var eventSource = ((EventSourceProvider

) this).getEventSource(); + filteringEventSource = eventSource instanceof RecentOperationEventFilter; + cachingEventSource = eventSource instanceof RecentOperationCacheFiller; + } else { + filteringEventSource = false; + cachingEventSource = false; + } } @SuppressWarnings({"unchecked"}) @@ -67,61 +77,63 @@ protected R handleCreate(R desired, P primary, Context context) { ResourceID resourceID = ResourceID.fromResource(primary); R created = null; try { - if (isEventSourceARecentOperationEventFilter()) { - eventSourceAsRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(resourceID, - desired); - } + prepareEventFiltering(desired, resourceID); created = creator.create(desired, primary, context); - if (isEventSourceARecentOperationCacheFiller()) { - eventSourceAsRecentOperationCacheFiller().handleRecentResourceCreate(resourceID, created); - } + cacheAfterCreate(resourceID, created); return created; } catch (RuntimeException e) { - if (isEventSourceARecentOperationEventFilter()) { - eventSourceAsRecentOperationEventFilter() - .cleanupOnCreateOrUpdateEventFiltering(resourceID, created == null ? desired : created); - } + cleanupAfterEventFiltering(desired, resourceID, created); throw e; } } + private void cleanupAfterEventFiltering(R desired, ResourceID resourceID, R created) { + if (filteringEventSource) { + eventSourceAsRecentOperationEventFilter() + .cleanupOnCreateOrUpdateEventFiltering(resourceID, created == null ? desired : created); + } + } + + private void cacheAfterCreate(ResourceID resourceID, R created) { + if (cachingEventSource) { + eventSourceAsRecentOperationCacheFiller().handleRecentResourceCreate(resourceID, created); + } + } + + private void cacheAfterUpdate(R actual, ResourceID resourceID, R updated) { + if (cachingEventSource) { + eventSourceAsRecentOperationCacheFiller().handleRecentResourceUpdate(resourceID, updated, + actual); + } + } + + private void prepareEventFiltering(R desired, ResourceID resourceID) { + if (filteringEventSource) { + eventSourceAsRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(resourceID, + desired); + } + } + protected R handleUpdate(R actual, R desired, P primary, Context context) { ResourceID resourceID = ResourceID.fromResource(primary); R updated = null; try { - if (isEventSourceARecentOperationEventFilter()) { - eventSourceAsRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(resourceID, - desired); - } + prepareEventFiltering(desired, resourceID); updated = updater.update(actual, desired, primary, context); - if (isEventSourceARecentOperationCacheFiller()) { - eventSourceAsRecentOperationCacheFiller().handleRecentResourceUpdate(resourceID, updated, - actual); - } + cacheAfterUpdate(actual, resourceID, updated); return updated; } catch (RuntimeException e) { - if (isEventSourceARecentOperationEventFilter()) { - eventSourceAsRecentOperationEventFilter() - .cleanupOnCreateOrUpdateEventFiltering(resourceID, updated == null ? desired : updated); - } + cleanupAfterEventFiltering(desired, resourceID, updated); throw e; } } - private boolean isEventSourceARecentOperationEventFilter() { - return this instanceof EventSourceProvider && - ((EventSourceProvider

) this).getEventSource() instanceof RecentOperationEventFilter; - } - + @SuppressWarnings("unchecked") private RecentOperationEventFilter eventSourceAsRecentOperationEventFilter() { return (RecentOperationEventFilter) ((EventSourceProvider

) this).getEventSource(); } - private boolean isEventSourceARecentOperationCacheFiller() { - return this instanceof EventSourceProvider && - ((EventSourceProvider

) this).getEventSource() instanceof RecentOperationCacheFiller; - } - + @SuppressWarnings("unchecked") private RecentOperationCacheFiller eventSourceAsRecentOperationCacheFiller() { return (RecentOperationCacheFiller) ((EventSourceProvider

) this).getEventSource(); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredEqualsMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredEqualsMatcher.java index a64c2ea90f..99470bf1d5 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredEqualsMatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredEqualsMatcher.java @@ -12,7 +12,7 @@ public DesiredEqualsMatcher(AbstractDependentResource abstractDependentRes } @Override - public Result match(R actualResource, P primary, Context context) { + public Result match(R actualResource, P primary, Context context) { var desired = abstractDependentResource.desired(primary, context); return Result.computed(actualResource.equals(desired), desired); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java index 551490b43e..015f7a18bd 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java @@ -41,20 +41,18 @@ public UpdateControl reconcile( .get(); if (configMap == null) { var configMapToCreate = createConfigMap(resource); + final var resourceID = ResourceID.fromResource(configMapToCreate); try { - informerEventSource.prepareForCreateOrUpdateEventFiltering( - ResourceID.fromResource(configMapToCreate), configMapToCreate); + informerEventSource.prepareForCreateOrUpdateEventFiltering(resourceID, configMapToCreate); configMap = client .configMaps() .inNamespace(resource.getMetadata().getNamespace()) .create(configMapToCreate); - informerEventSource.handleRecentResourceCreate(ResourceID.fromResource(configMapToCreate), - configMap); + informerEventSource.handleRecentResourceCreate(resourceID, configMap); } catch (RuntimeException e) { informerEventSource - .cleanupOnCreateOrUpdateEventFiltering(ResourceID.fromResource(configMapToCreate), - configMapToCreate); + .cleanupOnCreateOrUpdateEventFiltering(resourceID, configMapToCreate); throw e; } } else { From d9935683d8be90ab6850871bc2938219304e1d6f Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 4 Mar 2022 15:16:34 +0100 Subject: [PATCH 14/17] fix: remove return type oh handle methods --- .../api/reconciler/dependent/AbstractDependentResource.java | 6 ++---- .../dependent/external/AbstractSimpleDependentResource.java | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java index 239273ee3d..bb10483ff5 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java @@ -73,14 +73,13 @@ public void reconcile(P primary, Context context) { } } - protected R handleCreate(R desired, P primary, Context context) { + protected void handleCreate(R desired, P primary, Context context) { ResourceID resourceID = ResourceID.fromResource(primary); R created = null; try { prepareEventFiltering(desired, resourceID); created = creator.create(desired, primary, context); cacheAfterCreate(resourceID, created); - return created; } catch (RuntimeException e) { cleanupAfterEventFiltering(desired, resourceID, created); throw e; @@ -114,14 +113,13 @@ private void prepareEventFiltering(R desired, ResourceID resourceID) { } } - protected R handleUpdate(R actual, R desired, P primary, Context context) { + protected void handleUpdate(R actual, R desired, P primary, Context context) { ResourceID resourceID = ResourceID.fromResource(primary); R updated = null; try { prepareEventFiltering(desired, resourceID); updated = updater.update(actual, desired, primary, context); cacheAfterUpdate(actual, resourceID, updated); - return updated; } catch (RuntimeException e) { cleanupAfterEventFiltering(desired, resourceID, updated); throw e; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java index 55ef049191..ed24ab36bd 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java @@ -51,17 +51,15 @@ public void delete(P primary, Context context) { } @Override - protected R handleCreate(R desired, P primary, Context context) { + protected void handleCreate(R desired, P primary, Context context) { var res = this.creator.create(desired, primary, context); cache.put(ResourceID.fromResource(primary), res); - return res; } @Override - protected R handleUpdate(R actual, R desired, P primary, Context context) { + protected void handleUpdate(R actual, R desired, P primary, Context context) { var res = updater.update(actual, desired, primary, context); cache.put(ResourceID.fromResource(primary), res); - return res; } public Matcher.Result match(R actualResource, P primary, Context context) { From 99e8edeb45611708e96cf3bed25ca2b35638bf59 Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 4 Mar 2022 15:29:11 +0100 Subject: [PATCH 15/17] fix: PR review comments --- .../AbstractCachingDependentResource.java | 2 +- .../AbstractSimpleDependentResource.java | 4 ++-- .../PerResourcePollingDependentResource.java | 2 +- .../polling/PerResourcePollingEventSource.java | 18 +++++++++--------- .../AbstractSimpleDependentResourceTest.java | 2 +- .../PerResourcePollingEventSourceTest.java | 18 +++++++++--------- .../operator/sample/MySQLSchemaReconciler.java | 2 +- .../dependent/SchemaDependentResource.java | 2 +- ....java => SchemaPollingResourceFetcher.java} | 8 ++++---- 9 files changed, 29 insertions(+), 29 deletions(-) rename sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/{SchemaPollingResourceSupplier.java => SchemaPollingResourceFetcher.java} (69%) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractCachingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractCachingDependentResource.java index b785b861a6..86f2c23d54 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractCachingDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractCachingDependentResource.java @@ -14,7 +14,7 @@ public abstract class AbstractCachingDependentResource protected ExternalResourceCachingEventSource eventSource; - public Optional getSupplierResource(P primaryResource) { + public Optional fetchResource(P primaryResource) { return eventSource.getAssociated(primaryResource); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java index ed24ab36bd..617b47959b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java @@ -35,12 +35,12 @@ public Optional getResource(HasMetadata primaryResource) { } /** Actually read the resource from the target API */ - public abstract Optional supplyResource(HasMetadata primaryResource); + public abstract Optional fetchResource(HasMetadata primaryResource); @Override public void reconcile(P primary, Context context) { var resourceId = ResourceID.fromResource(primary); - Optional resource = supplyResource(primary); + Optional resource = fetchResource(primary); resource.ifPresentOrElse(r -> cache.put(resourceId, r), () -> cache.remove(resourceId)); super.reconcile(primary, context); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java index cd06aa4e2e..c5f9e2c888 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java @@ -9,7 +9,7 @@ public abstract class PerResourcePollingDependentResource extends AbstractCachingDependentResource - implements PerResourcePollingEventSource.ResourceSupplier { + implements PerResourcePollingEventSource.ResourceFetcher { protected long pollingPeriod; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java index 61169214f3..74cf420cd5 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java @@ -37,28 +37,28 @@ public class PerResourcePollingEventSource private final Timer timer = new Timer(); private final Map timerTasks = new ConcurrentHashMap<>(); - private final ResourceSupplier resourceSupplier; + private final ResourceFetcher resourceFetcher; private final Cache

resourceCache; private final Predicate

registerPredicate; private final long period; - public PerResourcePollingEventSource(ResourceSupplier resourceSupplier, + public PerResourcePollingEventSource(ResourceFetcher resourceFetcher, Cache

resourceCache, long period, Class resourceClass) { - this(resourceSupplier, resourceCache, period, null, resourceClass); + this(resourceFetcher, resourceCache, period, null, resourceClass); } - public PerResourcePollingEventSource(ResourceSupplier resourceSupplier, + public PerResourcePollingEventSource(ResourceFetcher resourceFetcher, Cache

resourceCache, long period, Predicate

registerPredicate, Class resourceClass) { super(resourceClass); - this.resourceSupplier = resourceSupplier; + this.resourceFetcher = resourceFetcher; this.resourceCache = resourceCache; this.period = period; this.registerPredicate = registerPredicate; } private void pollForResource(P resource) { - var value = resourceSupplier.getSupplierResource(resource); + var value = resourceFetcher.fetchResource(resource); var resourceID = ResourceID.fromResource(resource); if (value.isEmpty()) { super.handleDelete(resourceID); @@ -70,7 +70,7 @@ private void pollForResource(P resource) { private Optional getAndCacheResource(ResourceID resourceID) { var resource = resourceCache.get(resourceID); if (resource.isPresent()) { - var value = resourceSupplier.getSupplierResource(resource.get()); + var value = resourceFetcher.fetchResource(resource.get()); value.ifPresent(v -> cache.put(resourceID, v)); return value; } @@ -152,8 +152,8 @@ public Optional getValueFromCacheOrSupplier(ResourceID resourceID) { } } - public interface ResourceSupplier { - Optional getSupplierResource(P resource); + public interface ResourceFetcher { + Optional fetchResource(P primaryResource); } @Override diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java index 6cce688bf1..eb70d923fe 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java @@ -106,7 +106,7 @@ public SimpleDependentResource( } @Override - public Optional supplyResource(HasMetadata primaryResource) { + public Optional fetchResource(HasMetadata primaryResource) { return Optional.ofNullable(supplier.get()); } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSourceTest.java index a09416714a..eb8d80c0c1 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSourceTest.java @@ -27,15 +27,15 @@ class PerResourcePollingEventSourceTest extends AbstractEventSourceTestBase, EventHandler> { public static final int PERIOD = 80; - private PerResourcePollingEventSource.ResourceSupplier supplier = - mock(PerResourcePollingEventSource.ResourceSupplier.class); + private PerResourcePollingEventSource.ResourceFetcher supplier = + mock(PerResourcePollingEventSource.ResourceFetcher.class); private Cache resourceCache = mock(Cache.class); private TestCustomResource testCustomResource = TestUtils.testCustomResource(); @BeforeEach public void setup() { when(resourceCache.get(any())).thenReturn(Optional.of(testCustomResource)); - when(supplier.getSupplierResource(any())) + when(supplier.fetchResource(any())) .thenReturn(Optional.of(SampleExternalResource.testResource1())); setUpSource(new PerResourcePollingEventSource<>(supplier, resourceCache, PERIOD, @@ -47,7 +47,7 @@ public void pollsTheResourceAfterAwareOfIt() throws InterruptedException { source.onResourceCreated(testCustomResource); Thread.sleep(3 * PERIOD); - verify(supplier, atLeast(2)).getSupplierResource(eq(testCustomResource)); + verify(supplier, atLeast(2)).fetchResource(eq(testCustomResource)); verify(eventHandler, times(1)).handleEvent(any()); } @@ -59,31 +59,31 @@ public void registeringTaskOnAPredicate() throws InterruptedException { source.onResourceCreated(testCustomResource); Thread.sleep(2 * PERIOD); - verify(supplier, times(0)).getSupplierResource(eq(testCustomResource)); + verify(supplier, times(0)).fetchResource(eq(testCustomResource)); testCustomResource.getMetadata().setGeneration(2L); source.onResourceUpdated(testCustomResource, testCustomResource); Thread.sleep(2 * PERIOD); - verify(supplier, atLeast(1)).getSupplierResource(eq(testCustomResource)); + verify(supplier, atLeast(1)).fetchResource(eq(testCustomResource)); } @Test public void propagateEventOnDeletedResource() throws InterruptedException { source.onResourceCreated(testCustomResource); - when(supplier.getSupplierResource(any())) + when(supplier.fetchResource(any())) .thenReturn(Optional.of(SampleExternalResource.testResource1())) .thenReturn(Optional.empty()); Thread.sleep(3 * PERIOD); - verify(supplier, atLeast(2)).getSupplierResource(eq(testCustomResource)); + verify(supplier, atLeast(2)).fetchResource(eq(testCustomResource)); verify(eventHandler, times(2)).handleEvent(any()); } @Test public void getsValueFromCacheOrSupplier() throws InterruptedException { source.onResourceCreated(testCustomResource); - when(supplier.getSupplierResource(any())) + when(supplier.fetchResource(any())) .thenReturn(Optional.empty()) .thenReturn(Optional.of(SampleExternalResource.testResource1())); diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java index 410f5a59f5..140047a3b4 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java @@ -41,7 +41,7 @@ public UpdateControl reconcile(MySQLSchema schema, Context context) Secret secret = context.getSecondaryResource(Secret.class).orElseThrow(); SchemaDependentResource schemaDependentResource = context.managedDependentResourceContext() .getDependentResource(SchemaDependentResource.class); - return schemaDependentResource.getSupplierResource(schema).map(s -> { + return schemaDependentResource.fetchResource(schema).map(s -> { updateStatusPojo(schema, secret.getMetadata().getName(), secret.getData().get(MYSQL_SECRET_USERNAME)); log.info("Schema {} created - updating CR status", schema.getMetadata().getName()); diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java index 9e1e919f76..18d5d45040 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java @@ -81,7 +81,7 @@ public void del(MySQLSchema primary, Context context) { } @Override - public Optional getSupplierResource(MySQLSchema primaryResource) { + public Optional fetchResource(MySQLSchema primaryResource) { try (Connection connection = getConnection()) { var schema = SchemaService.getSchema(connection, primaryResource.getMetadata().getName()).orElse(null); diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaPollingResourceSupplier.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaPollingResourceFetcher.java similarity index 69% rename from sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaPollingResourceSupplier.java rename to sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaPollingResourceFetcher.java index e5e029f1a6..2830a4b08b 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaPollingResourceSupplier.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaPollingResourceFetcher.java @@ -8,17 +8,17 @@ import io.javaoperatorsdk.operator.sample.schema.Schema; import io.javaoperatorsdk.operator.sample.schema.SchemaService; -public class SchemaPollingResourceSupplier - implements PerResourcePollingEventSource.ResourceSupplier { +public class SchemaPollingResourceFetcher + implements PerResourcePollingEventSource.ResourceFetcher { private final SchemaService schemaService; - public SchemaPollingResourceSupplier(MySQLDbConfig mySQLDbConfig) { + public SchemaPollingResourceFetcher(MySQLDbConfig mySQLDbConfig) { this.schemaService = new SchemaService(mySQLDbConfig); } @Override - public Optional getSupplierResource(MySQLSchema resource) { + public Optional fetchResource(MySQLSchema resource) { return schemaService.getSchema(resource.getMetadata().getName()); } } From b5de3c0f8a0883ff010cd403a32c5abe1451470c Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Fri, 4 Mar 2022 17:09:17 +0100 Subject: [PATCH 16/17] refactor: remove need for no-op traits implementation, clean-up --- .../dependent/AbstractDependentResource.java | 14 ++++---------- .../operator/api/reconciler/dependent/Creator.java | 3 --- .../operator/api/reconciler/dependent/Deleter.java | 4 ---- .../operator/api/reconciler/dependent/Updater.java | 13 ------------- .../kubernetes/KubernetesDependentResource.java | 12 ------------ .../AbstractSimpleDependentResourceTest.java | 5 +++-- 6 files changed, 7 insertions(+), 44 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java index bb10483ff5..db9140b3bf 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java @@ -22,7 +22,6 @@ public abstract class AbstractDependentResource @SuppressWarnings("unchecked") public AbstractDependentResource() { - init(Creator.NOOP, Updater.NOOP, Deleter.NOOP); if (this instanceof EventSourceProvider) { final var eventSource = ((EventSourceProvider

) this).getEventSource(); filteringEventSource = eventSource instanceof RecentOperationEventFilter; @@ -31,14 +30,9 @@ public AbstractDependentResource() { filteringEventSource = false; cachingEventSource = false; } - } - - @SuppressWarnings({"unchecked"}) - protected void init(Creator defaultCreator, Updater defaultUpdater, - Deleter

defaultDeleter) { - creator = creatable ? (Creator) this : defaultCreator; - updater = updatable ? (Updater) this : defaultUpdater; - deleter = deletable ? (Deleter

) this : defaultDeleter; + creator = creatable ? (Creator) this : null; + updater = updatable ? (Updater) this : null; + deleter = deletable ? (Deleter

) this : null; } @Override @@ -89,7 +83,7 @@ protected void handleCreate(R desired, P primary, Context context) { private void cleanupAfterEventFiltering(R desired, ResourceID resourceID, R created) { if (filteringEventSource) { eventSourceAsRecentOperationEventFilter() - .cleanupOnCreateOrUpdateEventFiltering(resourceID, created == null ? desired : created); + .cleanupOnCreateOrUpdateEventFiltering(resourceID, created); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Creator.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Creator.java index b8a6056499..223203b2b0 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Creator.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Creator.java @@ -3,10 +3,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.Context; -@SuppressWarnings("rawtypes") @FunctionalInterface public interface Creator { - Creator NOOP = (desired, primary, context) -> null; - R create(R desired, P primary, Context context); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java index f4b094df18..5d899c767c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java @@ -3,11 +3,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.Context; -@SuppressWarnings("rawtypes") @FunctionalInterface public interface Deleter

{ - Deleter NOOP = (primary, context) -> { - }; - void del(P primary, Context context); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Updater.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Updater.java index 3a108ddbfb..25e0567781 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Updater.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Updater.java @@ -4,20 +4,7 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.dependent.Matcher.Result; -@SuppressWarnings("rawtypes") public interface Updater { - Updater NOOP = new Updater() { - @Override - public Object update(Object actual, Object desired, HasMetadata primary, Context context) { - return null; - } - - @Override - public Result match(Object actualResource, HasMetadata primary, Context context) { - return Result.nonComputed(true); - } - }; - R update(R actual, R desired, P primary, Context context); Result match(R actualResource, P primary, Context context); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index d3197222f2..4d8aa5c9e8 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -23,7 +23,6 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.Matcher; import io.javaoperatorsdk.operator.api.reconciler.dependent.Matcher.Result; import io.javaoperatorsdk.operator.api.reconciler.dependent.ResourceUpdatePreProcessor; -import io.javaoperatorsdk.operator.api.reconciler.dependent.Updater; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; import io.javaoperatorsdk.operator.processing.event.source.EventSource; @@ -46,17 +45,6 @@ public abstract class KubernetesDependentResource() { - @Override - public R update(R actual, R desired, P primary, Context context) { - return KubernetesDependentResource.this.update(actual, desired, primary, context); - } - - @Override - public Result match(R actualResource, P primary, Context context) { - return KubernetesDependentResource.this.match(actualResource, primary, context); - } - }, this::del); matcher = this instanceof Matcher ? (Matcher) this : GenericKubernetesResourceMatcher.matcherFor(resourceType(), this); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java index eb70d923fe..d6010cc277 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java @@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; +@SuppressWarnings("unchecked") class AbstractSimpleDependentResourceTest { UpdatableCache updatableCacheMock = mock(UpdatableCache.class); @@ -87,13 +88,13 @@ void deleteRemovesResourceFromCache() { verify(updatableCacheMock, times(1)).remove(any()); } - private class SimpleDependentResource + private static class SimpleDependentResource extends AbstractSimpleDependentResource implements Creator, Updater, Deleter { - private Supplier supplier; + private final Supplier supplier; public SimpleDependentResource(Supplier supplier) { this.supplier = supplier; From 3bca00580b42194bd0128ee0804d4c323ca13e73 Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 4 Mar 2022 17:21:53 +0100 Subject: [PATCH 17/17] fix: naming --- .../api/reconciler/dependent/AbstractDependentResource.java | 4 ++-- .../operator/api/reconciler/dependent/Deleter.java | 2 +- .../operator/api/reconciler/dependent/DependentResource.java | 2 +- .../processing/dependent/DependentResourceManager.java | 2 +- .../dependent/external/AbstractSimpleDependentResource.java | 4 ++-- .../dependent/kubernetes/KubernetesDependentResource.java | 2 +- .../external/AbstractSimpleDependentResourceTest.java | 4 ++-- .../operator/sample/dependent/SchemaDependentResource.java | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java index db9140b3bf..af727b66eb 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java @@ -131,9 +131,9 @@ private RecentOperationCacheFiller eventSourceAsRecentOperationCacheFiller() } @Override - public void delete(P primary, Context context) { + public void cleanup(P primary, Context context) { if (isDeletable(primary, context)) { - deleter.del(primary, context); + deleter.delete(primary, context); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java index 5d899c767c..b81ffc0380 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java @@ -5,5 +5,5 @@ @FunctionalInterface public interface Deleter

{ - void del(P primary, Context context); + void delete(P primary, Context context); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java index 09394f11b0..239ac58d0b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java @@ -8,7 +8,7 @@ public interface DependentResource { void reconcile(P primary, Context context); - default void delete(P primary, Context context) {} + default void cleanup(P primary, Context context) {} Optional getResource(P primaryResource); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java index 1d869d3b43..554f019d81 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java @@ -72,7 +72,7 @@ public UpdateControl

reconcile(P resource, Context context) { @Override public DeleteControl cleanup(P resource, Context context) { initContextIfNeeded(resource, context); - dependents.forEach(dependent -> dependent.delete(resource, context)); + dependents.forEach(dependent -> dependent.cleanup(resource, context)); return Reconciler.super.cleanup(resource, context); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java index 617b47959b..18de3390e0 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java @@ -45,8 +45,8 @@ public void reconcile(P primary, Context context) { super.reconcile(primary, context); } - public void delete(P primary, Context context) { - super.delete(primary, context); + public void cleanup(P primary, Context context) { + super.cleanup(primary, context); cache.remove(ResourceID.fromResource(primary)); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 4d8aa5c9e8..c94cec73d8 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -105,7 +105,7 @@ public Result match(R actualResource, P primary, Context context) { return matcher.match(actualResource, primary, context); } - public void del(P primary, Context context) { + public void delete(P primary, Context context) { if (!addOwnerReference) { var resource = getResource(primary); resource.ifPresent(r -> client.resource(r).delete()); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java index d6010cc277..00557e7e61 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResourceTest.java @@ -84,7 +84,7 @@ void updatePutsNewResourceToCache() { @Test void deleteRemovesResourceFromCache() { - simpleDependentResource.delete(TestUtils.testCustomResource1(), null); + simpleDependentResource.cleanup(TestUtils.testCustomResource1(), null); verify(updatableCacheMock, times(1)).remove(any()); } @@ -127,7 +127,7 @@ public SampleExternalResource update( } @Override - public void del(TestCustomResource primary, Context context) {} + public void delete(TestCustomResource primary, Context context) {} @Override protected SampleExternalResource desired(TestCustomResource primary, Context context) { diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java index 18d5d45040..f1fbc4b642 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java @@ -70,7 +70,7 @@ private Connection getConnection() throws SQLException { } @Override - public void del(MySQLSchema primary, Context context) { + public void delete(MySQLSchema primary, Context context) { try (Connection connection = getConnection()) { var userName = primary.getStatus() != null ? primary.getStatus().getUserName() : null; SchemaService.deleteSchemaAndRelatedUser(connection, primary.getMetadata().getName(),