diff --git a/docsy/content/en/docs/migration/v5-0-migration.md b/docsy/content/en/docs/migration/v5-0-migration.md index c766d5c770..fdf624e29c 100644 --- a/docsy/content/en/docs/migration/v5-0-migration.md +++ b/docsy/content/en/docs/migration/v5-0-migration.md @@ -60,4 +60,5 @@ description: Migrating from v4.7 to v5.0 This also means, that `BulkDependentResource` now does not automatically implement `Creator` and `Deleter` as before. Make sure to implement those interfaces in your bulk dependent resources. You can use also the new helper interface, the [`CRUDBulkDependentResource`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/CRUDBulkDependentResource.java) - what also implement `BulkUpdater` interface. \ No newline at end of file + what also implement `BulkUpdater` interface. +12. `ErrorStatusHandler` is deleted. Just delete the interface from your impl. \ No newline at end of file diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusHandler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusHandler.java deleted file mode 100644 index c7bd09a930..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.javaoperatorsdk.operator.api.reconciler; - -import io.fabric8.kubernetes.api.model.HasMetadata; - -public interface ErrorStatusHandler
{ - - /** - *
- * Reconciler can implement this interface in order to update the status sub-resource in the case - * an exception in thrown. In that case - * {@link #updateErrorStatus(HasMetadata, Context, Exception)} is called automatically. - *
- * The result of the method call is used to make a status update on the custom resource. This is - * always a sub-resource update request, so no update on custom resource itself (like spec of - * metadata) happens. Note that this update request will also produce an event, and will result in - * a reconciliation if the controller is not generation aware. - *
- * Note that the scope of this feature is only the reconcile method of the reconciler, since there - * should not be updates on custom resource after it is marked for deletion. - * - * @param resource to update the status on - * @param context the current context - * @param e exception thrown from the reconciler - * @return the updated resource - */ - ErrorStatusUpdateControl
updateErrorStatus(P resource, Context
context, Exception e); - -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusUpdateControl.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusUpdateControl.java index 7236d5898b..e9073d613c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusUpdateControl.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusUpdateControl.java @@ -10,6 +10,7 @@ public class ErrorStatusUpdateControl
private final P resource;
private boolean noRetry = false;
+ private final boolean defaultErrorProcessing;
public static withNoRetry() {
+ if (defaultErrorProcessing) {
+ throw new IllegalStateException("Cannot set no-retry for default error processing");
+ }
this.noRetry = true;
return this;
}
@@ -41,6 +58,10 @@ public boolean isNoRetry() {
return noRetry;
}
+ public boolean isDefaultErrorProcessing() {
+ return defaultErrorProcessing;
+ }
+
/**
* If re-scheduled using this method, it is not considered as retry, it effectively cancels retry.
*
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Reconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Reconciler.java
index 40a8a3b407..f271652686 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Reconciler.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Reconciler.java
@@ -31,4 +31,28 @@ default List context) {
return Collections.emptyList();
}
+ /**
+ *
+ * Reconciler can override this method in order to update the status sub-resource in the case an
+ * exception in thrown. In that case {@link #updateErrorStatus(HasMetadata, Context, Exception)}
+ * is called automatically.
+ *
+ * The result of the method call is used to make a status update on the custom resource. This is
+ * always a sub-resource update request, so no update on custom resource itself (like spec of
+ * metadata) happens. Note that this update request will also produce an event, and will result in
+ * a reconciliation if the controller is not generation aware.
+ *
+ * Note that the scope of this feature is only the reconcile method of the reconciler, since there
+ * should not be updates on custom resource after it is marked for deletion.
+ *
+ * @param resource to update the status on
+ * @param context the current context
+ * @param e exception thrown from the reconciler
+ * @return the updated resource
+ */
+ default ErrorStatusUpdateControl updateErrorStatus(P resource, Context context,
+ Exception e) {
+ return ErrorStatusUpdateControl.defaultErrorProcessing();
+ }
+
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java
index 2b33133ae4..1ad3b65910 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java
@@ -22,7 +22,6 @@
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.DefaultContext;
import io.javaoperatorsdk.operator.api.reconciler.DeleteControl;
-import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler;
import io.javaoperatorsdk.operator.api.reconciler.RetryInfo;
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
import io.javaoperatorsdk.operator.processing.Controller;
@@ -174,55 +173,46 @@ private PostExecutionControl reconcileExecution(ExecutionScope executionSc
private PostExecutionControl handleErrorStatusHandler(P resource, P originalResource,
Context context,
Exception e) throws Exception {
- if (isErrorStatusHandlerPresent()) {
- try {
- RetryInfo retryInfo = context.getRetryInfo().orElseGet(() -> new RetryInfo() {
- @Override
- public int getAttemptCount() {
- return 0;
- }
- @Override
- public boolean isLastAttempt() {
- // check also if the retry is limited to 0
- return retryConfigurationHasZeroAttempts ||
- controller.getConfiguration().getRetry() == null;
- }
- });
- ((DefaultContext ) context).setRetryInfo(retryInfo);
- var errorStatusUpdateControl = ((ErrorStatusHandler ) controller.getReconciler())
- .updateErrorStatus(resource, context, e);
-
- P updatedResource = null;
- if (errorStatusUpdateControl.getResource().isPresent()) {
- updatedResource = customResourceFacade
- .patchStatus(errorStatusUpdateControl.getResource().orElseThrow(), originalResource);
- }
- if (errorStatusUpdateControl.isNoRetry()) {
- PostExecutionControl postExecutionControl;
- if (updatedResource != null) {
- postExecutionControl =
- PostExecutionControl.customResourceStatusPatched(updatedResource);
- } else {
- postExecutionControl = PostExecutionControl.defaultDispatch();
- }
- errorStatusUpdateControl.getScheduleDelay()
- .ifPresent(postExecutionControl::withReSchedule);
- return postExecutionControl;
- }
- } catch (RuntimeException ex) {
- log.error("Error during error status handling.", ex);
+ RetryInfo retryInfo = context.getRetryInfo().orElseGet(() -> new RetryInfo() {
+ @Override
+ public int getAttemptCount() {
+ return 0;
}
- }
- throw e;
- }
- private boolean isErrorStatusHandlerPresent() {
- return controller.getReconciler() instanceof ErrorStatusHandler;
- }
+ @Override
+ public boolean isLastAttempt() {
+ // check also if the retry is limited to 0
+ return retryConfigurationHasZeroAttempts ||
+ controller.getConfiguration().getRetry() == null;
+ }
+ });
+ ((DefaultContext ) context).setRetryInfo(retryInfo);
+ var errorStatusUpdateControl = controller.getReconciler()
+ .updateErrorStatus(resource, context, e);
- private P patchStatusGenerationAware(P resource, P originalResource) {
- return customResourceFacade.patchStatus(resource, originalResource);
+ if (errorStatusUpdateControl.isDefaultErrorProcessing()) {
+ throw e;
+ }
+
+ P updatedResource = null;
+ if (errorStatusUpdateControl.getResource().isPresent()) {
+ updatedResource = customResourceFacade
+ .patchStatus(errorStatusUpdateControl.getResource().orElseThrow(), originalResource);
+ }
+ if (errorStatusUpdateControl.isNoRetry()) {
+ PostExecutionControl postExecutionControl;
+ if (updatedResource != null) {
+ postExecutionControl =
+ PostExecutionControl.customResourceStatusPatched(updatedResource);
+ } else {
+ postExecutionControl = PostExecutionControl.defaultDispatch();
+ }
+ errorStatusUpdateControl.getScheduleDelay()
+ .ifPresent(postExecutionControl::withReSchedule);
+ return postExecutionControl;
+ }
+ throw e;
}
private PostExecutionControl createPostExecutionControl(P updatedCustomResource,
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java
index 7e80f4aedc..efec8c4228 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java
@@ -5,11 +5,11 @@
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
+import java.util.function.Supplier;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
import org.mockito.ArgumentMatchers;
import org.mockito.stubbing.Answer;
@@ -28,7 +28,6 @@
import io.javaoperatorsdk.operator.api.reconciler.Cleaner;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.DeleteControl;
-import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler;
import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
import io.javaoperatorsdk.operator.api.reconciler.RetryInfo;
@@ -479,7 +478,7 @@ void callErrorStatusHandlerIfImplemented() {
reconciler.reconcile = (r, c) -> {
throw new IllegalStateException("Error Status Test");
};
- reconciler.errorHandler = (r, ri, e) -> {
+ reconciler.errorHandler = () -> {
testCustomResource.getStatus().setConfigMapStatus(ERROR_MESSAGE);
return ErrorStatusUpdateControl.patchStatus(testCustomResource);
};
@@ -499,7 +498,7 @@ public boolean isLastAttempt() {
}).setResource(testCustomResource));
verify(customResourceFacade, times(1)).patchStatus(eq(testCustomResource), any());
- verify(((ErrorStatusHandler) reconciler), times(1)).updateErrorStatus(eq(testCustomResource),
+ verify(reconciler, times(1)).updateErrorStatus(eq(testCustomResource),
any(), any());
}
@@ -510,7 +509,7 @@ void callErrorStatusHandlerEvenOnFirstError() {
reconciler.reconcile = (r, c) -> {
throw new IllegalStateException("Error Status Test");
};
- reconciler.errorHandler = (r, ri, e) -> {
+ reconciler.errorHandler = () -> {
testCustomResource.getStatus().setConfigMapStatus(ERROR_MESSAGE);
return ErrorStatusUpdateControl.patchStatus(testCustomResource);
};
@@ -518,7 +517,7 @@ void callErrorStatusHandlerEvenOnFirstError() {
var postExecControl = reconciliationDispatcher.handleExecution(
new ExecutionScope(null).setResource(testCustomResource));
verify(customResourceFacade, times(1)).patchStatus(eq(testCustomResource), any());
- verify(((ErrorStatusHandler) reconciler), times(1)).updateErrorStatus(eq(testCustomResource),
+ verify(reconciler, times(1)).updateErrorStatus(eq(testCustomResource),
any(), any());
assertThat(postExecControl.exceptionDuringExecution()).isTrue();
}
@@ -529,7 +528,7 @@ void errorHandlerCanInstructNoRetryWithUpdate() {
reconciler.reconcile = (r, c) -> {
throw new IllegalStateException("Error Status Test");
};
- reconciler.errorHandler = (r, ri, e) -> {
+ reconciler.errorHandler = () -> {
testCustomResource.getStatus().setConfigMapStatus(ERROR_MESSAGE);
return ErrorStatusUpdateControl.patchStatus(testCustomResource).withNoRetry();
};
@@ -537,7 +536,7 @@ void errorHandlerCanInstructNoRetryWithUpdate() {
var postExecControl = reconciliationDispatcher.handleExecution(
new ExecutionScope(null).setResource(testCustomResource));
- verify(((ErrorStatusHandler) reconciler), times(1)).updateErrorStatus(eq(testCustomResource),
+ verify(reconciler, times(1)).updateErrorStatus(eq(testCustomResource),
any(), any());
verify(customResourceFacade, times(1)).patchStatus(eq(testCustomResource), any());
assertThat(postExecControl.exceptionDuringExecution()).isFalse();
@@ -549,7 +548,7 @@ void errorHandlerCanInstructNoRetryNoUpdate() {
reconciler.reconcile = (r, c) -> {
throw new IllegalStateException("Error Status Test");
};
- reconciler.errorHandler = (r, ri, e) -> {
+ reconciler.errorHandler = () -> {
testCustomResource.getStatus().setConfigMapStatus(ERROR_MESSAGE);
return ErrorStatusUpdateControl.