Skip to content

Commit

Permalink
Add functionality to set task run spec
Browse files Browse the repository at this point in the history
Currently it is not possible to set task run specs on each individual tasks. This PR aims to fix that and give the user more flexibility to set podTemplate for each task.

Co-Authored-By: Daniel Helfand <helfand.4@gmail.com>
  • Loading branch information
NikeNano and danielhelfand committed May 4, 2020
1 parent 94f7092 commit 5440c4e
Show file tree
Hide file tree
Showing 9 changed files with 431 additions and 3 deletions.
23 changes: 23 additions & 0 deletions docs/pipelineruns.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ weight: 4
- [Speciying `Parameters`](#specifying-parameters)
- [Specifying custom `ServiceAccount` credentials](#specifying-custom-serviceaccount-credentials)
- [Mapping `ServiceAccount` credentials to `Tasks`](#mapping-serviceaccount-credentials-to-tasks)
- [Specifying `TaskRunSpecs`](#specifying-task-run-specs)
- [Specifying a `Pod` template](#specifying-a-pod-template)
- [Specifying `Workspaces`](#specifying-workspaces)
- [Specifying `LimitRange` values](#specifying-limitrange-values)
Expand Down Expand Up @@ -51,6 +52,7 @@ A `PipelineRun` definition supports the following fields:
object that supplies specific execution credentials for the `Pipeline`.
- [`serviceAccountNames`](#mapping-serviceaccount-credentials-to-tasks) - Maps specific `serviceAccountName` values
to `Tasks` in the `Pipeline`. This overrides the credentials set for the entire `Pipeline`.
- [`taskRunSpec`](#specifying-task-run-specs) - Specifies a list of `PipelineRunTaskSpec` which allows for setting `ServiceAccountName` and [`Pod` template](./podtemplates.md) for each task. This overrides the `Pod` template set for the entire `Pipeline`.
- [`timeout`](#configuring-a-failure-timeout) - Specifies the timeout before the `PipelineRun` fails.
- [`podTemplate`](#pod-template) - Specifies a [`Pod` template](./podtemplates.md) to use as the basis
for the configuration of the `Pod` that executes each `Task`.
Expand Down Expand Up @@ -349,3 +351,24 @@ Except as otherwise noted, the content of this page is licensed under the
[Creative Commons Attribution 4.0 License](https://creativecommons.org/licenses/by/4.0/),
and code samples are licensed under the
[Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0).

## Specifying task run specs

Specifies a list of `PipelineRunTaskSpec` which contains `TaskServiceAccountName`,`TaskPodTemplate` and `TaskName`. Mapping the specs to the corresponding `Task` based upon the `TaskName` a PipelineTask will run with the configured `TaskServiceAccountName` and `TaskPodTemplate` overwriting the pipeline wide [`ServiceAccountName`](#service-account) and [`podTemplate`](#pod-template) configuration, for example:

```yaml
spec:
podTemplate:
securityContext:
runAsUser: 1000
runAsGroup: 2000
fsGroup: 3000
taskRunSpecs:
- taskName: build-task
taskServiceAccountName: sa-for-build
taskPodTemplate:
nodeSelector:
disktype: ssd
```

If used with this `Pipeline`, `build-task` will use the task specific pod template (where `nodeSelector` has `disktype` equal to `ssd`).
86 changes: 86 additions & 0 deletions examples/v1beta1/pipelineruns/pipelinerun-taskrunspecs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: add-task-taskspec
spec:
params:
- name: first
description: the first operand
- name: second
description: the second operand
results:
- name: sum
description: the sum of the first and second operand
steps:
- name: add
image: alpine
env:
- name: OP1
value: $(params.first)
- name: OP2
value: $(params.second)
command: ["/bin/sh", "-c"]
args:
- echo -n $((${OP1}+${OP2})) | tee $(results.sum.path);
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: add-pipeline-taskspec
spec:
params:
- name: first
description: the first operand
- name: second
description: the second operand
- name: third
description: the third operand
tasks:
- name: first-add-taskspec
taskRef:
name: add-task-taskspec
params:
- name: first
value: $(params.first)
- name: second
value: $(params.second)
- name: second-add-taskspec
taskRef:
name: add-task-taskspec
params:
- name: first
value: $(tasks.first-add-taskspec.results.sum)
- name: second
value: $(params.third)
results:
- name: sum
description: the sum of all three operands
value: $(tasks.second-add-taskspec.results.sum)
- name: partial-sum
description: the sum of first two operands
value: $(tasks.first-add-taskspec.results.sum)
- name: all-sum
description: the sum of everything
value: $(tasks.second-add-taskspec.results.sum)-$(tasks.first-add-taskspec.results.sum)
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: task-spec-pipeline
spec:
pipelineRef:
name: add-pipeline-taskspec
taskRunSpecs:
- pipelineTaskName: first-add-taskspec
taskServiceAccountName: 'default'
- pipelineTaskName: second-add-taskspec
taskPodTemplate:
nodeSelector:
disktype: ssd
params:
- name: first
value: "2"
- name: second
value: "10"
- name: third
value: "10"
24 changes: 24 additions & 0 deletions pkg/apis/pipeline/v1alpha1/pipelinerun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ type PipelineRunSpec struct {
// with those declared in the pipeline.
// +optional
Workspaces []WorkspaceBinding `json:"workspaces,omitempty"`
// TaskRunSpecs holds a set of task specific specs
// +optional
TaskRunSpecs []PipelineTaskRunSpec `json:"taskRunSpecs,omitempty"`
}

// PipelineRunSpecStatus defines the pipelinerun spec status the user can provide
Expand Down Expand Up @@ -217,3 +220,24 @@ func (pr *PipelineRun) HasVolumeClaimTemplate() bool {
}
return false
}

// PipelineTaskRunSpec holds task specific specs
type PipelineTaskRunSpec struct {
PipelineTaskName string `json:"pipelineTaskName,omitempty"`
TaskServiceAccountName string `json:"taskServiceAccountName,omitempty"`
TaskPodTemplate *PodTemplate `json:"taskPodTemplate,omitempty"`
}

// GetTaskRunSpecs returns the task specific spec for a given
// PipelineTask if configured, otherwise it returns the PipelineRun's default.
func (pr *PipelineRun) GetTaskRunSpecs(pipelineTaskName string) (string, *PodTemplate) {
serviceAccountName := pr.GetServiceAccountName(pipelineTaskName)
taskPodTemplate := pr.Spec.PodTemplate
for _, task := range pr.Spec.TaskRunSpecs {
if task.PipelineTaskName == pipelineTaskName {
taskPodTemplate = task.TaskPodTemplate
serviceAccountName = task.TaskServiceAccountName
}
}
return serviceAccountName, taskPodTemplate
}
107 changes: 107 additions & 0 deletions pkg/apis/pipeline/v1alpha1/pipelinerun_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,3 +281,110 @@ func TestPipelineRunGetServiceAccountName(t *testing.T) {
}
}
}

func TestPipelineRunGetPodSpecSABackcompatibility(t *testing.T) {
for _, tt := range []struct {
name string
pr *v1alpha1.PipelineRun
expectedSAs map[string]string
}{
{
name: "test backward compatibility",
pr: &v1alpha1.PipelineRun{
ObjectMeta: metav1.ObjectMeta{Name: "pr"},
Spec: v1alpha1.PipelineRunSpec{
PipelineRef: &v1alpha1.PipelineRef{Name: "prs"},
ServiceAccountName: "defaultSA",
ServiceAccountNames: []v1alpha1.PipelineRunSpecServiceAccountName{{
TaskName: "taskName", ServiceAccountName: "taskSA",
}},
TaskRunSpecs: []v1alpha1.PipelineTaskRunSpec{{
PipelineTaskName: "taskName",
TaskServiceAccountName: "newTaskSA",
}},
},
},
expectedSAs: map[string]string{
"unknown": "defaultSA",
"taskName": "newTaskSA",
},
},
{
name: "mixed default SA backward compatibility",
pr: &v1alpha1.PipelineRun{
ObjectMeta: metav1.ObjectMeta{Name: "pr"},
Spec: v1alpha1.PipelineRunSpec{
PipelineRef: &v1alpha1.PipelineRef{Name: "prs"},
ServiceAccountName: "defaultSA",
TaskRunSpecs: []v1alpha1.PipelineTaskRunSpec{{
PipelineTaskName: "taskNameOne",
TaskServiceAccountName: "TaskSAOne",
}, {
PipelineTaskName: "taskNameTwo",
TaskServiceAccountName: "newTaskTwo",
}},
},
},
expectedSAs: map[string]string{
"unknown": "defaultSA",
"taskNameOne": "TaskSAOne",
"taskNameTwo": "newTaskTwo",
},
},
} {
for taskName, expected := range tt.expectedSAs {
t.Run(tt.name, func(t *testing.T) {
sa, _ := tt.pr.GetTaskRunSpecs(taskName)
if expected != sa {
t.Errorf("%s: wrong service account: got: %v, want: %v", tt.name, sa, expected)
}
})
}
}
}

func TestPipelineRunGetPodSpec(t *testing.T) {
for _, tt := range []struct {
name string
pr *v1alpha1.PipelineRun
expectedPodTemplates map[string][]string
}{
{
name: "mix default and none default",
pr: &v1alpha1.PipelineRun{
ObjectMeta: metav1.ObjectMeta{Name: "pr"},
Spec: v1alpha1.PipelineRunSpec{
PodTemplate: &v1alpha1.PodTemplate{SchedulerName: "scheduleTest"},
PipelineRef: &v1alpha1.PipelineRef{Name: "prs"},
ServiceAccountName: "defaultSA",
TaskRunSpecs: []v1alpha1.PipelineTaskRunSpec{{
PipelineTaskName: "taskNameOne",
TaskServiceAccountName: "TaskSAOne",
TaskPodTemplate: &v1alpha1.PodTemplate{SchedulerName: "scheduleTestOne"},
}, {
PipelineTaskName: "taskNameTwo",
TaskServiceAccountName: "newTaskTwo",
TaskPodTemplate: &v1alpha1.PodTemplate{SchedulerName: "scheduleTestTwo"},
}},
},
},
expectedPodTemplates: map[string][]string{
"unknown": {"scheduleTest", "defaultSA"},
"taskNameOne": {"scheduleTestOne", "TaskSAOne"},
"taskNameTwo": {"scheduleTestTwo", "newTaskTwo"},
},
},
} {
for taskName, values := range tt.expectedPodTemplates {
t.Run(tt.name, func(t *testing.T) {
sa, taskPodTemplate := tt.pr.GetTaskRunSpecs(taskName)
if values[0] != taskPodTemplate.SchedulerName {
t.Errorf("%s: wrong task podtemplate scheduler name: got: %v, want: %v", tt.name, taskPodTemplate.SchedulerName, values[0])
}
if values[1] != sa {
t.Errorf("%s: wrong service account: got: %v, want: %v", tt.name, sa, values[1])
}
})
}
}
}
28 changes: 28 additions & 0 deletions pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions pkg/apis/pipeline/v1beta1/pipelinerun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ type PipelineRunSpec struct {
// with those declared in the pipeline.
// +optional
Workspaces []WorkspaceBinding `json:"workspaces,omitempty"`
// TaskRunSpecs holds a set of runtime specs
// +optional
TaskRunSpecs []PipelineTaskRunSpec `json:"taskRunSpecs,omitempty"`
}

// PipelineRunSpecStatus defines the pipelinerun spec status the user can provide
Expand Down Expand Up @@ -310,3 +313,25 @@ type PipelineRunList struct {
type PipelineTaskRun struct {
Name string `json:"name,omitempty"`
}

// PipelineTaskRunSpec can be used to configure specific
// specs for a concrete Task
type PipelineTaskRunSpec struct {
PipelineTaskName string `json:"pipelineTaskName,omitempty"`
TaskServiceAccountName string `json:"taskServiceAccountName,omitempty"`
TaskPodTemplate *PodTemplate `json:"taskPodTemplate,omitempty"`
}

// GetTaskRunSpecs returns the task specific spec for a given
// PipelineTask if configured, otherwise it returns the PipelineRun's default.
func (pr *PipelineRun) GetTaskRunSpecs(pipelineTaskName string) (string, *PodTemplate) {
serviceAccountName := pr.GetServiceAccountName(pipelineTaskName)
taskPodTemplate := pr.Spec.PodTemplate
for _, task := range pr.Spec.TaskRunSpecs {
if task.PipelineTaskName == pipelineTaskName {
taskPodTemplate = task.TaskPodTemplate
serviceAccountName = task.TaskServiceAccountName
}
}
return serviceAccountName, taskPodTemplate
}
Loading

0 comments on commit 5440c4e

Please sign in to comment.