diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/DefaultManagedWorkflowAndDependentResourceContext.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/DefaultManagedWorkflowAndDependentResourceContext.java
index 1e9e10ca20..0102b58d80 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/DefaultManagedWorkflowAndDependentResourceContext.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/DefaultManagedWorkflowAndDependentResourceContext.java
@@ -83,19 +83,18 @@ public WorkflowCleanupResult getWorkflowCleanupResult() {
}
@Override
- public void reconcileManagedWorkflow() {
+ public WorkflowReconcileResult reconcileManagedWorkflow() {
if (!controller.isWorkflowExplicitInvocation()) {
throw new IllegalStateException("Workflow explicit invocation is not set.");
}
- controller.reconcileManagedWorkflow(primaryResource, context);
+ return controller.reconcileManagedWorkflow(primaryResource, context);
}
@Override
- public void cleanupManageWorkflow() {
+ public WorkflowCleanupResult cleanupManageWorkflow() {
if (!controller.isWorkflowExplicitInvocation()) {
throw new IllegalStateException("Workflow explicit invocation is not set.");
}
- controller.cleanupManagedWorkflow(primaryResource, context);
+ return controller.cleanupManagedWorkflow(primaryResource, context);
}
-
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/ManagedWorkflowAndDependentResourceContext.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/ManagedWorkflowAndDependentResourceContext.java
index 6bb1e60b0e..617505b387 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/ManagedWorkflowAndDependentResourceContext.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/ManagedWorkflowAndDependentResourceContext.java
@@ -70,9 +70,10 @@ public interface ManagedWorkflowAndDependentResourceContext {
* Explicitly reconcile the declared workflow for the associated
* {@link io.javaoperatorsdk.operator.api.reconciler.Reconciler}
*
+ * @return the result of the workflow reconciliation
* @throws IllegalStateException if called when explicit invocation is not requested
*/
- void reconcileManagedWorkflow();
+ WorkflowReconcileResult reconcileManagedWorkflow();
/**
* Explicitly clean-up dependent resources in the declared workflow for the associated
@@ -80,8 +81,9 @@ public interface ManagedWorkflowAndDependentResourceContext {
* only needed if the associated reconciler implements the
* {@link io.javaoperatorsdk.operator.api.reconciler.Cleaner} interface.
*
+ * @return the result of the workflow reconciliation on cleanup
* @throws IllegalStateException if called when explicit invocation is not requested
*/
- void cleanupManageWorkflow();
+ WorkflowCleanupResult cleanupManageWorkflow();
}
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 76c8401249..da9843ec40 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
@@ -40,6 +40,7 @@
import io.javaoperatorsdk.operator.health.ControllerHealthInfo;
import io.javaoperatorsdk.operator.processing.dependent.workflow.Workflow;
import io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowCleanupResult;
+import io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowReconcileResult;
import io.javaoperatorsdk.operator.processing.event.EventProcessor;
import io.javaoperatorsdk.operator.processing.event.EventSourceManager;
import io.javaoperatorsdk.operator.processing.event.ResourceID;
@@ -449,16 +450,18 @@ public EventSourceContext
eventSourceContext() {
return eventSourceContext;
}
- public void reconcileManagedWorkflow(P primary, Context
context) {
+ public WorkflowReconcileResult reconcileManagedWorkflow(P primary, Context
context) {
if (!managedWorkflow.isEmpty()) {
- managedWorkflow.reconcile(primary, context);
+ return managedWorkflow.reconcile(primary, context);
}
+ return WorkflowReconcileResult.EMPTY;
}
- public void cleanupManagedWorkflow(P resource, Context
context) {
+ public WorkflowCleanupResult cleanupManagedWorkflow(P resource, Context
context) {
if (managedWorkflow.hasCleaner()) {
- managedWorkflow.cleanup(resource, context);
+ return managedWorkflow.cleanup(resource, context);
}
+ return WorkflowCleanupResult.EMPTY;
}
public boolean isWorkflowExplicitInvocation() {
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java
index eb0f3f7e83..60d137fa1a 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java
@@ -24,7 +24,7 @@ abstract class AbstractWorkflowExecutor
{
protected final P primary;
protected final ResourceID primaryID;
protected final Context
context;
- protected final Map, WorkflowResult.DetailBuilder>> results;
+ protected final Map, BaseWorkflowResult.DetailBuilder>> results;
/**
* Covers both deleted and reconciled
*/
@@ -74,30 +74,30 @@ protected boolean noMoreExecutionsScheduled() {
}
protected boolean alreadyVisited(DependentResourceNode, P> dependentResourceNode) {
- return getResultFlagFor(dependentResourceNode, WorkflowResult.DetailBuilder::isVisited);
+ return getResultFlagFor(dependentResourceNode, BaseWorkflowResult.DetailBuilder::isVisited);
}
protected boolean postDeleteConditionNotMet(DependentResourceNode, P> drn) {
- return getResultFlagFor(drn, WorkflowResult.DetailBuilder::hasPostDeleteConditionNotMet);
+ return getResultFlagFor(drn, BaseWorkflowResult.DetailBuilder::hasPostDeleteConditionNotMet);
}
protected boolean isMarkedForDelete(DependentResourceNode, P> drn) {
- return getResultFlagFor(drn, WorkflowResult.DetailBuilder::isMarkedForDelete);
+ return getResultFlagFor(drn, BaseWorkflowResult.DetailBuilder::isMarkedForDelete);
}
- protected synchronized WorkflowResult.DetailBuilder createOrGetResultFor(
+ protected synchronized BaseWorkflowResult.DetailBuilder createOrGetResultFor(
DependentResourceNode, P> dependentResourceNode) {
return results.computeIfAbsent(dependentResourceNode,
- unused -> new WorkflowResult.DetailBuilder());
+ unused -> new BaseWorkflowResult.DetailBuilder());
}
- protected synchronized Optional> getResultFor(
+ protected synchronized Optional> getResultFor(
DependentResourceNode, P> dependentResourceNode) {
return Optional.ofNullable(results.get(dependentResourceNode));
}
protected boolean getResultFlagFor(DependentResourceNode, P> dependentResourceNode,
- Function, Boolean> flag) {
+ Function, Boolean> flag) {
return getResultFor(dependentResourceNode).map(flag).orElse(false);
}
@@ -117,11 +117,11 @@ protected synchronized void handleExceptionInExecutor(
}
protected boolean isReady(DependentResourceNode, P> dependentResourceNode) {
- return getResultFlagFor(dependentResourceNode, WorkflowResult.DetailBuilder::isReady);
+ return getResultFlagFor(dependentResourceNode, BaseWorkflowResult.DetailBuilder::isReady);
}
protected boolean isInError(DependentResourceNode, P> dependentResourceNode) {
- return getResultFlagFor(dependentResourceNode, WorkflowResult.DetailBuilder::hasError);
+ return getResultFlagFor(dependentResourceNode, BaseWorkflowResult.DetailBuilder::hasError);
}
protected synchronized void handleNodeExecutionFinish(
@@ -141,7 +141,7 @@ protected boolean isConditionMet(
return condition.map(c -> {
final DetailedCondition.Result> r = c.detailedIsMet(dr, primary, context);
synchronized (this) {
- results.computeIfAbsent(dependentResource, unused -> new WorkflowResult.DetailBuilder())
+ results.computeIfAbsent(dependentResource, unused -> new BaseWorkflowResult.DetailBuilder())
.withResultForCondition(c, r);
}
return r;
@@ -173,7 +173,7 @@ protected void registerOrDeregisterEventSourceBasedOnActivation(
}
}
- protected synchronized Map> asDetails() {
+ protected synchronized Map> asDetails() {
return results.entrySet().stream()
.collect(
Collectors.toMap(e -> e.getKey().getDependentResource(), e -> e.getValue().build()));
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/BaseWorkflowResult.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/BaseWorkflowResult.java
new file mode 100644
index 0000000000..cf759022dc
--- /dev/null
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/BaseWorkflowResult.java
@@ -0,0 +1,193 @@
+package io.javaoperatorsdk.operator.processing.dependent.workflow;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import io.javaoperatorsdk.operator.AggregatedOperatorException;
+import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
+import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult;
+
+@SuppressWarnings("rawtypes")
+class BaseWorkflowResult implements WorkflowResult {
+ private final Map> results;
+ private Boolean hasErroredDependents;
+
+ BaseWorkflowResult(Map> results) {
+ this.results = results;
+ }
+
+ @Override
+ public Map getErroredDependents() {
+ return getErroredDependentsStream()
+ .collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().error));
+ }
+
+ private Stream>> getErroredDependentsStream() {
+ return results.entrySet().stream().filter(entry -> entry.getValue().error != null);
+ }
+
+ protected Map> results() {
+ return results;
+ }
+
+ @Override
+ public Optional getDependentResourceByName(String name) {
+ if (name == null || name.isEmpty()) {
+ return Optional.empty();
+ }
+ return results.keySet().stream().filter(dr -> dr.name().equals(name)).findFirst();
+ }
+
+ @Override
+ public Optional getDependentConditionResult(DependentResource dependentResource,
+ Condition.Type conditionType, Class expectedResultType) {
+ if (dependentResource == null) {
+ return Optional.empty();
+ }
+
+ final var result = new Object[1];
+ try {
+ return Optional.ofNullable(results().get(dependentResource))
+ .flatMap(detail -> detail.getResultForConditionWithType(conditionType))
+ .map(r -> result[0] = r.getDetail())
+ .map(expectedResultType::cast);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Condition " +
+ "result " + result[0] +
+ " for Dependent " + dependentResource.name() + " doesn't match expected type "
+ + expectedResultType.getSimpleName(), e);
+ }
+ }
+
+ protected List listFilteredBy(
+ Function filter) {
+ return results.entrySet().stream()
+ .filter(e -> filter.apply(e.getValue()))
+ .map(Map.Entry::getKey)
+ .toList();
+ }
+
+ @Override
+ public boolean erroredDependentsExist() {
+ if (hasErroredDependents == null) {
+ hasErroredDependents = !getErroredDependents().isEmpty();
+ }
+ return hasErroredDependents;
+ }
+
+ @Override
+ public void throwAggregateExceptionIfErrorsPresent() {
+ if (erroredDependentsExist()) {
+ throw new AggregatedOperatorException("Exception(s) during workflow execution.",
+ getErroredDependentsStream()
+ .collect(Collectors.toMap(e -> e.getKey().name(), e -> e.getValue().error)));
+ }
+ }
+
+ @SuppressWarnings("UnusedReturnValue")
+ static class DetailBuilder {
+ private Exception error;
+ private ReconcileResult reconcileResult;
+ private DetailedCondition.Result activationConditionResult;
+ private DetailedCondition.Result deletePostconditionResult;
+ private DetailedCondition.Result readyPostconditionResult;
+ private DetailedCondition.Result reconcilePostconditionResult;
+ private boolean deleted;
+ private boolean visited;
+ private boolean markedForDelete;
+
+ Detail build() {
+ return new Detail<>(error, reconcileResult, activationConditionResult,
+ deletePostconditionResult, readyPostconditionResult, reconcilePostconditionResult,
+ deleted, visited, markedForDelete);
+ }
+
+ DetailBuilder withResultForCondition(
+ ConditionWithType conditionWithType,
+ DetailedCondition.Result conditionResult) {
+ switch (conditionWithType.type()) {
+ case ACTIVATION -> activationConditionResult = conditionResult;
+ case DELETE -> deletePostconditionResult = conditionResult;
+ case READY -> readyPostconditionResult = conditionResult;
+ case RECONCILE -> reconcilePostconditionResult = conditionResult;
+ default ->
+ throw new IllegalStateException("Unexpected condition type: " + conditionWithType);
+ }
+ return this;
+ }
+
+ DetailBuilder withError(Exception error) {
+ this.error = error;
+ return this;
+ }
+
+ DetailBuilder withReconcileResult(ReconcileResult reconcileResult) {
+ this.reconcileResult = reconcileResult;
+ return this;
+ }
+
+ DetailBuilder markAsDeleted() {
+ this.deleted = true;
+ return this;
+ }
+
+ public boolean hasError() {
+ return error != null;
+ }
+
+ public boolean hasPostDeleteConditionNotMet() {
+ return deletePostconditionResult != null && !deletePostconditionResult.isSuccess();
+ }
+
+ public boolean isReady() {
+ return readyPostconditionResult == null || readyPostconditionResult.isSuccess();
+ }
+
+ DetailBuilder markAsVisited() {
+ visited = true;
+ return this;
+ }
+
+ public boolean isVisited() {
+ return visited;
+ }
+
+ public boolean isMarkedForDelete() {
+ return markedForDelete;
+ }
+
+ DetailBuilder markForDelete() {
+ markedForDelete = true;
+ return this;
+ }
+ }
+
+
+ record Detail(Exception error, ReconcileResult reconcileResult,
+ DetailedCondition.Result activationConditionResult,
+ DetailedCondition.Result deletePostconditionResult,
+ DetailedCondition.Result readyPostconditionResult,
+ DetailedCondition.Result reconcilePostconditionResult,
+ boolean deleted, boolean visited, boolean markedForDelete) {
+
+ boolean isConditionWithTypeMet(Condition.Type conditionType) {
+ return getResultForConditionWithType(conditionType).map(DetailedCondition.Result::isSuccess)
+ .orElse(true);
+ }
+
+ Optional> getResultForConditionWithType(
+ Condition.Type conditionType) {
+ return switch (conditionType) {
+ case ACTIVATION -> Optional.ofNullable(activationConditionResult);
+ case DELETE -> Optional.ofNullable(deletePostconditionResult);
+ case READY -> Optional.ofNullable(readyPostconditionResult);
+ case RECONCILE -> Optional.ofNullable(reconcilePostconditionResult);
+ };
+ }
+ }
+}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultWorkflowCleanupResult.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultWorkflowCleanupResult.java
new file mode 100644
index 0000000000..951ff98bca
--- /dev/null
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultWorkflowCleanupResult.java
@@ -0,0 +1,30 @@
+package io.javaoperatorsdk.operator.processing.dependent.workflow;
+
+import java.util.List;
+import java.util.Map;
+
+import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
+
+@SuppressWarnings("rawtypes")
+class DefaultWorkflowCleanupResult extends BaseWorkflowResult implements WorkflowCleanupResult {
+ private Boolean allPostConditionsMet;
+
+ DefaultWorkflowCleanupResult(Map> results) {
+ super(results);
+ }
+
+ public List getDeleteCalledOnDependents() {
+ return listFilteredBy(BaseWorkflowResult.Detail::deleted);
+ }
+
+ public List getPostConditionNotMetDependents() {
+ return listFilteredBy(detail -> !detail.isConditionWithTypeMet(Condition.Type.DELETE));
+ }
+
+ public boolean allPostConditionsMet() {
+ if (allPostConditionsMet == null) {
+ allPostConditionsMet = getPostConditionNotMetDependents().isEmpty();
+ }
+ return allPostConditionsMet;
+ }
+}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultWorkflowReconcileResult.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultWorkflowReconcileResult.java
new file mode 100644
index 0000000000..3221308312
--- /dev/null
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultWorkflowReconcileResult.java
@@ -0,0 +1,28 @@
+package io.javaoperatorsdk.operator.processing.dependent.workflow;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
+
+@SuppressWarnings("rawtypes")
+class DefaultWorkflowReconcileResult extends BaseWorkflowResult implements WorkflowReconcileResult {
+ DefaultWorkflowReconcileResult(Map> results) {
+ super(results);
+ }
+
+
+ public List getReconciledDependents() {
+ return listFilteredBy(detail -> detail.reconcileResult() != null);
+ }
+
+ public List getNotReadyDependents() {
+ return listFilteredBy(detail -> !detail.isConditionWithTypeMet(Condition.Type.READY));
+ }
+
+ public Optional getNotReadyDependentResult(DependentResource dependentResource,
+ Class expectedResultType) {
+ return getDependentConditionResult(dependentResource, Condition.Type.READY, expectedResultType);
+ }
+}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutor.java
index 73633adb82..4681502a3b 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutor.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutor.java
@@ -127,6 +127,6 @@ private boolean hasErroredDependent(DependentResourceNode dependentResourceNode)
}
private WorkflowCleanupResult createCleanupResult() {
- return new WorkflowCleanupResult(asDetails());
+ return new DefaultWorkflowCleanupResult(asDetails());
}
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupResult.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupResult.java
index b93741ef56..1333270b47 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupResult.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupResult.java
@@ -1,30 +1,22 @@
package io.javaoperatorsdk.operator.processing.dependent.workflow;
import java.util.List;
-import java.util.Map;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
@SuppressWarnings("rawtypes")
-public class WorkflowCleanupResult extends WorkflowResult {
- private Boolean allPostConditionsMet;
+public interface WorkflowCleanupResult extends WorkflowResult {
+ WorkflowCleanupResult EMPTY = new WorkflowCleanupResult() {};
- WorkflowCleanupResult(Map> results) {
- super(results);
+ default List getDeleteCalledOnDependents() {
+ return List.of();
}
- public List getDeleteCalledOnDependents() {
- return listFilteredBy(Detail::deleted);
+ default List getPostConditionNotMetDependents() {
+ return List.of();
}
- public List getPostConditionNotMetDependents() {
- return listFilteredBy(detail -> !detail.isConditionWithTypeMet(Condition.Type.DELETE));
- }
-
- public boolean allPostConditionsMet() {
- if (allPostConditionsMet == null) {
- allPostConditionsMet = getPostConditionNotMetDependents().isEmpty();
- }
- return allPostConditionsMet;
+ default boolean allPostConditionsMet() {
+ return true;
}
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java
index 962d01c8e5..432a168ad7 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java
@@ -241,6 +241,6 @@ private boolean hasErroredParent(DependentResourceNode, ?> dependentResourceNo
}
private WorkflowReconcileResult createReconcileResult() {
- return new WorkflowReconcileResult(asDetails());
+ return new DefaultWorkflowReconcileResult(asDetails());
}
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileResult.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileResult.java
index 055fca3bfe..dd05e3f8e3 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileResult.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileResult.java
@@ -1,32 +1,28 @@
package io.javaoperatorsdk.operator.processing.dependent.workflow;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
@SuppressWarnings("rawtypes")
-public class WorkflowReconcileResult extends WorkflowResult {
+public interface WorkflowReconcileResult extends WorkflowResult {
+ WorkflowReconcileResult EMPTY = new WorkflowReconcileResult() {};
- WorkflowReconcileResult(Map> results) {
- super(results);
+ default List getReconciledDependents() {
+ return List.of();
}
- public List getReconciledDependents() {
- return listFilteredBy(detail -> detail.reconcileResult() != null);
+ default List getNotReadyDependents() {
+ return List.of();
}
- public List getNotReadyDependents() {
- return listFilteredBy(detail -> !detail.isConditionWithTypeMet(Condition.Type.READY));
- }
-
- public Optional getNotReadyDependentResult(DependentResource dependentResource,
+ default Optional getNotReadyDependentResult(DependentResource dependentResource,
Class expectedResultType) {
- return getDependentConditionResult(dependentResource, Condition.Type.READY, expectedResultType);
+ return Optional.empty();
}
- public boolean allDependentResourcesReady() {
+ default boolean allDependentResourcesReady() {
return getNotReadyDependents().isEmpty();
}
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResult.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResult.java
index 1b278fed77..0d7e74fa78 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResult.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResult.java
@@ -1,52 +1,26 @@
package io.javaoperatorsdk.operator.processing.dependent.workflow;
-import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Optional;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import io.javaoperatorsdk.operator.AggregatedOperatorException;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
-import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult;
@SuppressWarnings("rawtypes")
-class WorkflowResult {
- private final Map> results;
- private Boolean hasErroredDependents;
-
- WorkflowResult(Map> results) {
- this.results = results;
- }
-
- public Map getErroredDependents() {
- return getErroredDependentsStream()
- .collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().error));
- }
-
- private Stream>> getErroredDependentsStream() {
- return results.entrySet().stream().filter(entry -> entry.getValue().error != null);
- }
-
- protected Map> results() {
- return results;
+public interface WorkflowResult {
+ default Map getErroredDependents() {
+ return Map.of();
}
/**
* Retrieves the {@link DependentResource} associated with the specified name if it exists,
* {@link Optional#empty()} otherwise.
- *
+ *
* @param name the name of the {@link DependentResource} to retrieve
* @return the {@link DependentResource} associated with the specified name if it exists,
* {@link Optional#empty()} otherwise
*/
- public Optional getDependentResourceByName(String name) {
- if (name == null || name.isEmpty()) {
- return Optional.empty();
- }
- return results.keySet().stream().filter(dr -> dr.name().equals(name)).findFirst();
+ default Optional getDependentResourceByName(String name) {
+ return Optional.empty();
}
/**
@@ -61,7 +35,7 @@ public Optional getDependentResourceByName(String name) {
* @return the dependent condition result if it exists or {@link Optional#empty()} otherwise
* @throws IllegalArgumentException if a result exists but is not of the expected type
*/
- public Optional getDependentConditionResult(String dependentResourceName,
+ default Optional getDependentConditionResult(String dependentResourceName,
Condition.Type conditionType, Class expectedResultType) {
return getDependentConditionResult(
getDependentResourceByName(dependentResourceName).orElse(null), conditionType,
@@ -80,148 +54,16 @@ public Optional getDependentConditionResult(String dependentResourceName,
* @return the dependent condition result if it exists or {@link Optional#empty()} otherwise
* @throws IllegalArgumentException if a result exists but is not of the expected type
*/
- public Optional getDependentConditionResult(DependentResource dependentResource,
+ default Optional getDependentConditionResult(DependentResource dependentResource,
Condition.Type conditionType, Class expectedResultType) {
- if (dependentResource == null) {
- return Optional.empty();
- }
-
- final var result = new Object[1];
- try {
- return Optional.ofNullable(results().get(dependentResource))
- .flatMap(detail -> detail.getResultForConditionWithType(conditionType))
- .map(r -> result[0] = r.getDetail())
- .map(expectedResultType::cast);
- } catch (Exception e) {
- throw new IllegalArgumentException("Condition " +
- "result " + result[0] +
- " for Dependent " + dependentResource.name() + " doesn't match expected type "
- + expectedResultType.getSimpleName(), e);
- }
- }
-
- protected List listFilteredBy(
- Function filter) {
- return results.entrySet().stream()
- .filter(e -> filter.apply(e.getValue()))
- .map(Map.Entry::getKey)
- .toList();
- }
-
- public boolean erroredDependentsExist() {
- if (hasErroredDependents == null) {
- hasErroredDependents = !getErroredDependents().isEmpty();
- }
- return hasErroredDependents;
- }
-
- public void throwAggregateExceptionIfErrorsPresent() {
- if (erroredDependentsExist()) {
- throw new AggregatedOperatorException("Exception(s) during workflow execution.",
- getErroredDependentsStream()
- .collect(Collectors.toMap(e -> e.getKey().name(), e -> e.getValue().error)));
- }
+ return Optional.empty();
}
- @SuppressWarnings("UnusedReturnValue")
- static class DetailBuilder {
- private Exception error;
- private ReconcileResult reconcileResult;
- private DetailedCondition.Result activationConditionResult;
- private DetailedCondition.Result deletePostconditionResult;
- private DetailedCondition.Result readyPostconditionResult;
- private DetailedCondition.Result reconcilePostconditionResult;
- private boolean deleted;
- private boolean visited;
- private boolean markedForDelete;
-
- Detail build() {
- return new Detail<>(error, reconcileResult, activationConditionResult,
- deletePostconditionResult, readyPostconditionResult, reconcilePostconditionResult,
- deleted, visited, markedForDelete);
- }
-
- DetailBuilder withResultForCondition(
- ConditionWithType conditionWithType,
- DetailedCondition.Result conditionResult) {
- switch (conditionWithType.type()) {
- case ACTIVATION -> activationConditionResult = conditionResult;
- case DELETE -> deletePostconditionResult = conditionResult;
- case READY -> readyPostconditionResult = conditionResult;
- case RECONCILE -> reconcilePostconditionResult = conditionResult;
- default ->
- throw new IllegalStateException("Unexpected condition type: " + conditionWithType);
- }
- return this;
- }
-
- DetailBuilder withError(Exception error) {
- this.error = error;
- return this;
- }
-
- DetailBuilder withReconcileResult(ReconcileResult reconcileResult) {
- this.reconcileResult = reconcileResult;
- return this;
- }
-
- DetailBuilder markAsDeleted() {
- this.deleted = true;
- return this;
- }
-
- public boolean hasError() {
- return error != null;
- }
-
- public boolean hasPostDeleteConditionNotMet() {
- return deletePostconditionResult != null && !deletePostconditionResult.isSuccess();
- }
-
- public boolean isReady() {
- return readyPostconditionResult == null || readyPostconditionResult.isSuccess();
- }
-
- DetailBuilder markAsVisited() {
- visited = true;
- return this;
- }
-
- public boolean isVisited() {
- return visited;
- }
-
- public boolean isMarkedForDelete() {
- return markedForDelete;
- }
-
- DetailBuilder markForDelete() {
- markedForDelete = true;
- return this;
- }
+ default boolean erroredDependentsExist() {
+ return false;
}
-
- record Detail(Exception error, ReconcileResult reconcileResult,
- DetailedCondition.Result activationConditionResult,
- DetailedCondition.Result deletePostconditionResult,
- DetailedCondition.Result readyPostconditionResult,
- DetailedCondition.Result reconcilePostconditionResult,
- boolean deleted, boolean visited, boolean markedForDelete) {
-
- boolean isConditionWithTypeMet(Condition.Type conditionType) {
- return getResultForConditionWithType(conditionType).map(DetailedCondition.Result::isSuccess)
- .orElse(true);
- }
-
- Optional> getResultForConditionWithType(
- Condition.Type conditionType) {
- return switch (conditionType) {
- case ACTIVATION -> Optional.ofNullable(activationConditionResult);
- case DELETE -> Optional.ofNullable(deletePostconditionResult);
- case READY -> Optional.ofNullable(readyPostconditionResult);
- case RECONCILE -> Optional.ofNullable(reconcilePostconditionResult);
- };
- }
+ default void throwAggregateExceptionIfErrorsPresent() {
+ throw new UnsupportedOperationException("Implement this method");
}
}
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResultTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/BaseWorkflowResultTest.java
similarity index 85%
rename from operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResultTest.java
rename to operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/BaseWorkflowResultTest.java
index ca0b883e99..8503e402f1 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResultTest.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/BaseWorkflowResultTest.java
@@ -12,14 +12,14 @@
import static org.assertj.core.api.Assertions.assertThat;
-class WorkflowResultTest {
- private final static WorkflowResult.Detail> detail =
- new WorkflowResult.Detail<>(new RuntimeException(), null, null, null, null, null, false,
+class BaseWorkflowResultTest {
+ private final static BaseWorkflowResult.Detail> detail =
+ new BaseWorkflowResult.Detail<>(new RuntimeException(), null, null, null, null, null, false,
false, false);
@Test
void throwsExceptionWithoutNumberingIfAllDifferentClass() {
- var res = new WorkflowResult(Map.of(new DependentA(), detail,
+ var res = new BaseWorkflowResult(Map.of(new DependentA(), detail,
new DependentB(), detail));
try {
res.throwAggregateExceptionIfErrorsPresent();
@@ -31,7 +31,7 @@ void throwsExceptionWithoutNumberingIfAllDifferentClass() {
@Test
void numbersDependentClassNamesIfMoreOfSameType() {
- var res = new WorkflowResult(Map.of(new DependentA("name1"), detail,
+ var res = new BaseWorkflowResult(Map.of(new DependentA("name1"), detail,
new DependentA("name2"), detail));
try {
res.throwAggregateExceptionIfErrorsPresent();