Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow custom tasks to use workspaces, service accounts, pod templates #3660

Merged
merged 1 commit into from
Jan 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/pipelineruns.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@ set for the target [`namespace`](https://kubernetes.io/docs/concepts/overview/wo

For more information, see [`ServiceAccount`](auth.md).

[`Custom tasks`](pipelines.md#using-custom-tasks) may or may not use a service account name.
Consult the documentation of the custom task that you are using to determine whether it supports a service account name.

### Mapping `ServiceAccount` credentials to `Tasks`

If you require more granularity in specifying execution credentials, use the `serviceAccountNames` field to
Expand Down Expand Up @@ -341,6 +344,9 @@ spec:
claimName: my-volume-claim
```

[`Custom tasks`](pipelines.md#using-custom-tasks) may or may not use a pod template.
Consult the documentation of the custom task that you are using to determine whether it supports a pod template.

### Specifying taskRunSpecs

Specifies a list of `PipelineTaskRunSpec` which contains `TaskServiceAccountName`, `TaskPodTemplate`
Expand Down Expand Up @@ -385,6 +391,9 @@ For more information, see the following topics:
- For a list of supported `Volume` types, see [Specifying `VolumeSources` in `Workspaces`](workspaces.md#specifying-volumesources-in-workspaces).
- For an end-to-end example, see [`Workspaces` in a `PipelineRun`](../examples/v1beta1/pipelineruns/workspaces.yaml).

[`Custom tasks`](pipelines.md#using-custom-tasks) may or may not use workspaces.
Consult the documentation of the custom task that you are using to determine whether it supports workspaces.

### Specifying `LimitRange` values

In order to only consume the bare minimum amount of resources needed to execute one `Step` at a
Expand Down
32 changes: 23 additions & 9 deletions docs/pipelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -954,13 +954,12 @@ If the `taskRef` specifies a name, the custom task controller should look up the
If the `taskRef` does not specify a name, the custom task controller might support
some default behavior for executing unnamed tasks.

### Specifying `Parameters`
### Specifying parameters

If a custom task supports [`parameters`](tasks.md#parameters), you can use the
`params` field to specify their values:

```yaml
spec:
spec:
tasks:
- name: run-custom-task
Expand All @@ -973,21 +972,36 @@ spec:
value: bah
```

### Specifying workspaces

If the custom task supports it, you can provide [`Workspaces`](workspaces.md#using-workspaces-in-tasks) to share data with the custom task.

```yaml
spec:
tasks:
- name: run-custom-task
taskRef:
apiVersion: example.dev/v1alpha1
kind: Example
name: myexample
workspaces:
- name: my-workspace
```

Consult the documentation of the custom task that you are using to determine whether it supports workspaces and how to name them.

### Using `Results`

If the custom task produces results, you can reference them in a Pipeline using the normal syntax,
`$(tasks.<task-name>.results.<result-name>)`.

### Limitations

Pipelines do not directly support passing the following items to custom tasks:
Pipelines do not support the following items with custom tasks:
* Pipeline Resources
* Workspaces
* Service account name
* Pod templates

A pipeline task that references a custom task cannot reference `Conditions`.
`Conditions` are deprecated. Use [`WhenExpressions`](#guard-task-execution-using-whenexpressions) instead.
* [`retries`](#using-the-retries-parameter)
* [`timeout`](#configuring-the-failure-timeout)
* Conditions (`Conditions` are deprecated. Use [`WhenExpressions`](#guard-task-execution-using-whenexpressions) instead.)

## Code examples

Expand Down
60 changes: 59 additions & 1 deletion docs/runs.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ weight: 2
- [Overview](#overview)
- [Configuring a `Run`](#configuring-a-run)
- [Specifying the target Custom Task](#specifying-the-target-custom-task)
- [Specifying `Parameters`](#specifying-parameters)
- [Specifying Parameters](#specifying-parameters)
- [Specifying Workspaces, Service Account, and Pod Template](#specifying-workspaces-service-account-and-pod-template)
- [Monitoring execution status](#monitoring-execution-status)
- [Monitoring `Results`](#monitoring-results)
- [Code examples](#code-examples)
Expand Down Expand Up @@ -51,6 +52,12 @@ A `Run` definition supports the following fields:
- Optional:
- [`params`](#specifying-parameters) - Specifies the desired execution
parameters for the custom task.
- [`serviceAccountName`](#specifying-a-serviceaccount) - Specifies a `ServiceAccount`
object that provides custom credentials for executing the `Run`.
- [`workspaces`](#specifying-workspaces) - Specifies the physical volumes to use for the
[`Workspaces`](workspaces.md) required by a custom task.
- [`podTemplate`](#specifying-a-pod-template) - Specifies a [`Pod` template](podtemplates.md) to use
to configure pods created by the custom task.

[kubernetes-overview]:
https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields
Expand Down Expand Up @@ -108,6 +115,57 @@ If the custom task controller knows how to interpret the parameter value, it
will do so. It might enforce that some parameter values must be specified, or
reject unknown parameter values.

### Specifying Workspaces, Service Account, and Pod Template

A `Run` object can specify workspaces, a service account name, or a pod template.
These are intended to be used with custom tasks that create Pods or other resources that embed a Pod specification.
The custom task can use these specifications to construct the Pod specification.
Not all custom tasks will support these values.
Consult the documentation of the custom task that you are using to determine whether these values apply.

#### Specifying workspaces

If the custom task supports it, you can provide [`Workspaces`](workspaces.md) to share data with the custom task.

```yaml
spec:
workspaces:
- name: my-workspace
emptyDir: {}
```

Consult the documentation of the custom task that you are using to determine whether it supports workspaces and how to name them.

#### Specifying a ServiceAccount

If the custom task supports it, you can execute the `Run` with a specific set of credentials by
specifying a `ServiceAccount` object name in the `serviceAccountName` field in your `Run`
definition. If you do not explicitly specify this, the `Run` executes with the service account
specified in the `configmap-defaults` `ConfigMap`. If this default is not specified, `Runs`
will execute with the [`default` service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server)
set for the target [`namespace`](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/).

```yaml
spec:
serviceAccountName: my-account
```

Consult the documentation of the custom task that you are using to determine whether it supports a service account name.

#### Specifying a pod template

If the custom task supports it, you can specify a [`Pod` template](podtemplates.md) configuration that the custom task will
use to configure Pods (or other resources that embed a Pod specification) that it creates.

```yaml
spec:
podTemplate:
securityContext:
runAsUser: 1001
```

Consult the documentation of the custom task that you are using to determine whether it supports a pod template.

## Monitoring execution status

As your `Run` executes, its `status` field accumulates information on the
Expand Down
11 changes: 10 additions & 1 deletion pkg/apis/pipeline/v1alpha1/run_defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package v1alpha1
import (
"context"

"github.com/tektoncd/pipeline/pkg/apis/config"
"knative.dev/pkg/apis"
)

Expand All @@ -30,5 +31,13 @@ func (r *Run) SetDefaults(ctx context.Context) {
}

func (rs *RunSpec) SetDefaults(ctx context.Context) {
// No defaults to set.
cfg := config.FromContextOrDefaults(ctx)
defaultSA := cfg.Defaults.DefaultServiceAccount
if rs.ServiceAccountName == "" && defaultSA != "" {
rs.ServiceAccountName = defaultSA
}
defaultPodTemplate := cfg.Defaults.DefaultPodTemplate
if rs.PodTemplate == nil {
rs.PodTemplate = defaultPodTemplate
}
}
18 changes: 17 additions & 1 deletion pkg/apis/pipeline/v1alpha1/run_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,20 @@ type RunSpec struct {
// +optional
Status RunSpecStatus `json:"status,omitempty"`

// +optional
ServiceAccountName string `json:"serviceAccountName"`

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

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

// TODO(https://github.com/tektoncd/community/pull/128)
// - timeout
// - inline task spec
// - workspaces ?
}

// RunSpecStatus defines the taskrun spec status the user can provide
Expand All @@ -76,6 +86,12 @@ func (rs RunSpec) GetParam(name string) *v1beta1.Param {
const (
// RunReasonCancelled must be used in the Condition Reason to indicate that a Run was cancelled.
RunReasonCancelled = "RunCancelled"
// RunReasonWorkspaceNotSupported can be used in the Condition Reason to indicate that the
// Run contains a workspace which is not supported by this custom task.
RunReasonWorkspaceNotSupported = "RunWorkspaceNotSupported"
// RunReasonPodTemplateNotSupported can be used in the Condition Reason to indicate that the
// Run contains a pod template which is not supported by this custom task.
RunReasonPodTemplateNotSupported = "RunPodTemplateNotSupported"
)

// RunStatus defines the observed state of Run.
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/pipeline/v1alpha1/run_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,9 @@ func (rs *RunSpec) Validate(ctx context.Context) *apis.FieldError {
return err
}

if err := validateWorkspaceBindings(ctx, rs.Workspaces); err != nil {
return err
}

return nil
}
68 changes: 68 additions & 0 deletions pkg/apis/pipeline/v1alpha1/run_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
v1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"github.com/tektoncd/pipeline/test/diff"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"knative.dev/pkg/apis"
)
Expand Down Expand Up @@ -145,6 +146,20 @@ func TestRun_Valid(t *testing.T) {
}},
},
},
}, {
name: "valid workspace",
run: &v1alpha1.Run{
Spec: v1alpha1.RunSpec{
Ref: &v1alpha1.TaskRef{
APIVersion: "blah",
Kind: "blah",
},
Workspaces: []v1beta1.WorkspaceBinding{{
Name: "workspace",
EmptyDir: &corev1.EmptyDirVolumeSource{},
}},
},
},
}} {
t.Run(c.name, func(t *testing.T) {
if err := c.run.Validate(context.Background()); err != nil {
Expand All @@ -153,3 +168,56 @@ func TestRun_Valid(t *testing.T) {
})
}
}

func TestRun_Workspaces_Invalid(t *testing.T) {
tests := []struct {
name string
run *v1alpha1.Run
wantErr *apis.FieldError
}{{
name: "make sure WorkspaceBinding validation invoked",
run: &v1alpha1.Run{
Spec: v1alpha1.RunSpec{
Ref: &v1alpha1.TaskRef{
APIVersion: "blah",
Kind: "blah",
},
Workspaces: []v1beta1.WorkspaceBinding{{
Name: "workspace",
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: "",
},
}},
},
},
wantErr: apis.ErrMissingField("workspace.persistentvolumeclaim.claimname"),
}, {
name: "bind same workspace twice",
run: &v1alpha1.Run{
Spec: v1alpha1.RunSpec{
Ref: &v1alpha1.TaskRef{
APIVersion: "blah",
Kind: "blah",
},
Workspaces: []v1beta1.WorkspaceBinding{{
Name: "workspace",
EmptyDir: &corev1.EmptyDirVolumeSource{},
}, {
Name: "workspace",
EmptyDir: &corev1.EmptyDirVolumeSource{},
}},
},
},
wantErr: apis.ErrMultipleOneOf("spec.workspaces.name"),
}}
for _, ts := range tests {
t.Run(ts.name, func(t *testing.T) {
err := ts.run.Validate(context.Background())
if err == nil {
t.Errorf("Expected error for invalid Run but got none")
} else if d := cmp.Diff(ts.wantErr.Error(), err.Error()); d != "" {
t.Errorf("Did not get expected error for %q: %s", ts.name, diff.PrintWantGot(d))
}
})
}
}
12 changes: 12 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.

3 changes: 0 additions & 3 deletions pkg/apis/pipeline/v1beta1/pipeline_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,6 @@ func validatePipelineTask(ctx context.Context, t PipelineTask, taskNames sets.St
if t.Resources != nil {
errs = errs.Also(apis.ErrInvalidValue("custom tasks do not support PipelineResources", "resources"))
}
if len(t.Workspaces) > 0 {
errs = errs.Also(apis.ErrInvalidValue("custom tasks do not support Workspaces", "workspaces"))
}
if t.Timeout != nil {
errs = errs.Also(apis.ErrInvalidValue("custom tasks do not support timeout", "timeout"))
}
Expand Down
12 changes: 0 additions & 12 deletions pkg/apis/pipeline/v1beta1/pipeline_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -620,18 +620,6 @@ func TestValidatePipelineTasks_Failure(t *testing.T) {
Paths: []string{"tasks[0].resources"},
},
wc: enableFeature(t, "enable-custom-tasks"),
}, {
name: "pipelinetask custom task doesn't support workspaces",
tasks: []PipelineTask{{
Name: "foo",
Workspaces: []WorkspacePipelineTaskBinding{{}},
TaskRef: &TaskRef{APIVersion: "example.dev/v0", Kind: "Example"},
}},
expectedError: apis.FieldError{
Message: `invalid value: custom tasks do not support Workspaces`,
Paths: []string{"tasks[0].workspaces"},
},
wc: enableFeature(t, "enable-custom-tasks"),
}, {
name: "pipelinetask custom task doesn't support timeout",
tasks: []PipelineTask{{
Expand Down
Loading