Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

access taskRun reason in addition to status in finally task #8127

Merged
merged 1 commit into from
Jul 18, 2024
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
3 changes: 2 additions & 1 deletion docs/variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ For instructions on using variable substitutions see the relevant section of [th
| `context.pipelineRun.namespace` | The namespace of the `PipelineRun` that this `Pipeline` is running in. |
| `context.pipelineRun.uid` | The uid of the `PipelineRun` that this `Pipeline` is running in. |
| `context.pipeline.name` | The name of this `Pipeline` . |
| `tasks.<pipelineTaskName>.status` | The execution status of the specified `pipelineTask`, only available in `finally` tasks. The execution status can be set to any one of the values (`Succeeded`, `Failed`, or `None`) described [here](pipelines.md#using-execution-status-of-pipelinetask) |
| `tasks.<pipelineTaskName>.status` | The execution status of the specified `pipelineTask`, only available in `finally` tasks. The execution status can be set to any one of the values (`Succeeded`, `Failed`, or `None`) described [here](pipelines.md#using-execution-status-of-pipelinetask). |
| `tasks.<pipelineTaskName>.reason` | The execution reason of the specified `pipelineTask`, only available in `finally` tasks. The reason can be set to any one of the values (`Failed`, `TaskRunCancelled`, `TaskRunTimeout`, `FailureIgnored`, etc ) described [here](taskruns.md#monitoring-execution-status). |
| `tasks.status` | An aggregate status of all the `pipelineTasks` under the `tasks` section (excluding the `finally` section). This variable is only available in the `finally` tasks and can have any one of the values (`Succeeded`, `Failed`, `Completed`, or `None`) described [here](pipelines.md#using-aggregate-execution-status-of-all-tasks). |
| `context.pipelineTask.retries` | The retries of this `PipelineTask`. |
| `tasks.<taskName>.outputs.<artifactName>` | The value of a specific output artifact of the `Task` |
Expand Down
44 changes: 43 additions & 1 deletion examples/v1/pipelineruns/beta/ignore-task-error.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,30 @@ spec:
- name: write
image: docker.io/library/alpine
script: |
#!/usr/bin/env sh
echo "this is a failing task"
exit 1
exit 1;
- name: echo-continue-with-matrix
onError: continue
matrix:
params:
- name: param1
value:
- "foo"
- "bar"
taskSpec:
params:
- name: param1
steps:
- name: write
image: docker.io/library/alpine
script: |
#!/usr/bin/env sh
echo "this is a failing task if param1 is set bar"
if [[ $(params.param1) == "bar" ]]; then
exit 1;
fi
exit 0
- name: echo
runAfter:
- echo-continue
Expand All @@ -22,4 +44,24 @@ spec:
- name: write
image: docker.io/library/alpine
script: |
#!/usr/bin/env sh
echo "this is a success task"
finally:
- name: verify-task-reason # this task verifies the reason of failure ignored task, it fails if verification fails
params:
- name: echo-continue-task-reason
value: $(tasks.echo-continue.reason)
- name: echo-continue-with-matrix-task-reason
value: $(tasks.echo-continue-with-matrix.reason)
taskSpec:
steps:
- name: verify-task-reason
image: docker.io/library/alpine
script: |
#!/usr/bin/env sh
if [[ $(params.echo-continue-task-reason) != "FailureIgnored" ]]; then
exit 1;
fi
if [[ $(params.echo-continue-with-matrix-task-reason) != "FailureIgnored" ]]; then
exit 1;
fi
24 changes: 18 additions & 6 deletions pkg/apis/pipeline/v1/pipeline_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,9 +513,13 @@ func (pt *PipelineTask) GetVarSubstitutionExpressions() []string {
return allExpressions
}

// containsExecutionStatusRef checks if a specified param has a reference to execution status or reason
// $(tasks.<task-name>.status), $(tasks.status), or $(tasks.<task-name>.reason)
func containsExecutionStatusRef(p string) bool {
if strings.HasPrefix(p, "tasks.") && strings.HasSuffix(p, ".status") {
return true
if strings.HasPrefix(p, "tasks.") {
if strings.HasSuffix(p, ".status") || strings.HasSuffix(p, ".reason") {
return true
}
}
return false
}
Expand Down Expand Up @@ -589,7 +593,7 @@ func containsExecutionStatusReferences(expressions []string) bool {
if !LooksLikeContainsResultRefs(expressions) {
for _, e := range expressions {
// check if it contains context variable accessing execution status - $(tasks.taskname.status)
// or an aggregate status - $(tasks.status)
// or an aggregate status - $(tasks.status) or reason - $(tasks.taskname.reason)
if containsExecutionStatusRef(e) {
return true
}
Expand All @@ -606,17 +610,25 @@ func validateExecutionStatusVariablesExpressions(expressions []string, ptNames s
if expression == PipelineTasksAggregateStatus {
continue
}
// check if it contains context variable accessing execution status - $(tasks.taskname.status)
// check if it contains context variable accessing execution status - $(tasks.taskname.status) | $(tasks.taskname.reason)
if containsExecutionStatusRef(expression) {
// strip tasks. and .status from tasks.taskname.status to further verify task name
pt := strings.TrimSuffix(strings.TrimPrefix(expression, "tasks."), ".status")
var pt string
if strings.HasSuffix(expression, ".status") {
// strip tasks. and .status from tasks.taskname.status to further verify task name
pt = strings.TrimSuffix(strings.TrimPrefix(expression, "tasks."), ".status")
}
if strings.HasSuffix(expression, ".reason") {
// strip tasks. and .reason from tasks.taskname.reason to further verify task name
pt = strings.TrimSuffix(strings.TrimPrefix(expression, "tasks."), ".reason")
}
// report an error if the task name does not exist in the list of dag tasks
if !ptNames.Has(pt) {
errs = errs.Also(apis.ErrInvalidValue(fmt.Sprintf("pipeline task %s is not defined in the pipeline", pt), fieldPath))
}
}
}
}

return errs
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/apis/pipeline/v1/pipeline_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3866,13 +3866,19 @@ func TestPipelineTasksExecutionStatus(t *testing.T) {
TaskRef: &TaskRef{Name: "bar-task"},
Params: Params{{
Name: "foo-status", Value: ParamValue{Type: ParamTypeString, StringVal: "$(tasks.foo.status)"},
}, {
Name: "foo-reason", Value: ParamValue{Type: ParamTypeString, StringVal: "$(tasks.foo.reason)"},
}, {
Name: "tasks-status", Value: ParamValue{Type: ParamTypeString, StringVal: "$(tasks.status)"},
}},
When: WhenExpressions{{
Input: "$(tasks.foo.status)",
Operator: selection.In,
Values: []string{"Failure"},
}, {
Input: "$(tasks.foo.reason)",
Operator: selection.In,
Values: []string{"Failed"},
}, {
Input: "$(tasks.status)",
Operator: selection.In,
Expand Down
21 changes: 16 additions & 5 deletions pkg/apis/pipeline/v1beta1/pipeline_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -495,9 +495,13 @@ func (pt *PipelineTask) extractAllParams() Params {
return allParams
}

// containsExecutionStatusRef checks if a specified param has a reference to execution status or reason
// $(tasks.<task-name>.status), $(tasks.status), or $(tasks.<task-name>.reason)
func containsExecutionStatusRef(p string) bool {
if strings.HasPrefix(p, "tasks.") && strings.HasSuffix(p, ".status") {
return true
if strings.HasPrefix(p, "tasks.") {
if strings.HasSuffix(p, ".status") || strings.HasSuffix(p, ".reason") {
return true
}
}
return false
}
Expand Down Expand Up @@ -588,10 +592,17 @@ func validateExecutionStatusVariablesExpressions(expressions []string, ptNames s
if expression == PipelineTasksAggregateStatus {
continue
}
// check if it contains context variable accessing execution status - $(tasks.taskname.status)
// check if it contains context variable accessing execution status - $(tasks.taskname.status) | $(tasks.taskname.reason)
if containsExecutionStatusRef(expression) {
// strip tasks. and .status from tasks.taskname.status to further verify task name
pt := strings.TrimSuffix(strings.TrimPrefix(expression, "tasks."), ".status")
var pt string
if strings.HasSuffix(expression, ".status") {
// strip tasks. and .status from tasks.taskname.status to further verify task name
pt = strings.TrimSuffix(strings.TrimPrefix(expression, "tasks."), ".status")
}
if strings.HasSuffix(expression, ".reason") {
// strip tasks. and .reason from tasks.taskname.reason to further verify task name
pt = strings.TrimSuffix(strings.TrimPrefix(expression, "tasks."), ".reason")
}
// report an error if the task name does not exist in the list of dag tasks
if !ptNames.Has(pt) {
errs = errs.Also(apis.ErrInvalidValue(fmt.Sprintf("pipeline task %s is not defined in the pipeline", pt), fieldPath))
Expand Down
6 changes: 6 additions & 0 deletions pkg/apis/pipeline/v1beta1/pipeline_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3785,13 +3785,19 @@ func TestPipelineTasksExecutionStatus(t *testing.T) {
TaskRef: &TaskRef{Name: "bar-task"},
Params: Params{{
Name: "foo-status", Value: ParamValue{Type: ParamTypeString, StringVal: "$(tasks.foo.status)"},
}, {
Name: "foo-reason", Value: ParamValue{Type: ParamTypeString, StringVal: "$(tasks.foo.reason)"},
}, {
Name: "tasks-status", Value: ParamValue{Type: ParamTypeString, StringVal: "$(tasks.status)"},
}},
WhenExpressions: WhenExpressions{{
Input: "$(tasks.foo.status)",
Operator: selection.In,
Values: []string{"Failure"},
}, {
Input: "$(tasks.foo.reason)",
Operator: selection.In,
Values: []string{"Failed"},
}, {
Input: "$(tasks.status)",
Operator: selection.In,
Expand Down
31 changes: 31 additions & 0 deletions pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,37 @@ func (t ResolvedPipelineTask) IsCustomTask() bool {
return t.CustomTask
}

// getReason returns the latest reason if the run has completed successfully
// If the PipelineTask has a Matrix, getReason returns the failure reason for any failure
pritidesai marked this conversation as resolved.
Show resolved Hide resolved
// otherwise, it returns an empty string
func (t ResolvedPipelineTask) getReason() string {
if t.IsCustomTask() {
if len(t.CustomRuns) == 0 {
return ""
}
for _, run := range t.CustomRuns {
if !run.IsSuccessful() && len(run.Status.Conditions) >= 1 {
return run.Status.Conditions[0].Reason
}
}
if len(t.CustomRuns) >= 1 && len(t.CustomRuns[0].Status.Conditions) >= 1 {
return t.CustomRuns[0].Status.Conditions[0].Reason
}
}
if len(t.TaskRuns) == 0 {
return ""
}
for _, taskRun := range t.TaskRuns {
if !taskRun.IsSuccessful() && len(taskRun.Status.Conditions) >= 1 {
return taskRun.Status.Conditions[0].Reason
}
}
if len(t.TaskRuns) >= 1 && len(t.TaskRuns[0].Status.Conditions) >= 1 {
return t.TaskRuns[0].Status.Conditions[0].Reason
}
return ""
pritidesai marked this conversation as resolved.
Show resolved Hide resolved
}

// isSuccessful returns true only if the run has completed successfully
// If the PipelineTask has a Matrix, isSuccessful returns true if all runs have completed successfully
func (t ResolvedPipelineTask) isSuccessful() bool {
Expand Down
Loading