diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java index e16e42f83e..c6801ff271 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java @@ -32,7 +32,7 @@ public Optional getRetryInfo() { public Optional getSecondaryResource(Class expectedType, String eventSourceName) { return controller.getEventSourceManager() .getResourceEventSourceFor(expectedType, eventSourceName) - .flatMap(es -> es.getAssociated(primaryResource)); + .flatMap(es -> es.getAssociatedResource(primaryResource)); } @Override diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java index 38f21683d8..e539e10b3a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java @@ -14,11 +14,12 @@ public interface EventSourceInitializer

{ /** - * Prepares a list of {@link EventSource} implementations to be registered by the SDK. + * Prepares a map of {@link EventSource} implementations keyed by the name with which they need to + * be registered by the SDK. * * @param context a {@link EventSourceContext} providing access to information useful to event * sources - * @return list of event sources to register + * @return a map of event sources to register */ Map prepareEventSources(EventSourceContext

context); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/UpdateControl.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/UpdateControl.java index 1762198286..eb44735a89 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/UpdateControl.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/UpdateControl.java @@ -2,7 +2,6 @@ import io.fabric8.kubernetes.api.model.HasMetadata; -@SuppressWarnings("rawtypes") public class UpdateControl extends BaseControl> { private final T resource; @@ -32,8 +31,7 @@ public static UpdateControl updateResource(T customRe return new UpdateControl<>(customResource, false, true); } - public static UpdateControl updateStatus( - T customResource) { + public static UpdateControl updateStatus(T customResource) { return new UpdateControl<>(customResource, true, false); } 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 e562f6f244..3f8b8077c5 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 @@ -1,9 +1,8 @@ package io.javaoperatorsdk.operator.api.reconciler.dependent; -import java.util.Optional; - import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.ResourceOwner; /** * An interface to implement and provide dependent resource support. @@ -11,7 +10,7 @@ * @param the dependent resource type * @param

the associated primary resource type */ -public interface DependentResource { +public interface DependentResource extends ResourceOwner { /** * Reconciles the dependent resource given the desired primary state @@ -22,25 +21,6 @@ public interface DependentResource { */ ReconcileResult reconcile(P primary, Context

context); - /** - * The intention with get resource is to return the actual state of the resource. Usually from a - * local cache, what was updated after the reconciliation, or typically from the event source that - * caches the resources. - * - * @param primaryResource the primary resource for which we want to retrieve the secondary - * resource - * @return an {@link Optional} containing the secondary resource or {@link Optional#empty()} if it - * doesn't exist - */ - Optional getResource(P primaryResource); - - /** - * Retrieves the resource type associated with this DependentResource - * - * @return the resource type associated with this DependentResource - */ - Class resourceType(); - /** * Computes a default name for the specified DependentResource class * 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 cc1514fac0..98190cb7ef 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 @@ -10,6 +10,4 @@ public interface EventSourceProvider

{ * @return the initiated event source. */ EventSource initEventSource(EventSourceContext

context); - - EventSource getEventSource(); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java index 2a96965000..2429bc03e9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java @@ -205,7 +205,7 @@ public UpdateControl

execute() throws Exception { if (!exceptions.isEmpty()) { throw new AggregatedOperatorException("One or more DependentResource(s) failed:\n" + exceptions.stream() - .map(e -> "\t\t- " + e.getMessage()) + .map(Controller.this::createExceptionInformation) .collect(Collectors.joining("\n")), exceptions); } @@ -215,6 +215,24 @@ public UpdateControl

execute() throws Exception { }); } + private String createExceptionInformation(Exception e) { + final var exceptionLocation = Optional.ofNullable(e.getCause()) + .map(Throwable::getStackTrace) + .filter(stackTrace -> stackTrace.length > 0) + .map(stackTrace -> { + int i = 0; + while (i < stackTrace.length) { + final var moduleName = stackTrace[i].getModuleName(); + if (!"java.base".equals(moduleName)) { + return " at: " + stackTrace[i].toString(); + } + i++; + } + return ""; + }); + return "\t\t- " + e.getMessage() + exceptionLocation.orElse(""); + } + public void initAndRegisterEventSources(EventSourceContext

context) { dependents.entrySet().stream() .filter(drEntry -> drEntry.getValue() instanceof EventSourceProvider) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceOwner.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceOwner.java new file mode 100644 index 0000000000..e0dfaf5694 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceOwner.java @@ -0,0 +1,26 @@ +package io.javaoperatorsdk.operator.processing; + +import java.util.Optional; + +import io.fabric8.kubernetes.api.model.HasMetadata; + +public interface ResourceOwner { + + /** + * Retrieves the resource type associated with this ResourceOwner + * + * @return the resource type associated with this ResourceOwner + */ + Class resourceType(); + + /** + * Retrieves the resource associated with the specified primary one, returning the actual state of + * the resource. Typically, this state might come from a local cache, updated after + * reconciliation. + * + * @param primary the primary resource for which we want to retrieve the secondary resource + * @return an {@link Optional} containing the secondary resource or {@link Optional#empty()} if it + * doesn't exist + */ + Optional getAssociatedResource(P primary); +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java index 8b1a634c08..c0c245db46 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java @@ -7,9 +7,6 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; -import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider; -import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationCacheFiller; -import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationEventFilter; import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult; import io.javaoperatorsdk.operator.processing.event.ResourceID; @@ -31,14 +28,12 @@ public AbstractDependentResource() { @Override public ReconcileResult reconcile(P primary, Context

context) { - var maybeActual = getResource(primary); + var maybeActual = getAssociatedResource(primary); if (creatable || updatable) { if (maybeActual.isEmpty()) { if (creatable) { var desired = desired(primary, context); - log.info("Creating {} for primary {}", desired.getClass().getSimpleName(), - ResourceID.fromResource(primary)); - log.debug("Creating dependent {} for primary {}", desired, primary); + logForOperation("Creating", primary, desired); var createdResource = handleCreate(desired, primary, context); return ReconcileResult.resourceCreated(createdResource); } @@ -48,9 +43,7 @@ public ReconcileResult reconcile(P primary, Context

context) { final var match = updater.match(actual, primary, context); if (!match.matched()) { final var desired = match.computedDesired().orElse(desired(primary, context)); - log.info("Updating {} for primary {}", desired.getClass().getSimpleName(), - ResourceID.fromResource(primary)); - log.debug("Updating dependent {} for primary {}", desired, primary); + logForOperation("Updating", primary, desired); var updatedResource = handleUpdate(actual, desired, primary, context); return ReconcileResult.resourceUpdated(updatedResource); } @@ -66,91 +59,47 @@ public ReconcileResult reconcile(P primary, Context

context) { return ReconcileResult.noOperation(maybeActual.orElse(null)); } - protected R 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; - } - } - - private void cleanupAfterEventFiltering(R desired, ResourceID resourceID, R created) { - if (isFilteringEventSource()) { - eventSourceAsRecentOperationEventFilter() - .cleanupOnCreateOrUpdateEventFiltering(resourceID, created); - } - } - - private void cacheAfterCreate(ResourceID resourceID, R created) { - if (isRecentOperationCacheFiller()) { - eventSourceAsRecentOperationCacheFiller().handleRecentResourceCreate(resourceID, created); - } + private void logForOperation(String operation, P primary, R desired) { + final var desiredDesc = desired instanceof HasMetadata + ? "'" + ((HasMetadata) desired).getMetadata().getName() + "' " + + ((HasMetadata) desired).getKind() + : desired.getClass().getSimpleName(); + log.info("{} {} for primary {}", operation, desiredDesc, ResourceID.fromResource(primary)); + log.debug("{} dependent {} for primary {}", operation, desired, primary); } - private void cacheAfterUpdate(R actual, ResourceID resourceID, R updated) { - if (isRecentOperationCacheFiller()) { - eventSourceAsRecentOperationCacheFiller().handleRecentResourceUpdate(resourceID, updated, - actual); - } + protected R handleCreate(R desired, P primary, Context

context) { + ResourceID resourceID = ResourceID.fromResource(primary); + R created = creator.create(desired, primary, context); + onCreated(resourceID, created); + return created; } - private void prepareEventFiltering(R desired, ResourceID resourceID) { - if (isFilteringEventSource()) { - eventSourceAsRecentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(resourceID, - desired); - } - } + /** + * Allows sub-classes to perform additional processing (e.g. caching) on the created resource if + * needed. + * + * @param primaryResourceId the {@link ResourceID} of the primary resource associated with the + * newly created resource + * @param created the newly created resource + */ + protected abstract void onCreated(ResourceID primaryResourceId, R created); + + /** + * Allows sub-classes to perform additional processing on the updated resource if needed. + * + * @param primaryResourceId the {@link ResourceID} of the primary resource associated with the + * newly updated resource + * @param updated the updated resource + * @param actual the resource as it was before the update + */ + protected abstract void onUpdated(ResourceID primaryResourceId, R updated, R actual); protected R 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; - } - } - - @SuppressWarnings("unchecked") - private RecentOperationEventFilter eventSourceAsRecentOperationEventFilter() { - return (RecentOperationEventFilter) ((EventSourceProvider

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

) this).getEventSource(); - } - - @SuppressWarnings("unchecked") - // this cannot be done in constructor since event source might be initialized later - protected boolean isFilteringEventSource() { - if (this instanceof EventSourceProvider) { - final var eventSource = ((EventSourceProvider

) this).getEventSource(); - return eventSource instanceof RecentOperationEventFilter; - } else { - return false; - } - } - - @SuppressWarnings("unchecked") - // this cannot be done in constructor since event source might be initialized later - protected boolean isRecentOperationCacheFiller() { - if (this instanceof EventSourceProvider) { - final var eventSource = ((EventSourceProvider

) this).getEventSource(); - return eventSource instanceof RecentOperationCacheFiller; - } else { - return false; - } + R updated = updater.update(actual, desired, primary, context); + onUpdated(resourceID, updated, actual); + return updated; } protected R desired(P primary, Context

context) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java new file mode 100644 index 0000000000..ba7f07f6a6 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java @@ -0,0 +1,122 @@ +package io.javaoperatorsdk.operator.processing.dependent; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.OperatorException; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider; +import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationCacheFiller; +import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationEventFilter; +import io.javaoperatorsdk.operator.processing.event.EventHandler; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; +import io.javaoperatorsdk.operator.processing.event.source.ResourceEventSource; + +public abstract class AbstractEventSourceHolderDependentResource> + extends AbstractDependentResource + implements ResourceEventSource, EventSourceProvider

{ + private T eventSource; + private boolean isFilteringEventSource; + private boolean isCacheFillerEventSource; + + @Override + public void start() throws OperatorException { + eventSource.start(); + } + + @Override + public void stop() throws OperatorException { + eventSource.stop(); + } + + public EventSource initEventSource(EventSourceContext

context) { + // some sub-classes (e.g. KubernetesDependentResource) can have their event source created + // before this method is called in the managed case, so only create the event source if it + // hasn't already been set + if (eventSource == null) { + eventSource = createEventSource(context); + } + + // but we still need to record which interfaces the event source implements even if it has + // already been set before this method is called + isFilteringEventSource = eventSource instanceof RecentOperationEventFilter; + isCacheFillerEventSource = eventSource instanceof RecentOperationCacheFiller; + return this; + } + + protected abstract T createEventSource(EventSourceContext

context); + + protected void setEventSource(T eventSource) { + this.eventSource = eventSource; + } + + @Override + public void setEventHandler(EventHandler handler) { + eventSource.setEventHandler(handler); + } + + protected T eventSource() { + return eventSource; + } + + protected R handleCreate(R desired, P primary, Context

context) { + ResourceID resourceID = ResourceID.fromResource(primary); + R created = null; + try { + prepareEventFiltering(desired, resourceID); + created = super.handleCreate(desired, primary, context); + return created; + } catch (RuntimeException e) { + cleanupAfterEventFiltering(desired, resourceID, created); + throw e; + } + } + + protected R handleUpdate(R actual, R desired, P primary, Context

context) { + ResourceID resourceID = ResourceID.fromResource(primary); + R updated = null; + try { + prepareEventFiltering(desired, resourceID); + updated = super.handleUpdate(actual, desired, primary, context); + return updated; + } catch (RuntimeException e) { + cleanupAfterEventFiltering(desired, resourceID, updated); + throw e; + } + } + + + protected void onCreated(ResourceID primaryResourceId, R created) { + if (isCacheFillerEventSource) { + recentOperationCacheFiller().handleRecentResourceCreate(primaryResourceId, created); + } + } + + protected void onUpdated(ResourceID primaryResourceId, R updated, R actual) { + if (isCacheFillerEventSource) { + recentOperationCacheFiller().handleRecentResourceUpdate(primaryResourceId, updated, actual); + } + } + + private void prepareEventFiltering(R desired, ResourceID resourceID) { + if (isFilteringEventSource) { + recentOperationEventFilter().prepareForCreateOrUpdateEventFiltering(resourceID, desired); + } + } + + private void cleanupAfterEventFiltering(R desired, ResourceID resourceID, R created) { + if (isFilteringEventSource) { + recentOperationEventFilter().cleanupOnCreateOrUpdateEventFiltering(resourceID, created); + } + } + + @SuppressWarnings("unchecked") + private RecentOperationEventFilter recentOperationEventFilter() { + return (RecentOperationEventFilter) eventSource; + } + + @SuppressWarnings("unchecked") + private RecentOperationCacheFiller recentOperationCacheFiller() { + return (RecentOperationCacheFiller) eventSource; + } +} 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 b131850b1e..7350c2d741 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 @@ -3,16 +3,12 @@ import java.util.Optional; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider; -import io.javaoperatorsdk.operator.processing.dependent.AbstractDependentResource; +import io.javaoperatorsdk.operator.processing.dependent.AbstractEventSourceHolderDependentResource; import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource; -import io.javaoperatorsdk.operator.processing.event.source.EventSource; public abstract class AbstractCachingDependentResource - extends AbstractDependentResource - implements EventSourceProvider

{ - - protected ExternalResourceCachingEventSource eventSource; + extends + AbstractEventSourceHolderDependentResource> { private final Class resourceType; protected AbstractCachingDependentResource(Class resourceType) { @@ -20,12 +16,7 @@ protected AbstractCachingDependentResource(Class resourceType) { } public Optional fetchResource(P primaryResource) { - return eventSource.getAssociated(primaryResource); - } - - @Override - public EventSource getEventSource() { - return eventSource; + return eventSource().getAssociatedResource(primaryResource); } @Override @@ -34,7 +25,7 @@ public Class resourceType() { } @Override - public Optional getResource(P primaryResource) { - return eventSource.getAssociated(primaryResource); + public Optional getAssociatedResource(P primaryResource) { + return eventSource().getAssociatedResource(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 2b91e6d75f..9b1d008077 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 @@ -31,7 +31,7 @@ public AbstractSimpleDependentResource(UpdatableCache cache) { } @Override - public Optional getResource(HasMetadata primaryResource) { + public Optional getAssociatedResource(HasMetadata primaryResource) { return cache.get(ResourceID.fromResource(primaryResource)); } @@ -59,17 +59,13 @@ public final void delete(P primary, Context

context) { protected abstract void deleteResource(P primary, Context

context); @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; + protected void onCreated(ResourceID primaryResourceId, R created) { + cache.put(primaryResourceId, created); } @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; + protected void onUpdated(ResourceID primaryResourceId, R updated, R actual) { + cache.put(primaryResourceId, updated); } public Matcher.Result match(R actualResource, P primary, Context

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 11b18832a7..b598073a21 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 @@ -2,7 +2,7 @@ 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.ExternalResourceCachingEventSource; import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource; public abstract class PerResourcePollingDependentResource @@ -17,9 +17,9 @@ public PerResourcePollingDependentResource(Class resourceType, long pollingPe } @Override - public EventSource initEventSource(EventSourceContext

context) { - eventSource = new PerResourcePollingEventSource<>(this, context.getPrimaryCache(), + protected ExternalResourceCachingEventSource createEventSource( + EventSourceContext

context) { + return new PerResourcePollingEventSource<>(this, context.getPrimaryCache(), getPollingPeriod(), resourceType()); - return eventSource; } } 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 index 58723a6f11..1cc6e22afe 100644 --- 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 @@ -5,8 +5,8 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource; import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.polling.PollingEventSource; public abstract class PollingDependentResource @@ -21,8 +21,8 @@ public PollingDependentResource(Class resourceType, long pollingPeriod) { } @Override - public EventSource initEventSource(EventSourceContext

context) { - eventSource = new PollingEventSource<>(this, getPollingPeriod(), resourceType()); - return eventSource; + protected ExternalResourceCachingEventSource createEventSource( + EventSourceContext

context) { + return new PollingEventSource<>(this, getPollingPeriod(), resourceType()); } } 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 f77ec0b4aa..0c8153a959 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 @@ -14,28 +14,25 @@ import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider; import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.DependentResourceConfigurator; import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.KubernetesClientAware; -import io.javaoperatorsdk.operator.processing.dependent.AbstractDependentResource; +import io.javaoperatorsdk.operator.processing.dependent.AbstractEventSourceHolderDependentResource; import io.javaoperatorsdk.operator.processing.dependent.Matcher; import io.javaoperatorsdk.operator.processing.dependent.Matcher.Result; import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper; import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; public abstract class KubernetesDependentResource - extends AbstractDependentResource - implements KubernetesClientAware, EventSourceProvider

, + extends AbstractEventSourceHolderDependentResource> + implements KubernetesClientAware, DependentResourceConfigurator { private static final Logger log = LoggerFactory.getLogger(KubernetesDependentResource.class); protected KubernetesClient client; - private InformerEventSource informerEventSource; private final Matcher matcher; private final ResourceUpdatePreProcessor processor; private final Class resourceType; @@ -80,12 +77,11 @@ private void configureWith(String labelSelector, Set namespaces) { * * @param informerEventSource informer to use* */ - public void configureWith( - InformerEventSource informerEventSource) { - this.informerEventSource = informerEventSource; - + public void configureWith(InformerEventSource informerEventSource) { + setEventSource(informerEventSource); } + @SuppressWarnings("unused") public R create(R target, P primary, Context

context) { return prepare(target, primary, "Creating").create(target); } @@ -101,7 +97,7 @@ public Result match(R actualResource, P primary, Context

context) { public void delete(P primary, Context

context) { if (!addOwnerReference()) { - var resource = getResource(primary); + var resource = getAssociatedResource(primary); resource.ifPresent(r -> client.resource(r).delete()); } } @@ -121,19 +117,11 @@ protected NonNamespaceOperation, Resource> prepa } @Override - public EventSource initEventSource(EventSourceContext

context) { - if (informerEventSource == null) { - configureWith(null, context.getControllerConfiguration().getNamespaces()); - log.warn("Using default configuration for " + resourceType().getSimpleName() - + " KubernetesDependentResource, call configureWith to provide configuration"); - } - return informerEventSource; - } - - public KubernetesDependentResource setInformerEventSource( - InformerEventSource informerEventSource) { - this.informerEventSource = informerEventSource; - return this; + protected InformerEventSource createEventSource(EventSourceContext

context) { + configureWith(null, context.getControllerConfiguration().getNamespaces()); + log.warn("Using default configuration for " + resourceType().getSimpleName() + + " KubernetesDependentResource, call configureWith to provide configuration"); + return eventSource(); } protected boolean addOwnerReference() { @@ -146,8 +134,8 @@ public Class resourceType() { } @Override - public Optional getResource(P primaryResource) { - return informerEventSource.getAssociated(primaryResource); + public Optional getAssociatedResource(P primaryResource) { + return eventSource().getAssociatedResource(primaryResource); } @Override @@ -164,9 +152,4 @@ public KubernetesClient getKubernetesClient() { protected R desired(P primary, Context

context) { return super.desired(primary, context); } - - @Override - public EventSource getEventSource() { - return informerEventSource; - } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java index 86fb203f97..64d0039136 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java @@ -86,7 +86,7 @@ private void logEventSourceEvent(NamedEventSource eventSource, String event) { if (eventSource instanceof ResourceEventSource) { ResourceEventSource source = (ResourceEventSource) eventSource; log.debug("{} event source {} for {}", event, eventSource.name(), - source.getResourceClass()); + source.resourceType()); } else { log.debug("{} event source {}", event, eventSource.name()); } @@ -171,12 +171,12 @@ public ControllerResourceEventSource getControllerResourceEventSource() { return eventSources.controllerResourceEventSource(); } - public Optional> getResourceEventSourceFor( + public Optional> getResourceEventSourceFor( Class dependentType) { return getResourceEventSourceFor(dependentType, null); } - public Optional> getResourceEventSourceFor( + public Optional> getResourceEventSourceFor( Class dependentType, String qualifier) { if (dependentType == null) { return Optional.empty(); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSources.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSources.java index b890cd5d52..2b802a988b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSources.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSources.java @@ -9,6 +9,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.processing.Controller; +import io.javaoperatorsdk.operator.processing.ResourceOwner; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.ResourceEventSource; import io.javaoperatorsdk.operator.processing.event.source.controller.ControllerResourceEventSource; @@ -68,8 +69,8 @@ public void add(String name, EventSource eventSource) { @SuppressWarnings("rawtypes") private Class getDependentType(EventSource source) { - return source instanceof ResourceEventSource - ? ((ResourceEventSource) source).getResourceClass() + return source instanceof ResourceOwner + ? ((ResourceOwner) source).resourceType() : source.getClass(); } @@ -84,7 +85,7 @@ private String keyFor(Class dependentType) { // this is needed so that these sources are set when informer sources start so that events can // properly be processed if (controllerResourceEventSource != null - && key.equals(controllerResourceEventSource.getResourceClass().getCanonicalName())) { + && key.equals(controllerResourceEventSource.resourceType().getCanonicalName())) { key = 1 + "-" + key; } else if (key.equals(retryAndRescheduleTimerEventSource.getClass().getCanonicalName())) { key = 0 + "-" + key; @@ -93,7 +94,7 @@ private String keyFor(Class dependentType) { } @SuppressWarnings("unchecked") - public ResourceEventSource get(Class dependentType, String name) { + public ResourceEventSource get(Class dependentType, String name) { final var sourcesForType = sources.get(keyFor(dependentType)); if (sourcesForType == null || sourcesForType.isEmpty()) { return null; @@ -122,8 +123,8 @@ public ResourceEventSource get(Class dependentType, String name) { + keyAsString(dependentType, name) + " is not a " + ResourceEventSource.class.getSimpleName()); } - final var res = (ResourceEventSource) source; - final var resourceClass = res.getResourceClass(); + final var res = (ResourceEventSource) source; + final var resourceClass = res.resourceType(); if (!resourceClass.isAssignableFrom(dependentType)) { throw new IllegalArgumentException(source + " associated with " + keyAsString(dependentType, name) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/AbstractResourceEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/AbstractResourceEventSource.java index de3340eff5..b22899f246 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/AbstractResourceEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/AbstractResourceEventSource.java @@ -4,7 +4,7 @@ public abstract class AbstractResourceEventSource

extends AbstractEventSource - implements ResourceEventSource { + implements ResourceEventSource { private final Class resourceClass; protected AbstractResourceEventSource(Class resourceClass) { @@ -12,7 +12,7 @@ protected AbstractResourceEventSource(Class resourceClass) { } @Override - public Class getResourceClass() { + public Class resourceType() { return resourceClass; } } 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 57d94d8922..5b3926e20c 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 @@ -54,7 +54,7 @@ public Optional getCachedValue(ResourceID resourceID) { } @Override - public Optional getAssociated(P primary) { + public Optional getAssociatedResource(P primary) { return cache.get(ResourceID.fromResource(primary)); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ResourceEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ResourceEventSource.java index ccc907bb0c..d65208f746 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ResourceEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ResourceEventSource.java @@ -1,12 +1,9 @@ package io.javaoperatorsdk.operator.processing.event.source; -import java.util.Optional; - import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.processing.ResourceOwner; -public interface ResourceEventSource

extends EventSource { - - Class getResourceClass(); +public interface ResourceEventSource extends EventSource, + ResourceOwner { - Optional getAssociated(P primary); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java index fe9d802630..67a59e48d3 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java @@ -29,6 +29,7 @@ public class ControllerResourceEventSource private final Controller controller; private final ResourceEventFilter filter; + @SuppressWarnings("unchecked") public ControllerResourceEventSource(Controller controller) { super(controller.getCRClient(), controller.getConfiguration()); this.controller = controller; @@ -101,7 +102,7 @@ private void handleKubernetesClientException(Exception e) { } @Override - public Optional getAssociated(T primary) { + public Optional getAssociatedResource(T primary) { return get(ResourceID.fromResource(primary)); } } 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 f5163c9973..4650637f3b 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 @@ -152,7 +152,7 @@ private void propagateEvent(R object) { * @return the informed resource associated with the specified primary resource */ @Override - public Optional getAssociated(P resource) { + public Optional getAssociatedResource(P resource) { final var id = configuration.getAssociatedResourceIdentifier().associatedSecondaryID(resource); return get(id); } @@ -165,8 +165,7 @@ public InformerConfiguration getConfiguration() { public synchronized void handleRecentResourceUpdate(ResourceID resourceID, R resource, R previousResourceVersion) { handleRecentCreateOrUpdate(resource, - () -> super.handleRecentResourceUpdate(resourceID, resource, - previousResourceVersion)); + () -> super.handleRecentResourceUpdate(resourceID, resource, previousResourceVersion)); } @Override 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 063207b0e7..f5f181ecf0 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 @@ -93,7 +93,7 @@ public Optional get(ResourceID resourceID) { } @Override - public Optional getAssociated(P primary) { + public Optional getAssociatedResource(P primary) { return get(ResourceID.fromResource(primary)); } @@ -119,9 +119,7 @@ public Stream list(String namespace, Predicate predicate) { return manager().list(namespace, predicate); } - ManagedInformerEventSource setTemporalResourceCache( - TemporaryResourceCache temporaryResourceCache) { + void setTemporalResourceCache(TemporaryResourceCache temporaryResourceCache) { this.temporaryResourceCache = temporaryResourceCache; - 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 74cf420cd5..1827324c3e 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 @@ -132,7 +132,7 @@ public void run() { * @return the related resource for this event source */ @Override - public Optional getAssociated(P primary) { + public Optional getAssociatedResource(P primary) { return getValueFromCacheOrSupplier(ResourceID.fromResource(primary)); } 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 8a09b71658..6d9a5a3f2f 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 @@ -1,6 +1,9 @@ package io.javaoperatorsdk.operator.processing.event.source.polling; -import java.util.*; +import java.util.Map; +import java.util.Optional; +import java.util.Timer; +import java.util.TimerTask; import java.util.function.Supplier; import org.slf4j.Logger; @@ -95,7 +98,7 @@ public void stop() throws OperatorException { * @return related resource */ @Override - public Optional getAssociated(P primary) { + public Optional getAssociatedResource(P primary) { return getCachedValue(ResourceID.fromResource(primary)); } } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/UtilsTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/UtilsTest.java index f762b7d2c3..de1c7e4cc1 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/UtilsTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/UtilsTest.java @@ -98,7 +98,7 @@ public ReconcileResult reconcile(TestCustomResource primary, } @Override - public Optional getResource(TestCustomResource primaryResource) { + public Optional getAssociatedResource(TestCustomResource primaryResource) { return Optional.empty(); } 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 53bbd05464..2594a935b7 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 @@ -45,14 +45,14 @@ void getsTheResourceFromSupplyIfReconciling() { simpleDependentResource.reconcile(TestUtils.testCustomResource1(), null); verify(supplierMock, times(1)).get(); - assertThat(simpleDependentResource.getResource(TestUtils.testCustomResource1())) + assertThat(simpleDependentResource.getAssociatedResource(TestUtils.testCustomResource1())) .isPresent() .isEqualTo(Optional.of(SampleExternalResource.testResource1())); } @Test void getResourceReadsTheResourceFromCache() { - simpleDependentResource.getResource(TestUtils.testCustomResource1()); + simpleDependentResource.getAssociatedResource(TestUtils.testCustomResource1()); verify(supplierMock, times(0)).get(); verify(updatableCacheMock, times(1)).get(any()); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventSourceManagerTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventSourceManagerTest.java index 3ba1258d3e..d1935a3eed 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventSourceManagerTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventSourceManagerTest.java @@ -86,7 +86,7 @@ void retrievingEventSourceForClassShouldWork() { assertTrue(source.get() instanceof ControllerResourceEventSource); CachingEventSource eventSource = mock(CachingEventSource.class); - when(eventSource.getResourceClass()).thenReturn(String.class); + when(eventSource.resourceType()).thenReturn(String.class); manager.registerEventSource(eventSource); source = manager.getResourceEventSourceFor(String.class); @@ -100,11 +100,11 @@ void shouldNotBePossibleToAddEventSourcesForSameTypeAndName() { final var name = "name1"; CachingEventSource eventSource = mock(CachingEventSource.class); - when(eventSource.getResourceClass()).thenReturn(TestCustomResource.class); + when(eventSource.resourceType()).thenReturn(TestCustomResource.class); manager.registerEventSource(name, eventSource); eventSource = mock(CachingEventSource.class); - when(eventSource.getResourceClass()).thenReturn(TestCustomResource.class); + when(eventSource.resourceType()).thenReturn(TestCustomResource.class); final var source = eventSource; final var exception = assertThrows(OperatorException.class, @@ -121,11 +121,11 @@ void retrievingAnEventSourceWhenMultipleAreRegisteredForATypeShouldRequireAQuali EventSourceManager manager = initManager(); CachingEventSource eventSource = mock(CachingEventSource.class); - when(eventSource.getResourceClass()).thenReturn(TestCustomResource.class); + when(eventSource.resourceType()).thenReturn(TestCustomResource.class); manager.registerEventSource("name1", eventSource); CachingEventSource eventSource2 = mock(CachingEventSource.class); - when(eventSource2.getResourceClass()).thenReturn(TestCustomResource.class); + when(eventSource2.resourceType()).thenReturn(TestCustomResource.class); manager.registerEventSource("name2", eventSource2); final var exception = assertThrows(IllegalArgumentException.class, @@ -144,7 +144,7 @@ void timerAndControllerEventSourcesShouldBeListedFirst() { EventSourceManager manager = initManager(); CachingEventSource eventSource = mock(CachingEventSource.class); - when(eventSource.getResourceClass()).thenReturn(String.class); + when(eventSource.resourceType()).thenReturn(String.class); manager.registerEventSource(eventSource); final Set sources = manager.getRegisteredEventSources(); 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 0751c38d0a..8519f5fa7b 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 @@ -47,7 +47,7 @@ public UpdateControl reconcile( StandaloneDependentTestCustomResource primary, Context context) { deploymentDependent.reconcile(primary, context); - Optional deployment = deploymentDependent.getResource(primary); + Optional deployment = deploymentDependent.getAssociatedResource(primary); if (deployment.isEmpty()) { throw new IllegalStateException("Resource should not be empty after reconcile."); } diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java index 7ee78deed7..673e5154f9 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java @@ -48,8 +48,8 @@ protected Secret desired(MySQLSchema schema, Context context) { .build(); } - private String getSecretName(String name) { - return String.format(SECRET_FORMAT, name); + private String getSecretName(String schemaName) { + return String.format(SECRET_FORMAT, schemaName); } @Override @@ -61,7 +61,6 @@ public Result match(Secret actual, MySQLSchema primary, Context configMapDR; - private KubernetesDependentResource deploymentDR; - private KubernetesDependentResource serviceDR; + private final Map> dependentResources; public WebPageStandaloneDependentsReconciler(KubernetesClient kubernetesClient) { - createDependentResources(kubernetesClient); + dependentResources = Map.of( + "configmap", new ConfigMapDependentResource(), + "deployment", new DeploymentDependentResource(), + "service", new ServiceDependentResource()); + final var config = new KubernetesDependentResourceConfig() + .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR); + dependentResources.values().forEach(dr -> { + dr.setKubernetesClient(kubernetesClient); + dr.configureWith(config); + }); } @Override public Map prepareEventSources(EventSourceContext context) { - return Map.of( - "configmap", configMapDR.initEventSource(context), - "deployment", deploymentDR.initEventSource(context), - "service", serviceDR.initEventSource(context)); + return dependentResources.entrySet().stream() + .collect(Collectors.toUnmodifiableMap(Entry::getKey, Entry::getValue)); } @Override @@ -58,35 +63,24 @@ public UpdateControl reconcile(WebPage webPage, Context contex throws Exception { simulateErrorIfRequested(webPage); - configMapDR.reconcile(webPage, context); - deploymentDR.reconcile(webPage, context); - serviceDR.reconcile(webPage, context); + dependentResources.values().forEach(dr -> dr.reconcile(webPage, context)); - webPage.setStatus( - createStatus(configMapDR.getResource(webPage).orElseThrow().getMetadata().getName())); + webPage.setStatus(createStatus(getConfigMapName(webPage))); return UpdateControl.updateStatus(webPage); } + private String getConfigMapName(WebPage webPage) { + return dependent("configmap").getAssociatedResource(webPage).orElseThrow().getMetadata() + .getName(); + } + @Override public ErrorStatusUpdateControl updateErrorStatus( WebPage resource, Context retryInfo, Exception e) { return handleError(resource, e); } - private void createDependentResources(KubernetesClient client) { - this.configMapDR = new ConfigMapDependentResource(); - this.configMapDR.setKubernetesClient(client); - configMapDR.configureWith(new KubernetesDependentResourceConfig() - .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR)); - - this.deploymentDR = new DeploymentDependentResource(); - deploymentDR.setKubernetesClient(client); - deploymentDR.configureWith(new KubernetesDependentResourceConfig() - .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR)); - - this.serviceDR = new ServiceDependentResource(); - serviceDR.setKubernetesClient(client); - serviceDR.configureWith(new KubernetesDependentResourceConfig() - .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR)); + private KubernetesDependentResource dependent(String name) { + return dependentResources.get(name); } }