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

Add volumeClaimTemplate as a Workspace volume source #2326

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
12 changes: 9 additions & 3 deletions docs/workspaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

`Workspaces` allow `Tasks` to declare parts of the filesystem that need to be provided
at runtime by `TaskRuns`. A `TaskRun` can make these parts of the filesystem available
in many ways: using a read-only `ConfigMap` or `Secret`, a `PersistentVolumeClaim`
shared with other Tasks, or simply an `emptyDir` that is discarded when the `TaskRun`
in many ways: using a read-only `ConfigMap` or `Secret`, an existing `PersistentVolumeClaim`
shared with other Tasks, create a `PersistentVolumeClaim` from a provided `VolumeClaimTemplate`, or simply an `emptyDir` that is discarded when the `TaskRun`
completes.

`Workspaces` are similar to `Volumes` except that they allow a `Task` author
Expand Down Expand Up @@ -294,9 +294,15 @@ However, they work well for single `TaskRuns` where the data stored in the `empt

#### `persistentVolumeClaim`

The `persistentVolumeClaim` field references a [`persistentVolumeClaim` volume](https://kubernetes.io/docs/concepts/storage/volumes/#persistentvolumeclaim).
The `persistentVolumeClaim` field references an existing [`persistentVolumeClaim` volume](https://kubernetes.io/docs/concepts/storage/volumes/#persistentvolumeclaim).
`PersistentVolumeClaim` volumes are a good choice for sharing data among `Tasks` within a `Pipeline`.

#### `volumeClaimTemplate`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to name it volumeClaimTemplate and not persistentVolumeClaim ?
(Mainy reason for this question is if we should be consistent with the persistentVolumeClaim field)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I borrowed the whole syntax and idea with volumeClaimTemplate from StatefulSet https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#components and wanted to be consistent with that terminology. The persistentVolumeClaim is still there for workspaces and can be used if you want to use an existing PVC.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. I don't have a strong opinion on this, although I would tend to prefer be consistent in the naming with our own API than k8s one 😛

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree with the persistence part, makes lots of sense...


The `volumeClaimTemplate` is a template of a [`persistentVolumeClaim` volume](https://kubernetes.io/docs/concepts/storage/volumes/#persistentvolumeclaim), created for each `PipelineRun` or `TaskRun`.
When the volume is created from a template in a `PipelineRun` or `TaskRun` it will be deleted when the `PipelineRun` or `TaskRun` is deleted.
`volumeClaimTemplate` volumes are a good choice for sharing data among `Tasks` within a `Pipeline` when the volume is only used during a `PipelineRun` or `TaskRun`.

#### `configMap`

The `configMap` field references a [`configMap` volume](https://kubernetes.io/docs/concepts/storage/volumes/#configmap).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: volume-from-template
spec:
tasks:
- name: writer
taskSpec:
steps:
- name: write
image: ubuntu
script: echo bar > $(workspaces.task-ws.path)/foo
workspaces:
- name: task-ws
workspaces:
- name: task-ws
workspace: ws
- name: reader
runAfter:
- writer
taskSpec:
steps:
- name: read
image: ubuntu
script: cat $(workspaces.myws.path)/foo | grep bar
workspaces:
- name: myws
workspaces:
- name: myws
workspace: ws
workspaces:
- name: ws
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: run-with-template-
spec:
pipelineRef:
name: volume-from-template
workspaces:
- name: ws
volumeClaimTemplate:
metadata:
name: mypvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
11 changes: 11 additions & 0 deletions pkg/apis/pipeline/v1alpha1/pipelinerun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,14 @@ func (pr *PipelineRun) GetServiceAccountName(pipelineTaskName string) string {
}
return serviceAccountName
}

// HasVolumeClaimTemplate returns true if PipelineRun contains volumeClaimTemplates that is
// used for creating PersistentVolumeClaims with an OwnerReference for each run
func (pr *PipelineRun) HasVolumeClaimTemplate() bool {
for _, ws := range pr.Spec.Workspaces {
if ws.VolumeClaimTemplate != nil {
return true
}
}
return false
}
19 changes: 19 additions & 0 deletions pkg/apis/pipeline/v1alpha1/pipelinerun_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,25 @@ func TestPipelineRunIsCancelled(t *testing.T) {
}
}

func TestPipelineRunHasVolumeClaimTemplate(t *testing.T) {
pr := &v1alpha1.PipelineRun{
Spec: v1alpha1.PipelineRunSpec{
Workspaces: []v1alpha1.WorkspaceBinding{{
Name: "my-workspace",
VolumeClaimTemplate: &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc",
},
Spec: corev1.PersistentVolumeClaimSpec{},
},
}},
},
}
if !pr.HasVolumeClaimTemplate() {
t.Fatal("Expected pipelinerun to have a volumeClaimTemplate workspace")
}
}

func TestPipelineRunKey(t *testing.T) {
pr := tb.PipelineRun("prunname", "testns")
expectedKey := fmt.Sprintf("PipelineRun/%p", pr)
Expand Down
25 changes: 25 additions & 0 deletions pkg/apis/pipeline/v1alpha1/taskrun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,18 @@ import (
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"knative.dev/pkg/apis"
)

var (
taskRunGroupVersionKind = schema.GroupVersionKind{
Group: SchemeGroupVersion.Group,
Version: SchemeGroupVersion.Version,
Kind: pipeline.TaskRunControllerName,
}
)

// TaskRunSpec defines the desired state of TaskRun
type TaskRunSpec struct {
// +optional
Expand Down Expand Up @@ -165,6 +174,11 @@ func (tr *TaskRun) GetBuildPodRef() corev1.ObjectReference {
}
}

// GetOwnerReference gets the task run as owner reference for any related objects
func (tr *TaskRun) GetOwnerReference() metav1.OwnerReference {
return *metav1.NewControllerRef(tr, taskRunGroupVersionKind)
}

// GetPipelineRunPVCName for taskrun gets pipelinerun
func (tr *TaskRun) GetPipelineRunPVCName() string {
if tr == nil {
Expand Down Expand Up @@ -228,3 +242,14 @@ func (tr *TaskRun) IsPartOfPipeline() (bool, string, string) {

return false, "", ""
}

// HasVolumeClaimTemplate returns true if TaskRun contains volumeClaimTemplates that is
// used for creating PersistentVolumeClaims with an OwnerReference for each run
func (tr *TaskRun) HasVolumeClaimTemplate() bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't those changes be also on v1beta1 ? (even though this is the one used by the controller)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I should add it to v1beta1 as well, yes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the the changes I made on v1alpha1 to v1beta1 and also squashed my commits. Thanks for reviewing.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, not sure where to ask for this, anyone can help with how would you use it in a CLI with tkn to pass the name of the template which already exists in the system (not template file)? e.g.:
image

I have tried this but it continuously says cannot find the PVC (NOTE: the "default-netapp-disk" exists in OpenShift as a VolumeClaimTemplate and it is the default one as well):

_tkn pipeline start pipeline-name -w name=shared-data,claimName=VolumeClaimTemplate,storageClass=default-netapp-disk,accessModes=ReadWriteOnce,storage=1Gi,volumeMode=Filesystem ....

OUTPUT:
message: >-
pod status "PodScheduled":"False"; message: "0/12 nodes are available:
12 persistentvolumeclaim "VolumeClaimTemplate" not found. preemption:
0/12 nodes are available: 12 Preemption is not helpful for scheduling."

I've also tried using 'claimName=default-netapp-disk' as well, and many other things though nothing works when it comes to sending the VCT and it's details through the tkn CLI...

This is very critical to me and I did not really found any useful info during this last week while working on it...

for _, ws := range tr.Spec.Workspaces {
if ws.VolumeClaimTemplate != nil {
return true
}
}
return false
}
19 changes: 19 additions & 0 deletions pkg/apis/pipeline/v1alpha1/taskrun_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,25 @@ func TestTaskRunIsCancelled(t *testing.T) {
}
}

func TestTaskRunHasVolumeClaimTemplate(t *testing.T) {
tr := &v1alpha1.TaskRun{
Spec: v1alpha1.TaskRunSpec{
Workspaces: []v1alpha1.WorkspaceBinding{{
Name: "my-workspace",
VolumeClaimTemplate: &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc",
},
Spec: corev1.PersistentVolumeClaimSpec{},
},
}},
},
}
if !tr.HasVolumeClaimTemplate() {
t.Fatal("Expected taskrun to have a volumeClaimTemplate workspace")
}
}

func TestTaskRunKey(t *testing.T) {
tr := tb.TaskRun("taskrunname", "")
expectedKey := fmt.Sprintf("TaskRun/%p", tr)
Expand Down
11 changes: 11 additions & 0 deletions pkg/apis/pipeline/v1beta1/pipelinerun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ func (pr *PipelineRun) GetServiceAccountName(pipelineTaskName string) string {
return serviceAccountName
}

// HasVolumeClaimTemplate returns true if PipelineRun contains volumeClaimTemplates that is
// used for creating PersistentVolumeClaims with an OwnerReference for each run
func (pr *PipelineRun) HasVolumeClaimTemplate() bool {
for _, ws := range pr.Spec.Workspaces {
if ws.VolumeClaimTemplate != nil {
return true
}
}
return false
}

// PipelineRunSpec defines the desired state of PipelineRun
type PipelineRunSpec struct {
// +optional
Expand Down
19 changes: 19 additions & 0 deletions pkg/apis/pipeline/v1beta1/pipelinerun_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,25 @@ func TestPipelineRunIsCancelled(t *testing.T) {
}
}

func TestPipelineRunHasVolumeClaimTemplate(t *testing.T) {
pr := &v1beta1.PipelineRun{
Spec: v1beta1.PipelineRunSpec{
Workspaces: []v1beta1.WorkspaceBinding{{
Name: "my-workspace",
VolumeClaimTemplate: &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc",
},
Spec: corev1.PersistentVolumeClaimSpec{},
},
}},
},
}
if !pr.HasVolumeClaimTemplate() {
t.Fatal("Expected pipelinerun to have a volumeClaimTemplate workspace")
}
}

func TestPipelineRunKey(t *testing.T) {
pr := tb.PipelineRun("prunname", "testns")
expectedKey := fmt.Sprintf("PipelineRun/%p", pr)
Expand Down
25 changes: 25 additions & 0 deletions pkg/apis/pipeline/v1beta1/taskrun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,19 @@ import (
"github.com/tektoncd/pipeline/pkg/apis/pipeline"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"knative.dev/pkg/apis"
duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1"
)

var (
taskRunGroupVersionKind = schema.GroupVersionKind{
Group: SchemeGroupVersion.Group,
Version: SchemeGroupVersion.Version,
Kind: pipeline.TaskRunControllerName,
}
)

// TaskRunSpec defines the desired state of TaskRun
type TaskRunSpec struct {
// +optional
Expand Down Expand Up @@ -163,6 +172,11 @@ type TaskRunResult struct {
Value string `json:"value"`
}

// GetOwnerReference gets the task run as owner reference for any related objects
func (tr *TaskRun) GetOwnerReference() metav1.OwnerReference {
return *metav1.NewControllerRef(tr, taskRunGroupVersionKind)
}

// GetCondition returns the Condition matching the given type.
func (trs *TaskRunStatus) GetCondition(t apis.ConditionType) *apis.Condition {
return taskRunCondSet.Manage(trs).GetCondition(t)
Expand Down Expand Up @@ -338,3 +352,14 @@ func (tr *TaskRun) IsPartOfPipeline() (bool, string, string) {

return false, "", ""
}

// HasVolumeClaimTemplate returns true if TaskRun contains volumeClaimTemplates that is
// used for creating PersistentVolumeClaims with an OwnerReference for each run
func (tr *TaskRun) HasVolumeClaimTemplate() bool {
for _, ws := range tr.Spec.Workspaces {
if ws.VolumeClaimTemplate != nil {
return true
}
}
return false
}
19 changes: 19 additions & 0 deletions pkg/apis/pipeline/v1beta1/taskrun_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,25 @@ func TestTaskRunIsCancelled(t *testing.T) {
}
}

func TestTaskRunHasVolumeClaimTemplate(t *testing.T) {
tr := &v1beta1.TaskRun{
Spec: v1beta1.TaskRunSpec{
Workspaces: []v1beta1.WorkspaceBinding{{
Name: "my-workspace",
VolumeClaimTemplate: &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc",
},
Spec: corev1.PersistentVolumeClaimSpec{},
},
}},
},
}
if !tr.HasVolumeClaimTemplate() {
t.Fatal("Expected taskrun to have a volumeClaimTemplate workspace")
}
}

func TestTaskRunKey(t *testing.T) {
tr := &v1beta1.TaskRun{
ObjectMeta: metav1.ObjectMeta{
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/pipeline/v1beta1/workspace_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ type WorkspaceBinding struct {
// for this binding (i.e. the volume will be mounted at this sub directory).
// +optional
SubPath string `json:"subPath,omitempty"`
// VolumeClaimTemplate is a template for a claim that will be created in the same namespace.
// The PipelineRun controller is responsible for creating a unique claim for each instance of PipelineRun.
// +optional
VolumeClaimTemplate *corev1.PersistentVolumeClaim `json:"volumeClaimTemplate,omitempty"`
// PersistentVolumeClaimVolumeSource represents a reference to a
// PersistentVolumeClaim in the same namespace. Either this OR EmptyDir can be used.
// +optional
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/pipeline/v1beta1/workspace_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
// WorkspaceBinding may include.
var allVolumeSourceFields []string = []string{
"workspace.persistentvolumeclaim",
"workspace.volumeclaimtemplate",
"workspace.emptydir",
"workspace.configmap",
"workspace.secret",
Expand Down Expand Up @@ -72,6 +73,9 @@ func (b *WorkspaceBinding) Validate(ctx context.Context) *apis.FieldError {
// has been configured with.
func (b *WorkspaceBinding) numSources() int {
n := 0
if b.VolumeClaimTemplate != nil {
n++
}
if b.PersistentVolumeClaim != nil {
n++
}
Expand Down
20 changes: 20 additions & 0 deletions pkg/apis/pipeline/v1beta1/workspace_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"testing"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestWorkspaceBindingValidateValid(t *testing.T) {
Expand All @@ -35,6 +37,24 @@ func TestWorkspaceBindingValidateValid(t *testing.T) {
ClaimName: "pool-party",
},
},
}, {
name: "Valid volumeClaimTemplate",
binding: &WorkspaceBinding{
Name: "beth",
VolumeClaimTemplate: &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "mypvc",
},
Spec: corev1.PersistentVolumeClaimSpec{
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
"storage": resource.MustParse("1Gi"),
},
},
},
},
},
}, {
name: "Valid emptyDir",
binding: &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.

Loading