Introduce new helm charts for the preview auto-scaling mode for ARC. (#2168)
This commit is contained in:
		
							parent
							
								
									c4d3cff3df
								
							
						
					
					
						commit
						0324658a3f
					
				
							
								
								
									
										4
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										4
									
								
								Makefile
								
								
								
								
							|  | @ -116,6 +116,10 @@ manifests-gen-crds: controller-gen yq | |||
| 
 | ||||
| chart-crds: | ||||
| 	cp config/crd/bases/*.yaml charts/actions-runner-controller/crds/ | ||||
| 	cp config/crd/bases/actions.github.com_autoscalingrunnersets.yaml charts/actions-runner-controller-2/crds/ | ||||
| 	cp config/crd/bases/actions.github.com_autoscalinglisteners.yaml charts/actions-runner-controller-2/crds/ | ||||
| 	cp config/crd/bases/actions.github.com_ephemeralrunnersets.yaml charts/actions-runner-controller-2/crds/ | ||||
| 	cp config/crd/bases/actions.github.com_ephemeralrunners.yaml charts/actions-runner-controller-2/crds/ | ||||
| 	rm charts/actions-runner-controller/crds/actions.github.com_autoscalingrunnersets.yaml | ||||
| 	rm charts/actions-runner-controller/crds/actions.github.com_autoscalinglisteners.yaml | ||||
| 	rm charts/actions-runner-controller/crds/actions.github.com_ephemeralrunnersets.yaml | ||||
|  |  | |||
|  | @ -0,0 +1,23 @@ | |||
| # 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/ | ||||
|  | @ -0,0 +1,33 @@ | |||
| apiVersion: v2 | ||||
| name: actions-runner-controller-2 | ||||
| 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.1.0 | ||||
| 
 | ||||
| # 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: "preview" | ||||
| 
 | ||||
| home: https://github.com/actions/actions-runner-controller | ||||
| 
 | ||||
| sources: | ||||
|   - "https://github.com/actions/actions-runner-controller" | ||||
| 
 | ||||
| maintainers: | ||||
|   - name: actions | ||||
|     url: https://github.com/actions | ||||
|  | @ -0,0 +1,97 @@ | |||
| apiVersion: apiextensions.k8s.io/v1 | ||||
| kind: CustomResourceDefinition | ||||
| metadata: | ||||
|   annotations: | ||||
|     controller-gen.kubebuilder.io/version: v0.7.0 | ||||
|   creationTimestamp: null | ||||
|   name: autoscalinglisteners.actions.github.com | ||||
| spec: | ||||
|   group: actions.github.com | ||||
|   names: | ||||
|     kind: AutoscalingListener | ||||
|     listKind: AutoscalingListenerList | ||||
|     plural: autoscalinglisteners | ||||
|     singular: autoscalinglistener | ||||
|   scope: Namespaced | ||||
|   versions: | ||||
|     - additionalPrinterColumns: | ||||
|         - jsonPath: .spec.githubConfigUrl | ||||
|           name: GitHub Configure URL | ||||
|           type: string | ||||
|         - jsonPath: .spec.autoscalingRunnerSetNamespace | ||||
|           name: AutoscalingRunnerSet Namespace | ||||
|           type: string | ||||
|         - jsonPath: .spec.autoscalingRunnerSetName | ||||
|           name: AutoscalingRunnerSet Name | ||||
|           type: string | ||||
|       name: v1alpha1 | ||||
|       schema: | ||||
|         openAPIV3Schema: | ||||
|           description: AutoscalingListener is the Schema for the autoscalinglisteners API | ||||
|           properties: | ||||
|             apiVersion: | ||||
|               description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' | ||||
|               type: string | ||||
|             kind: | ||||
|               description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' | ||||
|               type: string | ||||
|             metadata: | ||||
|               type: object | ||||
|             spec: | ||||
|               description: AutoscalingListenerSpec defines the desired state of AutoscalingListener | ||||
|               properties: | ||||
|                 autoscalingRunnerSetName: | ||||
|                   description: Required | ||||
|                   type: string | ||||
|                 autoscalingRunnerSetNamespace: | ||||
|                   description: Required | ||||
|                   type: string | ||||
|                 ephemeralRunnerSetName: | ||||
|                   description: Required | ||||
|                   type: string | ||||
|                 githubConfigSecret: | ||||
|                   description: Required | ||||
|                   type: string | ||||
|                 githubConfigUrl: | ||||
|                   description: Required | ||||
|                   type: string | ||||
|                 image: | ||||
|                   description: Required | ||||
|                   type: string | ||||
|                 imagePullSecrets: | ||||
|                   description: Required | ||||
|                   items: | ||||
|                     description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. | ||||
|                     properties: | ||||
|                       name: | ||||
|                         description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' | ||||
|                         type: string | ||||
|                     type: object | ||||
|                   type: array | ||||
|                 maxRunners: | ||||
|                   description: Required | ||||
|                   minimum: 0 | ||||
|                   type: integer | ||||
|                 minRunners: | ||||
|                   description: Required | ||||
|                   minimum: 0 | ||||
|                   type: integer | ||||
|                 runnerScaleSetId: | ||||
|                   description: Required | ||||
|                   type: integer | ||||
|               type: object | ||||
|             status: | ||||
|               description: AutoscalingListenerStatus defines the observed state of AutoscalingListener | ||||
|               type: object | ||||
|           type: object | ||||
|       served: true | ||||
|       storage: true | ||||
|       subresources: | ||||
|         status: {} | ||||
|   preserveUnknownFields: false | ||||
| status: | ||||
|   acceptedNames: | ||||
|     kind: "" | ||||
|     plural: "" | ||||
|   conditions: [] | ||||
|   storedVersions: [] | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,3 @@ | |||
| Thank you for installing {{ .Chart.Name }}. | ||||
| 
 | ||||
| Your release is named {{ .Release.Name }}. | ||||
|  | @ -0,0 +1,97 @@ | |||
| {{/* | ||||
| Expand the name of the chart. | ||||
| */}} | ||||
| {{- define "actions-runner-controller-2.name" -}} | ||||
| {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} | ||||
| {{- 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 "actions-runner-controller-2.fullname" -}} | ||||
| {{- if .Values.fullnameOverride }} | ||||
| {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} | ||||
| {{- else }} | ||||
| {{- $name := default .Chart.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 }} | ||||
| 
 | ||||
