From a804bf8b00ddf9fbeaa34a1060fffe9f81f9c6fa Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Tue, 4 Apr 2023 19:07:20 +0200 Subject: [PATCH] Add ImagePullPolicy to the AutoscalingListener, configurable through Manager env (#2477) --- .../v1alpha1/autoscalinglistener_types.go | 3 ++ ...tions.github.com_autoscalinglisteners.yaml | 3 ++ .../templates/deployment.yaml | 2 + .../tests/template_test.go | 45 +++++++++++-------- ...tions.github.com_autoscalinglisteners.yaml | 3 ++ config/manager/manager.yaml | 2 + .../actions.github.com/resourcebuilder.go | 18 +++++++- main.go | 7 +++ 8 files changed, 64 insertions(+), 19 deletions(-) diff --git a/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go b/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go index 82458657..c5fedd7b 100644 --- a/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go +++ b/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go @@ -52,6 +52,9 @@ type AutoscalingListenerSpec struct { // Required Image string `json:"image,omitempty"` + // Required + ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` + // Required ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` diff --git a/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalinglisteners.yaml b/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalinglisteners.yaml index 6df9c051..d75ef5fe 100644 --- a/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalinglisteners.yaml +++ b/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalinglisteners.yaml @@ -80,6 +80,9 @@ spec: image: description: Required type: string + imagePullPolicy: + description: Required + type: string imagePullSecrets: description: Required items: diff --git a/charts/gha-runner-scale-set-controller/templates/deployment.yaml b/charts/gha-runner-scale-set-controller/templates/deployment.yaml index b624d963..1997d2b0 100644 --- a/charts/gha-runner-scale-set-controller/templates/deployment.yaml +++ b/charts/gha-runner-scale-set-controller/templates/deployment.yaml @@ -68,6 +68,8 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace + - name: CONTROLLER_MANAGER_LISTENER_IMAGE_PULL_POLICY + value: "{{ .Values.image.pullPolicy | default "IfNotPresent" }}" {{- with .Values.env }} {{- if kindIs "slice" . }} {{- toYaml . | nindent 8 }} diff --git a/charts/gha-runner-scale-set-controller/tests/template_test.go b/charts/gha-runner-scale-set-controller/tests/template_test.go index 3ee12f7d..469cdecf 100644 --- a/charts/gha-runner-scale-set-controller/tests/template_test.go +++ b/charts/gha-runner-scale-set-controller/tests/template_test.go @@ -349,13 +349,16 @@ func TestTemplate_ControllerDeployment_Defaults(t *testing.T) { assert.Equal(t, "--auto-scaling-runner-set-only", deployment.Spec.Template.Spec.Containers[0].Args[0]) assert.Equal(t, "--log-level=debug", deployment.Spec.Template.Spec.Containers[0].Args[1]) - assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 2) + assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 3) assert.Equal(t, "CONTROLLER_MANAGER_CONTAINER_IMAGE", deployment.Spec.Template.Spec.Containers[0].Env[0].Name) assert.Equal(t, managerImage, deployment.Spec.Template.Spec.Containers[0].Env[0].Value) 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, "CONTROLLER_MANAGER_LISTENER_IMAGE_PULL_POLICY", deployment.Spec.Template.Spec.Containers[0].Env[2].Name) + assert.Equal(t, "IfNotPresent", deployment.Spec.Template.Spec.Containers[0].Env[2].Value) // default value. Needs to align with controllers/actions.github.com/resourcebuilder.go + 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) @@ -434,8 +437,8 @@ func TestTemplate_ControllerDeployment_Customize(t *testing.T) { assert.Equal(t, "bar", deployment.Spec.Template.Annotations["foo"]) assert.Equal(t, "manager", deployment.Spec.Template.Annotations["kubectl.kubernetes.io/default-container"]) - assert.Equal(t, "ENV_VAR_NAME_1", deployment.Spec.Template.Spec.Containers[0].Env[2].Name) - assert.Equal(t, "ENV_VAR_VALUE_1", deployment.Spec.Template.Spec.Containers[0].Env[2].Value) + assert.Equal(t, "ENV_VAR_NAME_1", deployment.Spec.Template.Spec.Containers[0].Env[3].Name) + assert.Equal(t, "ENV_VAR_VALUE_1", deployment.Spec.Template.Spec.Containers[0].Env[3].Value) assert.Len(t, deployment.Spec.Template.Spec.ImagePullSecrets, 1) assert.Equal(t, "dockerhub", deployment.Spec.Template.Spec.ImagePullSecrets[0].Name) @@ -472,12 +475,15 @@ func TestTemplate_ControllerDeployment_Customize(t *testing.T) { assert.Equal(t, "--auto-scaler-image-pull-secrets=dockerhub", deployment.Spec.Template.Spec.Containers[0].Args[1]) assert.Equal(t, "--log-level=debug", deployment.Spec.Template.Spec.Containers[0].Args[2]) - assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 3) + assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 4) assert.Equal(t, "CONTROLLER_MANAGER_CONTAINER_IMAGE", deployment.Spec.Template.Spec.Containers[0].Env[0].Name) assert.Equal(t, managerImage, deployment.Spec.Template.Spec.Containers[0].Env[0].Value) - assert.Equal(t, "ENV_VAR_NAME_1", deployment.Spec.Template.Spec.Containers[0].Env[2].Name) - assert.Equal(t, "ENV_VAR_VALUE_1", deployment.Spec.Template.Spec.Containers[0].Env[2].Value) + assert.Equal(t, "CONTROLLER_MANAGER_LISTENER_IMAGE_PULL_POLICY", deployment.Spec.Template.Spec.Containers[0].Env[2].Name) + assert.Equal(t, "Always", deployment.Spec.Template.Spec.Containers[0].Env[2].Value) // default value. Needs to align with controllers/actions.github.com/resourcebuilder.go + + assert.Equal(t, "ENV_VAR_NAME_1", deployment.Spec.Template.Spec.Containers[0].Env[3].Name) + assert.Equal(t, "ENV_VAR_VALUE_1", deployment.Spec.Template.Spec.Containers[0].Env[3].Value) 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) @@ -698,13 +704,16 @@ func TestTemplate_ControllerDeployment_WatchSingleNamespace(t *testing.T) { assert.Equal(t, "--log-level=debug", deployment.Spec.Template.Spec.Containers[0].Args[1]) assert.Equal(t, "--watch-single-namespace=demo", deployment.Spec.Template.Spec.Containers[0].Args[2]) - assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 2) + assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 3) assert.Equal(t, "CONTROLLER_MANAGER_CONTAINER_IMAGE", deployment.Spec.Template.Spec.Containers[0].Env[0].Name) assert.Equal(t, managerImage, deployment.Spec.Template.Spec.Containers[0].Env[0].Value) 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, "CONTROLLER_MANAGER_LISTENER_IMAGE_PULL_POLICY", deployment.Spec.Template.Spec.Containers[0].Env[2].Name) + assert.Equal(t, "IfNotPresent", deployment.Spec.Template.Spec.Containers[0].Env[2].Value) // default value. Needs to align with controllers/actions.github.com/resourcebuilder.go + 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) @@ -745,17 +754,17 @@ func TestTemplate_ControllerContainerEnvironmentVariables(t *testing.T) { assert.Equal(t, namespaceName, deployment.Namespace) assert.Equal(t, "test-arc-gha-runner-scale-set-controller", deployment.Name) - assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 6) - assert.Equal(t, "ENV_VAR_NAME_1", deployment.Spec.Template.Spec.Containers[0].Env[2].Name) - assert.Equal(t, "ENV_VAR_VALUE_1", deployment.Spec.Template.Spec.Containers[0].Env[2].Value) - assert.Equal(t, "ENV_VAR_NAME_2", deployment.Spec.Template.Spec.Containers[0].Env[3].Name) - assert.Equal(t, "secret-name", deployment.Spec.Template.Spec.Containers[0].Env[3].ValueFrom.SecretKeyRef.Name) - assert.Equal(t, "ENV_VAR_NAME_2", deployment.Spec.Template.Spec.Containers[0].Env[3].ValueFrom.SecretKeyRef.Key) - assert.True(t, *deployment.Spec.Template.Spec.Containers[0].Env[3].ValueFrom.SecretKeyRef.Optional) - assert.Equal(t, "ENV_VAR_NAME_3", deployment.Spec.Template.Spec.Containers[0].Env[4].Name) - assert.Empty(t, deployment.Spec.Template.Spec.Containers[0].Env[4].Value) - assert.Equal(t, "ENV_VAR_NAME_4", deployment.Spec.Template.Spec.Containers[0].Env[5].Name) - assert.Empty(t, deployment.Spec.Template.Spec.Containers[0].Env[5].ValueFrom) + assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 7) + assert.Equal(t, "ENV_VAR_NAME_1", deployment.Spec.Template.Spec.Containers[0].Env[3].Name) + assert.Equal(t, "ENV_VAR_VALUE_1", deployment.Spec.Template.Spec.Containers[0].Env[3].Value) + assert.Equal(t, "ENV_VAR_NAME_2", deployment.Spec.Template.Spec.Containers[0].Env[4].Name) + assert.Equal(t, "secret-name", deployment.Spec.Template.Spec.Containers[0].Env[4].ValueFrom.SecretKeyRef.Name) + assert.Equal(t, "ENV_VAR_NAME_2", deployment.Spec.Template.Spec.Containers[0].Env[4].ValueFrom.SecretKeyRef.Key) + assert.True(t, *deployment.Spec.Template.Spec.Containers[0].Env[4].ValueFrom.SecretKeyRef.Optional) + assert.Equal(t, "ENV_VAR_NAME_3", deployment.Spec.Template.Spec.Containers[0].Env[5].Name) + assert.Empty(t, deployment.Spec.Template.Spec.Containers[0].Env[5].Value) + assert.Equal(t, "ENV_VAR_NAME_4", deployment.Spec.Template.Spec.Containers[0].Env[6].Name) + assert.Empty(t, deployment.Spec.Template.Spec.Containers[0].Env[6].ValueFrom) } func TestTemplate_WatchSingleNamespace_NotCreateManagerClusterRole(t *testing.T) { diff --git a/config/crd/bases/actions.github.com_autoscalinglisteners.yaml b/config/crd/bases/actions.github.com_autoscalinglisteners.yaml index 6df9c051..d75ef5fe 100644 --- a/config/crd/bases/actions.github.com_autoscalinglisteners.yaml +++ b/config/crd/bases/actions.github.com_autoscalinglisteners.yaml @@ -80,6 +80,9 @@ spec: image: description: Required type: string + imagePullPolicy: + description: Required + type: string imagePullSecrets: description: Required items: diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index f90df347..fb63c83a 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -56,6 +56,8 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace + - name: CONTROLLER_MANAGER_LISTENER_IMAGE_PULL_POLICY + value: IfNotPresent volumeMounts: - name: controller-manager mountPath: "/etc/actions-runner-controller" diff --git a/controllers/actions.github.com/resourcebuilder.go b/controllers/actions.github.com/resourcebuilder.go index 0ea81461..2ddba11b 100644 --- a/controllers/actions.github.com/resourcebuilder.go +++ b/controllers/actions.github.com/resourcebuilder.go @@ -67,6 +67,21 @@ var commonLabelKeys = [...]string{ const labelValueKubernetesPartOf = "gha-runner-scale-set" +const DefaultScaleSetListenerImagePullPolicy = corev1.PullIfNotPresent + +// scaleSetListenerImagePullPolicy is applied to all listeners +var scaleSetListenerImagePullPolicy = DefaultScaleSetListenerImagePullPolicy + +func SetListenerImagePullPolicy(pullPolicy string) bool { + switch p := corev1.PullPolicy(pullPolicy); p { + case corev1.PullAlways, corev1.PullNever, corev1.PullIfNotPresent: + scaleSetListenerImagePullPolicy = p + return true + default: + return false + } +} + type resourceBuilder struct{} func (b *resourceBuilder) newScaleSetListenerPod(autoscalingListener *v1alpha1.AutoscalingListener, serviceAccount *corev1.ServiceAccount, secret *corev1.Secret, envs ...corev1.EnvVar) *corev1.Pod { @@ -161,7 +176,7 @@ func (b *resourceBuilder) newScaleSetListenerPod(autoscalingListener *v1alpha1.A Name: autoscalingListenerContainerName, Image: autoscalingListener.Spec.Image, Env: listenerEnv, - ImagePullPolicy: corev1.PullIfNotPresent, + ImagePullPolicy: autoscalingListener.Spec.ImagePullPolicy, Command: []string{ "/github-runnerscaleset-listener", }, @@ -375,6 +390,7 @@ func (b *resourceBuilder) newAutoScalingListener(autoscalingRunnerSet *v1alpha1. MinRunners: effectiveMinRunners, MaxRunners: effectiveMaxRunners, Image: image, + ImagePullPolicy: scaleSetListenerImagePullPolicy, ImagePullSecrets: imagePullSecrets, Proxy: autoscalingRunnerSet.Spec.Proxy, GitHubServerTLS: autoscalingRunnerSet.Spec.GitHubServerTLS, diff --git a/main.go b/main.go index ac9a79c5..aee03225 100644 --- a/main.go +++ b/main.go @@ -170,6 +170,13 @@ func main() { } } + listenerPullPolicy := os.Getenv("CONTROLLER_MANAGER_LISTENER_IMAGE_PULL_POLICY") + if ok := actionsgithubcom.SetListenerImagePullPolicy(listenerPullPolicy); ok { + log.Info("AutoscalingListener image pull policy changed", "ImagePullPolicy", listenerPullPolicy) + } else { + log.Info("Using default AutoscalingListener image pull policy", "ImagePullPolicy", actionsgithubcom.DefaultScaleSetListenerImagePullPolicy) + } + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ Scheme: scheme, NewCache: newCache,