diff --git a/test/e2e/functional/global-scope.yaml b/test/e2e/functional/global-scope.yaml new file mode 100644 index 000000000000..a929ff9cf3bd --- /dev/null +++ b/test/e2e/functional/global-scope.yaml @@ -0,0 +1,84 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: overwrite-output-parameter- + labels: + argo-e2e: true +spec: + entrypoint: plan + templates: + - name: plan + steps: + + - - name: write-global-parameter + template: global-parameter-generation + arguments: + parameters: + - name: parameter + value: initial + + - - name: consume-global-parameter-1 + template: global-parameter-consumption + + - - name: consume-global-parameter-2 + template: global-parameter-consumption + + - - name: overwrite-global-parameter + template: nested-global-parameter-generation + arguments: + parameters: + - name: parameter + value: final + + - - name: consume-global-parameter-3 + template: global-parameter-consumption + + - - name: consume-global-parameter-4 + template: global-parameter-consumption + outputs: + parameters: + - name: output-1 + valueFrom: + parameter: "{{steps.consume-global-parameter-1.outputs.result}}" + - name: output-2 + valueFrom: + parameter: "{{steps.consume-global-parameter-2.outputs.result}}" + - name: output-3 + valueFrom: + parameter: "{{steps.consume-global-parameter-3.outputs.result}}" + - name: output-4 + valueFrom: + parameter: "{{steps.consume-global-parameter-4.outputs.result}}" + + - name: global-parameter-generation + inputs: + parameters: + - name: parameter + container: + image: alpine:latest + command: [sh, -c] + args: ["echo '{{inputs.parameters.parameter}}' > /tmp/hello_world.txt"] + outputs: + parameters: + - name: parameter + valueFrom: + path: /tmp/hello_world.txt + globalName: global-parameter + + - name: nested-global-parameter-generation + inputs: + parameters: + - name: parameter + steps: + - - name: generate-parameter + template: global-parameter-generation + arguments: + parameters: + - name: parameter + value: "{{inputs.parameters.parameter}}" + + - name: global-parameter-consumption + container: + image: alpine:latest + command: [sh, -c] + args: ["echo {{workflow.outputs.parameters.global-parameter}}"] diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go index 2bfb639de7a5..c6f8e28e3dca 100644 --- a/test/e2e/functional_test.go +++ b/test/e2e/functional_test.go @@ -364,6 +364,38 @@ func (s *FunctionalSuite) TestParameterAggregation() { }) } +func (s *FunctionalSuite) TestGlobalScope() { + s.Given(). + Workflow("@functional/global-scope.yaml"). + When(). + SubmitWorkflow(). + WaitForWorkflow(60 * time.Second). + Then(). + ExpectWorkflow(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + assert.Equal(t, wfv1.NodeSucceeded, status.Phase) + nodeStatus := status.Nodes.FindByDisplayName("consume-global-parameter-1") + if assert.NotNil(t, nodeStatus) { + assert.Equal(t, wfv1.NodeSucceeded, nodeStatus.Phase) + assert.Equal(t, "initial", *nodeStatus.Outputs.Result) + } + nodeStatus = status.Nodes.FindByDisplayName("consume-global-parameter-2") + if assert.NotNil(t, nodeStatus) { + assert.Equal(t, wfv1.NodeSucceeded, nodeStatus.Phase) + assert.Equal(t, "initial", *nodeStatus.Outputs.Result) + } + nodeStatus = status.Nodes.FindByDisplayName("consume-global-parameter-3") + if assert.NotNil(t, nodeStatus) { + assert.Equal(t, wfv1.NodeSucceeded, nodeStatus.Phase) + assert.Equal(t, "final", *nodeStatus.Outputs.Result) + } + nodeStatus = status.Nodes.FindByDisplayName("consume-global-parameter-4") + if assert.NotNil(t, nodeStatus) { + assert.Equal(t, wfv1.NodeSucceeded, nodeStatus.Phase) + assert.Equal(t, "final", *nodeStatus.Outputs.Result) + } + }) +} + func (s *FunctionalSuite) TestStopBehavior() { s.Given(). Workflow("@functional/stop-terminate.yaml"). diff --git a/workflow/controller/operator_test.go b/workflow/controller/operator_test.go index b272baeacc2e..5d731e2040cf 100644 --- a/workflow/controller/operator_test.go +++ b/workflow/controller/operator_test.go @@ -2816,3 +2816,157 @@ func TestContainerOutputsResult(t *testing.T) { } } } + +var nestedStepGroupGlobalParams = ` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + name: global-outputs-bg7gl +spec: + arguments: {} + entrypoint: generate-globals + templates: + - arguments: {} + inputs: {} + metadata: {} + name: generate-globals + outputs: {} + steps: + - - arguments: {} + name: generate + template: nested-global-output-generation + - arguments: {} + container: + args: + - sleep 1; echo -n hello world > /tmp/hello_world.txt + command: + - sh + - -c + image: alpine:3.7 + name: "" + resources: {} + inputs: {} + metadata: {} + name: output-generation + outputs: + parameters: + - name: hello-param + valueFrom: + path: /tmp/hello_world.txt + - arguments: {} + inputs: {} + metadata: {} + name: nested-global-output-generation + outputs: + parameters: + - globalName: global-param + name: hello-param + valueFrom: + parameter: '{{steps.generate-output.outputs.parameters.hello-param}}' + steps: + - - arguments: {} + name: generate-output + template: output-generation +status: + conditions: + - status: "True" + type: Completed + finishedAt: "2020-04-24T15:55:18Z" + nodes: + global-outputs-bg7gl: + children: + - global-outputs-bg7gl-1831647575 + displayName: global-outputs-bg7gl + id: global-outputs-bg7gl + name: global-outputs-bg7gl + outboundNodes: + - global-outputs-bg7gl-1290716463 + phase: Running + startedAt: "2020-04-24T15:55:11Z" + templateName: generate-globals + templateScope: local/global-outputs-bg7gl + type: Steps + global-outputs-bg7gl-1290716463: + boundaryID: global-outputs-bg7gl-2228002836 + displayName: generate-output + finishedAt: "2020-04-24T15:55:16Z" + hostNodeName: minikube + id: global-outputs-bg7gl-1290716463 + name: global-outputs-bg7gl[0].generate[0].generate-output + outputs: + parameters: + - name: hello-param + value: hello world + valueFrom: + path: /tmp/hello_world.txt + phase: Succeeded + startedAt: "2020-04-24T15:55:11Z" + templateName: output-generation + templateScope: local/global-outputs-bg7gl + type: Pod + global-outputs-bg7gl-1831647575: + boundaryID: global-outputs-bg7gl + children: + - global-outputs-bg7gl-2228002836 + displayName: '[0]' + finishedAt: "2020-04-24T15:55:18Z" + id: global-outputs-bg7gl-1831647575 + name: global-outputs-bg7gl[0] + phase: Succeeded + startedAt: "2020-04-24T15:55:11Z" + templateName: generate-globals + templateScope: local/global-outputs-bg7gl + type: StepGroup + global-outputs-bg7gl-2228002836: + boundaryID: global-outputs-bg7gl + children: + - global-outputs-bg7gl-3089902334 + displayName: generate + id: global-outputs-bg7gl-2228002836 + name: global-outputs-bg7gl[0].generate + phase: Running + outboundNodes: + - global-outputs-bg7gl-1290716463 + startedAt: "2020-04-24T15:55:11Z" + templateName: nested-global-output-generation + templateScope: local/global-outputs-bg7gl + type: Steps + global-outputs-bg7gl-3089902334: + boundaryID: global-outputs-bg7gl-2228002836 + children: + - global-outputs-bg7gl-1290716463 + displayName: '[0]' + finishedAt: "2020-04-24T15:55:18Z" + id: global-outputs-bg7gl-3089902334 + name: global-outputs-bg7gl[0].generate[0] + phase: Succeeded + startedAt: "2020-04-24T15:55:11Z" + templateName: nested-global-output-generation + templateScope: local/global-outputs-bg7gl + type: StepGroup + startedAt: "2020-04-24T15:55:11Z" +` + +func TestNestedStepGroupGlobalParams(t *testing.T) { + cancel, controller := newController() + defer cancel() + wfcset := controller.wfclientset.ArgoprojV1alpha1().Workflows("") + + // operate the workflow. it should create a pod. + wf := unmarshalWF(nestedStepGroupGlobalParams) + wf, err := wfcset.Create(wf) + assert.NoError(t, err) + + woc := newWorkflowOperationCtx(wf, controller) + woc.operate() + + node := woc.wf.Status.Nodes.FindByDisplayName("generate") + if assert.NotNil(t, node) { + assert.Equal(t, "hello-param", node.Outputs.Parameters[0].Name) + assert.Equal(t, "global-param", node.Outputs.Parameters[0].GlobalName) + assert.Equal(t, "hello world", *node.Outputs.Parameters[0].Value) + } + + assert.Equal(t, "hello world", *woc.wf.Status.Outputs.Parameters[0].Value) + assert.Equal(t, "global-param", woc.wf.Status.Outputs.Parameters[0].Name) +} diff --git a/workflow/controller/steps.go b/workflow/controller/steps.go index 082230913e25..19da16657416 100644 --- a/workflow/controller/steps.go +++ b/workflow/controller/steps.go @@ -149,6 +149,7 @@ func (woc *wfOperationCtx) executeSteps(nodeName string, tmplCtx *templateresolu if outputs != nil { node := woc.getNodeByName(nodeName) node.Outputs = outputs + woc.addOutputsToGlobalScope(node.Outputs) woc.wf.Status.Nodes[node.ID] = *node } return woc.markNodePhase(nodeName, wfv1.NodeSucceeded), nil