From 7b5a02b0b6a02ce4d7a8d817171574cca4759dbd Mon Sep 17 00:00:00 2001 From: Rob Herley Date: Mon, 13 Jan 2025 12:20:02 -0500 Subject: [PATCH 01/14] Update dependabot config to group packages (& include actions eco) (#3880) --- .github/dependabot.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e0871f93..bf19191e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,3 +9,15 @@ updates: directory: "/" # Location of package manifests schedule: interval: "weekly" + groups: + gomod: + patterns: + - "*" + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: "weekly" + groups: + actions: + patterns: + - "*" From 66172ab0bd5d7237766146ad7778088a71a969ba Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Wed, 15 Jan 2025 15:54:33 +0100 Subject: [PATCH 02/14] Fix template tests and add go test on gha-validate-chart (#3886) --- .github/workflows/gha-validate-chart.yaml | 14 ++++++++++++++ .../tests/template_test.go | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/.github/workflows/gha-validate-chart.yaml b/.github/workflows/gha-validate-chart.yaml index 91304702..70a67de2 100644 --- a/.github/workflows/gha-validate-chart.yaml +++ b/.github/workflows/gha-validate-chart.yaml @@ -123,3 +123,17 @@ jobs: if: steps.list-changed.outputs.changed == 'true' run: | ct install --config charts/.ci/ct-config-gha.yaml + test-chart: + name: Test Chart + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + cache: false + - name: Test gha-runner-scale-set + run: go test ./charts/gha-runner-scale-set/... + - name: Test gha-runner-scale-set-controller + run: go test ./charts/gha-runner-scale-set-controller/... 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 afee95a2..c1efe293 100644 --- a/charts/gha-runner-scale-set-controller/tests/template_test.go +++ b/charts/gha-runner-scale-set-controller/tests/template_test.go @@ -366,6 +366,7 @@ func TestTemplate_ControllerDeployment_Defaults(t *testing.T) { "--metrics-addr=0", "--listener-metrics-addr=0", "--listener-metrics-endpoint=", + "--runner-max-concurrent-reconciles=2", } assert.ElementsMatch(t, expectedArgs, deployment.Spec.Template.Spec.Containers[0].Args) @@ -518,6 +519,7 @@ func TestTemplate_ControllerDeployment_Customize(t *testing.T) { "--listener-metrics-addr=0", "--listener-metrics-endpoint=", "--metrics-addr=0", + "--runner-max-concurrent-reconciles=2", } assert.ElementsMatch(t, expectArgs, deployment.Spec.Template.Spec.Containers[0].Args) @@ -646,6 +648,7 @@ func TestTemplate_EnableLeaderElection(t *testing.T) { "--listener-metrics-addr=0", "--listener-metrics-endpoint=", "--metrics-addr=0", + "--runner-max-concurrent-reconciles=2", } assert.ElementsMatch(t, expectedArgs, deployment.Spec.Template.Spec.Containers[0].Args) @@ -686,6 +689,7 @@ func TestTemplate_ControllerDeployment_ForwardImagePullSecrets(t *testing.T) { "--listener-metrics-addr=0", "--listener-metrics-endpoint=", "--metrics-addr=0", + "--runner-max-concurrent-reconciles=2", } assert.ElementsMatch(t, expectedArgs, deployment.Spec.Template.Spec.Containers[0].Args) @@ -776,6 +780,7 @@ func TestTemplate_ControllerDeployment_WatchSingleNamespace(t *testing.T) { "--listener-metrics-addr=0", "--listener-metrics-endpoint=", "--metrics-addr=0", + "--runner-max-concurrent-reconciles=2", } assert.ElementsMatch(t, expectedArgs, deployment.Spec.Template.Spec.Containers[0].Args) From f673a085b00d5736b207400a18ba429180ea666d Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Fri, 17 Jan 2025 12:25:33 +0100 Subject: [PATCH 03/14] cmd/ghalistener/config: export Validate (#3870) Co-authored-by: Han-Wen Nienhuys --- cmd/ghalistener/config/config.go | 5 +++-- cmd/ghalistener/config/config_test.go | 12 ++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cmd/ghalistener/config/config.go b/cmd/ghalistener/config/config.go index d27d6af9..d734db16 100644 --- a/cmd/ghalistener/config/config.go +++ b/cmd/ghalistener/config/config.go @@ -46,14 +46,15 @@ func Read(path string) (Config, error) { return Config{}, fmt.Errorf("failed to decode config: %w", err) } - if err := config.validate(); err != nil { + if err := config.Validate(); err != nil { return Config{}, fmt.Errorf("failed to validate config: %w", err) } return config, nil } -func (c *Config) validate() error { +// Validate checks the configuration for errors. +func (c *Config) Validate() error { if len(c.ConfigureUrl) == 0 { return fmt.Errorf("GitHubConfigUrl is not provided") } diff --git a/cmd/ghalistener/config/config_test.go b/cmd/ghalistener/config/config_test.go index 99e6ac99..fba4f17c 100644 --- a/cmd/ghalistener/config/config_test.go +++ b/cmd/ghalistener/config/config_test.go @@ -17,7 +17,7 @@ func TestConfigValidationMinMax(t *testing.T) { MaxRunners: 2, Token: "token", } - err := config.validate() + err := config.Validate() assert.ErrorContains(t, err, "MinRunners '5' cannot be greater than MaxRunners '2", "Expected error about MinRunners > MaxRunners") } @@ -28,7 +28,7 @@ func TestConfigValidationMissingToken(t *testing.T) { EphemeralRunnerSetName: "deployment", RunnerScaleSetId: 1, } - err := config.validate() + err := config.Validate() expectedError := fmt.Sprintf("GitHub auth credential is missing, token length: '%d', appId: '%d', installationId: '%d', private key length: '%d", len(config.Token), config.AppID, config.AppInstallationID, len(config.AppPrivateKey)) assert.ErrorContains(t, err, expectedError, "Expected error about missing auth") } @@ -42,7 +42,7 @@ func TestConfigValidationAppKey(t *testing.T) { EphemeralRunnerSetName: "deployment", RunnerScaleSetId: 1, } - err := config.validate() + err := config.Validate() expectedError := fmt.Sprintf("GitHub auth credential is missing, token length: '%d', appId: '%d', installationId: '%d', private key length: '%d", len(config.Token), config.AppID, config.AppInstallationID, len(config.AppPrivateKey)) assert.ErrorContains(t, err, expectedError, "Expected error about missing auth") } @@ -58,7 +58,7 @@ func TestConfigValidationOnlyOneTypeOfCredentials(t *testing.T) { EphemeralRunnerSetName: "deployment", RunnerScaleSetId: 1, } - err := config.validate() + err := config.Validate() expectedError := fmt.Sprintf("only one GitHub auth method supported at a time. Have both PAT and App auth: token length: '%d', appId: '%d', installationId: '%d', private key length: '%d", len(config.Token), config.AppID, config.AppInstallationID, len(config.AppPrivateKey)) assert.ErrorContains(t, err, expectedError, "Expected error about missing auth") } @@ -74,7 +74,7 @@ func TestConfigValidation(t *testing.T) { Token: "asdf", } - err := config.validate() + err := config.Validate() assert.NoError(t, err, "Expected no error") } @@ -86,7 +86,7 @@ func TestConfigValidationConfigUrl(t *testing.T) { RunnerScaleSetId: 1, } - err := config.validate() + err := config.Validate() assert.ErrorContains(t, err, "GitHubConfigUrl is not provided", "Expected error about missing ConfigureUrl") } From 4584cc65a9d6c58c4bd4441640cb50d01f4d06ba Mon Sep 17 00:00:00 2001 From: Matteo Bianchi <37507190+mbianchidev@users.noreply.github.com> Date: Fri, 17 Jan 2025 12:39:15 +0100 Subject: [PATCH 04/14] Updated dead link (#3830) Co-authored-by: Nikola Jokic --- docs/about-arc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/about-arc.md b/docs/about-arc.md index 6955006d..30a29bf1 100644 --- a/docs/about-arc.md +++ b/docs/about-arc.md @@ -157,7 +157,7 @@ kubectl set env deploy controller-manager -c manager GITHUB_ENTERPRISE_URL= -The GitHub hosted runners include a large amount of pre-installed software packages. GitHub maintains a list in README files at . +The GitHub hosted runners include a large amount of pre-installed software packages. GitHub maintains a list in README files at . This solution maintains a few Ubuntu based runner images, these images do not contain all of the software installed on the GitHub runners. The images contain the following subset of packages from the GitHub runners: From f6b4d874319026515a586bdcb2fca488fc5fa67e Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 17 Jan 2025 06:44:12 -0500 Subject: [PATCH 05/14] docs: end markdown code block correctly (#3736) --- docs/automatically-scaling-runners.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/automatically-scaling-runners.md b/docs/automatically-scaling-runners.md index 7df9cbf3..a0129edf 100644 --- a/docs/automatically-scaling-runners.md +++ b/docs/automatically-scaling-runners.md @@ -430,6 +430,7 @@ resources: - github.com/actions/actions-runner-controller/config//default?ref=v0.22.2 # Add the below! - github.com/actions/actions-runner-controller/config//github-webhook-server?ref=v0.22.2 +``` Finally, you will have to configure an ingress so that you may configure the webhook in github. An example of such ingress can be find below: From 790191e9871ab4cab5983c9943cb7cb057ea2ac5 Mon Sep 17 00:00:00 2001 From: John Wesley Walker III <81404201+jww3@users.noreply.github.com> Date: Tue, 21 Jan 2025 13:29:41 +0100 Subject: [PATCH 06/14] Clarify syntax for `githubConfigSecret` (#3812) Co-authored-by: Bassem Dghaidi <568794+Link-@users.noreply.github.com> --- charts/gha-runner-scale-set/values.yaml | 43 +++++++++++++++++-------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/charts/gha-runner-scale-set/values.yaml b/charts/gha-runner-scale-set/values.yaml index 6018b7d0..db3256b2 100644 --- a/charts/gha-runner-scale-set/values.yaml +++ b/charts/gha-runner-scale-set/values.yaml @@ -2,25 +2,40 @@ ## 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 is the k8s secret information to use when authenticating via the GitHub API. +## You can choose to supply: +## A) a PAT token, +## B) a GitHub App, or +## C) a pre-defined Kubernetes secret. +## The syntax for each of these variations is documented below. +## (Variation A) When using a PAT token, the syntax is as follows: 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: "" -## If you have a pre-define Kubernetes secret in the same namespace the gha-runner-scale-set is going to deploy, -## you can also reference it via `githubConfigSecret: pre-defined-secret`. -## You need to make sure your predefined secret has all the required secret data set properly. + # Example: + # github_token: "ghp_sampleSampleSampleSampleSampleSample" + github_token: "" +# +## (Variation B) When using a GitHub App, the syntax is as follows: +# githubConfigSecret: +# # NOTE: IDs MUST be strings, use quotes +# github_app_id: "" +# github_app_installation_id: "" +# github_app_private_key: | +# private key line 1 +# private key line 2 +# . +# . +# . +# private key line N +# +## (Variation C) When using a pre-defined Kubernetes secret in the same namespace that the gha-runner-scale-set is going to deploy, +## the syntax is as follows: +# githubConfigSecret: pre-defined-secret +## Notes on using pre-defined Kubernetes secrets: +## You need to make sure your predefined secret has all the required secret data set properly. ## For a pre-defined secret using GitHub PAT, the secret needs to be created like this: ## > kubectl create secret generic pre-defined-secret --namespace=my_namespace --from-literal=github_token='ghp_your_pat' ## For a pre-defined secret using GitHub App, the secret needs to be created like this: ## > kubectl create secret generic pre-defined-secret --namespace=my_namespace --from-literal=github_app_id=123456 --from-literal=github_app_installation_id=654321 --from-literal=github_app_private_key='-----BEGIN CERTIFICATE-----*******' -# githubConfigSecret: pre-defined-secret ## proxy can be used to define proxy settings that will be used by the ## controller, the listener and the runner of this scale set. From 4dd68f1a89f5cb564cbe0382dcf732922d88435c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 14:04:55 +0100 Subject: [PATCH 07/14] Bump golang.org/x/net from 0.25.0 to 0.33.0 (#3881) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Nikola Jokic --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 87c52afb..914cd425 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/teambition/rrule-go v1.8.2 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 - golang.org/x/net v0.25.0 + golang.org/x/net v0.33.0 golang.org/x/oauth2 v0.19.0 golang.org/x/sync v0.10.0 gomodules.xyz/jsonpatch/v2 v2.4.0 diff --git a/go.sum b/go.sum index 9f3a18b9..31e4f761 100644 --- a/go.sum +++ b/go.sum @@ -259,8 +259,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 68787beab5396085227c16e0b2cd472c0520d435 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 09:39:40 -0500 Subject: [PATCH 08/14] Updates: runner to v2.322.0 (#3893) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- Makefile | 2 +- runner/Makefile | 2 +- runner/VERSION | 2 +- test/e2e/e2e_test.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index df448bd1..bb87e607 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ endif DOCKER_USER ?= $(shell echo ${DOCKER_IMAGE_NAME} | cut -d / -f1) VERSION ?= dev COMMIT_SHA = $(shell git rev-parse HEAD) -RUNNER_VERSION ?= 2.321.0 +RUNNER_VERSION ?= 2.322.0 TARGETPLATFORM ?= $(shell arch) RUNNER_NAME ?= ${DOCKER_USER}/actions-runner RUNNER_TAG ?= ${VERSION} diff --git a/runner/Makefile b/runner/Makefile index 6d151982..3c943441 100644 --- a/runner/Makefile +++ b/runner/Makefile @@ -6,7 +6,7 @@ DIND_ROOTLESS_RUNNER_NAME ?= ${DOCKER_USER}/actions-runner-dind-rootless OS_IMAGE ?= ubuntu-22.04 TARGETPLATFORM ?= $(shell arch) -RUNNER_VERSION ?= 2.321.0 +RUNNER_VERSION ?= 2.322.0 RUNNER_CONTAINER_HOOKS_VERSION ?= 0.6.2 DOCKER_VERSION ?= 24.0.7 diff --git a/runner/VERSION b/runner/VERSION index 0845a9f6..f4a8d2ef 100644 --- a/runner/VERSION +++ b/runner/VERSION @@ -1,2 +1,2 @@ -RUNNER_VERSION=2.321.0 +RUNNER_VERSION=2.322.0 RUNNER_CONTAINER_HOOKS_VERSION=0.6.2 \ No newline at end of file diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index b02fd899..3795d363 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -36,7 +36,7 @@ var ( testResultCMNamePrefix = "test-result-" - RunnerVersion = "2.321.0" + RunnerVersion = "2.322.0" RunnerContainerHooksVersion = "0.6.2" ) From 7ccc177b84a20e10af55845c405defc4c06ee4bc Mon Sep 17 00:00:00 2001 From: &es <84567633+and-es@users.noreply.github.com> Date: Tue, 18 Feb 2025 23:15:39 +0900 Subject: [PATCH 09/14] Sanitize labels ending in hyphen, underscore, and dot (#3664) --- controllers/actions.github.com/resourcebuilder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/actions.github.com/resourcebuilder.go b/controllers/actions.github.com/resourcebuilder.go index 57fd7257..152eea6d 100644 --- a/controllers/actions.github.com/resourcebuilder.go +++ b/controllers/actions.github.com/resourcebuilder.go @@ -747,7 +747,7 @@ func trimLabelValue(val string) string { if len(val) > 63 { return val[:63-len(trimLabelVauleSuffix)] + trimLabelVauleSuffix } - return val + return strings.Trim(val, "-_.") } func (b *ResourceBuilder) mergeLabels(base, overwrite map[string]string) map[string]string { From ddc872d3ee2ca2ca131eb2a86e14592ed6a1d332 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Wed, 26 Feb 2025 09:34:17 -0500 Subject: [PATCH 10/14] metrics cardinality for ghalistener (#3671) Co-authored-by: Bassem Dghaidi <568794+Link-@users.noreply.github.com> Co-authored-by: Nikola Jokic --- cmd/ghalistener/metrics/metrics.go | 28 +++------ pkg/actionsmetrics/metrics.go | 96 +++++++++++++++--------------- 2 files changed, 56 insertions(+), 68 deletions(-) diff --git a/cmd/ghalistener/metrics/metrics.go b/cmd/ghalistener/metrics/metrics.go index 2940dd2f..14717589 100644 --- a/cmd/ghalistener/metrics/metrics.go +++ b/cmd/ghalistener/metrics/metrics.go @@ -3,7 +3,6 @@ package metrics import ( "context" "net/http" - "strconv" "time" "github.com/actions/actions-runner-controller/github/actions" @@ -19,11 +18,8 @@ const ( labelKeyOrganization = "organization" labelKeyRepository = "repository" labelKeyJobName = "job_name" - labelKeyJobWorkflowRef = "job_workflow_ref" labelKeyEventName = "event_name" labelKeyJobResult = "job_result" - labelKeyRunnerID = "runner_id" - labelKeyRunnerName = "runner_name" ) const githubScaleSetSubsystem = "gha" @@ -43,14 +39,13 @@ var ( labelKeyOrganization, labelKeyEnterprise, labelKeyJobName, - labelKeyJobWorkflowRef, labelKeyEventName, } - completedJobsTotalLabels = append(jobLabels, labelKeyJobResult, labelKeyRunnerID, labelKeyRunnerName) - jobExecutionDurationLabels = append(jobLabels, labelKeyJobResult, labelKeyRunnerID, labelKeyRunnerName) - startedJobsTotalLabels = append(jobLabels, labelKeyRunnerID, labelKeyRunnerName) - jobStartupDurationLabels = append(jobLabels, labelKeyRunnerID, labelKeyRunnerName) + completedJobsTotalLabels = append(jobLabels, labelKeyJobResult) + jobExecutionDurationLabels = append(jobLabels, labelKeyJobResult) + startedJobsTotalLabels = jobLabels + jobStartupDurationLabels = jobLabels ) var ( @@ -223,12 +218,11 @@ type baseLabels struct { func (b *baseLabels) jobLabels(jobBase *actions.JobMessageBase) prometheus.Labels { return prometheus.Labels{ - labelKeyEnterprise: b.enterprise, - labelKeyOrganization: jobBase.OwnerName, - labelKeyRepository: jobBase.RepositoryName, - labelKeyJobName: jobBase.JobDisplayName, - labelKeyJobWorkflowRef: jobBase.JobWorkflowRef, - labelKeyEventName: jobBase.EventName, + labelKeyEnterprise: b.enterprise, + labelKeyOrganization: jobBase.OwnerName, + labelKeyRepository: jobBase.RepositoryName, + labelKeyJobName: jobBase.JobDisplayName, + labelKeyEventName: jobBase.EventName, } } @@ -244,16 +238,12 @@ func (b *baseLabels) scaleSetLabels() prometheus.Labels { func (b *baseLabels) completedJobLabels(msg *actions.JobCompleted) prometheus.Labels { l := b.jobLabels(&msg.JobMessageBase) - l[labelKeyRunnerID] = strconv.Itoa(msg.RunnerId) l[labelKeyJobResult] = msg.Result - l[labelKeyRunnerName] = msg.RunnerName return l } func (b *baseLabels) startedJobLabels(msg *actions.JobStarted) prometheus.Labels { l := b.jobLabels(&msg.JobMessageBase) - l[labelKeyRunnerID] = strconv.Itoa(msg.RunnerId) - l[labelKeyRunnerName] = msg.RunnerName return l } diff --git a/pkg/actionsmetrics/metrics.go b/pkg/actionsmetrics/metrics.go index 96619f37..6a5a0123 100644 --- a/pkg/actionsmetrics/metrics.go +++ b/pkg/actionsmetrics/metrics.go @@ -21,55 +21,53 @@ func init() { ) } -var ( - runtimeBuckets []float64 = []float64{ - 0.01, - 0.05, - 0.1, - 0.5, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 12, - 15, - 18, - 20, - 25, - 30, - 40, - 50, - 60, - 70, - 80, - 90, - 100, - 110, - 120, - 150, - 180, - 210, - 240, - 300, - 360, - 420, - 480, - 540, - 600, - 900, - 1200, - 1800, - 2400, - 3000, - 3600, - } -) +var runtimeBuckets []float64 = []float64{ + 0.01, + 0.05, + 0.1, + 0.5, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 12, + 15, + 18, + 20, + 25, + 30, + 40, + 50, + 60, + 70, + 80, + 90, + 100, + 110, + 120, + 150, + 180, + 210, + 240, + 300, + 360, + 420, + 480, + 540, + 600, + 900, + 1200, + 1800, + 2400, + 3000, + 3600, +} func metricLabels(extras ...string) []string { return append(append([]string{}, commonLabels...), extras...) From e12a892748f024abfc7c7341e9f7983b88e16498 Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Tue, 4 Mar 2025 17:01:34 +0100 Subject: [PATCH 11/14] Rename log from target/actual to build/autoscalingRunnerSet version (#3957) --- .../actions.github.com/autoscalingrunnerset_controller.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/controllers/actions.github.com/autoscalingrunnerset_controller.go b/controllers/actions.github.com/autoscalingrunnerset_controller.go index 6746df3d..5ea12298 100644 --- a/controllers/actions.github.com/autoscalingrunnerset_controller.go +++ b/controllers/actions.github.com/autoscalingrunnerset_controller.go @@ -154,15 +154,15 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl if autoscalingRunnerSet.Labels[LabelKeyKubernetesVersion] != build.Version { if err := r.Delete(ctx, autoscalingRunnerSet); err != nil { log.Error(err, "Failed to delete autoscaling runner set on version mismatch", - "targetVersion", build.Version, - "actualVersion", autoscalingRunnerSet.Labels[LabelKeyKubernetesVersion], + "buildVersion", build.Version, + "autoscalingRunnerSetVersion", autoscalingRunnerSet.Labels[LabelKeyKubernetesVersion], ) return ctrl.Result{}, nil } log.Info("Autoscaling runner set version doesn't match the build version. Deleting the resource.", - "targetVersion", build.Version, - "actualVersion", autoscalingRunnerSet.Labels[LabelKeyKubernetesVersion], + "buildVersion", build.Version, + "autoscalingRunnerSetVersion", autoscalingRunnerSet.Labels[LabelKeyKubernetesVersion], ) return ctrl.Result{}, nil } From e1226155535d2b4e6376f316c2eaf22ee2f8f113 Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Wed, 5 Mar 2025 10:21:06 +0100 Subject: [PATCH 12/14] Use Ready from the pod conditions when setting it to the EphemeralRunner (#3891) --- .../ephemeralrunner_controller.go | 29 ++++- .../ephemeralrunner_controller_test.go | 104 +++++++++++++++++- 2 files changed, 123 insertions(+), 10 deletions(-) diff --git a/controllers/actions.github.com/ephemeralrunner_controller.go b/controllers/actions.github.com/ephemeralrunner_controller.go index b39d35da..005f621c 100644 --- a/controllers/actions.github.com/ephemeralrunner_controller.go +++ b/controllers/actions.github.com/ephemeralrunner_controller.go @@ -712,22 +712,41 @@ func (r *EphemeralRunnerReconciler) updateRunStatusFromPod(ctx context.Context, if pod.Status.Phase == corev1.PodSucceeded || pod.Status.Phase == corev1.PodFailed { return nil } - if ephemeralRunner.Status.Phase == pod.Status.Phase { + + var ready bool + var lastTransitionTime time.Time + for _, condition := range pod.Status.Conditions { + if condition.Type == corev1.PodReady && condition.LastTransitionTime.After(lastTransitionTime) { + ready = condition.Status == corev1.ConditionTrue + lastTransitionTime = condition.LastTransitionTime.Time + } + } + + phaseChanged := ephemeralRunner.Status.Phase != pod.Status.Phase + readyChanged := ready != ephemeralRunner.Status.Ready + + if !phaseChanged && !readyChanged { return nil } - log.Info("Updating ephemeral runner status with pod phase", "statusPhase", pod.Status.Phase, "statusReason", pod.Status.Reason, "statusMessage", pod.Status.Message) + log.Info( + "Updating ephemeral runner status", + "statusPhase", pod.Status.Phase, + "statusReason", pod.Status.Reason, + "statusMessage", pod.Status.Message, + "ready", ready, + ) err := patchSubResource(ctx, r.Status(), ephemeralRunner, func(obj *v1alpha1.EphemeralRunner) { obj.Status.Phase = pod.Status.Phase - obj.Status.Ready = obj.Status.Ready || (pod.Status.Phase == corev1.PodRunning) + obj.Status.Ready = ready obj.Status.Reason = pod.Status.Reason obj.Status.Message = pod.Status.Message }) if err != nil { - return fmt.Errorf("failed to update runner status for Phase/Reason/Message: %v", err) + return fmt.Errorf("failed to update runner status for Phase/Reason/Message/Ready: %v", err) } - log.Info("Updated ephemeral runner status with pod phase") + log.Info("Updated ephemeral runner status") return nil } diff --git a/controllers/actions.github.com/ephemeralrunner_controller_test.go b/controllers/actions.github.com/ephemeralrunner_controller_test.go index 14c51d43..15f7d8ae 100644 --- a/controllers/actions.github.com/ephemeralrunner_controller_test.go +++ b/controllers/actions.github.com/ephemeralrunner_controller_test.go @@ -379,16 +379,21 @@ var _ = Describe("EphemeralRunner", func() { podCopy := pod.DeepCopy() pod.Status.Phase = phase // set container state to force status update - pod.Status.ContainerStatuses = append(pod.Status.ContainerStatuses, corev1.ContainerStatus{ - Name: EphemeralRunnerContainerName, - State: corev1.ContainerState{}, - }) + pod.Status.ContainerStatuses = append( + pod.Status.ContainerStatuses, + corev1.ContainerStatus{ + Name: EphemeralRunnerContainerName, + State: corev1.ContainerState{}, + }, + ) + err := k8sClient.Status().Patch(ctx, pod, client.MergeFrom(podCopy)) Expect(err).To(BeNil(), "failed to patch pod status") + var updated *v1alpha1.EphemeralRunner Eventually( func() (corev1.PodPhase, error) { - updated := new(v1alpha1.EphemeralRunner) + updated = new(v1alpha1.EphemeralRunner) err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, updated) if err != nil { return "", err @@ -401,6 +406,95 @@ var _ = Describe("EphemeralRunner", func() { } }) + It("It should update ready based on the latest condition", func() { + pod := new(corev1.Pod) + Eventually(func() (bool, error) { + if err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, pod); err != nil { + return false, err + } + return true, nil + }).Should(BeEquivalentTo(true)) + + newPod := pod.DeepCopy() + newPod.Status.Conditions = []corev1.PodCondition{ + { + Type: corev1.PodScheduled, + Status: corev1.ConditionTrue, + LastTransitionTime: metav1.Now(), + }, + { + Type: corev1.PodInitialized, + Status: corev1.ConditionTrue, + LastTransitionTime: metav1.Now(), + }, + { + Type: corev1.ContainersReady, + Status: corev1.ConditionTrue, + LastTransitionTime: metav1.Now(), + }, + { + Type: corev1.PodReady, + Status: corev1.ConditionTrue, + LastTransitionTime: metav1.Now(), + }, + } + newPod.Status.ContainerStatuses = append(pod.Status.ContainerStatuses, corev1.ContainerStatus{ + Name: EphemeralRunnerContainerName, + State: corev1.ContainerState{}, + }) + err := k8sClient.Status().Patch(ctx, newPod, client.MergeFrom(pod)) + Expect(err).To(BeNil(), "failed to patch pod status") + + var er *v1alpha1.EphemeralRunner + Eventually( + func() (bool, error) { + er = new(v1alpha1.EphemeralRunner) + err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, er) + if err != nil { + return false, err + } + return er.Status.Ready, nil + }, + ephemeralRunnerTimeout, + ephemeralRunnerInterval, + ).Should(BeEquivalentTo(true)) + + // Fetch the pod again + Eventually( + func() (bool, error) { + err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, pod) + if err != nil { + return false, err + } + return true, nil + }, + ephemeralRunnerTimeout, + ephemeralRunnerInterval, + ).Should(BeEquivalentTo(true)) + + newPod = pod.DeepCopy() + newPod.Status.Conditions = append(newPod.Status.Conditions, corev1.PodCondition{ + Type: corev1.PodReady, + Status: corev1.ConditionFalse, + LastTransitionTime: metav1.Time{Time: metav1.Now().Add(1 * time.Second)}, + }) + + err = k8sClient.Status().Patch(ctx, newPod, client.MergeFrom(pod)) + Expect(err).To(BeNil(), "expected no errors when updating new pod status") + + Eventually( + func() (bool, error) { + err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, pod) + if err != nil { + return false, err + } + return ephemeralRunner.Status.Ready, nil + }, + ephemeralRunnerTimeout, + ephemeralRunnerInterval, + ).Should(BeEquivalentTo(false)) + }) + It("It should not update phase if container state does not exist", func() { pod := new(corev1.Pod) Eventually( From 75e037909ef21dda8781c1b1a1fac98aba3868b6 Mon Sep 17 00:00:00 2001 From: thinkbiggerltd <46003245+thinkbiggerltd@users.noreply.github.com> Date: Wed, 5 Mar 2025 10:00:13 +0000 Subject: [PATCH 13/14] AutoscalingRunnerSet env: not Rendering correctly (#3826) Co-authored-by: Nikola Jokic --- charts/gha-runner-scale-set/templates/_helpers.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/gha-runner-scale-set/templates/_helpers.tpl b/charts/gha-runner-scale-set/templates/_helpers.tpl index bd71ed64..b73c5dbe 100644 --- a/charts/gha-runner-scale-set/templates/_helpers.tpl +++ b/charts/gha-runner-scale-set/templates/_helpers.tpl @@ -218,7 +218,7 @@ env: {{- if eq $env.name "RUNNER_UPDATE_CA_CERTS" }} {{- $setRunnerUpdateCaCerts = 0 }} {{- end }} - - {{ $env | toYaml | nindent 4 }} + - {{ $env | toYaml | nindent 4 | trim }} {{- end }} {{- end }} {{- if $setDockerHost }} From 2f5c981d4699398b28026f29412feded27ffe743 Mon Sep 17 00:00:00 2001 From: Cees-Jan Kiewiet Date: Wed, 5 Mar 2025 21:02:27 +0100 Subject: [PATCH 14/14] Drop verbose flag from runner scale set init-dind-externals copy (#3805) --- charts/gha-runner-scale-set/templates/_helpers.tpl | 2 +- charts/gha-runner-scale-set/tests/template_test.go | 2 +- charts/gha-runner-scale-set/values.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/gha-runner-scale-set/templates/_helpers.tpl b/charts/gha-runner-scale-set/templates/_helpers.tpl index b73c5dbe..a83f2a56 100644 --- a/charts/gha-runner-scale-set/templates/_helpers.tpl +++ b/charts/gha-runner-scale-set/templates/_helpers.tpl @@ -87,7 +87,7 @@ app.kubernetes.io/instance: {{ include "gha-runner-scale-set.scale-set-name" . } {{- if eq $val.name "runner" }} image: {{ $val.image }} command: ["cp"] -args: ["-r", "-v", "/home/runner/externals/.", "/home/runner/tmpDir/"] +args: ["-r", "/home/runner/externals/.", "/home/runner/tmpDir/"] volumeMounts: - name: dind-externals mountPath: /home/runner/tmpDir diff --git a/charts/gha-runner-scale-set/tests/template_test.go b/charts/gha-runner-scale-set/tests/template_test.go index 070f1ef1..8f5a833e 100644 --- a/charts/gha-runner-scale-set/tests/template_test.go +++ b/charts/gha-runner-scale-set/tests/template_test.go @@ -893,7 +893,7 @@ func TestTemplateRenderedAutoScalingRunnerSet_EnableDinD(t *testing.T) { 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 /home/runner/externals/. /home/runner/tmpDir/", strings.Join(ars.Spec.Template.Spec.InitContainers[0].Args, " ")) + assert.Equal(t, "-r /home/runner/externals/. /home/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) diff --git a/charts/gha-runner-scale-set/values.yaml b/charts/gha-runner-scale-set/values.yaml index db3256b2..214a2dce 100644 --- a/charts/gha-runner-scale-set/values.yaml +++ b/charts/gha-runner-scale-set/values.yaml @@ -130,7 +130,7 @@ template: ## initContainers: ## - name: init-dind-externals ## image: ghcr.io/actions/actions-runner:latest - ## command: ["cp", "-r", "-v", "/home/runner/externals/.", "/home/runner/tmpDir/"] + ## command: ["cp", "-r", "/home/runner/externals/.", "/home/runner/tmpDir/"] ## volumeMounts: ## - name: dind-externals ## mountPath: /home/runner/tmpDir