mirror of
https://github.com/actions-runner-controller/actions-runner-controller.git
synced 2026-10-02 23:31:16 +02:00
Validate runner metadata labels and annotations at chart render time
Invalid labels supplied through .Values.template.metadata.labels (or the resourceMeta blocks) are not rejected by the API server: they live inside the AutoscalingRunnerSet spec, whose CRD schema only enforces the value type. The invalid value is only caught when the controller creates the runner pod, at which point the EphemeralRunner is marked as failed with ReasonInvalidPodFailure and the scale set never produces runners. Validate every label and annotation map the charts render against the Kubernetes key/value rules so helm install/upgrade fails immediately with the offending values path, key and value. Also render all metadata values as strings. Scalars such as 'true' or '1' were previously emitted as YAML booleans and numbers, which Kubernetes rejects for labels and annotations. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
Copilot App
parent
7c68e1d318
commit
c156b81e00
@@ -32,11 +32,11 @@ Render a ResourceMeta block for AutoscalingRunnerSet spec fields.
|
||||
{{- define "autoscaling-runner-set.spec-resource-metadata" -}}
|
||||
{{- with .labels }}
|
||||
labels:
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- include "string-map" . | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- with .annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- include "string-map" . | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
|
||||
@@ -1,3 +1,80 @@
|
||||
{{/*
|
||||
Render a labels or annotations map with all values coerced to strings.
|
||||
Kubernetes only accepts string values, so scalars such as `true` or `1` must not be
|
||||
rendered as YAML booleans or numbers.
|
||||
*/}}
|
||||
{{- define "string-map" -}}
|
||||
{{- $out := dict -}}
|
||||
{{- range $k, $v := . -}}
|
||||
{{- $_ := set $out $k (printf "%v" $v) -}}
|
||||
{{- end -}}
|
||||
{{- toYaml $out -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate a label or annotation key against the Kubernetes qualified name rules.
|
||||
Expects a dict with "key", "kind" (label|annotation) and "path" (the values path used in the error message).
|
||||
*/}}
|
||||
{{- define "validate-metadata-key" -}}
|
||||
{{- $key := .key -}}
|
||||
{{- $parts := splitList "/" $key -}}
|
||||
{{- $name := $key -}}
|
||||
{{- if gt (len $parts) 2 -}}
|
||||
{{- fail (printf "%s: invalid %s key %q: a qualified name must consist of an optional DNS subdomain prefix followed by a single '/'" .path .kind $key) -}}
|
||||
{{- end -}}
|
||||
{{- if eq (len $parts) 2 -}}
|
||||
{{- $prefix := index $parts 0 -}}
|
||||
{{- $name = index $parts 1 -}}
|
||||
{{- if or (eq $prefix "") (gt (len $prefix) 253) (not (regexMatch "^[a-z0-9]([-a-z0-9.]*[a-z0-9])?$" $prefix)) -}}
|
||||
{{- fail (printf "%s: invalid %s key %q: the prefix %q must be a DNS subdomain of no more than 253 characters" .path .kind $key $prefix) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if or (eq $name "") (gt (len $name) 63) (not (regexMatch "^[A-Za-z0-9]([-A-Za-z0-9_.]*[A-Za-z0-9])?$" $name)) -}}
|
||||
{{- fail (printf "%s: invalid %s key %q: the name part must be no more than 63 characters, consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character" .path .kind $key) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate a metadata block (dict with optional "labels" and "annotations").
|
||||
Invalid runner pod labels are only rejected once the controller creates the runner pod,
|
||||
which leaves the scale set without runners, so fail at render time instead.
|
||||
Expects a dict with "metadata" and "path".
|
||||
*/}}
|
||||
{{- define "validate-metadata" -}}
|
||||
{{- $path := .path -}}
|
||||
{{- $metadata := .metadata | default dict -}}
|
||||
{{- if kindIs "map" $metadata -}}
|
||||
{{- range $key, $value := ((index $metadata "labels") | default dict) -}}
|
||||
{{- include "validate-metadata-key" (dict "key" $key "kind" "label" "path" (printf "%s.labels" $path)) -}}
|
||||
{{- $rendered := printf "%v" $value -}}
|
||||
{{- if gt (len $rendered) 63 -}}
|
||||
{{- fail (printf "%s.labels: invalid value %q for label %q: a label value must be no more than 63 characters" $path $rendered $key) -}}
|
||||
{{- end -}}
|
||||
{{- if not (regexMatch "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" $rendered) -}}
|
||||
{{- fail (printf "%s.labels: invalid value %q for label %q: a valid label value must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character" $path $rendered $key) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- range $key, $value := ((index $metadata "annotations") | default dict) -}}
|
||||
{{- include "validate-metadata-key" (dict "key" $key "kind" "annotation" "path" (printf "%s.annotations" $path)) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate every label and annotation map the chart can render onto resources it manages.
|
||||
*/}}
|
||||
{{- define "validate-all-metadata" -}}
|
||||
{{- range $resource, $config := (.Values.resource | default dict) }}
|
||||
{{- if kindIs "map" $config }}
|
||||
{{- include "validate-metadata" (dict "metadata" (index $config "metadata") "path" (printf ".Values.resource.%s.metadata" $resource)) -}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- $runnerPod := (index (.Values.runner | default dict) "pod") | default dict }}
|
||||
{{- if kindIs "map" $runnerPod }}
|
||||
{{- include "validate-metadata" (dict "metadata" (index $runnerPod "metadata") "path" ".Values.runner.pod.metadata") -}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the labels for the GitHub auth secret.
|
||||
*/}}
|
||||
@@ -53,14 +130,16 @@ Reserved annotations are excluded from both levels.
|
||||
|
||||
|
||||
{{/*
|
||||
Takes a map of user labels and removes the ones with "actions.github.com/" prefix
|
||||
Takes a map of user labels and removes the ones with "actions.github.com/" prefix.
|
||||
Values are rendered as strings so that scalars such as `true` or `1.0` do not become
|
||||
non-string YAML values, which Kubernetes rejects for labels and annotations.
|
||||
*/}}
|
||||
{{- define "apply-non-reserved-gha-labels-and-annotations" -}}
|
||||
{{- $userLabels := . -}}
|
||||
{{- $processed := dict -}}
|
||||
{{- range $key, $value := $userLabels -}}
|
||||
{{- if not (hasPrefix "actions.github.com/" $key) -}}
|
||||
{{- $_ := set $processed $key $value -}}
|
||||
{{- $_ := set $processed $key (printf "%v" $value) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if not (empty $processed) -}}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{{- $runner := (.Values.runner | default dict) }}
|
||||
{{- include "validate-all-metadata" . }}
|
||||
{{- $runnerMode := (index $runner "mode" | default "") }}
|
||||
{{- $kubeMode := (index $runner "kubernetesMode" | default dict) }}
|
||||
{{- $dind := (index $runner "dind" | default dict) }}
|
||||
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
suite: "AutoscalingRunnerSet metadata validation"
|
||||
templates:
|
||||
- autoscalingrunnserset.yaml
|
||||
tests:
|
||||
- it: should fail when a runner pod label value is not a valid Kubernetes label value
|
||||
set:
|
||||
scaleset.name: "test"
|
||||
auth.url: "https://github.com/org"
|
||||
auth.githubToken: "gh_token12345"
|
||||
controllerServiceAccount.name: "arc"
|
||||
controllerServiceAccount.namespace: "arc-system"
|
||||
runner:
|
||||
pod:
|
||||
metadata:
|
||||
labels:
|
||||
purpose: "“true”"
|
||||
release:
|
||||
name: "test-name"
|
||||
namespace: "test-namespace"
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: '.Values.runner.pod.metadata.labels: invalid value "“true”" for label "purpose": a valid label value must be an empty string or consist of alphanumeric characters, ''-'', ''_'' or ''.'', and must start and end with an alphanumeric character'
|
||||
|
||||
- it: should fail when a runner pod label key is not a valid qualified name
|
||||
set:
|
||||
scaleset.name: "test"
|
||||
auth.url: "https://github.com/org"
|
||||
auth.githubToken: "gh_token12345"
|
||||
controllerServiceAccount.name: "arc"
|
||||
controllerServiceAccount.namespace: "arc-system"
|
||||
runner:
|
||||
pod:
|
||||
metadata:
|
||||
labels:
|
||||
"Invalid.Prefix/purpose": "ci"
|
||||
release:
|
||||
name: "test-name"
|
||||
namespace: "test-namespace"
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: '.Values.runner.pod.metadata.labels: invalid label key "Invalid.Prefix/purpose": the prefix "Invalid.Prefix" must be a DNS subdomain of no more than 253 characters'
|
||||
|
||||
- it: should fail when a resource label value is not a valid Kubernetes label value
|
||||
set:
|
||||
scaleset.name: "test"
|
||||
auth.url: "https://github.com/org"
|
||||
auth.githubToken: "gh_token12345"
|
||||
controllerServiceAccount.name: "arc"
|
||||
controllerServiceAccount.namespace: "arc-system"
|
||||
resource:
|
||||
all:
|
||||
metadata:
|
||||
labels:
|
||||
team: "not valid"
|
||||
release:
|
||||
name: "test-name"
|
||||
namespace: "test-namespace"
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: '.Values.resource.all.metadata.labels: invalid value "not valid" for label "team": a valid label value must be an empty string or consist of alphanumeric characters, ''-'', ''_'' or ''.'', and must start and end with an alphanumeric character'
|
||||
|
||||
- it: should fail when an annotation key is not a valid qualified name
|
||||
set:
|
||||
scaleset.name: "test"
|
||||
auth.url: "https://github.com/org"
|
||||
auth.githubToken: "gh_token12345"
|
||||
controllerServiceAccount.name: "arc"
|
||||
controllerServiceAccount.namespace: "arc-system"
|
||||
resource:
|
||||
all:
|
||||
metadata:
|
||||
annotations:
|
||||
"invalid key": "value"
|
||||
release:
|
||||
name: "test-name"
|
||||
namespace: "test-namespace"
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: '.Values.resource.all.metadata.annotations: invalid annotation key "invalid key": the name part must be no more than 63 characters, consist of alphanumeric characters, ''-'', ''_'' or ''.'', and must start and end with an alphanumeric character'
|
||||
|
||||
- it: should render scalar label and annotation values as strings
|
||||
set:
|
||||
scaleset.name: "test"
|
||||
auth.url: "https://github.com/org"
|
||||
auth.githubToken: "gh_token12345"
|
||||
controllerServiceAccount.name: "arc"
|
||||
controllerServiceAccount.namespace: "arc-system"
|
||||
resource:
|
||||
ephemeralRunner:
|
||||
metadata:
|
||||
labels:
|
||||
sync-wave: 1
|
||||
annotations:
|
||||
enabled: true
|
||||
runner:
|
||||
pod:
|
||||
metadata:
|
||||
labels:
|
||||
enabled: true
|
||||
release:
|
||||
name: "test-name"
|
||||
namespace: "test-namespace"
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["enabled"]
|
||||
value: "true"
|
||||
- equal:
|
||||
path: spec.ephemeralRunnerMetadata.labels["sync-wave"]
|
||||
value: "1"
|
||||
- equal:
|
||||
path: spec.ephemeralRunnerMetadata.annotations["enabled"]
|
||||
value: "true"
|
||||
@@ -54,17 +54,103 @@ app.kubernetes.io/name: {{ include "gha-runner-scale-set.scale-set-name" . }}
|
||||
app.kubernetes.io/instance: {{ include "gha-runner-scale-set.scale-set-name" . }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Render a labels or annotations map with all values coerced to strings.
|
||||
Kubernetes only accepts string values, so scalars such as `true` or `1` must not be
|
||||
rendered as YAML booleans or numbers.
|
||||
*/}}
|
||||
{{- define "gha-runner-scale-set.stringMap" -}}
|
||||
{{- $out := dict -}}
|
||||
{{- range $k, $v := . -}}
|
||||
{{- $_ := set $out $k (printf "%v" $v) -}}
|
||||
{{- end -}}
|
||||
{{- toYaml $out -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate a label or annotation key against the Kubernetes qualified name rules.
|
||||
Expects a dict with "key", "kind" (label|annotation) and "path" (the values path used in the error message).
|
||||
*/}}
|
||||
{{- define "gha-runner-scale-set.validateMetadataKey" -}}
|
||||
{{- $key := .key -}}
|
||||
{{- $parts := splitList "/" $key -}}
|
||||
{{- $name := $key -}}
|
||||
{{- if gt (len $parts) 2 -}}
|
||||
{{- fail (printf "%s: invalid %s key %q: a qualified name must consist of an optional DNS subdomain prefix followed by a single '/'" .path .kind $key) -}}
|
||||
{{- end -}}
|
||||
{{- if eq (len $parts) 2 -}}
|
||||
{{- $prefix := index $parts 0 -}}
|
||||
{{- $name = index $parts 1 -}}
|
||||
{{- if or (eq $prefix "") (gt (len $prefix) 253) (not (regexMatch "^[a-z0-9]([-a-z0-9.]*[a-z0-9])?$" $prefix)) -}}
|
||||
{{- fail (printf "%s: invalid %s key %q: the prefix %q must be a DNS subdomain of no more than 253 characters" .path .kind $key $prefix) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if or (eq $name "") (gt (len $name) 63) (not (regexMatch "^[A-Za-z0-9]([-A-Za-z0-9_.]*[A-Za-z0-9])?$" $name)) -}}
|
||||
{{- fail (printf "%s: invalid %s key %q: the name part must be no more than 63 characters, consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character" .path .kind $key) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate a map of labels. Invalid labels are only rejected once the controller creates the
|
||||
runner pod, which leaves the scale set without runners, so fail at render time instead.
|
||||
Expects a dict with "labels" and "path".
|
||||
*/}}
|
||||
{{- define "gha-runner-scale-set.validateLabels" -}}
|
||||
{{- $path := .path -}}
|
||||
{{- range $key, $value := (.labels | default dict) -}}
|
||||
{{- include "gha-runner-scale-set.validateMetadataKey" (dict "key" $key "kind" "label" "path" $path) -}}
|
||||
{{- $rendered := printf "%v" $value -}}
|
||||
{{- if gt (len $rendered) 63 -}}
|
||||
{{- fail (printf "%s: invalid value %q for label %q: a label value must be no more than 63 characters" $path $rendered $key) -}}
|
||||
{{- end -}}
|
||||
{{- if not (regexMatch "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" $rendered) -}}
|
||||
{{- fail (printf "%s: invalid value %q for label %q: a valid label value must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character" $path $rendered $key) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate a map of annotations. Annotation values are unconstrained, so only keys are validated.
|
||||
Expects a dict with "annotations" and "path".
|
||||
*/}}
|
||||
{{- define "gha-runner-scale-set.validateAnnotations" -}}
|
||||
{{- $path := .path -}}
|
||||
{{- range $key, $value := (.annotations | default dict) -}}
|
||||
{{- include "gha-runner-scale-set.validateMetadataKey" (dict "key" $key "kind" "annotation" "path" $path) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate every label and annotation map the chart can render onto resources it manages.
|
||||
*/}}
|
||||
{{- define "gha-runner-scale-set.validateMetadata" -}}
|
||||
{{- include "gha-runner-scale-set.validateLabels" (dict "labels" .Values.labels "path" ".Values.labels") -}}
|
||||
{{- include "gha-runner-scale-set.validateAnnotations" (dict "annotations" .Values.annotations "path" ".Values.annotations") -}}
|
||||
{{- with .Values.template }}
|
||||
{{- with .metadata }}
|
||||
{{- include "gha-runner-scale-set.validateLabels" (dict "labels" .labels "path" ".Values.template.metadata.labels") -}}
|
||||
{{- include "gha-runner-scale-set.validateAnnotations" (dict "annotations" .annotations "path" ".Values.template.metadata.annotations") -}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range $resource, $meta := (.Values.resourceMeta | default dict) }}
|
||||
{{- if kindIs "map" $meta }}
|
||||
{{- include "gha-runner-scale-set.validateLabels" (dict "labels" (index $meta "labels") "path" (printf ".Values.resourceMeta.%s.labels" $resource)) -}}
|
||||
{{- include "gha-runner-scale-set.validateAnnotations" (dict "annotations" (index $meta "annotations") "path" (printf ".Values.resourceMeta.%s.annotations" $resource)) -}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Render a ResourceMeta block for AutoscalingRunnerSet spec fields.
|
||||
*/}}
|
||||
{{- define "gha-runner-scale-set.resourceMetaSpec" -}}
|
||||
{{- with .labels }}
|
||||
labels:
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- with .annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{{- $resourceMeta := default (dict) .Values.resourceMeta }}
|
||||
{{- $hasCustomResourceMeta := (and .Values.resourceMeta .Values.resourceMeta.autoscalingRunnerSet) }}
|
||||
{{- /* .Values.listenerConfig is validated by values.schema.json */ -}}
|
||||
{{- include "gha-runner-scale-set.validateMetadata" . }}
|
||||
apiVersion: actions.github.com/v1alpha1
|
||||
kind: AutoscalingRunnerSet
|
||||
metadata:
|
||||
@@ -218,11 +219,11 @@ spec:
|
||||
metadata:
|
||||
{{- with .labels }}
|
||||
labels:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
spec:
|
||||
|
||||
@@ -18,17 +18,17 @@ metadata:
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.githubConfigSecret.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- include "gha-runner-scale-set.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
{{- with .Values.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.githubConfigSecret.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
finalizers:
|
||||
|
||||
@@ -20,17 +20,17 @@ metadata:
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.kubernetesModeRole.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- include "gha-runner-scale-set.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
{{- with .Values.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.kubernetesModeRole.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
finalizers:
|
||||
|
||||
@@ -19,18 +19,18 @@ metadata:
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.kubernetesModeRoleBinding.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- include "gha-runner-scale-set.labels" . | nindent 4 }}
|
||||
|
||||
annotations:
|
||||
{{- with .Values.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.kubernetesModeRoleBinding.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
finalizers:
|
||||
|
||||
@@ -9,11 +9,11 @@ metadata:
|
||||
{{- if or .Values.annotations $hasCustomResourceMeta }}
|
||||
annotations:
|
||||
{{- with .Values.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.kubernetesModeServiceAccount.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -30,7 +30,7 @@ metadata:
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.kubernetesModeServiceAccount.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- include "gha-runner-scale-set.labels" . | nindent 4 }}
|
||||
|
||||
@@ -17,18 +17,18 @@ metadata:
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.managerRole.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- include "gha-runner-scale-set.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: manager-role
|
||||
annotations:
|
||||
{{- with .Values.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.managerRole.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
finalizers:
|
||||
|
||||
@@ -17,18 +17,18 @@ metadata:
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.managerRoleBinding.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- include "gha-runner-scale-set.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: manager-role-binding
|
||||
annotations:
|
||||
{{- with .Values.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.managerRoleBinding.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
finalizers:
|
||||
|
||||
@@ -19,17 +19,17 @@ metadata:
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.noPermissionServiceAccount.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- include "gha-runner-scale-set.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
{{- with .Values.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if $hasCustomResourceMeta }}
|
||||
{{- with .Values.resourceMeta.noPermissionServiceAccount.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- include "gha-runner-scale-set.stringMap" . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
finalizers:
|
||||
|
||||
@@ -2684,7 +2684,7 @@ func TestCustomLabels(t *testing.T) {
|
||||
"controllerServiceAccount.name": "arc",
|
||||
"containerMode.type": "kubernetes",
|
||||
"controllerServiceAccount.namespace": "arc-system",
|
||||
`labels.argocd\.argoproj\.io/sync-wave`: `"1"`,
|
||||
`labels.argocd\.argoproj\.io/sync-wave`: "1",
|
||||
`labels.app\.kubernetes\.io/part-of`: "no-override", // this shouldn't be overwritten
|
||||
"resourceMeta.autoscalingRunnerSet.labels.ars-custom": "ars-custom-value",
|
||||
"resourceMeta.githubConfigSecret.labels.gh-custom": "gh-custom-value",
|
||||
@@ -2708,7 +2708,7 @@ func TestCustomLabels(t *testing.T) {
|
||||
output := helm.RenderTemplateContext(t, t.Context(), options, helmChartPath, releaseName, []string{"templates/githubsecret.yaml"})
|
||||
|
||||
const targetLabel = "argocd.argoproj.io/sync-wave"
|
||||
const wantCustomValue = `"1"`
|
||||
const wantCustomValue = "1"
|
||||
const reservedLabel = "app.kubernetes.io/part-of"
|
||||
const wantReservedValue = "gha-rs"
|
||||
|
||||
@@ -2783,7 +2783,7 @@ func TestCustomLabels(t *testing.T) {
|
||||
"githubConfigSecret.github_token": "gh_token12345",
|
||||
"controllerServiceAccount.name": "arc",
|
||||
"controllerServiceAccount.namespace": "arc-system",
|
||||
`labels.argocd\.argoproj\.io/sync-wave`: `"1"`,
|
||||
`labels.argocd\.argoproj\.io/sync-wave`: "1",
|
||||
"resourceMeta.noPermissionServiceAccount.labels.npsa-custom": "npsa-custom-value",
|
||||
},
|
||||
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
|
||||
@@ -2815,7 +2815,7 @@ func TestCustomAnnotations(t *testing.T) {
|
||||
"containerMode.type": "kubernetes",
|
||||
"controllerServiceAccount.name": "arc",
|
||||
"controllerServiceAccount.namespace": "arc-system",
|
||||
`annotations.argocd\.argoproj\.io/sync-wave`: `"1"`,
|
||||
`annotations.argocd\.argoproj\.io/sync-wave`: "1",
|
||||
"resourceMeta.autoscalingRunnerSet.annotations.ars-custom": "ars-custom-value",
|
||||
"resourceMeta.githubConfigSecret.annotations.gh-custom": "gh-custom-value",
|
||||
"resourceMeta.kubernetesModeRole.annotations.kmr-custom": "kmr-custom-value",
|
||||
@@ -2836,7 +2836,7 @@ func TestCustomAnnotations(t *testing.T) {
|
||||
}
|
||||
|
||||
const targetAnnotations = "argocd.argoproj.io/sync-wave"
|
||||
const wantCustomValue = `"1"`
|
||||
const wantCustomValue = "1"
|
||||
|
||||
output := helm.RenderTemplateContext(t, t.Context(), options, helmChartPath, releaseName, []string{"templates/githubsecret.yaml"})
|
||||
|
||||
@@ -2904,7 +2904,7 @@ func TestCustomAnnotations(t *testing.T) {
|
||||
"githubConfigSecret.github_token": "gh_token12345",
|
||||
"controllerServiceAccount.name": "arc",
|
||||
"controllerServiceAccount.namespace": "arc-system",
|
||||
`annotations.argocd\.argoproj\.io/sync-wave`: `"1"`,
|
||||
`annotations.argocd\.argoproj\.io/sync-wave`: "1",
|
||||
"resourceMeta.noPermissionServiceAccount.annotations.npsa-custom": "npsa-custom-value",
|
||||
},
|
||||
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
|
||||
@@ -3152,3 +3152,107 @@ func TestAutoscalingRunnerSetCustomAnnotationsAndLabelsApplied(t *testing.T) {
|
||||
assert.NotEqual(t, "not-propagated", autoscalingRunnerSet.Annotations["actions.github.com/cleanup-manager-role-name"])
|
||||
assert.NotEqual(t, "not-propagated", autoscalingRunnerSet.Labels["app.kubernetes.io/component"])
|
||||
}
|
||||
|
||||
func TestTemplateRenderedAutoScalingRunnerSet_InvalidMetadataValidationError(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
|
||||
require.NoError(t, err)
|
||||
|
||||
tt := map[string]struct {
|
||||
key string
|
||||
value string
|
||||
expectedError string
|
||||
}{
|
||||
"runner pod label with smart quotes": {
|
||||
key: "template.metadata.labels.custom",
|
||||
value: "\u201ctrue\u201d",
|
||||
expectedError: `.Values.template.metadata.labels: invalid value "“true”" for label "custom"`,
|
||||
},
|
||||
"runner pod label value too long": {
|
||||
key: "template.metadata.labels.custom",
|
||||
value: strings.Repeat("a", 64),
|
||||
expectedError: `.Values.template.metadata.labels: invalid value "` + strings.Repeat("a", 64) + `" for label "custom": a label value must be no more than 63 characters`,
|
||||
},
|
||||
"runner pod label key with invalid prefix": {
|
||||
key: "template.metadata.labels.Invalid\\.Prefix/custom",
|
||||
value: "value",
|
||||
expectedError: `.Values.template.metadata.labels: invalid label key "Invalid.Prefix/custom"`,
|
||||
},
|
||||
"runner pod annotation key invalid": {
|
||||
key: "template.metadata.annotations.invalid key",
|
||||
value: "value",
|
||||
expectedError: `.Values.template.metadata.annotations: invalid annotation key "invalid key"`,
|
||||
},
|
||||
"chart level label invalid": {
|
||||
key: "labels.custom",
|
||||
value: "not valid",
|
||||
expectedError: `.Values.labels: invalid value "not valid" for label "custom"`,
|
||||
},
|
||||
"resource meta label invalid": {
|
||||
key: "resourceMeta.ephemeralRunner.labels.custom",
|
||||
value: "not valid",
|
||||
expectedError: `.Values.resourceMeta.ephemeralRunner.labels: invalid value "not valid" for label "custom"`,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range tt {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
releaseName := "test-runners"
|
||||
namespaceName := "test-" + strings.ToLower(random.UniqueID())
|
||||
|
||||
options := &helm.Options{
|
||||
Logger: logger.Discard,
|
||||
SetValues: map[string]string{
|
||||
"githubConfigUrl": "https://github.com/actions",
|
||||
"githubConfigSecret.github_token": "gh_token12345",
|
||||
"controllerServiceAccount.name": "arc",
|
||||
"controllerServiceAccount.namespace": "arc-system",
|
||||
tc.key: tc.value,
|
||||
},
|
||||
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
|
||||
}
|
||||
|
||||
_, err := helm.RenderTemplateContextE(t, t.Context(), options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
|
||||
require.Error(t, err)
|
||||
assert.ErrorContains(t, err, tc.expectedError)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateRenderedAutoScalingRunnerSet_ValidMetadataIsAccepted(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
|
||||
require.NoError(t, err)
|
||||
|
||||
releaseName := "test-runners"
|
||||
namespaceName := "test-" + strings.ToLower(random.UniqueID())
|
||||
|
||||
options := &helm.Options{
|
||||
Logger: logger.Discard,
|
||||
SetValues: map[string]string{
|
||||
"githubConfigUrl": "https://github.com/actions",
|
||||
"githubConfigSecret.github_token": "gh_token12345",
|
||||
"controllerServiceAccount.name": "arc",
|
||||
"controllerServiceAccount.namespace": "arc-system",
|
||||
"template.metadata.labels.custom": "true",
|
||||
"template.metadata.labels.example\\.com/custom": "value_1.0-rc",
|
||||
"template.metadata.labels.empty": "",
|
||||
"template.metadata.annotations.example\\.com/an": "any value is allowed: ✅",
|
||||
},
|
||||
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
|
||||
}
|
||||
|
||||
output := helm.RenderTemplateContext(t, t.Context(), options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
|
||||
|
||||
var autoscalingRunnerSet v1alpha1.AutoscalingRunnerSet
|
||||
helm.UnmarshalK8SYaml(t, output, &autoscalingRunnerSet)
|
||||
|
||||
assert.Equal(t, "true", autoscalingRunnerSet.Spec.Template.Labels["custom"])
|
||||
assert.Equal(t, "value_1.0-rc", autoscalingRunnerSet.Spec.Template.Labels["example.com/custom"])
|
||||
assert.Equal(t, "", autoscalingRunnerSet.Spec.Template.Labels["empty"])
|
||||
assert.Equal(t, "any value is allowed: ✅", autoscalingRunnerSet.Spec.Template.Annotations["example.com/an"])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user