Skip to content

Commit

Permalink
Add workspace types for Task and TaskRun with validation
Browse files Browse the repository at this point in the history
This allows users to use Volumes with Tasks such that:
- The actual volumes to use (or subdirectories on those volumes) are
  provided at runtime, not at Task authoring time
- At Task authoring time you can declare that you expect a volume to
  be provided and control what path that volume should end up at
- Validation will be provided that the volumes (workspaces) are actually
  provided at runtime

Before this change, there were two ways to use Volumes with Tasks:
- VolumeMounts were explicitly declared at the level of a step
- Volumes were declared in Tasks, meaning the Task author controlled the
  name of the volume being used and it wasn't possible at runtime to use
  a subdir of the volume
- Or the Volume could be provided via the podTemplate, if the user
  realized this was possible

None of this was validated and could cause unexpected and hard to
diagnose errors at runtime.

We have also limited (at least initially) the types of volume source
being supported instead of expanding to all volume sources, tho we can
expand it later if we want to and if users need it. This would reduce
the API surface that a Tekton compliant system would need to conform to
(once we actually define what conformance means!).

Part of #1438

In future commits we will add support for workspaces to Pipelines and
PipelineRuns as well; for now if a user tries to use a Pipeline with a
Task that requires a Workspace, it will fail at runtime because it is
not (yet) possible for the Pipeline and PipelineRun to provide
workspaces.

Co-authored-by: Scott <[email protected]>
  • Loading branch information