| {{/* | ||||
| Create chart name and version as used by the chart label. | ||||
| */}} | ||||
| {{- define "actions-runner-controller-2.chart" -}} | ||||
| {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{/* | ||||
| Common labels | ||||
| */}} | ||||
| {{- define "actions-runner-controller-2.labels" -}} | ||||
| helm.sh/chart: {{ include "actions-runner-controller-2.chart" . }} | ||||
| {{ include "actions-runner-controller-2.selectorLabels" . }} | ||||
| {{- if .Chart.AppVersion }} | ||||
| app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} | ||||
| {{- end }} | ||||
| app.kubernetes.io/part-of: {{ .Chart.Name }} | ||||
| app.kubernetes.io/managed-by: {{ .Release.Service }} | ||||
| {{- range $k, $v := .Values.labels }} | ||||
| {{ $k }}: {{ $v }} | ||||
| {{- end }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{/* | ||||
| Selector labels | ||||
| */}} | ||||
| {{- define "actions-runner-controller-2.selectorLabels" -}} | ||||
| app.kubernetes.io/name: {{ include "actions-runner-controller-2.name" . }} | ||||
| app.kubernetes.io/instance: {{ .Release.Name }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{/* | ||||
| Create the name of the service account to use | ||||
| */}} | ||||
| {{- define "actions-runner-controller-2.serviceAccountName" -}} | ||||
| {{- if eq .Values.serviceAccount.name "default"}} | ||||
| {{- fail "serviceAccount.name cannot be set to 'default'" }} | ||||
| {{- end }} | ||||
| {{- if .Values.serviceAccount.create }} | ||||
| {{- default (include "actions-runner-controller-2.fullname" .) .Values.serviceAccount.name }} | ||||
| {{- else }} | ||||
|     {{- if not .Values.serviceAccount.name }} | ||||
| {{- fail "serviceAccount.name must be set if serviceAccount.create is false" }} | ||||
|     {{- else }} | ||||
| {{- .Values.serviceAccount.name }} | ||||
|     {{- end }} | ||||
| {{- end }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "actions-runner-controller-2.managerRoleName" -}} | ||||
| {{- include "actions-runner-controller-2.fullname" . }}-manager-role | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "actions-runner-controller-2.managerRoleBinding" -}} | ||||
| {{- include "actions-runner-controller-2.fullname" . }}-manager-rolebinding | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "actions-runner-controller-2.leaderElectionRoleName" -}} | ||||
| {{- include "actions-runner-controller-2.fullname" . }}-leader-election-role | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "actions-runner-controller-2.leaderElectionRoleBinding" -}} | ||||
| {{- include "actions-runner-controller-2.fullname" . }}-leader-election-rolebinding | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "actions-runner-controller-2.imagePullSecretsNames" -}} | ||||
| {{- $names := list }} | ||||
| {{- range $k, $v := . }} | ||||
| {{- $names = append $names $v.name }} | ||||
| {{- end }} | ||||
| {{- $names | join ","}} | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,98 @@ | |||
| apiVersion: apps/v1 | ||||
| kind: Deployment | ||||
| metadata: | ||||
|   name: {{ include "actions-runner-controller-2.fullname" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
|   labels: | ||||
|     {{- include "actions-runner-controller-2.labels" . | nindent 4 }} | ||||
| spec: | ||||
|   replicas: {{ default 1 .Values.replicaCount }} | ||||
|   selector: | ||||
|     matchLabels: | ||||
|       {{- include "actions-runner-controller-2.selectorLabels" . | nindent 6 }} | ||||
|   template: | ||||
|     metadata: | ||||
|       annotations: | ||||
|         kubectl.kubernetes.io/default-container: "manager" | ||||
|       {{- with .Values.podAnnotations }} | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|       labels: | ||||
|         app.kubernetes.io/part-of: actions-runner-controller | ||||
|         app.kubernetes.io/component: controller-manager | ||||
|         app.kubernetes.io/version: {{ .Chart.Version }} | ||||
|         {{- include "actions-runner-controller-2.selectorLabels" . | nindent 8 }} | ||||
|     spec: | ||||
|       {{- with .Values.imagePullSecrets }} | ||||
|       imagePullSecrets: | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|       serviceAccountName: {{ include "actions-runner-controller-2.serviceAccountName" . }} | ||||
|       {{- with .Values.podSecurityContext }} | ||||
|       securityContext: | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|       {{- with .Values.priorityClassName }} | ||||
|       priorityClassName: "{{ . }}" | ||||
|       {{- end }} | ||||
|       containers: | ||||
|       - name: manager | ||||
|         image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" | ||||
|         imagePullPolicy: {{ .Values.image.pullPolicy }} | ||||
|         args: | ||||
|         - "--auto-scaling-runner-set-only" | ||||
|         {{- if gt (int (default 1 .Values.replicaCount)) 1 }} | ||||
|         - "--enable-leader-election" | ||||
|         - "--leader-election-id={{ include "actions-runner-controller-2.fullname" . }}" | ||||
|         {{- end }} | ||||
|         {{- with .Values.imagePullSecrets }} | ||||
|         - "--auto-scaler-image-pull-secrets={{ include "actions-runner-controller-2.imagePullSecretsNames" . }}" | ||||
|         {{- end }} | ||||
|         command: | ||||
|         - "/manager" | ||||
|         env: | ||||
|         - name: CONTROLLER_MANAGER_POD_NAME | ||||
|           valueFrom: | ||||
|             fieldRef: | ||||
|               fieldPath: metadata.name | ||||
|         - name: CONTROLLER_MANAGER_POD_NAMESPACE | ||||
|           valueFrom: | ||||
|             fieldRef: | ||||
|               fieldPath: metadata.namespace | ||||
|         {{- with .Values.env }} | ||||
|           {{- if kindIs "slice" .Values.env }} | ||||
|         {{- toYaml .Values.env | nindent 8 }} | ||||
|           {{- else }} | ||||
|             {{- range $key, $val := .Values.env }} | ||||
|         - name: {{ $key }} | ||||
|           value: {{ $val | quote }} | ||||
|             {{- end }} | ||||
|           {{- end }} | ||||
|         {{- end }} | ||||
|         {{- with .Values.resources }} | ||||
|         resources: | ||||
|           {{- toYaml . | nindent 12 }} | ||||
|         {{- end }} | ||||
|         {{- with .Values.securityContext }} | ||||
|         securityContext: | ||||
|           {{- toYaml . | nindent 12 }} | ||||
|         {{- end }} | ||||
|         volumeMounts: | ||||
|         - mountPath: /tmp | ||||
|           name: tmp | ||||
|       terminationGracePeriodSeconds: 10 | ||||
|       volumes: | ||||
|       - name: tmp | ||||
|         emptyDir: {} | ||||
|       {{- with .Values.nodeSelector }} | ||||
|       nodeSelector: | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|       {{- with .Values.affinity }} | ||||
|       affinity: | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|       {{- with .Values.tolerations }} | ||||
|       tolerations: | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|  | @ -0,0 +1,12 @@ | |||
| {{- if gt (int (default 1 .Values.replicaCount)) 1 -}} | ||||
| # permissions to do leader election. | ||||
| apiVersion: rbac.authorization.k8s.io/v1 | ||||
| kind: Role | ||||
| metadata: | ||||
|   name: {{ include "actions-runner-controller-2.leaderElectionRoleName" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
| rules: | ||||
|   - apiGroups: ["coordination.k8s.io"] | ||||
|     resources: ["leases"] | ||||
|     verbs: ["get", "watch", "list", "delete", "update", "create"] | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,15 @@ | |||
| {{- if gt (int (default 1 .Values.replicaCount)) 1 -}} | ||||
| apiVersion: rbac.authorization.k8s.io/v1 | ||||
| kind: RoleBinding | ||||
| metadata: | ||||
|   name: {{ include "actions-runner-controller-2.leaderElectionRoleBinding" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
| roleRef: | ||||
|   apiGroup: rbac.authorization.k8s.io | ||||
|   kind: Role | ||||
|   name: {{ include "actions-runner-controller-2.leaderElectionRoleName" . }} | ||||
| subjects: | ||||
| - kind: ServiceAccount | ||||
|   name: {{ include "actions-runner-controller-2.serviceAccountName" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,250 @@ | |||
| apiVersion: rbac.authorization.k8s.io/v1 | ||||
| kind: ClusterRole | ||||
| metadata: | ||||
|   name: {{ include "actions-runner-controller-2.managerRoleName" . }} | ||||
| rules: | ||||
| - apiGroups: | ||||
|   - actions.github.com | ||||
|   resources: | ||||
|   - autoscalingrunnersets | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - list | ||||
|   - patch | ||||
|   - update | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - actions.github.com | ||||
|   resources: | ||||
|   - autoscalingrunnersets/finalizers | ||||
|   verbs: | ||||
|   - 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: | ||||
|   - 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: | ||||
|   - ephemeralrunners | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - list | ||||
|   - patch | ||||
|   - update | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - actions.github.com | ||||
|   resources: | ||||
|   - ephemeralrunners/finalizers | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - list | ||||
|   - patch | ||||
|   - update | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - actions.github.com | ||||
|   resources: | ||||
|   - ephemeralrunners/status | ||||
|   verbs: | ||||
|   - get | ||||
|   - patch | ||||
|   - update | ||||
| - apiGroups: | ||||
|   - "" | ||||
|   resources: | ||||
|   - events | ||||
|   verbs: | ||||
|   - create | ||||
|   - patch | ||||
| - apiGroups: | ||||
|   - "" | ||||
|   resources: | ||||
|   - namespaces | ||||
|   - pods | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - list | ||||
|   - patch | ||||
|   - update | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - "" | ||||
|   resources: | ||||
|   - persistentvolumeclaims | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - list | ||||
|   - patch | ||||
|   - update | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - "" | ||||
|   resources: | ||||
|   - namespaces/status | ||||
|   - pods/status | ||||
|   verbs: | ||||
|   - get | ||||
| - apiGroups: | ||||
|   - "" | ||||
|   resources: | ||||
|   - persistentvolumes | ||||
|   verbs: | ||||
|   - delete | ||||
|   - get | ||||
|   - list | ||||
|   - patch | ||||
|   - update | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - "" | ||||
|   resources: | ||||
|   - pods | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - list | ||||
|   - patch | ||||
|   - update | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - "" | ||||
|   resources: | ||||
|   - pods/finalizers | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - list | ||||
|   - patch | ||||
|   - update | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - "" | ||||
|   resources: | ||||
|   - secrets | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - list | ||||
|   - watch | ||||
|   - update | ||||
| - apiGroups: | ||||
|   - "" | ||||
|   resources: | ||||
|   - serviceaccounts | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - list | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - rbac.authorization.k8s.io | ||||
|   resources: | ||||
|   - rolebindings | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - update | ||||
|   - list | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - rbac.authorization.k8s.io | ||||
|   resources: | ||||
|   - roles | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - update | ||||
|   - list | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - "" | ||||
|   resources: | ||||
|   - pods/exec | ||||
|   verbs: | ||||
|   - create | ||||
|   - get | ||||
| - apiGroups: | ||||
|   - "" | ||||
|   resources: | ||||
|   - pods/log | ||||
|   verbs: | ||||
|   - get | ||||
|   - list | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - "batch" | ||||
|   resources: | ||||
|   - jobs | ||||
|   verbs: | ||||
|   - get | ||||
|   - list | ||||
|   - create | ||||
|   - delete | ||||
|  | @ -0,0 +1,12 @@ | |||
| apiVersion: rbac.authorization.k8s.io/v1 | ||||
| kind: ClusterRoleBinding | ||||
| metadata: | ||||
|   name: {{ include "actions-runner-controller-2.managerRoleBinding" . }} | ||||
| roleRef: | ||||
|   apiGroup: rbac.authorization.k8s.io | ||||
|   kind: ClusterRole | ||||
|   name: {{ include "actions-runner-controller-2.managerRoleName" . }} | ||||
| subjects: | ||||
| - kind: ServiceAccount | ||||
|   name: {{ include "actions-runner-controller-2.serviceAccountName" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
|  | @ -0,0 +1,13 @@ | |||
| {{- if .Values.serviceAccount.create -}} | ||||
| apiVersion: v1 | ||||
| kind: ServiceAccount | ||||
| metadata: | ||||
|   name: {{ include "actions-runner-controller-2.serviceAccountName" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
|   labels: | ||||
|     {{- include "actions-runner-controller-2.labels" . | nindent 4 }} | ||||
|   {{- with .Values.serviceAccount.annotations }} | ||||
|   annotations: | ||||
|     {{- toYaml . | nindent 4 }} | ||||
|   {{- end }} | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,508 @@ | |||
| package tests | ||||
| 
 | ||||
| import ( | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/gruntwork-io/terratest/modules/helm" | ||||
| 	"github.com/gruntwork-io/terratest/modules/k8s" | ||||
| 	"github.com/gruntwork-io/terratest/modules/random" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| 	appsv1 "k8s.io/api/apps/v1" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	rbacv1 "k8s.io/api/rbac/v1" | ||||
| ) | ||||
| 
 | ||||
| func TestTemplate_CreateServiceAccount(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../actions-runner-controller-2") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-arc" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"serviceAccount.create":          "true", | ||||
| 			"serviceAccount.annotations.foo": "bar", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/serviceaccount.yaml"}) | ||||
| 
 | ||||
| 	var serviceAccount corev1.ServiceAccount | ||||
| 	helm.UnmarshalK8SYaml(t, output, &serviceAccount) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, serviceAccount.Namespace) | ||||
| 	assert.Equal(t, "test-arc-actions-runner-controller-2", serviceAccount.Name) | ||||
| 	assert.Equal(t, "bar", string(serviceAccount.Annotations["foo"])) | ||||
| } | ||||
| 
 | ||||
| func TestTemplate_CreateServiceAccount_OverwriteName(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../actions-runner-controller-2") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-arc" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"serviceAccount.create":          "true", | ||||
| 			"serviceAccount.name":            "overwritten-name", | ||||
| 			"serviceAccount.annotations.foo": "bar", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/serviceaccount.yaml"}) | ||||
| 
 | ||||
| 	var serviceAccount corev1.ServiceAccount | ||||
| 	helm.UnmarshalK8SYaml(t, output, &serviceAccount) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, serviceAccount.Namespace) | ||||
| 	assert.Equal(t, "overwritten-name", serviceAccount.Name) | ||||
| 	assert.Equal(t, "bar", string(serviceAccount.Annotations["foo"])) | ||||
| } | ||||
| 
 | ||||
| func TestTemplate_CreateServiceAccount_CannotUseDefaultServiceAccount(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../actions-runner-controller-2") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-arc" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"serviceAccount.create":          "true", | ||||
| 			"serviceAccount.name":            "default", | ||||
| 			"serviceAccount.annotations.foo": "bar", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/serviceaccount.yaml"}) | ||||
| 	assert.ErrorContains(t, err, "serviceAccount.name cannot be set to 'default'", "We should get an error because the default service account cannot be used") | ||||
| } | ||||
| 
 | ||||
| func TestTemplate_NotCreateServiceAccount(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../actions-runner-controller-2") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-arc" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"serviceAccount.create":          "false", | ||||
| 			"serviceAccount.name":            "overwritten-name", | ||||
| 			"serviceAccount.annotations.foo": "bar", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/serviceaccount.yaml"}) | ||||
| 	assert.ErrorContains(t, err, "could not find template templates/serviceaccount.yaml in chart", "We should get an error because the template should be skipped") | ||||
| } | ||||
| 
 | ||||
| func TestTemplate_NotCreateServiceAccount_ServiceAccountNotSet(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../actions-runner-controller-2") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-arc" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"serviceAccount.create":          "false", | ||||
| 			"serviceAccount.annotations.foo": "bar", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/deployment.yaml"}) | ||||
| 	assert.ErrorContains(t, err, "serviceAccount.name must be set if serviceAccount.create is false", "We should get an error because the default service account cannot be used") | ||||
| } | ||||
| 
 | ||||
| func TestTemplate_CreateManagerRole(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../actions-runner-controller-2") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-arc" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues:      map[string]string{}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/manager_role.yaml"}) | ||||
| 
 | ||||
| 	var managerRole rbacv1.ClusterRole | ||||
| 	helm.UnmarshalK8SYaml(t, output, &managerRole) | ||||
| 
 | ||||
| 	assert.Empty(t, managerRole.Namespace, "ClusterRole should not have a namespace") | ||||
| 	assert.Equal(t, "test-arc-actions-runner-controller-2-manager-role", managerRole.Name) | ||||
| 	assert.Equal(t, 25, len(managerRole.Rules)) | ||||
| } | ||||
| 
 | ||||
| func TestTemplate_ManagerRoleBinding(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../actions-runner-controller-2") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-arc" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"serviceAccount.create": "true", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/manager_role_binding.yaml"}) | ||||
| 
 | ||||
| 	var managerRoleBinding rbacv1.ClusterRoleBinding | ||||
| 	helm.UnmarshalK8SYaml(t, output, &managerRoleBinding) | ||||
| 
 | ||||
| 	assert.Empty(t, managerRoleBinding.Namespace, "ClusterRoleBinding should not have a namespace") | ||||
| 	assert.Equal(t, "test-arc-actions-runner-controller-2-manager-rolebinding", managerRoleBinding.Name) | ||||
| 	assert.Equal(t, "test-arc-actions-runner-controller-2-manager-role", managerRoleBinding.RoleRef.Name) | ||||
| 	assert.Equal(t, "test-arc-actions-runner-controller-2", managerRoleBinding.Subjects[0].Name) | ||||
| 	assert.Equal(t, namespaceName, managerRoleBinding.Subjects[0].Namespace) | ||||
| } | ||||
| 
 | ||||
| func TestTemplate_ControllerDeployment_Defaults(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../actions-runner-controller-2") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-arc" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"image.tag": "dev", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/deployment.yaml"}) | ||||
| 
 | ||||
| 	var deployment appsv1.Deployment | ||||
| 	helm.UnmarshalK8SYaml(t, output, &deployment) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, deployment.Namespace) | ||||
| 	assert.Equal(t, "test-arc-actions-runner-controller-2", deployment.Name) | ||||
| 	assert.Equal(t, "actions-runner-controller-2-0.1.0", deployment.Labels["helm.sh/chart"]) | ||||
| 	assert.Equal(t, "actions-runner-controller-2", deployment.Labels["app.kubernetes.io/name"]) | ||||
| 	assert.Equal(t, "test-arc", deployment.Labels["app.kubernetes.io/instance"]) | ||||
| 	assert.Equal(t, "preview", deployment.Labels["app.kubernetes.io/version"]) | ||||
| 	assert.Equal(t, "Helm", deployment.Labels["app.kubernetes.io/managed-by"]) | ||||
| 
 | ||||
| 	assert.Equal(t, int32(1), *deployment.Spec.Replicas) | ||||
| 
 | ||||
| 	assert.Equal(t, "actions-runner-controller-2", deployment.Spec.Selector.MatchLabels["app.kubernetes.io/name"]) | ||||
| 	assert.Equal(t, "test-arc", deployment.Spec.Selector.MatchLabels["app.kubernetes.io/instance"]) | ||||
| 
 | ||||
| 	assert.Equal(t, "actions-runner-controller-2", deployment.Spec.Template.Labels["app.kubernetes.io/name"]) | ||||
| 	assert.Equal(t, "test-arc", deployment.Spec.Template.Labels["app.kubernetes.io/instance"]) | ||||
| 
 | ||||
| 	assert.Equal(t, "manager", deployment.Spec.Template.Annotations["kubectl.kubernetes.io/default-container"]) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.ImagePullSecrets, 0) | ||||
| 	assert.Equal(t, "test-arc-actions-runner-controller-2", deployment.Spec.Template.Spec.ServiceAccountName) | ||||
| 	assert.Nil(t, deployment.Spec.Template.Spec.SecurityContext) | ||||
| 	assert.Empty(t, deployment.Spec.Template.Spec.PriorityClassName) | ||||
| 	assert.Equal(t, int64(10), *deployment.Spec.Template.Spec.TerminationGracePeriodSeconds) | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Volumes, 1) | ||||
| 	assert.Equal(t, "tmp", deployment.Spec.Template.Spec.Volumes[0].Name) | ||||
| 	assert.NotNil(t, 10, deployment.Spec.Template.Spec.Volumes[0].EmptyDir) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.NodeSelector, 0) | ||||
| 	assert.Nil(t, deployment.Spec.Template.Spec.Affinity) | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Tolerations, 0) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers, 1) | ||||
| 	assert.Equal(t, "manager", deployment.Spec.Template.Spec.Containers[0].Name) | ||||
| 	assert.Equal(t, "ghcr.io/actions/actions-runner-controller-2:dev", deployment.Spec.Template.Spec.Containers[0].Image) | ||||
| 	assert.Equal(t, corev1.PullIfNotPresent, deployment.Spec.Template.Spec.Containers[0].ImagePullPolicy) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Command, 1) | ||||
| 	assert.Equal(t, "/manager", deployment.Spec.Template.Spec.Containers[0].Command[0]) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Args, 1) | ||||
| 	assert.Equal(t, "--auto-scaling-runner-set-only", deployment.Spec.Template.Spec.Containers[0].Args[0]) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 2) | ||||
| 	assert.Equal(t, "CONTROLLER_MANAGER_POD_NAME", deployment.Spec.Template.Spec.Containers[0].Env[0].Name) | ||||
| 	assert.Equal(t, "metadata.name", deployment.Spec.Template.Spec.Containers[0].Env[0].ValueFrom.FieldRef.FieldPath) | ||||
| 
 | ||||
| 	assert.Equal(t, "CONTROLLER_MANAGER_POD_NAMESPACE", deployment.Spec.Template.Spec.Containers[0].Env[1].Name) | ||||
| 	assert.Equal(t, "metadata.namespace", deployment.Spec.Template.Spec.Containers[0].Env[1].ValueFrom.FieldRef.FieldPath) | ||||
| 
 | ||||
| 	assert.Empty(t, deployment.Spec.Template.Spec.Containers[0].Resources) | ||||
| 	assert.Nil(t, deployment.Spec.Template.Spec.Containers[0].SecurityContext) | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers[0].VolumeMounts, 1) | ||||
| 	assert.Equal(t, "tmp", deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].Name) | ||||
| 	assert.Equal(t, "/tmp", deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].MountPath) | ||||
| } | ||||
| 
 | ||||
