Skip to content

Commit

Permalink
implementing finally at the pipeline level
Browse files Browse the repository at this point in the history
We can now specify a list of tasks needs to be executed just before
pipeline exits (either after finishing all non-final tasks successfully or after
a single failure)

Most useful for tasks such as report test results, cleanup cluster resources, etc

```
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: pipeline-with-final-tasks
spec:
  tasks:
    - name: pre-work
      taskRef:
        Name: some-pre-work
    - name: unit-test
      taskRef:
        Name: run-unit-test
      runAfter:
        - pre-work
    - name: integration-test
      taskRef:
        Name: run-integration-test
      runAfter:
        - unit-test
  finally:
    - name: cleanup-test
      taskRef:
        Name: cleanup-cluster
    - name: report-results
      taskRef:
        Name: report-test-results
```
  • Loading branch information
pritidesai committed Apr 18, 2020
1 parent 25b2446 commit 9279df2
Show file tree
Hide file tree
Showing 17 changed files with 1,120 additions and 147 deletions.
236 changes: 236 additions & 0 deletions examples/v1beta1/pipelineruns/pipelinerun-with-final-tasks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
# Task producing success by exiting with 0
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: successful-task
spec:
steps:
- name: success
image: ubuntu
script: |
exit 0
---

apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: pipeline-with-final-tasks
spec:
tasks:
- name: pre-work
taskRef:
Name: successful-task
- name: unit-test
taskRef:
Name: successful-task
runAfter:
- pre-work
- name: integration-test
taskRef:
Name: successful-task
runAfter:
- unit-test
finally:
- name: cleanup-test
taskRef:
Name: successful-task
- name: report-results
taskRef:
Name: successful-task
---

apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: pipelinerun-with-final-tasks
spec:
pipelineRef:
name: pipeline-with-final-tasks
---

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: sum
annotations:
description: |
A simple task that sums the two provided integers
spec:
params:
- name: a
type: string
default: "1"
description: The first integer
- name: b
type: string
default: "1"
description: The second integer
results:
- name: sum
description: The sum of the two provided integers
steps:
- name: sum
image: bash:latest
script: |
#!/usr/bin/env bash
echo -n $(( "$(params.a)" + "$(params.b)" )) | tee $(results.sum.path)
---

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: format-result
spec:
params:
- name: result
type: string
default: "0"
steps:
- name: print-sum
image: ubuntu
script: echo "*** Result = $(params.result) ***"
---

apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: sum-and-print-pipeline
spec:
params:
- name: a
type: string
default: "1"
- name: b
type: string
default: "1"
tasks:
- name: sum-inputs
taskRef:
name: sum
params:
- name: a
value: "$(params.a)"
- name: b
value: "$(params.b)"
finally:
- name: print-sum
taskRef:
name: format-result
params:
- name: result
value: "$(tasks.sum-inputs.results.sum)"
---

apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: sum-and-print-pipeline-run
spec:
pipelineRef:
name: sum-and-print-pipeline
params:
- name: a
value: "100"
- name: b
value: "1000"
---

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-workspace
spec:
resources:
requests:
storage: 16Mi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
---

apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
name: clone-app-repo-to-workspace
spec:
workspaces:
- name: shared-workspace
resources:
inputs:
- name: app-git
type: git
targetPath: application
steps:
- name: clone-app-repo-to-workspace
image: ubuntu
script: |
#!/usr/bin/env bash
set -xe
cp -avr $(resources.inputs.app-git.path)/ $(workspaces.shared-workspace.path)/
---

apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
name: cleanup-workspace
spec:
workspaces:
- name: shared-workspace
steps:
- name: cleanup-workspace
image: ubuntu
script: |
#!/usr/bin/env bash
set -xe
rm -rf $(workspaces.shared-workspace.path)/application/
---

apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
name: clone-into-workspace-and-cleanup-workspace
spec:
resources:
- name: app-git
type: git
workspaces:
- name: shared-workspace
tasks:
- name: clone-app-source
taskRef:
name: clone-app-repo-to-workspace
workspaces:
- name: shared-workspace
workspace: shared-workspace
resources:
inputs:
- name: app-git
resource: app-git
finally:
- name: cleanup-workspace
taskRef:
name: cleanup-workspace
workspaces:
- name: shared-workspace
workspace: shared-workspace
---

apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
name: write-and-cleanup-workspace
spec:
pipelineRef:
name: clone-into-workspace-and-cleanup-workspace
workspaces:
- name: shared-workspace
persistentVolumeClaim:
claimName: shared-workspace
resources:
- name: app-git
resourceSpec:
type: git
params:
- name: url
value: https://github.com/tektoncd/pipeline.git
---
46 changes: 46 additions & 0 deletions pkg/apis/pipeline/v1alpha1/pipeline_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ func (source *PipelineSpec) ConvertTo(ctx context.Context, sink *v1beta1.Pipelin
}
}
}
if len(source.Finally) > 0 {
sink.Finally = make([]v1beta1.FinalPipelineTask, len(source.Finally))
for i := range source.Finally {
if err := source.Finally[i].ConvertTo(ctx, &sink.Finally[i]); err != nil {
return err
}
}
}
return nil
}