bobcatfish and Scott committed Nov 27, 2019
1 parent f2daa0b commit f9b302e
Show file tree
Hide file tree
Showing 20 changed files with 1,003 additions and 23 deletions.
16 changes: 15 additions & 1 deletion docs/pipelineruns.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Creation of a `PipelineRun` will trigger the creation of
- [Service account](#service-account)
- [Service accounts](#service-accounts)
- [Pod Template](#pod-template)
- [Workspaces](#workspaces)
- [Cancelling a PipelineRun](#cancelling-a-pipelinerun)
- [Examples](https://github.com/tektoncd/pipeline/tree/master/examples/pipelineruns)
- [Logs](logs.md)
Expand All @@ -27,7 +28,14 @@ following fields:

- Required:
- [`apiVersion`][kubernetes-overview] - Specifies the API version, for example
`tekton.dev/v1alpha1`.
`tekton.dev/v1alpha1`#### Workspace Substitution

Paths to a `Task's` declared [workspaces](#workspaces) can be substituted with:

```
$(workspaces.myworkspace.path)
```
.
- [`kind`][kubernetes-overview] - Specify the `PipelineRun` resource object.
- [`metadata`][kubernetes-overview] - Specifies data to uniquely identify the
`PipelineRun` resource object, for example a `name`.
Expand Down Expand Up @@ -265,6 +273,12 @@ spec:
claimName: my-volume-claim
```

## Workspaces

It is not yet possible to specify [workspaces](tasks.md#workspaces) via `Pipelines`
or `PipelineRuns`, so `Tasks` requiring `workspaces` cannot be used with them until
[#1438](https://github.com/tektoncd/pipeline/issues/1438) is completed.

## Cancelling a PipelineRun

In order to cancel a running pipeline (`PipelineRun`), you need to update its
Expand Down
7 changes: 7 additions & 0 deletions docs/pipelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This document defines `Pipelines` and their capabilities.

- [Syntax](#syntax)
- [Declared resources](#declared-resources)
- [Workspaces][#declared-workspaces]
- [Parameters](#parameters)
- [Pipeline Tasks](#pipeline-tasks)
- [From](#from)
Expand Down Expand Up @@ -72,6 +73,12 @@ spec:
type: image
```
### Declared Workspaces
It is not yet possible to specify [workspaces](tasks.md#workspaces) via `Pipelines`
or `PipelineRuns`, so `Tasks` requiring `workspaces` cannot be used with them until
[#1438](https://github.com/tektoncd/pipeline/issues/1438) is completed.

### Parameters

`Pipeline`s can declare input parameters that must be supplied to the `Pipeline`
Expand Down
41 changes: 40 additions & 1 deletion docs/taskruns.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ A `TaskRun` runs until all `steps` have completed or until a failure occurs.
- [Overriding where resources are copied from](#overriding-where-resources-are-copied-from)
- [Service Account](#service-account)
- [Pod Template](#pod-template)
- [Workspaces](#workspaces)
- [Status](#status)
- [Steps](#steps)
- [Cancelling a TaskRun](#cancelling-a-taskrun)
Expand Down Expand Up @@ -57,7 +58,9 @@ following fields:
to configure the default timeout.
- [`podTemplate`](#pod-template) - Specifies a subset of
[`PodSpec`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.15/#pod-v1-core)
configuration that will be used as the basis for the `Task` pod.
configuration that will be used as the basis for the `Task` pod.
- [`workspaces`](#workspaces) - Specify the actual volumes to use for the
[workspaces](tasks.md#workspaces) declared by a `Task`

[kubernetes-overview]:
https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields
Expand Down Expand Up @@ -227,7 +230,43 @@ spec:
claimName: my-volume-claim
```

## Workspaces

For a `TaskRun` to execute [a `Task` that declares `workspaces`](tasks.md#workspaces),
at runtime you need to map the `workspaces` to actual physical volumes with
`workspaces`. Values in `workspaces` are
[`Volumes`](https://kubernetes.io/docs/tasks/configure-pod-container/configure-volume-storage/), however currently we only support a subset of `VolumeSources`:

* [`emptyDir`](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir)
* [`persistentVolumeClaim`](https://kubernetes.io/docs/concepts/storage/volumes/#persistentvolumeclaim)

_If you need support for a `VolumeSource` not listed here
[please open an issue](https://github.com/tektoncd/pipeline/issues) or feel free to
[contribute a PR](https://github.com/tektoncd/pipeline/blob/master/CONTRIBUTING.md)._


If the declared `workspaces` are not provided at runtime, the `TaskRun` will fail
with an error.

For example to provide an existing PVC called `mypvc` for a `workspace` called
`myworkspace` declared by the `Pipeline`, using the `my-subdir` folder which already exists
on the PVC (there will be an error if it does not exist):

```yaml
workspaces:
- name: myworkspace
persistentVolumeClaim:
claimName: mypvc
volumeSubPath: my-subdir
```

Or to use [`emptyDir`](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir) for the same `workspace`:

```yaml
workspaces:
- name: myworkspace
emptyDir: {}
```

## Status

Expand Down
64 changes: 58 additions & 6 deletions docs/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ entire Kubernetes cluster.
- [Syntax](#syntax)
- [Steps](#steps)
- [Step script](#step-script)
- [Workspaces](#workspaces)
- [Inputs](#inputs)
- [Outputs](#outputs)
- [Controlling where resources are mounted](#controlling-where-resources-are-mounted)
- [Volumes](#volumes)
- [Container Template **deprecated**](#step-template)
- [Workspaces](#workspaces)
- [Step Template](#step-template)
- [Variable Substitution](#variable-substitution)
- [Examples](#examples)
Expand Down Expand Up @@ -77,6 +78,8 @@ following fields:
created by your `Task`
- [`volumes`](#volumes) - Specifies one or more volumes that you want to make
available to your `Task`'s steps.
- [`workspaces`](#workspaces) - Specifies paths at which you expect volumes to
be mounted and available
- [`stepTemplate`](#step-template) - Specifies a `Container` step
definition to use as the basis for all steps within your `Task`.
- [`sidecars`](#sidecars) - Specifies sidecar containers to run alongside
Expand Down Expand Up @@ -132,7 +135,6 @@ the body of a `Task`.

If multiple `steps` are defined, they will be executed in the same order as they
are defined, if the `Task` is invoked by a [`TaskRun`](taskruns.md).

Each `steps` in a `Task` must specify a container image that adheres to the
[container contract](./container-contract.md). For each of the `steps` fields,
or container images that you define:
Expand Down Expand Up @@ -182,7 +184,7 @@ steps:
...or to execute a Node script, if the image includes `node`:

```yaml
steps:
steps:- [Workspaces](#workspaces)
- image: node # contains node
script: |
#!/usr/bin/env node
Expand Down Expand Up @@ -369,6 +371,40 @@ For example, use volumes to accomplish one of the following common tasks:
unsafe_. Use [kaniko](https://github.com/GoogleContainerTools/kaniko) instead.
This is used only for the purposes of demonstration.

### Workspaces

`workspaces` are a way of declaring volumes you expect to be made available to your
executing `Task` and the path to make them available at. They are similar to
[`volumes`](#volumes) but allow you to enforce at runtime that the volumes have
been attached and [allow you to specify subpaths](taskruns.md#workspaces) in the volumes
to attach.

The volume will be made available at `/workspace/myworkspace`, or you can or override
this with `mountPath`. The value at `mountPath` can be anywhere on your pod's filesystem.
The path will be available via [variable substitution](#variable-substituation) with
`$(workspaces.myworkspace.path)`.

The actual volumes must be provided at runtime
[in the `TaskRun`](taskruns.md#workspaces).
In a future iteration ([#1438](https://github.com/tektoncd/pipeline/issues/1438))
it [will be possible to specify these in the `PipelineRun`](pipelineruns.md#workspaces)
as well.

For example:

```yaml
spec:
steps:
- name: write-message
image: ubuntu
command: ['bash']
args: ['-c', 'echo hello! > $(workspaces.messages.path)/message']
workspaces:
- name: messages
description: The folder where we write the message to
mountPath: /custom/path/relative/to/root
```

### Step Template

Specifies a [`Container`](https://kubernetes.io/docs/concepts/containers/)
Expand Down Expand Up @@ -459,9 +495,17 @@ has been created to track this bug.

### Variable Substitution

`Tasks` support string replacement using values from all [`inputs`](#inputs) and
[`outputs`](#outputs).
`Tasks` support string replacement using values from:

* [Inputs and Outputs](#input-and-output-substitution)
* [Array params](#variable-substitution-with-parameters-of-type-array)
* [`workspaces`](#workspaces)
* [`volumes`](#variable-substitution-with-volumes)

#### Input and Output substitution

[`inputs`](#inputs) and [outputs](#outputs) attributes can be used in replacements,
including [`params`](#params) and [resources](./resources.md#variable-substitution).

Input parameters can be referenced in the `Task` spec using the variable substitution syntax below,
where `<name>` is the name of the parameter:
Expand All @@ -472,7 +516,7 @@ $(inputs.params.<name>)

Param values from resources can also be accessed using [variable substitution](./resources.md#variable-substitution)

#### Variable Substitution with Parameters of Type `Array`
##### Variable Substitution with Parameters of Type `Array`

Referenced parameters of type `array` will expand to insert the array elements in the reference string's spot.

Expand Down Expand Up @@ -515,6 +559,14 @@ A valid reference to the `build-args` parameter is isolated and in an eligible f
args: ["build", "$(inputs.params.build-args)", "additonalArg"]
```

#### Workspace Substitution

Paths to a `Task's` declared [workspaces](#workspaces) can be substituted with:

```
$(workspaces.myworkspace.path)
```
#### Variable Substitution within Volumes
Task volume names and different
Expand Down
7 changes: 4 additions & 3 deletions examples/taskruns/custom-volume.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ spec:
steps:
- name: write
image: ubuntu
command: ["/bin/bash"]
args: ["-c", "echo some stuff > /im/a/custom/mount/path/file"]
script: |
#!/usr/bin/env bash
echo some stuff > /im/a/custom/mount/path/file
volumeMounts:
- name: custom
mountPath: /im/a/custom/mount/path
- name: read
image: ubuntu
command: ["/bin/bash"]
args: ["-c", "cat /short/and/stout/file"]
args: ["-c", "cat /short/and/stout/file | grep stuff"]
volumeMounts:
- name: custom
mountPath: /short/and/stout
Expand Down
35 changes: 35 additions & 0 deletions examples/taskruns/workspace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
resources:
requests:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
---
apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
generateName: custom-volume-
spec:
workspaces:
- name: custom
emptyDir: {}
persistentVolumeClaim:
claimName: my-pvc
subPath: my-subdir
taskSpec:
steps:
- name: write
image: ubuntu
command: ["/bin/bash"]
args: ["-c", "echo stuff > /workspace/custom/foo"]
- name: read
image: ubuntu
command: ["/bin/bash"]
args: ["-c", "cat /workspace/custom/foo | grep stuff"]
workspaces:
- name: custom
3 changes: 3 additions & 0 deletions pkg/apis/pipeline/v1alpha1/task_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ type TaskSpec struct {
// Sidecars are run alongside the Task's step containers. They begin before
// the steps start and end after the steps complete.
Sidecars []corev1.Container `json:"sidecars,omitempty"`

// Workspaces are the volumes that this Task requires.
Workspaces []WorkspaceDeclaration
}

// Step embeds the Container type, which allows it to include fields not
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/pipeline/v1alpha1/taskrun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@ type TaskRunSpec struct {
Timeout *metav1.Duration `json:"timeout,omitempty"`

// PodTemplate holds pod specific configuration
// +optional
PodTemplate PodTemplate `json:"podTemplate,omitempty"`

// Workspaces is a list of WorkspaceBindings from volumes to workspaces.
// +optional
Workspaces []WorkspaceBinding `json:"workspaces,omitempty"`
}

// TaskRunSpecStatus defines the taskrun spec status the user can provide
Expand Down
53 changes: 53 additions & 0 deletions pkg/apis/pipeline/v1alpha1/workspace_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
Copyright 2019 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1

import (
corev1 "k8s.io/api/core/v1"
)

// WorkspaceDeclaration is a declaration of a volume that a Task requires.
type WorkspaceDeclaration struct {
// Name is the name by which you can bind the volume at runtime.
Name string `json:"name"`
// Description is an optional human readable description of this volume.
// +optional
Description string `json:"description,omitempty"`
// MountPath overrides the directory that the volume will be made available at.
// +optional
MountPath string `json:"mountPath,omitempty"`
}

// WorkspaceBinding maps a Task's declared workspace to a Volume.
// Currently we only support PersistentVolumeClaims and EmptyDir.
type WorkspaceBinding struct {
// Name is the name of the workspace populated by the volume.
Name string `json:"name"`
// SubPath is optionally a directory on the volume which should be used
// for this binding (i.e. the volume will be mounted at this sub directory).
// +optional
SubPath string `json:"subPath,omitempty"`
// PersistentVolumeClaimVolumeSource represents a reference to a
// PersistentVolumeClaim in the same namespace. Either this OR EmptyDir can be used.
// +optional
PersistentVolumeClaim *corev1.PersistentVolumeClaimVolumeSource `json:"persistentVolumeClaim,omitempty"`
// EmptyDir represents a temporary directory that shares a Task's lifetime.
// More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir
// Either this OR PersistentVolumeClaim can be used.
// +optional
EmptyDir *corev1.EmptyDirVolumeSource `json:"emptyDir,omitempty"`
}
Loading

0 comments on commit f9b302e

Please sign in to comment.