| func TestTemplate_ControllerDeployment_Customize(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../actions-runner-controller-2") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-arc" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"labels.foo":                   "bar", | ||||
| 			"labels.github":                "actions", | ||||
| 			"replicaCount":                 "1", | ||||
| 			"image.pullPolicy":             "Always", | ||||
| 			"image.tag":                    "dev", | ||||
| 			"imagePullSecrets[0].name":     "dockerhub", | ||||
| 			"nameOverride":                 "actions-runner-controller-2-override", | ||||
| 			"fullnameOverride":             "actions-runner-controller-2-fullname-override", | ||||
| 			"serviceAccount.name":          "actions-runner-controller-2-sa", | ||||
| 			"podAnnotations.foo":           "bar", | ||||
| 			"podSecurityContext.fsGroup":   "1000", | ||||
| 			"securityContext.runAsUser":    "1000", | ||||
| 			"securityContext.runAsNonRoot": "true", | ||||
| 			"resources.limits.cpu":         "500m", | ||||
| 			"nodeSelector.foo":             "bar", | ||||
| 			"tolerations[0].key":           "foo", | ||||
| 			"affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].key":      "foo", | ||||
| 			"affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].operator": "bar", | ||||
| 			"priorityClassName": "test-priority-class", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/deployment.yaml"}) | ||||
| 
 | ||||
| 	var deployment appsv1.Deployment | ||||
| 	helm.UnmarshalK8SYaml(t, output, &deployment) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, deployment.Namespace) | ||||
| 	assert.Equal(t, "actions-runner-controller-2-fullname-override", deployment.Name) | ||||
| 	assert.Equal(t, "actions-runner-controller-2-0.1.0", deployment.Labels["helm.sh/chart"]) | ||||
| 	assert.Equal(t, "actions-runner-controller-2-override", deployment.Labels["app.kubernetes.io/name"]) | ||||
| 	assert.Equal(t, "test-arc", deployment.Labels["app.kubernetes.io/instance"]) | ||||
| 	assert.Equal(t, "preview", deployment.Labels["app.kubernetes.io/version"]) | ||||
| 	assert.Equal(t, "Helm", deployment.Labels["app.kubernetes.io/managed-by"]) | ||||
| 	assert.Equal(t, "bar", deployment.Labels["foo"]) | ||||
| 	assert.Equal(t, "actions", deployment.Labels["github"]) | ||||
| 
 | ||||
| 	assert.Equal(t, int32(1), *deployment.Spec.Replicas) | ||||
| 
 | ||||
| 	assert.Equal(t, "actions-runner-controller-2-override", deployment.Spec.Selector.MatchLabels["app.kubernetes.io/name"]) | ||||
| 	assert.Equal(t, "test-arc", deployment.Spec.Selector.MatchLabels["app.kubernetes.io/instance"]) | ||||
| 
 | ||||
| 	assert.Equal(t, "actions-runner-controller-2-override", deployment.Spec.Template.Labels["app.kubernetes.io/name"]) | ||||
| 	assert.Equal(t, "test-arc", deployment.Spec.Template.Labels["app.kubernetes.io/instance"]) | ||||
| 
 | ||||
| 	assert.Equal(t, "bar", deployment.Spec.Template.Annotations["foo"]) | ||||
| 	assert.Equal(t, "manager", deployment.Spec.Template.Annotations["kubectl.kubernetes.io/default-container"]) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.ImagePullSecrets, 1) | ||||
| 	assert.Equal(t, "dockerhub", deployment.Spec.Template.Spec.ImagePullSecrets[0].Name) | ||||
| 	assert.Equal(t, "actions-runner-controller-2-sa", deployment.Spec.Template.Spec.ServiceAccountName) | ||||
| 	assert.Equal(t, int64(1000), *deployment.Spec.Template.Spec.SecurityContext.FSGroup) | ||||
| 	assert.Equal(t, "test-priority-class", deployment.Spec.Template.Spec.PriorityClassName) | ||||
| 	assert.Equal(t, int64(10), *deployment.Spec.Template.Spec.TerminationGracePeriodSeconds) | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Volumes, 1) | ||||
| 	assert.Equal(t, "tmp", deployment.Spec.Template.Spec.Volumes[0].Name) | ||||
| 	assert.NotNil(t, 10, deployment.Spec.Template.Spec.Volumes[0].EmptyDir) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.NodeSelector, 1) | ||||
| 	assert.Equal(t, "bar", deployment.Spec.Template.Spec.NodeSelector["foo"]) | ||||
| 
 | ||||
| 	assert.NotNil(t, deployment.Spec.Template.Spec.Affinity.NodeAffinity) | ||||
| 	assert.Equal(t, "foo", deployment.Spec.Template.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0].MatchExpressions[0].Key) | ||||
| 	assert.Equal(t, "bar", string(deployment.Spec.Template.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0].MatchExpressions[0].Operator)) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Tolerations, 1) | ||||
| 	assert.Equal(t, "foo", deployment.Spec.Template.Spec.Tolerations[0].Key) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers, 1) | ||||
| 	assert.Equal(t, "manager", deployment.Spec.Template.Spec.Containers[0].Name) | ||||
| 	assert.Equal(t, "ghcr.io/actions/actions-runner-controller-2:dev", deployment.Spec.Template.Spec.Containers[0].Image) | ||||
| 	assert.Equal(t, corev1.PullAlways, deployment.Spec.Template.Spec.Containers[0].ImagePullPolicy) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Command, 1) | ||||
| 	assert.Equal(t, "/manager", deployment.Spec.Template.Spec.Containers[0].Command[0]) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Args, 2) | ||||
| 	assert.Equal(t, "--auto-scaling-runner-set-only", deployment.Spec.Template.Spec.Containers[0].Args[0]) | ||||
| 	assert.Equal(t, "--auto-scaler-image-pull-secrets=dockerhub", deployment.Spec.Template.Spec.Containers[0].Args[1]) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 2) | ||||
| 	assert.Equal(t, "CONTROLLER_MANAGER_POD_NAME", deployment.Spec.Template.Spec.Containers[0].Env[0].Name) | ||||
| 	assert.Equal(t, "metadata.name", deployment.Spec.Template.Spec.Containers[0].Env[0].ValueFrom.FieldRef.FieldPath) | ||||
| 
 | ||||
