From 42370f6b54840eaa692f855fbea27fbbb26d37e0 Mon Sep 17 00:00:00 2001 From: Julien Vincent Date: Mon, 25 May 2026 11:13:07 +0100 Subject: [PATCH 1/2] Allow disabling service workspace volumes in k8s Currently when using the Kubernetes backend all services are provisioned with the workspace PVC volume mounted. This causes problems when using `ReadWriteOnce` PVC volumes in multi-node clusters as the service and step Pods can be provisioned onto different nodes. A workaround for this is to use the PodAffinity controls on the agent: ```yaml env: WOODPECKER_BACKEND_K8S_POD_AFFINITY: | podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: {} matchLabelKeys: ['woodpecker-ci.org/task-uuid'] topologyKey: 'kubernetes.io/hostname' ``` This ensures the step Pods are provisioned onto nodes already containing Pods from the same task. This will always result in co-locating the service Pods with step Pods. While this kind of works, it means that a single Node now needs to be sized appropriately to host all the service Pods as well as the step Pod which uses them. A better solution that allows distributing service Pods over all the available nodes is to stop attaching the workspace PVC to service Pods. A similar problem/solution is discussed in #3344, as well as some related discussion in https://github.com/woodpecker-ci/woodpecker/discussions/5312. The discussion in #3344 mentions attaching a dedicated PVC to services, but IMO this overly complicates things and adds very little value. I believe that for most use-cases services' won't need to interact with a PVC at all. They are just there to run a database or service dependency. --- This change introduces two new controls: - An agent-level environment variable `WOODPECKER_BACKEND_K8S_SERVICE_WORKSPACE_VOLUME` which defaults to `true`. - A step-level Kubernetes backend option `backend_options.kubernetes.workspaceVolume` which also defaults to `true`. If either of these are set to `false` then the workspace PVC will not be attached to the Pod. Closes #3344 --- .../11-backends/20-kubernetes.md | 27 +++++++++++ .../backend/kubernetes/backend_options.go | 1 + .../kubernetes/backend_options_test.go | 2 + pipeline/backend/kubernetes/flags.go | 6 +++ pipeline/backend/kubernetes/kubernetes.go | 2 + .../backend/kubernetes/kubernetes_test.go | 20 +++++++++ pipeline/backend/kubernetes/pod.go | 29 ++++++++++-- pipeline/backend/kubernetes/pod_test.go | 45 +++++++++++++++++++ 8 files changed, 128 insertions(+), 4 deletions(-) diff --git a/docs/docs/30-administration/10-configuration/11-backends/20-kubernetes.md b/docs/docs/30-administration/10-configuration/11-backends/20-kubernetes.md index a6f43a683af..951aa3734d2 100644 --- a/docs/docs/30-administration/10-configuration/11-backends/20-kubernetes.md +++ b/docs/docs/30-administration/10-configuration/11-backends/20-kubernetes.md @@ -81,6 +81,23 @@ steps: To give steps access to the Kubernetes API via service account, take a look at [RBAC Authorization](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) +### Workspace volume + +`workspaceVolume` controls whether the default workspace volume is mounted into a +service Pod. It only affects service containers and does not disable explicitly +configured service volumes. + +If unset, the value of `WOODPECKER_BACKEND_K8S_SERVICE_WORKSPACE_VOLUME` is used. + +```yaml +services: + postgres: + image: postgres:16 + backend_options: + kubernetes: + workspaceVolume: false +``` + ### Node selector `nodeSelector` specifies the labels which are used to select the node on which the step will be executed. @@ -499,6 +516,16 @@ Determines if `RWX` should be used for the pipeline volume's [access mode](https --- +### BACKEND_K8S_SERVICE_WORKSPACE_VOLUME + +- Name: `WOODPECKER_BACKEND_K8S_SERVICE_WORKSPACE_VOLUME` +- Default: `true` + +Determines if the default workspace volume should be mounted into service Pods. +Explicit service volumes are still mounted. + +--- + ### BACKEND_K8S_POD_LABELS - Name: `WOODPECKER_BACKEND_K8S_POD_LABELS` diff --git a/pipeline/backend/kubernetes/backend_options.go b/pipeline/backend/kubernetes/backend_options.go index 5f37f2690a8..e0882e3bee4 100644 --- a/pipeline/backend/kubernetes/backend_options.go +++ b/pipeline/backend/kubernetes/backend_options.go @@ -33,6 +33,7 @@ type BackendOptions struct { Affinity *kube_core_v1.Affinity `mapstructure:"affinity"` SecurityContext *SecurityContext `mapstructure:"securityContext"` Secrets []SecretRef `mapstructure:"secrets"` + WorkspaceVolume *bool `mapstructure:"workspaceVolume"` } // Resources defines two maps for kubernetes resource definitions. diff --git a/pipeline/backend/kubernetes/backend_options_test.go b/pipeline/backend/kubernetes/backend_options_test.go index f1d22cae27b..7a228e85c8e 100644 --- a/pipeline/backend/kubernetes/backend_options_test.go +++ b/pipeline/backend/kubernetes/backend_options_test.go @@ -48,6 +48,7 @@ func Test_parseBackendOptions(t *testing.T) { "kubernetes": map[string]any{ "nodeSelector": map[string]string{"storage": "ssd"}, "serviceAccountName": "wp-svc-acc", + "workspaceVolume": false, "labels": map[string]string{"app": "test"}, "annotations": map[string]string{"apps.kubernetes.io/pod-index": "0"}, "tolerations": []map[string]any{ @@ -107,6 +108,7 @@ func Test_parseBackendOptions(t *testing.T) { want: BackendOptions{ NodeSelector: map[string]string{"storage": "ssd"}, ServiceAccountName: "wp-svc-acc", + WorkspaceVolume: newBool(false), Labels: map[string]string{"app": "test"}, Annotations: map[string]string{"apps.kubernetes.io/pod-index": "0"}, Tolerations: []Toleration{{Key: "net-port", Value: "100Mbit", Effect: TaintEffectNoSchedule}}, diff --git a/pipeline/backend/kubernetes/flags.go b/pipeline/backend/kubernetes/flags.go index f34cb6538b2..ebe1059f1e1 100644 --- a/pipeline/backend/kubernetes/flags.go +++ b/pipeline/backend/kubernetes/flags.go @@ -49,6 +49,12 @@ var Flags = []cli.Flag{ Usage: "backend k8s storage access mode, should ReadWriteMany (RWX) instead of ReadWriteOnce (RWO) be used? (default: true)", Value: true, }, + &cli.BoolFlag{ + Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_SERVICE_WORKSPACE_VOLUME"), + Name: "backend-k8s-service-workspace-volume", + Usage: "whether to mount the default workspace volume into service pods", + Value: true, + }, &cli.StringFlag{ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_POD_LABELS"), Name: "backend-k8s-pod-labels", diff --git a/pipeline/backend/kubernetes/kubernetes.go b/pipeline/backend/kubernetes/kubernetes.go index 8ba29b4cd26..8e0ff44cb18 100644 --- a/pipeline/backend/kubernetes/kubernetes.go +++ b/pipeline/backend/kubernetes/kubernetes.go @@ -64,6 +64,7 @@ type config struct { StorageClass string VolumeSize string StorageRwx bool + UseServiceWorkspaceVolume bool PodLabels map[string]string PodLabelsAllowFromStep bool PodAnnotations map[string]string @@ -110,6 +111,7 @@ func configFromCliContext(ctx context.Context) (*config, error) { StorageClass: c.String("backend-k8s-storage-class"), VolumeSize: c.String("backend-k8s-volume-size"), StorageRwx: c.Bool("backend-k8s-storage-rwx"), + UseServiceWorkspaceVolume: c.Bool("backend-k8s-service-workspace-volume"), PriorityClassName: c.String("backend-k8s-priority-class"), PodLabels: make(map[string]string), // just init empty map to prevent nil panic PodLabelsAllowFromStep: c.Bool("backend-k8s-pod-labels-allow-from-step"), diff --git a/pipeline/backend/kubernetes/kubernetes_test.go b/pipeline/backend/kubernetes/kubernetes_test.go index ab4e014378e..1dc3d60d24b 100644 --- a/pipeline/backend/kubernetes/kubernetes_test.go +++ b/pipeline/backend/kubernetes/kubernetes_test.go @@ -181,6 +181,26 @@ func TestAffinityFromCliContext(t *testing.T) { require.NoError(t, err) } +func TestServiceWorkspaceVolumeFromCliContext(t *testing.T) { + t.Setenv("WOODPECKER_BACKEND_K8S_SERVICE_WORKSPACE_VOLUME", "false") + + cmd := &cli.Command{ + Flags: Flags, + Action: func(ctx context.Context, c *cli.Command) error { + ctx = context.WithValue(ctx, types.CliCommand, c) + config, err := configFromCliContext(ctx) + + require.NoError(t, err) + require.NotNil(t, config) + assert.False(t, config.UseServiceWorkspaceVolume) + + return nil + }, + } + err := cmd.Run(context.Background(), []string{"test"}) + require.NoError(t, err) +} + func makeStep(uuid string) *types.Step { return &types.Step{ UUID: uuid, diff --git a/pipeline/backend/kubernetes/pod.go b/pipeline/backend/kubernetes/pod.go index c77ccb94d23..85f924b4ad4 100644 --- a/pipeline/backend/kubernetes/pod.go +++ b/pipeline/backend/kubernetes/pod.go @@ -61,7 +61,7 @@ func mkPod(step *types.Step, config *config, podName, goos string, options Backe return nil, err } - container, err := podContainer(step, podName, goos, options, nsp) + container, err := podContainer(step, config, podName, goos, options, nsp) if err != nil { return nil, err } @@ -206,7 +206,7 @@ func podSpec(step *types.Step, config *config, options BackendOptions, nsp nativ spec.Tolerations = tolerations(config.PodTolerations) } - spec.Volumes, err = pvcVolumes(step.Volumes) + spec.Volumes, err = pvcVolumes(podVolumes(step, config, options)) if err != nil { return spec, err } @@ -237,7 +237,7 @@ func podSpec(step *types.Step, config *config, options BackendOptions, nsp nativ return spec, nil } -func podContainer(step *types.Step, podName, goos string, options BackendOptions, nsp nativeSecretsProcessor) (kube_core_v1.Container, error) { +func podContainer(step *types.Step, config *config, podName, goos string, options BackendOptions, nsp nativeSecretsProcessor) (kube_core_v1.Container, error) { var err error container := kube_core_v1.Container{ Name: podName, @@ -278,7 +278,7 @@ func podContainer(step *types.Step, podName, goos string, options BackendOptions return container, err } - container.VolumeMounts, err = volumeMounts(step.Volumes) + container.VolumeMounts, err = volumeMounts(podVolumes(step, config, options)) if err != nil { return container, err } @@ -388,6 +388,27 @@ func pvcVolumes(volumes []string) ([]kube_core_v1.Volume, error) { return vols, nil } +func podVolumes(step *types.Step, config *config, options BackendOptions) []string { + if !isService(step) || useWorkspaceVolume(config, options) { + return step.Volumes + } + + volumes := make([]string, 0, len(step.Volumes)) + for _, volume := range step.Volumes { + if volumeMountPath(volume) != step.WorkspaceBase { + volumes = append(volumes, volume) + } + } + return volumes +} + +func useWorkspaceVolume(config *config, options BackendOptions) bool { + if options.WorkspaceVolume != nil { + return *options.WorkspaceVolume + } + return config == nil || config.UseServiceWorkspaceVolume +} + func pvcVolume(name string) kube_core_v1.Volume { pvcSource := kube_core_v1.PersistentVolumeClaimVolumeSource{ ClaimName: name, diff --git a/pipeline/backend/kubernetes/pod_test.go b/pipeline/backend/kubernetes/pod_test.go index 1aa17ac5c9a..68e12957617 100644 --- a/pipeline/backend/kubernetes/pod_test.go +++ b/pipeline/backend/kubernetes/pod_test.go @@ -220,6 +220,51 @@ func TestTinyPod(t *testing.T) { ja.Assertf(string(podJSON), expected) } +func TestServiceWorkspaceVolume(t *testing.T) { + useWorkspaceVolume := true + disableWorkspaceVolume := false + step := &types.Step{ + Name: "postgres", + Image: "postgres:16", + UUID: "01he8bebctabr3kgk0qj36d2me-0", + Type: types.StepTypeService, + WorkingDir: "/woodpecker/src", + WorkspaceBase: "/woodpecker", + Environment: map[string]string{}, + Volumes: []string{"workspace:/woodpecker", "cache:/cache"}, + } + + pod, err := mkPod(step, &config{Namespace: "woodpecker", UseServiceWorkspaceVolume: true}, "wp-svc-postgres", "linux/amd64", BackendOptions{}, taskUUID) + assert.NoError(t, err) + assert.Len(t, pod.Spec.Volumes, 2) + assert.Equal(t, "workspace", pod.Spec.Volumes[0].Name) + assert.Equal(t, "/woodpecker", pod.Spec.Containers[0].VolumeMounts[0].MountPath) + assert.Equal(t, "cache", pod.Spec.Volumes[1].Name) + assert.Equal(t, "/cache", pod.Spec.Containers[0].VolumeMounts[1].MountPath) + + pod, err = mkPod(step, &config{Namespace: "woodpecker", UseServiceWorkspaceVolume: false}, "wp-svc-postgres", "linux/amd64", BackendOptions{}, taskUUID) + assert.NoError(t, err) + assert.Len(t, pod.Spec.Volumes, 1) + assert.Equal(t, "cache", pod.Spec.Volumes[0].Name) + assert.Len(t, pod.Spec.Containers[0].VolumeMounts, 1) + assert.Equal(t, "/cache", pod.Spec.Containers[0].VolumeMounts[0].MountPath) + + pod, err = mkPod(step, &config{Namespace: "woodpecker", UseServiceWorkspaceVolume: true}, "wp-svc-postgres", "linux/amd64", BackendOptions{WorkspaceVolume: &disableWorkspaceVolume}, taskUUID) + assert.NoError(t, err) + assert.Len(t, pod.Spec.Volumes, 1) + assert.Equal(t, "cache", pod.Spec.Volumes[0].Name) + assert.Len(t, pod.Spec.Containers[0].VolumeMounts, 1) + assert.Equal(t, "/cache", pod.Spec.Containers[0].VolumeMounts[0].MountPath) + + pod, err = mkPod(step, &config{Namespace: "woodpecker", UseServiceWorkspaceVolume: false}, "wp-svc-postgres", "linux/amd64", BackendOptions{WorkspaceVolume: &useWorkspaceVolume}, taskUUID) + assert.NoError(t, err) + assert.Len(t, pod.Spec.Volumes, 2) + assert.Equal(t, "workspace", pod.Spec.Volumes[0].Name) + assert.Equal(t, "/woodpecker", pod.Spec.Containers[0].VolumeMounts[0].MountPath) + assert.Equal(t, "cache", pod.Spec.Volumes[1].Name) + assert.Equal(t, "/cache", pod.Spec.Containers[0].VolumeMounts[1].MountPath) +} + func TestFullPod(t *testing.T) { const expected = ` { From 53b09652a3782fa2021f2a082e3b5a2b8cabc001 Mon Sep 17 00:00:00 2001 From: Julien Vincent Date: Tue, 26 May 2026 17:02:02 +0100 Subject: [PATCH 2/2] Remove agent service-workspace-volume flag --- .../11-backends/20-kubernetes.md | 17 +++------------- pipeline/backend/kubernetes/flags.go | 6 ------ pipeline/backend/kubernetes/kubernetes.go | 2 -- .../backend/kubernetes/kubernetes_test.go | 20 ------------------- pipeline/backend/kubernetes/pod.go | 16 +++++++-------- pipeline/backend/kubernetes/pod_test.go | 13 +++--------- 6 files changed, 14 insertions(+), 60 deletions(-) diff --git a/docs/docs/30-administration/10-configuration/11-backends/20-kubernetes.md b/docs/docs/30-administration/10-configuration/11-backends/20-kubernetes.md index 951aa3734d2..e2796f5ba64 100644 --- a/docs/docs/30-administration/10-configuration/11-backends/20-kubernetes.md +++ b/docs/docs/30-administration/10-configuration/11-backends/20-kubernetes.md @@ -83,11 +83,10 @@ To give steps access to the Kubernetes API via service account, take a look at [ ### Workspace volume -`workspaceVolume` controls whether the default workspace volume is mounted into a -service Pod. It only affects service containers and does not disable explicitly -configured service volumes. +`workspaceVolume` controls whether the default workspace volume is mounted into a service Pod. It only affects service +containers and does not disable explicitly configured service volumes. -If unset, the value of `WOODPECKER_BACKEND_K8S_SERVICE_WORKSPACE_VOLUME` is used. +If unset, the default workspace volume is mounted. ```yaml services: @@ -516,16 +515,6 @@ Determines if `RWX` should be used for the pipeline volume's [access mode](https --- -### BACKEND_K8S_SERVICE_WORKSPACE_VOLUME - -- Name: `WOODPECKER_BACKEND_K8S_SERVICE_WORKSPACE_VOLUME` -- Default: `true` - -Determines if the default workspace volume should be mounted into service Pods. -Explicit service volumes are still mounted. - ---- - ### BACKEND_K8S_POD_LABELS - Name: `WOODPECKER_BACKEND_K8S_POD_LABELS` diff --git a/pipeline/backend/kubernetes/flags.go b/pipeline/backend/kubernetes/flags.go index ebe1059f1e1..f34cb6538b2 100644 --- a/pipeline/backend/kubernetes/flags.go +++ b/pipeline/backend/kubernetes/flags.go @@ -49,12 +49,6 @@ var Flags = []cli.Flag{ Usage: "backend k8s storage access mode, should ReadWriteMany (RWX) instead of ReadWriteOnce (RWO) be used? (default: true)", Value: true, }, - &cli.BoolFlag{ - Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_SERVICE_WORKSPACE_VOLUME"), - Name: "backend-k8s-service-workspace-volume", - Usage: "whether to mount the default workspace volume into service pods", - Value: true, - }, &cli.StringFlag{ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_POD_LABELS"), Name: "backend-k8s-pod-labels", diff --git a/pipeline/backend/kubernetes/kubernetes.go b/pipeline/backend/kubernetes/kubernetes.go index 8e0ff44cb18..8ba29b4cd26 100644 --- a/pipeline/backend/kubernetes/kubernetes.go +++ b/pipeline/backend/kubernetes/kubernetes.go @@ -64,7 +64,6 @@ type config struct { StorageClass string VolumeSize string StorageRwx bool - UseServiceWorkspaceVolume bool PodLabels map[string]string PodLabelsAllowFromStep bool PodAnnotations map[string]string @@ -111,7 +110,6 @@ func configFromCliContext(ctx context.Context) (*config, error) { StorageClass: c.String("backend-k8s-storage-class"), VolumeSize: c.String("backend-k8s-volume-size"), StorageRwx: c.Bool("backend-k8s-storage-rwx"), - UseServiceWorkspaceVolume: c.Bool("backend-k8s-service-workspace-volume"), PriorityClassName: c.String("backend-k8s-priority-class"), PodLabels: make(map[string]string), // just init empty map to prevent nil panic PodLabelsAllowFromStep: c.Bool("backend-k8s-pod-labels-allow-from-step"), diff --git a/pipeline/backend/kubernetes/kubernetes_test.go b/pipeline/backend/kubernetes/kubernetes_test.go index 1dc3d60d24b..ab4e014378e 100644 --- a/pipeline/backend/kubernetes/kubernetes_test.go +++ b/pipeline/backend/kubernetes/kubernetes_test.go @@ -181,26 +181,6 @@ func TestAffinityFromCliContext(t *testing.T) { require.NoError(t, err) } -func TestServiceWorkspaceVolumeFromCliContext(t *testing.T) { - t.Setenv("WOODPECKER_BACKEND_K8S_SERVICE_WORKSPACE_VOLUME", "false") - - cmd := &cli.Command{ - Flags: Flags, - Action: func(ctx context.Context, c *cli.Command) error { - ctx = context.WithValue(ctx, types.CliCommand, c) - config, err := configFromCliContext(ctx) - - require.NoError(t, err) - require.NotNil(t, config) - assert.False(t, config.UseServiceWorkspaceVolume) - - return nil - }, - } - err := cmd.Run(context.Background(), []string{"test"}) - require.NoError(t, err) -} - func makeStep(uuid string) *types.Step { return &types.Step{ UUID: uuid, diff --git a/pipeline/backend/kubernetes/pod.go b/pipeline/backend/kubernetes/pod.go index 85f924b4ad4..06e1bd9d79b 100644 --- a/pipeline/backend/kubernetes/pod.go +++ b/pipeline/backend/kubernetes/pod.go @@ -61,7 +61,7 @@ func mkPod(step *types.Step, config *config, podName, goos string, options Backe return nil, err } - container, err := podContainer(step, config, podName, goos, options, nsp) + container, err := podContainer(step, podName, goos, options, nsp) if err != nil { return nil, err } @@ -206,7 +206,7 @@ func podSpec(step *types.Step, config *config, options BackendOptions, nsp nativ spec.Tolerations = tolerations(config.PodTolerations) } - spec.Volumes, err = pvcVolumes(podVolumes(step, config, options)) + spec.Volumes, err = pvcVolumes(podVolumes(step, options)) if err != nil { return spec, err } @@ -237,7 +237,7 @@ func podSpec(step *types.Step, config *config, options BackendOptions, nsp nativ return spec, nil } -func podContainer(step *types.Step, config *config, podName, goos string, options BackendOptions, nsp nativeSecretsProcessor) (kube_core_v1.Container, error) { +func podContainer(step *types.Step, podName, goos string, options BackendOptions, nsp nativeSecretsProcessor) (kube_core_v1.Container, error) { var err error container := kube_core_v1.Container{ Name: podName, @@ -278,7 +278,7 @@ func podContainer(step *types.Step, config *config, podName, goos string, option return container, err } - container.VolumeMounts, err = volumeMounts(podVolumes(step, config, options)) + container.VolumeMounts, err = volumeMounts(podVolumes(step, options)) if err != nil { return container, err } @@ -388,8 +388,8 @@ func pvcVolumes(volumes []string) ([]kube_core_v1.Volume, error) { return vols, nil } -func podVolumes(step *types.Step, config *config, options BackendOptions) []string { - if !isService(step) || useWorkspaceVolume(config, options) { +func podVolumes(step *types.Step, options BackendOptions) []string { + if !isService(step) || useWorkspaceVolume(options) { return step.Volumes } @@ -402,11 +402,11 @@ func podVolumes(step *types.Step, config *config, options BackendOptions) []stri return volumes } -func useWorkspaceVolume(config *config, options BackendOptions) bool { +func useWorkspaceVolume(options BackendOptions) bool { if options.WorkspaceVolume != nil { return *options.WorkspaceVolume } - return config == nil || config.UseServiceWorkspaceVolume + return true } func pvcVolume(name string) kube_core_v1.Volume { diff --git a/pipeline/backend/kubernetes/pod_test.go b/pipeline/backend/kubernetes/pod_test.go index 68e12957617..5b5a5c1edf7 100644 --- a/pipeline/backend/kubernetes/pod_test.go +++ b/pipeline/backend/kubernetes/pod_test.go @@ -234,7 +234,7 @@ func TestServiceWorkspaceVolume(t *testing.T) { Volumes: []string{"workspace:/woodpecker", "cache:/cache"}, } - pod, err := mkPod(step, &config{Namespace: "woodpecker", UseServiceWorkspaceVolume: true}, "wp-svc-postgres", "linux/amd64", BackendOptions{}, taskUUID) + pod, err := mkPod(step, &config{Namespace: "woodpecker"}, "wp-svc-postgres", "linux/amd64", BackendOptions{}, taskUUID) assert.NoError(t, err) assert.Len(t, pod.Spec.Volumes, 2) assert.Equal(t, "workspace", pod.Spec.Volumes[0].Name) @@ -242,21 +242,14 @@ func TestServiceWorkspaceVolume(t *testing.T) { assert.Equal(t, "cache", pod.Spec.Volumes[1].Name) assert.Equal(t, "/cache", pod.Spec.Containers[0].VolumeMounts[1].MountPath) - pod, err = mkPod(step, &config{Namespace: "woodpecker", UseServiceWorkspaceVolume: false}, "wp-svc-postgres", "linux/amd64", BackendOptions{}, taskUUID) + pod, err = mkPod(step, &config{Namespace: "woodpecker"}, "wp-svc-postgres", "linux/amd64", BackendOptions{WorkspaceVolume: &disableWorkspaceVolume}, taskUUID) assert.NoError(t, err) assert.Len(t, pod.Spec.Volumes, 1) assert.Equal(t, "cache", pod.Spec.Volumes[0].Name) assert.Len(t, pod.Spec.Containers[0].VolumeMounts, 1) assert.Equal(t, "/cache", pod.Spec.Containers[0].VolumeMounts[0].MountPath) - pod, err = mkPod(step, &config{Namespace: "woodpecker", UseServiceWorkspaceVolume: true}, "wp-svc-postgres", "linux/amd64", BackendOptions{WorkspaceVolume: &disableWorkspaceVolume}, taskUUID) - assert.NoError(t, err) - assert.Len(t, pod.Spec.Volumes, 1) - assert.Equal(t, "cache", pod.Spec.Volumes[0].Name) - assert.Len(t, pod.Spec.Containers[0].VolumeMounts, 1) - assert.Equal(t, "/cache", pod.Spec.Containers[0].VolumeMounts[0].MountPath) - - pod, err = mkPod(step, &config{Namespace: "woodpecker", UseServiceWorkspaceVolume: false}, "wp-svc-postgres", "linux/amd64", BackendOptions{WorkspaceVolume: &useWorkspaceVolume}, taskUUID) + pod, err = mkPod(step, &config{Namespace: "woodpecker"}, "wp-svc-postgres", "linux/amd64", BackendOptions{WorkspaceVolume: &useWorkspaceVolume}, taskUUID) assert.NoError(t, err) assert.Len(t, pod.Spec.Volumes, 2) assert.Equal(t, "workspace", pod.Spec.Volumes[0].Name)