Introduce experimental chart release (#4373)

This commit is contained in:
Nikola Jokic
2026-03-16 10:09:05 +01:00
committed by GitHub
parent f99c6eda0b
commit aa031d3902
119 changed files with 50377 additions and 20 deletions

View File

@@ -0,0 +1,24 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
tests/

View File

@@ -0,0 +1,33 @@
apiVersion: v2
name: gha-runner-scale-set-controller-experimental
description: A Helm chart for install actions-runner-controller CRD
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.13.1
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "0.13.1"
home: https://github.com/actions/actions-runner-controller
sources:
- "https://github.com/actions/actions-runner-controller"
maintainers:
- name: actions
url: https://github.com/actions

View File

@@ -0,0 +1,3 @@
Thank you for installing {{ .Chart.Name }}.
Your release is named {{ .Release.Name }}.

View File

@@ -0,0 +1,67 @@
{{/*
Allow overriding the namespace for the resources.
*/}}
{{- define "gha-controller.namespace" -}}
{{- if .Values.namespaceOverride }}
{{- .Values.namespaceOverride }}
{{- else }}
{{- .Release.Namespace }}
{{- end }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "gha-controller.name" -}}
{{- if .Values.nameOverride }}
{{- .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default (include "gha-base-name" .) .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Labels applied to the controller deployment
*/}}
{{- define "gha-controller.labels" -}}
{{- $resourceLabels := dict "app.kubernetes.io/component" "controller-manager" -}}
{{- $commonLabels := include "gha-common.labels" . | fromYaml -}}
{{- $userLabels := include "apply-non-reserved-gha-labels-and-annotations" (.Values.controller.metadata.labels | default (dict)) | fromYaml -}}
{{- $global := include "apply-non-reserved-gha-labels-and-annotations" (.Values.labels | default (dict)) | fromYaml -}}
{{- $labels := mergeOverwrite $global $userLabels $resourceLabels $commonLabels -}}
{{- /* Reserved actions.github.com/* labels owned by the chart itself */ -}}
{{- $_ := set $labels "actions.github.com/controller-service-account-namespace" (include "gha-controller.namespace" .) -}}
{{- $_ := set $labels "actions.github.com/controller-service-account-name" (include "gha-controller.service-account-name" .) -}}
{{- with .Values.controller.manager.config.watchSingleNamespace }}
{{- $_ := set $labels "actions.github.com/controller-watch-single-namespace" . -}}
{{- end }}
{{- toYaml $labels -}}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "gha-controller.service-account-name" -}}
{{- if eq .Values.controller.serviceAccount.name "default"}}
{{- fail "serviceAccount.name cannot be set to 'default'" }}
{{- end }}
{{- if .Values.controller.serviceAccount.create }}
{{- default (include "gha-controller.name" .) .Values.controller.serviceAccount.name }}
{{- else }}
{{- if not .Values.controller.serviceAccount.name }}
{{- fail "serviceAccount.name must be set if serviceAccount.create is false" }}
{{- else }}
{{- .Values.controller.serviceAccount.name }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,122 @@
{{/*
Labels applied to the controller Pod template (spec.template.metadata.labels)
*/}}
{{- define "gha-controller-template.labels" -}}
{{- $static := dict "app.kubernetes.io/part-of" "gha-rs-controller" "app.kubernetes.io/component" "controller-manager" -}}
{{- $_ := set $static "app.kubernetes.io/version" (.Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-") -}}
{{- $selector := include "gha-controller.selector-labels" . | fromYaml -}}
{{- $podUser := include "apply-non-reserved-gha-labels-and-annotations" (.Values.controller.pod.metadata.labels | default (dict)) | fromYaml -}}
{{- $labels := mergeOverwrite $podUser $selector $static -}}
{{- toYaml $labels -}}
{{- end }}
{{/*
Annotations applied to the controller Pod template (spec.template.metadata.annotations)
*/}}
{{- define "gha-controller-template.annotations" -}}
{{- $static := dict "kubectl.kubernetes.io/default-container" "manager" -}}
{{- $podUser := include "apply-non-reserved-gha-labels-and-annotations" (.Values.controller.pod.metadata.annotations | default (dict)) | fromYaml -}}
{{- $annotations := mergeOverwrite $podUser $static -}}
{{- toYaml $annotations -}}
{{- end }}
{{- define "gha-controller-template.manager-container" -}}
name: manager
image: "{{ .Values.controller.manager.container.image }}"
imagePullPolicy: {{ default "IfNotPresent" .Values.controller.manager.container.pullPolicy }}
command:
- "/manager"
args:
- "--auto-scaling-runner-set-only"
{{- if gt (int (default 1 .Values.controller.replicaCount)) 1 }}
- "--enable-leader-election"
- "--leader-election-id={{ include "gha-controller.name" . }}"
{{- end }}
{{- with .Values.imagePullSecrets }}
{{- range . }}
- "--auto-scaler-image-pull-secrets={{- .name -}}"
{{- end }}
{{- end }}
{{- with .Values.controller.manager.config.logLevel }}
- "--log-level={{ . }}"
{{- end }}
{{- with .Values.controller.manager.config.logFormat }}
- "--log-format={{ . }}"
{{- end }}
{{- with .Values.controller.manager.config.watchSingleNamespace }}
- "--watch-single-namespace={{ . }}"
{{- end }}
{{- with .Values.controller.manager.config.runnerMaxConcurrentReconciles }}
- "--runner-max-concurrent-reconciles={{ . }}"
{{- end }}
{{- with .Values.controller.manager.config.updateStrategy }}
- "--update-strategy={{ . }}"
{{- end }}
{{- if .Values.controller.metrics }}
{{- with .Values.controller.metrics }}
- "--listener-metrics-addr={{ .listenerAddr }}"
- "--listener-metrics-endpoint={{ .listenerEndpoint }}"
- "--metrics-addr={{ .controllerManagerAddr }}"
{{- end }}
{{- else }}
- "--listener-metrics-addr=0"
- "--listener-metrics-endpoint="
- "--metrics-addr=0"
{{- end }}
{{- range .Values.controller.manager.config.excludeLabelPropagationPrefixes }}
- "--exclude-label-propagation-prefix={{ . }}"
{{- end }}
{{- with .Values.controller.manager.config.k8sClientRateLimiterQPS }}
- "--k8s-client-rate-limiter-qps={{ . }}"
{{- end }}
{{- with .Values.controller.manager.config.k8sClientRateLimiterBurst }}
- "--k8s-client-rate-limiter-burst={{ . }}"
{{- end }}
{{- with .Values.controller.manager.container.extraArgs }}
{{- range . }}
- "{{ . }}"
{{- end }}
{{- end }}
{{- $ports := list -}}
{{- if .Values.controller.metrics }}
{{- $metricsPort := dict "containerPort" ((regexReplaceAll ":([0-9]+)" .Values.controller.metrics.controllerManagerAddr "${1}") | int) "protocol" "TCP" "name" "metrics" -}}
{{- $ports = append $ports $metricsPort -}}
{{- end }}
{{- with .Values.controller.manager.container.extraPorts }}
{{- if kindIs "slice" . }}
{{- $ports = concat $ports . -}}
{{- end }}
{{- end }}
{{- if gt (len $ports) 0 }}
ports:
{{- toYaml $ports | nindent 2 }}
{{- end }}
env:
- name: CONTROLLER_MANAGER_CONTAINER_IMAGE
value: "{{ .Values.controller.manager.container.image }}"
- name: CONTROLLER_MANAGER_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
{{- with .Values.controller.manager.container.env }}
{{- if kindIs "slice" . }}
{{- toYaml . | nindent 2 }}
{{- end }}
{{- end }}
{{- with .Values.controller.manager.container.resources }}
resources:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- with .Values.controller.manager.container.securityContext }}
securityContext:
{{- toYaml . | nindent 2 }}
{{- end }}
volumeMounts:
- mountPath: /tmp
name: tmp
{{- $podVolumeMounts := (.Values.controller.pod.volumeMounts | default list) -}}
{{- range $podVolumeMounts }}
- {{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,74 @@
{{- define "gha-base-name" -}}
gha-rs-controller
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "gha-controller.chart" -}}
{{- printf "%s-%s" (include "gha-base-name" .) .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "gha-common.labels" -}}
helm.sh/chart: {{ include "gha-controller.chart" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/part-of: "gha-rs-controller"
app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
app.kubernetes.io/name: {{ include "gha-controller.name" . }}
app.kubernetes.io/namespace: {{ include "gha-controller.namespace" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{- define "gha-controller.manager-cluster-role-name" -}}
{{- include "gha-controller.name" . }}
{{- end }}
{{- define "gha-controller.manager-cluster-role-binding" -}}
{{- include "gha-controller.name" . }}
{{- end }}
{{- define "gha-controller.manager-single-namespace-role-name" -}}
{{- include "gha-controller.name" . }}-single-namespace
{{- end }}
{{- define "gha-controller.manager-single-namespace-role-binding" -}}
{{- include "gha-controller.name" . }}-single-namespace
{{- end }}
{{- define "gha-controller.manager-single-namespace-watch-role-name" -}}
{{- include "gha-controller.name" . }}-single-namespace-watch
{{- end }}
{{- define "gha-controller.manager-single-namespace-watch-role-binding" -}}
{{- include "gha-controller.name" . }}-single-namespace-watch
{{- end }}
{{- define "gha-controller.manager-listener-role-name" -}}
{{- include "gha-controller.name" . }}-listener
{{- end }}
{{- define "gha-controller.manager-listener-role-binding" -}}
{{- include "gha-controller.name" . }}-listener
{{- end }}
{{- define "gha-controller.leaderElectionRoleName" -}}
{{- include "gha-controller.name" . }}-leader-election
{{- end }}
{{- define "gha-controller.leader-election-role-name" -}}
{{- include "gha-controller.leaderElectionRoleName" . -}}
{{- end }}
{{- define "gha-controller.leaderElectionRoleBinding" -}}
{{- include "gha-controller.name" . }}-leader-election
{{- end }}
{{- define "gha-controller.leader-election-role-binding" -}}
{{- include "gha-controller.leaderElectionRoleBinding" . -}}
{{- end }}

View File

@@ -0,0 +1,21 @@
{{/*
Takes a map of user labels and removes the ones with "actions.github.com/" prefix
*/}}
{{- 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 -}}
{{- end -}}
{{- end -}}
{{- if not (empty $processed) -}}
{{- $processed | toYaml }}
{{- end }}
{{- end }}
{{- define "gha-controller.selector-labels" -}}
app.kubernetes.io/name: {{ include "gha-controller.name" . }}
app.kubernetes.io/namespace: {{ include "gha-controller.namespace" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

View File

@@ -0,0 +1,54 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "gha-controller.name" . }}
namespace: {{ include "gha-controller.namespace" . }}
labels:
{{- include "gha-controller.labels" . | nindent 4 }}
spec:
replicas: {{ default 1 .Values.controller.replicaCount }}
selector:
matchLabels:
{{- include "gha-controller.selector-labels" . | nindent 6 }}
template:
metadata:
annotations:
{{- include "gha-controller-template.annotations" . | nindent 8 }}
labels:
{{- include "gha-controller-template.labels" . | nindent 8 }}
spec:
{{- $pod := (.Values.controller.pod | default dict) -}}
{{- if and (hasKey .Values.controller "pod") (not (kindIs "map" $pod)) -}}
{{- fail "controller.pod must be an object" -}}
{{- end -}}
{{- $podSpec := (index $pod "spec" | default dict) -}}
{{- if and (hasKey $pod "spec") (not (kindIs "map" $podSpec)) -}}
{{- fail "controller.pod.spec must be an object" -}}
{{- end -}}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "gha-controller.service-account-name" . }}
containers:
-
{{- include "gha-controller-template.manager-container" . | nindent 10 }}
{{- $extraContainers := (index $podSpec "containers" | default list) -}}
{{- range $extraContainers }}
-
{{- toYaml . | nindent 10 }}
{{- end }}
terminationGracePeriodSeconds: {{ default 10 (index $podSpec "terminationGracePeriodSeconds") }}
volumes:
- name: tmp
emptyDir: {}
{{- $podVolumes := (index $podSpec "volumes" | default list) -}}
{{- range $podVolumes }}
- {{- toYaml . | nindent 10 }}
{{- end }}
{{- $runnerPodSpecExtraFields := (omit $podSpec "containers" "serviceAccountName" "terminationGracePeriodSeconds" "volumes") -}}
{{- if gt (len $runnerPodSpecExtraFields) 0 }}
{{- toYaml $runnerPodSpecExtraFields | nindent 6 }}
{{- end }}

View File

@@ -0,0 +1,15 @@
{{- if gt (int (default 1 .Values.controller.replicaCount)) 1 }}
# permissions to do leader election.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "gha-controller.leader-election-role-name" . }}
namespace: {{ include "gha-controller.namespace" . }}
rules:
- apiGroups: ["coordination.k8s.io"]
resources: ["leases"]
verbs: ["get", "watch", "list", "delete", "update", "create"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "patch"]
{{- end }}

View File

@@ -0,0 +1,15 @@
{{- if gt (int (default 1 .Values.controller.replicaCount)) 1 }}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "gha-controller.leader-election-role-binding" . }}
namespace: {{ include "gha-controller.namespace" . }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ include "gha-controller.leader-election-role-name" . }}
subjects:
- kind: ServiceAccount
name: {{ include "gha-controller.service-account-name" . }}
namespace: {{ include "gha-controller.namespace" . }}
{{- end }}