| 	assert.Equal(t, "CONTROLLER_MANAGER_POD_NAMESPACE", deployment.Spec.Template.Spec.Containers[0].Env[1].Name) | ||||
| 	assert.Equal(t, "metadata.namespace", deployment.Spec.Template.Spec.Containers[0].Env[1].ValueFrom.FieldRef.FieldPath) | ||||
| 
 | ||||
| 	assert.Equal(t, "500m", deployment.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().String()) | ||||
| 	assert.True(t, *deployment.Spec.Template.Spec.Containers[0].SecurityContext.RunAsNonRoot) | ||||
| 	assert.Equal(t, int64(1000), *deployment.Spec.Template.Spec.Containers[0].SecurityContext.RunAsUser) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers[0].VolumeMounts, 1) | ||||
| 	assert.Equal(t, "tmp", deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].Name) | ||||
| 	assert.Equal(t, "/tmp", deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].MountPath) | ||||
| } | ||||
| 
 | ||||
| func TestTemplate_EnableLeaderElectionRole(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../actions-runner-controller-2") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-arc" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"replicaCount": "2", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/leader_election_role.yaml"}) | ||||
| 
 | ||||
| 	var leaderRole rbacv1.Role | ||||
| 	helm.UnmarshalK8SYaml(t, output, &leaderRole) | ||||
| 
 | ||||
| 	assert.Equal(t, "test-arc-actions-runner-controller-2-leader-election-role", leaderRole.Name) | ||||
| 	assert.Equal(t, namespaceName, leaderRole.Namespace) | ||||
| } | ||||
| 
 | ||||
| func TestTemplate_EnableLeaderElectionRoleBinding(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../actions-runner-controller-2") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-arc" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"replicaCount": "2", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/leader_election_role_binding.yaml"}) | ||||
| 
 | ||||
| 	var leaderRoleBinding rbacv1.RoleBinding | ||||
| 	helm.UnmarshalK8SYaml(t, output, &leaderRoleBinding) | ||||
| 
 | ||||
| 	assert.Equal(t, "test-arc-actions-runner-controller-2-leader-election-rolebinding", leaderRoleBinding.Name) | ||||
| 	assert.Equal(t, namespaceName, leaderRoleBinding.Namespace) | ||||
| 	assert.Equal(t, "test-arc-actions-runner-controller-2-leader-election-role", leaderRoleBinding.RoleRef.Name) | ||||
| 	assert.Equal(t, "test-arc-actions-runner-controller-2", leaderRoleBinding.Subjects[0].Name) | ||||
| } | ||||
| 
 | ||||
| func TestTemplate_EnableLeaderElection(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../actions-runner-controller-2") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-arc" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"replicaCount": "2", | ||||
| 			"image.tag":    "dev", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/deployment.yaml"}) | ||||
| 
 | ||||
| 	var deployment appsv1.Deployment | ||||
| 	helm.UnmarshalK8SYaml(t, output, &deployment) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, deployment.Namespace) | ||||
| 	assert.Equal(t, "test-arc-actions-runner-controller-2", deployment.Name) | ||||
| 
 | ||||
| 	assert.Equal(t, int32(2), *deployment.Spec.Replicas) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers, 1) | ||||
| 	assert.Equal(t, "manager", deployment.Spec.Template.Spec.Containers[0].Name) | ||||
| 	assert.Equal(t, "ghcr.io/actions/actions-runner-controller-2:dev", deployment.Spec.Template.Spec.Containers[0].Image) | ||||
| 	assert.Equal(t, corev1.PullIfNotPresent, deployment.Spec.Template.Spec.Containers[0].ImagePullPolicy) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Command, 1) | ||||
| 	assert.Equal(t, "/manager", deployment.Spec.Template.Spec.Containers[0].Command[0]) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Args, 3) | ||||
| 	assert.Equal(t, "--auto-scaling-runner-set-only", deployment.Spec.Template.Spec.Containers[0].Args[0]) | ||||
| 	assert.Equal(t, "--enable-leader-election", deployment.Spec.Template.Spec.Containers[0].Args[1]) | ||||
| 	assert.Equal(t, "--leader-election-id=test-arc-actions-runner-controller-2", deployment.Spec.Template.Spec.Containers[0].Args[2]) | ||||
| } | ||||
| 
 | ||||
| func TestTemplate_ControllerDeployment_ForwardImagePullSecrets(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../actions-runner-controller-2") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-arc" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"imagePullSecrets[0].name": "dockerhub", | ||||
| 			"imagePullSecrets[1].name": "ghcr", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/deployment.yaml"}) | ||||
| 
 | ||||
| 	var deployment appsv1.Deployment | ||||
| 	helm.UnmarshalK8SYaml(t, output, &deployment) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, deployment.Namespace) | ||||
| 
 | ||||
| 	assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Args, 2) | ||||
| 	assert.Equal(t, "--auto-scaling-runner-set-only", deployment.Spec.Template.Spec.Containers[0].Args[0]) | ||||
| 	assert.Equal(t, "--auto-scaler-image-pull-secrets=dockerhub,ghcr", deployment.Spec.Template.Spec.Containers[0].Args[1]) | ||||
| } | ||||
|  | @ -0,0 +1,65 @@ | |||
| # Default values for actions-runner-controller-2. | ||||
| # This is a YAML-formatted file. | ||||
| # Declare variables to be passed into your templates. | ||||
| labels: {} | ||||
| 
 | ||||
| # leaderElection will be enabled when replicaCount>1, | ||||
| # So, only one replica will in charge of reconciliation at a given time | ||||
| # leaderElectionId will be set to {{ define actions-runner-controller-2.fullname }}. | ||||
| replicaCount: 1 | ||||
| 
 | ||||
| image: | ||||
|   repository: "ghcr.io/actions/actions-runner-controller-2" | ||||
|   pullPolicy: IfNotPresent | ||||
|   # Overrides the image tag whose default is the chart appVersion. | ||||
|   tag: "" | ||||
| 
 | ||||
| imagePullSecrets: [] | ||||
| nameOverride: "" | ||||
| fullnameOverride: "" | ||||
| 
 | ||||
| serviceAccount: | ||||
|   # Specifies whether a service account should be created for running the controller pod | ||||
|   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 | ||||
|   # You can not use the default service account for this. | ||||
|   name: "" | ||||
| 
 | ||||
| podAnnotations: {} | ||||
| 
 | ||||
| podSecurityContext: {} | ||||
|   # fsGroup: 2000 | ||||
| 
 | ||||
| securityContext: {} | ||||
|   # capabilities: | ||||
|   #   drop: | ||||
|   #   - ALL | ||||
|   # readOnlyRootFilesystem: true | ||||
|   # runAsNonRoot: true | ||||
|   # runAsUser: 1000 | ||||
| 
 | ||||
| resources: {} | ||||
|   # We usually recommend not to specify default resources and to leave this as a conscious | ||||
|   # choice for the user. This also increases chances charts run on environments with little | ||||
|   # resources, such as Minikube. If you do want to specify resources, uncomment the following | ||||
|   # lines, adjust them as necessary, and remove the curly braces after 'resources:'. | ||||
|   # limits: | ||||
|   #   cpu: 100m | ||||
|   #   memory: 128Mi | ||||
|   # requests: | ||||
|   #   cpu: 100m | ||||
|   #   memory: 128Mi | ||||
| 
 | ||||
| nodeSelector: {} | ||||
| 
 | ||||
| tolerations: [] | ||||
| 
 | ||||
| affinity: {} | ||||
| 
 | ||||
| # Leverage a PriorityClass to ensure your pods survive resource shortages | ||||
| # ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ | ||||
| # PriorityClass: system-cluster-critical | ||||
| priorityClassName: "" | ||||
|  | @ -0,0 +1,23 @@ | |||
| # 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/ | ||||
|  | @ -0,0 +1,33 @@ | |||
| apiVersion: v2 | ||||
| name: auto-scaling-runner-set | ||||
| description: A Helm chart for deploying an AutoScalingRunnerSet | ||||
| 
 | ||||
| # 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.1.0 | ||||
| 
 | ||||
| # 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.1.0" | ||||
| 
 | ||||
| home: https://github.com/actions/dev-arc | ||||
| 
 | ||||
| sources: | ||||
|   - "https://github.com/actions/dev-arc" | ||||
| 
 | ||||
| maintainers: | ||||
|   - name: actions | ||||
|     url: https://github.com/actions | ||||
|  | @ -0,0 +1,6 @@ | |||
| # Set the following to dummy values. | ||||
| # This is only useful in CI | ||||
| githubConfigUrl: https://github.com/actions/actions-runner-controller | ||||
| 
 | ||||
| githubConfigSecret: | ||||
|   github_token: test | ||||
|  | @ -0,0 +1,3 @@ | |||
| Thank you for installing {{ .Chart.Name }}. | ||||
| 
 | ||||
| Your release is named {{ .Release.Name }}. | ||||
|  | @ -0,0 +1,313 @@ | |||
| {{/* | ||||
| Expand the name of the chart. | ||||
| */}} | ||||
| {{- define "auto-scaling-runner-set.name" -}} | ||||
| {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} | ||||
| {{- 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 "auto-scaling-runner-set.fullname" -}} | ||||
| {{- if .Values.fullnameOverride }} | ||||
| {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} | ||||
| {{- else }} | ||||
| {{- $name := default .Chart.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 }} | ||||
| 
 | ||||
