Skip to content

Commit

Permalink
fix: Add Step node outputs to global scope (#2826)
Browse files Browse the repository at this point in the history
  • Loading branch information
simster7 committed Apr 27, 2020
1 parent 462f6af commit 83fa940
Show file tree
Hide file tree
Showing 4 changed files with 323 additions and 0 deletions.
84 changes: 84 additions & 0 deletions test/e2e/functional/global-scope.yaml
Original file line number Diff line number Diff line change
@@ -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}}"]
32 changes: 32 additions & 0 deletions test/e2e/functional_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,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.T().SkipNow()
s.Given().
Expand Down
206 changes: 206 additions & 0 deletions workflow/controller/operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2715,3 +2715,209 @@ func TestRetryNodeOutputs(t *testing.T) {
woc.buildLocalScope(scope, "steps.influx", retryNode)
assert.Contains(t, scope.scope, "steps.influx.ip")
}

var containerOutputsResult = `
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: steps-
spec:
entrypoint: hello-hello-hello
templates:
- name: hello-hello-hello
steps:
- - name: hello1
template: whalesay
arguments:
parameters: [{name: message, value: "hello1"}]
- - name: hello2
template: whalesay
arguments:
parameters: [{name: message, value: "{{steps.hello1.outputs.result}}"}]
- name: whalesay
inputs:
parameters:
- name: message
container:
image: alpine:latest
command: [echo]
args: ["{{pod.name}}: {{inputs.parameters.message}}"]
`

func TestContainerOutputsResult(t *testing.T) {
controller := newController()
wfcset := controller.wfclientset.ArgoprojV1alpha1().Workflows("")

// operate the workflow. it should create a pod.
wf := unmarshalWF(containerOutputsResult)
wf, err := wfcset.Create(wf)
assert.NoError(t, err)

assert.True(t, hasOutputResultRef("hello1", &wf.Spec.Templates[0]))
assert.False(t, hasOutputResultRef("hello2", &wf.Spec.Templates[0]))

woc := newWorkflowOperationCtx(wf, controller)
woc.operate()

for _, node := range wf.Status.Nodes {
if strings.Contains(node.Name, "hello1") {
assert.True(t, getStepOrDAGTaskName(node.Name) == "hello1")
} else if strings.Contains(node.Name, "hello2") {
assert.True(t, getStepOrDAGTaskName(node.Name) == "hello2")
}
}
}

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) {
controller := newController()
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)
}
1 change: 1 addition & 0 deletions workflow/controller/steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,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
Expand Down

0 comments on commit 83fa940

Please sign in to comment.