View File

@@ -0,0 +1,144 @@
{{- if empty .Values.controller.manager.config.watchSingleNamespace }}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "gha-controller.manager-cluster-role-name" . }}
rules:
- apiGroups:
- actions.github.com
resources:
- autoscalingrunnersets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- actions.github.com
resources:
- autoscalingrunnersets/finalizers
verbs:
- patch
- update
- apiGroups:
- actions.github.com
resources:
- autoscalingrunnersets/status
verbs:
- get
- patch
- update
- apiGroups:
- actions.github.com
resources:
- autoscalinglisteners
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- actions.github.com
resources:
- autoscalinglisteners/status
verbs:
- get
- patch
- update
- apiGroups:
- actions.github.com
resources:
- autoscalinglisteners/finalizers
verbs:
- patch
- update
- apiGroups:
- actions.github.com
resources:
- ephemeralrunnersets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- actions.github.com
resources:
- ephemeralrunnersets/status
verbs:
- get
- patch
- update
- apiGroups:
- actions.github.com
resources:
- ephemeralrunnersets/finalizers
verbs:
- patch
- update
- apiGroups:
- actions.github.com
resources:
- ephemeralrunners
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- actions.github.com
resources:
- ephemeralrunners/finalizers
verbs:
- patch
- update
- apiGroups:
- actions.github.com
resources:
- ephemeralrunners/status
verbs:
- get
- patch
- update
- apiGroups:
- ""
resources:
- pods
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- list
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
- rolebindings
verbs:
- list
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
- roles
verbs:
- list
- watch
- patch
{{- end }}