| {{/* | ||||
| Create chart name and version as used by the chart label. | ||||
| */}} | ||||
| {{- define "auto-scaling-runner-set.chart" -}} | ||||
| {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{/* | ||||
| Common labels | ||||
| */}} | ||||
| {{- define "auto-scaling-runner-set.labels" -}} | ||||
| helm.sh/chart: {{ include "auto-scaling-runner-set.chart" . }} | ||||
| {{ include "auto-scaling-runner-set.selectorLabels" . }} | ||||
| {{- if .Chart.AppVersion }} | ||||
| app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} | ||||
| {{- end }} | ||||
| app.kubernetes.io/managed-by: {{ .Release.Service }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{/* | ||||
| Selector labels | ||||
| */}} | ||||
| {{- define "auto-scaling-runner-set.selectorLabels" -}} | ||||
| app.kubernetes.io/name: {{ include "auto-scaling-runner-set.name" . }} | ||||
| app.kubernetes.io/instance: {{ .Release.Name }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "auto-scaling-runner-set.githubsecret" -}} | ||||
| {{- include "auto-scaling-runner-set.fullname" . }}-github-secret | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "auto-scaling-runner-set.noPermissionServiceAccountName" -}} | ||||
| {{- include "auto-scaling-runner-set.fullname" . }}-no-permission-service-account | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "auto-scaling-runner-set.kubeModeRoleName" -}} | ||||
| {{- include "auto-scaling-runner-set.fullname" . }}-kube-mode-role | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "auto-scaling-runner-set.kubeModeServiceAccountName" -}} | ||||
| {{- include "auto-scaling-runner-set.fullname" . }}-kube-mode-service-account | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "auto-scaling-runner-set.dind-init-container" -}} | ||||
| {{- range $i, $val := .Values.template.spec.containers -}} | ||||
| {{- if eq $val.name "runner" -}} | ||||
| image: {{ $val.image }} | ||||
| {{- if $val.imagePullSecrets }} | ||||
| imagePullSecrets: | ||||
|   {{ $val.imagePullSecrets | toYaml -}} | ||||
| {{- end }} | ||||
| command: ["cp"] | ||||
| args: ["-r", "-v", "/actions-runner/externals/.", "/actions-runner/tmpDir/"] | ||||
| volumeMounts: | ||||
|   - name: dind-externals | ||||
|     mountPath: /actions-runner/tmpDir | ||||
| {{- end }} | ||||
| {{- end }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "auto-scaling-runner-set.dind-container" -}} | ||||
| image: docker:dind | ||||
| securityContext: | ||||
|   privileged: true | ||||
| volumeMounts: | ||||
|   - name: work | ||||
|     mountPath: /actions-runner/_work | ||||
|   - name: dind-cert | ||||
|     mountPath: /certs/client | ||||
|   - name: dind-externals | ||||
|     mountPath: /actions-runner/externals | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "auto-scaling-runner-set.dind-volume" -}} | ||||
| - name: dind-cert | ||||
|   emptyDir: {} | ||||
| - name: dind-externals | ||||
|   emptyDir: {} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "auto-scaling-runner-set.dind-work-volume" -}} | ||||
| {{- $createWorkVolume := 1 }} | ||||
|   {{- range $i, $volume := .Values.template.spec.volumes }} | ||||
|     {{- if eq $volume.name "work" }} | ||||
|       {{- $createWorkVolume = 0 -}} | ||||
| - name: work | ||||
|       {{- range $key, $val := $volume }} | ||||
|         {{- if ne $key "name" }} | ||||
|   {{ $key }}: {{ $val }} | ||||
|         {{- end }} | ||||
|       {{- end }} | ||||
|     {{- end }} | ||||
|   {{- end }} | ||||
|   {{- if eq $createWorkVolume 1 }} | ||||
| - name: work | ||||
|   emptyDir: {} | ||||
|   {{- end }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "auto-scaling-runner-set.kubernetes-mode-work-volume" -}} | ||||
| {{- $createWorkVolume := 1 }} | ||||
|   {{- range $i, $volume := .Values.template.spec.volumes }} | ||||
|     {{- if eq $volume.name "work" }} | ||||
|       {{- $createWorkVolume = 0 -}} | ||||
| - name: work | ||||
|       {{- range $key, $val := $volume }} | ||||
|         {{- if ne $key "name" }} | ||||
|   {{ $key }}: {{ $val }} | ||||
|         {{- end }} | ||||
|       {{- end }} | ||||
|     {{- end }} | ||||
|   {{- end }} | ||||
|   {{- if eq $createWorkVolume 1 }} | ||||
| - name: work | ||||
|   ephemeral: | ||||
|     volumeClaimTemplate: | ||||
|       spec: | ||||
|         {{- .Values.containerMode.kubernetesModeWorkVolumeClaim | toYaml | nindent 8 }} | ||||
|   {{- end }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "auto-scaling-runner-set.non-work-volumes" -}} | ||||
|   {{- range $i, $volume := .Values.template.spec.volumes }} | ||||
|     {{- if ne $volume.name "work" }} | ||||
| - name: {{ $volume.name }} | ||||
|       {{- range $key, $val := $volume }} | ||||
|         {{- if ne $key "name" }} | ||||
|   {{ $key }}: {{ $val }} | ||||
|         {{- end }} | ||||
|       {{- end }} | ||||
|     {{- end }} | ||||
|   {{- end }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "auto-scaling-runner-set.non-runner-containers" -}} | ||||
|   {{- range $i, $container := .Values.template.spec.containers -}} | ||||
|     {{- if ne $container.name "runner" -}} | ||||
| - name: {{ $container.name }} | ||||
|       {{- range $key, $val := $container }} | ||||
|         {{- if ne $key "name" }} | ||||
|   {{ $key }}: {{ $val }} | ||||
|         {{- end }} | ||||
|       {{- end }} | ||||
|     {{- end }} | ||||
|   {{- end }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "auto-scaling-runner-set.dind-runner-container" -}} | ||||
| {{- range $i, $container := .Values.template.spec.containers -}} | ||||
|   {{- if eq $container.name "runner" -}} | ||||
|     {{- range $key, $val := $container }} | ||||
|       {{- if and (ne $key "env") (ne $key "volumeMounts") (ne $key "name") }} | ||||
| {{ $key }}: {{ $val }} | ||||
|       {{- end }} | ||||
|     {{- end }} | ||||
|     {{- $setDockerHost := 1 }} | ||||
|     {{- $setDockerTlsVerify := 1 }} | ||||
|     {{- $setDockerCertPath := 1 }} | ||||
| env: | ||||
|     {{- with $container.env }} | ||||
|       {{- range $i, $env := . }} | ||||
|         {{- if eq $env.name "DOCKER_HOST" }} | ||||
|           {{- $setDockerHost = 0 -}} | ||||
|         {{- end }} | ||||
|         {{- if eq $env.name "DOCKER_TLS_VERIFY" }} | ||||
|           {{- $setDockerTlsVerify = 0 -}} | ||||
|         {{- end }} | ||||
|         {{- if eq $env.name "DOCKER_CERT_PATH" }} | ||||
|           {{- $setDockerCertPath = 0 -}} | ||||
|         {{- end }} | ||||
|   - name: {{ $env.name }} | ||||
|         {{- range $envKey, $envVal := $env }} | ||||
|           {{- if ne $envKey "name" }} | ||||
|     {{ $envKey }}: {{ $envVal | toYaml | nindent 8 }} | ||||
|           {{- end }} | ||||
|         {{- end }} | ||||
|       {{- end }} | ||||
|       {{- if $setDockerHost }} | ||||
|   - name: DOCKER_HOST | ||||
|     value: tcp://localhost:2376 | ||||
|       {{- end }} | ||||
|       {{- if $setDockerTlsVerify }} | ||||
|   - name: DOCKER_TLS_VERIFY | ||||
|     value: "1" | ||||
|       {{- end }} | ||||
|       {{- if $setDockerCertPath }} | ||||
|   - name: DOCKER_CERT_PATH | ||||
|     value: /certs/client | ||||
|       {{- end }} | ||||
|     {{- end }} | ||||
|     {{- $mountWork := 1 }} | ||||
|     {{- $mountDindCert := 1 }} | ||||
| volumeMounts: | ||||
|     {{- with $container.volumeMounts }} | ||||
|       {{- range $i, $volMount := . }} | ||||
|         {{- if eq $volMount.name "work" }} | ||||
|           {{- $mountWork = 0 -}} | ||||
|         {{- end }} | ||||
|         {{- if eq $volMount.name "dind-cert" }} | ||||
|           {{- $mountDindCert = 0 -}} | ||||
|         {{- end }} | ||||
|   - name: {{ $volMount.name }} | ||||
|         {{- range $mountKey, $mountVal := $volMount }} | ||||
|           {{- if ne $mountKey "name" }} | ||||
|     {{ $mountKey }}: {{ $mountVal | toYaml | nindent 8 }} | ||||
|           {{- end }} | ||||
|         {{- end }} | ||||
|       {{- end }} | ||||
|     {{- end }} | ||||
|     {{- if $mountWork }} | ||||
|   - name: work | ||||
|     mountPath: /actions-runner/_work | ||||
|     {{- end }} | ||||
|     {{- if $mountDindCert }} | ||||
|   - name: dind-cert | ||||
|     mountPath: /certs/client | ||||
|     {{- end }} | ||||
|   {{- end }} | ||||
| {{- end }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "auto-scaling-runner-set.kubernetes-mode-runner-container" -}} | ||||
| {{- range $i, $container := .Values.template.spec.containers -}} | ||||
|   {{- if eq $container.name "runner" -}} | ||||
|     {{- range $key, $val := $container }} | ||||
|       {{- if and (ne $key "env") (ne $key "volumeMounts") (ne $key "name") }} | ||||
| {{ $key }}: {{ $val }} | ||||
|       {{- end }} | ||||
|     {{- end }} | ||||
|     {{- $setContainerHooks := 1 }} | ||||
|     {{- $setPodName := 1 }} | ||||
|     {{- $setRequireJobContainer := 1 }} | ||||
| env: | ||||
|     {{- with $container.env }} | ||||
|       {{- range $i, $env := . }} | ||||
|         {{- if eq $env.name "ACTIONS_RUNNER_CONTAINER_HOOKS" }} | ||||
|           {{- $setContainerHooks = 0 -}} | ||||
|         {{- end }} | ||||
|         {{- if eq $env.name "ACTIONS_RUNNER_POD_NAME" }} | ||||
|           {{- $setPodName = 0 -}} | ||||
|         {{- end }} | ||||
|         {{- if eq $env.name "ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER" }} | ||||
|           {{- $setRequireJobContainer = 0 -}} | ||||
|         {{- end }} | ||||
|   - name: {{ $env.name }} | ||||
|         {{- range $envKey, $envVal := $env }} | ||||
|           {{- if ne $envKey "name" }} | ||||
|     {{ $envKey }}: {{ $envVal | toYaml | nindent 8 }} | ||||
|           {{- end }} | ||||
|         {{- end }} | ||||
|       {{- end }} | ||||
|     {{- end }} | ||||
|     {{- if $setContainerHooks }} | ||||
|   - name: ACTIONS_RUNNER_CONTAINER_HOOKS | ||||
|     value: /actions-runner/k8s/index.js | ||||
|     {{- end }} | ||||
|     {{- if $setPodName }} | ||||
|   - name: ACTIONS_RUNNER_POD_NAME | ||||
|     valueFrom: | ||||
|       fieldRef: | ||||
|         fieldPath: metadata.name | ||||
|     {{- end }} | ||||
|     {{- if $setRequireJobContainer }} | ||||
|   - name: ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER | ||||
|     value: "true" | ||||
|     {{- end }} | ||||
|     {{- $mountWork := 1 }} | ||||
| volumeMounts: | ||||
|     {{- with $container.volumeMounts }} | ||||
|       {{- range $i, $volMount := . }} | ||||
|         {{- if eq $volMount.name "work" }} | ||||
|           {{- $mountWork = 0 -}} | ||||
|         {{- end }} | ||||
|   - name: {{ $volMount.name }} | ||||
|         {{- range $mountKey, $mountVal := $volMount }} | ||||
|           {{- if ne $mountKey "name" }} | ||||
|     {{ $mountKey }}: {{ $mountVal | toYaml | nindent 8 }} | ||||
|           {{- end }} | ||||
|         {{- end }} | ||||
|       {{- end }} | ||||
|     {{- end }} | ||||
|     {{- if $mountWork }} | ||||
|   - name: work | ||||
|     mountPath: /actions-runner/_work | ||||
|     {{- end }} | ||||
|   {{- end }} | ||||
| {{- end }} | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,91 @@ | |||
| apiVersion: actions.github.com/v1alpha1 | ||||
| kind: AutoscalingRunnerSet | ||||
| metadata: | ||||
|   name: {{ .Release.Name }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
|   labels: | ||||
|     {{- include "auto-scaling-runner-set.labels" . | nindent 4 }} | ||||
| spec: | ||||
|   githubConfigUrl: {{ required ".Values.githubConfigUrl is required" .Values.githubConfigUrl }} | ||||
|   githubConfigSecret: {{ include "auto-scaling-runner-set.githubsecret" . }} | ||||
|   {{- with .Values.runnerGroup }} | ||||
|   runnerGroup: {{ . }} | ||||
|   {{- end }} | ||||
| 
 | ||||
|   {{- if and (kindIs "int64" .Values.minRunners) (kindIs "int64" .Values.maxRunners) }} | ||||
|     {{- if gt .Values.minRunners .Values.maxRunners }} | ||||
|       {{- fail "maxRunners has to be greater or equal to minRunners" }} | ||||
|     {{- end }} | ||||
|   {{- end }} | ||||
| 
 | ||||
|   {{- if kindIs "int64" .Values.maxRunners }} | ||||
|     {{- if lt .Values.maxRunners 0 }} | ||||
|       {{- fail "maxRunners has to be greater or equal to 0" }} | ||||
|     {{- end }} | ||||
|   maxRunners: {{ .Values.maxRunners | int }} | ||||
|   {{- end }} | ||||
| 
 | ||||
|   {{- if kindIs "int64" .Values.minRunners }} | ||||
|     {{- if lt .Values.minRunners 0 }} | ||||
|       {{- fail "minRunners has to be greater or equal to 0" }} | ||||
|     {{- end }} | ||||
|   minRunners: {{ .Values.minRunners | int }} | ||||
|   {{- end }} | ||||
| 
 | ||||
|   template: | ||||
|     {{- with .Values.template.metadata }} | ||||
|     metadata: | ||||
|       {{- with .labels }} | ||||
|       labels: | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|       {{- with .annotations }} | ||||
|       annotations: | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|     {{- end }} | ||||
|     spec: | ||||
|       {{- range $key, $val := .Values.template.spec }} | ||||
|         {{- if and (ne $key "containers") (ne $key "volumes") (ne $key "initContainers") (ne $key "serviceAccountName") }} | ||||
|       {{ $key }}: {{ $val | toYaml | nindent 8 }} | ||||
|         {{- end }} | ||||
|       {{- end }} | ||||
|       {{- if eq .Values.containerMode.type "kubernetes" }} | ||||
|       serviceAccountName: {{ default (include "auto-scaling-runner-set.kubeModeServiceAccountName" .) .Values.template.spec.serviceAccountName }} | ||||
|       {{- else }} | ||||
|       serviceAccountName: {{ default (include "auto-scaling-runner-set.noPermissionServiceAccountName" .) .Values.template.spec.serviceAccountName }} | ||||
|       {{- end }} | ||||
|       {{- if or .Values.template.spec.initContainers (eq .Values.containerMode.type "dind") }} | ||||
|       initContainers: | ||||
|         {{- if eq .Values.containerMode.type "dind" }} | ||||
|       - name: init-dind-externals | ||||
|         {{- include "auto-scaling-runner-set.dind-init-container" . | nindent 8 }} | ||||
|         {{- end }} | ||||
|         {{- with .Values.template.spec.initContainers }} | ||||
|       {{- toYaml . | nindent 8 }} | ||||
|         {{- end }} | ||||
|       {{- end }} | ||||
|       containers:  | ||||
|       {{- if eq .Values.containerMode.type "dind" }} | ||||
|       - name: runner | ||||
|         {{- include "auto-scaling-runner-set.dind-runner-container" . | nindent 8 }} | ||||
|       - name: dind | ||||
|         {{- include "auto-scaling-runner-set.dind-container" . | nindent 8 }} | ||||
|       {{- include "auto-scaling-runner-set.non-runner-containers" . | nindent 6 }} | ||||
|       {{- else if eq .Values.containerMode.type "kubernetes" }} | ||||
|       - name: runner | ||||
|         {{- include "auto-scaling-runner-set.kubernetes-mode-runner-container" . | nindent 8 }} | ||||
|       {{- include "auto-scaling-runner-set.non-runner-containers" . | nindent 6 }} | ||||
|       {{- else }} | ||||
|       {{ .Values.template.spec.containers | toYaml | nindent 6 }} | ||||
|       {{- end }} | ||||
|       {{- if or .Values.template.spec.volumes (eq .Values.containerMode.type "dind") (eq .Values.containerMode.type "kubernetes") }} | ||||
|       volumes:  | ||||
|         {{- if eq .Values.containerMode.type "dind" }} | ||||
|           {{- include "auto-scaling-runner-set.dind-volume" . | nindent 6 }} | ||||
|           {{- include "auto-scaling-runner-set.dind-work-volume" . | nindent 6 }} | ||||
|         {{- else if eq .Values.containerMode.type "kubernetes" }} | ||||
|           {{- include "auto-scaling-runner-set.kubernetes-mode-work-volume" . | nindent 6 }} | ||||
|         {{- end }} | ||||
|         {{- include "auto-scaling-runner-set.non-work-volumes" . | nindent 6 }} | ||||
|       {{- end }} | ||||
|  | @ -0,0 +1,37 @@ | |||
| apiVersion: v1 | ||||
| kind: Secret | ||||
| metadata: | ||||
|   name: {{ include "auto-scaling-runner-set.githubsecret" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
|   labels: | ||||
|     {{- include "auto-scaling-runner-set.labels" . | nindent 4 }} | ||||
|   finalizers: | ||||
|     - actions.github.com/secret-protection | ||||
| data: | ||||
|   {{- $hasToken := false }} | ||||
|   {{- $hasAppId := false }} | ||||
|   {{- $hasInstallationId := false }} | ||||
|   {{- $hasPrivateKey := false }} | ||||
|   {{- range $secretName, $secretValue := (required "Values.githubConfigSecret is required for setting auth with GitHub server." .Values.githubConfigSecret) }} | ||||
|     {{- if $secretValue }} | ||||
|   {{ $secretName }}: {{ $secretValue | toString | b64enc }} | ||||
|       {{- if eq $secretName "github_token" }} | ||||
|         {{- $hasToken = true }} | ||||
|       {{- end }} | ||||
|       {{- if eq $secretName "github_app_id" }} | ||||
|         {{- $hasAppId = true }} | ||||
|       {{- end }} | ||||
|       {{- if eq $secretName "github_app_installation_id" }} | ||||
|         {{- $hasInstallationId = true }} | ||||
|       {{- end }} | ||||
|       {{- if eq $secretName "github_app_private_key" }} | ||||
|         {{- $hasPrivateKey = true }} | ||||
|       {{- end }} | ||||
|     {{- end }} | ||||
|   {{- end }} | ||||
|   {{- if and (not $hasToken) (not ($hasAppId)) }} | ||||
|     {{- fail "A valid .Values.githubConfigSecret is required for setting auth with GitHub server, provide .Values.githubConfigSecret.github_token or .Values.githubConfigSecret.github_app_id." }} | ||||
|   {{- end }} | ||||
|   {{- if and $hasAppId (or (not $hasInstallationId) (not $hasPrivateKey)) }} | ||||
|     {{- fail "A valid .Values.githubConfigSecret is required for setting auth with GitHub server, provide .Values.githubConfigSecret.github_app_installation_id and .Values.githubConfigSecret.github_app_private_key." }} | ||||
|   {{- end }} | ||||
|  | @ -0,0 +1,24 @@ | |||
| {{- if and (eq .Values.containerMode.type "kubernetes") (not .Values.template.spec.serviceAccountName) }} | ||||
| # default permission for runner pod service account in kubernetes mode (container hook) | ||||
| apiVersion: rbac.authorization.k8s.io/v1 | ||||
| kind: Role | ||||
| metadata: | ||||
|   name: {{ include "auto-scaling-runner-set.kubeModeRoleName" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
| rules: | ||||
| - apiGroups: [""] | ||||
|   resources: ["pods"] | ||||
|   verbs: ["get", "list", "create", "delete"] | ||||
| - apiGroups: [""] | ||||
|   resources: ["pods/exec"] | ||||
|   verbs: ["get", "create"] | ||||
| - apiGroups: [""] | ||||
|   resources: ["pods/log"] | ||||
|   verbs: ["get", "list", "watch",] | ||||
| - apiGroups: ["batch"] | ||||
|   resources: ["jobs"] | ||||
|   verbs: ["get", "list", "create", "delete"] | ||||
| - apiGroups: [""] | ||||
|   resources: ["secrets"] | ||||
|   verbs: ["get", "list", "create", "delete"] | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,15 @@ | |||
| {{- if and (eq .Values.containerMode.type "kubernetes") (not .Values.template.spec.serviceAccountName) }} | ||||
| apiVersion: rbac.authorization.k8s.io/v1 | ||||
| kind: RoleBinding | ||||
| metadata: | ||||
|   name: {{ include "auto-scaling-runner-set.kubeModeRoleName" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
| roleRef: | ||||
|   apiGroup: rbac.authorization.k8s.io | ||||
|   kind: Role | ||||
|   name: {{ include "auto-scaling-runner-set.kubeModeRoleName" . }} | ||||
| subjects: | ||||
| - kind: ServiceAccount | ||||
|   name: {{ include "auto-scaling-runner-set.kubeModeServiceAccountName" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,9 @@ | |||
| {{- if and (eq .Values.containerMode.type "kubernetes") (not .Values.template.spec.serviceAccountName) }} | ||||
| apiVersion: v1 | ||||
| kind: ServiceAccount | ||||
| metadata: | ||||
|   name: {{ include "auto-scaling-runner-set.kubeModeServiceAccountName" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
|   labels: | ||||
|     {{- include "auto-scaling-runner-set.labels" . | nindent 4 }} | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,9 @@ | |||
| {{- if and (ne .Values.containerMode.type "kubernetes") (not .Values.template.spec.serviceAccountName) }} | ||||
| apiVersion: v1 | ||||
| kind: ServiceAccount | ||||
| metadata: | ||||
|   name: {{ include "auto-scaling-runner-set.noPermissionServiceAccountName" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
|   labels: | ||||
|     {{- include "auto-scaling-runner-set.labels" . | nindent 4 }} | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,606 @@ | |||
| package tests | ||||
| 
 | ||||
| import ( | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	v1alpha1 "github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1" | ||||
| 	"github.com/gruntwork-io/terratest/modules/helm" | ||||
| 	"github.com/gruntwork-io/terratest/modules/k8s" | ||||
| 	"github.com/gruntwork-io/terratest/modules/random" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	rbacv1 "k8s.io/api/rbac/v1" | ||||
| ) | ||||
| 
 | ||||
| func TestTemplateRenderedGitHubSecretWithGitHubToken(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                 "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token": "gh_token12345", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/githubsecret.yaml"}) | ||||
| 
 | ||||
| 	var githubSecret corev1.Secret | ||||
| 	helm.UnmarshalK8SYaml(t, output, &githubSecret) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, githubSecret.Namespace) | ||||
| 	assert.Equal(t, "test-runners-auto-scaling-runner-set-github-secret", githubSecret.Name) | ||||
| 	assert.Equal(t, "gh_token12345", string(githubSecret.Data["github_token"])) | ||||
| 	assert.Equal(t, "actions.github.com/secret-protection", githubSecret.Finalizers[0]) | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedGitHubSecretWithGitHubApp(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                               "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_app_id":              "10", | ||||
| 			"githubConfigSecret.github_app_installation_id": "100", | ||||
| 			"githubConfigSecret.github_app_private_key":     "private_key", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/githubsecret.yaml"}) | ||||
| 
 | ||||
| 	var githubSecret corev1.Secret | ||||
| 	helm.UnmarshalK8SYaml(t, output, &githubSecret) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, githubSecret.Namespace) | ||||
| 	assert.Equal(t, "10", string(githubSecret.Data["github_app_id"])) | ||||
| 	assert.Equal(t, "100", string(githubSecret.Data["github_app_installation_id"])) | ||||
| 	assert.Equal(t, "private_key", string(githubSecret.Data["github_app_private_key"])) | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedGitHubSecretErrorWithMissingAuthInput(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                  "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_app_id": "", | ||||
| 			"githubConfigSecret.github_token":  "", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/githubsecret.yaml"}) | ||||
| 	require.Error(t, err) | ||||
| 
 | ||||
| 	assert.ErrorContains(t, err, "provide .Values.githubConfigSecret.github_token or .Values.githubConfigSecret.github_app_id") | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedGitHubSecretErrorWithMissingAppInput(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                  "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_app_id": "10", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/githubsecret.yaml"}) | ||||
| 	require.Error(t, err) | ||||
| 
 | ||||
| 	assert.ErrorContains(t, err, "provide .Values.githubConfigSecret.github_app_installation_id and .Values.githubConfigSecret.github_app_private_key") | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedSetServiceAccountToNoPermission(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                 "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token": "gh_token12345", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/no_permission_serviceaccount.yaml"}) | ||||
| 	var serviceAccount corev1.ServiceAccount | ||||
| 	helm.UnmarshalK8SYaml(t, output, &serviceAccount) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, serviceAccount.Namespace) | ||||
| 	assert.Equal(t, "test-runners-auto-scaling-runner-set-no-permission-service-account", serviceAccount.Name) | ||||
| 
 | ||||
| 	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) | ||||
| 	var ars v1alpha1.AutoscalingRunnerSet | ||||
| 	helm.UnmarshalK8SYaml(t, output, &ars) | ||||
| 
 | ||||
| 	assert.Equal(t, "test-runners-auto-scaling-runner-set-no-permission-service-account", ars.Spec.Template.Spec.ServiceAccountName) | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedSetServiceAccountToKubeMode(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                 "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token": "gh_token12345", | ||||
| 			"containerMode.type":              "kubernetes", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_serviceaccount.yaml"}) | ||||
| 	var serviceAccount corev1.ServiceAccount | ||||
| 	helm.UnmarshalK8SYaml(t, output, &serviceAccount) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, serviceAccount.Namespace) | ||||
| 	assert.Equal(t, "test-runners-auto-scaling-runner-set-kube-mode-service-account", serviceAccount.Name) | ||||
| 
 | ||||
| 	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_role.yaml"}) | ||||
| 	var role rbacv1.Role | ||||
| 	helm.UnmarshalK8SYaml(t, output, &role) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, role.Namespace) | ||||
| 	assert.Equal(t, "test-runners-auto-scaling-runner-set-kube-mode-role", role.Name) | ||||
| 	assert.Len(t, role.Rules, 5, "kube mode role should have 5 rules") | ||||
| 	assert.Equal(t, "pods", role.Rules[0].Resources[0]) | ||||
| 	assert.Equal(t, "pods/exec", role.Rules[1].Resources[0]) | ||||
| 	assert.Equal(t, "pods/log", role.Rules[2].Resources[0]) | ||||
| 	assert.Equal(t, "jobs", role.Rules[3].Resources[0]) | ||||
| 	assert.Equal(t, "secrets", role.Rules[4].Resources[0]) | ||||
| 
 | ||||
| 	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_role_binding.yaml"}) | ||||
| 	var roleBinding rbacv1.RoleBinding | ||||
| 	helm.UnmarshalK8SYaml(t, output, &roleBinding) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, roleBinding.Namespace) | ||||
| 	assert.Equal(t, "test-runners-auto-scaling-runner-set-kube-mode-role", roleBinding.Name) | ||||
| 	assert.Len(t, roleBinding.Subjects, 1) | ||||
| 	assert.Equal(t, "test-runners-auto-scaling-runner-set-kube-mode-service-account", roleBinding.Subjects[0].Name) | ||||
| 	assert.Equal(t, namespaceName, roleBinding.Subjects[0].Namespace) | ||||
| 	assert.Equal(t, "test-runners-auto-scaling-runner-set-kube-mode-role", roleBinding.RoleRef.Name) | ||||
| 	assert.Equal(t, "Role", roleBinding.RoleRef.Kind) | ||||
| 
 | ||||
| 	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) | ||||
| 	var ars v1alpha1.AutoscalingRunnerSet | ||||
| 	helm.UnmarshalK8SYaml(t, output, &ars) | ||||
| 
 | ||||
| 	assert.Equal(t, "test-runners-auto-scaling-runner-set-kube-mode-service-account", ars.Spec.Template.Spec.ServiceAccountName) | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedUserProvideSetServiceAccount(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                  "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token":  "gh_token12345", | ||||
| 			"template.spec.serviceAccountName": "test-service-account", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/no_permission_serviceaccount.yaml"}) | ||||
| 	assert.ErrorContains(t, err, "could not find template templates/no_permission_serviceaccount.yaml in chart", "no permission service account should not be rendered") | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) | ||||
| 	var ars v1alpha1.AutoscalingRunnerSet | ||||
| 	helm.UnmarshalK8SYaml(t, output, &ars) | ||||
| 
 | ||||
| 	assert.Equal(t, "test-service-account", ars.Spec.Template.Spec.ServiceAccountName) | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedAutoScalingRunnerSet(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                 "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token": "gh_token12345", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) | ||||
| 
 | ||||
| 	var ars v1alpha1.AutoscalingRunnerSet | ||||
| 	helm.UnmarshalK8SYaml(t, output, &ars) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, ars.Namespace) | ||||
| 	assert.Equal(t, "test-runners", ars.Name) | ||||
| 
 | ||||
| 	assert.Equal(t, "auto-scaling-runner-set", ars.Labels["app.kubernetes.io/name"]) | ||||
| 	assert.Equal(t, "test-runners", ars.Labels["app.kubernetes.io/instance"]) | ||||
| 	assert.Equal(t, "https://github.com/actions", ars.Spec.GitHubConfigUrl) | ||||
| 	assert.Equal(t, "test-runners-auto-scaling-runner-set-github-secret", ars.Spec.GitHubConfigSecret) | ||||
| 
 | ||||
| 	assert.Empty(t, ars.Spec.RunnerGroup, "RunnerGroup should be empty") | ||||
| 
 | ||||
| 	assert.Nil(t, ars.Spec.MinRunners, "MinRunners should be nil") | ||||
| 	assert.Nil(t, ars.Spec.MaxRunners, "MaxRunners should be nil") | ||||
| 	assert.Nil(t, ars.Spec.Proxy, "Proxy should be nil") | ||||
| 	assert.Nil(t, ars.Spec.GitHubServerTLS, "GitHubServerTLS should be nil") | ||||
| 
 | ||||
| 	assert.NotNil(t, ars.Spec.Template.Spec, "Template.Spec should not be nil") | ||||
| 
 | ||||
| 	assert.Len(t, ars.Spec.Template.Spec.Containers, 1, "Template.Spec should have 1 container") | ||||
| 	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name) | ||||
| 	assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.Containers[0].Image) | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedAutoScalingRunnerSet_ProvideMetadata(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                     "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token":     "gh_token12345", | ||||
| 			"template.metadata.labels.test1":      "test1", | ||||
| 			"template.metadata.labels.test2":      "test2", | ||||
| 			"template.metadata.annotations.test3": "test3", | ||||
| 			"template.metadata.annotations.test4": "test4", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) | ||||
| 
 | ||||
| 	var ars v1alpha1.AutoscalingRunnerSet | ||||
| 	helm.UnmarshalK8SYaml(t, output, &ars) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, ars.Namespace) | ||||
| 	assert.Equal(t, "test-runners", ars.Name) | ||||
| 
 | ||||
| 	assert.NotNil(t, ars.Spec.Template.Labels, "Template.Spec.Labels should not be nil") | ||||
| 	assert.Equal(t, "test1", ars.Spec.Template.Labels["test1"], "Template.Spec.Labels should have test1") | ||||
| 	assert.Equal(t, "test2", ars.Spec.Template.Labels["test2"], "Template.Spec.Labels should have test2") | ||||
| 
 | ||||
| 	assert.NotNil(t, ars.Spec.Template.Annotations, "Template.Spec.Annotations should not be nil") | ||||
| 	assert.Equal(t, "test3", ars.Spec.Template.Annotations["test3"], "Template.Spec.Annotations should have test3") | ||||
| 	assert.Equal(t, "test4", ars.Spec.Template.Annotations["test4"], "Template.Spec.Annotations should have test4") | ||||
| 
 | ||||
| 	assert.NotNil(t, ars.Spec.Template.Spec, "Template.Spec should not be nil") | ||||
| 
 | ||||
| 	assert.Len(t, ars.Spec.Template.Spec.Containers, 1, "Template.Spec should have 1 container") | ||||
| 	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name) | ||||
| 	assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.Containers[0].Image) | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedAutoScalingRunnerSet_MaxRunnersValidationError(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                 "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token": "gh_token12345", | ||||
| 			"maxRunners":                      "-1", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) | ||||
| 	require.Error(t, err) | ||||
| 
 | ||||
| 	assert.ErrorContains(t, err, "maxRunners has to be greater or equal to 0") | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedAutoScalingRunnerSet_MinRunnersValidationError(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                 "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token": "gh_token12345", | ||||
| 			"maxRunners":                      "1", | ||||
| 			"minRunners":                      "-1", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) | ||||
| 	require.Error(t, err) | ||||
| 
 | ||||
| 	assert.ErrorContains(t, err, "minRunners has to be greater or equal to 0") | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedAutoScalingRunnerSet_MinMaxRunnersValidationError(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                 "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token": "gh_token12345", | ||||
| 			"maxRunners":                      "0", | ||||
| 			"minRunners":                      "1", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) | ||||
| 	require.Error(t, err) | ||||
| 
 | ||||
| 	assert.ErrorContains(t, err, "maxRunners has to be greater or equal to minRunners") | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedAutoScalingRunnerSet_MinMaxRunnersValidationSameValue(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                 "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token": "gh_token12345", | ||||
| 			"maxRunners":                      "0", | ||||
| 			"minRunners":                      "0", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) | ||||
| 
 | ||||
| 	var ars v1alpha1.AutoscalingRunnerSet | ||||
| 	helm.UnmarshalK8SYaml(t, output, &ars) | ||||
| 
 | ||||
| 	assert.Equal(t, 0, *ars.Spec.MinRunners, "MinRunners should be 0") | ||||
| 	assert.Equal(t, 0, *ars.Spec.MaxRunners, "MaxRunners should be 0") | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedAutoScalingRunnerSet_MinMaxRunnersValidation_OnlyMin(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                 "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token": "gh_token12345", | ||||
| 			"minRunners":                      "5", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) | ||||
| 
 | ||||
| 	var ars v1alpha1.AutoscalingRunnerSet | ||||
| 	helm.UnmarshalK8SYaml(t, output, &ars) | ||||
| 
 | ||||
| 	assert.Equal(t, 5, *ars.Spec.MinRunners, "MinRunners should be 5") | ||||
| 	assert.Nil(t, ars.Spec.MaxRunners, "MaxRunners should be nil") | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedAutoScalingRunnerSet_MinMaxRunnersValidation_OnlyMax(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                 "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token": "gh_token12345", | ||||
| 			"maxRunners":                      "5", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) | ||||
| 
 | ||||
| 	var ars v1alpha1.AutoscalingRunnerSet | ||||
| 	helm.UnmarshalK8SYaml(t, output, &ars) | ||||
| 
 | ||||
| 	assert.Equal(t, 5, *ars.Spec.MaxRunners, "MaxRunners should be 5") | ||||
| 	assert.Nil(t, ars.Spec.MinRunners, "MinRunners should be nil") | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedAutoScalingRunnerSet_EnableDinD(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                 "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token": "gh_token12345", | ||||
| 			"containerMode.type":              "dind", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) | ||||
| 
 | ||||
| 	var ars v1alpha1.AutoscalingRunnerSet | ||||
| 	helm.UnmarshalK8SYaml(t, output, &ars) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, ars.Namespace) | ||||
| 	assert.Equal(t, "test-runners", ars.Name) | ||||
| 
 | ||||
| 	assert.Equal(t, "auto-scaling-runner-set", ars.Labels["app.kubernetes.io/name"]) | ||||
| 	assert.Equal(t, "test-runners", ars.Labels["app.kubernetes.io/instance"]) | ||||
| 	assert.Equal(t, "https://github.com/actions", ars.Spec.GitHubConfigUrl) | ||||
| 	assert.Equal(t, "test-runners-auto-scaling-runner-set-github-secret", ars.Spec.GitHubConfigSecret) | ||||
| 
 | ||||
| 	assert.Empty(t, ars.Spec.RunnerGroup, "RunnerGroup should be empty") | ||||
| 
 | ||||
| 	assert.Nil(t, ars.Spec.MinRunners, "MinRunners should be nil") | ||||
| 	assert.Nil(t, ars.Spec.MaxRunners, "MaxRunners should be nil") | ||||
| 	assert.Nil(t, ars.Spec.Proxy, "Proxy should be nil") | ||||
| 	assert.Nil(t, ars.Spec.GitHubServerTLS, "GitHubServerTLS should be nil") | ||||
| 
 | ||||
| 	assert.NotNil(t, ars.Spec.Template.Spec, "Template.Spec should not be nil") | ||||
| 
 | ||||
| 	assert.Len(t, ars.Spec.Template.Spec.InitContainers, 1, "Template.Spec should have 1 init container") | ||||
| 	assert.Equal(t, "init-dind-externals", ars.Spec.Template.Spec.InitContainers[0].Name) | ||||
| 	assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.InitContainers[0].Image) | ||||
| 	assert.Equal(t, "cp", ars.Spec.Template.Spec.InitContainers[0].Command[0]) | ||||
| 	assert.Equal(t, "-r -v /actions-runner/externals/. /actions-runner/tmpDir/", strings.Join(ars.Spec.Template.Spec.InitContainers[0].Args, " ")) | ||||
| 
 | ||||
| 	assert.Len(t, ars.Spec.Template.Spec.Containers, 2, "Template.Spec should have 2 container") | ||||
| 	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name) | ||||
| 	assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.Containers[0].Image) | ||||
| 
 | ||||
| 	assert.Equal(t, "dind", ars.Spec.Template.Spec.Containers[1].Name) | ||||
| 	assert.Equal(t, "docker:dind", ars.Spec.Template.Spec.Containers[1].Image) | ||||
| } | ||||
| 
 | ||||
