Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions workflow/validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,38 @@ func ValidateWorkflow(ctx context.Context, wftmplGetter templateresolution.Workf
}
if tmplHolder != nil {
tctx.globalParams[common.GlobalVarWorkflowFailures] = placeholderGenerator.NextPlaceholder()

// Check if any template has parametrized global artifacts, if so enable global artifact resolution for exit handlers
hasParametrizedGlobalArtifacts := false
for _, tmpl := range wf.Spec.Templates {
for _, art := range tmpl.Outputs.Artifacts {
if art.GlobalName != "" && isParameter(art.GlobalName) {
hasParametrizedGlobalArtifacts = true
break
}
}
if hasParametrizedGlobalArtifacts {
break
}
}
if hasWorkflowTemplateRef && !hasParametrizedGlobalArtifacts {
// Also check the referenced workflow template
for _, tmpl := range wfSpecHolder.GetWorkflowSpec().Templates {
for _, art := range tmpl.Outputs.Artifacts {
if art.GlobalName != "" && isParameter(art.GlobalName) {
hasParametrizedGlobalArtifacts = true
break
}
}
if hasParametrizedGlobalArtifacts {
break
}
}
}
if hasParametrizedGlobalArtifacts {
tctx.globalParams[anyWorkflowOutputArtifactMagicValue] = "true"
}

_, err = tctx.validateTemplateHolder(ctx, tmplHolder, tmplCtx, &wf.Spec.Arguments, opts.WorkflowTemplateValidation)
if err != nil {
return err
Expand Down
128 changes: 128 additions & 0 deletions workflow/validate/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3435,3 +3435,131 @@ func TestDynamicWorkflowTemplateRef(t *testing.T) {
_ = deleteWorkflowTemplate(ctx, wftmplA.Name)
_ = deleteWorkflowTemplate(ctx, wftmplB.Name)
}

var parameterizedGlobalArtifactsWorkflow = `
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: test-parameterized-global-artifacts-
spec:
entrypoint: main
onExit: exit-handler
arguments:
parameters:
- name: variable
value: "car"
templates:
- name: main
container:
image: alpine:latest
command: [sh, -c]
args: ["echo 'test data' > /tmp/result.txt"]
outputs:
artifacts:
- name: result
globalName: output-result-{{workflow.parameters.variable}}
path: /tmp/result.txt
archive:
none: {}
- name: exit-handler
container:
image: alpine:latest
command: [sh, -c]
args: ["echo 'Access artifact: {{workflow.outputs.artifacts.output-result-car}}'"]
`

var parameterizedGlobalArtifactsWithWorkflowTemplateRef = `
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: test-wft-ref-
spec:
onExit: exit-handler
arguments:
parameters:
- name: variable
value: "test"
workflowTemplateRef:
name: parameterized-artifacts-template
`

var parameterizedArtifactsWorkflowTemplate = `
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: parameterized-artifacts-template
spec:
entrypoint: main
onExit: exit-handler
templates:
- name: main
container:
image: alpine:latest
command: [sh, -c]
args: ["echo 'test data' > /tmp/result.txt"]
outputs:
artifacts:
- name: result
globalName: output-result-{{workflow.parameters.variable}}
path: /tmp/result.txt
archive:
none: {}
- name: exit-handler
container:
image: alpine:latest
command: [sh, -c]
args: ["echo 'Access artifact: {{workflow.outputs.artifacts.output-result-test}}'"]
`

func TestParameterizedGlobalArtifactsInExitHandler(t *testing.T) {
// Test that parameterized global artifacts can be referenced in exit handlers
err := validate(logging.TestContext(t.Context()), parameterizedGlobalArtifactsWorkflow)
require.NoError(t, err)
}

func TestParameterizedGlobalArtifactsWithWorkflowTemplateRef(t *testing.T) {
ctx := logging.TestContext(t.Context())

// Create the workflow template with parameterized artifacts
err := createWorkflowTemplateFromSpec(ctx, parameterizedArtifactsWorkflowTemplate)
require.NoError(t, err)

// Test that parameterized global artifacts from workflow template refs can be referenced in exit handlers
err = validate(ctx, parameterizedGlobalArtifactsWithWorkflowTemplateRef)
require.NoError(t, err)
}

var workflowWithoutParameterizedArtifacts = `
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: test-no-parameterized-
spec:
entrypoint: main
onExit: exit-handler
templates:
- name: main
container:
image: alpine:latest
command: [sh, -c]
args: ["echo 'test data' > /tmp/result.txt"]
outputs:
artifacts:
- name: result
globalName: simple-artifact
path: /tmp/result.txt
archive:
none: {}
- name: exit-handler
container:
image: alpine:latest
command: [sh, -c]
args: ["echo 'Access artifact: {{workflow.outputs.artifacts.nonexistent}}'"]
`

func TestWorkflowWithoutParameterizedArtifactsFails(t *testing.T) {
// Test that referencing non-existent global artifacts still fails validation when there are no parameterized artifacts
err := validate(logging.TestContext(t.Context()), workflowWithoutParameterizedArtifacts)
require.Error(t, err)
require.Contains(t, err.Error(), "failed to resolve {{workflow.outputs.artifacts.nonexistent}}")
}
Loading