View File

@@ -0,0 +1,14 @@
{{- if empty .Values.controller.manager.config.watchSingleNamespace }}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "gha-controller.manager-cluster-role-binding" . }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "gha-controller.manager-cluster-role-name" . }}
subjects:
- kind: ServiceAccount
name: {{ include "gha-controller.service-account-name" . }}
namespace: {{ include "gha-controller.namespace" . }}
{{- end }}

View File

@@ -0,0 +1,40 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "gha-controller.manager-listener-role-name" . }}
namespace: {{ include "gha-controller.namespace" . }}
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- create
- delete
- get
- apiGroups:
- ""
resources:
- pods/status
verbs:
- get
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- delete
- get
- patch
- update
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- create
- delete
- get
- patch
- update

View File

@@ -0,0 +1,13 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "gha-controller.manager-listener-role-binding" . }}
namespace: {{ include "gha-controller.namespace" . }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ include "gha-controller.manager-listener-role-name" . }}
subjects:
- kind: ServiceAccount
name: {{ include "gha-controller.service-account-name" . }}
namespace: {{ include "gha-controller.namespace" . }}

View File

@@ -0,0 +1,84 @@
{{- if .Values.controller.manager.config.watchSingleNamespace }}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "gha-controller.manager-single-namespace-role-name" . }}
namespace: {{ include "gha-controller.namespace" . }}
rules:
- apiGroups:
- actions.github.com
resources:
- autoscalinglisteners
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- actions.github.com
resources:
- autoscalinglisteners/status
verbs:
- get
- patch
- update
- apiGroups:
- actions.github.com
resources:
- autoscalinglisteners/finalizers
verbs:
- patch
- update
- apiGroups:
- ""
resources:
- pods
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- list
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
- rolebindings
verbs:
- list
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
- roles
verbs:
- list
- watch
- apiGroups:
- actions.github.com
resources:
- autoscalingrunnersets
verbs:
- list
- watch
- apiGroups:
- actions.github.com
resources:
- ephemeralrunnersets
verbs:
- list
- watch
- apiGroups:
- actions.github.com
resources:
- ephemeralrunners
verbs:
- list
- watch
{{- end }}