| func TestTemplateRenderedAutoScalingRunnerSet_EnableKubernetesMode(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	// Path to the helm chart we will test
 | ||||
| 	helmChartPath, err := filepath.Abs("../../auto-scaling-runner-set") | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	releaseName := "test-runners" | ||||
| 	namespaceName := "test-" + strings.ToLower(random.UniqueId()) | ||||
| 
 | ||||
| 	options := &helm.Options{ | ||||
| 		SetValues: map[string]string{ | ||||
| 			"githubConfigUrl":                 "https://github.com/actions", | ||||
| 			"githubConfigSecret.github_token": "gh_token12345", | ||||
| 			"containerMode.type":              "kubernetes", | ||||
| 		}, | ||||
| 		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), | ||||
| 	} | ||||
| 
 | ||||
| 	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) | ||||
| 
 | ||||
| 	var ars v1alpha1.AutoscalingRunnerSet | ||||
| 	helm.UnmarshalK8SYaml(t, output, &ars) | ||||
| 
 | ||||
| 	assert.Equal(t, namespaceName, ars.Namespace) | ||||
| 	assert.Equal(t, "test-runners", ars.Name) | ||||
| 
 | ||||
| 	assert.Equal(t, "auto-scaling-runner-set", ars.Labels["app.kubernetes.io/name"]) | ||||
| 	assert.Equal(t, "test-runners", ars.Labels["app.kubernetes.io/instance"]) | ||||
| 	assert.Equal(t, "https://github.com/actions", ars.Spec.GitHubConfigUrl) | ||||
| 	assert.Equal(t, "test-runners-auto-scaling-runner-set-github-secret", ars.Spec.GitHubConfigSecret) | ||||
| 
 | ||||
