Skip to content

Commit fdf682f

Browse files
0xFelixtekton-robot
authored andcommitted
Add support for projected volumes as workspace type
By adding support for projected volumes [1] as workspace type an arbitrary amount of ConfigMaps or Secrets can be passed to a TaskRun/PipelineRun without modifying the actual Task/ClusterTask. This allows to pass data to Tasks/Pipelines in a flexible way. Fixes #5075 [1] https://kubernetes.io/docs/concepts/storage/projected-volumes Signed-off-by: Felix Matouschek <[email protected]>
1 parent 201d57b commit fdf682f

File tree

11 files changed

+379
-20
lines changed

11 files changed

+379
-20
lines changed

docs/install.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ Features currently in "alpha" are:
434434
| [Matrix](./matrix.md) | [TEP-0090](https://github.com/tektoncd/community/blob/main/teps/0090-matrix.md) | | |
435435
| [Embedded Statuses](pipelineruns.md#configuring-usage-of-taskrun-and-run-embedded-statuses) | [TEP-0100](https://github.com/tektoncd/community/blob/main/teps/0100-embedded-taskruns-and-runs-status-in-pipelineruns.md) | | |
436436
| [Task-level Resource Requirements](compute-resources.md#task-level-compute-resources-configuration) | [TEP-0104](https://github.com/tektoncd/community/blob/main/teps/0104-tasklevel-resource-requirements.md) | | |
437+
| [Projected Workspace Type](workspaces.md#projected) | | | |
437438
| [CSI Workspace Type](workspaces.md#csi) | | | |
438439

439440
## Configuring High Availability

docs/workspaces.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,29 @@ workspaces:
512512
secretName: my-secret
513513
```
514514

515+
##### `projected`
516+
517+
This is an alpha feature. The `enable-api-fields` feature flag [must be set to `"alpha"`](./install.md)
518+
for projected volume source to function.
519+
520+
The `projected` field references a [`projected` volume](https://kubernetes.io/docs/concepts/storage/projected-volumes).
521+
Using a `projected` volume has the following limitations:
522+
523+
- `projected` volume sources are always mounted as read-only. `Steps` cannot write to them and will error out if they try.
524+
- The volumes you want to project as a `Workspace` must exist prior to submitting the `TaskRun`.
525+
- The following volumes can be projected: `configMap`, `secret`, `serviceAccountToken` and `downwardApi`
526+
527+
```yaml
528+
workspaces:
529+
- name: myworkspace
530+
projected:
531+
sources:
532+
- configMap:
533+
name: my-configmap
534+
- secret:
535+
name: my-secret
536+
```
537+
515538
##### `csi`
516539

517540
This is an alpha feature. The `enable-api-fields` feature flag [must be set to `"alpha"`](./install.md)
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# In this contrived example two different kinds of workspace volume are used to thread
2+
# data through a pipeline's tasks.
3+
# 1. A projected volume combines a:
4+
# - ConfigMap as source of recipe data.
5+
# - Secret to store a password.
6+
# 2. A PVC is used to share data from one task to the next.
7+
#
8+
# The end result is a pipeline that first checks if the password is correct and, if so,
9+
# copies data out of a recipe store onto a shared volume. The recipe data is then read
10+
# by a subsequent task and printed to screen.
11+
apiVersion: v1
12+
kind: ConfigMap
13+
metadata:
14+
name: sensitive-recipe-storage
15+
data:
16+
brownies: |
17+
1. Heat oven to 325 degrees F
18+
2. Melt 1/2 cup butter w/ 1/2 cup cocoa, stirring smooth.
19+
3. Remove from heat, allow to cool for a few minutes.
20+
4. Transfer to bowl.
21+
5. Whisk in 2 eggs, one at a time.
22+
6. Stir in vanilla.
23+
7. Separately combine 1 cup sugar, 1/4 cup flour, 1 cup chopped
24+
walnuts and pinch of salt
25+
8. Combine mixtures.
26+
9. Bake in greased pan for 30 minutes. Watch carefully for
27+
appropriate level of gooeyness.
28+
---
29+
apiVersion: v1
30+
kind: Secret
31+
metadata:
32+
name: secret-password
33+
type: Opaque
34+
data:
35+
password: aHVudGVyMg==
36+
---
37+
apiVersion: v1
38+
kind: PersistentVolumeClaim
39+
metadata:
40+
name: shared-task-storage
41+
spec:
42+
resources:
43+
requests:
44+
storage: 16Mi
45+
volumeMode: Filesystem
46+
accessModes:
47+
- ReadWriteOnce
48+
---
49+
apiVersion: tekton.dev/v1beta1
50+
kind: Task
51+
metadata:
52+
name: fetch-secure-data
53+
spec:
54+
workspaces:
55+
- name: secure-store
56+
- name: filedrop
57+
steps:
58+
- name: fetch-and-write
59+
image: ubuntu
60+
script: |
61+
if [ "hunter2" = "$(cat $(workspaces.secure-store.path)/password)" ]; then
62+
cp $(workspaces.secure-store.path)/recipe.txt $(workspaces.filedrop.path)
63+
else
64+
echo "wrong password!"
65+
exit 1
66+
fi
67+
---
68+
apiVersion: tekton.dev/v1beta1
69+
kind: Task
70+
metadata:
71+
name: print-data
72+
spec:
73+
workspaces:
74+
- name: storage
75+
readOnly: true
76+
params:
77+
- name: filename
78+
steps:
79+
- name: print-secrets
80+
image: ubuntu
81+
script: cat $(workspaces.storage.path)/$(params.filename)
82+
---
83+
apiVersion: tekton.dev/v1beta1
84+
kind: Pipeline
85+
metadata:
86+
name: fetch-and-print-recipe
87+
spec:
88+
workspaces:
89+
- name: data-store
90+
- name: shared-data
91+
tasks:
92+
- name: fetch-the-recipe
93+
taskRef:
94+
name: fetch-secure-data
95+
workspaces:
96+
- name: secure-store
97+
workspace: data-store
98+
- name: filedrop
99+
workspace: shared-data
100+
- name: print-the-recipe
101+
taskRef:
102+
name: print-data
103+
# Note: this is currently required to ensure order of write / read on PVC is correct.
104+
runAfter:
105+
- fetch-the-recipe
106+
params:
107+
- name: filename
108+
value: recipe.txt
109+
workspaces:
110+
- name: storage
111+
workspace: shared-data
112+
---
113+
apiVersion: tekton.dev/v1beta1
114+
kind: PipelineRun
115+
metadata:
116+
generateName: recipe-time-
117+
spec:
118+
pipelineRef:
119+
name: fetch-and-print-recipe
120+
workspaces:
121+
- name: data-store
122+
projected:
123+
sources:
124+
- secret:
125+
name: secret-password
126+
- configMap:
127+
name: sensitive-recipe-storage
128+
items:
129+
- key: brownies
130+
path: recipe.txt
131+
- name: shared-data
132+
persistentVolumeClaim:
133+
claimName: shared-task-storage

pkg/apis/pipeline/v1beta1/openapi_generated.go

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/pipeline/v1beta1/swagger.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2887,6 +2887,10 @@
28872887
"description": "PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. Either this OR EmptyDir can be used.",
28882888
"$ref": "#/definitions/v1.PersistentVolumeClaimVolumeSource"
28892889
},
2890+
"projected": {
2891+
"description": "Projected represents a projected volume that should populate this workspace.",
2892+
"$ref": "#/definitions/v1.ProjectedVolumeSource"
2893+
},
28902894
"secret": {
28912895
"description": "Secret represents a secret that should populate this workspace.",
28922896
"$ref": "#/definitions/v1.SecretVolumeSource"

pkg/apis/pipeline/v1beta1/workspace_types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ type WorkspaceBinding struct {
7777
// Secret represents a secret that should populate this workspace.
7878
// +optional
7979
Secret *corev1.SecretVolumeSource `json:"secret,omitempty"`
80+
// Projected represents a projected volume that should populate this workspace.
81+
// +optional
82+
Projected *corev1.ProjectedVolumeSource `json:"projected,omitempty"`
8083
// CSI (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers.
8184
// +optional
8285
CSI *corev1.CSIVolumeSource `json:"csi,omitempty"`

pkg/apis/pipeline/v1beta1/workspace_validation.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,17 @@ func (b *WorkspaceBinding) Validate(ctx context.Context) (errs *apis.FieldError)
6868
return apis.ErrMissingField("secret.secretName")
6969
}
7070

71+
// The projected workspace is only supported when the alpha feature gate is enabled.
72+
// For a Projected volume to work, you must provide at least one source.
73+
if b.Projected != nil {
74+
if err := version.ValidateEnabledAPIFields(ctx, "projected workspace type", config.AlphaAPIFields).ViaField("workspace"); err != nil {
75+
return err
76+
}
77+
if len(b.Projected.Sources) == 0 {
78+
return apis.ErrMissingField("projected.sources")
79+
}
80+
}
81+
7182
// The csi workspace is only supported when the alpha feature gate is enabled.
7283
// For a CSI to work, you must provide and have installed the driver to use.
7384
if b.CSI != nil {
@@ -102,6 +113,9 @@ func (b *WorkspaceBinding) numSources() int {
102113
if b.Secret != nil {
103114
n++
104115
}
116+
if b.Projected != nil {
117+
n++
118+
}
105119
if b.CSI != nil {
106120
n++
107121
}

pkg/apis/pipeline/v1beta1/workspace_validation_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,27 @@ func TestWorkspaceBindingValidateValid(t *testing.T) {
8282
SecretName: "my-secret",
8383
},
8484
},
85+
}, {
86+
name: "Valid projected",
87+
binding: &v1beta1.WorkspaceBinding{
88+
Name: "beth",
89+
Projected: &corev1.ProjectedVolumeSource{
90+
Sources: []corev1.VolumeProjection{{
91+
ConfigMap: &corev1.ConfigMapProjection{
92+
LocalObjectReference: corev1.LocalObjectReference{
93+
Name: "a-configmap-name",
94+
},
95+
},
96+
}, {
97+
Secret: &corev1.SecretProjection{
98+
LocalObjectReference: corev1.LocalObjectReference{
99+
Name: "my-secret",
100+
},
101+
},
102+
}},
103+
},
104+
},
105+
wc: config.EnableAlphaAPIFields,
85106
}, {
86107
name: "Valid csi",
87108
binding: &v1beta1.WorkspaceBinding{
@@ -145,6 +166,19 @@ func TestWorkspaceBindingValidateInvalid(t *testing.T) {
145166
Name: "beth",
146167
Secret: &corev1.SecretVolumeSource{},
147168
},
169+
}, {
170+
name: "projected workspace should be disallowed without alpha feature gate",
171+
binding: &v1beta1.WorkspaceBinding{
172+
Name: "beth",
173+
Projected: &corev1.ProjectedVolumeSource{},
174+
},
175+
}, {
176+
name: "Provide projected without sources",
177+
binding: &v1beta1.WorkspaceBinding{
178+
Name: "beth",
179+
Projected: &corev1.ProjectedVolumeSource{},
180+
},
181+
wc: config.EnableAlphaAPIFields,
148182
}, {
149183
name: "csi workspace should be disallowed without alpha feature gate",
150184
binding: &v1beta1.WorkspaceBinding{

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

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

pkg/workspace/apply.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ func CreateVolumes(wb []v1beta1.WorkspaceBinding) map[string]corev1.Volume {
7070
case w.Secret != nil:
7171
s := *w.Secret
7272
v.setVolumeSource(w.Name, name, corev1.VolumeSource{Secret: &s})
73+
case w.Projected != nil:
74+
s := *w.Projected
75+
v.setVolumeSource(w.Name, name, corev1.VolumeSource{Projected: &s})
7376
case w.CSI != nil:
7477
csi := *w.CSI
7578
v.setVolumeSource(w.Name, name, corev1.VolumeSource{CSI: &csi})

0 commit comments

Comments
 (0)