This is an automated email from the ASF dual-hosted git repository. heneveld pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
commit 918acb96e765d8a217146213431b33de0acdf876 Author: Alex Heneveld <[email protected]> AuthorDate: Fri Sep 15 13:41:56 2023 +0100 allow workflow to have no steps if it has output --- .../core/workflow/WorkflowExecutionContext.java | 2 +- .../core/workflow/WorkflowStepResolution.java | 11 +++++++++-- .../core/workflow/steps/CustomWorkflowStep.java | 21 +++++++++++++++------ .../brooklyn/core/workflow/WorkflowBasicTest.java | 16 ++++++++++++++-- 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java index 0abb57c806..deef3d0353 100644 --- a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java @@ -917,7 +917,7 @@ public class WorkflowExecutionContext { @JsonIgnore List<WorkflowStepDefinition> getStepsResolved() { if (stepsResolved ==null) { - stepsResolved = MutableList.copyOf(WorkflowStepResolution.resolveSteps(getManagementContext(), WorkflowExecutionContext.this.stepsDefinition)); + stepsResolved = MutableList.copyOf(WorkflowStepResolution.resolveSteps(getManagementContext(), WorkflowExecutionContext.this.stepsDefinition, outputDefinition)); } return stepsResolved; } diff --git a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowStepResolution.java b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowStepResolution.java index 515153a33c..102843d950 100644 --- a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowStepResolution.java +++ b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowStepResolution.java @@ -45,8 +45,15 @@ import java.util.Map; public class WorkflowStepResolution { public static List<WorkflowStepDefinition> resolveSteps(ManagementContext mgmt, List<Object> steps) { + return resolveSteps(mgmt, steps, null); + } + public static List<WorkflowStepDefinition> resolveSteps(ManagementContext mgmt, List<Object> steps, Object outputDefinition) { List<WorkflowStepDefinition> result = MutableList.of(); - if (steps==null || steps.isEmpty()) throw new IllegalStateException("No steps defined in workflow"); + if (steps==null || steps.isEmpty()) { + if (outputDefinition==null) throw new IllegalStateException("No steps defined in workflow and no output set"); + // if there is output, an empty workflow makes sense + return result; + } for (int i=0; i<steps.size(); i++) { try { result.add(resolveStep(mgmt, steps.get(i))); @@ -172,7 +179,7 @@ public class WorkflowStepResolution { if (!hasCondition && entityOrAdjunctWhereRunningIfKnown!=null) { // ideally try to resolve the steps at entity init time; except if a condition is required we skip that so you can have steps that only resolve late, // and if entity isn't available then we don't need that either - WorkflowStepResolution.resolveSteps( ((BrooklynObjectInternal)entityOrAdjunctWhereRunningIfKnown).getManagementContext(), steps); + WorkflowStepResolution.resolveSteps( ((BrooklynObjectInternal)entityOrAdjunctWhereRunningIfKnown).getManagementContext(), steps, params.containsKey(WorkflowCommonConfig.OUTPUT.getName()) ? "has_output" : null); } } diff --git a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/CustomWorkflowStep.java b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/CustomWorkflowStep.java index d1925d2327..e56d38e00a 100644 --- a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/CustomWorkflowStep.java +++ b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/CustomWorkflowStep.java @@ -58,6 +58,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -163,8 +164,10 @@ public class CustomWorkflowStep extends WorkflowStepDefinition implements Workfl public void validateStep(@Nullable ManagementContext mgmt, @Nullable WorkflowExecutionContext workflow) { super.validateStep(mgmt, workflow); - if (steps instanceof List) WorkflowStepResolution.resolveSteps(mgmt, (List<Object>) steps); - else if (steps!=null) throw new IllegalArgumentException("Workflow `steps` must be a list"); + if (steps instanceof List) { + if (((List)steps).isEmpty()) throw new IllegalArgumentException("Workflow `steps` must be supplied for a custom or nested workflow"); + WorkflowStepResolution.resolveSteps(mgmt, (List<Object>) steps, null); + } else if (steps!=null) throw new IllegalArgumentException("Workflow `steps` must be a list"); else if (target!=null) throw new IllegalArgumentException("Workflow cannot take a `target` without `steps`"); } @@ -561,7 +564,10 @@ public class CustomWorkflowStep extends WorkflowStepDefinition implements Workfl return newWorkflowExecution(entity, name, extraConfig, null); } public WorkflowExecutionContext newWorkflowExecution(Entity entity, String name, ConfigBag extraConfig, Map extraTaskFlags) { - if (steps==null) throw new IllegalArgumentException("Cannot make new workflow with no steps"); + if (steps==null) { + if (target!=null) throw new IllegalArgumentException("Steps are required for a workflow with a target"); + else steps = MutableList.of(); + } if (target==null) { // copy everything as we are going to run it "flat" @@ -580,12 +586,15 @@ public class CustomWorkflowStep extends WorkflowStepDefinition implements Workfl } } - private ConfigBag getConfigForSubWorkflow(boolean includeInput) { + private ConfigBag getConfigForSubWorkflow(boolean isFlattened) { + if (isFlattened && (output!=null && workflowOutput!=null)) { + if (!Objects.equals(output, workflowOutput)) throw new IllegalArgumentException("Setting both 'output' and 'workflowOutput' is not supported for custom steps without target"); + } ConfigBag result = ConfigBag.newInstance() .configure(WorkflowCommonConfig.PARAMETER_DEFS, parameters) .configure(WorkflowCommonConfig.STEPS, steps) - .configure(WorkflowCommonConfig.INPUT, includeInput ? input : null) // input is resolved in outer workflow so it can reference outer workflow vars - .configure(WorkflowCommonConfig.OUTPUT, workflowOutput) + .configure(WorkflowCommonConfig.INPUT, isFlattened ? input : null) // input is resolved in outer workflow so it can reference outer workflow vars + .configure(WorkflowCommonConfig.OUTPUT, isFlattened && workflowOutput==null ? output : workflowOutput) .configure(WorkflowCommonConfig.RETENTION, retention) .configure(WorkflowCommonConfig.REPLAYABLE, replayable) .configure(WorkflowCommonConfig.IDEMPOTENT, idempotent) diff --git a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java index 8d0ce20a87..9287cfb8b2 100644 --- a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java @@ -216,7 +216,7 @@ public class WorkflowBasicTest extends BrooklynMgmtUnitTestSupport { "log test message" ); - List<WorkflowStepDefinition> steps = WorkflowStepResolution.resolveSteps(mgmt, stepsDefinition); + List<WorkflowStepDefinition> steps = WorkflowStepResolution.resolveSteps(mgmt, stepsDefinition, null); Asserts.assertSize(steps, 4); } @@ -229,7 +229,7 @@ public class WorkflowBasicTest extends BrooklynMgmtUnitTestSupport { Asserts.assertInstanceOf(wf, CustomWorkflowStep.class); Asserts.assertSize(((CustomWorkflowStep) wf).peekSteps(), 1); Asserts.assertInstanceOf( - WorkflowStepResolution.resolveSteps( mgmt, ((CustomWorkflowStep) wf).peekSteps() ).get(0), LogWorkflowStep.class); + WorkflowStepResolution.resolveSteps( mgmt, ((CustomWorkflowStep) wf).peekSteps(), null ).get(0), LogWorkflowStep.class); }; test.accept( BeanWithTypeUtils.convert(mgmt, @@ -480,5 +480,17 @@ public class WorkflowBasicTest extends BrooklynMgmtUnitTestSupport { w1.getTask(false).get().getUnchecked(), MutableList.of("a=b", "b=c")); } + + @Test + public void testOutputOnlyWorkflow() { + loadTypes(); + BasicApplication app = mgmt.getEntityManager().createEntity(EntitySpec.create(BasicApplication.class)); + WorkflowExecutionContext w1 = WorkflowBasicTest.runWorkflow(app, Strings.lines( + "output: 42" + ), null); + Asserts.assertEquals( + w1.getTask(false).get().getUnchecked(), + 42); + } }