| 	assert.Empty(t, ars.Spec.RunnerGroup, "RunnerGroup should be empty") | ||||
| 	assert.Nil(t, ars.Spec.MinRunners, "MinRunners should be nil") | ||||
| 	assert.Nil(t, ars.Spec.MaxRunners, "MaxRunners should be nil") | ||||
| 	assert.Nil(t, ars.Spec.Proxy, "Proxy should be nil") | ||||
| 	assert.Nil(t, ars.Spec.GitHubServerTLS, "GitHubServerTLS should be nil") | ||||
| 
 | ||||
| 	assert.NotNil(t, ars.Spec.Template.Spec, "Template.Spec should not be nil") | ||||
| 
 | ||||
| 	assert.Len(t, ars.Spec.Template.Spec.Containers, 1, "Template.Spec should have 1 container") | ||||
| 	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name) | ||||
| 	assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.Containers[0].Image) | ||||
| 
 | ||||
| 	assert.Equal(t, "ACTIONS_RUNNER_CONTAINER_HOOKS", ars.Spec.Template.Spec.Containers[0].Env[0].Name) | ||||
| 	assert.Equal(t, "/actions-runner/k8s/index.js", ars.Spec.Template.Spec.Containers[0].Env[0].Value) | ||||
| 	assert.Equal(t, "ACTIONS_RUNNER_POD_NAME", ars.Spec.Template.Spec.Containers[0].Env[1].Name) | ||||
| 	assert.Equal(t, "ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER", ars.Spec.Template.Spec.Containers[0].Env[2].Name) | ||||
| 	assert.Equal(t, "true", ars.Spec.Template.Spec.Containers[0].Env[2].Value) | ||||
| 
 | ||||
