From a2e7c5a1bef21552e85ca426ac64a439d8ba7a6c Mon Sep 17 00:00:00 2001 From: ivancili <16418251+ivancili@users.noreply.github.com> Date: Wed, 29 Nov 2023 20:00:53 +0100 Subject: [PATCH] fix: properly resolve exit handler inputs (fixes #12283) (#12288) Signed-off-by: ivancili <16418251+ivancili@users.noreply.github.com> --- workflow/controller/exit_handler.go | 14 +++-- workflow/controller/exit_handler_test.go | 73 ++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/workflow/controller/exit_handler.go b/workflow/controller/exit_handler.go index 292bba2bb029..238b10c2119e 100644 --- a/workflow/controller/exit_handler.go +++ b/workflow/controller/exit_handler.go @@ -33,7 +33,7 @@ func (woc *wfOperationCtx) runOnExitNode(ctx context.Context, exitHook *wfv1.Lif woc.log.WithField("lifeCycleHook", exitHook).Infof("Running OnExit handler") onExitNodeName := common.GenerateOnExitNodeName(parentNode.Name) resolvedArgs := exitHook.Arguments - if !resolvedArgs.IsEmpty() && outputs != nil { + if !resolvedArgs.IsEmpty() { resolvedArgs, err = woc.resolveExitTmplArgument(exitHook.Arguments, prefix, outputs, scope) if err != nil { return true, nil, err @@ -56,11 +56,13 @@ func (woc *wfOperationCtx) resolveExitTmplArgument(args wfv1.Arguments, prefix s if scope == nil { scope = createScope(nil) } - for _, param := range outputs.Parameters { - scope.addParamToScope(fmt.Sprintf("%s.outputs.parameters.%s", prefix, param.Name), param.Value.String()) - } - for _, arts := range outputs.Artifacts { - scope.addArtifactToScope(fmt.Sprintf("%s.outputs.artifacts.%s", prefix, arts.Name), arts) + if outputs != nil { + for _, param := range outputs.Parameters { + scope.addParamToScope(fmt.Sprintf("%s.outputs.parameters.%s", prefix, param.Name), param.Value.String()) + } + for _, arts := range outputs.Artifacts { + scope.addArtifactToScope(fmt.Sprintf("%s.outputs.artifacts.%s", prefix, arts.Name), arts) + } } stepBytes, err := json.Marshal(args) diff --git a/workflow/controller/exit_handler_test.go b/workflow/controller/exit_handler_test.go index 1a10001cf697..32bd3dbe8f6c 100644 --- a/workflow/controller/exit_handler_test.go +++ b/workflow/controller/exit_handler_test.go @@ -999,3 +999,76 @@ status: woc.operate(ctx) assert.Equal(t, woc.wf.Status.Phase, wfv1.WorkflowRunning) } + +func TestStepsTemplateOnExitStatusArgument(t *testing.T) { + wf := wfv1.MustUnmarshalWorkflow(` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: lifecycle-hook-tmpl-level- + labels: + test: test +spec: + entrypoint: main + templates: + - name: main + steps: + - - name: main + template: echo + hooks: + exit: + template: hook + arguments: + parameters: + - name: status + value: "{{steps.main.status}}" + - name: echo + container: + image: alpine:3.6 + command: [sh, -c] + args: ["echo hi"] + - name: hook + inputs: + parameters: + - name: status + container: + image: alpine:3.6 + command: [sh, -c] + args: ["echo {{inputs.parameters.status}}"] +`) + cancel, controller := newController(wf) + defer cancel() + + ctx := context.Background() + woc := newWorkflowOperationCtx(wf, controller) + woc.operate(ctx) + + makePodsPhase(ctx, woc, apiv1.PodFailed) + + woc = newWorkflowOperationCtx(woc.wf, controller) + woc.operate(ctx) + + var hasExitNode bool + var exitNodeName string + + for _, node := range woc.wf.Status.Nodes { + if node.IsExitNode() { + hasExitNode = true + exitNodeName = node.DisplayName + break + } + } + + assert.True(t, hasExitNode) + assert.NotEmpty(t, exitNodeName) + + hookNode := woc.wf.Status.Nodes.FindByDisplayName(exitNodeName) + + if assert.NotNil(t, hookNode) { + assert.NotNil(t, hookNode.Inputs) + if assert.Len(t, hookNode.Inputs.Parameters, 1) { + assert.NotNil(t, hookNode.Inputs.Parameters[0].Value) + assert.Equal(t, hookNode.Inputs.Parameters[0].Value.String(), string(apiv1.PodFailed)) + } + } +}