View File

@@ -0,0 +1,15 @@
{{- if .Values.controller.manager.config.watchSingleNamespace }}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "gha-controller.manager-single-namespace-role-binding" . }}
namespace: {{ include "gha-controller.namespace" . }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ include "gha-controller.manager-single-namespace-role-name" . }}
subjects:
- kind: ServiceAccount
name: {{ include "gha-controller.service-account-name" . }}
namespace: {{ include "gha-controller.namespace" . }}
{{- end }}

View File

@@ -0,0 +1,125 @@
{{- if .Values.controller.manager.config.watchSingleNamespace }}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "gha-controller.manager-single-namespace-watch-role-name" . }}
namespace: {{ .Values.controller.manager.config.watchSingleNamespace }}
rules:
- apiGroups:
- actions.github.com
resources:
- autoscalingrunnersets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- actions.github.com
resources:
- autoscalingrunnersets/finalizers
verbs:
- patch
- update
- apiGroups:
- actions.github.com
resources:
- autoscalingrunnersets/status
verbs:
- get
- patch
- update
- apiGroups:
- actions.github.com
resources:
- ephemeralrunnersets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- actions.github.com
resources:
- ephemeralrunnersets/status
verbs:
- get
- patch
- update
- apiGroups:
- actions.github.com
resources:
- ephemeralrunnersets/finalizers
verbs:
- patch
- update
- apiGroups:
- actions.github.com
resources:
- ephemeralrunners
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- actions.github.com
resources:
- ephemeralrunners/finalizers
verbs:
- patch
- update
- apiGroups:
- actions.github.com
resources:
- ephemeralrunners/status
verbs:
- get
- patch
- update
- apiGroups:
- actions.github.com
resources:
- autoscalinglisteners
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- pods
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- list
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
- rolebindings
verbs:
- list
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
- roles
verbs:
- list
- watch
- patch
{{- end }}

View File

@@ -0,0 +1,15 @@
{{- if .Values.controller.manager.config.watchSingleNamespace }}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "gha-controller.manager-single-namespace-watch-role-binding" . }}
namespace: {{ .Values.controller.manager.config.watchSingleNamespace }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ include "gha-controller.manager-single-namespace-watch-role-name" . }}
subjects:
- kind: ServiceAccount
name: {{ include "gha-controller.service-account-name" . }}
namespace: {{ include "gha-controller.namespace" . }}
{{- end }}

View File