| 	assert.Len(t, ars.Spec.Template.Spec.Volumes, 1, "Template.Spec should have 1 volume") | ||||
| 	assert.Equal(t, "work", ars.Spec.Template.Spec.Volumes[0].Name) | ||||
| 	assert.NotNil(t, ars.Spec.Template.Spec.Volumes[0].Ephemeral, "Template.Spec should have 1 ephemeral volume") | ||||
| } | ||||
|  | @ -0,0 +1,117 @@ | |||
| ## githubConfigUrl is the GitHub url for where you want to configure runners | ||||
| ## ex: https://github.com/myorg/myrepo or https://github.com/myorg | ||||
| githubConfigUrl: "" | ||||
| 
 | ||||
| ## githubConfigSecret is the k8s secrets to use when auth with GitHub API. | ||||
| ## You can choose to use GitHub App or a PAT token | ||||
| githubConfigSecret:  | ||||
|   ### GitHub Apps Configuration | ||||
|   ## NOTE: IDs MUST be strings, use quotes | ||||
|   #github_app_id: "" | ||||
|   #github_app_installation_id: "" | ||||
|   #github_app_private_key: | | ||||
| 
 | ||||
|   ### GitHub PAT Configuration | ||||
|   github_token: "" | ||||
| 
 | ||||
| ## maxRunners is the max number of runners the auto scaling runner set will scale up to. | ||||
| # maxRunners: 5 | ||||
| 
 | ||||
| ## minRunners is the min number of runners the auto scaling runner set will scale down to. | ||||
| # minRunners: 0 | ||||
| 
 | ||||
| # runnerGroup: "default" | ||||
| 
 | ||||
| ## template is the PodSpec for each runner Pod | ||||
| template: | ||||
|   spec: | ||||
|     containers: | ||||
|     - name: runner | ||||
|       image: ghcr.io/actions/actions-runner:latest | ||||
|       command: ["/actions-runner/run.sh"] | ||||
| 
 | ||||
| containerMode: | ||||
|   type: ""  ## type can be set to dind or kubernetes | ||||
|   ## with containerMode.type=dind, we will populate the template.spec with following pod spec | ||||
|   ## template: | ||||
|   ##   spec: | ||||
|   ##     initContainers: | ||||
|   ##     - name: initExternalsInternalVolume | ||||
|   ##       image: ghcr.io/actions/actions-runner:latest | ||||
|   ##       command: ["cp", "-r", "-v", "/actions-runner/externals/.", "/actions-runner/tmpDir/"] | ||||
|   ##       volumeMounts: | ||||
|   ##         - name: externalsInternal | ||||
|   ##           mountPath: /actions-runner/tmpDir | ||||
|   ##     containers: | ||||
|   ##     - name: runner | ||||
|   ##       image: ghcr.io/actions/actions-runner:latest | ||||
|   ##       env: | ||||
|   ##         - name: DOCKER_HOST | ||||
|   ##           value: tcp://localhost:2376 | ||||
|   ##         - name: DOCKER_TLS_VERIFY | ||||
|   ##           value: "1" | ||||
|   ##         - name: DOCKER_CERT_PATH | ||||
|   ##           value: /certs/client | ||||
|   ##       volumeMounts: | ||||
|   ##         - name: workingDirectoryInternal | ||||
|   ##           mountPath: /actions-runner/_work | ||||
|   ##         - name: dinDInternal | ||||
|   ##           mountPath: /certs/client | ||||
|   ##           readOnly: true | ||||
|   ##     - name: dind | ||||
|   ##       image: docker:dind | ||||
|   ##       securityContext: | ||||
|   ##         privileged: true | ||||
|   ##       volumeMounts: | ||||
|   ##         - mountPath: /certs/client | ||||
|   ##           name: dinDInternal | ||||
|   ##         - mountPath: /actions-runner/_work | ||||
|   ##           name: workingDirectoryInternal | ||||
|   ##         - mountPath: /actions-runner/externals | ||||
|   ##           name: externalsInternal | ||||
|   ##     volumes: | ||||
|   ##     - name: dinDInternal | ||||
|   ##       emptyDir: {} | ||||
|   ##     - name: workingDirectoryInternal | ||||
|   ##       emptyDir: {} | ||||
|   ##     - name: externalsInternal | ||||
|   ##       emptyDir: {} | ||||
|   ###################################################################################################### | ||||
|   ## with containerMode.type=kubernetes, we will populate the template.spec with following pod spec | ||||
|   ## template: | ||||
|   ##   spec: | ||||
|   ##     containers: | ||||
|   ##     - name: runner | ||||
|   ##       image: ghcr.io/actions/actions-runner:latest | ||||
|   ##       env: | ||||
|   ##         - name: ACTIONS_RUNNER_CONTAINER_HOOKS | ||||
|   ##           value: /actions-runner/k8s/index.js | ||||
|   ##         - name: ACTIONS_RUNNER_POD_NAME | ||||
|   ##           valueFrom: | ||||
|   ##             fieldRef: | ||||
|   ##               fieldPath: metadata.name | ||||
|   ##         - name: ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER | ||||
|   ##           value: "true" | ||||
|   ##       volumeMounts: | ||||
|   ##         - name: work | ||||
|   ##           mountPath: /actions-runner/_work | ||||
|   ##     volumes: | ||||
|   ##       - name: work | ||||
|   ##         ephemeral: | ||||
|   ##           volumeClaimTemplate: | ||||
|   ##             spec: | ||||
|   ##               accessModes: [ "ReadWriteOnce" ] | ||||
|   ##               storageClassName: "local-path" | ||||
|   ##               resources: | ||||
|   ##                 requests: | ||||
|   ##                   storage: 1Gi | ||||
| 
 | ||||
|   ## the following is required when containerMode.type=kubernetes | ||||
|   kubernetesModeWorkVolumeClaim: | ||||
|     accessModes: ["ReadWriteOnce"] | ||||
|     # For testing, use https://github.com/rancher/local-path-provisioner to provide dynamic provision volume | ||||
|     # TODO: remove before release | ||||
|     storageClassName: "dynamic-blob-storage" | ||||
|     resources: | ||||
|       requests: | ||||
|         storage: 1Gi | ||||
		Loading…
	
		Reference in New Issue