Skip to content

Commit 2fcbfae

Browse files
NikeNanodanielhelfand
authored andcommitted
Add functionality to set task run spec
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 <[email protected]>
1 parent 8bac7f3 commit 2fcbfae

File tree

9 files changed

+431
-3
lines changed

9 files changed

+431
-3
lines changed

docs/pipelineruns.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ weight: 4
1313
- [Speciying `Parameters`](#specifying-parameters)
1414
- [Specifying custom `ServiceAccount` credentials](#specifying-custom-serviceaccount-credentials)
1515
- [Mapping `ServiceAccount` credentials to `Tasks`](#mapping-serviceaccount-credentials-to-tasks)
16+
- [Specifying `TaskRunSpecs`](#specifying-task-run-specs)
1617
- [Specifying a `Pod` template](#specifying-a-pod-template)
1718
- [Specifying `Workspaces`](#specifying-workspaces)
1819
- [Specifying `LimitRange` values](#specifying-limitrange-values)
@@ -58,6 +59,7 @@ A `PipelineRun` definition supports the following fields:
5859
object that supplies specific execution credentials for the `Pipeline`.
5960
- [`serviceAccountNames`](#mapping-serviceaccount-credentials-to-tasks) - Maps specific `serviceAccountName` values
6061
to `Tasks` in the `Pipeline`. This overrides the credentials set for the entire `Pipeline`.
62+
- [`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`.
6163
- [`timeout`](#configuring-a-failure-timeout) - Specifies the timeout before the `PipelineRun` fails.
6264
- [`podTemplate`](#pod-template) - Specifies a [`Pod` template](./podtemplates.md) to use as the basis
6365
for the configuration of the `Pod` that executes each `Task`.
@@ -357,3 +359,24 @@ Except as otherwise noted, the content of this page is licensed under the
357359
[Creative Commons Attribution 4.0 License](https://creativecommons.org/licenses/by/4.0/),
358360
and code samples are licensed under the
359361
[Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0).
362+
363+
## Specifying task run specs
364+
365+
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:
366+
367+
```yaml
368+
spec:
369+
podTemplate:
370+
securityContext:
371+
runAsUser: 1000
372+
runAsGroup: 2000
373+
fsGroup: 3000
374+
taskRunSpecs:
375+
- taskName: build-task
376+
taskServiceAccountName: sa-for-build
377+
taskPodTemplate:
378+
nodeSelector:
379+
disktype: ssd
380+
```
381+
382+
If used with this `Pipeline`, `build-task` will use the task specific pod template (where `nodeSelector` has `disktype` equal to `ssd`).
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
apiVersion: tekton.dev/v1beta1
2+
kind: Task
3+
metadata:
4+
name: add-task-taskspec
5+
spec:
6+
params:
7+
- name: first
8+
description: the first operand
9+
- name: second
10+
description: the second operand
11+
results:
12+
- name: sum
13+
description: the sum of the first and second operand
14+
steps:
15+
- name: add
16+
image: alpine
17+
env:
18+
- name: OP1
19+
value: $(params.first)
20+
- name: OP2
21+
value: $(params.second)
22+
command: ["/bin/sh", "-c"]
23+
args:
24+
- echo -n $((${OP1}+${OP2})) | tee $(results.sum.path);
25+
---
26+
apiVersion: tekton.dev/v1beta1
27+
kind: Pipeline
28+
metadata:
29+
name: add-pipeline-taskspec
30+
spec:
31+
params:
32+
- name: first
33+
description: the first operand
34+
- name: second
35+
description: the second operand
36+
- name: third
37+
description: the third operand
38+
tasks:
39+
- name: first-add-taskspec
40+
taskRef:
41+
name: add-task-taskspec
42+
params:
43+
- name: first
44+
value: $(params.first)
45+
- name: second
46+
value: $(params.second)
47+
- name: second-add-taskspec
48+
taskRef:
49+
name: add-task-taskspec
50+
params:
51+
- name: first
52+
value: $(tasks.first-add-taskspec.results.sum)
53+
- name: second
54+
value: $(params.third)
55+
results:
56+
- name: sum
57+
description: the sum of all three operands
58+
value: $(tasks.second-add-taskspec.results.sum)
59+
- name: partial-sum
60+
description: the sum of first two operands
61+
value: $(tasks.first-add-taskspec.results.sum)
62+
- name: all-sum
63+
description: the sum of everything
64+
value: $(tasks.second-add-taskspec.results.sum)-$(tasks.first-add-taskspec.results.sum)
65+
---
66+
apiVersion: tekton.dev/v1beta1
67+
kind: PipelineRun
68+
metadata:
69+
name: task-spec-pipeline
70+
spec:
71+
pipelineRef:
72+
name: add-pipeline-taskspec
73+
taskRunSpecs:
74+
- pipelineTaskName: first-add-taskspec
75+
taskServiceAccountName: 'default'
76+
- pipelineTaskName: second-add-taskspec
77+
taskPodTemplate:
78+
nodeSelector:
79+
disktype: ssd
80+
params:
81+
- name: first
82+
value: "2"
83+
- name: second
84+
value: "10"
85+
- name: third
86+
value: "10"

pkg/apis/pipeline/v1alpha1/pipelinerun_types.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ type PipelineRunSpec struct {
9191
// with those declared in the pipeline.
9292
// +optional
9393
Workspaces []WorkspaceBinding `json:"workspaces,omitempty"`
94+
// TaskRunSpecs holds a set of task specific specs
95+
// +optional
96+
TaskRunSpecs []PipelineTaskRunSpec `json:"taskRunSpecs,omitempty"`
9497
}
9598

9699
// PipelineRunSpecStatus defines the pipelinerun spec status the user can provide
@@ -217,3 +220,24 @@ func (pr *PipelineRun) HasVolumeClaimTemplate() bool {
217220
}
218221
return false
219222
}
223+
224+
// PipelineTaskRunSpec holds task specific specs
225+
type PipelineTaskRunSpec struct {
226+
PipelineTaskName string `json:"pipelineTaskName,omitempty"`
227+
TaskServiceAccountName string `json:"taskServiceAccountName,omitempty"`
228+
TaskPodTemplate *PodTemplate `json:"taskPodTemplate,omitempty"`
229+
}
230+
231+
// GetTaskRunSpecs returns the task specific spec for a given
232+
// PipelineTask if configured, otherwise it returns the PipelineRun's default.
233+
func (pr *PipelineRun) GetTaskRunSpecs(pipelineTaskName string) (string, *PodTemplate) {
234+
serviceAccountName := pr.GetServiceAccountName(pipelineTaskName)
235+
taskPodTemplate := pr.Spec.PodTemplate
236+
for _, task := range pr.Spec.TaskRunSpecs {
237+
if task.PipelineTaskName == pipelineTaskName {
238+
taskPodTemplate = task.TaskPodTemplate
239+
serviceAccountName = task.TaskServiceAccountName
240+
}
241+
}
242+
return serviceAccountName, taskPodTemplate
243+
}

pkg/apis/pipeline/v1alpha1/pipelinerun_types_test.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,3 +282,110 @@ func TestPipelineRunGetServiceAccountName(t *testing.T) {
282282
}
283283
}
284284
}
285+
286+
func TestPipelineRunGetPodSpecSABackcompatibility(t *testing.T) {
287+
for _, tt := range []struct {
288+
name string
289+
pr *v1alpha1.PipelineRun
290+
expectedSAs map[string]string
291+
}{
292+
{
293+
name: "test backward compatibility",
294+
pr: &v1alpha1.PipelineRun{
295+
ObjectMeta: metav1.ObjectMeta{Name: "pr"},
296+
Spec: v1alpha1.PipelineRunSpec{
297+
PipelineRef: &v1alpha1.PipelineRef{Name: "prs"},
298+
ServiceAccountName: "defaultSA",
299+
ServiceAccountNames: []v1alpha1.PipelineRunSpecServiceAccountName{{
300+
TaskName: "taskName", ServiceAccountName: "taskSA",
301+
}},
302+
TaskRunSpecs: []v1alpha1.PipelineTaskRunSpec{{
303+
PipelineTaskName: "taskName",
304+
TaskServiceAccountName: "newTaskSA",
305+
}},
306+
},
307+
},
308+
expectedSAs: map[string]string{
309+
"unknown": "defaultSA",
310+
"taskName": "newTaskSA",
311+
},
312+
},
313+
{
314+
name: "mixed default SA backward compatibility",
315+
pr: &v1alpha1.PipelineRun{
316+
ObjectMeta: metav1.ObjectMeta{Name: "pr"},
317+
Spec: v1alpha1.PipelineRunSpec{
318+
PipelineRef: &v1alpha1.PipelineRef{Name: "prs"},
319+
ServiceAccountName: "defaultSA",
320+
TaskRunSpecs: []v1alpha1.PipelineTaskRunSpec{{
321+
PipelineTaskName: "taskNameOne",
322+
TaskServiceAccountName: "TaskSAOne",
323+
}, {
324+
PipelineTaskName: "taskNameTwo",
325+
TaskServiceAccountName: "newTaskTwo",
326+
}},
327+
},
328+
},
329+
expectedSAs: map[string]string{
330+
"unknown": "defaultSA",
331+
"taskNameOne": "TaskSAOne",
332+
"taskNameTwo": "newTaskTwo",
333+
},
334+
},
335+
} {
336+
for taskName, expected := range tt.expectedSAs {
337+
t.Run(tt.name, func(t *testing.T) {
338+
sa, _ := tt.pr.GetTaskRunSpecs(taskName)
339+
if expected != sa {
340+
t.Errorf("%s: wrong service account: got: %v, want: %v", tt.name, sa, expected)
341+
}
342+
})
343+
}
344+
}
345+
}
346+
347+
func TestPipelineRunGetPodSpec(t *testing.T) {
348+
for _, tt := range []struct {
349+
name string
350+
pr *v1alpha1.PipelineRun
351+
expectedPodTemplates map[string][]string
352+
}{
353+
{
354+
name: "mix default and none default",
355+
pr: &v1alpha1.PipelineRun{
356+
ObjectMeta: metav1.ObjectMeta{Name: "pr"},
357+
Spec: v1alpha1.PipelineRunSpec{
358+
PodTemplate: &v1alpha1.PodTemplate{SchedulerName: "scheduleTest"},
359+
PipelineRef: &v1alpha1.PipelineRef{Name: "prs"},
360+
ServiceAccountName: "defaultSA",
361+
TaskRunSpecs: []v1alpha1.PipelineTaskRunSpec{{
362+
PipelineTaskName: "taskNameOne",
363+
TaskServiceAccountName: "TaskSAOne",
364+
TaskPodTemplate: &v1alpha1.PodTemplate{SchedulerName: "scheduleTestOne"},
365+
}, {
366+
PipelineTaskName: "taskNameTwo",
367+
TaskServiceAccountName: "newTaskTwo",
368+
TaskPodTemplate: &v1alpha1.PodTemplate{SchedulerName: "scheduleTestTwo"},
369+
}},
370+
},
371+
},
372+
expectedPodTemplates: map[string][]string{
373+
"unknown": {"scheduleTest", "defaultSA"},
374+
"taskNameOne": {"scheduleTestOne", "TaskSAOne"},
375+
"taskNameTwo": {"scheduleTestTwo", "newTaskTwo"},
376+
},
377+
},
378+
} {
379+
for taskName, values := range tt.expectedPodTemplates {
380+
t.Run(tt.name, func(t *testing.T) {
381+
sa, taskPodTemplate := tt.pr.GetTaskRunSpecs(taskName)
382+
if values[0] != taskPodTemplate.SchedulerName {
383+
t.Errorf("%s: wrong task podtemplate scheduler name: got: %v, want: %v", tt.name, taskPodTemplate.SchedulerName, values[0])
384+
}
385+
if values[1] != sa {
386+
t.Errorf("%s: wrong service account: got: %v, want: %v", tt.name, sa, values[1])
387+
}
388+
})
389+
}
390+
}
391+
}

pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go

Lines changed: 28 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/pipeline/v1beta1/pipelinerun_types.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ type PipelineRunSpec struct {
168168
// with those declared in the pipeline.
169169
// +optional
170170
Workspaces []WorkspaceBinding `json:"workspaces,omitempty"`
171+
// TaskRunSpecs holds a set of runtime specs
172+
// +optional
173+
TaskRunSpecs []PipelineTaskRunSpec `json:"taskRunSpecs,omitempty"`
171174
}
172175

173176
// PipelineRunSpecStatus defines the pipelinerun spec status the user can provide
@@ -313,3 +316,25 @@ type PipelineRunList struct {
313316
type PipelineTaskRun struct {
314317
Name string `json:"name,omitempty"`
315318
}
319+
320+
// PipelineTaskRunSpec can be used to configure specific
321+
// specs for a concrete Task
322+
type PipelineTaskRunSpec struct {
323+
PipelineTaskName string `json:"pipelineTaskName,omitempty"`
324+
TaskServiceAccountName string `json:"taskServiceAccountName,omitempty"`
325+
TaskPodTemplate *PodTemplate `json:"taskPodTemplate,omitempty"`
326+
}
327+
328+
// GetTaskRunSpecs returns the task specific spec for a given
329+
// PipelineTask if configured, otherwise it returns the PipelineRun's default.
330+
func (pr *PipelineRun) GetTaskRunSpecs(pipelineTaskName string) (string, *PodTemplate) {
331+
serviceAccountName := pr.GetServiceAccountName(pipelineTaskName)
332+
taskPodTemplate := pr.Spec.PodTemplate
333+
for _, task := range pr.Spec.TaskRunSpecs {
334+
if task.PipelineTaskName == pipelineTaskName {
335+
taskPodTemplate = task.TaskPodTemplate
336+
serviceAccountName = task.TaskServiceAccountName
337+
}
338+
}
339+
return serviceAccountName, taskPodTemplate
340+
}

0 commit comments

Comments
 (0)