@@ -0,0 +1,13 @@
{{- if .Values.controller.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "gha-controller.service-account-name" . }}
namespace: {{ include "gha-controller.namespace" . }}
labels:
{{- include "gha-controller.labels" . | nindent 4 }}
{{- with .Values.controller.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,75 @@
suite: "Controller Deployment args"
templates:
- deployment.yaml
tests:
- it: should include metrics-disabled flags by default
release:
name: "test-arc"
namespace: "test-ns"
asserts:
- contains:
path: spec.template.spec.containers[0].args
content: "--metrics-addr=0"
- contains:
path: spec.template.spec.containers[0].args
content: "--listener-metrics-addr=0"
- contains:
path: spec.template.spec.containers[0].args
content: "--listener-metrics-endpoint="
- it: should include watch-single-namespace flag when configured
set:
controller:
manager:
config:
watchSingleNamespace: "demo"
release:
name: "test-arc"
namespace: "test-ns"
asserts:
- contains:
path: spec.template.spec.containers[0].args
content: "--watch-single-namespace=demo"
- it: should include exclude-label-propagation-prefix flags when configured
set:
controller:
manager:
config:
excludeLabelPropagationPrefixes:
- "prefix.com/"
- "complete.io/label"
release:
name: "test-arc"
namespace: "test-ns"
asserts:
- contains:
path: spec.template.spec.containers[0].args
content: "--exclude-label-propagation-prefix=prefix.com/"
- contains:
path: spec.template.spec.containers[0].args
content: "--exclude-label-propagation-prefix=complete.io/label"
- it: should render metrics port when metrics are enabled
set:
controller:
metrics:
controllerManagerAddr: ":8080"
listenerAddr: ":8081"
listenerEndpoint: "/metrics"
release:
name: "test-arc"
namespace: "test-ns"
asserts:
- equal:
path: spec.template.spec.containers[0].ports[0].containerPort
value: 8080
- contains:
path: spec.template.spec.containers[0].args
content: "--metrics-addr=:8080"
- contains:
path: spec.template.spec.containers[0].args
content: "--listener-metrics-addr=:8081"
- contains:
path: spec.template.spec.containers[0].args
content: "--listener-metrics-endpoint=/metrics"

View File

@@ -0,0 +1,46 @@
suite: "Controller Deployment env"
templates:
- deployment.yaml
tests:
- it: should not render envFrom in manager container
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- notExists:
path: spec.template.spec.containers[0].envFrom
- notExists:
path: spec.template.spec.containers[0].ports
- it: should include extra env entries from values
set:
controller:
manager:
container:
env:
- name: "FOO"
value: "bar"
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- contains:
path: spec.template.spec.containers[0].env
content:
name: "FOO"
value: "bar"
- it: should enable leader election when replicaCount > 1
set:
controller:
replicaCount: 2
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- contains:
path: spec.template.spec.containers[0].args
content: "--enable-leader-election"
- contains:
path: spec.template.spec.containers[0].args
content: "--leader-election-id=test-name-gha-rs-controller"

View File

@@ -0,0 +1,55 @@
suite: "Controller Deployment extra containers"
templates:
- deployment.yaml
tests:
- it: should render manager container first and then extra containers
set:
controller:
pod:
spec:
containers:
- name: "sidecar"
image: "busybox:1.36"
command:
- "sh"
- "-c"
args:
- "echo hello && sleep 3600"
- name: "another"
image: "alpine:3.19"
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- equal:
path: spec.template.spec.containers[0].name
value: "manager"
- equal:
path: spec.template.spec.containers[1].name
value: "sidecar"
- equal:
path: spec.template.spec.containers[1].image
value: "busybox:1.36"
- equal:
path: spec.template.spec.containers[1].command[0]
value: "sh"
- equal:
path: spec.template.spec.containers[1].args[0]
value: "echo hello && sleep 3600"
- equal:
path: spec.template.spec.containers[2].name
value: "another"
- equal:
path: spec.template.spec.containers[2].image
value: "alpine:3.19"
- it: should not fail when extra containers are unset
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- equal:
path: spec.template.spec.containers[0].name
value: "manager"
- notExists:
path: spec.template.spec.containers[1]

View File

@@ -0,0 +1,33 @@
suite: "Controller Deployment imagePullSecrets"
templates:
- deployment.yaml
tests:
- it: should not render imagePullSecrets by default
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- notExists:
path: spec.template.spec.imagePullSecrets
- it: should render imagePullSecrets and forward them as args when configured
set:
imagePullSecrets:
- name: regcred
- name: another
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- equal:
path: spec.template.spec.imagePullSecrets[0].name
value: regcred
- equal:
path: spec.template.spec.imagePullSecrets[1].name
value: another
- contains:
path: spec.template.spec.containers[0].args
content: "--auto-scaler-image-pull-secrets=regcred"
- contains:
path: spec.template.spec.containers[0].args
content: "--auto-scaler-image-pull-secrets=another"

View File

@@ -0,0 +1,54 @@
suite: "Controller Deployment pod extra fields"
templates:
- deployment.yaml
tests:
- it: should render extra pod spec fields from controller.pod
set:
controller:
pod:
spec:
nodeSelector:
kubernetes.io/os: linux
tolerations:
- key: "dedicated"
operator: "Equal"
value: "arc"
effect: "NoSchedule"
hostNetwork: true
dnsPolicy: "ClusterFirstWithHostNet"
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- equal:
path: spec.template.spec.nodeSelector["kubernetes.io/os"]
value: "linux"
- equal:
path: spec.template.spec.tolerations[0].key
value: "dedicated"
- equal:
path: spec.template.spec.tolerations[0].value
value: "arc"
- equal:
path: spec.template.spec.hostNetwork
value: true
- equal:
path: spec.template.spec.dnsPolicy
value: "ClusterFirstWithHostNet"
- it: should not allow overriding serviceAccountName via controller.pod
set:
controller:
pod:
spec:
serviceAccountName: "hacker-sa"
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- equal:
path: spec.template.spec.serviceAccountName
value: "test-name-gha-rs-controller"
- notEqual:
path: spec.template.spec.serviceAccountName
value: "hacker-sa"

View File

@@ -0,0 +1,27 @@
suite: "Controller Deployment smoke"
templates:
- deployment.yaml
tests:
- it: should render deployment basics
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- equal:
path: apiVersion
value: "apps/v1"
- equal:
path: kind
value: "Deployment"
- equal:
path: metadata.name
value: "test-name-gha-rs-controller"
- equal:
path: metadata.namespace
value: "test-namespace"
- equal:
path: spec.template.spec.containers[0].name
value: "manager"
- contains:
path: spec.template.spec.containers[0].command
content: "/manager"

View File

@@ -0,0 +1,25 @@
suite: "Controller Deployment volume mounts"
templates:
- deployment.yaml
tests:
- it: should append controller.pod.volumeMounts to manager container
set:
controller:
manager:
container:
image: "ghcr.io/actions/gha-runner-scale-set-controller:latest"
pod:
volumeMounts:
- name: my-config
mountPath: /etc/my-config
readOnly: true
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- contains:
path: spec.template.spec.containers[0].volumeMounts
content:
name: my-config
mountPath: /etc/my-config
readOnly: true

View File

@@ -0,0 +1,26 @@
suite: "Controller Deployment volumes"
templates:
- deployment.yaml
tests:
- it: should append controller.pod.spec.volumes to pod spec volumes
set:
controller:
manager:
container:
image: "ghcr.io/actions/gha-runner-scale-set-controller:latest"
pod:
spec:
volumes:
- name: my-config
configMap:
name: my-config
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- contains:
path: spec.template.spec.volumes
content:
name: my-config
configMap:
name: my-config

View File

@@ -0,0 +1,37 @@
suite: "Controller Manager ClusterRoleBinding"
templates:
- manager_cluster_role_binding.yaml
tests:
- it: should render when watchSingleNamespace is empty
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- equal:
path: apiVersion
value: "rbac.authorization.k8s.io/v1"
- equal:
path: kind
value: "ClusterRoleBinding"
- equal:
path: subjects[0].kind
value: "ServiceAccount"
- equal:
path: subjects[0].name
value: "test-name-gha-rs-controller"
- equal:
path: subjects[0].namespace
value: "test-namespace"
- it: should not render when watchSingleNamespace is set
set:
controller:
manager:
config:
watchSingleNamespace: "my-ns"
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- hasDocuments:
count: 0

View File

@@ -0,0 +1,24 @@
suite: "Controller namespaceOverride"
templates:
- deployment.yaml
- serviceaccount.yaml
tests:
- it: should apply namespaceOverride to deployment and serviceaccount
set:
namespaceOverride: "override-ns"
release:
name: "test-name"
namespace: "release-ns"
asserts:
- equal:
path: metadata.namespace
value: "override-ns"
template: deployment.yaml
- equal:
path: metadata.labels["actions.github.com/controller-service-account-namespace"]
value: "override-ns"
template: deployment.yaml
- equal:
path: metadata.namespace
value: "override-ns"
template: serviceaccount.yaml

View File

@@ -0,0 +1,38 @@
suite: "Controller RBAC cluster"
templates:
- manager_cluster_role.yaml
tests:
- it: should render manager ClusterRole when watchSingleNamespace is empty
release:
name: "test-arc"
namespace: "test-ns"
asserts:
- equal:
path: kind
value: "ClusterRole"
- equal:
path: metadata.name
value: "test-arc-gha-rs-controller"
- contains:
path: rules
content:
apiGroups:
- ""
resources:
- pods
verbs:
- list
- watch
- it: should not render manager ClusterRole when watchSingleNamespace is set
set:
controller:
manager:
config:
watchSingleNamespace: "demo"
release:
name: "test-arc"
namespace: "test-ns"
asserts:
- hasDocuments:
count: 0

View File

@@ -0,0 +1,52 @@
suite: "Controller RBAC leader election"
templates:
- leader_election_role.yaml
- leader_election_role_binding.yaml
tests:
- it: should not render leader election resources when replicaCount is 1
set:
controller:
replicaCount: 1
release:
name: "test-arc"
namespace: "test-ns"
asserts:
- hasDocuments:
count: 0
template: leader_election_role.yaml
- hasDocuments:
count: 0
template: leader_election_role_binding.yaml
- it: should render leader election resources when replicaCount > 1
set:
controller:
replicaCount: 2
release:
name: "test-arc"
namespace: "test-ns"
asserts:
- equal:
path: kind
value: "Role"
template: leader_election_role.yaml
- equal:
path: metadata.name
value: "test-arc-gha-rs-controller-leader-election"
template: leader_election_role.yaml
- equal:
path: metadata.namespace
value: "test-ns"
template: leader_election_role.yaml
- equal:
path: kind
value: "RoleBinding"
template: leader_election_role_binding.yaml
- equal:
path: roleRef.name
value: "test-arc-gha-rs-controller-leader-election"
template: leader_election_role_binding.yaml
- equal:
path: subjects[0].name
value: "test-arc-gha-rs-controller"
template: leader_election_role_binding.yaml

View File

@@ -0,0 +1,68 @@
suite: "Controller RBAC listener"
templates:
- manager_listener_role.yaml
- manager_listener_role_binding.yaml
tests:
- it: should render listener role with expected rules
release:
name: "test-arc"
namespace: "test-ns"
asserts:
- equal:
path: kind
value: "Role"
template: manager_listener_role.yaml
- equal:
path: metadata.name
value: "test-arc-gha-rs-controller-listener"
template: manager_listener_role.yaml
- equal:
path: metadata.namespace
value: "test-ns"
template: manager_listener_role.yaml
- equal:
path: rules[0].resources[0]
value: "pods"
template: manager_listener_role.yaml
- equal:
path: rules[1].resources[0]
value: "pods/status"
template: manager_listener_role.yaml
- equal:
path: rules[2].resources[0]
value: "secrets"
template: manager_listener_role.yaml
- equal:
path: rules[3].resources[0]
value: "serviceaccounts"
template: manager_listener_role.yaml
- it: should bind listener role to controller serviceaccount
release:
name: "test-arc"
namespace: "test-ns"
asserts:
- equal:
path: kind
value: "RoleBinding"
template: manager_listener_role_binding.yaml
- equal:
path: metadata.name
value: "test-arc-gha-rs-controller-listener"
template: manager_listener_role_binding.yaml
- equal:
path: metadata.namespace
value: "test-ns"
template: manager_listener_role_binding.yaml
- equal:
path: roleRef.name
value: "test-arc-gha-rs-controller-listener"
template: manager_listener_role_binding.yaml
- equal:
path: subjects[0].name
value: "test-arc-gha-rs-controller"
template: manager_listener_role_binding.yaml
- equal:
path: subjects[0].namespace
value: "test-ns"
template: manager_listener_role_binding.yaml

View File

@@ -0,0 +1,56 @@
suite: "Controller RBAC single-namespace mode"
templates:
- manager_single_namespace_controller_role.yaml
- manager_single_namespace_controller_role_binding.yaml
- manager_single_namespace_watch_role.yaml
- manager_single_namespace_watch_role_binding.yaml
tests:
- it: should not render single-namespace roles when watchSingleNamespace is empty
set:
controller:
manager:
config:
watchSingleNamespace: ""
release:
name: "test-arc"
namespace: "test-ns"
asserts:
- hasDocuments:
count: 0
template: manager_single_namespace_controller_role.yaml
- hasDocuments:
count: 0
template: manager_single_namespace_controller_role_binding.yaml
- hasDocuments:
count: 0
template: manager_single_namespace_watch_role.yaml
- hasDocuments:
count: 0
template: manager_single_namespace_watch_role_binding.yaml
- it: should render roles in controller namespace and watch namespace
set:
controller:
manager:
config:
watchSingleNamespace: "demo"
release:
name: "test-arc"
namespace: "ctrl-ns"
asserts:
- equal:
path: metadata.namespace
value: "ctrl-ns"
template: manager_single_namespace_controller_role.yaml
- equal:
path: metadata.namespace
value: "ctrl-ns"
template: manager_single_namespace_controller_role_binding.yaml
- equal:
path: metadata.namespace
value: "demo"
template: manager_single_namespace_watch_role.yaml
- equal:
path: metadata.namespace
value: "demo"
template: manager_single_namespace_watch_role_binding.yaml

View File

@@ -0,0 +1,46 @@
suite: "Controller serviceAccount.create toggle"
templates:
- serviceaccount.yaml
- deployment.yaml
tests:
- it: should create ServiceAccount and use it in Deployment when create is true
set:
controller:
manager:
container:
image: "ghcr.io/actions/gha-runner-scale-set-controller:latest"
serviceAccount:
create: true
name: ""
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- hasDocuments:
count: 1
template: serviceaccount.yaml
- equal:
path: spec.template.spec.serviceAccountName
value: "test-name-gha-rs-controller"
template: deployment.yaml
- it: should not create ServiceAccount and use provided name in Deployment when create is false
set:
controller:
manager:
container:
image: "ghcr.io/actions/gha-runner-scale-set-controller:latest"
serviceAccount:
create: false
name: "existing-sa"
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- hasDocuments:
count: 0
template: serviceaccount.yaml
- equal:
path: spec.template.spec.serviceAccountName
value: "existing-sa"
template: deployment.yaml

View File

@@ -0,0 +1,72 @@
suite: "Controller ServiceAccount"
templates:
- serviceaccount.yaml
tests:
- it: should render serviceaccount by default
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- equal:
path: apiVersion
value: "v1"
- equal:
path: kind
value: "ServiceAccount"
- equal:
path: metadata.name
value: "test-name-gha-rs-controller"
- equal:
path: metadata.namespace
value: "test-namespace"
- equal:
path: metadata.labels["actions.github.com/controller-service-account-name"]
value: "test-name-gha-rs-controller"
- equal:
path: metadata.labels["actions.github.com/controller-service-account-namespace"]
value: "test-namespace"
- it: should allow overriding serviceAccount.name when create is true
set:
controller:
serviceAccount:
create: true
name: "overwritten-name"
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- equal:
path: metadata.name
value: "overwritten-name"
- equal:
path: metadata.labels["actions.github.com/controller-service-account-name"]
value: "overwritten-name"
- it: should render serviceAccount annotations
set:
controller:
serviceAccount:
create: true
annotations:
foo: bar
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- equal:
path: metadata.annotations.foo
value: "bar"
- it: should not render when serviceAccount.create is false
set:
controller:
serviceAccount:
create: false
name: "existing-sa"
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- hasDocuments:
count: 0

View File

@@ -0,0 +1,32 @@
suite: "Controller ServiceAccount validation"
templates:
- serviceaccount.yaml
- deployment.yaml
tests:
- it: should fail if serviceAccount.name is 'default'
set:
controller:
serviceAccount:
create: true
name: "default"
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- failedTemplate:
errorMessage: "serviceAccount.name cannot be set to 'default'"
template: serviceaccount.yaml
- it: should fail when serviceAccount.create is false and name is not set
set:
controller:
serviceAccount:
create: false
name: ""
release:
name: "test-name"
namespace: "test-namespace"
asserts:
- failedTemplate:
errorMessage: "serviceAccount.name must be set if serviceAccount.create is false"
template: deployment.yaml

View File

@@ -0,0 +1,106 @@
# Global chart-level labels applied to all resources (Deployment, RBAC, etc.).
labels: {}
# Overrides the default `.Release.Namespace` for all resources in this chart.
namespaceOverride: ""
# Optional imagePullSecrets added to the controller Pod spec.
# When set, the manager container also receives `--auto-scaler-image-pull-secrets=<name>` args.
imagePullSecrets: []
controller:
# Number of controller replicas.
replicaCount: 1
# Deployment-level metadata
metadata:
labels: {}
annotations: {}
manager:
config:
# Log level: "debug", "info", "warn", "error".
logLevel: "debug"
# Log format: "text", "json".
logFormat: "text"
# Restricts the controller to only watch resources in the desired namespace.
# Defaults to watch all namespaces when unset.
watchSingleNamespace: ""
# The maximum number of concurrent reconciles which can be run by the EphemeralRunner controller.
runnerMaxConcurrentReconciles: 2
# How the controller handles upgrades with running jobs: "immediate" or "eventual".
updateStrategy: "immediate"
# List of label prefixes that should NOT be propagated to internal resources.
excludeLabelPropagationPrefixes: []
# Example:
# excludeLabelPropagationPrefixes:
# - "argocd.argoproj.io/instance"
# K8s client rate limiter parameters.
k8sClientRateLimiterQPS: null
k8sClientRateLimiterBurst: null
container:
image: "ghcr.io/actions/gha-runner-scale-set-controller:latest"
pullPolicy: IfNotPresent
# Extra arguments appended to the default set generated by the chart.
extraArgs: []
# Container-level environment variables.
env: []
# Container-level security context.
securityContext: {}
# Container-level resource requests/limits.
resources: {}
# Extra container ports (metrics port is derived from controller.metrics).
extraPorts: []
serviceAccount:
# Specifies whether a service account should be created.
create: true
# Annotations to add to the service account.
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template.
name: ""
# Pod-level configuration.
pod:
metadata:
labels: {}
annotations: {}
# PodSpec fields applied to spec.template.spec.
# Note: containers provided here are appended after the built-in manager container.
spec:
# Pod-level security context.
securityContext: {}
# Pod priority class name.
priorityClassName: ""
# Node selection constraints.
nodeSelector: {}
# Pod tolerations.
tolerations: []
# Pod affinity.
affinity: {}
# Pod topology spread constraints.
topologySpreadConstraints: []
# Pod termination grace period (overrides default 10s).
terminationGracePeriodSeconds: null
# Additional volumes appended to the default ones.
volumes: []
# Additional containers appended after the manager container.
containers: []
# Additional volume mounts appended to the manager container's default ones.
volumeMounts: []
# Metrics configuration. If omitted, metrics are disabled.
# metrics:
# controllerManagerAddr: ":8080"
# listenerAddr: ":8080"
# listenerEndpoint: "/metrics"