diff --git a/charts/gha-runner-scale-set-experimental/templates/_defaults.tpl b/charts/gha-runner-scale-set-experimental/templates/_defaults.tpl index 055c75a202..2cecf588a1 100644 --- a/charts/gha-runner-scale-set-experimental/templates/_defaults.tpl +++ b/charts/gha-runner-scale-set-experimental/templates/_defaults.tpl @@ -122,6 +122,40 @@ Hook extension ConfigMap name for kubernetes runner mode. If runner.kubernetesMode.extension.metadata.name is set, use it. Otherwise, default to a name derived from the scale set name. */}} +{{/* +Validate runner.container fields. + +Fails with a descriptive error if: +- runner.container is set but is not a map/object +- runner.container.env is set but is not a list +- runner.container.volumeMounts is set but is not a list +- runner.container.args is set but is not a list +- runner.container.securityContext is set but is not a map/object +- runner.container.volumes is set (unsupported; use runner.pod.spec.volumes) +*/}} +{{- define "runner.container.validate" -}} +{{- $runner := (.Values.runner | default dict) -}} +{{- $container := ($runner.container | default dict) -}} +{{- if and (hasKey $runner "container") (not (kindIs "map" $container)) -}} + {{- fail "runner.container must be a map/object" -}} +{{- end -}} +{{- if and (hasKey $container "env") (not (kindIs "slice" $container.env)) -}} + {{- fail "runner.container.env must be a list" -}} +{{- end -}} +{{- if and (hasKey $container "volumeMounts") (not (kindIs "slice" $container.volumeMounts)) -}} + {{- fail "runner.container.volumeMounts must be a list" -}} +{{- end -}} +{{- if hasKey $container "volumes" -}} + {{- fail "runner.container.volumes is not supported; use runner.pod.spec.volumes" -}} +{{- end -}} +{{- if and (hasKey $container "args") (not (kindIs "slice" $container.args)) -}} + {{- fail "runner.container.args must be a list" -}} +{{- end -}} +{{- if and (hasKey $container "securityContext") (not (kindIs "map" $container.securityContext)) -}} + {{- fail "runner.container.securityContext must be a map/object" -}} +{{- end -}} +{{- end -}} + {{- define "runner-mode-kubernetes.extension-name" -}} {{- $runner := (.Values.runner | default dict) -}} {{- $kubeMode := (index $runner "kubernetesMode" | default dict) -}} diff --git a/charts/gha-runner-scale-set-experimental/templates/_mode_dind.tpl b/charts/gha-runner-scale-set-experimental/templates/_mode_dind.tpl index a6e7ade5a2..854acb9c84 100644 --- a/charts/gha-runner-scale-set-experimental/templates/_mode_dind.tpl +++ b/charts/gha-runner-scale-set-experimental/templates/_mode_dind.tpl @@ -1,4 +1,7 @@ {{- define "runner-mode-dind.runner-container" -}} +{{- include "runner.container.validate" . -}} +{{- $runner := (.Values.runner | default dict) -}} +{{- $container := ($runner.container | default dict) -}} name: runner image: {{ include "runner.image" . | quote }} command: {{ include "runner.command" . }} @@ -15,7 +18,11 @@ volumeMounts: mountPath: /home/runner/_work - name: dind-sock mountPath: {{ include "runner-mode-dind.sock-mount-dir" . | quote }} - {{ include "githubServerTLS.volumeMountItem" (dict "root" $ "existingVolumeMounts" (list)) | nindent 2 }} + {{ include "githubServerTLS.volumeMountItem" (dict "root" $ "existingVolumeMounts" (list)) | nindent 2 -}} +{{- $extra := omit $container "name" "image" "command" "env" "volumeMounts" -}} +{{- if not (empty $extra) }} +{{ toYaml $extra -}} +{{- end -}} {{- end }} {{- define "runner-mode-dind.dind-container" -}} diff --git a/charts/gha-runner-scale-set-experimental/templates/_mode_kubernetes.tpl b/charts/gha-runner-scale-set-experimental/templates/_mode_kubernetes.tpl index 6589d01d1c..e876b0a3e8 100644 --- a/charts/gha-runner-scale-set-experimental/templates/_mode_kubernetes.tpl +++ b/charts/gha-runner-scale-set-experimental/templates/_mode_kubernetes.tpl @@ -1,5 +1,7 @@ {{- define "runner-mode-kubernetes.runner-container" -}} +{{- include "runner.container.validate" . -}} {{- $runner := (.Values.runner | default dict) -}} +{{- $container := ($runner.container | default dict) -}} {{- $kubeMode := (index $runner "kubernetesMode" | default dict) -}} {{- $hookPath := (index $kubeMode "hookPath" | default "/home/runner/k8s/index.js") -}} {{- $extensionRef := (index $kubeMode "extensionRef" | default "") -}} @@ -82,7 +84,11 @@ volumeMounts: subPath: extension readOnly: true {{- end }} - {{ include "githubServerTLS.volumeMountItem" (dict "root" $ "existingVolumeMounts" (list)) | nindent 2 }} + {{ include "githubServerTLS.volumeMountItem" (dict "root" $ "existingVolumeMounts" (list)) | nindent 2 -}} +{{- $extra := omit $container "name" "image" "command" "env" "volumeMounts" -}} +{{- if not (empty $extra) }} +{{ toYaml $extra -}} +{{- end -}} {{- end }} {{- define "runner-mode-kubernetes.pod-volumes" -}} diff --git a/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_dind_mode_spec_test.yaml b/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_dind_mode_spec_test.yaml index 2ec6d4dbc8..7832184ce3 100644 --- a/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_dind_mode_spec_test.yaml +++ b/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_dind_mode_spec_test.yaml @@ -400,6 +400,171 @@ tests: name: cache mountPath: /cache + - it: should pass extra fields from runner.container to the runner container in dind mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "dind" + container: + securityContext: + runAsUser: 1000 + resources: + limits: + cpu: "250m" + memory: "64Mi" + imagePullPolicy: Always + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - equal: + path: spec.template.spec.containers[0].name + value: runner + - equal: + path: spec.template.spec.containers[0].securityContext.runAsUser + value: 1000 + - equal: + path: spec.template.spec.containers[0].resources.limits.cpu + value: 250m + - equal: + path: spec.template.spec.containers[0].resources.limits.memory + value: 64Mi + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: Always + + - it: should silently ignore runner.container.name in dind mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "dind" + container: + name: not-runner + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - equal: + path: spec.template.spec.containers[0].name + value: runner + + - it: should fail when runner.container is not a map in dind mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "dind" + container: "invalid" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: runner.container must be a map/object + + - it: should fail when runner.container.env is not a list in dind mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "dind" + container: + env: "not-a-list" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: runner.container.env must be a list + + - it: should fail when runner.container.volumeMounts is not a list in dind mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "dind" + container: + volumeMounts: "not-a-list" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: runner.container.volumeMounts must be a list + + - it: should fail when runner.container.volumes is set in dind mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "dind" + container: + volumes: + - name: cache + emptyDir: {} + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: runner.container.volumes is not supported; use runner.pod.spec.volumes + + - it: should fail when runner.container.args is not a list in dind mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "dind" + container: + args: "not-a-list" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: runner.container.args must be a list + + - it: should fail when runner.container.securityContext is not a map in dind mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "dind" + container: + securityContext: "not-a-map" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: runner.container.securityContext must be a map/object + - it: should fail when runner.dind.container.volumes is provided set: scaleset.name: "test" diff --git a/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_kubernetes_mode_spec_test.yaml b/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_kubernetes_mode_spec_test.yaml index 91429779e7..f571e1b724 100644 --- a/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_kubernetes_mode_spec_test.yaml +++ b/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_kubernetes_mode_spec_test.yaml @@ -99,6 +99,171 @@ tests: path: spec.template.spec.volumes[0].ephemeral.volumeClaimTemplate.spec.resources.requests.storage value: 10Gi + - it: should pass extra fields from runner.container to the runner container in kubernetes mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "kubernetes" + container: + securityContext: + runAsUser: 1000 + resources: + limits: + cpu: "250m" + memory: "64Mi" + imagePullPolicy: Always + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - equal: + path: spec.template.spec.containers[0].name + value: runner + - equal: + path: spec.template.spec.containers[0].securityContext.runAsUser + value: 1000 + - equal: + path: spec.template.spec.containers[0].resources.limits.cpu + value: 250m + - equal: + path: spec.template.spec.containers[0].resources.limits.memory + value: 64Mi + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: Always + + - it: should silently ignore runner.container.name in kubernetes mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "kubernetes" + container: + name: not-runner + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - equal: + path: spec.template.spec.containers[0].name + value: runner + + - it: should fail when runner.container is not a map in kubernetes mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "kubernetes" + container: "invalid" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: runner.container must be a map/object + + - it: should fail when runner.container.env is not a list in kubernetes mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "kubernetes" + container: + env: "not-a-list" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: runner.container.env must be a list + + - it: should fail when runner.container.volumeMounts is not a list in kubernetes mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "kubernetes" + container: + volumeMounts: "not-a-list" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: runner.container.volumeMounts must be a list + + - it: should fail when runner.container.volumes is set in kubernetes mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "kubernetes" + container: + volumes: + - name: cache + emptyDir: {} + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: runner.container.volumes is not supported; use runner.pod.spec.volumes + + - it: should fail when runner.container.args is not a list in kubernetes mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "kubernetes" + container: + args: "not-a-list" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: runner.container.args must be a list + + - it: should fail when runner.container.securityContext is not a map in kubernetes mode + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + runner: + mode: "kubernetes" + container: + securityContext: "not-a-map" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: runner.container.securityContext must be a map/object + - it: should include extraVolumes in kubernetes mode set: scaleset.name: "test" diff --git a/charts/gha-runner-scale-set-experimental/values.yaml b/charts/gha-runner-scale-set-experimental/values.yaml index 4984251dc2..dd5a678689 100644 --- a/charts/gha-runner-scale-set-experimental/values.yaml +++ b/charts/gha-runner-scale-set-experimental/values.yaml @@ -232,10 +232,16 @@ runner: initContainers: [] volumes: [] - # container field is applied to the container named "runner". You cannot override the name of the runner container + # container field is applied to the container named "runner". You cannot override the name of the runner container. + # Additional container fields are passed through as-is (e.g. resources, securityContext, imagePullPolicy, etc.) container: image: "ghcr.io/actions/actions-runner:latest" command: ["/home/runner/run.sh"] + # env: [] + # volumeMounts: [] + # args: [] + # securityContext: {} + # resources: {} dind: # If official runner image is used, or the dind image doesn't contain