diff --git a/micrometer-support/src/main/java/io/javaoperatorsdk/operator/monitoring/micrometer/MicrometerMetrics.java b/micrometer-support/src/main/java/io/javaoperatorsdk/operator/monitoring/micrometer/MicrometerMetrics.java index c3bbb219b7..fff9cf427f 100644 --- a/micrometer-support/src/main/java/io/javaoperatorsdk/operator/monitoring/micrometer/MicrometerMetrics.java +++ b/micrometer-support/src/main/java/io/javaoperatorsdk/operator/monitoring/micrometer/MicrometerMetrics.java @@ -1,14 +1,16 @@ package io.javaoperatorsdk.operator.monitoring.micrometer; +import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.api.monitoring.Metrics; +import io.javaoperatorsdk.operator.api.reconciler.Constants; import io.javaoperatorsdk.operator.api.reconciler.RetryInfo; +import io.javaoperatorsdk.operator.processing.GroupVersionKind; import io.javaoperatorsdk.operator.processing.event.Event; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.micrometer.core.instrument.MeterRegistry; @@ -27,9 +29,24 @@ public MicrometerMetrics(MeterRegistry registry) { public T timeControllerExecution(ControllerExecution execution) { final var name = execution.controllerName(); final var execName = PREFIX + "controllers.execution." + execution.name(); + final var resourceID = execution.resourceID(); + final var metadata = execution.metadata(); + final var tags = new ArrayList(metadata.size() + 4); + tags.addAll(List.of( + "controller", name, + "resource.name", resourceID.getName(), + "resource.namespace", resourceID.getNamespace().orElse(""), + "resource.scope", resourceID.getNamespace().isPresent() ? "namespace" : "cluster")); + final var gvk = (GroupVersionKind) metadata.get(Constants.RESOURCE_GVK_KEY); + if (gvk != null) { + tags.addAll(List.of( + "resource.group", gvk.group, + "resource.version", gvk.version, + "resource.kind", gvk.kind)); + } final var timer = Timer.builder(execName) - .tags("controller", name) + .tags(tags.toArray(new String[0])) .publishPercentiles(0.3, 0.5, 0.95) .publishPercentileHistogram() .register(registry); @@ -55,20 +72,23 @@ public T timeControllerExecution(ControllerExecution execution) { } } - public void receivedEvent(Event event) { - incrementCounter(event.getRelatedCustomResourceID(), "events.received", "event", - event.getClass().getSimpleName()); + public void receivedEvent(Event event, Map metadata) { + incrementCounter(event.getRelatedCustomResourceID(), "events.received", + metadata, + "event", event.getClass().getSimpleName()); } @Override - public void cleanupDoneFor(ResourceID resourceID) { - incrementCounter(resourceID, "events.delete"); + public void cleanupDoneFor(ResourceID resourceID, Map metadata) { + incrementCounter(resourceID, "events.delete", metadata); } @Override - public void reconcileCustomResource(ResourceID resourceID, RetryInfo retryInfoNullable) { + public void reconcileCustomResource(ResourceID resourceID, RetryInfo retryInfoNullable, + Map metadata) { Optional retryInfo = Optional.ofNullable(retryInfoNullable); incrementCounter(resourceID, RECONCILIATIONS + "started", + metadata, RECONCILIATIONS + "retries.number", "" + retryInfo.map(RetryInfo::getAttemptCount).orElse(0), RECONCILIATIONS + "retries.last", @@ -76,18 +96,19 @@ public void reconcileCustomResource(ResourceID resourceID, RetryInfo retryInfoNu } @Override - public void finishedReconciliation(ResourceID resourceID) { - incrementCounter(resourceID, RECONCILIATIONS + "success"); + public void finishedReconciliation(ResourceID resourceID, Map metadata) { + incrementCounter(resourceID, RECONCILIATIONS + "success", metadata); } - public void failedReconciliation(ResourceID resourceID, Exception exception) { + public void failedReconciliation(ResourceID resourceID, Exception exception, + Map metadata) { var cause = exception.getCause(); if (cause == null) { cause = exception; } else if (cause instanceof RuntimeException) { cause = cause.getCause() != null ? cause.getCause() : cause; } - incrementCounter(resourceID, RECONCILIATIONS + "failed", "exception", + incrementCounter(resourceID, RECONCILIATIONS + "failed", metadata, "exception", cause.getClass().getSimpleName()); } @@ -95,15 +116,26 @@ public void failedReconciliation(ResourceID resourceID, Exception exception) { return registry.gaugeMapSize(PREFIX + name + ".size", Collections.emptyList(), map); } - private void incrementCounter(ResourceID id, String counterName, String... additionalTags) { - var tags = List.of( + private void incrementCounter(ResourceID id, String counterName, Map metadata, + String... additionalTags) { + final var additionalTagsNb = + additionalTags != null && additionalTags.length > 0 ? additionalTags.length : 0; + final var metadataNb = metadata != null ? metadata.size() : 0; + final var tags = new ArrayList(6 + additionalTagsNb + metadataNb); + tags.addAll(List.of( "name", id.getName(), - "name", id.getName(), "namespace", id.getNamespace().orElse(""), - "scope", id.getNamespace().isPresent() ? "namespace" : "cluster"); - if (additionalTags != null && additionalTags.length > 0) { - tags = new LinkedList<>(tags); + "namespace", id.getNamespace().orElse(""), + "scope", id.getNamespace().isPresent() ? "namespace" : "cluster")); + if (additionalTagsNb > 0) { tags.addAll(List.of(additionalTags)); } + if (metadataNb > 0) { + final var gvk = (GroupVersionKind) metadata.get(Constants.RESOURCE_GVK_KEY); + tags.addAll(List.of( + "group", gvk.group, + "version", gvk.version, + "kind", gvk.kind)); + } registry.counter(PREFIX + counterName, tags.toArray(new String[0])).increment(); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/monitoring/Metrics.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/monitoring/Metrics.java index a1e643ac6f..be608b098e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/monitoring/Metrics.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/monitoring/Metrics.java @@ -1,39 +1,213 @@ package io.javaoperatorsdk.operator.api.monitoring; +import java.util.Collections; import java.util.Map; +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.RetryInfo; import io.javaoperatorsdk.operator.processing.event.Event; import io.javaoperatorsdk.operator.processing.event.ResourceID; +/** + * An interface that metrics providers can implement and that the SDK will call at different times + * of its execution cycle. + */ public interface Metrics { + + /** + * The default Metrics provider: a no-operation implementation. + */ Metrics NOOP = new Metrics() {}; - default void receivedEvent(Event event) {} + /** + * Called when an event has been accepted by the SDK from an event source, which would result in + * potentially triggering the associated Reconciler. + * + * @param event the event + * @param metadata metadata associated with the resource being processed + */ + default void receivedEvent(Event event, Map metadata) {} - default void reconcileCustomResource(ResourceID resourceID, RetryInfo retryInfo) {} + /** + * + * @deprecated Use (and implement) {@link #receivedEvent(Event, Map)} instead + */ + @Deprecated + default void receivedEvent(Event event) { + receivedEvent(event, Collections.emptyMap()); + } - default void failedReconciliation(ResourceID resourceID, Exception exception) {} + /** + * + * @deprecated Use (and implement) {@link #reconcileCustomResource(ResourceID, RetryInfo, Map)} + * instead + */ + @Deprecated + default void reconcileCustomResource(ResourceID resourceID, RetryInfo retryInfo) { + reconcileCustomResource(resourceID, retryInfo, Collections.emptyMap()); + } - default void cleanupDoneFor(ResourceID resourceID) {} + /** + * Called right before a resource is dispatched to the ExecutorService for reconciliation. + * + * @param resourceID the {@link ResourceID} associated with the resource + * @param retryInfo the current retry state information for the reconciliation request + * @param metadata metadata associated with the resource being processed + */ + default void reconcileCustomResource(ResourceID resourceID, RetryInfo retryInfo, + Map metadata) {} - default void finishedReconciliation(ResourceID resourceID) {} + /** + * + * @deprecated Use (and implement) {@link #failedReconciliation(ResourceID, Exception, Map)} + * instead + */ + @Deprecated + default void failedReconciliation(ResourceID resourceID, Exception exception) { + failedReconciliation(resourceID, exception, Collections.emptyMap()); + } + + /** + * Called when a precedent reconciliation for the resource associated with the specified + * {@link ResourceID} resulted in the provided exception, resulting in a retry of the + * reconciliation. + * + * @param resourceID the {@link ResourceID} associated with the resource being processed + * @param exception the exception that caused the failed reconciliation resulting in a retry + * @param metadata metadata associated with the resource being processed + */ + default void failedReconciliation(ResourceID resourceID, Exception exception, + Map metadata) {} + + /** + * + * @deprecated Use (and implement) {@link #cleanupDoneFor(ResourceID, Map)} instead + */ + @Deprecated + default void cleanupDoneFor(ResourceID resourceID) { + cleanupDoneFor(resourceID, Collections.emptyMap()); + } + /** + * Called when the resource associated with the specified {@link ResourceID} has been successfully + * deleted and the clean-up performed by the associated reconciler is finished. + * + * @param resourceID the {@link ResourceID} associated with the resource being processed + * @param metadata metadata associated with the resource being processed + */ + default void cleanupDoneFor(ResourceID resourceID, Map metadata) {} + /** + * + * @deprecated Use (and implement) {@link #finishedReconciliation(ResourceID, Map)} instead + */ + @Deprecated + default void finishedReconciliation(ResourceID resourceID) { + finishedReconciliation(resourceID, Collections.emptyMap()); + } + + /** + * Called when the + * {@link io.javaoperatorsdk.operator.api.reconciler.Reconciler#reconcile(HasMetadata, Context)} + * method of the Reconciler associated with the resource associated with the specified + * {@link ResourceID} has sucessfully finished. + * + * @param resourceID the {@link ResourceID} associated with the resource being processed + * @param metadata metadata associated with the resource being processed + */ + default void finishedReconciliation(ResourceID resourceID, Map metadata) {} + + /** + * Encapsulates the information about a controller execution i.e. a call to either + * {@link io.javaoperatorsdk.operator.api.reconciler.Reconciler#reconcile(HasMetadata, Context)} + * or {@link io.javaoperatorsdk.operator.api.reconciler.Cleaner#cleanup(HasMetadata, Context)}. + * Note that instances are automatically created for you by the SDK and passed to your Metrics + * implementation at the appropriate time to the + * {@link #timeControllerExecution(ControllerExecution)} method. + * + * @param the outcome type associated with the controller execution. Currently, one of + * {@link io.javaoperatorsdk.operator.api.reconciler.UpdateControl} or + * {@link io.javaoperatorsdk.operator.api.reconciler.DeleteControl} + */ interface ControllerExecution { + + /** + * Retrieves the name of type of reconciliation being performed: either {@code reconcile} or + * {@code cleanup}. + * + * @return the name of type of reconciliation being performed + */ String name(); + /** + * Retrieves the name of the controller executing the reconciliation. + * + * @return the associated controller name + */ String controllerName(); + /** + * Retrieves the name of the successful result when the reconciliation ended positively. + * Possible values comes from the different outcomes provided by + * {@link io.javaoperatorsdk.operator.api.reconciler.UpdateControl} or + * {@link io.javaoperatorsdk.operator.api.reconciler.DeleteControl}. + * + * @param result the reconciliation result + * @return a name associated with the specified outcome + */ String successTypeName(T result); + /** + * Retrieves the {@link ResourceID} of the resource associated with the controller execution + * being considered + * + * @return the {@link ResourceID} of the resource being reconciled + */ + ResourceID resourceID(); + + /** + * Retrieves metadata associated with the current reconciliation, typically additional + * information (such as kind) about the resource being reconciled + * + * @return metadata associated with the current reconciliation + */ + Map metadata(); + + /** + * Performs the controller execution. + * + * @return the result of the controller execution + * @throws Exception if an error occurred during the controller's execution + */ T execute() throws Exception; } + /** + * Times the execution of the controller operation encapsulated by the provided + * {@link ControllerExecution}. + * + * @param execution the controller operation to be timed + * @return the result of the controller's execution if successful + * @param the type of the outcome/result of the controller's execution + * @throws Exception if an error occurred during the controller's execution, usually this should + * just be a pass-through of whatever the controller returned + */ default T timeControllerExecution(ControllerExecution execution) throws Exception { return execution.execute(); } + /** + * Monitors the size of the specified map. This currently isn't used directly by the SDK but could + * be used by operators to monitor some of their structures, such as cache size. + * + * @param map the Map which size is to be monitored + * @param name the name of the provided Map to be used in metrics data + * @return the Map that was passed in so the registration can be done as part of an assignment + * statement. + * @param the type of the Map being monitored + */ + @SuppressWarnings("unused") default > T monitorSizeOf(T map, String name) { return map; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java index 68b88b4455..f8fa63961c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java @@ -19,5 +19,7 @@ public final class Constants { public static final long NO_RECONCILIATION_MAX_INTERVAL = -1L; public static final String SAME_AS_CONTROLLER = "JOSDK_SAME_AS_CONTROLLER"; + public static final String RESOURCE_GVK_KEY = "josdk.resource.gvk"; + private Constants() {} } 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 9891d358d4..afb37a8c53 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,6 @@ public Optional getRetryInfo() { } @Override - @SuppressWarnings("unchecked") public Set getSecondaryResources(Class expectedType) { return controller.getEventSourceManager().getEventSourcesFor(expectedType).stream() .map(es -> es.getSecondaryResources(primaryResource)) 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 acbf2f2632..66439ab8b8 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 @@ -1,5 +1,6 @@ package io.javaoperatorsdk.operator.processing; +import java.util.Map; import java.util.Optional; import java.util.Set; @@ -36,6 +37,7 @@ import io.javaoperatorsdk.operator.processing.dependent.workflow.ManagedWorkflow; import io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowCleanupResult; import io.javaoperatorsdk.operator.processing.event.EventSourceManager; +import io.javaoperatorsdk.operator.processing.event.ResourceID; import static io.javaoperatorsdk.operator.api.reconciler.Constants.WATCH_CURRENT_NAMESPACE; @@ -55,9 +57,14 @@ public class Controller

private final Metrics metrics; private final ManagedWorkflow

managedWorkflow; + private final GroupVersionKind associatedGVK; + public Controller(Reconciler

reconciler, ControllerConfiguration

configuration, KubernetesClient kubernetesClient) { + // needs to be initialized early since it's used in other downstream classes + associatedGVK = GroupVersionKind.gvkFor(configuration.getResourceClass()); + this.reconciler = reconciler; this.configuration = configuration; this.kubernetesClient = kubernetesClient; @@ -96,6 +103,16 @@ public String successTypeName(UpdateControl

result) { return successType; } + @Override + public ResourceID resourceID() { + return ResourceID.fromResource(resource); + } + + @Override + public Map metadata() { + return Map.of(Constants.RESOURCE_GVK_KEY, associatedGVK); + } + @Override public UpdateControl

execute() throws Exception { initContextIfNeeded(resource, context); @@ -130,6 +147,16 @@ public String successTypeName(DeleteControl deleteControl) { return deleteControl.isRemoveFinalizer() ? "delete" : "finalizerNotRemoved"; } + @Override + public ResourceID resourceID() { + return ResourceID.fromResource(resource); + } + + @Override + public Map metadata() { + return Map.of(Constants.RESOURCE_GVK_KEY, associatedGVK); + } + @Override public DeleteControl execute() { initContextIfNeeded(resource, context); @@ -328,4 +355,8 @@ public void stop() { public boolean useFinalizer() { return isCleaner || managedWorkflow.isCleaner(); } + + public GroupVersionKind getAssociatedGroupVersionKind() { + return associatedGVK; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/GroupVersionKind.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/GroupVersionKind.java new file mode 100644 index 0000000000..1a8a4b595d --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/GroupVersionKind.java @@ -0,0 +1,20 @@ +package io.javaoperatorsdk.operator.processing; + +import io.fabric8.kubernetes.api.model.HasMetadata; + +public class GroupVersionKind { + public final String group; + public final String version; + public final String kind; + + GroupVersionKind(String group, String version, String kind) { + this.group = group; + this.version = version; + this.kind = kind; + } + + public static GroupVersionKind gvkFor(Class resourceClass) { + return new GroupVersionKind(HasMetadata.getGroup(resourceClass), + HasMetadata.getVersion(resourceClass), HasMetadata.getKind(resourceClass)); + } +} 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 fcec37d852..226a656abc 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 @@ -1,6 +1,8 @@ package io.javaoperatorsdk.operator.processing.event; import java.time.Duration; +import java.util.Collections; +import java.util.Map; import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; @@ -14,6 +16,8 @@ import io.javaoperatorsdk.operator.api.config.ConfigurationServiceProvider; import io.javaoperatorsdk.operator.api.config.ExecutorServiceManager; import io.javaoperatorsdk.operator.api.monitoring.Metrics; +import io.javaoperatorsdk.operator.api.reconciler.Constants; +import io.javaoperatorsdk.operator.processing.Controller; import io.javaoperatorsdk.operator.processing.LifecycleAware; import io.javaoperatorsdk.operator.processing.MDCUtils; import io.javaoperatorsdk.operator.processing.event.rate.RateLimiter; @@ -40,10 +44,9 @@ class EventProcessor implements EventHandler, LifecycleAw private final Metrics metrics; private final Cache cache; private final EventSourceManager eventSourceManager; - // private final EventMarker eventMarker = new EventMarker(); private final RateLimiter rateLimiter; - private final ResourceStateManager resourceStateManager = new ResourceStateManager(); + private final Map metricsMetadata; EventProcessor(EventSourceManager eventSourceManager) { this( @@ -99,6 +102,11 @@ private EventProcessor( this.metrics = metrics != null ? metrics : Metrics.NOOP; this.eventSourceManager = eventSourceManager; this.rateLimiter = rateLimiter; + + metricsMetadata = Optional.ofNullable(eventSourceManager.getController()) + .map(Controller::getAssociatedGroupVersionKind) + .map(gvk -> Map.of(Constants.RESOURCE_GVK_KEY, (Object) gvk)) + .orElse(Collections.emptyMap()); } @Override @@ -109,7 +117,7 @@ public synchronized void handleEvent(Event event) { final var resourceID = event.getRelatedCustomResourceID(); final var state = resourceStateManager.getOrCreate(event.getRelatedCustomResourceID()); MDCUtils.addResourceIDInfo(resourceID); - metrics.receivedEvent(event); + metrics.receivedEvent(event, metricsMetadata); handleEventMarking(event, state); if (!this.running) { // events are received and marked, but will be processed when started, see start() method. @@ -133,9 +141,9 @@ private void handleMarkedEventForResource(ResourceState state) { private void submitReconciliationExecution(ResourceState state) { try { boolean controllerUnderExecution = isControllerUnderExecution(state); - Optional latest = cache.get(state.getId()); - latest.ifPresent(MDCUtils::addResourceInfo); - if (!controllerUnderExecution && latest.isPresent()) { + Optional maybeLatest = cache.get(state.getId()); + maybeLatest.ifPresent(MDCUtils::addResourceInfo); + if (!controllerUnderExecution && maybeLatest.isPresent()) { var rateLimit = state.getRateLimit(); if (rateLimit == null) { rateLimit = rateLimiter.initState(); @@ -147,10 +155,10 @@ private void submitReconciliationExecution(ResourceState state) { return; } state.setUnderProcessing(true); - final var retryInfo = state.getRetry(); - ExecutionScope executionScope = new ExecutionScope<>(latest.get(), retryInfo); + final var latest = maybeLatest.get(); + ExecutionScope executionScope = new ExecutionScope<>(latest, state.getRetry()); state.unMarkEventReceived(); - metrics.reconcileCustomResource(state.getId(), retryInfo); + metrics.reconcileCustomResource(state.getId(), state.getRetry(), metricsMetadata); log.debug("Executing events for custom resource. Scope: {}", executionScope); executor.execute(new ControllerExecution(executionScope)); } else { @@ -158,8 +166,8 @@ private void submitReconciliationExecution(ResourceState state) { "Skipping executing controller for resource id: {}. Controller in execution: {}. Latest Resource present: {}", state, controllerUnderExecution, - latest.isPresent()); - if (latest.isEmpty()) { + maybeLatest.isPresent()); + if (maybeLatest.isEmpty()) { log.debug("no custom resource found in cache for ResourceID: {}", state); } } @@ -241,7 +249,7 @@ synchronized void eventProcessingFinished( return; } cleanupOnSuccessfulExecution(executionScope); - metrics.finishedReconciliation(resourceID); + metrics.finishedReconciliation(resourceID, metricsMetadata); if (state.deleteEventPresent()) { cleanupForDeletedEvent(executionScope.getResourceID()); } else if (postExecutionControl.isFinalizerRemoved()) { @@ -308,7 +316,7 @@ private void handleRetryOnException( "Scheduling timer event for retry with delay:{} for resource: {}", delay, resourceID); - metrics.failedReconciliation(resourceID, exception); + metrics.failedReconciliation(resourceID, exception, metricsMetadata); retryEventSource().scheduleOnce(resourceID, delay); }, () -> log.error("Exhausted retries for {}", executionScope)); @@ -336,7 +344,7 @@ private ResourceState getOrInitRetryExecution(ExecutionScope executionScope) private void cleanupForDeletedEvent(ResourceID resourceID) { log.debug("Cleaning up for delete event for: {}", resourceID); resourceStateManager.remove(resourceID); - metrics.cleanupDoneFor(resourceID); + metrics.cleanupDoneFor(resourceID, metricsMetadata); } private boolean isControllerUnderExecution(ResourceState state) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ExecutionScope.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ExecutionScope.java index bd68d87a1b..e750c931c3 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ExecutionScope.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ExecutionScope.java @@ -9,7 +9,7 @@ class ExecutionScope { private final R resource; private final RetryInfo retryInfo; - public ExecutionScope(R resource, RetryInfo retryInfo) { + ExecutionScope(R resource, RetryInfo retryInfo) { this.resource = resource; this.retryInfo = retryInfo; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceStateManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceStateManager.java index 69e8126b59..4e03d1a34e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceStateManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceStateManager.java @@ -16,8 +16,8 @@ public ResourceState getOrCreate(ResourceID resourceID) { return states.computeIfAbsent(resourceID, ResourceState::new); } - public void remove(ResourceID resourceID) { - states.remove(resourceID); + public ResourceState remove(ResourceID resourceID) { + return states.remove(resourceID); } public boolean contains(ResourceID resourceID) { 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 36e286d9e9..2a97158a43 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 @@ -270,7 +270,7 @@ void startProcessedMarkedEventReceivedBefore() { eventProcessor.start(); verify(reconciliationDispatcherMock, timeout(100).times(1)).handleExecution(any()); - verify(metricsMock, times(1)).reconcileCustomResource(any(), isNull()); + verify(metricsMock, times(1)).reconcileCustomResource(any(), isNull(), any()); } @Test