Expand All @@ -72,6 +80,21 @@ func (source *PipelineTask) ConvertTo(ctx context.Context, sink *v1beta1.Pipelin
return nil
}

func (source *FinalPipelineTask) ConvertTo(ctx context.Context, sink *v1beta1.FinalPipelineTask) error {
sink.Name = source.Name
sink.TaskRef = source.TaskRef
if source.TaskSpec != nil {
sink.TaskSpec = &v1beta1.TaskSpec{}
if err := source.TaskSpec.ConvertTo(ctx, sink.TaskSpec); err != nil {
return err
}
}
sink.Resources = source.Resources
sink.Params = source.Params
sink.Workspaces = source.Workspaces
return nil
}

// ConvertFrom implements api.Convertible
func (sink *Pipeline) ConvertFrom(ctx context.Context, obj apis.Convertible) error {
switch source := obj.(type) {
Expand All @@ -96,6 +119,14 @@ func (sink *PipelineSpec) ConvertFrom(ctx context.Context, source v1beta1.Pipeli
}
}
}
if len(source.Finally) > 0 {
sink.Finally = make([]FinalPipelineTask, len(source.Finally))
for i := range source.Finally {
if err := sink.Finally[i].ConvertFrom(ctx, source.Finally[i]); err != nil {
return err
}
}
}
return nil
}

Expand All @@ -116,3 +147,18 @@ func (sink *PipelineTask) ConvertFrom(ctx context.Context, source v1beta1.Pipeli
sink.Workspaces = source.Workspaces
return nil
}

func (sink *FinalPipelineTask) ConvertFrom(ctx context.Context, source v1beta1.FinalPipelineTask) error {
sink.Name = source.Name
sink.TaskRef = source.TaskRef
if source.TaskSpec != nil {
sink.TaskSpec = &TaskSpec{}
if err := sink.TaskSpec.ConvertFrom(ctx, source.TaskSpec); err != nil {
return err
}
}
sink.Resources = source.Resources
sink.Params = source.Params
sink.Workspaces = source.Workspaces
return nil
}
8 changes: 8 additions & 0 deletions pkg/apis/pipeline/v1alpha1/pipeline_defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,12 @@ func (ps *PipelineSpec) SetDefaults(ctx context.Context) {
for i := range ps.Params {
ps.Params[i].SetDefaults(ctx)
}
for _, ft := range ps.Finally {
if ft.TaskRef.Kind == "" {
ft.TaskRef.Kind = NamespacedTaskKind
}
if ft.TaskSpec != nil {
ft.TaskSpec.SetDefaults(ctx)
}
}
}
33 changes: 33 additions & 0 deletions pkg/apis/pipeline/v1alpha1/pipeline_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ type PipelineSpec struct {
// Results are values that this pipeline can output once run
// +optional
Results []PipelineResult `json:"results,omitempty"`
// Finally declares the list of Tasks that execute just before leaving the Pipeline
// i.e. either after all Tasks are finished executing successfully
// or after a failure which would result in ending the Pipeline
Finally []FinalPipelineTask `json:"finally,omitempty"`
}

// PipelineResult used to describe the results of a pipeline
Expand Down Expand Up @@ -150,6 +154,35 @@ type PipelineTask struct {
Timeout *metav1.Duration `json:"timeout,omitempty"`
}

// FinalPipelineTask defines a final task in a Pipeline, passing inputs from both
// Params and from the output of non-final tasks.
type FinalPipelineTask struct {
// Name is the name of this task within the context of a Pipeline.
Name string `json:"name,omitempty"`

// TaskRef is a reference to a task definition.
// +optional
TaskRef *TaskRef `json:"taskRef,omitempty"`

// TaskSpec is specification of a task
// +optional
TaskSpec *TaskSpec `json:"taskSpec,omitempty"`

// Resources declares the resources given to this task as inputs and
// outputs.
// +optional
Resources *PipelineTaskResources `json:"resources,omitempty"`

// Parameters declares parameters passed to this task.
// +optional
Params []Param `json:"params,omitempty"`

// Workspaces maps workspaces from the pipeline spec to the workspaces
// declared in the Task.
// +optional
Workspaces []WorkspacePipelineTaskBinding `json:"workspaces,omitempty"`
}

func (pt PipelineTask) HashKey() string {
return pt.Name
}
Expand Down
Loading

0 comments on commit 9279df2

Please sign in to comment.