From f7c50cc9b243d31bbbf137cec8ace309ea3c82be Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Mon, 20 Apr 2026 17:49:31 +0200 Subject: [PATCH 1/2] Render empty arrays for kubernetes-novolume volumes fields Fixes #4411 --- .../templates/_helpers.tpl | 4 + .../templates/autoscalingrunnerset.yaml | 4 +- .../tests/template_test.go | 82 +++++++++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/charts/gha-runner-scale-set/templates/_helpers.tpl b/charts/gha-runner-scale-set/templates/_helpers.tpl index 53b1c2b3f5..4ad4bfef9f 100644 --- a/charts/gha-runner-scale-set/templates/_helpers.tpl +++ b/charts/gha-runner-scale-set/templates/_helpers.tpl @@ -468,6 +468,7 @@ env: {{- if $tlsConfig.runnerMountPath }} {{- $mountGitHubServerTLS = 1 }} {{- end }} + {{- if or $container.volumeMounts $mountGitHubServerTLS }} volumeMounts: {{- with $container.volumeMounts }} {{- range $i, $volMount := . }} @@ -482,6 +483,9 @@ volumeMounts: mountPath: {{ clean (print $tlsConfig.runnerMountPath "/" $tlsConfig.certificateFrom.configMapKeyRef.key) }} subPath: {{ $tlsConfig.certificateFrom.configMapKeyRef.key }} {{- end }} + {{- else }} +volumeMounts: [] + {{- end }} {{- end }} {{- end }} {{- end }} diff --git a/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml b/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml index 1a466d5b0d..45817de28f 100644 --- a/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml +++ b/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml @@ -269,7 +269,7 @@ spec: {{- include "gha-runner-scale-set.default-mode-runner-containers" . | nindent 6 }} {{- end }} {{- $tlsConfig := (default (dict) .Values.githubServerTLS) }} - {{- if or .Values.template.spec.volumes (eq $containerMode.type "dind") (eq $containerMode.type "kubernetes") (eq $containerMode.type "kubernetes-novolume") $tlsConfig.runnerMountPath }} + {{- if or .Values.template.spec.volumes (eq $containerMode.type "dind") (eq $containerMode.type "kubernetes") $tlsConfig.runnerMountPath }} volumes: {{- if $tlsConfig.runnerMountPath }} {{- include "gha-runner-scale-set.tls-volume" $tlsConfig | nindent 6 }} @@ -286,4 +286,6 @@ spec: {{- toYaml . | nindent 6 }} {{- end }} {{- end }} + {{- else if eq $containerMode.type "kubernetes-novolume" }} + volumes: [] {{- end }} diff --git a/charts/gha-runner-scale-set/tests/template_test.go b/charts/gha-runner-scale-set/tests/template_test.go index 00e16a7f82..802dbb18da 100644 --- a/charts/gha-runner-scale-set/tests/template_test.go +++ b/charts/gha-runner-scale-set/tests/template_test.go @@ -1154,6 +1154,88 @@ func TestTemplateRenderedAutoScalingRunnerSet_EnableKubernetesModeNoVolume(t *te assert.Equal(t, ars.Spec.Template.Spec.Containers[0].Image, ars.Spec.Template.Spec.Containers[0].Env[3].Value) assert.Len(t, ars.Spec.Template.Spec.Volumes, 0, "Template.Spec should have 0 volumes") + assert.NotNil(t, ars.Spec.Template.Spec.Volumes, "Template.Spec.Volumes should be non-nil empty slice, not null") + + // Regression check: ensure volumeMounts is also non-nil empty slice for kubernetes-novolume + runnerContainer := ars.Spec.Template.Spec.Containers[0] + assert.NotNil(t, runnerContainer.VolumeMounts, "runner container VolumeMounts should be non-nil empty slice, not null") + assert.Len(t, runnerContainer.VolumeMounts, 0, "runner container should have 0 volumeMounts in kubernetes-novolume mode") +} + +func TestTemplateRenderedAutoScalingRunnerSet_EnableKubernetesModeNoVolume_WithCustomVolumes(t *testing.T) { + t.Parallel() + + // Path to the helm chart we will test + helmChartPath, err := filepath.Abs("../../gha-runner-scale-set") + require.NoError(t, err) + + releaseName := "test-runners" + namespaceName := "test-" + strings.ToLower(random.UniqueId()) + + // Test that user-provided volumes are preserved even in kubernetes-novolume mode + options := &helm.Options{ + Logger: logger.Discard, + SetValues: map[string]string{ + "githubConfigUrl": "https://github.com/actions", + "githubConfigSecret.github_token": "gh_token12345", + "containerMode.type": "kubernetes-novolume", + "controllerServiceAccount.name": "arc", + "controllerServiceAccount.namespace": "arc-system", + "template.spec.volumes[0].name": "custom-volume", + "template.spec.volumes[0].emptyDir": "{}", + }, + KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), + } + + output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) + + var ars v1alpha1.AutoscalingRunnerSet + helm.UnmarshalK8SYaml(t, output, &ars) + + // Override preservation: user-provided volume should be present, not replaced by empty array + assert.Len(t, ars.Spec.Template.Spec.Volumes, 1, "Template.Spec should have 1 volume (user-provided override)") + assert.Equal(t, "custom-volume", ars.Spec.Template.Spec.Volumes[0].Name, "Volume name should be preserved as custom-volume") + assert.NotNil(t, ars.Spec.Template.Spec.Volumes[0].EmptyDir, "Volume should have EmptyDir configured") +} + +func TestTemplateRenderedAutoScalingRunnerSet_EnableKubernetesModeNoVolume_WithCustomVolumeMounts(t *testing.T) { + t.Parallel() + + // Path to the helm chart we will test + helmChartPath, err := filepath.Abs("../../gha-runner-scale-set") + require.NoError(t, err) + + releaseName := "test-runners" + namespaceName := "test-" + strings.ToLower(random.UniqueId()) + + // Test that user-provided volumeMounts are preserved in kubernetes-novolume runner container + options := &helm.Options{ + Logger: logger.Discard, + SetValues: map[string]string{ + "githubConfigUrl": "https://github.com/actions", + "githubConfigSecret.github_token": "gh_token12345", + "containerMode.type": "kubernetes-novolume", + "controllerServiceAccount.name": "arc", + "controllerServiceAccount.namespace": "arc-system", + "template.spec.volumes[0].name": "custom-volume", + "template.spec.volumes[0].emptyDir": "{}", + "template.spec.containers[0].name": "runner", + "template.spec.containers[0].volumeMounts[0].name": "custom-volume", + "template.spec.containers[0].volumeMounts[0].mountPath": "/mnt/custom", + }, + KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), + } + + output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) + + var ars v1alpha1.AutoscalingRunnerSet + helm.UnmarshalK8SYaml(t, output, &ars) + + runnerContainer := ars.Spec.Template.Spec.Containers[0] + // Override preservation: user-provided volumeMounts should be present, not replaced by empty array + assert.Len(t, runnerContainer.VolumeMounts, 1, "runner container should have 1 volumeMount (user-provided override)") + assert.Equal(t, "custom-volume", runnerContainer.VolumeMounts[0].Name, "VolumeMount name should be preserved as custom-volume") + assert.Equal(t, "/mnt/custom", runnerContainer.VolumeMounts[0].MountPath, "VolumeMount path should be preserved as /mnt/custom") } func TestTemplateRenderedAutoscalingRunnerSet_ListenerPodTemplate(t *testing.T) { From c46200c06ac4a293ad9f4d1c4f2b64ebd3922816 Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Mon, 20 Apr 2026 18:53:01 +0200 Subject: [PATCH 2/2] test(gha-runner-scale-set): fix emptyDir tests to use ValuesFiles Replace SetValues with ValuesFiles for tests that use emptyDir: {} to avoid Helm CLI's --set limitation that misparses object syntax. - Create values_k8s_novolume_custom_volumes.yaml - Create values_k8s_novolume_custom_volume_mounts.yaml - Update WithCustomVolumes and WithCustomVolumeMounts tests Fixes test failures introduced in previous commit. --- .../tests/template_test.go | 33 ++++++------------- ...ues_k8s_novolume_custom_volume_mounts.yaml | 18 ++++++++++ .../values_k8s_novolume_custom_volumes.yaml | 13 ++++++++ 3 files changed, 41 insertions(+), 23 deletions(-) create mode 100644 charts/gha-runner-scale-set/tests/values_k8s_novolume_custom_volume_mounts.yaml create mode 100644 charts/gha-runner-scale-set/tests/values_k8s_novolume_custom_volumes.yaml diff --git a/charts/gha-runner-scale-set/tests/template_test.go b/charts/gha-runner-scale-set/tests/template_test.go index 802dbb18da..ba67ea90ec 100644 --- a/charts/gha-runner-scale-set/tests/template_test.go +++ b/charts/gha-runner-scale-set/tests/template_test.go @@ -1169,21 +1169,16 @@ func TestTemplateRenderedAutoScalingRunnerSet_EnableKubernetesModeNoVolume_WithC helmChartPath, err := filepath.Abs("../../gha-runner-scale-set") require.NoError(t, err) + testValuesPath, err := filepath.Abs("../tests/values_k8s_novolume_custom_volumes.yaml") + require.NoError(t, err) + releaseName := "test-runners" namespaceName := "test-" + strings.ToLower(random.UniqueId()) // Test that user-provided volumes are preserved even in kubernetes-novolume mode options := &helm.Options{ - Logger: logger.Discard, - SetValues: map[string]string{ - "githubConfigUrl": "https://github.com/actions", - "githubConfigSecret.github_token": "gh_token12345", - "containerMode.type": "kubernetes-novolume", - "controllerServiceAccount.name": "arc", - "controllerServiceAccount.namespace": "arc-system", - "template.spec.volumes[0].name": "custom-volume", - "template.spec.volumes[0].emptyDir": "{}", - }, + Logger: logger.Discard, + ValuesFiles: []string{testValuesPath}, KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), } @@ -1205,24 +1200,16 @@ func TestTemplateRenderedAutoScalingRunnerSet_EnableKubernetesModeNoVolume_WithC helmChartPath, err := filepath.Abs("../../gha-runner-scale-set") require.NoError(t, err) + testValuesPath, err := filepath.Abs("../tests/values_k8s_novolume_custom_volume_mounts.yaml") + require.NoError(t, err) + releaseName := "test-runners" namespaceName := "test-" + strings.ToLower(random.UniqueId()) // Test that user-provided volumeMounts are preserved in kubernetes-novolume runner container options := &helm.Options{ - Logger: logger.Discard, - SetValues: map[string]string{ - "githubConfigUrl": "https://github.com/actions", - "githubConfigSecret.github_token": "gh_token12345", - "containerMode.type": "kubernetes-novolume", - "controllerServiceAccount.name": "arc", - "controllerServiceAccount.namespace": "arc-system", - "template.spec.volumes[0].name": "custom-volume", - "template.spec.volumes[0].emptyDir": "{}", - "template.spec.containers[0].name": "runner", - "template.spec.containers[0].volumeMounts[0].name": "custom-volume", - "template.spec.containers[0].volumeMounts[0].mountPath": "/mnt/custom", - }, + Logger: logger.Discard, + ValuesFiles: []string{testValuesPath}, KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), } diff --git a/charts/gha-runner-scale-set/tests/values_k8s_novolume_custom_volume_mounts.yaml b/charts/gha-runner-scale-set/tests/values_k8s_novolume_custom_volume_mounts.yaml new file mode 100644 index 0000000000..fda9bd39df --- /dev/null +++ b/charts/gha-runner-scale-set/tests/values_k8s_novolume_custom_volume_mounts.yaml @@ -0,0 +1,18 @@ +githubConfigUrl: https://github.com/actions +githubConfigSecret: + github_token: gh_token12345 +containerMode: + type: kubernetes-novolume +controllerServiceAccount: + name: arc + namespace: arc-system +template: + spec: + volumes: + - name: custom-volume + emptyDir: {} + containers: + - name: runner + volumeMounts: + - name: custom-volume + mountPath: /mnt/custom diff --git a/charts/gha-runner-scale-set/tests/values_k8s_novolume_custom_volumes.yaml b/charts/gha-runner-scale-set/tests/values_k8s_novolume_custom_volumes.yaml new file mode 100644 index 0000000000..820f12980a --- /dev/null +++ b/charts/gha-runner-scale-set/tests/values_k8s_novolume_custom_volumes.yaml @@ -0,0 +1,13 @@ +githubConfigUrl: https://github.com/actions +githubConfigSecret: + github_token: gh_token12345 +containerMode: + type: kubernetes-novolume +controllerServiceAccount: + name: arc + namespace: arc-system +template: + spec: + volumes: + - name: custom-volume + emptyDir: {}