Skip to content

Commit

Permalink
Add support for projected volumes as workspace type
Browse files Browse the repository at this point in the history
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 <fmatouschek@redhat.com>
  • Loading branch information
0xFelix authored and tekton-robot committed Jul 21, 2022
1 parent 201d57b commit fdf682f
Show file tree
Hide file tree
Showing 11 changed files with 379 additions and 20 deletions.
1 change: 1 addition & 0 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ Features currently in "alpha" are:
| [Matrix](./matrix.md) | [TEP-0090](https://github.com/tektoncd/community/blob/main/teps/0090-matrix.md) | | |
| [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) | | |
| [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) | | |
| [Projected Workspace Type](workspaces.md#projected) | | | |
| [CSI Workspace Type](workspaces.md#csi) | | | |

## Configuring High Availability
Expand Down
23 changes: 23 additions & 0 deletions docs/workspaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,29 @@ workspaces:
secretName: my-secret
```

##### `projected`

This is an alpha feature. The `enable-api-fields` feature flag [must be set to `"alpha"`](./install.md)
for projected volume source to function.

The `projected` field references a [`projected` volume](https://kubernetes.io/docs/concepts/storage/projected-volumes).
Using a `projected` volume has the following limitations:

- `projected` volume sources are always mounted as read-only. `Steps` cannot write to them and will error out if they try.
- The volumes you want to project as a `Workspace` must exist prior to submitting the `TaskRun`.
- The following volumes can be projected: `configMap`, `secret`, `serviceAccountToken` and `downwardApi`

```yaml
workspaces:
- name: myworkspace
projected:
sources:
- configMap:
name: my-configmap
- secret:
name: my-secret
```

##### `csi`

This is an alpha feature. The `enable-api-fields` feature flag [must be set to `"alpha"`](./install.md)
Expand Down
133 changes: 133 additions & 0 deletions examples/v1beta1/pipelineruns/alpha/workspaces-projected.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# In this contrived example two different kinds of workspace volume are used to thread
# data through a pipeline's tasks.
# 1. A projected volume combines a:
# - ConfigMap as source of recipe data.
# - Secret to store a password.
# 2. A PVC is used to share data from one task to the next.
#
# The end result is a pipeline that first checks if the password is correct and, if so,
# copies data out of a recipe store onto a shared volume. The recipe data is then read
# by a subsequent task and printed to screen.
apiVersion: v1
kind: ConfigMap
metadata:
name: sensitive-recipe-storage
data:
brownies: |
1. Heat oven to 325 degrees F
2. Melt 1/2 cup butter w/ 1/2 cup cocoa, stirring smooth.
3. Remove from heat, allow to cool for a few minutes.
4. Transfer to bowl.
5. Whisk in 2 eggs, one at a time.
6. Stir in vanilla.
7. Separately combine 1 cup sugar, 1/4 cup flour, 1 cup chopped
walnuts and pinch of salt
8. Combine mixtures.
9. Bake in greased pan for 30 minutes. Watch carefully for
appropriate level of gooeyness.
---
apiVersion: v1
kind: Secret
metadata:
name: secret-password
type: Opaque
data:
password: aHVudGVyMg==
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-task-storage
spec:
resources:
requests:
storage: 16Mi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: fetch-secure-data
spec:
workspaces:
- name: secure-store
- name: filedrop
steps:
- name: fetch-and-write
image: ubuntu
script: |
if [ "hunter2" = "$(cat $(workspaces.secure-store.path)/password)" ]; then
cp $(workspaces.secure-store.path)/recipe.txt $(workspaces.filedrop.path)
else
echo "wrong password!"
exit 1
fi
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: print-data
spec:
workspaces:
- name: storage
readOnly: true
params:
- name: filename
steps:
- name: print-secrets
image: ubuntu
script: cat $(workspaces.storage.path)/$(params.filename)
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: fetch-and-print-recipe
spec:
workspaces:
- name: data-store
- name: shared-data
tasks:
- name: fetch-the-recipe
taskRef:
name: fetch-secure-data
workspaces:
- name: secure-store
workspace: data-store
- name: filedrop
workspace: shared-data
- name: print-the-recipe
taskRef:
name: print-data
# Note: this is currently required to ensure order of write / read on PVC is correct.
runAfter:
- fetch-the-recipe
params:
- name: filename
value: recipe.txt
workspaces:
- name: storage
workspace: shared-data
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: recipe-time-
spec:
pipelineRef:
name: fetch-and-print-recipe
workspaces:
- name: data-store
projected:
sources:
- secret:
name: secret-password
- configMap:
name: sensitive-recipe-storage
items:
- key: brownies
path: recipe.txt
- name: shared-data
persistentVolumeClaim:
claimName: shared-task-storage
8 changes: 7 additions & 1 deletion pkg/apis/pipeline/v1beta1/openapi_generated.go

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

4 changes: 4 additions & 0 deletions pkg/apis/pipeline/v1beta1/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -2887,6 +2887,10 @@
"description": "PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. Either this OR EmptyDir can be used.",
"$ref": "#/definitions/v1.PersistentVolumeClaimVolumeSource"
},
"projected": {
"description": "Projected represents a projected volume that should populate this workspace.",
"$ref": "#/definitions/v1.ProjectedVolumeSource"
},
"secret": {
"description": "Secret represents a secret that should populate this workspace.",
"$ref": "#/definitions/v1.SecretVolumeSource"
Expand Down
3 changes: 3 additions & 0 deletions pkg/apis/pipeline/v1beta1/workspace_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ type WorkspaceBinding struct {
// Secret represents a secret that should populate this workspace.
// +optional
Secret *corev1.SecretVolumeSource `json:"secret,omitempty"`
// Projected represents a projected volume that should populate this workspace.
// +optional
Projected *corev1.ProjectedVolumeSource `json:"projected,omitempty"`
// CSI (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers.
// +optional
CSI *corev1.CSIVolumeSource `json:"csi,omitempty"`
Expand Down
14 changes: 14 additions & 0 deletions pkg/apis/pipeline/v1beta1/workspace_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ func (b *WorkspaceBinding) Validate(ctx context.Context) (errs *apis.FieldError)
return apis.ErrMissingField("secret.secretName")
}

// The projected workspace is only supported when the alpha feature gate is enabled.
// For a Projected volume to work, you must provide at least one source.
if b.Projected != nil {
if err := version.ValidateEnabledAPIFields(ctx, "projected workspace type", config.AlphaAPIFields).ViaField("workspace"); err != nil {
return err
}
if len(b.Projected.Sources) == 0 {
return apis.ErrMissingField("projected.sources")
}
}

// The csi workspace is only supported when the alpha feature gate is enabled.
// For a CSI to work, you must provide and have installed the driver to use.
if b.CSI != nil {
Expand Down Expand Up @@ -102,6 +113,9 @@ func (b *WorkspaceBinding) numSources() int {
if b.Secret != nil {
n++
}
if b.Projected != nil {
n++
}
if b.CSI != nil {
n++
}
Expand Down
34 changes: 34 additions & 0 deletions pkg/apis/pipeline/v1beta1/workspace_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,27 @@ func TestWorkspaceBindingValidateValid(t *testing.T) {
SecretName: "my-secret",
},
},
}, {
name: "Valid projected",
binding: &v1beta1.WorkspaceBinding{
Name: "beth",
Projected: &corev1.ProjectedVolumeSource{
Sources: []corev1.VolumeProjection{{
ConfigMap: &corev1.ConfigMapProjection{
LocalObjectReference: corev1.LocalObjectReference{
Name: "a-configmap-name",
},
},
}, {
Secret: &corev1.SecretProjection{
LocalObjectReference: corev1.LocalObjectReference{
Name: "my-secret",
},
},
}},
},
},
wc: config.EnableAlphaAPIFields,
}, {
name: "Valid csi",
binding: &v1beta1.WorkspaceBinding{
Expand Down Expand Up @@ -145,6 +166,19 @@ func TestWorkspaceBindingValidateInvalid(t *testing.T) {
Name: "beth",
Secret: &corev1.SecretVolumeSource{},
},
}, {
name: "projected workspace should be disallowed without alpha feature gate",
binding: &v1beta1.WorkspaceBinding{
Name: "beth",
Projected: &corev1.ProjectedVolumeSource{},
},
}, {
name: "Provide projected without sources",
binding: &v1beta1.WorkspaceBinding{
Name: "beth",
Projected: &corev1.ProjectedVolumeSource{},
},
wc: config.EnableAlphaAPIFields,
}, {
name: "csi workspace should be disallowed without alpha feature gate",
binding: &v1beta1.WorkspaceBinding{
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go

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

3 changes: 3 additions & 0 deletions pkg/workspace/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ func CreateVolumes(wb []v1beta1.WorkspaceBinding) map[string]corev1.Volume {
case w.Secret != nil:
s := *w.Secret
v.setVolumeSource(w.Name, name, corev1.VolumeSource{Secret: &s})
case w.Projected != nil:
s := *w.Projected
v.setVolumeSource(w.Name, name, corev1.VolumeSource{Projected: &s})
case w.CSI != nil:
csi := *w.CSI
v.setVolumeSource(w.Name, name, corev1.VolumeSource{CSI: &csi})
Expand Down
Loading

0 comments on commit fdf682f

Please sign in to comment.