Compare commits

...

51 Commits

Author SHA1 Message Date
dependabot[bot]
d0c3d38903 Bump the gomod group with 2 updates
Bumps the gomod group with 2 updates: [github.com/gruntwork-io/terratest](https://github.com/gruntwork-io/terratest) and [go.uber.org/zap](https://github.com/uber-go/zap).


Updates `github.com/gruntwork-io/terratest` from 0.53.0 to 0.54.0
- [Release notes](https://github.com/gruntwork-io/terratest/releases)
- [Commits](https://github.com/gruntwork-io/terratest/compare/v0.53.0...v0.54.0)

Updates `go.uber.org/zap` from 1.27.0 to 1.27.1
- [Release notes](https://github.com/uber-go/zap/releases)
- [Changelog](https://github.com/uber-go/zap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/uber-go/zap/compare/v1.27.0...v1.27.1)

---
updated-dependencies:
- dependency-name: github.com/gruntwork-io/terratest
  dependency-version: 0.54.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: gomod
- dependency-name: go.uber.org/zap
  dependency-version: 1.27.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: gomod
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-24 22:13:04 +00:00
dependabot[bot]
a9e371e083 Bump the actions group across 1 directory with 4 updates (#4309)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nikola Jokic <jokicnikola07@gmail.com>
2025-11-21 19:23:19 +01:00
dependabot[bot]
fdf78189ab Bump golang.org/x/crypto from 0.43.0 to 0.45.0 (#4318)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nikola Jokic <jokicnikola07@gmail.com>
2025-11-21 17:14:05 +01:00
Marcus Ramberg
cac7a40b70 Add support for giving kubernetes mode scaleset service account additional permissions (#4282) 2025-11-21 15:56:08 +01:00
dependabot[bot]
837406ae01 Bump the gomod group across 1 directory with 11 updates (#4317)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nikola Jokic <jokicnikola07@gmail.com>
2025-11-21 14:49:28 +01:00
Nikola Jokic
95d2107a6a Code style changes on the controller (#4324) 2025-11-21 14:20:44 +01:00
github-actions[bot]
5a6bfc937a Updates: runner to v2.330.0 (#4319)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-11-21 10:10:16 +01:00
Nikola Jokic
6d07b8d853 Add ephemeral runner finalizer during creation and check finalizer without requeue (#4320) 2025-11-20 23:06:27 +01:00
Nikola Jokic
a50d8bfebc e2e: move from deprecated openebs charts to new registry (#4321) 2025-11-20 22:25:52 +01:00
Nikola Jokic
138b39bfcb Create e2e test suite (#3136)
Co-authored-by: Bassem Dghaidi <568794+Link-@users.noreply.github.com>
2025-11-19 16:25:58 +01:00
Rafik Salama
4615321588 Upgrade Docker and Docker Compose to match GH hosted runner (#4312) 2025-11-13 11:31:17 +01:00
Nikola Jokic
9f9409a4c1 Handle resource quota on status forbidden by retrying (#4305)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-10 13:58:25 +01:00
Nikola Jokic
3d73636407 Use combination of namespace, GitHub URL, and runner group when hashing the listener name (#4299) 2025-11-10 13:58:16 +01:00
Nikola Jokic
722c6e9edd Bump kubebuilder tools in the workflow (#4300) 2025-11-10 12:26:08 +00:00
Nikola Jokic
dcb45f0617 Bump timeout for min runners workflow to 30s (#4306) 2025-11-10 12:01:58 +00:00
Jiaren Wu
dbac55ca9e Fix for code scanning alert no. 5: Workflow does not contain permissions (#4292)
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-10-31 10:20:30 +01:00
github-actions[bot]
91d45d870a Updates: runner to v2.329.0 container-hooks to v0.8.0 (#4279)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-10-30 10:32:22 +01:00
Nikola Jokic
4d22089978 Delete listener resources without requeueing on each call (#4289) 2025-10-29 13:01:00 +01:00
Nikola Jokic
8007b8af25 Fix first interaction action (#4290) 2025-10-29 12:49:39 +01:00
dependabot[bot]
0baa4f6b09 Bump github/codeql-action from 3 to 4 in the actions group (#4281)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-22 11:26:36 +02:00
Nikola Jokic
a0c30df25b Prepare 0.13.0 release (#4280) 2025-10-16 19:25:56 +02:00
dependabot[bot]
27d03ef2e2 Bump the gomod group across 1 directory with 4 updates (#4277)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-15 01:31:29 +02:00
Nikola Jokic
634e42c916 Bump all dependencies (#4266) 2025-10-14 13:24:25 +02:00
Jiaren Wu
6e46b42bf4 Potential fix for code scanning alert no. 1: Workflow does not contain permissions (#4274)
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jiaren-wu <190862939+jiaren-wu@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-13 11:08:35 -07:00
Jiaren Wu
71ebdd9d3c Potential fix for code scanning alert no. 3: Workflow does not contain permissions (#4273)
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-10-13 10:38:14 -07:00
Berat Postalcioglu
7604c8361f docs: fix broken Grafana dashboard JSON path (#4270) 2025-10-09 22:05:43 +02:00
Nikola Jokic
94a6f3cc3a Ensure ephemeral runner is deleted from the service on exit != 0 (#4260) 2025-10-06 11:38:56 +02:00
Nikola Jokic
e3ed1ba226 Introduce new kubernetes-novolume mode (#4250)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-03 12:03:38 +02:00
dependabot[bot]
652bd99439 Bump the actions group across 1 directory with 5 updates (#4262)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-01 17:27:52 +02:00
Yusuke Kuoka
f731873df9 Add workflow name and target labels (#4240) 2025-09-30 16:01:51 +02:00
Nikola Jokic
088e2a3a90 Remove ephemeral runner when exit code != 0 and is patched with the job (#4239) 2025-09-17 21:40:37 +02:00
Dennis Stone
2035e13724 Update CODEOWNERS to include new maintainer (#4253) 2025-09-17 21:33:38 +02:00
Nikola Jokic
04b966dfec Update CODEOWNERS (#4251) 2025-09-17 17:49:12 +02:00
zkpepe
0a0be027fd docs: fix repo path typo (#4229) 2025-08-27 16:17:52 +02:00
Nikola Jokic
ddc2918a48 Requeue if create pod returns already exists error (#4201) 2025-08-14 17:00:48 +02:00
github-actions[bot]
0e006bb0ff Updates: runner to v2.328.0 (#4209)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-14 10:44:40 +01:00
dependabot[bot]
ce7722aed4 Bump actions/checkout from 4 to 5 in the actions group (#4205)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 23:27:53 +02:00
dependabot[bot]
ad2dd7d787 Bump docker/login-action from 3.4.0 to 3.5.0 in the actions group (#4196)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-06 23:08:12 +02:00
clechevalli
30abbe0cab Fix usage of underscore in Runner Scale Set name (#3545)
Co-authored-by: Nikola Jokic <jokicnikola07@gmail.com>
2025-08-06 09:32:49 +01:00
Nikola Jokic
c27541140a Remove JIT config from ephemeral runner status field (#4191) 2025-08-04 12:35:04 +02:00
github-actions[bot]
52d65c333b Updates: runner to v2.327.1 (#4188)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-29 10:07:13 +01:00
Alex Hatzenbuhler
a07dce28bb Remove deprecated preserveUnknownFields from CRDs (#4135) 2025-07-24 08:47:34 +02:00
github-actions[bot]
fb43abf1f3 Updates: runner to v2.327.0 (#4185)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-23 16:19:17 +01:00
Kylie Stradley
9c42f9f2e1 Add Missing Languages to CodeQL Advanced Configuration (#4179) 2025-07-16 11:16:19 +02:00
Cory Calahan
ad826725ce Update example GitHub URLs in values.yaml to include an example for enterprise account-level runners (#4181) 2025-07-16 10:40:38 +02:00
github-actions[bot]
4326693888 Updates: runner to v2.326.0 (#4176)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-14 11:39:15 -04:00
Nikola Jokic
469a0faec4 Remove workflow actions version comments since upgrades are done via dependabot (#4161) 2025-07-01 15:54:59 +02:00
Nikola Jokic
349cc0835e Fix image pull secrets list arguments in the chart (#4164) 2025-07-01 15:28:18 +02:00
Ho Kim
aa14f50e45 feat(runner): add ubuntu 24.04 support (#3598) 2025-07-01 18:34:52 +09:00
dependabot[bot]
ee8ca99e49 Bump the actions group across 1 directory with 5 updates (#4160)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-30 13:55:46 +02:00
adjn
6a13540076 Update CodeQL workflow for v3 (global-run-codeql.yaml) (#4157) 2025-06-30 11:16:11 +02:00
111 changed files with 29598 additions and 18037 deletions

View File

@@ -40,13 +40,12 @@ jobs:
publish-chart: ${{ steps.publish-chart-step.outputs.publish }} publish-chart: ${{ steps.publish-chart-step.outputs.publish }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up Helm - name: Set up Helm
# Using https://github.com/Azure/setup-helm/releases/tag/v4.2.0 uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814
with: with:
version: ${{ env.HELM_VERSION }} version: ${{ env.HELM_VERSION }}
@@ -59,13 +58,12 @@ jobs:
run: helm template --values charts/.ci/values-kube-score.yaml charts/* | ./kube-score score - --ignore-test pod-networkpolicy --ignore-test deployment-has-poddisruptionbudget --ignore-test deployment-has-host-podantiaffinity --ignore-test container-security-context --ignore-test pod-probes --ignore-test container-image-tag --enable-optional-test container-security-context-privileged --enable-optional-test container-security-context-readonlyrootfilesystem run: helm template --values charts/.ci/values-kube-score.yaml charts/* | ./kube-score score - --ignore-test pod-networkpolicy --ignore-test deployment-has-poddisruptionbudget --ignore-test deployment-has-host-podantiaffinity --ignore-test container-security-context --ignore-test pod-probes --ignore-test container-image-tag --enable-optional-test container-security-context-privileged --enable-optional-test container-security-context-readonlyrootfilesystem
# python is a requirement for the chart-testing action below (supports yamllint among other tests) # python is a requirement for the chart-testing action below (supports yamllint among other tests)
- uses: actions/setup-python@v5 - uses: actions/setup-python@v6
with: with:
python-version: "3.11" python-version: "3.11"
- name: Set up chart-testing - name: Set up chart-testing
# https://github.com/helm/chart-testing-action/releases/tag/v2.7.0 uses: helm/chart-testing-action@6ec842c01de15ebb84c8627d2744a0c2f2755c9f
uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b
- name: Run chart-testing (list-changed) - name: Run chart-testing (list-changed)
id: list-changed id: list-changed
@@ -81,8 +79,7 @@ jobs:
- name: Create kind cluster - name: Create kind cluster
if: steps.list-changed.outputs.changed == 'true' if: steps.list-changed.outputs.changed == 'true'
# https://github.com/helm/kind-action/releases/tag/v1.12.0 uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3
# We need cert-manager already installed in the cluster because we assume the CRDs exist # We need cert-manager already installed in the cluster because we assume the CRDs exist
- name: Install cert-manager - name: Install cert-manager
@@ -137,7 +134,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -148,8 +145,7 @@ jobs:
- name: Get Token - name: Get Token
id: get_workflow_token id: get_workflow_token
# https://github.com/peter-murray/workflow-application-token-action/releases/tag/v3.0.0 uses: peter-murray/workflow-application-token-action@d17e3a9a36850ea89f35db16c1067dd2b68ee343
uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3
with: with:
application_id: ${{ secrets.ACTIONS_ACCESS_APP_ID }} application_id: ${{ secrets.ACTIONS_ACCESS_APP_ID }}
application_private_key: ${{ secrets.ACTIONS_ACCESS_PK }} application_private_key: ${{ secrets.ACTIONS_ACCESS_PK }}
@@ -188,7 +184,7 @@ jobs:
# this workaround is intended to move the index.yaml to the target repo # this workaround is intended to move the index.yaml to the target repo
# where the github pages are hosted # where the github pages are hosted
- name: Checkout target repository - name: Checkout target repository
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
repository: ${{ env.CHART_TARGET_ORG }}/${{ env.CHART_TARGET_REPO }} repository: ${{ env.CHART_TARGET_ORG }}/${{ env.CHART_TARGET_REPO }}
path: ${{ env.CHART_TARGET_REPO }} path: ${{ env.CHART_TARGET_REPO }}

View File

@@ -39,9 +39,9 @@ jobs:
if: ${{ !startsWith(github.event.inputs.release_tag_name, 'gha-runner-scale-set-') }} if: ${{ !startsWith(github.event.inputs.release_tag_name, 'gha-runner-scale-set-') }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- uses: actions/setup-go@v5 - uses: actions/setup-go@v6
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
@@ -73,8 +73,7 @@ jobs:
- name: Get Token - name: Get Token
id: get_workflow_token id: get_workflow_token
# https://github.com/peter-murray/workflow-application-token-action/releases/tag/v3.0.0 uses: peter-murray/workflow-application-token-action@d17e3a9a36850ea89f35db16c1067dd2b68ee343
uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3
with: with:
application_id: ${{ secrets.ACTIONS_ACCESS_APP_ID }} application_id: ${{ secrets.ACTIONS_ACCESS_APP_ID }}
application_private_key: ${{ secrets.ACTIONS_ACCESS_PK }} application_private_key: ${{ secrets.ACTIONS_ACCESS_PK }}

View File

@@ -1,4 +1,6 @@
name: Release ARC Runner Images name: Release ARC Runner Images
permissions:
contents: read
# Revert to https://github.com/actions-runner-controller/releases#releases # Revert to https://github.com/actions-runner-controller/releases#releases
# for details on why we use this approach # for details on why we use this approach
@@ -17,7 +19,7 @@ env:
PUSH_TO_REGISTRIES: true PUSH_TO_REGISTRIES: true
TARGET_ORG: actions-runner-controller TARGET_ORG: actions-runner-controller
TARGET_WORKFLOW: release-runners.yaml TARGET_WORKFLOW: release-runners.yaml
DOCKER_VERSION: 24.0.7 DOCKER_VERSION: 28.0.4
concurrency: concurrency:
group: ${{ github.workflow }} group: ${{ github.workflow }}
@@ -28,7 +30,7 @@ jobs:
name: Trigger Build and Push of Runner Images name: Trigger Build and Push of Runner Images
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- name: Get runner version - name: Get runner version
id: versions id: versions
run: | run: |
@@ -39,8 +41,7 @@ jobs:
- name: Get Token - name: Get Token
id: get_workflow_token id: get_workflow_token
# https://github.com/peter-murray/workflow-application-token-action/releases/tag/v3.0.0 uses: peter-murray/workflow-application-token-action@d17e3a9a36850ea89f35db16c1067dd2b68ee343
uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3
with: with:
application_id: ${{ secrets.ACTIONS_ACCESS_APP_ID }} application_id: ${{ secrets.ACTIONS_ACCESS_APP_ID }}
application_private_key: ${{ secrets.ACTIONS_ACCESS_PK }} application_private_key: ${{ secrets.ACTIONS_ACCESS_PK }}

View File

@@ -1,6 +1,9 @@
# This workflows polls releases from actions/runner and in case of a new one it # This workflows polls releases from actions/runner and in case of a new one it
# updates files containing runner version and opens a pull request. # updates files containing runner version and opens a pull request.
name: Runner Updates Check (Scheduled Job) name: Runner Updates Check (Scheduled Job)
permissions:
pull-requests: write
contents: write
on: on:
schedule: schedule:
@@ -21,7 +24,7 @@ jobs:
container_hooks_current_version: ${{ steps.container_hooks_versions.outputs.container_hooks_current_version }} container_hooks_current_version: ${{ steps.container_hooks_versions.outputs.container_hooks_current_version }}
container_hooks_latest_version: ${{ steps.container_hooks_versions.outputs.container_hooks_latest_version }} container_hooks_latest_version: ${{ steps.container_hooks_versions.outputs.container_hooks_latest_version }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- name: Get runner current and latest versions - name: Get runner current and latest versions
id: runner_versions id: runner_versions
@@ -50,6 +53,8 @@ jobs:
# it sets a PR name as output. # it sets a PR name as output.
check_pr: check_pr:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
needs: check_versions needs: check_versions
if: needs.check_versions.outputs.runner_current_version != needs.check_versions.outputs.runner_latest_version || needs.check_versions.outputs.container_hooks_current_version != needs.check_versions.outputs.container_hooks_latest_version if: needs.check_versions.outputs.runner_current_version != needs.check_versions.outputs.runner_latest_version || needs.check_versions.outputs.container_hooks_current_version != needs.check_versions.outputs.container_hooks_latest_version
outputs: outputs:
@@ -64,7 +69,7 @@ jobs:
echo "CONTAINER_HOOKS_CURRENT_VERSION=${{ needs.check_versions.outputs.container_hooks_current_version }}" echo "CONTAINER_HOOKS_CURRENT_VERSION=${{ needs.check_versions.outputs.container_hooks_current_version }}"
echo "CONTAINER_HOOKS_LATEST_VERSION=${{ needs.check_versions.outputs.container_hooks_latest_version }}" echo "CONTAINER_HOOKS_LATEST_VERSION=${{ needs.check_versions.outputs.container_hooks_latest_version }}"
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- name: PR Name - name: PR Name
id: pr_name id: pr_name
@@ -119,7 +124,7 @@ jobs:
PR_NAME: ${{ needs.check_pr.outputs.pr_name }} PR_NAME: ${{ needs.check_pr.outputs.pr_name }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- name: New branch - name: New branch
run: git checkout -b update-runner-"$(date +%Y-%m-%d)" run: git checkout -b update-runner-"$(date +%Y-%m-%d)"

View File

@@ -40,24 +40,22 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up Helm - name: Set up Helm
# Using https://github.com/Azure/setup-helm/releases/tag/v4.2.0 uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814
with: with:
version: ${{ env.HELM_VERSION }} version: ${{ env.HELM_VERSION }}
# python is a requirement for the chart-testing action below (supports yamllint among other tests) # python is a requirement for the chart-testing action below (supports yamllint among other tests)
- uses: actions/setup-python@v5 - uses: actions/setup-python@v6
with: with:
python-version: "3.11" python-version: "3.11"
- name: Set up chart-testing - name: Set up chart-testing
# https://github.com/helm/chart-testing-action/releases/tag/v2.7.0 uses: helm/chart-testing-action@6ec842c01de15ebb84c8627d2744a0c2f2755c9f
uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b
- name: Run chart-testing (list-changed) - name: Run chart-testing (list-changed)
id: list-changed id: list-changed
@@ -72,8 +70,7 @@ jobs:
ct lint --config charts/.ci/ct-config.yaml ct lint --config charts/.ci/ct-config.yaml
- name: Create kind cluster - name: Create kind cluster
# https://github.com/helm/kind-action/releases/tag/v1.12.0 uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3
if: steps.list-changed.outputs.changed == 'true' if: steps.list-changed.outputs.changed == 'true'
# We need cert-manager already installed in the cluster because we assume the CRDs exist # We need cert-manager already installed in the cluster because we assume the CRDs exist

View File

@@ -24,7 +24,7 @@ jobs:
name: runner / shellcheck name: runner / shellcheck
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- name: "Run shellcheck" - name: "Run shellcheck"
run: make shellcheck run: make shellcheck
@@ -33,7 +33,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Run tests - name: Run tests
run: | run: |

View File

@@ -16,7 +16,7 @@ env:
TARGET_ORG: actions-runner-controller TARGET_ORG: actions-runner-controller
TARGET_REPO: arc_e2e_test_dummy TARGET_REPO: arc_e2e_test_dummy
IMAGE_NAME: "arc-test-image" IMAGE_NAME: "arc-test-image"
IMAGE_VERSION: "0.12.1" IMAGE_VERSION: "0.13.0"
concurrency: concurrency:
# This will make sure we only apply the concurrency limits on pull requests # This will make sure we only apply the concurrency limits on pull requests
@@ -26,6 +26,29 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
default-setup-v2:
runs-on: ubuntu-latest
timeout-minutes: 20
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id
steps:
- uses: actions/checkout@v5
with:
ref: ${{github.head_ref}}
- name: Get configure token
id: config-token
uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3
with:
application_id: ${{ secrets.E2E_TESTS_ACCESS_APP_ID }}
application_private_key: ${{ secrets.E2E_TESTS_ACCESS_PK }}
organization: ${{ env.TARGET_ORG }}
- name: Run default setup test
run: hack/e2e-test.sh default-setup
env:
GITHUB_TOKEN: "${{steps.config-token.outputs.token}}"
shell: bash
default-setup: default-setup:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 20 timeout-minutes: 20
@@ -33,7 +56,7 @@ jobs:
env: env:
WORKFLOW_FILE: "arc-test-workflow.yaml" WORKFLOW_FILE: "arc-test-workflow.yaml"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
ref: ${{github.head_ref}} ref: ${{github.head_ref}}
@@ -117,6 +140,29 @@ jobs:
arc-namespace: "arc-runners" arc-namespace: "arc-runners"
arc-controller-namespace: "arc-systems" arc-controller-namespace: "arc-systems"
single-namespace-setup-v2:
runs-on: ubuntu-latest
timeout-minutes: 20
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id
steps:
- uses: actions/checkout@v5
with:
ref: ${{github.head_ref}}
- name: Get configure token
id: config-token
uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3
with:
application_id: ${{ secrets.E2E_TESTS_ACCESS_APP_ID }}
application_private_key: ${{ secrets.E2E_TESTS_ACCESS_PK }}
organization: ${{ env.TARGET_ORG }}
- name: Run single namespace setup test
run: hack/e2e-test.sh single-namespace-setup
env:
GITHUB_TOKEN: "${{steps.config-token.outputs.token}}"
shell: bash
single-namespace-setup: single-namespace-setup:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 20 timeout-minutes: 20
@@ -124,7 +170,7 @@ jobs:
env: env:
WORKFLOW_FILE: "arc-test-workflow.yaml" WORKFLOW_FILE: "arc-test-workflow.yaml"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
ref: ${{github.head_ref}} ref: ${{github.head_ref}}
@@ -210,6 +256,29 @@ jobs:
arc-namespace: "arc-runners" arc-namespace: "arc-runners"
arc-controller-namespace: "arc-systems" arc-controller-namespace: "arc-systems"
dind-mode-setup-v2:
runs-on: ubuntu-latest
timeout-minutes: 20
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id
steps:
- uses: actions/checkout@v5
with:
ref: ${{github.head_ref}}
- name: Get configure token
id: config-token
uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3
with:
application_id: ${{ secrets.E2E_TESTS_ACCESS_APP_ID }}
application_private_key: ${{ secrets.E2E_TESTS_ACCESS_PK }}
organization: ${{ env.TARGET_ORG }}
- name: Run dind mode setup test
run: hack/e2e-test.sh dind-mode-setup
env:
GITHUB_TOKEN: "${{steps.config-token.outputs.token}}"
shell: bash
dind-mode-setup: dind-mode-setup:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 20 timeout-minutes: 20
@@ -217,7 +286,7 @@ jobs:
env: env:
WORKFLOW_FILE: arc-test-dind-workflow.yaml WORKFLOW_FILE: arc-test-dind-workflow.yaml
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
ref: ${{github.head_ref}} ref: ${{github.head_ref}}
@@ -302,6 +371,29 @@ jobs:
arc-namespace: "arc-runners" arc-namespace: "arc-runners"
arc-controller-namespace: "arc-systems" arc-controller-namespace: "arc-systems"
kubernetes-mode-setup-v2:
runs-on: ubuntu-latest
timeout-minutes: 20
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id
steps:
- uses: actions/checkout@v5
with:
ref: ${{github.head_ref}}
- name: Get configure token
id: config-token
uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3
with:
application_id: ${{ secrets.E2E_TESTS_ACCESS_APP_ID }}
application_private_key: ${{ secrets.E2E_TESTS_ACCESS_PK }}
organization: ${{ env.TARGET_ORG }}
- name: Run kubernetes mode setup test
run: hack/e2e-test.sh kubernetes-mode-setup
env:
GITHUB_TOKEN: "${{steps.config-token.outputs.token}}"
shell: bash
kubernetes-mode-setup: kubernetes-mode-setup:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 20 timeout-minutes: 20
@@ -309,7 +401,7 @@ jobs:
env: env:
WORKFLOW_FILE: "arc-test-kubernetes-workflow.yaml" WORKFLOW_FILE: "arc-test-kubernetes-workflow.yaml"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
ref: ${{github.head_ref}} ref: ${{github.head_ref}}
@@ -403,6 +495,29 @@ jobs:
arc-namespace: "arc-runners" arc-namespace: "arc-runners"
arc-controller-namespace: "arc-systems" arc-controller-namespace: "arc-systems"
auth-proxy-setup-v2:
runs-on: ubuntu-latest
timeout-minutes: 20
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id
steps:
- uses: actions/checkout@v5
with:
ref: ${{github.head_ref}}
- name: Get configure token
id: config-token
uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3
with:
application_id: ${{ secrets.E2E_TESTS_ACCESS_APP_ID }}
application_private_key: ${{ secrets.E2E_TESTS_ACCESS_PK }}
organization: ${{ env.TARGET_ORG }}
- name: Run single namespace setup test
run: hack/e2e-test.sh single-namespace-setup
env:
GITHUB_TOKEN: "${{steps.config-token.outputs.token}}"
shell: bash
auth-proxy-setup: auth-proxy-setup:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 20 timeout-minutes: 20
@@ -410,7 +525,7 @@ jobs:
env: env:
WORKFLOW_FILE: "arc-test-workflow.yaml" WORKFLOW_FILE: "arc-test-workflow.yaml"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
ref: ${{github.head_ref}} ref: ${{github.head_ref}}
@@ -506,6 +621,29 @@ jobs:
arc-namespace: "arc-runners" arc-namespace: "arc-runners"
arc-controller-namespace: "arc-systems" arc-controller-namespace: "arc-systems"
anonymous-proxy-setup-v2:
runs-on: ubuntu-latest
timeout-minutes: 20
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id
steps:
- uses: actions/checkout@v5
with:
ref: ${{github.head_ref}}
- name: Get configure token
id: config-token
uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3
with:
application_id: ${{ secrets.E2E_TESTS_ACCESS_APP_ID }}
application_private_key: ${{ secrets.E2E_TESTS_ACCESS_PK }}
organization: ${{ env.TARGET_ORG }}
- name: Run anonymous proxy setup test
run: hack/e2e-test.sh anonymous-proxy-setup
env:
GITHUB_TOKEN: "${{steps.config-token.outputs.token}}"
shell: bash
anonymous-proxy-setup: anonymous-proxy-setup:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 20 timeout-minutes: 20
@@ -513,7 +651,7 @@ jobs:
env: env:
WORKFLOW_FILE: "arc-test-workflow.yaml" WORKFLOW_FILE: "arc-test-workflow.yaml"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
ref: ${{github.head_ref}} ref: ${{github.head_ref}}
@@ -603,6 +741,29 @@ jobs:
arc-namespace: "arc-runners" arc-namespace: "arc-runners"
arc-controller-namespace: "arc-systems" arc-controller-namespace: "arc-systems"
self-signed-ca-setup-v2:
runs-on: ubuntu-latest
timeout-minutes: 20
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id
steps:
- uses: actions/checkout@v5
with:
ref: ${{github.head_ref}}
- name: Get configure token
id: config-token
uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3
with:
application_id: ${{ secrets.E2E_TESTS_ACCESS_APP_ID }}
application_private_key: ${{ secrets.E2E_TESTS_ACCESS_PK }}
organization: ${{ env.TARGET_ORG }}
- name: Run self signed CA setup test
run: hack/e2e-test.sh self-signed-ca-setup
env:
GITHUB_TOKEN: "${{steps.config-token.outputs.token}}"
shell: bash
self-signed-ca-setup: self-signed-ca-setup:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 20 timeout-minutes: 20
@@ -610,7 +771,7 @@ jobs:
env: env:
WORKFLOW_FILE: "arc-test-workflow.yaml" WORKFLOW_FILE: "arc-test-workflow.yaml"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
ref: ${{github.head_ref}} ref: ${{github.head_ref}}
@@ -725,6 +886,29 @@ jobs:
arc-namespace: "arc-runners" arc-namespace: "arc-runners"
arc-controller-namespace: "arc-systems" arc-controller-namespace: "arc-systems"
update-strategy-tests-v2:
runs-on: ubuntu-latest
timeout-minutes: 20
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id
steps:
- uses: actions/checkout@v5
with:
ref: ${{github.head_ref}}
- name: Get configure token
id: config-token
uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3
with:
application_id: ${{ secrets.E2E_TESTS_ACCESS_APP_ID }}
application_private_key: ${{ secrets.E2E_TESTS_ACCESS_PK }}
organization: ${{ env.TARGET_ORG }}
- name: Run update strategy test
run: hack/e2e-test.sh update-strategy
env:
GITHUB_TOKEN: "${{steps.config-token.outputs.token}}"
shell: bash
update-strategy-tests: update-strategy-tests:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 20 timeout-minutes: 20
@@ -732,7 +916,7 @@ jobs:
env: env:
WORKFLOW_FILE: "arc-test-sleepy-matrix.yaml" WORKFLOW_FILE: "arc-test-sleepy-matrix.yaml"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
ref: ${{github.head_ref}} ref: ${{github.head_ref}}
@@ -897,6 +1081,29 @@ jobs:
kubectl wait --timeout=10s --for=delete AutoScalingRunnerSet -n "${{ steps.install_arc.outputs.ARC_NAME }}" -l app.kubernetes.io/instance="${{ steps.install_arc.outputs.ARC_NAME }}" kubectl wait --timeout=10s --for=delete AutoScalingRunnerSet -n "${{ steps.install_arc.outputs.ARC_NAME }}" -l app.kubernetes.io/instance="${{ steps.install_arc.outputs.ARC_NAME }}"
kubectl logs deployment/arc-gha-rs-controller -n "arc-systems" kubectl logs deployment/arc-gha-rs-controller -n "arc-systems"
init-with-min-runners-v2:
runs-on: ubuntu-latest
timeout-minutes: 20
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id
steps:
- uses: actions/checkout@v5
with:
ref: ${{github.head_ref}}
- name: Get configure token
id: config-token
uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3
with:
application_id: ${{ secrets.E2E_TESTS_ACCESS_APP_ID }}
application_private_key: ${{ secrets.E2E_TESTS_ACCESS_PK }}
organization: ${{ env.TARGET_ORG }}
- name: Run init with min runners test
run: hack/e2e-test.sh init-with-min-runners
env:
GITHUB_TOKEN: "${{steps.config-token.outputs.token}}"
shell: bash
init-with-min-runners: init-with-min-runners:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 20 timeout-minutes: 20
@@ -904,7 +1111,7 @@ jobs:
env: env:
WORKFLOW_FILE: arc-test-workflow.yaml WORKFLOW_FILE: arc-test-workflow.yaml
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
ref: ${{ github.head_ref }} ref: ${{ github.head_ref }}
@@ -984,7 +1191,7 @@ jobs:
echo "5 pods are up!" echo "5 pods are up!"
break break
fi fi
if [[ "$count" -ge 12 ]]; then if [[ "$count" -ge 30 ]]; then
echo "Timeout waiting for 5 pods to be created" echo "Timeout waiting for 5 pods to be created"
exit 1 exit 1
fi fi

View File

@@ -45,7 +45,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
# If inputs.ref is empty, it'll resolve to the default branch # If inputs.ref is empty, it'll resolve to the default branch
ref: ${{ inputs.ref }} ref: ${{ inputs.ref }}
@@ -72,11 +72,10 @@ jobs:
echo "repository_owner=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT echo "repository_owner=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
- name: Set up QEMU - name: Set up QEMU
# https://github.com/docker/setup-qemu-action/releases/tag/v3.6.0 uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
with: with:
# Pinning v0.9.1 for Buildx and BuildKit v0.10.6 # Pinning v0.9.1 for Buildx and BuildKit v0.10.6
# BuildKit v0.11 which has a bug causing intermittent # BuildKit v0.11 which has a bug causing intermittent
@@ -85,15 +84,13 @@ jobs:
driver-opts: image=moby/buildkit:v0.10.6 driver-opts: image=moby/buildkit:v0.10.6
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
# https://github.com/docker/login-action/releases/tag/v3.4.0 uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build & push controller image - name: Build & push controller image
# https://github.com/docker/build-push-action/releases/tag/v6.18.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with: with:
file: Dockerfile file: Dockerfile
@@ -122,7 +119,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
# If inputs.ref is empty, it'll resolve to the default branch # If inputs.ref is empty, it'll resolve to the default branch
ref: ${{ inputs.ref }} ref: ${{ inputs.ref }}
@@ -141,8 +138,7 @@ jobs:
echo "repository_owner=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT echo "repository_owner=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
- name: Set up Helm - name: Set up Helm
# Using https://github.com/Azure/setup-helm/releases/tag/v4.2.0 uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814
with: with:
version: ${{ env.HELM_VERSION }} version: ${{ env.HELM_VERSION }}
@@ -170,7 +166,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
# If inputs.ref is empty, it'll resolve to the default branch # If inputs.ref is empty, it'll resolve to the default branch
ref: ${{ inputs.ref }} ref: ${{ inputs.ref }}
@@ -189,8 +185,7 @@ jobs:
echo "repository_owner=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT echo "repository_owner=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
- name: Set up Helm - name: Set up Helm
# Using https://github.com/Azure/setup-helm/releases/tag/v4.2.0 uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814
with: with:
version: ${{ env.HELM_VERSION }} version: ${{ env.HELM_VERSION }}

View File

@@ -36,24 +36,22 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up Helm - name: Set up Helm
# Using https://github.com/Azure/setup-helm/releases/tag/v4.2.0 uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814
with: with:
version: ${{ env.HELM_VERSION }} version: ${{ env.HELM_VERSION }}
# python is a requirement for the chart-testing action below (supports yamllint among other tests) # python is a requirement for the chart-testing action below (supports yamllint among other tests)
- uses: actions/setup-python@v5 - uses: actions/setup-python@v6
with: with:
python-version: "3.11" python-version: "3.11"
- name: Set up chart-testing - name: Set up chart-testing
# https://github.com/helm/chart-testing-action/releases/tag/v2.7.0 uses: helm/chart-testing-action@6ec842c01de15ebb84c8627d2744a0c2f2755c9f
uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b
- name: Run chart-testing (list-changed) - name: Run chart-testing (list-changed)
id: list-changed id: list-changed
@@ -69,13 +67,12 @@ jobs:
ct lint --config charts/.ci/ct-config-gha.yaml ct lint --config charts/.ci/ct-config-gha.yaml
- name: Set up docker buildx - name: Set up docker buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
if: steps.list-changed.outputs.changed == 'true' if: steps.list-changed.outputs.changed == 'true'
with: with:
version: latest version: latest
- name: Build controller image - name: Build controller image
# https://github.com/docker/build-push-action/releases/tag/v6.18.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
if: steps.list-changed.outputs.changed == 'true' if: steps.list-changed.outputs.changed == 'true'
with: with:
@@ -91,8 +88,7 @@ jobs:
cache-to: type=gha,mode=max cache-to: type=gha,mode=max
- name: Create kind cluster - name: Create kind cluster
# https://github.com/helm/kind-action/releases/tag/v1.12.0 uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3
if: steps.list-changed.outputs.changed == 'true' if: steps.list-changed.outputs.changed == 'true'
with: with:
cluster_name: chart-testing cluster_name: chart-testing
@@ -115,8 +111,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- uses: actions/setup-go@v5 - uses: actions/setup-go@v6
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
cache: false cache: false

View File

@@ -55,12 +55,11 @@ jobs:
TARGET_REPO: actions-runner-controller TARGET_REPO: actions-runner-controller
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Get Token - name: Get Token
id: get_workflow_token id: get_workflow_token
# https://github.com/peter-murray/workflow-application-token-action/releases/tag/v3.0.0 uses: peter-murray/workflow-application-token-action@d17e3a9a36850ea89f35db16c1067dd2b68ee343
uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3
with: with:
application_id: ${{ secrets.ACTIONS_ACCESS_APP_ID }} application_id: ${{ secrets.ACTIONS_ACCESS_APP_ID }}
application_private_key: ${{ secrets.ACTIONS_ACCESS_PK }} application_private_key: ${{ secrets.ACTIONS_ACCESS_PK }}
@@ -91,11 +90,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
# https://github.com/docker/login-action/releases/tag/v3.4.0 uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
@@ -112,18 +110,15 @@ jobs:
echo "repository_owner=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT echo "repository_owner=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
- name: Set up QEMU - name: Set up QEMU
# https://github.com/docker/setup-qemu-action/releases/tag/v3.6.0 uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392
- name: Set up Docker Buildx - name: Set up Docker Buildx
# https://github.com/docker/setup-buildx-action/releases/tag/v3.10.0 uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2
with: with:
version: latest version: latest
# Unstable builds - run at your own risk # Unstable builds - run at your own risk
- name: Build and Push - name: Build and Push
# https://github.com/docker/build-push-action/releases/tag/v6.18.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with: with:
context: . context: .

View File

@@ -25,20 +25,20 @@ jobs:
security-events: write security-events: write
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v6
with: with:
go-version-file: go.mod go-version-file: go.mod
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v2 uses: github/codeql-action/init@v4
with: with:
languages: go languages: go, actions
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v2 uses: github/codeql-action/autobuild@v4
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v4

View File

@@ -1,5 +1,10 @@
name: First Interaction name: First Interaction
permissions:
contents: read
issues: write
pull-requests: write
on: on:
issues: issues:
types: [opened] types: [opened]
@@ -11,19 +16,19 @@ jobs:
check_for_first_interaction: check_for_first_interaction:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: actions/first-interaction@main - uses: actions/first-interaction@v3
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
issue-message: | issue_message: |
Hello! Thank you for filing an issue. Hello! Thank you for filing an issue.
The maintainers will triage your issue shortly. The maintainers will triage your issue shortly.
In the meantime, please take a look at the [troubleshooting guide](https://github.com/actions/actions-runner-controller/blob/master/TROUBLESHOOTING.md) for bug reports. In the meantime, please take a look at the [troubleshooting guide](https://github.com/actions/actions-runner-controller/blob/master/TROUBLESHOOTING.md) for bug reports.
If this is a feature request, please review our [contribution guidelines](https://github.com/actions/actions-runner-controller/blob/master/CONTRIBUTING.md). If this is a feature request, please review our [contribution guidelines](https://github.com/actions/actions-runner-controller/blob/master/CONTRIBUTING.md).
pr-message: | pr_message: |
Hello! Thank you for your contribution. Hello! Thank you for your contribution.
Please review our [contribution guidelines](https://github.com/actions/actions-runner-controller/blob/master/CONTRIBUTING.md) to understand the project's testing and code conventions. Please review our [contribution guidelines](https://github.com/actions/actions-runner-controller/blob/master/CONTRIBUTING.md) to understand the project's testing and code conventions.

View File

@@ -14,7 +14,7 @@ jobs:
issues: write # for actions/stale to close stale issues issues: write # for actions/stale to close stale issues
pull-requests: write # for actions/stale to close stale PRs pull-requests: write # for actions/stale to close stale PRs
steps: steps:
- uses: actions/stale@v6 - uses: actions/stale@v10
with: with:
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.' stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
# turn off stale for both issues and PRs # turn off stale for both issues and PRs

View File

@@ -29,8 +29,8 @@ jobs:
fmt: fmt:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: actions/setup-go@v5 - uses: actions/setup-go@v6
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
cache: false cache: false
@@ -42,23 +42,22 @@ jobs:
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: actions/setup-go@v5 - uses: actions/setup-go@v6
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
cache: false cache: false
- name: golangci-lint - name: golangci-lint
# https://github.com/golangci/golangci-lint-action/releases/tag/v7.0.0 uses: golangci/golangci-lint-action@0a35821d5c230e903fcfe077583637dea1b27b47
uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd
with: with:
only-new-issues: true only-new-issues: true
version: v2.1.2 version: v2.5.0
generate: generate:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: actions/setup-go@v5 - uses: actions/setup-go@v6
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
cache: false cache: false
@@ -70,8 +69,8 @@ jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: actions/setup-go@v5 - uses: actions/setup-go@v6
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
- run: make manifests - run: make manifests
@@ -79,7 +78,7 @@ jobs:
run: git diff --exit-code run: git diff --exit-code
- name: Install kubebuilder - name: Install kubebuilder
run: | run: |
curl -D headers.txt -fsL "https://storage.googleapis.com/kubebuilder-tools/kubebuilder-tools-1.26.1-linux-amd64.tar.gz" -o kubebuilder-tools curl -D headers.txt -fsL "https://storage.googleapis.com/kubebuilder-tools/kubebuilder-tools-1.30.0-linux-amd64.tar.gz" -o kubebuilder-tools
echo "$(grep -i etag headers.txt -m 1 | cut -d'"' -f2) kubebuilder-tools" > sum echo "$(grep -i etag headers.txt -m 1 | cut -d'"' -f2) kubebuilder-tools" > sum
md5sum -c sum md5sum -c sum
tar -zvxf kubebuilder-tools tar -zvxf kubebuilder-tools

View File

@@ -1,2 +1,2 @@
# actions-runner-controller maintainers # actions-runner-controller maintainers
* @mumoshu @toast-gear @actions/actions-launch @nikola-jokic @rentziass * @mumoshu @toast-gear @actions/actions-launch @actions/actions-compute @nikola-jokic @rentziass

View File

@@ -1,5 +1,5 @@
# Build the manager binary # Build the manager binary
FROM --platform=$BUILDPLATFORM golang:1.24.3 AS builder FROM --platform=$BUILDPLATFORM golang:1.25.1 AS builder
WORKDIR /workspace WORKDIR /workspace

View File

@@ -6,7 +6,7 @@ endif
DOCKER_USER ?= $(shell echo ${DOCKER_IMAGE_NAME} | cut -d / -f1) DOCKER_USER ?= $(shell echo ${DOCKER_IMAGE_NAME} | cut -d / -f1)
VERSION ?= dev VERSION ?= dev
COMMIT_SHA = $(shell git rev-parse HEAD) COMMIT_SHA = $(shell git rev-parse HEAD)
RUNNER_VERSION ?= 2.325.0 RUNNER_VERSION ?= 2.330.0
TARGETPLATFORM ?= $(shell arch) TARGETPLATFORM ?= $(shell arch)
RUNNER_NAME ?= ${DOCKER_USER}/actions-runner RUNNER_NAME ?= ${DOCKER_USER}/actions-runner
RUNNER_TAG ?= ${VERSION} RUNNER_TAG ?= ${VERSION}
@@ -68,7 +68,7 @@ endif
all: manager all: manager
lint: lint:
docker run --rm -v $(PWD):/app -w /app golangci/golangci-lint:v2.1.2 golangci-lint run docker run --rm -v $(PWD):/app -w /app golangci/golangci-lint:v2.5.0 golangci-lint run
GO_TEST_ARGS ?= -short GO_TEST_ARGS ?= -short
@@ -117,9 +117,6 @@ manifests: manifests-gen-crds chart-crds
manifests-gen-crds: controller-gen yq manifests-gen-crds: controller-gen yq
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
for YAMLFILE in config/crd/bases/actions*.yaml; do \
$(YQ) '.spec.preserveUnknownFields = false' --inplace "$$YAMLFILE" ; \
done
make manifests-gen-crds-fix DELETE_KEY=x-kubernetes-list-type make manifests-gen-crds-fix DELETE_KEY=x-kubernetes-list-type
make manifests-gen-crds-fix DELETE_KEY=x-kubernetes-list-map-keys make manifests-gen-crds-fix DELETE_KEY=x-kubernetes-list-map-keys
@@ -213,8 +210,6 @@ docker-buildx:
docker buildx create --platform ${PLATFORMS} --name container-builder --use;\ docker buildx create --platform ${PLATFORMS} --name container-builder --use;\
fi fi
docker buildx build --platform ${PLATFORMS} \ docker buildx build --platform ${PLATFORMS} \
--build-arg RUNNER_VERSION=${RUNNER_VERSION} \
--build-arg DOCKER_VERSION=${DOCKER_VERSION} \
--build-arg VERSION=${VERSION} \ --build-arg VERSION=${VERSION} \
--build-arg COMMIT_SHA=${COMMIT_SHA} \ --build-arg COMMIT_SHA=${COMMIT_SHA} \
-t "${DOCKER_IMAGE_NAME}:${VERSION}" \ -t "${DOCKER_IMAGE_NAME}:${VERSION}" \
@@ -300,6 +295,10 @@ acceptance/runner/startup:
e2e: e2e:
go test -count=1 -v -timeout 600s -run '^TestE2E$$' ./test/e2e go test -count=1 -v -timeout 600s -run '^TestE2E$$' ./test/e2e
.PHONY: gha-e2e
gha-e2e:
bash hack/e2e-test.sh
# Upload release file to GitHub. # Upload release file to GitHub.
github-release: release github-release: release
ghr ${VERSION} release/ ghr ${VERSION} release/
@@ -310,7 +309,7 @@ github-release: release
# Otherwise we get errors like the below: # Otherwise we get errors like the below:
# Error: failed to install CRD crds/actions.summerwind.dev_runnersets.yaml: CustomResourceDefinition.apiextensions.k8s.io "runnersets.actions.summerwind.dev" is invalid: [spec.validation.openAPIV3Schema.properties[spec].properties[template].properties[spec].properties[containers].items.properties[ports].items.properties[protocol].default: Required value: this property is in x-kubernetes-list-map-keys, so it must have a default or be a required property, spec.validation.openAPIV3Schema.properties[spec].properties[template].properties[spec].properties[initContainers].items.properties[ports].items.properties[protocol].default: Required value: this property is in x-kubernetes-list-map-keys, so it must have a default or be a required property] # Error: failed to install CRD crds/actions.summerwind.dev_runnersets.yaml: CustomResourceDefinition.apiextensions.k8s.io "runnersets.actions.summerwind.dev" is invalid: [spec.validation.openAPIV3Schema.properties[spec].properties[template].properties[spec].properties[containers].items.properties[ports].items.properties[protocol].default: Required value: this property is in x-kubernetes-list-map-keys, so it must have a default or be a required property, spec.validation.openAPIV3Schema.properties[spec].properties[template].properties[spec].properties[initContainers].items.properties[ports].items.properties[protocol].default: Required value: this property is in x-kubernetes-list-map-keys, so it must have a default or be a required property]
# #
# Note that controller-gen newer than 0.7.0 is needed due to https://github.com/kubernetes-sigs/controller-tools/issues/448 # Note that controller-gen newer than 0.8.0 is needed due to https://github.com/kubernetes-sigs/controller-tools/issues/448
# Otherwise ObjectMeta embedded in Spec results in empty on the storage. # Otherwise ObjectMeta embedded in Spec results in empty on the storage.
controller-gen: controller-gen:
ifeq (, $(shell which controller-gen)) ifeq (, $(shell which controller-gen))
@@ -320,7 +319,7 @@ ifeq (, $(wildcard $(GOBIN)/controller-gen))
CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\ CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\
cd $$CONTROLLER_GEN_TMP_DIR ;\ cd $$CONTROLLER_GEN_TMP_DIR ;\
go mod init tmp ;\ go mod init tmp ;\
go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.17.2 ;\ go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.19.0 ;\
rm -rf $$CONTROLLER_GEN_TMP_DIR ;\ rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
} }
endif endif

View File

@@ -34,6 +34,7 @@ const EphemeralRunnerContainerName = "runner"
// +kubebuilder:printcolumn:JSONPath=".status.jobWorkflowRef",name=JobWorkflowRef,type=string // +kubebuilder:printcolumn:JSONPath=".status.jobWorkflowRef",name=JobWorkflowRef,type=string
// +kubebuilder:printcolumn:JSONPath=".status.workflowRunId",name=WorkflowRunId,type=number // +kubebuilder:printcolumn:JSONPath=".status.workflowRunId",name=WorkflowRunId,type=number
// +kubebuilder:printcolumn:JSONPath=".status.jobDisplayName",name=JobDisplayName,type=string // +kubebuilder:printcolumn:JSONPath=".status.jobDisplayName",name=JobDisplayName,type=string
// +kubebuilder:printcolumn:JSONPath=".status.jobId",name=JobId,type=string
// +kubebuilder:printcolumn:JSONPath=".status.message",name=Message,type=string // +kubebuilder:printcolumn:JSONPath=".status.message",name=Message,type=string
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
@@ -50,6 +51,10 @@ func (er *EphemeralRunner) IsDone() bool {
return er.Status.Phase == corev1.PodSucceeded || er.Status.Phase == corev1.PodFailed return er.Status.Phase == corev1.PodSucceeded || er.Status.Phase == corev1.PodFailed
} }
func (er *EphemeralRunner) HasJob() bool {
return len(er.Status.JobID) > 0
}
func (er *EphemeralRunner) HasContainerHookConfigured() bool { func (er *EphemeralRunner) HasContainerHookConfigured() bool {
for i := range er.Spec.Spec.Containers { for i := range er.Spec.Spec.Containers {
if er.Spec.Spec.Containers[i].Name != EphemeralRunnerContainerName { if er.Spec.Spec.Containers[i].Name != EphemeralRunnerContainerName {
@@ -145,8 +150,6 @@ type EphemeralRunnerStatus struct {
RunnerId int `json:"runnerId,omitempty"` RunnerId int `json:"runnerId,omitempty"`
// +optional // +optional
RunnerName string `json:"runnerName,omitempty"` RunnerName string `json:"runnerName,omitempty"`
// +optional
RunnerJITConfig string `json:"runnerJITConfig,omitempty"`
// +optional // +optional
Failures map[string]metav1.Time `json:"failures,omitempty"` Failures map[string]metav1.Time `json:"failures,omitempty"`
@@ -154,6 +157,9 @@ type EphemeralRunnerStatus struct {
// +optional // +optional
JobRequestId int64 `json:"jobRequestId,omitempty"` JobRequestId int64 `json:"jobRequestId,omitempty"`
// +optional
JobID string `json:"jobId,omitempty"`
// +optional // +optional
JobRepositoryName string `json:"jobRepositoryName,omitempty"` JobRepositoryName string `json:"jobRepositoryName,omitempty"`

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.17.2 controller-gen.kubebuilder.io/version: v0.19.0
name: horizontalrunnerautoscalers.actions.summerwind.dev name: horizontalrunnerautoscalers.actions.summerwind.dev
spec: spec:
group: actions.summerwind.dev group: actions.summerwind.dev
@@ -12,306 +12,313 @@ spec:
listKind: HorizontalRunnerAutoscalerList listKind: HorizontalRunnerAutoscalerList
plural: horizontalrunnerautoscalers plural: horizontalrunnerautoscalers
shortNames: shortNames:
- hra - hra
singular: horizontalrunnerautoscaler singular: horizontalrunnerautoscaler
scope: Namespaced scope: Namespaced
versions: versions:
- additionalPrinterColumns: - additionalPrinterColumns:
- jsonPath: .spec.minReplicas - jsonPath: .spec.minReplicas
name: Min name: Min
type: number type: number
- jsonPath: .spec.maxReplicas - jsonPath: .spec.maxReplicas
name: Max name: Max
type: number type: number
- jsonPath: .status.desiredReplicas - jsonPath: .status.desiredReplicas
name: Desired name: Desired
type: number type: number
- jsonPath: .status.scheduledOverridesSummary - jsonPath: .status.scheduledOverridesSummary
name: Schedule name: Schedule
type: string type: string
name: v1alpha1 name: v1alpha1
schema: schema:
openAPIV3Schema: openAPIV3Schema:
description: HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler API description: HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler
properties: API
apiVersion: properties:
description: |- apiVersion:
APIVersion defines the versioned schema of this representation of an object. description: |-
Servers should convert recognized schemas to the latest internal value, and APIVersion defines the versioned schema of this representation of an object.
may reject unrecognized values. Servers should convert recognized schemas to the latest internal value, and
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources may reject unrecognized values.
type: string More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
kind: type: string
description: |- kind:
Kind is a string value representing the REST resource this object represents. description: |-
Servers may infer this from the endpoint the client submits requests to. Kind is a string value representing the REST resource this object represents.
Cannot be updated. Servers may infer this from the endpoint the client submits requests to.
In CamelCase. Cannot be updated.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds In CamelCase.
type: string More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
metadata: type: string
type: object metadata:
spec: type: object
description: HorizontalRunnerAutoscalerSpec defines the desired state of HorizontalRunnerAutoscaler spec:
properties: description: HorizontalRunnerAutoscalerSpec defines the desired state
capacityReservations: of HorizontalRunnerAutoscaler
items: properties:
description: |- capacityReservations:
CapacityReservation specifies the number of replicas temporarily added items:
to the scale target until ExpirationTime.
properties:
effectiveTime:
format: date-time
type: string
expirationTime:
format: date-time
type: string
name:
type: string
replicas:
type: integer
type: object
type: array
githubAPICredentialsFrom:
properties:
secretRef:
properties:
name:
type: string
required:
- name
type: object
type: object
maxReplicas:
description: MaxReplicas is the maximum number of replicas the deployment is allowed to scale
type: integer
metrics:
description: Metrics is the collection of various metric targets to calculate desired number of runners
items:
properties:
repositoryNames:
description: |-
RepositoryNames is the list of repository names to be used for calculating the metric.
For example, a repository name is the REPO part of `github.com/USER/REPO`.
items:
type: string
type: array
scaleDownAdjustment:
description: |-
ScaleDownAdjustment is the number of runners removed on scale-down.
You can only specify either ScaleDownFactor or ScaleDownAdjustment.
type: integer
scaleDownFactor:
description: |-
ScaleDownFactor is the multiplicative factor applied to the current number of runners used
to determine how many pods should be removed.
type: string
scaleDownThreshold:
description: |-
ScaleDownThreshold is the percentage of busy runners less than which will
trigger the hpa to scale the runners down.
type: string
scaleUpAdjustment:
description: |-
ScaleUpAdjustment is the number of runners added on scale-up.
You can only specify either ScaleUpFactor or ScaleUpAdjustment.
type: integer
scaleUpFactor:
description: |-
ScaleUpFactor is the multiplicative factor applied to the current number of runners used
to determine how many pods should be added.
type: string
scaleUpThreshold:
description: |-
ScaleUpThreshold is the percentage of busy runners greater than which will
trigger the hpa to scale runners up.
type: string
type:
description: |-
Type is the type of metric to be used for autoscaling.
It can be TotalNumberOfQueuedAndInProgressWorkflowRuns or PercentageRunnersBusy.
type: string
type: object
type: array
minReplicas:
description: MinReplicas is the minimum number of replicas the deployment is allowed to scale
type: integer
scaleDownDelaySecondsAfterScaleOut:
description: |- description: |-
ScaleDownDelaySecondsAfterScaleUp is the approximate delay for a scale down followed by a scale up CapacityReservation specifies the number of replicas temporarily added
Used to prevent flapping (down->up->down->... loop) to the scale target until ExpirationTime.
type: integer
scaleTargetRef:
description: ScaleTargetRef is the reference to scaled resource like RunnerDeployment
properties: properties:
kind: effectiveTime:
description: Kind is the type of resource being referenced format: date-time
enum: type: string
- RunnerDeployment expirationTime:
- RunnerSet format: date-time
type: string type: string
name: name:
description: Name is the name of resource being referenced
type: string type: string
replicas:
type: integer
type: object type: object
scaleUpTriggers: type: array
description: |- githubAPICredentialsFrom:
ScaleUpTriggers is an experimental feature to increase the desired replicas by 1 properties:
on each webhook requested received by the webhookBasedAutoscaler. secretRef:
This feature requires you to also enable and deploy the webhookBasedAutoscaler onto your cluster.
Note that the added runners remain until the next sync period at least,
and they may or may not be used by GitHub Actions depending on the timing.
They are intended to be used to gain "resource slack" immediately after you
receive a webhook from GitHub, so that you can loosely expect MinReplicas runners to be always available.
items:
properties: properties:
amount: name:
type: integer
duration:
type: string
githubEvent:
properties:
checkRun:
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#check_run
properties:
names:
description: |-
Names is a list of GitHub Actions glob patterns.
Any check_run event whose name matches one of patterns in the list can trigger autoscaling.
Note that check_run name seem to equal to the job name you've defined in your actions workflow yaml file.
So it is very likely that you can utilize this to trigger depending on the job.
items:
type: string
type: array
repositories:
description: |-
Repositories is a list of GitHub repositories.
Any check_run event whose repository matches one of repositories in the list can trigger autoscaling.
items:
type: string
type: array
status:
type: string
types:
description: 'One of: created, rerequested, or completed'
items:
type: string
type: array
type: object
pullRequest:
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request
properties:
branches:
items:
type: string
type: array
types:
items:
type: string
type: array
type: object
push:
description: |-
PushSpec is the condition for triggering scale-up on push event
Also see https://docs.github.com/en/actions/reference/events-that-trigger-workflows#push
type: object
workflowJob:
description: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#workflow_job
type: object
type: object
type: object
type: array
scheduledOverrides:
description: |-
ScheduledOverrides is the list of ScheduledOverride.
It can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule.
The earlier a scheduled override is, the higher it is prioritized.
items:
description: |-
ScheduledOverride can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule.
A schedule can optionally be recurring, so that the corresponding override happens every day, week, month, or year.
properties:
endTime:
description: EndTime is the time at which the first override ends.
format: date-time
type: string
minReplicas:
description: |-
MinReplicas is the number of runners while overriding.
If omitted, it doesn't override minReplicas.
minimum: 0
nullable: true
type: integer
recurrenceRule:
properties:
frequency:
description: |-
Frequency is the name of a predefined interval of each recurrence.
The valid values are "Daily", "Weekly", "Monthly", and "Yearly".
If empty, the corresponding override happens only once.
enum:
- Daily
- Weekly
- Monthly
- Yearly
type: string
untilTime:
description: |-
UntilTime is the time of the final recurrence.
If empty, the schedule recurs forever.
format: date-time
type: string
type: object
startTime:
description: StartTime is the time at which the first override starts.
format: date-time
type: string type: string
required: required:
- endTime - name
- startTime
type: object type: object
type: array type: object
type: object maxReplicas:
status: description: MaxReplicas is the maximum number of replicas the deployment
properties: is allowed to scale
cacheEntries: type: integer
items: metrics:
properties: description: Metrics is the collection of various metric targets to
expirationTime: calculate desired number of runners
format: date-time items:
properties:
repositoryNames:
description: |-
RepositoryNames is the list of repository names to be used for calculating the metric.
For example, a repository name is the REPO part of `github.com/USER/REPO`.
items:
type: string type: string
key: type: array
type: string scaleDownAdjustment:
value: description: |-
type: integer ScaleDownAdjustment is the number of runners removed on scale-down.
type: object You can only specify either ScaleDownFactor or ScaleDownAdjustment.
type: array type: integer
desiredReplicas: scaleDownFactor:
description: |-
ScaleDownFactor is the multiplicative factor applied to the current number of runners used
to determine how many pods should be removed.
type: string
scaleDownThreshold:
description: |-
ScaleDownThreshold is the percentage of busy runners less than which will
trigger the hpa to scale the runners down.
type: string
scaleUpAdjustment:
description: |-
ScaleUpAdjustment is the number of runners added on scale-up.
You can only specify either ScaleUpFactor or ScaleUpAdjustment.
type: integer
scaleUpFactor:
description: |-
ScaleUpFactor is the multiplicative factor applied to the current number of runners used
to determine how many pods should be added.
type: string
scaleUpThreshold:
description: |-
ScaleUpThreshold is the percentage of busy runners greater than which will
trigger the hpa to scale runners up.
type: string
type:
description: |-
Type is the type of metric to be used for autoscaling.
It can be TotalNumberOfQueuedAndInProgressWorkflowRuns or PercentageRunnersBusy.
type: string
type: object
type: array
minReplicas:
description: MinReplicas is the minimum number of replicas the deployment
is allowed to scale
type: integer
scaleDownDelaySecondsAfterScaleOut:
description: |-
ScaleDownDelaySecondsAfterScaleUp is the approximate delay for a scale down followed by a scale up
Used to prevent flapping (down->up->down->... loop)
type: integer
scaleTargetRef:
description: ScaleTargetRef is the reference to scaled resource like
RunnerDeployment
properties:
kind:
description: Kind is the type of resource being referenced
enum:
- RunnerDeployment
- RunnerSet
type: string
name:
description: Name is the name of resource being referenced
type: string
type: object
scaleUpTriggers:
description: |-
ScaleUpTriggers is an experimental feature to increase the desired replicas by 1
on each webhook requested received by the webhookBasedAutoscaler.
This feature requires you to also enable and deploy the webhookBasedAutoscaler onto your cluster.
Note that the added runners remain until the next sync period at least,
and they may or may not be used by GitHub Actions depending on the timing.
They are intended to be used to gain "resource slack" immediately after you
receive a webhook from GitHub, so that you can loosely expect MinReplicas runners to be always available.
items:
properties:
amount:
type: integer
duration:
type: string
githubEvent:
properties:
checkRun:
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#check_run
properties:
names:
description: |-
Names is a list of GitHub Actions glob patterns.
Any check_run event whose name matches one of patterns in the list can trigger autoscaling.
Note that check_run name seem to equal to the job name you've defined in your actions workflow yaml file.
So it is very likely that you can utilize this to trigger depending on the job.
items:
type: string
type: array
repositories:
description: |-
Repositories is a list of GitHub repositories.
Any check_run event whose repository matches one of repositories in the list can trigger autoscaling.
items:
type: string
type: array
status:
type: string
types:
description: 'One of: created, rerequested, or completed'
items:
type: string
type: array
type: object
pullRequest:
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request
properties:
branches:
items:
type: string
type: array
types:
items:
type: string
type: array
type: object
push:
description: |-
PushSpec is the condition for triggering scale-up on push event
Also see https://docs.github.com/en/actions/reference/events-that-trigger-workflows#push
type: object
workflowJob:
description: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#workflow_job
type: object
type: object
type: object
type: array
scheduledOverrides:
description: |-
ScheduledOverrides is the list of ScheduledOverride.
It can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule.
The earlier a scheduled override is, the higher it is prioritized.
items:
description: |- description: |-
DesiredReplicas is the total number of desired, non-terminated and latest pods to be set for the primary RunnerSet ScheduledOverride can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule.
This doesn't include outdated pods while upgrading the deployment and replacing the runnerset. A schedule can optionally be recurring, so that the corresponding override happens every day, week, month, or year.
type: integer properties:
lastSuccessfulScaleOutTime: endTime:
format: date-time description: EndTime is the time at which the first override
nullable: true ends.
type: string format: date-time
observedGeneration: type: string
description: |- minReplicas:
ObservedGeneration is the most recent generation observed for the target. It corresponds to e.g. description: |-
RunnerDeployment's generation, which is updated on mutation by the API Server. MinReplicas is the number of runners while overriding.
format: int64 If omitted, it doesn't override minReplicas.
type: integer minimum: 0
scheduledOverridesSummary: nullable: true
description: |- type: integer
ScheduledOverridesSummary is the summary of active and upcoming scheduled overrides to be shown in e.g. a column of a `kubectl get hra` output recurrenceRule:
for observability. properties:
type: string frequency:
type: object description: |-
type: object Frequency is the name of a predefined interval of each recurrence.
served: true The valid values are "Daily", "Weekly", "Monthly", and "Yearly".
storage: true If empty, the corresponding override happens only once.
subresources: enum:
status: {} - Daily
preserveUnknownFields: false - Weekly
- Monthly
- Yearly
type: string
untilTime:
description: |-
UntilTime is the time of the final recurrence.
If empty, the schedule recurs forever.
format: date-time
type: string
type: object
startTime:
description: StartTime is the time at which the first override
starts.
format: date-time
type: string
required:
- endTime
- startTime
type: object
type: array
type: object
status:
properties:
cacheEntries:
items:
properties:
expirationTime:
format: date-time
type: string
key:
type: string
value:
type: integer
type: object
type: array
desiredReplicas:
description: |-
DesiredReplicas is the total number of desired, non-terminated and latest pods to be set for the primary RunnerSet
This doesn't include outdated pods while upgrading the deployment and replacing the runnerset.
type: integer
lastSuccessfulScaleOutTime:
format: date-time
nullable: true
type: string
observedGeneration:
description: |-
ObservedGeneration is the most recent generation observed for the target. It corresponds to e.g.
RunnerDeployment's generation, which is updated on mutation by the API Server.
format: int64
type: integer
scheduledOverridesSummary:
description: |-
ScheduledOverridesSummary is the summary of active and upcoming scheduled overrides to be shown in e.g. a column of a `kubectl get hra` output
for observability.
type: string
type: object
type: object
served: true
storage: true
subresources:
status: {}

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.17.2 controller-gen.kubebuilder.io/version: v0.19.0
name: runnersets.actions.summerwind.dev name: runnersets.actions.summerwind.dev
spec: spec:
group: actions.summerwind.dev group: actions.summerwind.dev
@@ -554,7 +554,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -569,7 +568,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -730,7 +728,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -745,7 +742,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -834,8 +830,8 @@ spec:
most preferred is the one with the greatest sum of weights, i.e. most preferred is the one with the greatest sum of weights, i.e.
for each node that meets all of the scheduling requirements (resource for each node that meets all of the scheduling requirements (resource
request, requiredDuringScheduling anti-affinity expressions, etc.), request, requiredDuringScheduling anti-affinity expressions, etc.),
compute a sum by iterating through the elements of this field and adding compute a sum by iterating through the elements of this field and subtracting
"weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
node(s) with the highest sum are the most preferred. node(s) with the highest sum are the most preferred.
items: items:
description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s)
@@ -899,7 +895,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -914,7 +909,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -1075,7 +1069,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -1090,7 +1083,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -1217,7 +1209,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -1271,6 +1265,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -1326,13 +1356,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -1352,7 +1382,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -1601,6 +1633,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: |- description: |-
@@ -1991,7 +2029,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -2042,10 +2080,10 @@ spec:
restartPolicy: restartPolicy:
description: |- description: |-
RestartPolicy defines the restart behavior of individual containers in a pod. RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always". This overrides the pod-level restart policy. When this field is not specified,
For non-init containers or when this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type. the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect: Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always" containers have completed, all init containers with restartPolicy "Always"
@@ -2057,6 +2095,57 @@ spec:
init container is started, or after any startupProbe has successfully init container is started, or after any startupProbe has successfully
completed. completed.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
SecurityContext defines the security options the container should be run with. SecurityContext defines the security options the container should be run with.
@@ -2654,7 +2743,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -2708,6 +2799,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -2763,13 +2890,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -2789,7 +2916,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -3034,6 +3163,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: Probes are not allowed for ephemeral containers. description: Probes are not allowed for ephemeral containers.
@@ -3407,7 +3542,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -3459,9 +3594,51 @@ spec:
description: |- description: |-
Restart policy for the container to manage the restart behavior of each Restart policy for the container to manage the restart behavior of each
container within a pod. container within a pod.
This may only be set for init containers. You cannot set this field on You cannot set this field on ephemeral containers.
ephemeral containers.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. You cannot set this field on
ephemeral containers.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
Optional: SecurityContext defines the security options the ephemeral container should be run with. Optional: SecurityContext defines the security options the ephemeral container should be run with.
@@ -3980,7 +4157,9 @@ spec:
hostNetwork: hostNetwork:
description: |- description: |-
Host networking requested for this pod. Use the host's network namespace. Host networking requested for this pod. Use the host's network namespace.
If this option is set, the ports that will be used must be specified. When using HostNetwork you should specify ports so the scheduler is aware.
When `hostNetwork` is true, specified `hostPort` fields in port definitions must match `containerPort`,
and unspecified `hostPort` fields in port definitions are defaulted to match `containerPort`.
Default to false. Default to false.
type: boolean type: boolean
hostPID: hostPID:
@@ -4005,6 +4184,19 @@ spec:
Specifies the hostname of the Pod Specifies the hostname of the Pod
If not specified, the pod's hostname will be set to a system-defined value. If not specified, the pod's hostname will be set to a system-defined value.
type: string type: string
hostnameOverride:
description: |-
HostnameOverride specifies an explicit override for the pod's hostname as perceived by the pod.
This field only specifies the pod's hostname and does not affect its DNS records.
When this field is set to a non-empty string:
- It takes precedence over the values set in `hostname` and `subdomain`.
- The Pod's hostname will be set to this value.
- `setHostnameAsFQDN` must be nil or set to false.
- `hostNetwork` must be set to false.
This field must be a valid DNS subdomain as defined in RFC 1123 and contain at most 64 characters.
Requires the HostnameOverride feature gate to be enabled.
type: string
imagePullSecrets: imagePullSecrets:
description: |- description: |-
ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
@@ -4040,7 +4232,7 @@ spec:
Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes.
The resourceRequirements of an init container are taken into account during scheduling The resourceRequirements of an init container are taken into account during scheduling
by finding the highest request/limit for each resource type, and then using the max of by finding the highest request/limit for each resource type, and then using the max of
of that value or the sum of the normal containers. Limits are applied to init containers that value or the sum of the normal containers. Limits are applied to init containers
in a similar fashion. in a similar fashion.
Init containers cannot currently be added or removed. Init containers cannot currently be added or removed.
Cannot be updated. Cannot be updated.
@@ -4084,7 +4276,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -4138,6 +4332,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -4193,13 +4423,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -4219,7 +4449,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -4468,6 +4700,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: |- description: |-
@@ -4858,7 +5096,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -4909,10 +5147,10 @@ spec:
restartPolicy: restartPolicy:
description: |- description: |-
RestartPolicy defines the restart behavior of individual containers in a pod. RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always". This overrides the pod-level restart policy. When this field is not specified,
For non-init containers or when this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type. the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect: Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always" containers have completed, all init containers with restartPolicy "Always"
@@ -4924,6 +5162,57 @@ spec:
init container is started, or after any startupProbe has successfully init container is started, or after any startupProbe has successfully
completed. completed.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
SecurityContext defines the security options the container should be run with. SecurityContext defines the security options the container should be run with.
@@ -5437,6 +5726,7 @@ spec:
- spec.hostPID - spec.hostPID
- spec.hostIPC - spec.hostIPC
- spec.hostUsers - spec.hostUsers
- spec.resources
- spec.securityContext.appArmorProfile - spec.securityContext.appArmorProfile
- spec.securityContext.seLinuxOptions - spec.securityContext.seLinuxOptions
- spec.securityContext.seccompProfile - spec.securityContext.seccompProfile
@@ -5588,7 +5878,7 @@ spec:
description: |- description: |-
Resources is the total amount of CPU and Memory resources required by all Resources is the total amount of CPU and Memory resources required by all
containers in the pod. It supports specifying Requests and Limits for containers in the pod. It supports specifying Requests and Limits for
"cpu" and "memory" resource names only. ResourceClaims are not supported. "cpu", "memory" and "hugepages-" resource names only. ResourceClaims are not supported.
This field enables fine-grained control over resource allocation for the This field enables fine-grained control over resource allocation for the
entire pod, allowing resource sharing among containers in a pod. entire pod, allowing resource sharing among containers in a pod.
@@ -5601,7 +5891,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -6126,7 +6416,6 @@ spec:
- Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.
If this value is nil, the behavior is equivalent to the Honor policy. If this value is nil, the behavior is equivalent to the Honor policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string type: string
nodeTaintsPolicy: nodeTaintsPolicy:
description: |- description: |-
@@ -6137,7 +6426,6 @@ spec:
- Ignore: node taints are ignored. All nodes are included. - Ignore: node taints are ignored. All nodes are included.
If this value is nil, the behavior is equivalent to the Ignore policy. If this value is nil, the behavior is equivalent to the Ignore policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string type: string
topologyKey: topologyKey:
description: |- description: |-
@@ -6843,15 +7131,13 @@ spec:
volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim.
If specified, the CSI driver will create or update the volume with the attributes defined If specified, the CSI driver will create or update the volume with the attributes defined
in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName,
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass it can be changed after the claim is created. An empty string or nil value indicates that no
will be applied to the claim but it's not allowed to reset this field to empty string once it is set. VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass this field can be reset to its previous value (including nil) to cancel the modification.
will be set by the persistentvolume controller if it exists.
If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be
set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource
exists. exists.
More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/
(Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default).
type: string type: string
volumeMode: volumeMode:
description: |- description: |-
@@ -7025,12 +7311,9 @@ spec:
description: |- description: |-
glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime.
Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported.
More info: https://examples.k8s.io/volumes/glusterfs/README.md
properties: properties:
endpoints: endpoints:
description: |- description: endpoints is the endpoint name that details Glusterfs topology.
endpoints is the endpoint name that details Glusterfs topology.
More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod
type: string type: string
path: path:
description: |- description: |-
@@ -7084,7 +7367,7 @@ spec:
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
The volume will be mounted read-only (ro) and non-executable files (noexec). The volume will be mounted read-only (ro) and non-executable files (noexec).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties: properties:
pullPolicy: pullPolicy:
@@ -7109,7 +7392,7 @@ spec:
description: |- description: |-
iscsi represents an ISCSI Disk resource that is attached to a iscsi represents an ISCSI Disk resource that is attached to a
kubelet's host machine and then exposed to the pod. kubelet's host machine and then exposed to the pod.
More info: https://examples.k8s.io/volumes/iscsi/README.md More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi
properties: properties:
chapAuthDiscovery: chapAuthDiscovery:
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
@@ -7499,6 +7782,110 @@ spec:
type: array type: array
x-kubernetes-list-type: atomic x-kubernetes-list-type: atomic
type: object type: object
podCertificate:
description: |-
Projects an auto-rotating credential bundle (private key and certificate
chain) that the pod can use either as a TLS client or server.
Kubelet generates a private key and uses it to send a
PodCertificateRequest to the named signer. Once the signer approves the
request and issues a certificate chain, Kubelet writes the key and
certificate chain to the pod filesystem. The pod does not start until
certificates have been issued for each podCertificate projected volume
source in its spec.
Kubelet will begin trying to rotate the certificate at the time indicated
by the signer using the PodCertificateRequest.Status.BeginRefreshAt
timestamp.
Kubelet can write a single file, indicated by the credentialBundlePath
field, or separate files, indicated by the keyPath and
certificateChainPath fields.
The credential bundle is a single file in PEM format. The first PEM
entry is the private key (in PKCS#8 format), and the remaining PEM
entries are the certificate chain issued by the signer (typically,
signers will return their certificate chain in leaf-to-root order).
Prefer using the credential bundle format, since your application code
can read it atomically. If you use keyPath and certificateChainPath,
your application must make two separate file reads. If these coincide
with a certificate rotation, it is possible that the private key and leaf
certificate you read may not correspond to each other. Your application
will need to check for this condition, and re-read until they are
consistent.
The named signer controls chooses the format of the certificate it
issues; consult the signer implementation's documentation to learn how to
use the certificates it issues.
properties:
certificateChainPath:
description: |-
Write the certificate chain at this path in the projected volume.
Most applications should use credentialBundlePath. When using keyPath
and certificateChainPath, your application needs to check that the key
and leaf certificate are consistent, because it is possible to read the
files mid-rotation.
type: string
credentialBundlePath:
description: |-
Write the credential bundle at this path in the projected volume.
The credential bundle is a single file that contains multiple PEM blocks.
The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private
key.
The remaining blocks are CERTIFICATE blocks, containing the issued
certificate chain from the signer (leaf and any intermediates).
Using credentialBundlePath lets your Pod's application code make a single
atomic read that retrieves a consistent key and certificate chain. If you
project them to separate files, your application code will need to
additionally check that the leaf certificate was issued to the key.
type: string
keyPath:
description: |-
Write the key at this path in the projected volume.
Most applications should use credentialBundlePath. When using keyPath
and certificateChainPath, your application needs to check that the key
and leaf certificate are consistent, because it is possible to read the
files mid-rotation.
type: string
keyType:
description: |-
The type of keypair Kubelet will generate for the pod.
Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384",
"ECDSAP521", and "ED25519".
type: string
maxExpirationSeconds:
description: |-
maxExpirationSeconds is the maximum lifetime permitted for the
certificate.
Kubelet copies this value verbatim into the PodCertificateRequests it
generates for this projection.
If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver
will reject values shorter than 3600 (1 hour). The maximum allowable
value is 7862400 (91 days).
The signer implementation is then free to issue a certificate with any
lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600
seconds (1 hour). This constraint is enforced by kube-apiserver.
`kubernetes.io` signers will never issue certificates with a lifetime
longer than 24 hours.
format: int32
type: integer
signerName:
description: Kubelet's generated CSRs will be addressed to this signer.
type: string
required:
- keyType
- signerName
type: object
secret: secret:
description: secret information about the secret data to project description: secret information about the secret data to project
properties: properties:
@@ -7628,7 +8015,6 @@ spec:
description: |- description: |-
rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. rbd represents a Rados Block Device mount on the host that shares a pod's lifetime.
Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported.
More info: https://examples.k8s.io/volumes/rbd/README.md
properties: properties:
fsType: fsType:
description: |- description: |-
@@ -8170,15 +8556,13 @@ spec:
volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim.
If specified, the CSI driver will create or update the volume with the attributes defined If specified, the CSI driver will create or update the volume with the attributes defined
in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName,
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass it can be changed after the claim is created. An empty string or nil value indicates that no
will be applied to the claim but it's not allowed to reset this field to empty string once it is set. VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass this field can be reset to its previous value (including nil) to cancel the modification.
will be set by the persistentvolume controller if it exists.
If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be
set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource
exists. exists.
More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/
(Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default).
type: string type: string
volumeMode: volumeMode:
description: |- description: |-
@@ -8278,13 +8662,11 @@ spec:
description: |- description: |-
currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using.
When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim
This is a beta field and requires enabling VolumeAttributesClass feature (off by default).
type: string type: string
modifyVolumeStatus: modifyVolumeStatus:
description: |- description: |-
ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. ModifyVolumeStatus represents the status object of ControllerModifyVolume operation.
When this is unset, there is no ModifyVolume operation being attempted. When this is unset, there is no ModifyVolume operation being attempted.
This is a beta field and requires enabling VolumeAttributesClass feature (off by default).
properties: properties:
status: status:
description: "status is the status of the ControllerModifyVolume operation. It can be in any of following states:\n - Pending\n Pending indicates that the PersistentVolumeClaim cannot be modified due to unmet requirements, such as\n the specified VolumeAttributesClass not existing.\n - InProgress\n InProgress indicates that the volume is being modified.\n - Infeasible\n Infeasible indicates that the request has been rejected as invalid by the CSI driver. To\n\t resolve the error, a valid VolumeAttributesClass needs to be specified.\nNote: New statuses can be added in the future. Consumers should check for unknown statuses and fail appropriately." description: "status is the status of the ControllerModifyVolume operation. It can be in any of following states:\n - Pending\n Pending indicates that the PersistentVolumeClaim cannot be modified due to unmet requirements, such as\n the specified VolumeAttributesClass not existing.\n - InProgress\n InProgress indicates that the volume is being modified.\n - Infeasible\n Infeasible indicates that the request has been rejected as invalid by the CSI driver. To\n\t resolve the error, a valid VolumeAttributesClass needs to be specified.\nNote: New statuses can be added in the future. Consumers should check for unknown statuses and fail appropriately."
@@ -8355,7 +8737,6 @@ spec:
type: object type: object
required: required:
- selector - selector
- serviceName
- template - template
type: object type: object
status: status:
@@ -8389,4 +8770,3 @@ spec:
storage: true storage: true
subresources: subresources:
status: {} status: {}
preserveUnknownFields: false

View File

@@ -15,13 +15,13 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes # 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. # to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/) # Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.12.1 version: 0.13.0
# This is the version number of the application being deployed. This version number should be # 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 # 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. # follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes. # It is recommended to use it with quotes.
appVersion: "0.12.1" appVersion: "0.13.0"
home: https://github.com/actions/actions-runner-controller home: https://github.com/actions/actions-runner-controller

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.17.2 controller-gen.kubebuilder.io/version: v0.19.0
name: ephemeralrunners.actions.github.com name: ephemeralrunners.actions.github.com
spec: spec:
group: actions.github.com group: actions.github.com
@@ -36,6 +36,9 @@ spec:
- jsonPath: .status.jobDisplayName - jsonPath: .status.jobDisplayName
name: JobDisplayName name: JobDisplayName
type: string type: string
- jsonPath: .status.jobId
name: JobId
type: string
- jsonPath: .status.message - jsonPath: .status.message
name: Message name: Message
type: string type: string
@@ -427,7 +430,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -442,7 +444,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -603,7 +604,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -618,7 +618,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -707,8 +706,8 @@ spec:
most preferred is the one with the greatest sum of weights, i.e. most preferred is the one with the greatest sum of weights, i.e.
for each node that meets all of the scheduling requirements (resource for each node that meets all of the scheduling requirements (resource
request, requiredDuringScheduling anti-affinity expressions, etc.), request, requiredDuringScheduling anti-affinity expressions, etc.),
compute a sum by iterating through the elements of this field and adding compute a sum by iterating through the elements of this field and subtracting
"weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
node(s) with the highest sum are the most preferred. node(s) with the highest sum are the most preferred.
items: items:
description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s)
@@ -772,7 +771,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -787,7 +785,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -948,7 +945,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -963,7 +959,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -1090,7 +1085,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -1144,6 +1141,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -1199,13 +1232,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -1225,7 +1258,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -1474,6 +1509,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: |- description: |-
@@ -1864,7 +1905,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -1915,10 +1956,10 @@ spec:
restartPolicy: restartPolicy:
description: |- description: |-
RestartPolicy defines the restart behavior of individual containers in a pod. RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always". This overrides the pod-level restart policy. When this field is not specified,
For non-init containers or when this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type. the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect: Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always" containers have completed, all init containers with restartPolicy "Always"
@@ -1930,6 +1971,57 @@ spec:
init container is started, or after any startupProbe has successfully init container is started, or after any startupProbe has successfully
completed. completed.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
SecurityContext defines the security options the container should be run with. SecurityContext defines the security options the container should be run with.
@@ -2527,7 +2619,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -2581,6 +2675,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -2636,13 +2766,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -2662,7 +2792,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -2907,6 +3039,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: Probes are not allowed for ephemeral containers. description: Probes are not allowed for ephemeral containers.
@@ -3280,7 +3418,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -3332,9 +3470,51 @@ spec:
description: |- description: |-
Restart policy for the container to manage the restart behavior of each Restart policy for the container to manage the restart behavior of each
container within a pod. container within a pod.
This may only be set for init containers. You cannot set this field on You cannot set this field on ephemeral containers.
ephemeral containers.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. You cannot set this field on
ephemeral containers.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
Optional: SecurityContext defines the security options the ephemeral container should be run with. Optional: SecurityContext defines the security options the ephemeral container should be run with.
@@ -3853,7 +4033,9 @@ spec:
hostNetwork: hostNetwork:
description: |- description: |-
Host networking requested for this pod. Use the host's network namespace. Host networking requested for this pod. Use the host's network namespace.
If this option is set, the ports that will be used must be specified. When using HostNetwork you should specify ports so the scheduler is aware.
When `hostNetwork` is true, specified `hostPort` fields in port definitions must match `containerPort`,
and unspecified `hostPort` fields in port definitions are defaulted to match `containerPort`.
Default to false. Default to false.
type: boolean type: boolean
hostPID: hostPID:
@@ -3878,6 +4060,19 @@ spec:
Specifies the hostname of the Pod Specifies the hostname of the Pod
If not specified, the pod's hostname will be set to a system-defined value. If not specified, the pod's hostname will be set to a system-defined value.
type: string type: string
hostnameOverride:
description: |-
HostnameOverride specifies an explicit override for the pod's hostname as perceived by the pod.
This field only specifies the pod's hostname and does not affect its DNS records.
When this field is set to a non-empty string:
- It takes precedence over the values set in `hostname` and `subdomain`.
- The Pod's hostname will be set to this value.
- `setHostnameAsFQDN` must be nil or set to false.
- `hostNetwork` must be set to false.
This field must be a valid DNS subdomain as defined in RFC 1123 and contain at most 64 characters.
Requires the HostnameOverride feature gate to be enabled.
type: string
imagePullSecrets: imagePullSecrets:
description: |- description: |-
ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
@@ -3913,7 +4108,7 @@ spec:
Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes.
The resourceRequirements of an init container are taken into account during scheduling The resourceRequirements of an init container are taken into account during scheduling
by finding the highest request/limit for each resource type, and then using the max of by finding the highest request/limit for each resource type, and then using the max of
of that value or the sum of the normal containers. Limits are applied to init containers that value or the sum of the normal containers. Limits are applied to init containers
in a similar fashion. in a similar fashion.
Init containers cannot currently be added or removed. Init containers cannot currently be added or removed.
Cannot be updated. Cannot be updated.
@@ -3957,7 +4152,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -4011,6 +4208,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -4066,13 +4299,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -4092,7 +4325,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -4341,6 +4576,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: |- description: |-
@@ -4731,7 +4972,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -4782,10 +5023,10 @@ spec:
restartPolicy: restartPolicy:
description: |- description: |-
RestartPolicy defines the restart behavior of individual containers in a pod. RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always". This overrides the pod-level restart policy. When this field is not specified,
For non-init containers or when this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type. the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect: Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always" containers have completed, all init containers with restartPolicy "Always"
@@ -4797,6 +5038,57 @@ spec:
init container is started, or after any startupProbe has successfully init container is started, or after any startupProbe has successfully
completed. completed.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
SecurityContext defines the security options the container should be run with. SecurityContext defines the security options the container should be run with.
@@ -5310,6 +5602,7 @@ spec:
- spec.hostPID - spec.hostPID
- spec.hostIPC - spec.hostIPC
- spec.hostUsers - spec.hostUsers
- spec.resources
- spec.securityContext.appArmorProfile - spec.securityContext.appArmorProfile
- spec.securityContext.seLinuxOptions - spec.securityContext.seLinuxOptions
- spec.securityContext.seccompProfile - spec.securityContext.seccompProfile
@@ -5461,7 +5754,7 @@ spec:
description: |- description: |-
Resources is the total amount of CPU and Memory resources required by all Resources is the total amount of CPU and Memory resources required by all
containers in the pod. It supports specifying Requests and Limits for containers in the pod. It supports specifying Requests and Limits for
"cpu" and "memory" resource names only. ResourceClaims are not supported. "cpu", "memory" and "hugepages-" resource names only. ResourceClaims are not supported.
This field enables fine-grained control over resource allocation for the This field enables fine-grained control over resource allocation for the
entire pod, allowing resource sharing among containers in a pod. entire pod, allowing resource sharing among containers in a pod.
@@ -5474,7 +5767,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -6002,7 +6295,6 @@ spec:
- Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.
If this value is nil, the behavior is equivalent to the Honor policy. If this value is nil, the behavior is equivalent to the Honor policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string type: string
nodeTaintsPolicy: nodeTaintsPolicy:
description: |- description: |-
@@ -6013,7 +6305,6 @@ spec:
- Ignore: node taints are ignored. All nodes are included. - Ignore: node taints are ignored. All nodes are included.
If this value is nil, the behavior is equivalent to the Ignore policy. If this value is nil, the behavior is equivalent to the Ignore policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string type: string
topologyKey: topologyKey:
description: |- description: |-
@@ -6719,15 +7010,13 @@ spec:
volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim.
If specified, the CSI driver will create or update the volume with the attributes defined If specified, the CSI driver will create or update the volume with the attributes defined
in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName,
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass it can be changed after the claim is created. An empty string or nil value indicates that no
will be applied to the claim but it's not allowed to reset this field to empty string once it is set. VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass this field can be reset to its previous value (including nil) to cancel the modification.
will be set by the persistentvolume controller if it exists.
If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be
set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource
exists. exists.
More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/
(Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default).
type: string type: string
volumeMode: volumeMode:
description: |- description: |-
@@ -6901,12 +7190,9 @@ spec:
description: |- description: |-
glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime.
Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported.
More info: https://examples.k8s.io/volumes/glusterfs/README.md
properties: properties:
endpoints: endpoints:
description: |- description: endpoints is the endpoint name that details Glusterfs topology.
endpoints is the endpoint name that details Glusterfs topology.
More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod
type: string type: string
path: path:
description: |- description: |-
@@ -6960,7 +7246,7 @@ spec:
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
The volume will be mounted read-only (ro) and non-executable files (noexec). The volume will be mounted read-only (ro) and non-executable files (noexec).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties: properties:
pullPolicy: pullPolicy:
@@ -6985,7 +7271,7 @@ spec:
description: |- description: |-
iscsi represents an ISCSI Disk resource that is attached to a iscsi represents an ISCSI Disk resource that is attached to a
kubelet's host machine and then exposed to the pod. kubelet's host machine and then exposed to the pod.
More info: https://examples.k8s.io/volumes/iscsi/README.md More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi
properties: properties:
chapAuthDiscovery: chapAuthDiscovery:
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
@@ -7375,6 +7661,110 @@ spec:
type: array type: array
x-kubernetes-list-type: atomic x-kubernetes-list-type: atomic
type: object type: object
podCertificate:
description: |-
Projects an auto-rotating credential bundle (private key and certificate
chain) that the pod can use either as a TLS client or server.
Kubelet generates a private key and uses it to send a
PodCertificateRequest to the named signer. Once the signer approves the
request and issues a certificate chain, Kubelet writes the key and
certificate chain to the pod filesystem. The pod does not start until
certificates have been issued for each podCertificate projected volume
source in its spec.
Kubelet will begin trying to rotate the certificate at the time indicated
by the signer using the PodCertificateRequest.Status.BeginRefreshAt
timestamp.
Kubelet can write a single file, indicated by the credentialBundlePath
field, or separate files, indicated by the keyPath and
certificateChainPath fields.
The credential bundle is a single file in PEM format. The first PEM
entry is the private key (in PKCS#8 format), and the remaining PEM
entries are the certificate chain issued by the signer (typically,
signers will return their certificate chain in leaf-to-root order).
Prefer using the credential bundle format, since your application code
can read it atomically. If you use keyPath and certificateChainPath,
your application must make two separate file reads. If these coincide
with a certificate rotation, it is possible that the private key and leaf
certificate you read may not correspond to each other. Your application
will need to check for this condition, and re-read until they are
consistent.
The named signer controls chooses the format of the certificate it
issues; consult the signer implementation's documentation to learn how to
use the certificates it issues.
properties:
certificateChainPath:
description: |-
Write the certificate chain at this path in the projected volume.
Most applications should use credentialBundlePath. When using keyPath
and certificateChainPath, your application needs to check that the key
and leaf certificate are consistent, because it is possible to read the
files mid-rotation.
type: string
credentialBundlePath:
description: |-
Write the credential bundle at this path in the projected volume.
The credential bundle is a single file that contains multiple PEM blocks.
The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private
key.
The remaining blocks are CERTIFICATE blocks, containing the issued
certificate chain from the signer (leaf and any intermediates).
Using credentialBundlePath lets your Pod's application code make a single
atomic read that retrieves a consistent key and certificate chain. If you
project them to separate files, your application code will need to
additionally check that the leaf certificate was issued to the key.
type: string
keyPath:
description: |-
Write the key at this path in the projected volume.
Most applications should use credentialBundlePath. When using keyPath
and certificateChainPath, your application needs to check that the key
and leaf certificate are consistent, because it is possible to read the
files mid-rotation.
type: string
keyType:
description: |-
The type of keypair Kubelet will generate for the pod.
Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384",
"ECDSAP521", and "ED25519".
type: string
maxExpirationSeconds:
description: |-
maxExpirationSeconds is the maximum lifetime permitted for the
certificate.
Kubelet copies this value verbatim into the PodCertificateRequests it
generates for this projection.
If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver
will reject values shorter than 3600 (1 hour). The maximum allowable
value is 7862400 (91 days).
The signer implementation is then free to issue a certificate with any
lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600
seconds (1 hour). This constraint is enforced by kube-apiserver.
`kubernetes.io` signers will never issue certificates with a lifetime
longer than 24 hours.
format: int32
type: integer
signerName:
description: Kubelet's generated CSRs will be addressed to this signer.
type: string
required:
- keyType
- signerName
type: object
secret: secret:
description: secret information about the secret data to project description: secret information about the secret data to project
properties: properties:
@@ -7504,7 +7894,6 @@ spec:
description: |- description: |-
rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. rbd represents a Rados Block Device mount on the host that shares a pod's lifetime.
Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported.
More info: https://examples.k8s.io/volumes/rbd/README.md
properties: properties:
fsType: fsType:
description: |- description: |-
@@ -7846,6 +8235,8 @@ spec:
type: object type: object
jobDisplayName: jobDisplayName:
type: string type: string
jobId:
type: string
jobRepositoryName: jobRepositoryName:
type: string type: string
jobRequestId: jobRequestId:
@@ -7874,8 +8265,6 @@ spec:
type: string type: string
runnerId: runnerId:
type: integer type: integer
runnerJITConfig:
type: string
runnerName: runnerName:
type: string type: string
workflowRunId: workflowRunId:
@@ -7887,4 +8276,3 @@ spec:
storage: true storage: true
subresources: subresources:
status: {} status: {}
preserveUnknownFields: false

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.17.2 controller-gen.kubebuilder.io/version: v0.19.0
name: ephemeralrunnersets.actions.github.com name: ephemeralrunnersets.actions.github.com
spec: spec:
group: actions.github.com group: actions.github.com
@@ -421,7 +421,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -436,7 +435,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -597,7 +595,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -612,7 +609,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -701,8 +697,8 @@ spec:
most preferred is the one with the greatest sum of weights, i.e. most preferred is the one with the greatest sum of weights, i.e.
for each node that meets all of the scheduling requirements (resource for each node that meets all of the scheduling requirements (resource
request, requiredDuringScheduling anti-affinity expressions, etc.), request, requiredDuringScheduling anti-affinity expressions, etc.),
compute a sum by iterating through the elements of this field and adding compute a sum by iterating through the elements of this field and subtracting
"weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
node(s) with the highest sum are the most preferred. node(s) with the highest sum are the most preferred.
items: items:
description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s)
@@ -766,7 +762,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -781,7 +776,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -942,7 +936,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -957,7 +950,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -1084,7 +1076,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -1138,6 +1132,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -1193,13 +1223,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -1219,7 +1249,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -1468,6 +1500,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: |- description: |-
@@ -1858,7 +1896,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -1909,10 +1947,10 @@ spec:
restartPolicy: restartPolicy:
description: |- description: |-
RestartPolicy defines the restart behavior of individual containers in a pod. RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always". This overrides the pod-level restart policy. When this field is not specified,
For non-init containers or when this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type. the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect: Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always" containers have completed, all init containers with restartPolicy "Always"
@@ -1924,6 +1962,57 @@ spec:
init container is started, or after any startupProbe has successfully init container is started, or after any startupProbe has successfully
completed. completed.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
SecurityContext defines the security options the container should be run with. SecurityContext defines the security options the container should be run with.
@@ -2521,7 +2610,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -2575,6 +2666,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -2630,13 +2757,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -2656,7 +2783,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -2901,6 +3030,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: Probes are not allowed for ephemeral containers. description: Probes are not allowed for ephemeral containers.
@@ -3274,7 +3409,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -3326,9 +3461,51 @@ spec:
description: |- description: |-
Restart policy for the container to manage the restart behavior of each Restart policy for the container to manage the restart behavior of each
container within a pod. container within a pod.
This may only be set for init containers. You cannot set this field on You cannot set this field on ephemeral containers.
ephemeral containers.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. You cannot set this field on
ephemeral containers.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
Optional: SecurityContext defines the security options the ephemeral container should be run with. Optional: SecurityContext defines the security options the ephemeral container should be run with.
@@ -3847,7 +4024,9 @@ spec:
hostNetwork: hostNetwork:
description: |- description: |-
Host networking requested for this pod. Use the host's network namespace. Host networking requested for this pod. Use the host's network namespace.
If this option is set, the ports that will be used must be specified. When using HostNetwork you should specify ports so the scheduler is aware.
When `hostNetwork` is true, specified `hostPort` fields in port definitions must match `containerPort`,
and unspecified `hostPort` fields in port definitions are defaulted to match `containerPort`.
Default to false. Default to false.
type: boolean type: boolean
hostPID: hostPID:
@@ -3872,6 +4051,19 @@ spec:
Specifies the hostname of the Pod Specifies the hostname of the Pod
If not specified, the pod's hostname will be set to a system-defined value. If not specified, the pod's hostname will be set to a system-defined value.
type: string type: string
hostnameOverride:
description: |-
HostnameOverride specifies an explicit override for the pod's hostname as perceived by the pod.
This field only specifies the pod's hostname and does not affect its DNS records.
When this field is set to a non-empty string:
- It takes precedence over the values set in `hostname` and `subdomain`.
- The Pod's hostname will be set to this value.
- `setHostnameAsFQDN` must be nil or set to false.
- `hostNetwork` must be set to false.
This field must be a valid DNS subdomain as defined in RFC 1123 and contain at most 64 characters.
Requires the HostnameOverride feature gate to be enabled.
type: string
imagePullSecrets: imagePullSecrets:
description: |- description: |-
ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
@@ -3907,7 +4099,7 @@ spec:
Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes.
The resourceRequirements of an init container are taken into account during scheduling The resourceRequirements of an init container are taken into account during scheduling
by finding the highest request/limit for each resource type, and then using the max of by finding the highest request/limit for each resource type, and then using the max of
of that value or the sum of the normal containers. Limits are applied to init containers that value or the sum of the normal containers. Limits are applied to init containers
in a similar fashion. in a similar fashion.
Init containers cannot currently be added or removed. Init containers cannot currently be added or removed.
Cannot be updated. Cannot be updated.
@@ -3951,7 +4143,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -4005,6 +4199,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -4060,13 +4290,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -4086,7 +4316,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -4335,6 +4567,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: |- description: |-
@@ -4725,7 +4963,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -4776,10 +5014,10 @@ spec:
restartPolicy: restartPolicy:
description: |- description: |-
RestartPolicy defines the restart behavior of individual containers in a pod. RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always". This overrides the pod-level restart policy. When this field is not specified,
For non-init containers or when this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type. the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect: Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always" containers have completed, all init containers with restartPolicy "Always"
@@ -4791,6 +5029,57 @@ spec:
init container is started, or after any startupProbe has successfully init container is started, or after any startupProbe has successfully
completed. completed.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
SecurityContext defines the security options the container should be run with. SecurityContext defines the security options the container should be run with.
@@ -5304,6 +5593,7 @@ spec:
- spec.hostPID - spec.hostPID
- spec.hostIPC - spec.hostIPC
- spec.hostUsers - spec.hostUsers
- spec.resources
- spec.securityContext.appArmorProfile - spec.securityContext.appArmorProfile
- spec.securityContext.seLinuxOptions - spec.securityContext.seLinuxOptions
- spec.securityContext.seccompProfile - spec.securityContext.seccompProfile
@@ -5455,7 +5745,7 @@ spec:
description: |- description: |-
Resources is the total amount of CPU and Memory resources required by all Resources is the total amount of CPU and Memory resources required by all
containers in the pod. It supports specifying Requests and Limits for containers in the pod. It supports specifying Requests and Limits for
"cpu" and "memory" resource names only. ResourceClaims are not supported. "cpu", "memory" and "hugepages-" resource names only. ResourceClaims are not supported.
This field enables fine-grained control over resource allocation for the This field enables fine-grained control over resource allocation for the
entire pod, allowing resource sharing among containers in a pod. entire pod, allowing resource sharing among containers in a pod.
@@ -5468,7 +5758,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -5996,7 +6286,6 @@ spec:
- Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.
If this value is nil, the behavior is equivalent to the Honor policy. If this value is nil, the behavior is equivalent to the Honor policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string type: string
nodeTaintsPolicy: nodeTaintsPolicy:
description: |- description: |-
@@ -6007,7 +6296,6 @@ spec:
- Ignore: node taints are ignored. All nodes are included. - Ignore: node taints are ignored. All nodes are included.
If this value is nil, the behavior is equivalent to the Ignore policy. If this value is nil, the behavior is equivalent to the Ignore policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string type: string
topologyKey: topologyKey:
description: |- description: |-
@@ -6713,15 +7001,13 @@ spec:
volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim.
If specified, the CSI driver will create or update the volume with the attributes defined If specified, the CSI driver will create or update the volume with the attributes defined
in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName,
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass it can be changed after the claim is created. An empty string or nil value indicates that no
will be applied to the claim but it's not allowed to reset this field to empty string once it is set. VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass this field can be reset to its previous value (including nil) to cancel the modification.
will be set by the persistentvolume controller if it exists.
If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be
set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource
exists. exists.
More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/
(Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default).
type: string type: string
volumeMode: volumeMode:
description: |- description: |-
@@ -6895,12 +7181,9 @@ spec:
description: |- description: |-
glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime.
Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported.
More info: https://examples.k8s.io/volumes/glusterfs/README.md
properties: properties:
endpoints: endpoints:
description: |- description: endpoints is the endpoint name that details Glusterfs topology.
endpoints is the endpoint name that details Glusterfs topology.
More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod
type: string type: string
path: path:
description: |- description: |-
@@ -6954,7 +7237,7 @@ spec:
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
The volume will be mounted read-only (ro) and non-executable files (noexec). The volume will be mounted read-only (ro) and non-executable files (noexec).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties: properties:
pullPolicy: pullPolicy:
@@ -6979,7 +7262,7 @@ spec:
description: |- description: |-
iscsi represents an ISCSI Disk resource that is attached to a iscsi represents an ISCSI Disk resource that is attached to a
kubelet's host machine and then exposed to the pod. kubelet's host machine and then exposed to the pod.
More info: https://examples.k8s.io/volumes/iscsi/README.md More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi
properties: properties:
chapAuthDiscovery: chapAuthDiscovery:
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
@@ -7369,6 +7652,110 @@ spec:
type: array type: array
x-kubernetes-list-type: atomic x-kubernetes-list-type: atomic
type: object type: object
podCertificate:
description: |-
Projects an auto-rotating credential bundle (private key and certificate
chain) that the pod can use either as a TLS client or server.
Kubelet generates a private key and uses it to send a
PodCertificateRequest to the named signer. Once the signer approves the
request and issues a certificate chain, Kubelet writes the key and
certificate chain to the pod filesystem. The pod does not start until
certificates have been issued for each podCertificate projected volume
source in its spec.
Kubelet will begin trying to rotate the certificate at the time indicated
by the signer using the PodCertificateRequest.Status.BeginRefreshAt
timestamp.
Kubelet can write a single file, indicated by the credentialBundlePath
field, or separate files, indicated by the keyPath and
certificateChainPath fields.
The credential bundle is a single file in PEM format. The first PEM
entry is the private key (in PKCS#8 format), and the remaining PEM
entries are the certificate chain issued by the signer (typically,
signers will return their certificate chain in leaf-to-root order).
Prefer using the credential bundle format, since your application code
can read it atomically. If you use keyPath and certificateChainPath,
your application must make two separate file reads. If these coincide
with a certificate rotation, it is possible that the private key and leaf
certificate you read may not correspond to each other. Your application
will need to check for this condition, and re-read until they are
consistent.
The named signer controls chooses the format of the certificate it
issues; consult the signer implementation's documentation to learn how to
use the certificates it issues.
properties:
certificateChainPath:
description: |-
Write the certificate chain at this path in the projected volume.
Most applications should use credentialBundlePath. When using keyPath
and certificateChainPath, your application needs to check that the key
and leaf certificate are consistent, because it is possible to read the
files mid-rotation.
type: string
credentialBundlePath:
description: |-
Write the credential bundle at this path in the projected volume.
The credential bundle is a single file that contains multiple PEM blocks.
The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private
key.
The remaining blocks are CERTIFICATE blocks, containing the issued
certificate chain from the signer (leaf and any intermediates).
Using credentialBundlePath lets your Pod's application code make a single
atomic read that retrieves a consistent key and certificate chain. If you
project them to separate files, your application code will need to
additionally check that the leaf certificate was issued to the key.
type: string
keyPath:
description: |-
Write the key at this path in the projected volume.
Most applications should use credentialBundlePath. When using keyPath
and certificateChainPath, your application needs to check that the key
and leaf certificate are consistent, because it is possible to read the
files mid-rotation.
type: string
keyType:
description: |-
The type of keypair Kubelet will generate for the pod.
Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384",
"ECDSAP521", and "ED25519".
type: string
maxExpirationSeconds:
description: |-
maxExpirationSeconds is the maximum lifetime permitted for the
certificate.
Kubelet copies this value verbatim into the PodCertificateRequests it
generates for this projection.
If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver
will reject values shorter than 3600 (1 hour). The maximum allowable
value is 7862400 (91 days).
The signer implementation is then free to issue a certificate with any
lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600
seconds (1 hour). This constraint is enforced by kube-apiserver.
`kubernetes.io` signers will never issue certificates with a lifetime
longer than 24 hours.
format: int32
type: integer
signerName:
description: Kubelet's generated CSRs will be addressed to this signer.
type: string
required:
- keyType
- signerName
type: object
secret: secret:
description: secret information about the secret data to project description: secret information about the secret data to project
properties: properties:
@@ -7498,7 +7885,6 @@ spec:
description: |- description: |-
rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. rbd represents a Rados Block Device mount on the host that shares a pod's lifetime.
Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported.
More info: https://examples.k8s.io/volumes/rbd/README.md
properties: properties:
fsType: fsType:
description: |- description: |-
@@ -7859,4 +8245,3 @@ spec:
storage: true storage: true
subresources: subresources:
status: {} status: {}
preserveUnknownFields: false

View File

@@ -129,11 +129,3 @@ Create the name of the service account to use
{{- define "gha-runner-scale-set-controller.leaderElectionRoleBinding" -}} {{- define "gha-runner-scale-set-controller.leaderElectionRoleBinding" -}}
{{- include "gha-runner-scale-set-controller.fullname" . }}-leader-election {{- include "gha-runner-scale-set-controller.fullname" . }}-leader-election
{{- end }} {{- end }}
{{- define "gha-runner-scale-set-controller.imagePullSecretsNames" -}}
{{- $names := list }}
{{- range $k, $v := . }}
{{- $names = append $names $v.name }}
{{- end }}
{{- $names | join ","}}
{{- end }}

View File

@@ -54,7 +54,9 @@ spec:
- "--leader-election-id={{ include "gha-runner-scale-set-controller.fullname" . }}" - "--leader-election-id={{ include "gha-runner-scale-set-controller.fullname" . }}"
{{- end }} {{- end }}
{{- with .Values.imagePullSecrets }} {{- with .Values.imagePullSecrets }}
- "--auto-scaler-image-pull-secrets={{ include "gha-runner-scale-set-controller.imagePullSecretsNames" . }}" {{- range . }}
- "--auto-scaler-image-pull-secrets={{- .name -}}"
{{- end }}
{{- end }} {{- end }}
{{- with .Values.flags.logLevel }} {{- with .Values.flags.logLevel }}
- "--log-level={{ . }}" - "--log-level={{ . }}"

View File

@@ -683,7 +683,8 @@ func TestTemplate_ControllerDeployment_ForwardImagePullSecrets(t *testing.T) {
expectedArgs := []string{ expectedArgs := []string{
"--auto-scaling-runner-set-only", "--auto-scaling-runner-set-only",
"--auto-scaler-image-pull-secrets=dockerhub,ghcr", "--auto-scaler-image-pull-secrets=dockerhub",
"--auto-scaler-image-pull-secrets=ghcr",
"--log-level=debug", "--log-level=debug",
"--log-format=text", "--log-format=text",
"--update-strategy=immediate", "--update-strategy=immediate",
@@ -1079,6 +1080,7 @@ func TestDeployment_excludeLabelPropagationPrefixes(t *testing.T) {
assert.Contains(t, container.Args, "--exclude-label-propagation-prefix=prefix.com/") assert.Contains(t, container.Args, "--exclude-label-propagation-prefix=prefix.com/")
assert.Contains(t, container.Args, "--exclude-label-propagation-prefix=complete.io/label") assert.Contains(t, container.Args, "--exclude-label-propagation-prefix=complete.io/label")
} }
func TestNamespaceOverride(t *testing.T) { func TestNamespaceOverride(t *testing.T) {
t.Parallel() t.Parallel()

View File

@@ -15,13 +15,13 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes # 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. # to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/) # Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.12.1 version: 0.13.0
# This is the version number of the application being deployed. This version number should be # 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 # 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. # follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes. # It is recommended to use it with quotes.
appVersion: "0.12.1" appVersion: "0.13.0"
home: https://github.com/actions/actions-runner-controller home: https://github.com/actions/actions-runner-controller

View File

@@ -62,12 +62,12 @@ app.kubernetes.io/instance: {{ include "gha-runner-scale-set.scale-set-name" . }
{{- fail "Values.githubConfigSecret is required for setting auth with GitHub server." }} {{- fail "Values.githubConfigSecret is required for setting auth with GitHub server." }}
{{- end }} {{- end }}
{{- else }} {{- else }}
{{- include "gha-runner-scale-set.fullname" . }}-github-secret {{- include "gha-runner-scale-set.fullname" . | replace "_" "-" }}-github-secret
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- define "gha-runner-scale-set.noPermissionServiceAccountName" -}} {{- define "gha-runner-scale-set.noPermissionServiceAccountName" -}}
{{- include "gha-runner-scale-set.fullname" . }}-no-permission {{- include "gha-runner-scale-set.fullname" . | replace "_" "-" }}-no-permission
{{- end }} {{- end }}
{{- define "gha-runner-scale-set.kubeModeRoleName" -}} {{- define "gha-runner-scale-set.kubeModeRoleName" -}}
@@ -79,7 +79,7 @@ app.kubernetes.io/instance: {{ include "gha-runner-scale-set.scale-set-name" . }
{{- end }} {{- end }}
{{- define "gha-runner-scale-set.kubeModeServiceAccountName" -}} {{- define "gha-runner-scale-set.kubeModeServiceAccountName" -}}
{{- include "gha-runner-scale-set.fullname" . }}-kube-mode {{- include "gha-runner-scale-set.fullname" . | replace "_" "-" }}-kube-mode
{{- end }} {{- end }}
{{- define "gha-runner-scale-set.dind-init-container" -}} {{- define "gha-runner-scale-set.dind-init-container" -}}
@@ -377,6 +377,101 @@ volumeMounts:
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- define "gha-runner-scale-set.kubernetes-novolume-mode-runner-container" -}}
{{- $tlsConfig := (default (dict) .Values.githubServerTLS) }}
{{- range $i, $container := .Values.template.spec.containers }}
{{- if eq $container.name "runner" }}
{{- $setRunnerImage := "" }}
{{- range $key, $val := $container }}
{{- if and (ne $key "env") (ne $key "volumeMounts") (ne $key "name") }}
{{- if eq $key "image" }}
{{- $setRunnerImage = $val }}
{{- end }}
{{ $key }}: {{ $val | toYaml | nindent 2 }}
{{- end }}
{{- end }}
{{- $setContainerHooks := 1 }}
{{- $setPodName := 1 }}
{{- $setRequireJobContainer := 1 }}
{{- $setActionsRunnerImage := 1 }}
{{- $setNodeExtraCaCerts := 0 }}
{{- $setRunnerUpdateCaCerts := 0 }}
{{- if $tlsConfig.runnerMountPath }}
{{- $setNodeExtraCaCerts = 1 }}
{{- $setRunnerUpdateCaCerts = 1 }}
{{- end }}
env:
{{- with $container.env }}
{{- range $i, $env := . }}
{{- if eq $env.name "ACTIONS_RUNNER_CONTAINER_HOOKS" }}
{{- $setContainerHooks = 0 }}
{{- end }}
{{- if eq $env.name "ACTIONS_RUNNER_IMAGE" }}
{{- $setActionsRunnerImage = 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 }}
{{- if eq $env.name "NODE_EXTRA_CA_CERTS" }}
{{- $setNodeExtraCaCerts = 0 }}
{{- end }}
{{- if eq $env.name "RUNNER_UPDATE_CA_CERTS" }}
{{- $setRunnerUpdateCaCerts = 0 }}
{{- end }}
- {{ $env | toYaml | nindent 4 }}
{{- end }}
{{- end }}
{{- if $setContainerHooks }}
- name: ACTIONS_RUNNER_CONTAINER_HOOKS
value: /home/runner/k8s-novolume/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 }}
{{- if $setActionsRunnerImage }}
- name: ACTIONS_RUNNER_IMAGE
value: "{{- $setRunnerImage -}}"
{{- end }}
{{- if $setNodeExtraCaCerts }}
- name: NODE_EXTRA_CA_CERTS
value: {{ clean (print $tlsConfig.runnerMountPath "/" $tlsConfig.certificateFrom.configMapKeyRef.key) }}
{{- end }}
{{- if $setRunnerUpdateCaCerts }}
- name: RUNNER_UPDATE_CA_CERTS
value: "1"
{{- end }}
{{- $mountGitHubServerTLS := 0 }}
{{- if $tlsConfig.runnerMountPath }}
{{- $mountGitHubServerTLS = 1 }}
{{- end }}
volumeMounts:
{{- with $container.volumeMounts }}
{{- range $i, $volMount := . }}
{{- if eq $volMount.name "github-server-tls-cert" }}
{{- $mountGitHubServerTLS = 0 }}
{{- end }}
- {{ $volMount | toYaml | nindent 4 }}
{{- end }}
{{- end }}
{{- if $mountGitHubServerTLS }}
- name: github-server-tls-cert
mountPath: {{ clean (print $tlsConfig.runnerMountPath "/" $tlsConfig.certificateFrom.configMapKeyRef.key) }}
subPath: {{ $tlsConfig.certificateFrom.configMapKeyRef.key }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- define "gha-runner-scale-set.default-mode-runner-containers" -}} {{- define "gha-runner-scale-set.default-mode-runner-containers" -}}
{{- $tlsConfig := (default (dict) .Values.githubServerTLS) }} {{- $tlsConfig := (default (dict) .Values.githubServerTLS) }}
{{- range $i, $container := .Values.template.spec.containers }} {{- range $i, $container := .Values.template.spec.containers }}

View File

@@ -8,26 +8,45 @@ metadata:
{{- if gt (len (include "gha-runner-scale-set.namespace" .)) 63 }} {{- if gt (len (include "gha-runner-scale-set.namespace" .)) 63 }}
{{ fail "Namespace must have up to 63 characters" }} {{ fail "Namespace must have up to 63 characters" }}
{{- end }} {{- end }}
name: {{ include "gha-runner-scale-set.scale-set-name" . }} name: {{ include "gha-runner-scale-set.scale-set-name" . | replace "_" "-" }}
namespace: {{ include "gha-runner-scale-set.namespace" . }} namespace: {{ include "gha-runner-scale-set.namespace" . }}
labels: labels:
{{- $base := include "gha-runner-scale-set.labels" . | fromYaml }}
{{- $extra := dict "app.kubernetes.io/component" "" }}
{{- $reserved := merge $base $extra }}
{{- with .Values.labels }} {{- with .Values.labels }}
{{- toYaml . | nindent 4 }} {{- range $k, $v := . }}
{{- if not (or (hasKey $reserved $k) (hasPrefix "actions.github.com/" $k)) }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- if $hasCustomResourceMeta }} {{- if $hasCustomResourceMeta }}
{{- with .Values.resourceMeta.autoscalingRunnerSet.labels }} {{- with .Values.resourceMeta.autoscalingRunnerSet.labels }}
{{- toYaml . | nindent 4 }} {{- range $k, $v := . }}
{{- if not (or (hasKey $reserved $k) (hasPrefix "actions.github.com/" $k)) }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- end }} {{- end }}
app.kubernetes.io/component: "autoscaling-runner-set" app.kubernetes.io/component: "autoscaling-runner-set"
{{- include "gha-runner-scale-set.labels" . | nindent 4 }} {{- include "gha-runner-scale-set.labels" . | nindent 4 }}
annotations: annotations:
{{- with .Values.annotations }} {{- with .Values.annotations }}
{{- toYaml . | nindent 4 }} {{- range $k, $v := . }}
{{- if not (or (hasPrefix "actions.github.com/cleanup-" $k) (eq $k "actions.github.com/values-hash")) }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- if $hasCustomResourceMeta }} {{- if $hasCustomResourceMeta }}
{{- with .Values.resourceMeta.autoscalingRunnerSet.annotations }} {{- with .Values.resourceMeta.autoscalingRunnerSet.annotations }}
{{- toYaml . | nindent 4 }} {{- range $k, $v := . }}
{{- if not (or (hasPrefix "actions.github.com/cleanup-" $k) (eq $k "actions.github.com/values-hash")) }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- end }} {{- end }}
actions.github.com/values-hash: {{ toJson .Values | sha256sum | trunc 63 }} actions.github.com/values-hash: {{ toJson .Values | sha256sum | trunc 63 }}
@@ -37,12 +56,12 @@ metadata:
{{- end }} {{- end }}
actions.github.com/cleanup-manager-role-binding: {{ include "gha-runner-scale-set.managerRoleBindingName" . }} actions.github.com/cleanup-manager-role-binding: {{ include "gha-runner-scale-set.managerRoleBindingName" . }}
actions.github.com/cleanup-manager-role-name: {{ include "gha-runner-scale-set.managerRoleName" . }} actions.github.com/cleanup-manager-role-name: {{ include "gha-runner-scale-set.managerRoleName" . }}
{{- if and $containerMode (eq $containerMode.type "kubernetes") (not .Values.template.spec.serviceAccountName) }} {{- if and (or (eq $containerMode.type "kubernetes") (eq $containerMode.type "kubernetes-novolume")) (not .Values.template.spec.serviceAccountName) }}
actions.github.com/cleanup-kubernetes-mode-role-binding-name: {{ include "gha-runner-scale-set.kubeModeRoleBindingName" . }} actions.github.com/cleanup-kubernetes-mode-role-binding-name: {{ include "gha-runner-scale-set.kubeModeRoleBindingName" . }}
actions.github.com/cleanup-kubernetes-mode-role-name: {{ include "gha-runner-scale-set.kubeModeRoleName" . }} actions.github.com/cleanup-kubernetes-mode-role-name: {{ include "gha-runner-scale-set.kubeModeRoleName" . }}
actions.github.com/cleanup-kubernetes-mode-service-account-name: {{ include "gha-runner-scale-set.kubeModeServiceAccountName" . }} actions.github.com/cleanup-kubernetes-mode-service-account-name: {{ include "gha-runner-scale-set.kubeModeServiceAccountName" . }}
{{- end }} {{- end }}
{{- if and (ne $containerMode.type "kubernetes") (not .Values.template.spec.serviceAccountName) }} {{- if and (ne $containerMode.type "kubernetes") (ne $containerMode.type "kubernetes-novolume") (not .Values.template.spec.serviceAccountName) }}
actions.github.com/cleanup-no-permission-service-account-name: {{ include "gha-runner-scale-set.noPermissionServiceAccountName" . }} actions.github.com/cleanup-no-permission-service-account-name: {{ include "gha-runner-scale-set.noPermissionServiceAccountName" . }}
{{- end }} {{- end }}
@@ -157,7 +176,7 @@ spec:
restartPolicy: Never restartPolicy: Never
{{- end }} {{- end }}
{{- $containerMode := .Values.containerMode }} {{- $containerMode := .Values.containerMode }}
{{- if eq $containerMode.type "kubernetes" }} {{- if or (eq $containerMode.type "kubernetes") (eq $containerMode.type "kubernetes-novolume") }}
serviceAccountName: {{ default (include "gha-runner-scale-set.kubeModeServiceAccountName" .) .Values.template.spec.serviceAccountName }} serviceAccountName: {{ default (include "gha-runner-scale-set.kubeModeServiceAccountName" .) .Values.template.spec.serviceAccountName }}
{{- else }} {{- else }}
serviceAccountName: {{ default (include "gha-runner-scale-set.noPermissionServiceAccountName" .) .Values.template.spec.serviceAccountName }} serviceAccountName: {{ default (include "gha-runner-scale-set.noPermissionServiceAccountName" .) .Values.template.spec.serviceAccountName }}
@@ -189,11 +208,15 @@ spec:
- name: runner - name: runner
{{- include "gha-runner-scale-set.kubernetes-mode-runner-container" . | nindent 8 }} {{- include "gha-runner-scale-set.kubernetes-mode-runner-container" . | nindent 8 }}
{{- include "gha-runner-scale-set.non-runner-containers" . | nindent 6 }} {{- include "gha-runner-scale-set.non-runner-containers" . | nindent 6 }}
{{- else if eq $containerMode.type "kubernetes-novolume" }}
- name: runner
{{- include "gha-runner-scale-set.kubernetes-novolume-mode-runner-container" . | nindent 8 }}
{{- include "gha-runner-scale-set.non-runner-containers" . | nindent 6 }}
{{- else }} {{- else }}
{{- include "gha-runner-scale-set.default-mode-runner-containers" . | nindent 6 }} {{- include "gha-runner-scale-set.default-mode-runner-containers" . | nindent 6 }}
{{- end }} {{- end }}
{{- $tlsConfig := (default (dict) .Values.githubServerTLS) }} {{- $tlsConfig := (default (dict) .Values.githubServerTLS) }}
{{- if or .Values.template.spec.volumes (eq $containerMode.type "dind") (eq $containerMode.type "kubernetes") $tlsConfig.runnerMountPath }} {{- if or .Values.template.spec.volumes (eq $containerMode.type "dind") (eq $containerMode.type "kubernetes") (eq $containerMode.type "kubernetes-novolume") $tlsConfig.runnerMountPath }}
volumes: volumes:
{{- if $tlsConfig.runnerMountPath }} {{- if $tlsConfig.runnerMountPath }}
{{- include "gha-runner-scale-set.tls-volume" $tlsConfig | nindent 6 }} {{- include "gha-runner-scale-set.tls-volume" $tlsConfig | nindent 6 }}

View File

@@ -6,8 +6,15 @@ metadata:
name: {{ include "gha-runner-scale-set.githubsecret" . }} name: {{ include "gha-runner-scale-set.githubsecret" . }}
namespace: {{ include "gha-runner-scale-set.namespace" . }} namespace: {{ include "gha-runner-scale-set.namespace" . }}
labels: labels:
{{- $base := include "gha-runner-scale-set.labels" . | fromYaml }}
{{- $extra := dict "app.kubernetes.io/component" "" }}
{{- $reserved := merge $base $extra }}
{{- with .Values.labels }} {{- with .Values.labels }}
{{- toYaml . | nindent 4 }} {{- range $k, $v := . }}
{{- if not (or (hasKey $reserved $k) (hasPrefix "actions.github.com/" $k)) }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- if $hasCustomResourceMeta }} {{- if $hasCustomResourceMeta }}
{{- with .Values.resourceMeta.githubConfigSecret.labels }} {{- with .Values.resourceMeta.githubConfigSecret.labels }}

View File

@@ -1,6 +1,6 @@
{{- $containerMode := .Values.containerMode }} {{- $containerMode := .Values.containerMode }}
{{- $hasCustomResourceMeta := (and .Values.resourceMeta .Values.resourceMeta.kubernetesModeRole) }} {{- $hasCustomResourceMeta := (and .Values.resourceMeta .Values.resourceMeta.kubernetesModeRole) }}
{{- if and (eq $containerMode.type "kubernetes") (not .Values.template.spec.serviceAccountName) }} {{- if and (or (eq $containerMode.type "kubernetes") (eq $containerMode.type "kubernetes-novolume")) (not .Values.template.spec.serviceAccountName) }}
# default permission for runner pod service account in kubernetes mode (container hook) # default permission for runner pod service account in kubernetes mode (container hook)
apiVersion: rbac.authorization.k8s.io/v1 apiVersion: rbac.authorization.k8s.io/v1
kind: Role kind: Role
@@ -8,8 +8,15 @@ metadata:
name: {{ include "gha-runner-scale-set.kubeModeRoleName" . }} name: {{ include "gha-runner-scale-set.kubeModeRoleName" . }}
namespace: {{ include "gha-runner-scale-set.namespace" . }} namespace: {{ include "gha-runner-scale-set.namespace" . }}
labels: labels:
{{- $base := include "gha-runner-scale-set.labels" . | fromYaml }}
{{- $extra := dict "app.kubernetes.io/component" "" }}
{{- $reserved := merge $base $extra }}
{{- with .Values.labels }} {{- with .Values.labels }}
{{- toYaml . | nindent 4 }} {{- range $k, $v := . }}
{{- if not (or (hasKey $reserved $k) (hasPrefix "actions.github.com/" $k)) }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- if $hasCustomResourceMeta }} {{- if $hasCustomResourceMeta }}
{{- with .Values.resourceMeta.kubernetesModeRole.labels }} {{- with .Values.resourceMeta.kubernetesModeRole.labels }}
@@ -29,19 +36,24 @@ metadata:
finalizers: finalizers:
- actions.github.com/cleanup-protection - actions.github.com/cleanup-protection
rules: rules:
- apiGroups: [""] - apiGroups: [""]
resources: ["pods"] resources: ["pods"]
verbs: ["get", "list", "create", "delete"] verbs: ["get", "list", "create", "delete"]
- apiGroups: [""] - apiGroups: [""]
resources: ["pods/exec"] resources: ["pods/exec"]
verbs: ["get", "create"] verbs: ["get", "create"]
- apiGroups: [""] - apiGroups: [""]
resources: ["pods/log"] resources: ["pods/log"]
verbs: ["get", "list", "watch",] verbs: ["get", "list", "watch",]
- apiGroups: ["batch"] {{- if ne $containerMode.type "kubernetes-novolume" }}
resources: ["jobs"] - apiGroups: ["batch"]
verbs: ["get", "list", "create", "delete"] resources: ["jobs"]
- apiGroups: [""] verbs: ["get", "list", "create", "delete"]
resources: ["secrets"] {{- end }}
verbs: ["get", "list", "create", "delete"] - apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "create", "delete"]
{{- with $containerMode.kubernetesModeAdditionalRoleRules}}
{{- toYaml . | nindent 2}}
{{- end }}
{{- end }} {{- end }}

View File

@@ -1,14 +1,21 @@
{{- $containerMode := .Values.containerMode }} {{- $containerMode := .Values.containerMode }}
{{- $hasCustomResourceMeta := (and .Values.resourceMeta .Values.resourceMeta.kubernetesModeRoleBinding) }} {{- $hasCustomResourceMeta := (and .Values.resourceMeta .Values.resourceMeta.kubernetesModeRoleBinding) }}
{{- if and (eq $containerMode.type "kubernetes") (not .Values.template.spec.serviceAccountName) }} {{- if and (or (eq $containerMode.type "kubernetes") (eq $containerMode.type "kubernetes-novolume")) (not .Values.template.spec.serviceAccountName) }}
apiVersion: rbac.authorization.k8s.io/v1 apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding kind: RoleBinding
metadata: metadata:
name: {{ include "gha-runner-scale-set.kubeModeRoleBindingName" . }} name: {{ include "gha-runner-scale-set.kubeModeRoleBindingName" . }}
namespace: {{ include "gha-runner-scale-set.namespace" . }} namespace: {{ include "gha-runner-scale-set.namespace" . }}
labels: labels:
{{- $base := include "gha-runner-scale-set.labels" . | fromYaml }}
{{- $extra := dict "app.kubernetes.io/component" "" }}
{{- $reserved := merge $base $extra }}
{{- with .Values.labels }} {{- with .Values.labels }}
{{- toYaml . | nindent 4 }} {{- range $k, $v := . }}
{{- if not (or (hasKey $reserved $k) (hasPrefix "actions.github.com/" $k)) }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- if $hasCustomResourceMeta }} {{- if $hasCustomResourceMeta }}
{{- with .Values.resourceMeta.kubernetesModeRoleBinding.labels }} {{- with .Values.resourceMeta.kubernetesModeRoleBinding.labels }}

View File

@@ -1,6 +1,6 @@
{{- $containerMode := .Values.containerMode }} {{- $containerMode := .Values.containerMode }}
{{- $hasCustomResourceMeta := (and .Values.resourceMeta .Values.resourceMeta.kubernetesModeServiceAccount) }} {{- $hasCustomResourceMeta := (and .Values.resourceMeta .Values.resourceMeta.kubernetesModeServiceAccount) }}
{{- if and (eq $containerMode.type "kubernetes") (not .Values.template.spec.serviceAccountName) }} {{- if and (or (eq $containerMode.type "kubernetes") (eq $containerMode.type "kubernetes-novolume")) (not .Values.template.spec.serviceAccountName) }}
apiVersion: v1 apiVersion: v1
kind: ServiceAccount kind: ServiceAccount
metadata: metadata:
@@ -18,8 +18,15 @@ metadata:
{{- end }} {{- end }}
{{- end }} {{- end }}
labels: labels:
{{- $base := include "gha-runner-scale-set.labels" . | fromYaml }}
{{- $extra := dict "app.kubernetes.io/component" "" }}
{{- $reserved := merge $base $extra }}
{{- with .Values.labels }} {{- with .Values.labels }}
{{- toYaml . | nindent 4 }} {{- range $k, $v := . }}
{{- if not (or (hasKey $reserved $k) (hasPrefix "actions.github.com/" $k)) }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- if $hasCustomResourceMeta }} {{- if $hasCustomResourceMeta }}
{{- with .Values.resourceMeta.kubernetesModeServiceAccount.labels }} {{- with .Values.resourceMeta.kubernetesModeServiceAccount.labels }}

View File

@@ -5,8 +5,15 @@ metadata:
name: {{ include "gha-runner-scale-set.managerRoleName" . }} name: {{ include "gha-runner-scale-set.managerRoleName" . }}
namespace: {{ include "gha-runner-scale-set.namespace" . }} namespace: {{ include "gha-runner-scale-set.namespace" . }}
labels: labels:
{{- $base := include "gha-runner-scale-set.labels" . | fromYaml }}
{{- $extra := dict "app.kubernetes.io/component" "manager-role" }}
{{- $reserved := merge $base $extra }}
{{- with .Values.labels }} {{- with .Values.labels }}
{{- toYaml . | nindent 4 }} {{- range $k, $v := . }}
{{- if not (or (hasKey $reserved $k) (hasPrefix "actions.github.com/" $k)) }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- if $hasCustomResourceMeta }} {{- if $hasCustomResourceMeta }}
{{- with .Values.resourceMeta.managerRole.labels }} {{- with .Values.resourceMeta.managerRole.labels }}

View File

@@ -5,8 +5,15 @@ metadata:
name: {{ include "gha-runner-scale-set.managerRoleBindingName" . }} name: {{ include "gha-runner-scale-set.managerRoleBindingName" . }}
namespace: {{ include "gha-runner-scale-set.namespace" . }} namespace: {{ include "gha-runner-scale-set.namespace" . }}
labels: labels:
{{- $base := include "gha-runner-scale-set.labels" . | fromYaml }}
{{- $extra := dict "app.kubernetes.io/component" "manager-role-binding" }}
{{- $reserved := merge $base $extra }}
{{- with .Values.labels }} {{- with .Values.labels }}
{{- toYaml . | nindent 4 }} {{- range $k, $v := . }}
{{- if not (or (hasKey $reserved $k) (hasPrefix "actions.github.com/" $k)) }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- if $hasCustomResourceMeta }} {{- if $hasCustomResourceMeta }}
{{- with .Values.resourceMeta.managerRoleBinding.labels }} {{- with .Values.resourceMeta.managerRoleBinding.labels }}

View File

@@ -7,8 +7,15 @@ metadata:
name: {{ include "gha-runner-scale-set.noPermissionServiceAccountName" . }} name: {{ include "gha-runner-scale-set.noPermissionServiceAccountName" . }}
namespace: {{ include "gha-runner-scale-set.namespace" . }} namespace: {{ include "gha-runner-scale-set.namespace" . }}
labels: labels:
{{- $base := include "gha-runner-scale-set.labels" . | fromYaml }}
{{- $extra := dict "app.kubernetes.io/component" "" }}
{{- $reserved := merge $base $extra }}
{{- with .Values.labels }} {{- with .Values.labels }}
{{- toYaml . | nindent 4 }} {{- range $k, $v := . }}
{{- if not (or (hasKey $reserved $k) (hasPrefix "actions.github.com/" $k)) }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- if $hasCustomResourceMeta }} {{- if $hasCustomResourceMeta }}
{{- with .Values.resourceMeta.noPermissionServiceAccount.labels }} {{- with .Values.resourceMeta.noPermissionServiceAccount.labels }}

View File

@@ -204,7 +204,6 @@ func TestTemplateRenderedSetServiceAccountToNoPermission(t *testing.T) {
func TestTemplateRenderedSetServiceAccountToKubeMode(t *testing.T) { func TestTemplateRenderedSetServiceAccountToKubeMode(t *testing.T) {
t.Parallel() t.Parallel()
// Path to the helm chart we will test // Path to the helm chart we will test
helmChartPath, err := filepath.Abs("../../gha-runner-scale-set") helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
require.NoError(t, err) require.NoError(t, err)
@@ -270,6 +269,72 @@ func TestTemplateRenderedSetServiceAccountToKubeMode(t *testing.T) {
assert.Equal(t, expectedServiceAccountName, ars.Annotations[actionsgithubcom.AnnotationKeyKubernetesModeServiceAccountName]) assert.Equal(t, expectedServiceAccountName, ars.Annotations[actionsgithubcom.AnnotationKeyKubernetesModeServiceAccountName])
} }
func TestTemplateRenderedSetServiceAccountToKubeNoVolumeMode(t *testing.T) {
t.Parallel()
// Path to the helm chart we will test
helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
require.NoError(t, err)
releaseName := "test-runners"
namespaceName := "test-" + strings.ToLower(random.UniqueId())
options := &helm.Options{
Logger: logger.Discard,
SetValues: map[string]string{
"githubConfigUrl": "https://github.com/actions",
"githubConfigSecret.github_token": "gh_token12345",
"containerMode.type": "kubernetes-novolume",
"controllerServiceAccount.name": "arc",
"controllerServiceAccount.namespace": "arc-system",
},
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-gha-rs-kube-mode", serviceAccount.Name)
assert.Equal(t, "actions.github.com/cleanup-protection", serviceAccount.Finalizers[0])
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-gha-rs-kube-mode", role.Name)
assert.Equal(t, "actions.github.com/cleanup-protection", role.Finalizers[0])
assert.Len(t, role.Rules, 4, "kube mode role should have 4 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, "secrets", role.Rules[3].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-gha-rs-kube-mode", roleBinding.Name)
assert.Len(t, roleBinding.Subjects, 1)
assert.Equal(t, "test-runners-gha-rs-kube-mode", roleBinding.Subjects[0].Name)
assert.Equal(t, namespaceName, roleBinding.Subjects[0].Namespace)
assert.Equal(t, "test-runners-gha-rs-kube-mode", roleBinding.RoleRef.Name)
assert.Equal(t, "Role", roleBinding.RoleRef.Kind)
assert.Equal(t, "actions.github.com/cleanup-protection", serviceAccount.Finalizers[0])
output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
var ars v1alpha1.AutoscalingRunnerSet
helm.UnmarshalK8SYaml(t, output, &ars)
expectedServiceAccountName := "test-runners-gha-rs-kube-mode"
assert.Equal(t, expectedServiceAccountName, ars.Spec.Template.Spec.ServiceAccountName)
assert.Equal(t, expectedServiceAccountName, ars.Annotations[actionsgithubcom.AnnotationKeyKubernetesModeServiceAccountName])
}
func TestTemplateRenderedUserProvideSetServiceAccount(t *testing.T) { func TestTemplateRenderedUserProvideSetServiceAccount(t *testing.T) {
t.Parallel() t.Parallel()
@@ -961,6 +1026,65 @@ func TestTemplateRenderedAutoScalingRunnerSet_EnableKubernetesMode(t *testing.T)
assert.NotNil(t, ars.Spec.Template.Spec.Volumes[0].Ephemeral, "Template.Spec should have 1 ephemeral volume") assert.NotNil(t, ars.Spec.Template.Spec.Volumes[0].Ephemeral, "Template.Spec should have 1 ephemeral volume")
} }
func TestTemplateRenderedAutoScalingRunnerSet_EnableKubernetesModeNoVolume(t *testing.T) {
t.Parallel()
// Path to the helm chart we will test
helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
require.NoError(t, err)
releaseName := "test-runners"
namespaceName := "test-" + strings.ToLower(random.UniqueId())
options := &helm.Options{
Logger: logger.Discard,
SetValues: map[string]string{
"githubConfigUrl": "https://github.com/actions",
"githubConfigSecret.github_token": "gh_token12345",
"containerMode.type": "kubernetes-novolume",
"controllerServiceAccount.name": "arc",
"controllerServiceAccount.namespace": "arc-system",
},
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, "test-runners", 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-gha-rs-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)
require.Len(t, ars.Spec.Template.Spec.Containers[0].Env, 4, "The runner container should have 4 env vars")
assert.Equal(t, "ACTIONS_RUNNER_CONTAINER_HOOKS", ars.Spec.Template.Spec.Containers[0].Env[0].Name)
assert.Equal(t, "/home/runner/k8s-novolume/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.Equal(t, "ACTIONS_RUNNER_IMAGE", ars.Spec.Template.Spec.Containers[0].Env[3].Name)
assert.Equal(t, ars.Spec.Template.Spec.Containers[0].Image, ars.Spec.Template.Spec.Containers[0].Env[3].Value)
assert.Len(t, ars.Spec.Template.Spec.Volumes, 0, "Template.Spec should have 0 volumes")
}
func TestTemplateRenderedAutoscalingRunnerSet_ListenerPodTemplate(t *testing.T) { func TestTemplateRenderedAutoscalingRunnerSet_ListenerPodTemplate(t *testing.T) {
t.Parallel() t.Parallel()
@@ -1140,7 +1264,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
} }
t.Run("providing githubServerTLS.runnerMountPath", func(t *testing.T) { t.Run("providing githubServerTLS.runnerMountPath", func(t *testing.T) {
t.Run("mode: default", func(t *testing.T) { t.Run("mode default", func(t *testing.T) {
options := &helm.Options{ options := &helm.Options{
Logger: logger.Discard, Logger: logger.Discard,
SetValues: map[string]string{ SetValues: map[string]string{
@@ -1199,7 +1323,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
}) })
}) })
t.Run("mode: dind", func(t *testing.T) { t.Run("mode dind", func(t *testing.T) {
options := &helm.Options{ options := &helm.Options{
Logger: logger.Discard, Logger: logger.Discard,
SetValues: map[string]string{ SetValues: map[string]string{
@@ -1259,7 +1383,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
}) })
}) })
t.Run("mode: kubernetes", func(t *testing.T) { t.Run("mode kubernetes", func(t *testing.T) {
options := &helm.Options{ options := &helm.Options{
Logger: logger.Discard, Logger: logger.Discard,
SetValues: map[string]string{ SetValues: map[string]string{
@@ -1318,10 +1442,70 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
Value: "1", Value: "1",
}) })
}) })
t.Run("mode kubernetes-novolume", func(t *testing.T) {
options := &helm.Options{
Logger: logger.Discard,
SetValues: map[string]string{
"githubConfigUrl": "https://github.com/actions",
"githubConfigSecret": "pre-defined-secrets",
"githubServerTLS.certificateFrom.configMapKeyRef.name": "certs-configmap",
"githubServerTLS.certificateFrom.configMapKeyRef.key": "cert.pem",
"githubServerTLS.runnerMountPath": "/runner/mount/path",
"containerMode.type": "kubernetes-novolume",
"controllerServiceAccount.name": "arc",
"controllerServiceAccount.namespace": "arc-system",
},
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
}
ars := render(t, options)
require.NotNil(t, ars.Spec.GitHubServerTLS)
expected := &v1alpha1.TLSConfig{
CertificateFrom: &v1alpha1.TLSCertificateSource{
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "certs-configmap",
},
Key: "cert.pem",
},
},
}
assert.Equal(t, expected, ars.Spec.GitHubServerTLS)
var volume *corev1.Volume
for _, v := range ars.Spec.Template.Spec.Volumes {
if v.Name == "github-server-tls-cert" {
volume = &v
break
}
}
require.NotNil(t, volume)
assert.Equal(t, "certs-configmap", volume.ConfigMap.Name)
assert.Equal(t, "cert.pem", volume.ConfigMap.Items[0].Key)
assert.Equal(t, "cert.pem", volume.ConfigMap.Items[0].Path)
assert.Contains(t, ars.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
Name: "github-server-tls-cert",
MountPath: "/runner/mount/path/cert.pem",
SubPath: "cert.pem",
})
assert.Contains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
Name: "NODE_EXTRA_CA_CERTS",
Value: "/runner/mount/path/cert.pem",
})
assert.Contains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
Name: "RUNNER_UPDATE_CA_CERTS",
Value: "1",
})
})
}) })
t.Run("without providing githubServerTLS.runnerMountPath", func(t *testing.T) { t.Run("without providing githubServerTLS.runnerMountPath", func(t *testing.T) {
t.Run("mode: default", func(t *testing.T) { t.Run("mode default", func(t *testing.T) {
options := &helm.Options{ options := &helm.Options{
Logger: logger.Discard, Logger: logger.Discard,
SetValues: map[string]string{ SetValues: map[string]string{
@@ -1376,7 +1560,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
}) })
}) })
t.Run("mode: dind", func(t *testing.T) { t.Run("mode dind", func(t *testing.T) {
options := &helm.Options{ options := &helm.Options{
Logger: logger.Discard, Logger: logger.Discard,
SetValues: map[string]string{ SetValues: map[string]string{
@@ -1432,7 +1616,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
}) })
}) })
t.Run("mode: kubernetes", func(t *testing.T) { t.Run("mode kubernetes", func(t *testing.T) {
options := &helm.Options{ options := &helm.Options{
Logger: logger.Discard, Logger: logger.Discard,
SetValues: map[string]string{ SetValues: map[string]string{
@@ -1487,6 +1671,62 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
Value: "1", Value: "1",
}) })
}) })
t.Run("mode kubernetes-novolume", func(t *testing.T) {
options := &helm.Options{
Logger: logger.Discard,
SetValues: map[string]string{
"githubConfigUrl": "https://github.com/actions",
"githubConfigSecret": "pre-defined-secrets",
"githubServerTLS.certificateFrom.configMapKeyRef.name": "certs-configmap",
"githubServerTLS.certificateFrom.configMapKeyRef.key": "cert.pem",
"containerMode.type": "kubernetes-novolume",
"controllerServiceAccount.name": "arc",
"controllerServiceAccount.namespace": "arc-system",
},
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
}
ars := render(t, options)
require.NotNil(t, ars.Spec.GitHubServerTLS)
expected := &v1alpha1.TLSConfig{
CertificateFrom: &v1alpha1.TLSCertificateSource{
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "certs-configmap",
},
Key: "cert.pem",
},
},
}
assert.Equal(t, expected, ars.Spec.GitHubServerTLS)
var volume *corev1.Volume
for _, v := range ars.Spec.Template.Spec.Volumes {
if v.Name == "github-server-tls-cert" {
volume = &v
break
}
}
assert.Nil(t, volume)
assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
Name: "github-server-tls-cert",
MountPath: "/runner/mount/path/cert.pem",
SubPath: "cert.pem",
})
assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
Name: "NODE_EXTRA_CA_CERTS",
Value: "/runner/mount/path/cert.pem",
})
assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
Name: "RUNNER_UPDATE_CA_CERTS",
Value: "1",
})
})
}) })
} }
@@ -1951,40 +2191,44 @@ func TestTemplateRenderedAutoscalingRunnerSetAnnotation_GitHubSecret(t *testing.
func TestTemplateRenderedAutoscalingRunnerSetAnnotation_KubernetesModeCleanup(t *testing.T) { func TestTemplateRenderedAutoscalingRunnerSetAnnotation_KubernetesModeCleanup(t *testing.T) {
t.Parallel() t.Parallel()
// Path to the helm chart we will test for _, mode := range []string{"kubernetes", "kubernetes-novolume"} {
helmChartPath, err := filepath.Abs("../../gha-runner-scale-set") t.Run("containerMode "+mode, func(t *testing.T) {
require.NoError(t, err) // Path to the helm chart we will test
helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
require.NoError(t, err)
releaseName := "test-runners" releaseName := "test-runners"
namespaceName := "test-" + strings.ToLower(random.UniqueId()) namespaceName := "test-" + strings.ToLower(random.UniqueId())
options := &helm.Options{ options := &helm.Options{
Logger: logger.Discard, Logger: logger.Discard,
SetValues: map[string]string{ SetValues: map[string]string{
"githubConfigUrl": "https://github.com/actions", "githubConfigUrl": "https://github.com/actions",
"githubConfigSecret.github_token": "gh_token12345", "githubConfigSecret.github_token": "gh_token12345",
"controllerServiceAccount.name": "arc", "controllerServiceAccount.name": "arc",
"controllerServiceAccount.namespace": "arc-system", "controllerServiceAccount.namespace": "arc-system",
"containerMode.type": "kubernetes", "containerMode.type": mode,
}, },
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
} }
output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
var autoscalingRunnerSet v1alpha1.AutoscalingRunnerSet var autoscalingRunnerSet v1alpha1.AutoscalingRunnerSet
helm.UnmarshalK8SYaml(t, output, &autoscalingRunnerSet) helm.UnmarshalK8SYaml(t, output, &autoscalingRunnerSet)
annotationValues := map[string]string{ annotationValues := map[string]string{
actionsgithubcom.AnnotationKeyGitHubSecretName: "test-runners-gha-rs-github-secret", actionsgithubcom.AnnotationKeyGitHubSecretName: "test-runners-gha-rs-github-secret",
actionsgithubcom.AnnotationKeyManagerRoleName: "test-runners-gha-rs-manager", actionsgithubcom.AnnotationKeyManagerRoleName: "test-runners-gha-rs-manager",
actionsgithubcom.AnnotationKeyManagerRoleBindingName: "test-runners-gha-rs-manager", actionsgithubcom.AnnotationKeyManagerRoleBindingName: "test-runners-gha-rs-manager",
actionsgithubcom.AnnotationKeyKubernetesModeServiceAccountName: "test-runners-gha-rs-kube-mode", actionsgithubcom.AnnotationKeyKubernetesModeServiceAccountName: "test-runners-gha-rs-kube-mode",
actionsgithubcom.AnnotationKeyKubernetesModeRoleName: "test-runners-gha-rs-kube-mode", actionsgithubcom.AnnotationKeyKubernetesModeRoleName: "test-runners-gha-rs-kube-mode",
actionsgithubcom.AnnotationKeyKubernetesModeRoleBindingName: "test-runners-gha-rs-kube-mode", actionsgithubcom.AnnotationKeyKubernetesModeRoleBindingName: "test-runners-gha-rs-kube-mode",
} }
for annotation, value := range annotationValues { for annotation, value := range annotationValues {
assert.Equal(t, value, autoscalingRunnerSet.Annotations[annotation], fmt.Sprintf("Annotation %q does not match the expected value", annotation)) assert.Equal(t, value, autoscalingRunnerSet.Annotations[annotation], fmt.Sprintf("Annotation %q does not match the expected value", annotation))
}
})
} }
} }
@@ -2416,6 +2660,21 @@ func TestNamespaceOverride(t *testing.T) {
KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace), KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
}, },
}, },
"kube_novolume_mode_role": {
file: "kube_mode_role.yaml",
options: &helm.Options{
Logger: logger.Discard,
SetValues: map[string]string{
"namespaceOverride": namespaceOverride,
"containerMode.type": "kubernetes-novolume",
"controllerServiceAccount.name": "foo",
"controllerServiceAccount.namespace": "bar",
"githubConfigSecret.github_token": "gh_token12345",
"githubConfigUrl": "https://github.com",
},
KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
},
},
"kube_mode_role_binding": { "kube_mode_role_binding": {
file: "kube_mode_role_binding.yaml", file: "kube_mode_role_binding.yaml",
options: &helm.Options{ options: &helm.Options{
@@ -2431,6 +2690,21 @@ func TestNamespaceOverride(t *testing.T) {
KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace), KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
}, },
}, },
"kube_novolume_mode_role_binding": {
file: "kube_mode_role_binding.yaml",
options: &helm.Options{
Logger: logger.Discard,
SetValues: map[string]string{
"namespaceOverride": namespaceOverride,
"containerMode.type": "kubernetes-novolume",
"controllerServiceAccount.name": "foo",
"controllerServiceAccount.namespace": "bar",
"githubConfigSecret.github_token": "gh_token12345",
"githubConfigUrl": "https://github.com",
},
KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
},
},
"kube_mode_serviceaccount": { "kube_mode_serviceaccount": {
file: "kube_mode_serviceaccount.yaml", file: "kube_mode_serviceaccount.yaml",
options: &helm.Options{ options: &helm.Options{
@@ -2446,6 +2720,21 @@ func TestNamespaceOverride(t *testing.T) {
KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace), KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
}, },
}, },
"kube_novolume_mode_serviceaccount": {
file: "kube_mode_serviceaccount.yaml",
options: &helm.Options{
Logger: logger.Discard,
SetValues: map[string]string{
"namespaceOverride": namespaceOverride,
"containerMode.type": "kubernetes-novolume",
"controllerServiceAccount.name": "foo",
"controllerServiceAccount.namespace": "bar",
"githubConfigSecret.github_token": "gh_token12345",
"githubConfigUrl": "https://github.com",
},
KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
},
},
} }
for name, tc := range tt { for name, tc := range tt {

View File

@@ -0,0 +1,30 @@
githubConfigUrl: https://github.com/actions/actions-runner-controller
githubConfigSecret:
github_token: test
template:
spec:
containers:
- name: other
image: other-image:latest
volumes:
- name: foo
emptyDir: {}
- name: bar
emptyDir: {}
- name: work
hostPath:
path: /data
type: Directory
containerMode:
type: kubernetes
kubernetesModeAdditionalRoleRule:
- apiGroups:
- apps
resources:
- deployments
verbs:
- get
- list
- create
- delete

View File

@@ -1,5 +1,5 @@
## githubConfigUrl is the GitHub url for where you want to configure runners ## githubConfigUrl is the GitHub url for where you want to configure runners
## ex: https://github.com/myorg/myrepo or https://github.com/myorg ## ex: https://github.com/myorg/myrepo or https://github.com/myorg or https://github.com/enterprises/myenterprise
githubConfigUrl: "" githubConfigUrl: ""
## githubConfigSecret is the k8s secret information to use when authenticating via the GitHub API. ## githubConfigSecret is the k8s secret information to use when authenticating via the GitHub API.
@@ -115,7 +115,7 @@ githubConfigSecret:
## If any customization is required for dind or kubernetes mode, containerMode should remain ## If any customization is required for dind or kubernetes mode, containerMode should remain
## empty, and configuration should be applied to the template. ## empty, and configuration should be applied to the template.
# containerMode: # containerMode:
# type: "dind" ## type can be set to dind or kubernetes # type: "dind" ## type can be set to "dind", "kubernetes", or "kubernetes-novolume"
# ## the following is required when containerMode.type=kubernetes # ## the following is required when containerMode.type=kubernetes
# kubernetesModeWorkVolumeClaim: # kubernetesModeWorkVolumeClaim:
# accessModes: ["ReadWriteOnce"] # accessModes: ["ReadWriteOnce"]
@@ -124,6 +124,7 @@ githubConfigSecret:
# resources: # resources:
# requests: # requests:
# storage: 1Gi # storage: 1Gi
# kubernetesModeAdditionalRoleRules: []
# #
## listenerTemplate is the PodSpec for each listener Pod ## listenerTemplate is the PodSpec for each listener Pod
@@ -154,7 +155,7 @@ githubConfigSecret:
# counters: # counters:
# gha_started_jobs_total: # gha_started_jobs_total:
# labels: # labels:
# ["repository", "organization", "enterprise", "job_name", "event_name", "job_workflow_ref"] # ["repository", "organization", "enterprise", "job_name", "event_name", "job_workflow_ref", "job_workflow_name", "job_workflow_target"]
# gha_completed_jobs_total: # gha_completed_jobs_total:
# labels: # labels:
# [ # [
@@ -165,6 +166,8 @@ githubConfigSecret:
# "event_name", # "event_name",
# "job_result", # "job_result",
# "job_workflow_ref", # "job_workflow_ref",
# "job_workflow_name",
# "job_workflow_target",
# ] # ]
# gauges: # gauges:
# gha_assigned_jobs: # gha_assigned_jobs:
@@ -186,7 +189,7 @@ githubConfigSecret:
# histograms: # histograms:
# gha_job_startup_duration_seconds: # gha_job_startup_duration_seconds:
# labels: # labels:
# ["repository", "organization", "enterprise", "job_name", "event_name","job_workflow_ref"] # ["repository", "organization", "enterprise", "job_name", "event_name","job_workflow_ref", "job_workflow_name", "job_workflow_target"]
# buckets: # buckets:
# [ # [
# 0.01, # 0.01,
@@ -244,7 +247,9 @@ githubConfigSecret:
# "job_name", # "job_name",
# "event_name", # "event_name",
# "job_result", # "job_result",
# "job_workflow_ref" # "job_workflow_ref",
# "job_workflow_name",
# "job_workflow_target"
# ] # ]
# buckets: # buckets:
# [ # [
@@ -387,6 +392,25 @@ template:
## resources: ## resources:
## requests: ## requests:
## storage: 1Gi ## storage: 1Gi
######################################################################################################
## with containerMode.type=kubernetes-novolume, we will populate the template.spec with following pod spec
## template:
## spec:
## containers:
## - name: runner
## image: ghcr.io/actions/actions-runner:latest
## command: ["/home/runner/run.sh"]
## env:
## - name: ACTIONS_RUNNER_CONTAINER_HOOKS
## value: /home/runner/k8s-novolume/index.js
## - name: ACTIONS_RUNNER_POD_NAME
## valueFrom:
## fieldRef:
## fieldPath: metadata.name
## - name: ACTIONS_RUNNER_IMAGE
## value: ghcr.io/actions/actions-runner:latest # should match the runnerimage
## - name: ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER
## value: "true"
spec: spec:
containers: containers:
- name: runner - name: runner

View File

@@ -361,7 +361,7 @@ func (l *Listener) parseMessage(ctx context.Context, msg *actions.RunnerScaleSet
return nil, fmt.Errorf("failed to decode job available: %w", err) return nil, fmt.Errorf("failed to decode job available: %w", err)
} }
l.logger.Info("Job available message received", "jobId", jobAvailable.RunnerRequestId) l.logger.Info("Job available message received", "jobId", jobAvailable.JobID)
parsedMsg.jobsAvailable = append(parsedMsg.jobsAvailable, &jobAvailable) parsedMsg.jobsAvailable = append(parsedMsg.jobsAvailable, &jobAvailable)
case messageTypeJobAssigned: case messageTypeJobAssigned:
@@ -370,14 +370,14 @@ func (l *Listener) parseMessage(ctx context.Context, msg *actions.RunnerScaleSet
return nil, fmt.Errorf("failed to decode job assigned: %w", err) return nil, fmt.Errorf("failed to decode job assigned: %w", err)
} }
l.logger.Info("Job assigned message received", "jobId", jobAssigned.RunnerRequestId) l.logger.Info("Job assigned message received", "jobId", jobAssigned.JobID)
case messageTypeJobStarted: case messageTypeJobStarted:
var jobStarted actions.JobStarted var jobStarted actions.JobStarted
if err := json.Unmarshal(msg, &jobStarted); err != nil { if err := json.Unmarshal(msg, &jobStarted); err != nil {
return nil, fmt.Errorf("could not decode job started message. %w", err) return nil, fmt.Errorf("could not decode job started message. %w", err)
} }
l.logger.Info("Job started message received.", "RequestId", jobStarted.RunnerRequestId, "RunnerId", jobStarted.RunnerId) l.logger.Info("Job started message received.", "JobID", jobStarted.JobID, "RunnerId", jobStarted.RunnerID)
parsedMsg.jobsStarted = append(parsedMsg.jobsStarted, &jobStarted) parsedMsg.jobsStarted = append(parsedMsg.jobsStarted, &jobStarted)
case messageTypeJobCompleted: case messageTypeJobCompleted:
@@ -386,7 +386,13 @@ func (l *Listener) parseMessage(ctx context.Context, msg *actions.RunnerScaleSet
return nil, fmt.Errorf("failed to decode job completed: %w", err) return nil, fmt.Errorf("failed to decode job completed: %w", err)
} }
l.logger.Info("Job completed message received.", "RequestId", jobCompleted.RunnerRequestId, "Result", jobCompleted.Result, "RunnerId", jobCompleted.RunnerId, "RunnerName", jobCompleted.RunnerName) l.logger.Info(
"Job completed message received.",
"JobID", jobCompleted.JobID,
"Result", jobCompleted.Result,
"RunnerId", jobCompleted.RunnerId,
"RunnerName", jobCompleted.RunnerName,
)
parsedMsg.jobsCompleted = append(parsedMsg.jobsCompleted, &jobCompleted) parsedMsg.jobsCompleted = append(parsedMsg.jobsCompleted, &jobCompleted)
default: default:
@@ -400,7 +406,7 @@ func (l *Listener) parseMessage(ctx context.Context, msg *actions.RunnerScaleSet
func (l *Listener) acquireAvailableJobs(ctx context.Context, jobsAvailable []*actions.JobAvailable) ([]int64, error) { func (l *Listener) acquireAvailableJobs(ctx context.Context, jobsAvailable []*actions.JobAvailable) ([]int64, error) {
ids := make([]int64, 0, len(jobsAvailable)) ids := make([]int64, 0, len(jobsAvailable))
for _, job := range jobsAvailable { for _, job := range jobsAvailable {
ids = append(ids, job.RunnerRequestId) ids = append(ids, job.RunnerRequestID)
} }
l.logger.Info("Acquiring jobs", "count", len(ids), "requestIds", fmt.Sprint(ids)) l.logger.Info("Acquiring jobs", "count", len(ids), "requestIds", fmt.Sprint(ids))

View File

@@ -627,17 +627,17 @@ func TestListener_acquireAvailableJobs(t *testing.T) {
availableJobs := []*actions.JobAvailable{ availableJobs := []*actions.JobAvailable{
{ {
JobMessageBase: actions.JobMessageBase{ JobMessageBase: actions.JobMessageBase{
RunnerRequestId: 1, RunnerRequestID: 1,
}, },
}, },
{ {
JobMessageBase: actions.JobMessageBase{ JobMessageBase: actions.JobMessageBase{
RunnerRequestId: 2, RunnerRequestID: 2,
}, },
}, },
{ {
JobMessageBase: actions.JobMessageBase{ JobMessageBase: actions.JobMessageBase{
RunnerRequestId: 3, RunnerRequestID: 3,
}, },
}, },
} }
@@ -678,17 +678,17 @@ func TestListener_acquireAvailableJobs(t *testing.T) {
availableJobs := []*actions.JobAvailable{ availableJobs := []*actions.JobAvailable{
{ {
JobMessageBase: actions.JobMessageBase{ JobMessageBase: actions.JobMessageBase{
RunnerRequestId: 1, RunnerRequestID: 1,
}, },
}, },
{ {
JobMessageBase: actions.JobMessageBase{ JobMessageBase: actions.JobMessageBase{
RunnerRequestId: 2, RunnerRequestID: 2,
}, },
}, },
{ {
JobMessageBase: actions.JobMessageBase{ JobMessageBase: actions.JobMessageBase{
RunnerRequestId: 3, RunnerRequestID: 3,
}, },
}, },
} }
@@ -724,17 +724,17 @@ func TestListener_acquireAvailableJobs(t *testing.T) {
availableJobs := []*actions.JobAvailable{ availableJobs := []*actions.JobAvailable{
{ {
JobMessageBase: actions.JobMessageBase{ JobMessageBase: actions.JobMessageBase{
RunnerRequestId: 1, RunnerRequestID: 1,
}, },
}, },
{ {
JobMessageBase: actions.JobMessageBase{ JobMessageBase: actions.JobMessageBase{
RunnerRequestId: 2, RunnerRequestID: 2,
}, },
}, },
{ {
JobMessageBase: actions.JobMessageBase{ JobMessageBase: actions.JobMessageBase{
RunnerRequestId: 3, RunnerRequestID: 3,
}, },
}, },
} }
@@ -809,17 +809,17 @@ func TestListener_acquireAvailableJobs(t *testing.T) {
availableJobs := []*actions.JobAvailable{ availableJobs := []*actions.JobAvailable{
{ {
JobMessageBase: actions.JobMessageBase{ JobMessageBase: actions.JobMessageBase{
RunnerRequestId: 1, RunnerRequestID: 1,
}, },
}, },
{ {
JobMessageBase: actions.JobMessageBase{ JobMessageBase: actions.JobMessageBase{
RunnerRequestId: 2, RunnerRequestID: 2,
}, },
}, },
{ {
JobMessageBase: actions.JobMessageBase{ JobMessageBase: actions.JobMessageBase{
RunnerRequestId: 3, RunnerRequestID: 3,
}, },
}, },
} }
@@ -881,7 +881,7 @@ func TestListener_parseMessage(t *testing.T) {
JobMessageType: actions.JobMessageType{ JobMessageType: actions.JobMessageType{
MessageType: messageTypeJobAvailable, MessageType: messageTypeJobAvailable,
}, },
RunnerRequestId: 1, RunnerRequestID: 1,
}, },
}, },
{ {
@@ -890,7 +890,7 @@ func TestListener_parseMessage(t *testing.T) {
JobMessageType: actions.JobMessageType{ JobMessageType: actions.JobMessageType{
MessageType: messageTypeJobAvailable, MessageType: messageTypeJobAvailable,
}, },
RunnerRequestId: 2, RunnerRequestID: 2,
}, },
}, },
} }
@@ -904,7 +904,7 @@ func TestListener_parseMessage(t *testing.T) {
JobMessageType: actions.JobMessageType{ JobMessageType: actions.JobMessageType{
MessageType: messageTypeJobAssigned, MessageType: messageTypeJobAssigned,
}, },
RunnerRequestId: 3, RunnerRequestID: 3,
}, },
}, },
{ {
@@ -912,7 +912,7 @@ func TestListener_parseMessage(t *testing.T) {
JobMessageType: actions.JobMessageType{ JobMessageType: actions.JobMessageType{
MessageType: messageTypeJobAssigned, MessageType: messageTypeJobAssigned,
}, },
RunnerRequestId: 4, RunnerRequestID: 4,
}, },
}, },
} }
@@ -926,9 +926,9 @@ func TestListener_parseMessage(t *testing.T) {
JobMessageType: actions.JobMessageType{ JobMessageType: actions.JobMessageType{
MessageType: messageTypeJobStarted, MessageType: messageTypeJobStarted,
}, },
RunnerRequestId: 5, RunnerRequestID: 5,
}, },
RunnerId: 2, RunnerID: 2,
RunnerName: "runner2", RunnerName: "runner2",
}, },
} }
@@ -942,7 +942,7 @@ func TestListener_parseMessage(t *testing.T) {
JobMessageType: actions.JobMessageType{ JobMessageType: actions.JobMessageType{
MessageType: messageTypeJobCompleted, MessageType: messageTypeJobCompleted,
}, },
RunnerRequestId: 6, RunnerRequestID: 6,
}, },
Result: "success", Result: "success",
RunnerId: 1, RunnerId: 1,

View File

@@ -123,9 +123,9 @@ func TestHandleMessageMetrics(t *testing.T) {
JobMessageType: actions.JobMessageType{ JobMessageType: actions.JobMessageType{
MessageType: messageTypeJobStarted, MessageType: messageTypeJobStarted,
}, },
RunnerRequestId: 8, RunnerRequestID: 8,
}, },
RunnerId: 3, RunnerID: 3,
RunnerName: "runner3", RunnerName: "runner3",
}, },
} }
@@ -139,7 +139,7 @@ func TestHandleMessageMetrics(t *testing.T) {
JobMessageType: actions.JobMessageType{ JobMessageType: actions.JobMessageType{
MessageType: messageTypeJobCompleted, MessageType: messageTypeJobCompleted,
}, },
RunnerRequestId: 6, RunnerRequestID: 6,
}, },
Result: "success", Result: "success",
RunnerId: 1, RunnerId: 1,
@@ -150,7 +150,7 @@ func TestHandleMessageMetrics(t *testing.T) {
JobMessageType: actions.JobMessageType{ JobMessageType: actions.JobMessageType{
MessageType: messageTypeJobCompleted, MessageType: messageTypeJobCompleted,
}, },
RunnerRequestId: 7, RunnerRequestID: 7,
}, },
Result: "success", Result: "success",
RunnerId: 2, RunnerId: 2,

View File

@@ -22,6 +22,8 @@ const (
labelKeyRepository = "repository" labelKeyRepository = "repository"
labelKeyJobName = "job_name" labelKeyJobName = "job_name"
labelKeyJobWorkflowRef = "job_workflow_ref" labelKeyJobWorkflowRef = "job_workflow_ref"
labelKeyJobWorkflowName = "job_workflow_name"
labelKeyJobWorkflowTarget = "job_workflow_target"
labelKeyEventName = "event_name" labelKeyEventName = "event_name"
labelKeyJobResult = "job_result" labelKeyJobResult = "job_result"
) )
@@ -75,13 +77,16 @@ var metricsHelp = metricsHelpRegistry{
} }
func (e *exporter) jobLabels(jobBase *actions.JobMessageBase) prometheus.Labels { func (e *exporter) jobLabels(jobBase *actions.JobMessageBase) prometheus.Labels {
workflowRefInfo := ParseWorkflowRef(jobBase.JobWorkflowRef)
return prometheus.Labels{ return prometheus.Labels{
labelKeyEnterprise: e.scaleSetLabels[labelKeyEnterprise], labelKeyEnterprise: e.scaleSetLabels[labelKeyEnterprise],
labelKeyOrganization: jobBase.OwnerName, labelKeyOrganization: jobBase.OwnerName,
labelKeyRepository: jobBase.RepositoryName, labelKeyRepository: jobBase.RepositoryName,
labelKeyJobName: jobBase.JobDisplayName, labelKeyJobName: jobBase.JobDisplayName,
labelKeyJobWorkflowRef: jobBase.JobWorkflowRef, labelKeyJobWorkflowRef: jobBase.JobWorkflowRef,
labelKeyEventName: jobBase.EventName, labelKeyJobWorkflowName: workflowRefInfo.Name,
labelKeyJobWorkflowTarget: workflowRefInfo.Target,
labelKeyEventName: jobBase.EventName,
} }
} }

View File

@@ -0,0 +1,99 @@
package metrics
import (
"testing"
"github.com/actions/actions-runner-controller/github/actions"
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/assert"
)
func TestMetricsWithWorkflowRefParsing(t *testing.T) {
// Create a test exporter
exporter := &exporter{
scaleSetLabels: prometheus.Labels{
labelKeyEnterprise: "test-enterprise",
labelKeyOrganization: "test-org",
labelKeyRepository: "test-repo",
labelKeyRunnerScaleSetName: "test-scale-set",
labelKeyRunnerScaleSetNamespace: "test-namespace",
},
}
tests := []struct {
name string
jobBase actions.JobMessageBase
wantName string
wantTarget string
}{
{
name: "main branch workflow",
jobBase: actions.JobMessageBase{
OwnerName: "actions",
RepositoryName: "runner",
JobDisplayName: "Build and Test",
JobWorkflowRef: "actions/runner/.github/workflows/build.yml@refs/heads/main",
EventName: "push",
},
wantName: "build",
wantTarget: "heads/main",
},
{
name: "feature branch workflow",
jobBase: actions.JobMessageBase{
OwnerName: "myorg",
RepositoryName: "myrepo",
JobDisplayName: "CI/CD Pipeline",
JobWorkflowRef: "myorg/myrepo/.github/workflows/ci-cd-pipeline.yml@refs/heads/feature/new-metrics",
EventName: "push",
},
wantName: "ci-cd-pipeline",
wantTarget: "heads/feature/new-metrics",
},
{
name: "pull request workflow",
jobBase: actions.JobMessageBase{
OwnerName: "actions",
RepositoryName: "runner",
JobDisplayName: "PR Checks",
JobWorkflowRef: "actions/runner/.github/workflows/pr-checks.yml@refs/pull/123/merge",
EventName: "pull_request",
},
wantName: "pr-checks",
wantTarget: "pull/123",
},
{
name: "tag workflow",
jobBase: actions.JobMessageBase{
OwnerName: "actions",
RepositoryName: "runner",
JobDisplayName: "Release",
JobWorkflowRef: "actions/runner/.github/workflows/release.yml@refs/tags/v1.2.3",
EventName: "release",
},
wantName: "release",
wantTarget: "tags/v1.2.3",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
labels := exporter.jobLabels(&tt.jobBase)
// Build expected labels
expectedLabels := prometheus.Labels{
labelKeyEnterprise: "test-enterprise",
labelKeyOrganization: tt.jobBase.OwnerName,
labelKeyRepository: tt.jobBase.RepositoryName,
labelKeyJobName: tt.jobBase.JobDisplayName,
labelKeyJobWorkflowRef: tt.jobBase.JobWorkflowRef,
labelKeyJobWorkflowName: tt.wantName,
labelKeyJobWorkflowTarget: tt.wantTarget,
labelKeyEventName: tt.jobBase.EventName,
}
// Assert all expected labels match
assert.Equal(t, expectedLabels, labels, "jobLabels() returned unexpected labels for %s", tt.name)
})
}
}

View File

@@ -0,0 +1,78 @@
package metrics
import (
"path"
"strings"
)
// WorkflowRefInfo contains parsed information from a job_workflow_ref
type WorkflowRefInfo struct {
// Name is the workflow file name without extension
Name string
// Target is the target ref with type prefix retained for clarity
// Examples:
// - heads/main (branch)
// - heads/feature/new-feature (branch)
// - tags/v1.2.3 (tag)
// - pull/123 (pull request)
Target string
}
// ParseWorkflowRef parses a job_workflow_ref string to extract workflow name and target
// Format: {owner}/{repo}/.github/workflows/{workflow_file}@{ref}
// Example: mygithuborg/myrepo/.github/workflows/blank.yml@refs/heads/main
//
// The target field preserves type prefixes to differentiate between:
// - Branch references: "heads/{branch}" (from refs/heads/{branch})
// - Tag references: "tags/{tag}" (from refs/tags/{tag})
// - Pull requests: "pull/{number}" (from refs/pull/{number}/merge)
func ParseWorkflowRef(workflowRef string) WorkflowRefInfo {
info := WorkflowRefInfo{}
if workflowRef == "" {
return info
}
// Split by @ to separate path and ref
parts := strings.Split(workflowRef, "@")
if len(parts) != 2 {
return info
}
workflowPath := parts[0]
ref := parts[1]
// Extract workflow name from path
// The path format is: {owner}/{repo}/.github/workflows/{workflow_file}
workflowFile := path.Base(workflowPath)
// Remove .yml or .yaml extension
info.Name = strings.TrimSuffix(strings.TrimSuffix(workflowFile, ".yml"), ".yaml")
// Extract target from ref based on type
// Branch refs: refs/heads/{branch}
// Tag refs: refs/tags/{tag}
// PR refs: refs/pull/{number}/merge
const (
branchPrefix = "refs/heads/"
tagPrefix = "refs/tags/"
prPrefix = "refs/pull/"
)
switch {
case strings.HasPrefix(ref, branchPrefix):
// Keep "heads/" prefix to indicate branch
info.Target = "heads/" + strings.TrimPrefix(ref, branchPrefix)
case strings.HasPrefix(ref, tagPrefix):
// Keep "tags/" prefix to indicate tag
info.Target = "tags/" + strings.TrimPrefix(ref, tagPrefix)
case strings.HasPrefix(ref, prPrefix):
// Extract PR number from refs/pull/{number}/merge
// Keep "pull/" prefix to indicate pull request
prPart := strings.TrimPrefix(ref, prPrefix)
if idx := strings.Index(prPart, "/"); idx > 0 {
info.Target = "pull/" + prPart[:idx]
}
}
return info
}

View File

@@ -0,0 +1,82 @@
package metrics
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseWorkflowRef(t *testing.T) {
tests := []struct {
name string
workflowRef string
wantName string
wantTarget string
}{
{
name: "standard branch reference with yml",
workflowRef: "actions-runner-controller-sandbox/mumoshu-orgrunner-test-01/.github/workflows/blank.yml@refs/heads/main",
wantName: "blank",
wantTarget: "heads/main",
},
{
name: "branch with special characters",
workflowRef: "owner/repo/.github/workflows/ci-cd.yml@refs/heads/feature/new-feature",
wantName: "ci-cd",
wantTarget: "heads/feature/new-feature",
},
{
name: "yaml extension",
workflowRef: "owner/repo/.github/workflows/deploy.yaml@refs/heads/develop",
wantName: "deploy",
wantTarget: "heads/develop",
},
{
name: "tag reference",
workflowRef: "owner/repo/.github/workflows/release.yml@refs/tags/v1.0.0",
wantName: "release",
wantTarget: "tags/v1.0.0",
},
{
name: "pull request reference",
workflowRef: "owner/repo/.github/workflows/test.yml@refs/pull/123/merge",
wantName: "test",
wantTarget: "pull/123",
},
{
name: "empty workflow ref",
workflowRef: "",
wantName: "",
wantTarget: "",
},
{
name: "invalid format - no @ separator",
workflowRef: "owner/repo/.github/workflows/test.yml",
wantName: "",
wantTarget: "",
},
{
name: "workflow with dots in name",
workflowRef: "owner/repo/.github/workflows/build.test.yml@refs/heads/main",
wantName: "build.test",
wantTarget: "heads/main",
},
{
name: "workflow with hyphen and underscore",
workflowRef: "owner/repo/.github/workflows/build-test_deploy.yml@refs/heads/main",
wantName: "build-test_deploy",
wantTarget: "heads/main",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ParseWorkflowRef(tt.workflowRef)
expected := WorkflowRefInfo{
Name: tt.wantName,
Target: tt.wantTarget,
}
assert.Equal(t, expected, got, "ParseWorkflowRef(%q) returned unexpected result", tt.workflowRef)
})
}
}

View File

@@ -100,10 +100,11 @@ func (w *Worker) HandleJobStarted(ctx context.Context, jobInfo *actions.JobStart
"runnerName", jobInfo.RunnerName, "runnerName", jobInfo.RunnerName,
"ownerName", jobInfo.OwnerName, "ownerName", jobInfo.OwnerName,
"repoName", jobInfo.RepositoryName, "repoName", jobInfo.RepositoryName,
"jobId", jobInfo.JobID,
"workflowRef", jobInfo.JobWorkflowRef, "workflowRef", jobInfo.JobWorkflowRef,
"workflowRunId", jobInfo.WorkflowRunId, "workflowRunId", jobInfo.WorkflowRunID,
"jobDisplayName", jobInfo.JobDisplayName, "jobDisplayName", jobInfo.JobDisplayName,
"requestId", jobInfo.RunnerRequestId) "requestId", jobInfo.RunnerRequestID)
original, err := json.Marshal(&v1alpha1.EphemeralRunner{}) original, err := json.Marshal(&v1alpha1.EphemeralRunner{})
if err != nil { if err != nil {
@@ -113,9 +114,10 @@ func (w *Worker) HandleJobStarted(ctx context.Context, jobInfo *actions.JobStart
patch, err := json.Marshal( patch, err := json.Marshal(
&v1alpha1.EphemeralRunner{ &v1alpha1.EphemeralRunner{
Status: v1alpha1.EphemeralRunnerStatus{ Status: v1alpha1.EphemeralRunnerStatus{
JobRequestId: jobInfo.RunnerRequestId, JobRequestId: jobInfo.RunnerRequestID,
JobRepositoryName: fmt.Sprintf("%s/%s", jobInfo.OwnerName, jobInfo.RepositoryName), JobRepositoryName: fmt.Sprintf("%s/%s", jobInfo.OwnerName, jobInfo.RepositoryName),
WorkflowRunId: jobInfo.WorkflowRunId, JobID: jobInfo.JobID,
WorkflowRunId: jobInfo.WorkflowRunID,
JobWorkflowRef: jobInfo.JobWorkflowRef, JobWorkflowRef: jobInfo.JobWorkflowRef,
JobDisplayName: jobInfo.JobDisplayName, JobDisplayName: jobInfo.JobDisplayName,
}, },

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.17.2 controller-gen.kubebuilder.io/version: v0.19.0
name: ephemeralrunners.actions.github.com name: ephemeralrunners.actions.github.com
spec: spec:
group: actions.github.com group: actions.github.com
@@ -36,6 +36,9 @@ spec:
- jsonPath: .status.jobDisplayName - jsonPath: .status.jobDisplayName
name: JobDisplayName name: JobDisplayName
type: string type: string
- jsonPath: .status.jobId
name: JobId
type: string
- jsonPath: .status.message - jsonPath: .status.message
name: Message name: Message
type: string type: string
@@ -427,7 +430,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -442,7 +444,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -603,7 +604,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -618,7 +618,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -707,8 +706,8 @@ spec:
most preferred is the one with the greatest sum of weights, i.e. most preferred is the one with the greatest sum of weights, i.e.
for each node that meets all of the scheduling requirements (resource for each node that meets all of the scheduling requirements (resource
request, requiredDuringScheduling anti-affinity expressions, etc.), request, requiredDuringScheduling anti-affinity expressions, etc.),
compute a sum by iterating through the elements of this field and adding compute a sum by iterating through the elements of this field and subtracting
"weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
node(s) with the highest sum are the most preferred. node(s) with the highest sum are the most preferred.
items: items:
description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s)
@@ -772,7 +771,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -787,7 +785,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -948,7 +945,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -963,7 +959,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -1090,7 +1085,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -1144,6 +1141,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -1199,13 +1232,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -1225,7 +1258,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -1474,6 +1509,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: |- description: |-
@@ -1864,7 +1905,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -1915,10 +1956,10 @@ spec:
restartPolicy: restartPolicy:
description: |- description: |-
RestartPolicy defines the restart behavior of individual containers in a pod. RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always". This overrides the pod-level restart policy. When this field is not specified,
For non-init containers or when this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type. the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect: Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always" containers have completed, all init containers with restartPolicy "Always"
@@ -1930,6 +1971,57 @@ spec:
init container is started, or after any startupProbe has successfully init container is started, or after any startupProbe has successfully
completed. completed.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
SecurityContext defines the security options the container should be run with. SecurityContext defines the security options the container should be run with.
@@ -2527,7 +2619,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -2581,6 +2675,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -2636,13 +2766,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -2662,7 +2792,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -2907,6 +3039,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: Probes are not allowed for ephemeral containers. description: Probes are not allowed for ephemeral containers.
@@ -3280,7 +3418,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -3332,9 +3470,51 @@ spec:
description: |- description: |-
Restart policy for the container to manage the restart behavior of each Restart policy for the container to manage the restart behavior of each
container within a pod. container within a pod.
This may only be set for init containers. You cannot set this field on You cannot set this field on ephemeral containers.
ephemeral containers.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. You cannot set this field on
ephemeral containers.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
Optional: SecurityContext defines the security options the ephemeral container should be run with. Optional: SecurityContext defines the security options the ephemeral container should be run with.
@@ -3853,7 +4033,9 @@ spec:
hostNetwork: hostNetwork:
description: |- description: |-
Host networking requested for this pod. Use the host's network namespace. Host networking requested for this pod. Use the host's network namespace.
If this option is set, the ports that will be used must be specified. When using HostNetwork you should specify ports so the scheduler is aware.
When `hostNetwork` is true, specified `hostPort` fields in port definitions must match `containerPort`,
and unspecified `hostPort` fields in port definitions are defaulted to match `containerPort`.
Default to false. Default to false.
type: boolean type: boolean
hostPID: hostPID:
@@ -3878,6 +4060,19 @@ spec:
Specifies the hostname of the Pod Specifies the hostname of the Pod
If not specified, the pod's hostname will be set to a system-defined value. If not specified, the pod's hostname will be set to a system-defined value.
type: string type: string
hostnameOverride:
description: |-
HostnameOverride specifies an explicit override for the pod's hostname as perceived by the pod.
This field only specifies the pod's hostname and does not affect its DNS records.
When this field is set to a non-empty string:
- It takes precedence over the values set in `hostname` and `subdomain`.
- The Pod's hostname will be set to this value.
- `setHostnameAsFQDN` must be nil or set to false.
- `hostNetwork` must be set to false.
This field must be a valid DNS subdomain as defined in RFC 1123 and contain at most 64 characters.
Requires the HostnameOverride feature gate to be enabled.
type: string
imagePullSecrets: imagePullSecrets:
description: |- description: |-
ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
@@ -3913,7 +4108,7 @@ spec:
Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes.
The resourceRequirements of an init container are taken into account during scheduling The resourceRequirements of an init container are taken into account during scheduling
by finding the highest request/limit for each resource type, and then using the max of by finding the highest request/limit for each resource type, and then using the max of
of that value or the sum of the normal containers. Limits are applied to init containers that value or the sum of the normal containers. Limits are applied to init containers
in a similar fashion. in a similar fashion.
Init containers cannot currently be added or removed. Init containers cannot currently be added or removed.
Cannot be updated. Cannot be updated.
@@ -3957,7 +4152,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -4011,6 +4208,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -4066,13 +4299,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -4092,7 +4325,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -4341,6 +4576,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: |- description: |-
@@ -4731,7 +4972,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -4782,10 +5023,10 @@ spec:
restartPolicy: restartPolicy:
description: |- description: |-
RestartPolicy defines the restart behavior of individual containers in a pod. RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always". This overrides the pod-level restart policy. When this field is not specified,
For non-init containers or when this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type. the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect: Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always" containers have completed, all init containers with restartPolicy "Always"
@@ -4797,6 +5038,57 @@ spec:
init container is started, or after any startupProbe has successfully init container is started, or after any startupProbe has successfully
completed. completed.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
SecurityContext defines the security options the container should be run with. SecurityContext defines the security options the container should be run with.
@@ -5310,6 +5602,7 @@ spec:
- spec.hostPID - spec.hostPID
- spec.hostIPC - spec.hostIPC
- spec.hostUsers - spec.hostUsers
- spec.resources
- spec.securityContext.appArmorProfile - spec.securityContext.appArmorProfile
- spec.securityContext.seLinuxOptions - spec.securityContext.seLinuxOptions
- spec.securityContext.seccompProfile - spec.securityContext.seccompProfile
@@ -5461,7 +5754,7 @@ spec:
description: |- description: |-
Resources is the total amount of CPU and Memory resources required by all Resources is the total amount of CPU and Memory resources required by all
containers in the pod. It supports specifying Requests and Limits for containers in the pod. It supports specifying Requests and Limits for
"cpu" and "memory" resource names only. ResourceClaims are not supported. "cpu", "memory" and "hugepages-" resource names only. ResourceClaims are not supported.
This field enables fine-grained control over resource allocation for the This field enables fine-grained control over resource allocation for the
entire pod, allowing resource sharing among containers in a pod. entire pod, allowing resource sharing among containers in a pod.
@@ -5474,7 +5767,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -6002,7 +6295,6 @@ spec:
- Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.
If this value is nil, the behavior is equivalent to the Honor policy. If this value is nil, the behavior is equivalent to the Honor policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string type: string
nodeTaintsPolicy: nodeTaintsPolicy:
description: |- description: |-
@@ -6013,7 +6305,6 @@ spec:
- Ignore: node taints are ignored. All nodes are included. - Ignore: node taints are ignored. All nodes are included.
If this value is nil, the behavior is equivalent to the Ignore policy. If this value is nil, the behavior is equivalent to the Ignore policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string type: string
topologyKey: topologyKey:
description: |- description: |-
@@ -6719,15 +7010,13 @@ spec:
volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim.
If specified, the CSI driver will create or update the volume with the attributes defined If specified, the CSI driver will create or update the volume with the attributes defined
in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName,
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass it can be changed after the claim is created. An empty string or nil value indicates that no
will be applied to the claim but it's not allowed to reset this field to empty string once it is set. VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass this field can be reset to its previous value (including nil) to cancel the modification.
will be set by the persistentvolume controller if it exists.
If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be
set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource
exists. exists.
More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/
(Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default).
type: string type: string
volumeMode: volumeMode:
description: |- description: |-
@@ -6901,12 +7190,9 @@ spec:
description: |- description: |-
glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime.
Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported.
More info: https://examples.k8s.io/volumes/glusterfs/README.md
properties: properties:
endpoints: endpoints:
description: |- description: endpoints is the endpoint name that details Glusterfs topology.
endpoints is the endpoint name that details Glusterfs topology.
More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod
type: string type: string
path: path:
description: |- description: |-
@@ -6960,7 +7246,7 @@ spec:
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
The volume will be mounted read-only (ro) and non-executable files (noexec). The volume will be mounted read-only (ro) and non-executable files (noexec).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties: properties:
pullPolicy: pullPolicy:
@@ -6985,7 +7271,7 @@ spec:
description: |- description: |-
iscsi represents an ISCSI Disk resource that is attached to a iscsi represents an ISCSI Disk resource that is attached to a
kubelet's host machine and then exposed to the pod. kubelet's host machine and then exposed to the pod.
More info: https://examples.k8s.io/volumes/iscsi/README.md More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi
properties: properties:
chapAuthDiscovery: chapAuthDiscovery:
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
@@ -7375,6 +7661,110 @@ spec:
type: array type: array
x-kubernetes-list-type: atomic x-kubernetes-list-type: atomic
type: object type: object
podCertificate:
description: |-
Projects an auto-rotating credential bundle (private key and certificate
chain) that the pod can use either as a TLS client or server.
Kubelet generates a private key and uses it to send a
PodCertificateRequest to the named signer. Once the signer approves the
request and issues a certificate chain, Kubelet writes the key and
certificate chain to the pod filesystem. The pod does not start until
certificates have been issued for each podCertificate projected volume
source in its spec.
Kubelet will begin trying to rotate the certificate at the time indicated
by the signer using the PodCertificateRequest.Status.BeginRefreshAt
timestamp.
Kubelet can write a single file, indicated by the credentialBundlePath
field, or separate files, indicated by the keyPath and
certificateChainPath fields.
The credential bundle is a single file in PEM format. The first PEM
entry is the private key (in PKCS#8 format), and the remaining PEM
entries are the certificate chain issued by the signer (typically,
signers will return their certificate chain in leaf-to-root order).
Prefer using the credential bundle format, since your application code
can read it atomically. If you use keyPath and certificateChainPath,
your application must make two separate file reads. If these coincide
with a certificate rotation, it is possible that the private key and leaf
certificate you read may not correspond to each other. Your application
will need to check for this condition, and re-read until they are
consistent.
The named signer controls chooses the format of the certificate it
issues; consult the signer implementation's documentation to learn how to
use the certificates it issues.
properties:
certificateChainPath:
description: |-
Write the certificate chain at this path in the projected volume.
Most applications should use credentialBundlePath. When using keyPath
and certificateChainPath, your application needs to check that the key
and leaf certificate are consistent, because it is possible to read the
files mid-rotation.
type: string
credentialBundlePath:
description: |-
Write the credential bundle at this path in the projected volume.
The credential bundle is a single file that contains multiple PEM blocks.
The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private
key.
The remaining blocks are CERTIFICATE blocks, containing the issued
certificate chain from the signer (leaf and any intermediates).
Using credentialBundlePath lets your Pod's application code make a single
atomic read that retrieves a consistent key and certificate chain. If you
project them to separate files, your application code will need to
additionally check that the leaf certificate was issued to the key.
type: string
keyPath:
description: |-
Write the key at this path in the projected volume.
Most applications should use credentialBundlePath. When using keyPath
and certificateChainPath, your application needs to check that the key
and leaf certificate are consistent, because it is possible to read the
files mid-rotation.
type: string
keyType:
description: |-
The type of keypair Kubelet will generate for the pod.
Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384",
"ECDSAP521", and "ED25519".
type: string
maxExpirationSeconds:
description: |-
maxExpirationSeconds is the maximum lifetime permitted for the
certificate.
Kubelet copies this value verbatim into the PodCertificateRequests it
generates for this projection.
If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver
will reject values shorter than 3600 (1 hour). The maximum allowable
value is 7862400 (91 days).
The signer implementation is then free to issue a certificate with any
lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600
seconds (1 hour). This constraint is enforced by kube-apiserver.
`kubernetes.io` signers will never issue certificates with a lifetime
longer than 24 hours.
format: int32
type: integer
signerName:
description: Kubelet's generated CSRs will be addressed to this signer.
type: string
required:
- keyType
- signerName
type: object
secret: secret:
description: secret information about the secret data to project description: secret information about the secret data to project
properties: properties:
@@ -7504,7 +7894,6 @@ spec:
description: |- description: |-
rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. rbd represents a Rados Block Device mount on the host that shares a pod's lifetime.
Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported.
More info: https://examples.k8s.io/volumes/rbd/README.md
properties: properties:
fsType: fsType:
description: |- description: |-
@@ -7846,6 +8235,8 @@ spec:
type: object type: object
jobDisplayName: jobDisplayName:
type: string type: string
jobId:
type: string
jobRepositoryName: jobRepositoryName:
type: string type: string
jobRequestId: jobRequestId:
@@ -7874,8 +8265,6 @@ spec:
type: string type: string
runnerId: runnerId:
type: integer type: integer
runnerJITConfig:
type: string
runnerName: runnerName:
type: string type: string
workflowRunId: workflowRunId:
@@ -7887,4 +8276,3 @@ spec:
storage: true storage: true
subresources: subresources:
status: {} status: {}
preserveUnknownFields: false

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.17.2 controller-gen.kubebuilder.io/version: v0.19.0
name: ephemeralrunnersets.actions.github.com name: ephemeralrunnersets.actions.github.com
spec: spec:
group: actions.github.com group: actions.github.com
@@ -421,7 +421,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -436,7 +435,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -597,7 +595,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -612,7 +609,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -701,8 +697,8 @@ spec:
most preferred is the one with the greatest sum of weights, i.e. most preferred is the one with the greatest sum of weights, i.e.
for each node that meets all of the scheduling requirements (resource for each node that meets all of the scheduling requirements (resource
request, requiredDuringScheduling anti-affinity expressions, etc.), request, requiredDuringScheduling anti-affinity expressions, etc.),
compute a sum by iterating through the elements of this field and adding compute a sum by iterating through the elements of this field and subtracting
"weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
node(s) with the highest sum are the most preferred. node(s) with the highest sum are the most preferred.
items: items:
description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s)
@@ -766,7 +762,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -781,7 +776,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -942,7 +936,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -957,7 +950,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -1084,7 +1076,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -1138,6 +1132,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -1193,13 +1223,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -1219,7 +1249,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -1468,6 +1500,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: |- description: |-
@@ -1858,7 +1896,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -1909,10 +1947,10 @@ spec:
restartPolicy: restartPolicy:
description: |- description: |-
RestartPolicy defines the restart behavior of individual containers in a pod. RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always". This overrides the pod-level restart policy. When this field is not specified,
For non-init containers or when this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type. the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect: Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always" containers have completed, all init containers with restartPolicy "Always"
@@ -1924,6 +1962,57 @@ spec:
init container is started, or after any startupProbe has successfully init container is started, or after any startupProbe has successfully
completed. completed.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
SecurityContext defines the security options the container should be run with. SecurityContext defines the security options the container should be run with.
@@ -2521,7 +2610,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -2575,6 +2666,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -2630,13 +2757,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -2656,7 +2783,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -2901,6 +3030,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: Probes are not allowed for ephemeral containers. description: Probes are not allowed for ephemeral containers.
@@ -3274,7 +3409,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -3326,9 +3461,51 @@ spec:
description: |- description: |-
Restart policy for the container to manage the restart behavior of each Restart policy for the container to manage the restart behavior of each
container within a pod. container within a pod.
This may only be set for init containers. You cannot set this field on You cannot set this field on ephemeral containers.
ephemeral containers.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. You cannot set this field on
ephemeral containers.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
Optional: SecurityContext defines the security options the ephemeral container should be run with. Optional: SecurityContext defines the security options the ephemeral container should be run with.
@@ -3847,7 +4024,9 @@ spec:
hostNetwork: hostNetwork:
description: |- description: |-
Host networking requested for this pod. Use the host's network namespace. Host networking requested for this pod. Use the host's network namespace.
If this option is set, the ports that will be used must be specified. When using HostNetwork you should specify ports so the scheduler is aware.
When `hostNetwork` is true, specified `hostPort` fields in port definitions must match `containerPort`,
and unspecified `hostPort` fields in port definitions are defaulted to match `containerPort`.
Default to false. Default to false.
type: boolean type: boolean
hostPID: hostPID:
@@ -3872,6 +4051,19 @@ spec:
Specifies the hostname of the Pod Specifies the hostname of the Pod
If not specified, the pod's hostname will be set to a system-defined value. If not specified, the pod's hostname will be set to a system-defined value.
type: string type: string
hostnameOverride:
description: |-
HostnameOverride specifies an explicit override for the pod's hostname as perceived by the pod.
This field only specifies the pod's hostname and does not affect its DNS records.
When this field is set to a non-empty string:
- It takes precedence over the values set in `hostname` and `subdomain`.
- The Pod's hostname will be set to this value.
- `setHostnameAsFQDN` must be nil or set to false.
- `hostNetwork` must be set to false.
This field must be a valid DNS subdomain as defined in RFC 1123 and contain at most 64 characters.
Requires the HostnameOverride feature gate to be enabled.
type: string
imagePullSecrets: imagePullSecrets:
description: |- description: |-
ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
@@ -3907,7 +4099,7 @@ spec:
Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes.
The resourceRequirements of an init container are taken into account during scheduling The resourceRequirements of an init container are taken into account during scheduling
by finding the highest request/limit for each resource type, and then using the max of by finding the highest request/limit for each resource type, and then using the max of
of that value or the sum of the normal containers. Limits are applied to init containers that value or the sum of the normal containers. Limits are applied to init containers
in a similar fashion. in a similar fashion.
Init containers cannot currently be added or removed. Init containers cannot currently be added or removed.
Cannot be updated. Cannot be updated.
@@ -3951,7 +4143,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -4005,6 +4199,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -4060,13 +4290,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -4086,7 +4316,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -4335,6 +4567,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: |- description: |-
@@ -4725,7 +4963,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -4776,10 +5014,10 @@ spec:
restartPolicy: restartPolicy:
description: |- description: |-
RestartPolicy defines the restart behavior of individual containers in a pod. RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always". This overrides the pod-level restart policy. When this field is not specified,
For non-init containers or when this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type. the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect: Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always" containers have completed, all init containers with restartPolicy "Always"
@@ -4791,6 +5029,57 @@ spec:
init container is started, or after any startupProbe has successfully init container is started, or after any startupProbe has successfully
completed. completed.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
SecurityContext defines the security options the container should be run with. SecurityContext defines the security options the container should be run with.
@@ -5304,6 +5593,7 @@ spec:
- spec.hostPID - spec.hostPID
- spec.hostIPC - spec.hostIPC
- spec.hostUsers - spec.hostUsers
- spec.resources
- spec.securityContext.appArmorProfile - spec.securityContext.appArmorProfile
- spec.securityContext.seLinuxOptions - spec.securityContext.seLinuxOptions
- spec.securityContext.seccompProfile - spec.securityContext.seccompProfile
@@ -5455,7 +5745,7 @@ spec:
description: |- description: |-
Resources is the total amount of CPU and Memory resources required by all Resources is the total amount of CPU and Memory resources required by all
containers in the pod. It supports specifying Requests and Limits for containers in the pod. It supports specifying Requests and Limits for
"cpu" and "memory" resource names only. ResourceClaims are not supported. "cpu", "memory" and "hugepages-" resource names only. ResourceClaims are not supported.
This field enables fine-grained control over resource allocation for the This field enables fine-grained control over resource allocation for the
entire pod, allowing resource sharing among containers in a pod. entire pod, allowing resource sharing among containers in a pod.
@@ -5468,7 +5758,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -5996,7 +6286,6 @@ spec:
- Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.
If this value is nil, the behavior is equivalent to the Honor policy. If this value is nil, the behavior is equivalent to the Honor policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string type: string
nodeTaintsPolicy: nodeTaintsPolicy:
description: |- description: |-
@@ -6007,7 +6296,6 @@ spec:
- Ignore: node taints are ignored. All nodes are included. - Ignore: node taints are ignored. All nodes are included.
If this value is nil, the behavior is equivalent to the Ignore policy. If this value is nil, the behavior is equivalent to the Ignore policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string type: string
topologyKey: topologyKey:
description: |- description: |-
@@ -6713,15 +7001,13 @@ spec:
volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim.
If specified, the CSI driver will create or update the volume with the attributes defined If specified, the CSI driver will create or update the volume with the attributes defined
in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName,
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass it can be changed after the claim is created. An empty string or nil value indicates that no
will be applied to the claim but it's not allowed to reset this field to empty string once it is set. VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass this field can be reset to its previous value (including nil) to cancel the modification.
will be set by the persistentvolume controller if it exists.
If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be
set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource
exists. exists.
More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/
(Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default).
type: string type: string
volumeMode: volumeMode:
description: |- description: |-
@@ -6895,12 +7181,9 @@ spec:
description: |- description: |-
glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime.
Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported.
More info: https://examples.k8s.io/volumes/glusterfs/README.md
properties: properties:
endpoints: endpoints:
description: |- description: endpoints is the endpoint name that details Glusterfs topology.
endpoints is the endpoint name that details Glusterfs topology.
More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod
type: string type: string
path: path:
description: |- description: |-
@@ -6954,7 +7237,7 @@ spec:
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
The volume will be mounted read-only (ro) and non-executable files (noexec). The volume will be mounted read-only (ro) and non-executable files (noexec).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties: properties:
pullPolicy: pullPolicy:
@@ -6979,7 +7262,7 @@ spec:
description: |- description: |-
iscsi represents an ISCSI Disk resource that is attached to a iscsi represents an ISCSI Disk resource that is attached to a
kubelet's host machine and then exposed to the pod. kubelet's host machine and then exposed to the pod.
More info: https://examples.k8s.io/volumes/iscsi/README.md More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi
properties: properties:
chapAuthDiscovery: chapAuthDiscovery:
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
@@ -7369,6 +7652,110 @@ spec:
type: array type: array
x-kubernetes-list-type: atomic x-kubernetes-list-type: atomic
type: object type: object
podCertificate:
description: |-
Projects an auto-rotating credential bundle (private key and certificate
chain) that the pod can use either as a TLS client or server.
Kubelet generates a private key and uses it to send a
PodCertificateRequest to the named signer. Once the signer approves the
request and issues a certificate chain, Kubelet writes the key and
certificate chain to the pod filesystem. The pod does not start until
certificates have been issued for each podCertificate projected volume
source in its spec.
Kubelet will begin trying to rotate the certificate at the time indicated
by the signer using the PodCertificateRequest.Status.BeginRefreshAt
timestamp.
Kubelet can write a single file, indicated by the credentialBundlePath
field, or separate files, indicated by the keyPath and
certificateChainPath fields.
The credential bundle is a single file in PEM format. The first PEM
entry is the private key (in PKCS#8 format), and the remaining PEM
entries are the certificate chain issued by the signer (typically,
signers will return their certificate chain in leaf-to-root order).
Prefer using the credential bundle format, since your application code
can read it atomically. If you use keyPath and certificateChainPath,
your application must make two separate file reads. If these coincide
with a certificate rotation, it is possible that the private key and leaf
certificate you read may not correspond to each other. Your application
will need to check for this condition, and re-read until they are
consistent.
The named signer controls chooses the format of the certificate it
issues; consult the signer implementation's documentation to learn how to
use the certificates it issues.
properties:
certificateChainPath:
description: |-
Write the certificate chain at this path in the projected volume.
Most applications should use credentialBundlePath. When using keyPath
and certificateChainPath, your application needs to check that the key
and leaf certificate are consistent, because it is possible to read the
files mid-rotation.
type: string
credentialBundlePath:
description: |-
Write the credential bundle at this path in the projected volume.
The credential bundle is a single file that contains multiple PEM blocks.
The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private
key.
The remaining blocks are CERTIFICATE blocks, containing the issued
certificate chain from the signer (leaf and any intermediates).
Using credentialBundlePath lets your Pod's application code make a single
atomic read that retrieves a consistent key and certificate chain. If you
project them to separate files, your application code will need to
additionally check that the leaf certificate was issued to the key.
type: string
keyPath:
description: |-
Write the key at this path in the projected volume.
Most applications should use credentialBundlePath. When using keyPath
and certificateChainPath, your application needs to check that the key
and leaf certificate are consistent, because it is possible to read the
files mid-rotation.
type: string
keyType:
description: |-
The type of keypair Kubelet will generate for the pod.
Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384",
"ECDSAP521", and "ED25519".
type: string
maxExpirationSeconds:
description: |-
maxExpirationSeconds is the maximum lifetime permitted for the
certificate.
Kubelet copies this value verbatim into the PodCertificateRequests it
generates for this projection.
If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver
will reject values shorter than 3600 (1 hour). The maximum allowable
value is 7862400 (91 days).
The signer implementation is then free to issue a certificate with any
lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600
seconds (1 hour). This constraint is enforced by kube-apiserver.
`kubernetes.io` signers will never issue certificates with a lifetime
longer than 24 hours.
format: int32
type: integer
signerName:
description: Kubelet's generated CSRs will be addressed to this signer.
type: string
required:
- keyType
- signerName
type: object
secret: secret:
description: secret information about the secret data to project description: secret information about the secret data to project
properties: properties:
@@ -7498,7 +7885,6 @@ spec:
description: |- description: |-
rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. rbd represents a Rados Block Device mount on the host that shares a pod's lifetime.
Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported.
More info: https://examples.k8s.io/volumes/rbd/README.md
properties: properties:
fsType: fsType:
description: |- description: |-
@@ -7859,4 +8245,3 @@ spec:
storage: true storage: true
subresources: subresources:
status: {} status: {}
preserveUnknownFields: false

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.17.2 controller-gen.kubebuilder.io/version: v0.19.0
name: horizontalrunnerautoscalers.actions.summerwind.dev name: horizontalrunnerautoscalers.actions.summerwind.dev
spec: spec:
group: actions.summerwind.dev group: actions.summerwind.dev
@@ -12,306 +12,313 @@ spec:
listKind: HorizontalRunnerAutoscalerList listKind: HorizontalRunnerAutoscalerList
plural: horizontalrunnerautoscalers plural: horizontalrunnerautoscalers
shortNames: shortNames:
- hra - hra
singular: horizontalrunnerautoscaler singular: horizontalrunnerautoscaler
scope: Namespaced scope: Namespaced
versions: versions:
- additionalPrinterColumns: - additionalPrinterColumns:
- jsonPath: .spec.minReplicas - jsonPath: .spec.minReplicas
name: Min name: Min
type: number type: number
- jsonPath: .spec.maxReplicas - jsonPath: .spec.maxReplicas
name: Max name: Max
type: number type: number
- jsonPath: .status.desiredReplicas - jsonPath: .status.desiredReplicas
name: Desired name: Desired
type: number type: number
- jsonPath: .status.scheduledOverridesSummary - jsonPath: .status.scheduledOverridesSummary
name: Schedule name: Schedule
type: string type: string
name: v1alpha1 name: v1alpha1
schema: schema:
openAPIV3Schema: openAPIV3Schema:
description: HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler API description: HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler
properties: API
apiVersion: properties:
description: |- apiVersion:
APIVersion defines the versioned schema of this representation of an object. description: |-
Servers should convert recognized schemas to the latest internal value, and APIVersion defines the versioned schema of this representation of an object.
may reject unrecognized values. Servers should convert recognized schemas to the latest internal value, and
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources may reject unrecognized values.
type: string More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
kind: type: string
description: |- kind:
Kind is a string value representing the REST resource this object represents. description: |-
Servers may infer this from the endpoint the client submits requests to. Kind is a string value representing the REST resource this object represents.
Cannot be updated. Servers may infer this from the endpoint the client submits requests to.
In CamelCase. Cannot be updated.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds In CamelCase.
type: string More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
metadata: type: string
type: object metadata:
spec: type: object
description: HorizontalRunnerAutoscalerSpec defines the desired state of HorizontalRunnerAutoscaler spec:
properties: description: HorizontalRunnerAutoscalerSpec defines the desired state
capacityReservations: of HorizontalRunnerAutoscaler
items: properties:
description: |- capacityReservations:
CapacityReservation specifies the number of replicas temporarily added items:
to the scale target until ExpirationTime.
properties:
effectiveTime:
format: date-time
type: string
expirationTime:
format: date-time
type: string
name:
type: string
replicas:
type: integer
type: object
type: array
githubAPICredentialsFrom:
properties:
secretRef:
properties:
name:
type: string
required:
- name
type: object
type: object
maxReplicas:
description: MaxReplicas is the maximum number of replicas the deployment is allowed to scale
type: integer
metrics:
description: Metrics is the collection of various metric targets to calculate desired number of runners
items:
properties:
repositoryNames:
description: |-
RepositoryNames is the list of repository names to be used for calculating the metric.
For example, a repository name is the REPO part of `github.com/USER/REPO`.
items:
type: string
type: array
scaleDownAdjustment:
description: |-
ScaleDownAdjustment is the number of runners removed on scale-down.
You can only specify either ScaleDownFactor or ScaleDownAdjustment.
type: integer
scaleDownFactor:
description: |-
ScaleDownFactor is the multiplicative factor applied to the current number of runners used
to determine how many pods should be removed.
type: string
scaleDownThreshold:
description: |-
ScaleDownThreshold is the percentage of busy runners less than which will
trigger the hpa to scale the runners down.
type: string
scaleUpAdjustment:
description: |-
ScaleUpAdjustment is the number of runners added on scale-up.
You can only specify either ScaleUpFactor or ScaleUpAdjustment.
type: integer
scaleUpFactor:
description: |-
ScaleUpFactor is the multiplicative factor applied to the current number of runners used
to determine how many pods should be added.
type: string
scaleUpThreshold:
description: |-
ScaleUpThreshold is the percentage of busy runners greater than which will
trigger the hpa to scale runners up.
type: string
type:
description: |-
Type is the type of metric to be used for autoscaling.
It can be TotalNumberOfQueuedAndInProgressWorkflowRuns or PercentageRunnersBusy.
type: string
type: object
type: array
minReplicas:
description: MinReplicas is the minimum number of replicas the deployment is allowed to scale
type: integer
scaleDownDelaySecondsAfterScaleOut:
description: |- description: |-
ScaleDownDelaySecondsAfterScaleUp is the approximate delay for a scale down followed by a scale up CapacityReservation specifies the number of replicas temporarily added
Used to prevent flapping (down->up->down->... loop) to the scale target until ExpirationTime.
type: integer
scaleTargetRef:
description: ScaleTargetRef is the reference to scaled resource like RunnerDeployment
properties: properties:
kind: effectiveTime:
description: Kind is the type of resource being referenced format: date-time
enum: type: string
- RunnerDeployment expirationTime:
- RunnerSet format: date-time
type: string type: string
name: name:
description: Name is the name of resource being referenced
type: string type: string
replicas:
type: integer
type: object type: object
scaleUpTriggers: type: array
description: |- githubAPICredentialsFrom:
ScaleUpTriggers is an experimental feature to increase the desired replicas by 1 properties:
on each webhook requested received by the webhookBasedAutoscaler. secretRef:
This feature requires you to also enable and deploy the webhookBasedAutoscaler onto your cluster.
Note that the added runners remain until the next sync period at least,
and they may or may not be used by GitHub Actions depending on the timing.
They are intended to be used to gain "resource slack" immediately after you
receive a webhook from GitHub, so that you can loosely expect MinReplicas runners to be always available.
items:
properties: properties:
amount: name:
type: integer
duration:
type: string
githubEvent:
properties:
checkRun:
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#check_run
properties:
names:
description: |-
Names is a list of GitHub Actions glob patterns.
Any check_run event whose name matches one of patterns in the list can trigger autoscaling.
Note that check_run name seem to equal to the job name you've defined in your actions workflow yaml file.
So it is very likely that you can utilize this to trigger depending on the job.
items:
type: string
type: array
repositories:
description: |-
Repositories is a list of GitHub repositories.
Any check_run event whose repository matches one of repositories in the list can trigger autoscaling.
items:
type: string
type: array
status:
type: string
types:
description: 'One of: created, rerequested, or completed'
items:
type: string
type: array
type: object
pullRequest:
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request
properties:
branches:
items:
type: string
type: array
types:
items:
type: string
type: array
type: object
push:
description: |-
PushSpec is the condition for triggering scale-up on push event
Also see https://docs.github.com/en/actions/reference/events-that-trigger-workflows#push
type: object
workflowJob:
description: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#workflow_job
type: object
type: object
type: object
type: array
scheduledOverrides:
description: |-
ScheduledOverrides is the list of ScheduledOverride.
It can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule.
The earlier a scheduled override is, the higher it is prioritized.
items:
description: |-
ScheduledOverride can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule.
A schedule can optionally be recurring, so that the corresponding override happens every day, week, month, or year.
properties:
endTime:
description: EndTime is the time at which the first override ends.
format: date-time
type: string
minReplicas:
description: |-
MinReplicas is the number of runners while overriding.
If omitted, it doesn't override minReplicas.
minimum: 0
nullable: true
type: integer
recurrenceRule:
properties:
frequency:
description: |-
Frequency is the name of a predefined interval of each recurrence.
The valid values are "Daily", "Weekly", "Monthly", and "Yearly".
If empty, the corresponding override happens only once.
enum:
- Daily
- Weekly
- Monthly
- Yearly
type: string
untilTime:
description: |-
UntilTime is the time of the final recurrence.
If empty, the schedule recurs forever.
format: date-time
type: string
type: object
startTime:
description: StartTime is the time at which the first override starts.
format: date-time
type: string type: string
required: required:
- endTime - name
- startTime
type: object type: object
type: array type: object
type: object maxReplicas:
status: description: MaxReplicas is the maximum number of replicas the deployment
properties: is allowed to scale
cacheEntries: type: integer
items: metrics:
properties: description: Metrics is the collection of various metric targets to
expirationTime: calculate desired number of runners
format: date-time items:
properties:
repositoryNames:
description: |-
RepositoryNames is the list of repository names to be used for calculating the metric.
For example, a repository name is the REPO part of `github.com/USER/REPO`.
items:
type: string type: string
key: type: array
type: string scaleDownAdjustment:
value: description: |-
type: integer ScaleDownAdjustment is the number of runners removed on scale-down.
type: object You can only specify either ScaleDownFactor or ScaleDownAdjustment.
type: array type: integer
desiredReplicas: scaleDownFactor:
description: |-
ScaleDownFactor is the multiplicative factor applied to the current number of runners used
to determine how many pods should be removed.
type: string
scaleDownThreshold:
description: |-
ScaleDownThreshold is the percentage of busy runners less than which will
trigger the hpa to scale the runners down.
type: string
scaleUpAdjustment:
description: |-
ScaleUpAdjustment is the number of runners added on scale-up.
You can only specify either ScaleUpFactor or ScaleUpAdjustment.
type: integer
scaleUpFactor:
description: |-
ScaleUpFactor is the multiplicative factor applied to the current number of runners used
to determine how many pods should be added.
type: string
scaleUpThreshold:
description: |-
ScaleUpThreshold is the percentage of busy runners greater than which will
trigger the hpa to scale runners up.
type: string
type:
description: |-
Type is the type of metric to be used for autoscaling.
It can be TotalNumberOfQueuedAndInProgressWorkflowRuns or PercentageRunnersBusy.
type: string
type: object
type: array
minReplicas:
description: MinReplicas is the minimum number of replicas the deployment
is allowed to scale
type: integer
scaleDownDelaySecondsAfterScaleOut:
description: |-
ScaleDownDelaySecondsAfterScaleUp is the approximate delay for a scale down followed by a scale up
Used to prevent flapping (down->up->down->... loop)
type: integer
scaleTargetRef:
description: ScaleTargetRef is the reference to scaled resource like
RunnerDeployment
properties:
kind:
description: Kind is the type of resource being referenced
enum:
- RunnerDeployment
- RunnerSet
type: string
name:
description: Name is the name of resource being referenced
type: string
type: object
scaleUpTriggers:
description: |-
ScaleUpTriggers is an experimental feature to increase the desired replicas by 1
on each webhook requested received by the webhookBasedAutoscaler.
This feature requires you to also enable and deploy the webhookBasedAutoscaler onto your cluster.
Note that the added runners remain until the next sync period at least,
and they may or may not be used by GitHub Actions depending on the timing.
They are intended to be used to gain "resource slack" immediately after you
receive a webhook from GitHub, so that you can loosely expect MinReplicas runners to be always available.
items:
properties:
amount:
type: integer
duration:
type: string
githubEvent:
properties:
checkRun:
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#check_run
properties:
names:
description: |-
Names is a list of GitHub Actions glob patterns.
Any check_run event whose name matches one of patterns in the list can trigger autoscaling.
Note that check_run name seem to equal to the job name you've defined in your actions workflow yaml file.
So it is very likely that you can utilize this to trigger depending on the job.
items:
type: string
type: array
repositories:
description: |-
Repositories is a list of GitHub repositories.
Any check_run event whose repository matches one of repositories in the list can trigger autoscaling.
items:
type: string
type: array
status:
type: string
types:
description: 'One of: created, rerequested, or completed'
items:
type: string
type: array
type: object
pullRequest:
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request
properties:
branches:
items:
type: string
type: array
types:
items:
type: string
type: array
type: object
push:
description: |-
PushSpec is the condition for triggering scale-up on push event
Also see https://docs.github.com/en/actions/reference/events-that-trigger-workflows#push
type: object
workflowJob:
description: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#workflow_job
type: object
type: object
type: object
type: array
scheduledOverrides:
description: |-
ScheduledOverrides is the list of ScheduledOverride.
It can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule.
The earlier a scheduled override is, the higher it is prioritized.
items:
description: |- description: |-
DesiredReplicas is the total number of desired, non-terminated and latest pods to be set for the primary RunnerSet ScheduledOverride can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule.
This doesn't include outdated pods while upgrading the deployment and replacing the runnerset. A schedule can optionally be recurring, so that the corresponding override happens every day, week, month, or year.
type: integer properties:
lastSuccessfulScaleOutTime: endTime:
format: date-time description: EndTime is the time at which the first override
nullable: true ends.
type: string format: date-time
observedGeneration: type: string
description: |- minReplicas:
ObservedGeneration is the most recent generation observed for the target. It corresponds to e.g. description: |-
RunnerDeployment's generation, which is updated on mutation by the API Server. MinReplicas is the number of runners while overriding.
format: int64 If omitted, it doesn't override minReplicas.
type: integer minimum: 0
scheduledOverridesSummary: nullable: true
description: |- type: integer
ScheduledOverridesSummary is the summary of active and upcoming scheduled overrides to be shown in e.g. a column of a `kubectl get hra` output recurrenceRule:
for observability. properties:
type: string frequency:
type: object description: |-
type: object Frequency is the name of a predefined interval of each recurrence.
served: true The valid values are "Daily", "Weekly", "Monthly", and "Yearly".
storage: true If empty, the corresponding override happens only once.
subresources: enum:
status: {} - Daily
preserveUnknownFields: false - Weekly
- Monthly
- Yearly
type: string
untilTime:
description: |-
UntilTime is the time of the final recurrence.
If empty, the schedule recurs forever.
format: date-time
type: string
type: object
startTime:
description: StartTime is the time at which the first override
starts.
format: date-time
type: string
required:
- endTime
- startTime
type: object
type: array
type: object
status:
properties:
cacheEntries:
items:
properties:
expirationTime:
format: date-time
type: string
key:
type: string
value:
type: integer
type: object
type: array
desiredReplicas:
description: |-
DesiredReplicas is the total number of desired, non-terminated and latest pods to be set for the primary RunnerSet
This doesn't include outdated pods while upgrading the deployment and replacing the runnerset.
type: integer
lastSuccessfulScaleOutTime:
format: date-time
nullable: true
type: string
observedGeneration:
description: |-
ObservedGeneration is the most recent generation observed for the target. It corresponds to e.g.
RunnerDeployment's generation, which is updated on mutation by the API Server.
format: int64
type: integer
scheduledOverridesSummary:
description: |-
ScheduledOverridesSummary is the summary of active and upcoming scheduled overrides to be shown in e.g. a column of a `kubectl get hra` output
for observability.
type: string
type: object
type: object
served: true
storage: true
subresources:
status: {}

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.17.2 controller-gen.kubebuilder.io/version: v0.19.0
name: runnersets.actions.summerwind.dev name: runnersets.actions.summerwind.dev
spec: spec:
group: actions.summerwind.dev group: actions.summerwind.dev
@@ -554,7 +554,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -569,7 +568,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -730,7 +728,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -745,7 +742,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -834,8 +830,8 @@ spec:
most preferred is the one with the greatest sum of weights, i.e. most preferred is the one with the greatest sum of weights, i.e.
for each node that meets all of the scheduling requirements (resource for each node that meets all of the scheduling requirements (resource
request, requiredDuringScheduling anti-affinity expressions, etc.), request, requiredDuringScheduling anti-affinity expressions, etc.),
compute a sum by iterating through the elements of this field and adding compute a sum by iterating through the elements of this field and subtracting
"weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
node(s) with the highest sum are the most preferred. node(s) with the highest sum are the most preferred.
items: items:
description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s)
@@ -899,7 +895,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -914,7 +909,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -1075,7 +1069,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector. The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set. Also, matchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -1090,7 +1083,6 @@ spec:
pod labels will be ignored. The default value is empty. pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set. Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default).
items: items:
type: string type: string
type: array type: array
@@ -1217,7 +1209,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -1271,6 +1265,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -1326,13 +1356,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -1352,7 +1382,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -1601,6 +1633,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: |- description: |-
@@ -1991,7 +2029,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -2042,10 +2080,10 @@ spec:
restartPolicy: restartPolicy:
description: |- description: |-
RestartPolicy defines the restart behavior of individual containers in a pod. RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always". This overrides the pod-level restart policy. When this field is not specified,
For non-init containers or when this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type. the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect: Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always" containers have completed, all init containers with restartPolicy "Always"
@@ -2057,6 +2095,57 @@ spec:
init container is started, or after any startupProbe has successfully init container is started, or after any startupProbe has successfully
completed. completed.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
SecurityContext defines the security options the container should be run with. SecurityContext defines the security options the container should be run with.
@@ -2654,7 +2743,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -2708,6 +2799,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -2763,13 +2890,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -2789,7 +2916,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -3034,6 +3163,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: Probes are not allowed for ephemeral containers. description: Probes are not allowed for ephemeral containers.
@@ -3407,7 +3542,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -3459,9 +3594,51 @@ spec:
description: |- description: |-
Restart policy for the container to manage the restart behavior of each Restart policy for the container to manage the restart behavior of each
container within a pod. container within a pod.
This may only be set for init containers. You cannot set this field on You cannot set this field on ephemeral containers.
ephemeral containers.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. You cannot set this field on
ephemeral containers.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
Optional: SecurityContext defines the security options the ephemeral container should be run with. Optional: SecurityContext defines the security options the ephemeral container should be run with.
@@ -3980,7 +4157,9 @@ spec:
hostNetwork: hostNetwork:
description: |- description: |-
Host networking requested for this pod. Use the host's network namespace. Host networking requested for this pod. Use the host's network namespace.
If this option is set, the ports that will be used must be specified. When using HostNetwork you should specify ports so the scheduler is aware.
When `hostNetwork` is true, specified `hostPort` fields in port definitions must match `containerPort`,
and unspecified `hostPort` fields in port definitions are defaulted to match `containerPort`.
Default to false. Default to false.
type: boolean type: boolean
hostPID: hostPID:
@@ -4005,6 +4184,19 @@ spec:
Specifies the hostname of the Pod Specifies the hostname of the Pod
If not specified, the pod's hostname will be set to a system-defined value. If not specified, the pod's hostname will be set to a system-defined value.
type: string type: string
hostnameOverride:
description: |-
HostnameOverride specifies an explicit override for the pod's hostname as perceived by the pod.
This field only specifies the pod's hostname and does not affect its DNS records.
When this field is set to a non-empty string:
- It takes precedence over the values set in `hostname` and `subdomain`.
- The Pod's hostname will be set to this value.
- `setHostnameAsFQDN` must be nil or set to false.
- `hostNetwork` must be set to false.
This field must be a valid DNS subdomain as defined in RFC 1123 and contain at most 64 characters.
Requires the HostnameOverride feature gate to be enabled.
type: string
imagePullSecrets: imagePullSecrets:
description: |- description: |-
ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
@@ -4040,7 +4232,7 @@ spec:
Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes.
The resourceRequirements of an init container are taken into account during scheduling The resourceRequirements of an init container are taken into account during scheduling
by finding the highest request/limit for each resource type, and then using the max of by finding the highest request/limit for each resource type, and then using the max of
of that value or the sum of the normal containers. Limits are applied to init containers that value or the sum of the normal containers. Limits are applied to init containers
in a similar fashion. in a similar fashion.
Init containers cannot currently be added or removed. Init containers cannot currently be added or removed.
Cannot be updated. Cannot be updated.
@@ -4084,7 +4276,9 @@ spec:
description: EnvVar represents an environment variable present in a Container. description: EnvVar represents an environment variable present in a Container.
properties: properties:
name: name:
description: Name of the environment variable. Must be a C_IDENTIFIER. description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
value: value:
description: |- description: |-
@@ -4138,6 +4332,42 @@ spec:
- fieldPath - fieldPath
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef: resourceFieldRef:
description: |- description: |-
Selects a resource of the container: only resources limits and requests Selects a resource of the container: only resources limits and requests
@@ -4193,13 +4423,13 @@ spec:
envFrom: envFrom:
description: |- description: |-
List of sources to populate environment variables in the container. List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys The keys defined within a source may consist of any printable ASCII characters except '='.
will be reported as an event when the container is starting. When a key exists in multiple When a key exists in multiple
sources, the value associated with the last source will take precedence. sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence. Values defined by an Env with a duplicate key will take precedence.
Cannot be updated. Cannot be updated.
items: items:
description: EnvFromSource represents the source of a set of ConfigMaps description: EnvFromSource represents the source of a set of ConfigMaps or Secrets
properties: properties:
configMapRef: configMapRef:
description: The ConfigMap to select from description: The ConfigMap to select from
@@ -4219,7 +4449,9 @@ spec:
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
prefix: prefix:
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string type: string
secretRef: secretRef:
description: The Secret to select from description: The Secret to select from
@@ -4468,6 +4700,12 @@ spec:
- port - port
type: object type: object
type: object type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object type: object
livenessProbe: livenessProbe:
description: |- description: |-
@@ -4858,7 +5096,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -4909,10 +5147,10 @@ spec:
restartPolicy: restartPolicy:
description: |- description: |-
RestartPolicy defines the restart behavior of individual containers in a pod. RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always". This overrides the pod-level restart policy. When this field is not specified,
For non-init containers or when this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type. the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect: Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always" containers have completed, all init containers with restartPolicy "Always"
@@ -4924,6 +5162,57 @@ spec:
init container is started, or after any startupProbe has successfully init container is started, or after any startupProbe has successfully
completed. completed.
type: string type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext: securityContext:
description: |- description: |-
SecurityContext defines the security options the container should be run with. SecurityContext defines the security options the container should be run with.
@@ -5437,6 +5726,7 @@ spec:
- spec.hostPID - spec.hostPID
- spec.hostIPC - spec.hostIPC
- spec.hostUsers - spec.hostUsers
- spec.resources
- spec.securityContext.appArmorProfile - spec.securityContext.appArmorProfile
- spec.securityContext.seLinuxOptions - spec.securityContext.seLinuxOptions
- spec.securityContext.seccompProfile - spec.securityContext.seccompProfile
@@ -5588,7 +5878,7 @@ spec:
description: |- description: |-
Resources is the total amount of CPU and Memory resources required by all Resources is the total amount of CPU and Memory resources required by all
containers in the pod. It supports specifying Requests and Limits for containers in the pod. It supports specifying Requests and Limits for
"cpu" and "memory" resource names only. ResourceClaims are not supported. "cpu", "memory" and "hugepages-" resource names only. ResourceClaims are not supported.
This field enables fine-grained control over resource allocation for the This field enables fine-grained control over resource allocation for the
entire pod, allowing resource sharing among containers in a pod. entire pod, allowing resource sharing among containers in a pod.
@@ -5601,7 +5891,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims, Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container. that are used by this container.
This is an alpha field and requires enabling the This field depends on the
DynamicResourceAllocation feature gate. DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers. This field is immutable. It can only be set for containers.
@@ -6126,7 +6416,6 @@ spec:
- Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.
If this value is nil, the behavior is equivalent to the Honor policy. If this value is nil, the behavior is equivalent to the Honor policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string type: string
nodeTaintsPolicy: nodeTaintsPolicy:
description: |- description: |-
@@ -6137,7 +6426,6 @@ spec:
- Ignore: node taints are ignored. All nodes are included. - Ignore: node taints are ignored. All nodes are included.
If this value is nil, the behavior is equivalent to the Ignore policy. If this value is nil, the behavior is equivalent to the Ignore policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string type: string
topologyKey: topologyKey:
description: |- description: |-
@@ -6843,15 +7131,13 @@ spec:
volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim.
If specified, the CSI driver will create or update the volume with the attributes defined If specified, the CSI driver will create or update the volume with the attributes defined
in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName,
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass it can be changed after the claim is created. An empty string or nil value indicates that no
will be applied to the claim but it's not allowed to reset this field to empty string once it is set. VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass this field can be reset to its previous value (including nil) to cancel the modification.
will be set by the persistentvolume controller if it exists.
If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be
set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource
exists. exists.
More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/
(Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default).
type: string type: string
volumeMode: volumeMode:
description: |- description: |-
@@ -7025,12 +7311,9 @@ spec:
description: |- description: |-
glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime.
Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported.
More info: https://examples.k8s.io/volumes/glusterfs/README.md
properties: properties:
endpoints: endpoints:
description: |- description: endpoints is the endpoint name that details Glusterfs topology.
endpoints is the endpoint name that details Glusterfs topology.
More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod
type: string type: string
path: path:
description: |- description: |-
@@ -7084,7 +7367,7 @@ spec:
The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
The volume will be mounted read-only (ro) and non-executable files (noexec). The volume will be mounted read-only (ro) and non-executable files (noexec).
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
properties: properties:
pullPolicy: pullPolicy:
@@ -7109,7 +7392,7 @@ spec:
description: |- description: |-
iscsi represents an ISCSI Disk resource that is attached to a iscsi represents an ISCSI Disk resource that is attached to a
kubelet's host machine and then exposed to the pod. kubelet's host machine and then exposed to the pod.
More info: https://examples.k8s.io/volumes/iscsi/README.md More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi
properties: properties:
chapAuthDiscovery: chapAuthDiscovery:
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
@@ -7499,6 +7782,110 @@ spec:
type: array type: array
x-kubernetes-list-type: atomic x-kubernetes-list-type: atomic
type: object type: object
podCertificate:
description: |-
Projects an auto-rotating credential bundle (private key and certificate
chain) that the pod can use either as a TLS client or server.
Kubelet generates a private key and uses it to send a
PodCertificateRequest to the named signer. Once the signer approves the
request and issues a certificate chain, Kubelet writes the key and
certificate chain to the pod filesystem. The pod does not start until
certificates have been issued for each podCertificate projected volume
source in its spec.
Kubelet will begin trying to rotate the certificate at the time indicated
by the signer using the PodCertificateRequest.Status.BeginRefreshAt
timestamp.
Kubelet can write a single file, indicated by the credentialBundlePath
field, or separate files, indicated by the keyPath and
certificateChainPath fields.
The credential bundle is a single file in PEM format. The first PEM
entry is the private key (in PKCS#8 format), and the remaining PEM
entries are the certificate chain issued by the signer (typically,
signers will return their certificate chain in leaf-to-root order).
Prefer using the credential bundle format, since your application code
can read it atomically. If you use keyPath and certificateChainPath,
your application must make two separate file reads. If these coincide
with a certificate rotation, it is possible that the private key and leaf
certificate you read may not correspond to each other. Your application
will need to check for this condition, and re-read until they are
consistent.
The named signer controls chooses the format of the certificate it
issues; consult the signer implementation's documentation to learn how to
use the certificates it issues.
properties:
certificateChainPath:
description: |-
Write the certificate chain at this path in the projected volume.
Most applications should use credentialBundlePath. When using keyPath
and certificateChainPath, your application needs to check that the key
and leaf certificate are consistent, because it is possible to read the
files mid-rotation.
type: string
credentialBundlePath:
description: |-
Write the credential bundle at this path in the projected volume.
The credential bundle is a single file that contains multiple PEM blocks.
The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private
key.
The remaining blocks are CERTIFICATE blocks, containing the issued
certificate chain from the signer (leaf and any intermediates).
Using credentialBundlePath lets your Pod's application code make a single
atomic read that retrieves a consistent key and certificate chain. If you
project them to separate files, your application code will need to
additionally check that the leaf certificate was issued to the key.
type: string
keyPath:
description: |-
Write the key at this path in the projected volume.
Most applications should use credentialBundlePath. When using keyPath
and certificateChainPath, your application needs to check that the key
and leaf certificate are consistent, because it is possible to read the
files mid-rotation.
type: string
keyType:
description: |-
The type of keypair Kubelet will generate for the pod.
Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384",
"ECDSAP521", and "ED25519".
type: string
maxExpirationSeconds:
description: |-
maxExpirationSeconds is the maximum lifetime permitted for the
certificate.
Kubelet copies this value verbatim into the PodCertificateRequests it
generates for this projection.
If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver
will reject values shorter than 3600 (1 hour). The maximum allowable
value is 7862400 (91 days).
The signer implementation is then free to issue a certificate with any
lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600
seconds (1 hour). This constraint is enforced by kube-apiserver.
`kubernetes.io` signers will never issue certificates with a lifetime
longer than 24 hours.
format: int32
type: integer
signerName:
description: Kubelet's generated CSRs will be addressed to this signer.
type: string
required:
- keyType
- signerName
type: object
secret: secret:
description: secret information about the secret data to project description: secret information about the secret data to project
properties: properties:
@@ -7628,7 +8015,6 @@ spec:
description: |- description: |-
rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. rbd represents a Rados Block Device mount on the host that shares a pod's lifetime.
Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported.
More info: https://examples.k8s.io/volumes/rbd/README.md
properties: properties:
fsType: fsType:
description: |- description: |-
@@ -8170,15 +8556,13 @@ spec:
volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim.
If specified, the CSI driver will create or update the volume with the attributes defined If specified, the CSI driver will create or update the volume with the attributes defined
in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName,
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass it can be changed after the claim is created. An empty string or nil value indicates that no
will be applied to the claim but it's not allowed to reset this field to empty string once it is set. VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass this field can be reset to its previous value (including nil) to cancel the modification.
will be set by the persistentvolume controller if it exists.
If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be
set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource
exists. exists.
More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/
(Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default).
type: string type: string
volumeMode: volumeMode:
description: |- description: |-
@@ -8278,13 +8662,11 @@ spec:
description: |- description: |-
currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using.
When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim
This is a beta field and requires enabling VolumeAttributesClass feature (off by default).
type: string type: string
modifyVolumeStatus: modifyVolumeStatus:
description: |- description: |-
ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. ModifyVolumeStatus represents the status object of ControllerModifyVolume operation.
When this is unset, there is no ModifyVolume operation being attempted. When this is unset, there is no ModifyVolume operation being attempted.
This is a beta field and requires enabling VolumeAttributesClass feature (off by default).
properties: properties:
status: status:
description: "status is the status of the ControllerModifyVolume operation. It can be in any of following states:\n - Pending\n Pending indicates that the PersistentVolumeClaim cannot be modified due to unmet requirements, such as\n the specified VolumeAttributesClass not existing.\n - InProgress\n InProgress indicates that the volume is being modified.\n - Infeasible\n Infeasible indicates that the request has been rejected as invalid by the CSI driver. To\n\t resolve the error, a valid VolumeAttributesClass needs to be specified.\nNote: New statuses can be added in the future. Consumers should check for unknown statuses and fail appropriately." description: "status is the status of the ControllerModifyVolume operation. It can be in any of following states:\n - Pending\n Pending indicates that the PersistentVolumeClaim cannot be modified due to unmet requirements, such as\n the specified VolumeAttributesClass not existing.\n - InProgress\n InProgress indicates that the volume is being modified.\n - Infeasible\n Infeasible indicates that the request has been rejected as invalid by the CSI driver. To\n\t resolve the error, a valid VolumeAttributesClass needs to be specified.\nNote: New statuses can be added in the future. Consumers should check for unknown statuses and fail appropriately."
@@ -8355,7 +8737,6 @@ spec:
type: object type: object
required: required:
- selector - selector
- serviceName
- template - template
type: object type: object
status: status:
@@ -8389,4 +8770,3 @@ spec:
storage: true storage: true
subresources: subresources:
status: {} status: {}
preserveUnknownFields: false

View File

@@ -19,6 +19,7 @@ package actionsgithubcom
import ( import (
"context" "context"
"fmt" "fmt"
"time"
"github.com/go-logr/logr" "github.com/go-logr/logr"
kerrors "k8s.io/apimachinery/pkg/api/errors" kerrors "k8s.io/apimachinery/pkg/api/errors"
@@ -84,14 +85,14 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
} }
log.Info("Deleting resources") log.Info("Deleting resources")
done, err := r.cleanupResources(ctx, autoscalingListener, log) requeue, err := r.cleanupResources(ctx, autoscalingListener, log)
if err != nil { if err != nil {
log.Error(err, "Failed to cleanup resources after deletion") log.Error(err, "Failed to cleanup resources after deletion")
return ctrl.Result{}, err return ctrl.Result{}, err
} }
if !done { if requeue {
log.Info("Waiting for resources to be deleted before removing finalizer") log.Info("Waiting for resources to be deleted before removing finalizer")
return ctrl.Result{Requeue: true}, nil return ctrl.Result{Requeue: true, RequeueAfter: time.Second}, nil
} }
log.Info("Removing finalizer") log.Info("Removing finalizer")
@@ -272,7 +273,7 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
func (r *AutoscalingListenerReconciler) cleanupResources(ctx context.Context, autoscalingListener *v1alpha1.AutoscalingListener, logger logr.Logger) (done bool, err error) { func (r *AutoscalingListenerReconciler) cleanupResources(ctx context.Context, autoscalingListener *v1alpha1.AutoscalingListener, logger logr.Logger) (requeue bool, err error) {
logger.Info("Cleaning up the listener pod") logger.Info("Cleaning up the listener pod")
listenerPod := new(corev1.Pod) listenerPod := new(corev1.Pod)
err = r.Get(ctx, types.NamespacedName{Name: autoscalingListener.Name, Namespace: autoscalingListener.Namespace}, listenerPod) err = r.Get(ctx, types.NamespacedName{Name: autoscalingListener.Name, Namespace: autoscalingListener.Namespace}, listenerPod)
@@ -284,7 +285,7 @@ func (r *AutoscalingListenerReconciler) cleanupResources(ctx context.Context, au
return false, fmt.Errorf("failed to delete listener pod: %w", err) return false, fmt.Errorf("failed to delete listener pod: %w", err)
} }
} }
return false, nil requeue = true
case kerrors.IsNotFound(err): case kerrors.IsNotFound(err):
_ = r.publishRunningListener(autoscalingListener, false) // If error is returned, we never published metrics so it is safe to ignore _ = r.publishRunningListener(autoscalingListener, false) // If error is returned, we never published metrics so it is safe to ignore
default: default:
@@ -302,7 +303,7 @@ func (r *AutoscalingListenerReconciler) cleanupResources(ctx context.Context, au
return false, fmt.Errorf("failed to delete listener config secret: %w", err) return false, fmt.Errorf("failed to delete listener config secret: %w", err)
} }
} }
return false, nil requeue = true
case !kerrors.IsNotFound(err): case !kerrors.IsNotFound(err):
return false, fmt.Errorf("failed to get listener config secret: %w", err) return false, fmt.Errorf("failed to get listener config secret: %w", err)
} }
@@ -319,7 +320,7 @@ func (r *AutoscalingListenerReconciler) cleanupResources(ctx context.Context, au
return false, fmt.Errorf("failed to delete listener proxy secret: %w", err) return false, fmt.Errorf("failed to delete listener proxy secret: %w", err)
} }
} }
return false, nil requeue = true
case !kerrors.IsNotFound(err): case !kerrors.IsNotFound(err):
return false, fmt.Errorf("failed to get listener proxy secret: %w", err) return false, fmt.Errorf("failed to get listener proxy secret: %w", err)
} }
@@ -336,7 +337,7 @@ func (r *AutoscalingListenerReconciler) cleanupResources(ctx context.Context, au
return false, fmt.Errorf("failed to delete listener role binding: %w", err) return false, fmt.Errorf("failed to delete listener role binding: %w", err)
} }
} }
return false, nil requeue = true
case !kerrors.IsNotFound(err): case !kerrors.IsNotFound(err):
return false, fmt.Errorf("failed to get listener role binding: %w", err) return false, fmt.Errorf("failed to get listener role binding: %w", err)
} }
@@ -352,7 +353,7 @@ func (r *AutoscalingListenerReconciler) cleanupResources(ctx context.Context, au
return false, fmt.Errorf("failed to delete listener role: %w", err) return false, fmt.Errorf("failed to delete listener role: %w", err)
} }
} }
return false, nil requeue = true
case !kerrors.IsNotFound(err): case !kerrors.IsNotFound(err):
return false, fmt.Errorf("failed to get listener role: %w", err) return false, fmt.Errorf("failed to get listener role: %w", err)
} }
@@ -369,13 +370,13 @@ func (r *AutoscalingListenerReconciler) cleanupResources(ctx context.Context, au
return false, fmt.Errorf("failed to delete listener service account: %w", err) return false, fmt.Errorf("failed to delete listener service account: %w", err)
} }
} }
return false, nil requeue = true
case !kerrors.IsNotFound(err): case !kerrors.IsNotFound(err):
return false, fmt.Errorf("failed to get listener service account: %w", err) return false, fmt.Errorf("failed to get listener service account: %w", err)
} }
logger.Info("Listener service account is deleted") logger.Info("Listener service account is deleted")
return true, nil return requeue, nil
} }
func (r *AutoscalingListenerReconciler) createServiceAccountForListener(ctx context.Context, autoscalingListener *v1alpha1.AutoscalingListener, logger logr.Logger) (ctrl.Result, error) { func (r *AutoscalingListenerReconciler) createServiceAccountForListener(ctx context.Context, autoscalingListener *v1alpha1.AutoscalingListener, logger logr.Logger) (ctrl.Result, error) {

View File

@@ -26,9 +26,8 @@ import (
) )
const ( const (
autoscalingListenerTestTimeout = time.Second * 20 autoscalingListenerTestTimeout = time.Second * 20
autoscalingListenerTestInterval = time.Millisecond * 250 autoscalingListenerTestInterval = time.Millisecond * 250
autoscalingListenerTestGitHubToken = "gh_token"
) )
var _ = Describe("Test AutoScalingListener controller", func() { var _ = Describe("Test AutoScalingListener controller", func() {

View File

@@ -48,7 +48,7 @@ const (
annotationKeyValuesHash = "actions.github.com/values-hash" annotationKeyValuesHash = "actions.github.com/values-hash"
autoscalingRunnerSetFinalizerName = "autoscalingrunnerset.actions.github.com/finalizer" autoscalingRunnerSetFinalizerName = "autoscalingrunnerset.actions.github.com/finalizer"
runnerScaleSetIdAnnotationKey = "runner-scale-set-id" runnerScaleSetIDAnnotationKey = "runner-scale-set-id"
) )
type UpdateStrategy string type UpdateStrategy string
@@ -180,14 +180,14 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
scaleSetIdRaw, ok := autoscalingRunnerSet.Annotations[runnerScaleSetIdAnnotationKey] scaleSetIDRaw, ok := autoscalingRunnerSet.Annotations[runnerScaleSetIDAnnotationKey]
if !ok { if !ok {
// Need to create a new runner scale set on Actions service // Need to create a new runner scale set on Actions service
log.Info("Runner scale set id annotation does not exist. Creating a new runner scale set.") log.Info("Runner scale set id annotation does not exist. Creating a new runner scale set.")
return r.createRunnerScaleSet(ctx, autoscalingRunnerSet, log) return r.createRunnerScaleSet(ctx, autoscalingRunnerSet, log)
} }
if id, err := strconv.Atoi(scaleSetIdRaw); err != nil || id <= 0 { if id, err := strconv.Atoi(scaleSetIDRaw); err != nil || id <= 0 {
log.Info("Runner scale set id annotation is not an id, or is <= 0. Creating a new runner scale set.") log.Info("Runner scale set id annotation is not an id, or is <= 0. Creating a new runner scale set.")
// something modified the scaleSetId. Try to create one // something modified the scaleSetId. Try to create one
return r.createRunnerScaleSet(ctx, autoscalingRunnerSet, log) return r.createRunnerScaleSet(ctx, autoscalingRunnerSet, log)
@@ -403,7 +403,7 @@ func (r *AutoscalingRunnerSetReconciler) createRunnerScaleSet(ctx context.Contex
return ctrl.Result{}, err return ctrl.Result{}, err
} }
runnerGroupId := 1 runnerGroupID := 1
if len(autoscalingRunnerSet.Spec.RunnerGroup) > 0 { if len(autoscalingRunnerSet.Spec.RunnerGroup) > 0 {
runnerGroup, err := actionsClient.GetRunnerGroupByName(ctx, autoscalingRunnerSet.Spec.RunnerGroup) runnerGroup, err := actionsClient.GetRunnerGroupByName(ctx, autoscalingRunnerSet.Spec.RunnerGroup)
if err != nil { if err != nil {
@@ -411,14 +411,14 @@ func (r *AutoscalingRunnerSetReconciler) createRunnerScaleSet(ctx context.Contex
return ctrl.Result{}, err return ctrl.Result{}, err
} }
runnerGroupId = int(runnerGroup.ID) runnerGroupID = int(runnerGroup.ID)
} }
runnerScaleSet, err := actionsClient.GetRunnerScaleSet(ctx, runnerGroupId, autoscalingRunnerSet.Spec.RunnerScaleSetName) runnerScaleSet, err := actionsClient.GetRunnerScaleSet(ctx, runnerGroupID, autoscalingRunnerSet.Spec.RunnerScaleSetName)
if err != nil { if err != nil {
logger.Error(err, "Failed to get runner scale set from Actions service", logger.Error(err, "Failed to get runner scale set from Actions service",
"runnerGroupId", "runnerGroupId",
strconv.Itoa(runnerGroupId), strconv.Itoa(runnerGroupID),
"runnerScaleSetName", "runnerScaleSetName",
autoscalingRunnerSet.Spec.RunnerScaleSetName) autoscalingRunnerSet.Spec.RunnerScaleSetName)
return ctrl.Result{}, err return ctrl.Result{}, err
@@ -429,7 +429,7 @@ func (r *AutoscalingRunnerSetReconciler) createRunnerScaleSet(ctx context.Contex
ctx, ctx,
&actions.RunnerScaleSet{ &actions.RunnerScaleSet{
Name: autoscalingRunnerSet.Spec.RunnerScaleSetName, Name: autoscalingRunnerSet.Spec.RunnerScaleSetName,
RunnerGroupId: runnerGroupId, RunnerGroupId: runnerGroupID,
Labels: []actions.Label{ Labels: []actions.Label{
{ {
Name: autoscalingRunnerSet.Spec.RunnerScaleSetName, Name: autoscalingRunnerSet.Spec.RunnerScaleSetName,
@@ -466,7 +466,7 @@ func (r *AutoscalingRunnerSetReconciler) createRunnerScaleSet(ctx context.Contex
logger.Info("Adding runner scale set ID, name and runner group name as an annotation and url labels") logger.Info("Adding runner scale set ID, name and runner group name as an annotation and url labels")
if err = patch(ctx, r.Client, autoscalingRunnerSet, func(obj *v1alpha1.AutoscalingRunnerSet) { if err = patch(ctx, r.Client, autoscalingRunnerSet, func(obj *v1alpha1.AutoscalingRunnerSet) {
obj.Annotations[AnnotationKeyGitHubRunnerScaleSetName] = runnerScaleSet.Name obj.Annotations[AnnotationKeyGitHubRunnerScaleSetName] = runnerScaleSet.Name
obj.Annotations[runnerScaleSetIdAnnotationKey] = strconv.Itoa(runnerScaleSet.Id) obj.Annotations[runnerScaleSetIDAnnotationKey] = strconv.Itoa(runnerScaleSet.Id)
obj.Annotations[AnnotationKeyGitHubRunnerGroupName] = runnerScaleSet.RunnerGroupName obj.Annotations[AnnotationKeyGitHubRunnerGroupName] = runnerScaleSet.RunnerGroupName
if err := applyGitHubURLLabels(obj.Spec.GitHubConfigUrl, obj.Labels); err != nil { // should never happen if err := applyGitHubURLLabels(obj.Spec.GitHubConfigUrl, obj.Labels); err != nil { // should never happen
logger.Error(err, "Failed to apply GitHub URL labels") logger.Error(err, "Failed to apply GitHub URL labels")
@@ -484,7 +484,7 @@ func (r *AutoscalingRunnerSetReconciler) createRunnerScaleSet(ctx context.Contex
} }
func (r *AutoscalingRunnerSetReconciler) updateRunnerScaleSetRunnerGroup(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, logger logr.Logger) (ctrl.Result, error) { func (r *AutoscalingRunnerSetReconciler) updateRunnerScaleSetRunnerGroup(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, logger logr.Logger) (ctrl.Result, error) {
runnerScaleSetId, err := strconv.Atoi(autoscalingRunnerSet.Annotations[runnerScaleSetIdAnnotationKey]) runnerScaleSetID, err := strconv.Atoi(autoscalingRunnerSet.Annotations[runnerScaleSetIDAnnotationKey])
if err != nil { if err != nil {
logger.Error(err, "Failed to parse runner scale set ID") logger.Error(err, "Failed to parse runner scale set ID")
return ctrl.Result{}, err return ctrl.Result{}, err
@@ -496,7 +496,7 @@ func (r *AutoscalingRunnerSetReconciler) updateRunnerScaleSetRunnerGroup(ctx con
return ctrl.Result{}, err return ctrl.Result{}, err
} }
runnerGroupId := 1 runnerGroupID := 1
if len(autoscalingRunnerSet.Spec.RunnerGroup) > 0 { if len(autoscalingRunnerSet.Spec.RunnerGroup) > 0 {
runnerGroup, err := actionsClient.GetRunnerGroupByName(ctx, autoscalingRunnerSet.Spec.RunnerGroup) runnerGroup, err := actionsClient.GetRunnerGroupByName(ctx, autoscalingRunnerSet.Spec.RunnerGroup)
if err != nil { if err != nil {
@@ -504,12 +504,12 @@ func (r *AutoscalingRunnerSetReconciler) updateRunnerScaleSetRunnerGroup(ctx con
return ctrl.Result{}, err return ctrl.Result{}, err
} }
runnerGroupId = int(runnerGroup.ID) runnerGroupID = int(runnerGroup.ID)
} }
updatedRunnerScaleSet, err := actionsClient.UpdateRunnerScaleSet(ctx, runnerScaleSetId, &actions.RunnerScaleSet{RunnerGroupId: runnerGroupId}) updatedRunnerScaleSet, err := actionsClient.UpdateRunnerScaleSet(ctx, runnerScaleSetID, &actions.RunnerScaleSet{RunnerGroupId: runnerGroupID})
if err != nil { if err != nil {
logger.Error(err, "Failed to update runner scale set", "runnerScaleSetId", runnerScaleSetId) logger.Error(err, "Failed to update runner scale set", "runnerScaleSetId", runnerScaleSetID)
return ctrl.Result{}, err return ctrl.Result{}, err
} }
@@ -527,7 +527,7 @@ func (r *AutoscalingRunnerSetReconciler) updateRunnerScaleSetRunnerGroup(ctx con
} }
func (r *AutoscalingRunnerSetReconciler) updateRunnerScaleSetName(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, logger logr.Logger) (ctrl.Result, error) { func (r *AutoscalingRunnerSetReconciler) updateRunnerScaleSetName(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, logger logr.Logger) (ctrl.Result, error) {
runnerScaleSetId, err := strconv.Atoi(autoscalingRunnerSet.Annotations[runnerScaleSetIdAnnotationKey]) runnerScaleSetID, err := strconv.Atoi(autoscalingRunnerSet.Annotations[runnerScaleSetIDAnnotationKey])
if err != nil { if err != nil {
logger.Error(err, "Failed to parse runner scale set ID") logger.Error(err, "Failed to parse runner scale set ID")
return ctrl.Result{}, err return ctrl.Result{}, err
@@ -544,9 +544,9 @@ func (r *AutoscalingRunnerSetReconciler) updateRunnerScaleSetName(ctx context.Co
return ctrl.Result{}, err return ctrl.Result{}, err
} }
updatedRunnerScaleSet, err := actionsClient.UpdateRunnerScaleSet(ctx, runnerScaleSetId, &actions.RunnerScaleSet{Name: autoscalingRunnerSet.Spec.RunnerScaleSetName}) updatedRunnerScaleSet, err := actionsClient.UpdateRunnerScaleSet(ctx, runnerScaleSetID, &actions.RunnerScaleSet{Name: autoscalingRunnerSet.Spec.RunnerScaleSetName})
if err != nil { if err != nil {
logger.Error(err, "Failed to update runner scale set", "runnerScaleSetId", runnerScaleSetId) logger.Error(err, "Failed to update runner scale set", "runnerScaleSetId", runnerScaleSetID)
return ctrl.Result{}, err return ctrl.Result{}, err
} }
@@ -563,7 +563,7 @@ func (r *AutoscalingRunnerSetReconciler) updateRunnerScaleSetName(ctx context.Co
} }
func (r *AutoscalingRunnerSetReconciler) deleteRunnerScaleSet(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, logger logr.Logger) error { func (r *AutoscalingRunnerSetReconciler) deleteRunnerScaleSet(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, logger logr.Logger) error {
scaleSetId, ok := autoscalingRunnerSet.Annotations[runnerScaleSetIdAnnotationKey] scaleSetID, ok := autoscalingRunnerSet.Annotations[runnerScaleSetIDAnnotationKey]
if !ok { if !ok {
// Annotation not being present can occur in 3 scenarios // Annotation not being present can occur in 3 scenarios
// 1. Scale set is never created. // 1. Scale set is never created.
@@ -580,7 +580,7 @@ func (r *AutoscalingRunnerSetReconciler) deleteRunnerScaleSet(ctx context.Contex
return nil return nil
} }
logger.Info("Deleting the runner scale set from Actions service") logger.Info("Deleting the runner scale set from Actions service")
runnerScaleSetId, err := strconv.Atoi(scaleSetId) runnerScaleSetID, err := strconv.Atoi(scaleSetID)
if err != nil { if err != nil {
// If the annotation is not set correctly, we are going to get stuck in a loop trying to parse the scale set id. // If the annotation is not set correctly, we are going to get stuck in a loop trying to parse the scale set id.
// If the configuration is invalid (secret does not exist for example), we never got to the point to create runner set. // If the configuration is invalid (secret does not exist for example), we never got to the point to create runner set.
@@ -595,17 +595,17 @@ func (r *AutoscalingRunnerSetReconciler) deleteRunnerScaleSet(ctx context.Contex
return err return err
} }
err = actionsClient.DeleteRunnerScaleSet(ctx, runnerScaleSetId) err = actionsClient.DeleteRunnerScaleSet(ctx, runnerScaleSetID)
if err != nil { if err != nil {
logger.Error(err, "Failed to delete runner scale set", "runnerScaleSetId", runnerScaleSetId) logger.Error(err, "Failed to delete runner scale set", "runnerScaleSetId", runnerScaleSetID)
return err return err
} }
err = patch(ctx, r.Client, autoscalingRunnerSet, func(obj *v1alpha1.AutoscalingRunnerSet) { err = patch(ctx, r.Client, autoscalingRunnerSet, func(obj *v1alpha1.AutoscalingRunnerSet) {
delete(obj.Annotations, runnerScaleSetIdAnnotationKey) delete(obj.Annotations, runnerScaleSetIDAnnotationKey)
}) })
if err != nil { if err != nil {
logger.Error(err, "Failed to patch autoscaling runner set with annotation removed", "annotation", runnerScaleSetIdAnnotationKey) logger.Error(err, "Failed to patch autoscaling runner set with annotation removed", "annotation", runnerScaleSetIDAnnotationKey)
return err return err
} }
@@ -1006,6 +1006,7 @@ func (c *autoscalingRunnerSetFinalizerDependencyCleaner) removeManagerRoleFinali
// NOTE: if this is logic should be used for other resources, // NOTE: if this is logic should be used for other resources,
// consider using generics // consider using generics
type EphemeralRunnerSets struct { type EphemeralRunnerSets struct {
list *v1alpha1.EphemeralRunnerSetList list *v1alpha1.EphemeralRunnerSetList
sorted bool sorted bool

View File

@@ -34,9 +34,8 @@ import (
) )
const ( const (
autoscalingRunnerSetTestTimeout = time.Second * 20 autoscalingRunnerSetTestTimeout = time.Second * 20
autoscalingRunnerSetTestInterval = time.Millisecond * 250 autoscalingRunnerSetTestInterval = time.Millisecond * 250
autoscalingRunnerSetTestGitHubToken = "gh_token"
) )
var _ = Describe("Test AutoScalingRunnerSet controller", Ordered, func() { var _ = Describe("Test AutoScalingRunnerSet controller", Ordered, func() {
@@ -141,7 +140,7 @@ var _ = Describe("Test AutoScalingRunnerSet controller", Ordered, func() {
return "", err return "", err
} }
if _, ok := created.Annotations[runnerScaleSetIdAnnotationKey]; !ok { if _, ok := created.Annotations[runnerScaleSetIDAnnotationKey]; !ok {
return "", nil return "", nil
} }
@@ -149,7 +148,7 @@ var _ = Describe("Test AutoScalingRunnerSet controller", Ordered, func() {
return "", nil return "", nil
} }
return fmt.Sprintf("%s_%s", created.Annotations[runnerScaleSetIdAnnotationKey], created.Annotations[AnnotationKeyGitHubRunnerGroupName]), nil return fmt.Sprintf("%s_%s", created.Annotations[runnerScaleSetIDAnnotationKey], created.Annotations[AnnotationKeyGitHubRunnerGroupName]), nil
}, },
autoscalingRunnerSetTestTimeout, autoscalingRunnerSetTestTimeout,
autoscalingRunnerSetTestInterval).Should(BeEquivalentTo("1_testgroup"), "RunnerScaleSet should be created/fetched and update the AutoScalingRunnerSet's annotation") autoscalingRunnerSetTestInterval).Should(BeEquivalentTo("1_testgroup"), "RunnerScaleSet should be created/fetched and update the AutoScalingRunnerSet's annotation")

View File

@@ -36,7 +36,8 @@ const (
LabelKeyGitHubRepository = "actions.github.com/repository" LabelKeyGitHubRepository = "actions.github.com/repository"
) )
// Finalizer used to protect resources from deletion while AutoscalingRunnerSet is running // AutoscalingRunnerSetCleanupFinalizerName is a finalizer used to protect resources
// from deletion while AutoscalingRunnerSet is running
const AutoscalingRunnerSetCleanupFinalizerName = "actions.github.com/cleanup-protection" const AutoscalingRunnerSetCleanupFinalizerName = "actions.github.com/cleanup-protection"
const ( const (

View File

@@ -21,6 +21,8 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"strconv"
"strings"
"time" "time"
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1" "github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
@@ -152,38 +154,77 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
if !controllerutil.ContainsFinalizer(ephemeralRunner, ephemeralRunnerFinalizerName) { addFinalizers := !controllerutil.ContainsFinalizer(ephemeralRunner, ephemeralRunnerFinalizerName) || !controllerutil.ContainsFinalizer(ephemeralRunner, ephemeralRunnerActionsFinalizerName)
log.Info("Adding finalizer") if addFinalizers {
log.Info("Adding finalizers")
if err := patch(ctx, r.Client, ephemeralRunner, func(obj *v1alpha1.EphemeralRunner) { if err := patch(ctx, r.Client, ephemeralRunner, func(obj *v1alpha1.EphemeralRunner) {
controllerutil.AddFinalizer(obj, ephemeralRunnerFinalizerName) controllerutil.AddFinalizer(obj, ephemeralRunnerFinalizerName)
controllerutil.AddFinalizer(obj, ephemeralRunnerActionsFinalizerName)
}); err != nil { }); err != nil {
log.Error(err, "Failed to update with finalizer set") log.Error(err, "Failed to update with finalizer set")
return ctrl.Result{}, err return ctrl.Result{}, err
} }
log.Info("Successfully added finalizers")
log.Info("Successfully added finalizer")
return ctrl.Result{}, nil
} }
if !controllerutil.ContainsFinalizer(ephemeralRunner, ephemeralRunnerActionsFinalizerName) { secret := new(corev1.Secret)
log.Info("Adding runner registration finalizer") if err := r.Get(ctx, req.NamespacedName, secret); err != nil {
err := patch(ctx, r.Client, ephemeralRunner, func(obj *v1alpha1.EphemeralRunner) { if !kerrors.IsNotFound(err) {
controllerutil.AddFinalizer(obj, ephemeralRunnerActionsFinalizerName) log.Error(err, "Failed to fetch secret")
})
if err != nil {
log.Error(err, "Failed to update with runner registration finalizer set")
return ctrl.Result{}, err return ctrl.Result{}, err
} }
log.Info("Successfully added runner registration finalizer") jitConfig, err := r.createRunnerJitConfig(ctx, ephemeralRunner, log)
return ctrl.Result{}, nil switch {
case err == nil:
// create secret if not created
log.Info("Creating new ephemeral runner secret for jitconfig.")
jitSecret, err := r.createSecret(ctx, ephemeralRunner, jitConfig, log)
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed to create secret: %w", err)
}
log.Info("Created new ephemeral runner secret for jitconfig.")
secret = jitSecret
case errors.Is(err, retryableError):
log.Info("Encountered retryable error, requeueing", "error", err.Error())
return ctrl.Result{Requeue: true}, nil
case errors.Is(err, fatalError):
log.Info("JIT config cannot be created for this ephemeral runner, issuing delete", "error", err.Error())
if err := r.Delete(ctx, ephemeralRunner); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to delete the ephemeral runner: %w", err)
}
log.Info("Request to delete ephemeral runner has been issued")
return ctrl.Result{}, nil
default:
log.Error(err, "Failed to create ephemeral runners secret", "error", err.Error())
return ctrl.Result{}, err
}
} }
if ephemeralRunner.Status.RunnerId == 0 { if ephemeralRunner.Status.RunnerId == 0 {
log.Info("Creating new ephemeral runner registration and updating status with runner config") log.Info("Updating ephemeral runner status with runnerId and runnerName")
if r, err := r.updateStatusWithRunnerConfig(ctx, ephemeralRunner, log); r != nil { runnerID, err := strconv.Atoi(string(secret.Data["runnerId"]))
return *r, err if err != nil {
log.Error(err, "Runner config secret is corrupted: missing runnerId")
log.Info("Deleting corrupted runner config secret")
if err := r.Delete(ctx, secret); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to delete the corrupted runner config secret")
}
log.Info("Corrupted runner config secret has been deleted")
return ctrl.Result{Requeue: true}, nil
} }
runnerName := string(secret.Data["runnerName"])
if err := patchSubResource(ctx, r.Status(), ephemeralRunner, func(obj *v1alpha1.EphemeralRunner) {
obj.Status.RunnerId = runnerID
obj.Status.RunnerName = runnerName
}); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to update runner status for RunnerId/RunnerName/RunnerJITConfig: %w", err)
}
ephemeralRunner.Status.RunnerId = runnerID
ephemeralRunner.Status.RunnerName = runnerName
log.Info("Updated ephemeral runner status with runnerId and runnerName")
} }
if len(ephemeralRunner.Status.Failures) > maxFailures { if len(ephemeralRunner.Status.Failures) > maxFailures {
@@ -213,41 +254,49 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
}, nil }, nil
} }
secret := new(corev1.Secret)
if err := r.Get(ctx, req.NamespacedName, secret); err != nil {
if !kerrors.IsNotFound(err) {
log.Error(err, "Failed to fetch secret")
return ctrl.Result{}, err
}
// create secret if not created
log.Info("Creating new ephemeral runner secret for jitconfig.")
if r, err := r.createSecret(ctx, ephemeralRunner, log); r != nil {
return *r, err
}
// Retry to get the secret that was just created.
// Otherwise, even though we want to continue to create the pod,
// it fails due to the missing secret resulting in an invalid pod spec.
if err := r.Get(ctx, req.NamespacedName, secret); err != nil {
log.Error(err, "Failed to fetch secret")
return ctrl.Result{}, err
}
}
pod := new(corev1.Pod) pod := new(corev1.Pod)
if err := r.Get(ctx, req.NamespacedName, pod); err != nil { if err := r.Get(ctx, req.NamespacedName, pod); err != nil {
if !kerrors.IsNotFound(err) { if !kerrors.IsNotFound(err) {
log.Error(err, "Failed to fetch the pod") log.Error(err, "Failed to fetch the pod")
return ctrl.Result{}, err return ctrl.Result{}, err
} }
log.Info("Ephemeral runner pod does not exist. Creating new ephemeral runner")
// Pod was not found. Create if the pod has never been created
log.Info("Creating new EphemeralRunner pod.")
result, err := r.createPod(ctx, ephemeralRunner, secret, log) result, err := r.createPod(ctx, ephemeralRunner, secret, log)
switch { switch {
case err == nil: case err == nil:
return result, nil return result, nil
case kerrors.IsInvalid(err) || kerrors.IsForbidden(err): case kerrors.IsAlreadyExists(err):
log.Info("Runner pod already exists. Waiting for the pod event to be received")
return ctrl.Result{Requeue: true, RequeueAfter: 5 * time.Second}, nil
case kerrors.IsInvalid(err):
log.Error(err, "Failed to create a pod due to unrecoverable failure")
errMessage := fmt.Sprintf("Failed to create the pod: %v", err)
if err := r.markAsFailed(ctx, ephemeralRunner, errMessage, ReasonInvalidPodFailure, log); err != nil {
log.Error(err, "Failed to set ephemeral runner to phase Failed")
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
case kerrors.IsForbidden(err):
if status, ok := err.(kerrors.APIStatus); ok || errors.As(err, &status) {
isResourceQuotaExceeded := strings.Contains(status.Status().Message, "exceeded quota:")
isAboutToExpire := ephemeralRunner.CreationTimestamp.Time.Add(10 * time.Minute).Before(time.Now())
switch {
case isResourceQuotaExceeded && isAboutToExpire:
log.Error(err, "Failed to create a pod due to resource quota exceeded and the ephemeral runner is about to expire; re-creating the ephemeral runner")
if err := r.Delete(ctx, ephemeralRunner); err != nil {
log.Error(err, "Failed to delete the ephemeral runner")
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
case isResourceQuotaExceeded:
log.Error(err, "Resource quota is exceeded; requeue in 30s to retry pod creation")
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
default:
// other forbidden errors
// fallthrough to the default handling below
}
}
log.Error(err, "Failed to create a pod due to unrecoverable failure") log.Error(err, "Failed to create a pod due to unrecoverable failure")
errMessage := fmt.Sprintf("Failed to create the pod: %v", err) errMessage := fmt.Sprintf("Failed to create the pod: %v", err)
if err := r.markAsFailed(ctx, ephemeralRunner, errMessage, ReasonInvalidPodFailure, log); err != nil { if err := r.markAsFailed(ctx, ephemeralRunner, errMessage, ReasonInvalidPodFailure, log); err != nil {
@@ -291,6 +340,31 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
case cs.State.Terminated.ExitCode != 0: // failed case cs.State.Terminated.ExitCode != 0: // failed
log.Info("Ephemeral runner container failed", "exitCode", cs.State.Terminated.ExitCode) log.Info("Ephemeral runner container failed", "exitCode", cs.State.Terminated.ExitCode)
if ephemeralRunner.HasJob() {
log.Error(
errors.New("ephemeral runner has a job assigned, but the pod has failed"),
"Ephemeral runner either has faulty entrypoint or something external killing the runner",
)
log.Info("Deleting the ephemeral runner that has a job assigned but the pod has failed")
if err := r.Delete(ctx, ephemeralRunner); err != nil {
log.Error(err, "Failed to delete the ephemeral runner that has a job assigned but the pod has failed")
return ctrl.Result{}, err
}
log.Info("Deleted the ephemeral runner that has a job assigned but the pod has failed")
log.Info("Trying to remove the runner from the service")
actionsClient, err := r.GetActionsService(ctx, ephemeralRunner)
if err != nil {
log.Error(err, "Failed to get actions client for removing the runner from the service")
return ctrl.Result{}, nil
}
if err := actionsClient.RemoveRunner(ctx, int64(ephemeralRunner.Status.RunnerId)); err != nil {
log.Error(err, "Failed to remove the runner from the service")
return ctrl.Result{}, nil
}
log.Info("Removed the runner from the service")
return ctrl.Result{}, nil
}
if err := r.deletePodAsFailed(ctx, ephemeralRunner, pod, log); err != nil { if err := r.deletePodAsFailed(ctx, ephemeralRunner, pod, log); err != nil {
log.Error(err, "Failed to delete runner pod on failure") log.Error(err, "Failed to delete runner pod on failure")
return ctrl.Result{}, err return ctrl.Result{}, err
@@ -298,9 +372,9 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
return ctrl.Result{}, nil return ctrl.Result{}, nil
default: // succeeded default: // succeeded
log.Info("Ephemeral runner has finished successfully") log.Info("Ephemeral runner has finished successfully, deleting ephemeral runner", "exitCode", cs.State.Terminated.ExitCode)
if err := r.markAsFinished(ctx, ephemeralRunner, log); err != nil { if err := r.Delete(ctx, ephemeralRunner); err != nil {
log.Error(err, "Failed to mark ephemeral runner as finished") log.Error(err, "Failed to delete ephemeral runner after successful completion")
return ctrl.Result{}, err return ctrl.Result{}, err
} }
return ctrl.Result{}, nil return ctrl.Result{}, nil
@@ -470,18 +544,6 @@ func (r *EphemeralRunnerReconciler) markAsFailed(ctx context.Context, ephemeralR
return nil return nil
} }
func (r *EphemeralRunnerReconciler) markAsFinished(ctx context.Context, ephemeralRunner *v1alpha1.EphemeralRunner, log logr.Logger) error {
log.Info("Updating ephemeral runner status to Finished")
if err := patchSubResource(ctx, r.Status(), ephemeralRunner, func(obj *v1alpha1.EphemeralRunner) {
obj.Status.Phase = corev1.PodSucceeded
}); err != nil {
return fmt.Errorf("failed to update ephemeral runner with status finished: %w", err)
}
log.Info("EphemeralRunner status is marked as Finished")
return nil
}
// deletePodAsFailed is responsible for deleting the pod and updating the .Status.Failures for tracking failure count. // deletePodAsFailed is responsible for deleting the pod and updating the .Status.Failures for tracking failure count.
// It should not be responsible for setting the status to Failed. // It should not be responsible for setting the status to Failed.
func (r *EphemeralRunnerReconciler) deletePodAsFailed(ctx context.Context, ephemeralRunner *v1alpha1.EphemeralRunner, pod *corev1.Pod, log logr.Logger) error { func (r *EphemeralRunnerReconciler) deletePodAsFailed(ctx context.Context, ephemeralRunner *v1alpha1.EphemeralRunner, pod *corev1.Pod, log logr.Logger) error {
@@ -509,14 +571,12 @@ func (r *EphemeralRunnerReconciler) deletePodAsFailed(ctx context.Context, ephem
return nil return nil
} }
// updateStatusWithRunnerConfig fetches runtime configuration needed by the runner func (r *EphemeralRunnerReconciler) createRunnerJitConfig(ctx context.Context, ephemeralRunner *v1alpha1.EphemeralRunner, log logr.Logger) (*actions.RunnerScaleSetJitRunnerConfig, error) {
// This method should always set .status.runnerId and .status.runnerJITConfig
func (r *EphemeralRunnerReconciler) updateStatusWithRunnerConfig(ctx context.Context, ephemeralRunner *v1alpha1.EphemeralRunner, log logr.Logger) (*ctrl.Result, error) {
// Runner is not registered with the service. We need to register it first // Runner is not registered with the service. We need to register it first
log.Info("Creating ephemeral runner JIT config") log.Info("Creating ephemeral runner JIT config")
actionsClient, err := r.GetActionsService(ctx, ephemeralRunner) actionsClient, err := r.GetActionsService(ctx, ephemeralRunner)
if err != nil { if err != nil {
return &ctrl.Result{}, fmt.Errorf("failed to get actions client for generating JIT config: %w", err) return nil, fmt.Errorf("failed to get actions client for generating JIT config: %w", err)
} }
jitSettings := &actions.RunnerScaleSetJitRunnerSetting{ jitSettings := &actions.RunnerScaleSetJitRunnerSetting{
@@ -531,74 +591,52 @@ func (r *EphemeralRunnerReconciler) updateStatusWithRunnerConfig(ctx context.Con
} }
jitConfig, err := actionsClient.GenerateJitRunnerConfig(ctx, jitSettings, ephemeralRunner.Spec.RunnerScaleSetId) jitConfig, err := actionsClient.GenerateJitRunnerConfig(ctx, jitSettings, ephemeralRunner.Spec.RunnerScaleSetId)
if err == nil { // if NO error
log.Info("Created ephemeral runner JIT config", "runnerId", jitConfig.Runner.Id)
return jitConfig, nil
}
actionsError := &actions.ActionsError{}
if !errors.As(err, &actionsError) {
return nil, fmt.Errorf("failed to generate JIT config with generic error: %w", err)
}
if actionsError.StatusCode != http.StatusConflict ||
!actionsError.IsException("AgentExistsException") {
return nil, fmt.Errorf("failed to generate JIT config with Actions service error: %w", err)
}
// If the runner with the name we want already exists it means:
// - We might have a name collision.
// - Our previous reconciliation loop failed to update the
// status with the runnerId and runnerJITConfig after the `GenerateJitRunnerConfig`
// created the runner registration on the service.
// We will try to get the runner and see if it's belong to this AutoScalingRunnerSet,
// if so, we can simply delete the runner registration and create a new one.
log.Info("Getting runner jit config failed with conflict error, trying to get the runner by name", "runnerName", ephemeralRunner.Name)
existingRunner, err := actionsClient.GetRunnerByName(ctx, ephemeralRunner.Name)
if err != nil { if err != nil {
actionsError := &actions.ActionsError{} return nil, fmt.Errorf("failed to get runner by name: %w", err)
if !errors.As(err, &actionsError) { }
return &ctrl.Result{}, fmt.Errorf("failed to generate JIT config with generic error: %w", err)
}
if actionsError.StatusCode != http.StatusConflict || if existingRunner == nil {
!actionsError.IsException("AgentExistsException") { log.Info("Runner with the same name does not exist anymore, re-queuing the reconciliation")
return &ctrl.Result{}, fmt.Errorf("failed to generate JIT config with Actions service error: %w", err) return nil, fmt.Errorf("%w: runner existed, retry configuration", retryableError)
} }
// If the runner with the name we want already exists it means: log.Info("Found the runner with the same name", "runnerId", existingRunner.Id, "runnerScaleSetId", existingRunner.RunnerScaleSetId)
// - We might have a name collision. if existingRunner.RunnerScaleSetId == ephemeralRunner.Spec.RunnerScaleSetId {
// - Our previous reconciliation loop failed to update the log.Info("Removing the runner with the same name")
// status with the runnerId and runnerJITConfig after the `GenerateJitRunnerConfig` err := actionsClient.RemoveRunner(ctx, int64(existingRunner.Id))
// created the runner registration on the service.
// We will try to get the runner and see if it's belong to this AutoScalingRunnerSet,
// if so, we can simply delete the runner registration and create a new one.
log.Info("Getting runner jit config failed with conflict error, trying to get the runner by name", "runnerName", ephemeralRunner.Name)
existingRunner, err := actionsClient.GetRunnerByName(ctx, ephemeralRunner.Name)
if err != nil { if err != nil {
return &ctrl.Result{}, fmt.Errorf("failed to get runner by name: %w", err) return nil, fmt.Errorf("failed to remove runner from the service: %w", err)
} }
if existingRunner == nil { log.Info("Removed the runner with the same name, re-queuing the reconciliation")
log.Info("Runner with the same name does not exist, re-queuing the reconciliation") return nil, fmt.Errorf("%w: runner existed belonging to the scale set, retry configuration", retryableError)
return &ctrl.Result{Requeue: true}, nil
}
log.Info("Found the runner with the same name", "runnerId", existingRunner.Id, "runnerScaleSetId", existingRunner.RunnerScaleSetId)
if existingRunner.RunnerScaleSetId == ephemeralRunner.Spec.RunnerScaleSetId {
log.Info("Removing the runner with the same name")
err := actionsClient.RemoveRunner(ctx, int64(existingRunner.Id))
if err != nil {
return &ctrl.Result{}, fmt.Errorf("failed to remove runner from the service: %w", err)
}
log.Info("Removed the runner with the same name, re-queuing the reconciliation")
return &ctrl.Result{Requeue: true}, nil
}
// TODO: Do we want to mark the ephemeral runner as failed, and let EphemeralRunnerSet to clean it up, so we can recover from this situation?
// The situation is that the EphemeralRunner's name is already used by something else to register a runner, and we can't take the control back.
return &ctrl.Result{}, fmt.Errorf("runner with the same name but doesn't belong to this RunnerScaleSet: %w", err)
}
log.Info("Created ephemeral runner JIT config", "runnerId", jitConfig.Runner.Id)
log.Info("Updating ephemeral runner status with runnerId and runnerJITConfig")
err = patchSubResource(ctx, r.Status(), ephemeralRunner, func(obj *v1alpha1.EphemeralRunner) {
obj.Status.RunnerId = jitConfig.Runner.Id
obj.Status.RunnerName = jitConfig.Runner.Name
obj.Status.RunnerJITConfig = jitConfig.EncodedJITConfig
})
if err != nil {
return &ctrl.Result{}, fmt.Errorf("failed to update runner status for RunnerId/RunnerName/RunnerJITConfig: %w", err)
} }
// We want to continue without a requeue for faster pod creation. return nil, fmt.Errorf("%w: runner with the same name but doesn't belong to this RunnerScaleSet: %w", fatalError, err)
//
// To do so, we update the status in-place, so that both continuing the loop and
// and requeuing and skipping updateStatusWithRunnerConfig in the next loop, will
// have the same effect.
ephemeralRunner.Status.RunnerId = jitConfig.Runner.Id
ephemeralRunner.Status.RunnerName = jitConfig.Runner.Name
ephemeralRunner.Status.RunnerJITConfig = jitConfig.EncodedJITConfig
log.Info("Updated ephemeral runner status with runnerId and runnerJITConfig")
return nil, nil
} }
func (r *EphemeralRunnerReconciler) createPod(ctx context.Context, runner *v1alpha1.EphemeralRunner, secret *corev1.Secret, log logr.Logger) (ctrl.Result, error) { func (r *EphemeralRunnerReconciler) createPod(ctx context.Context, runner *v1alpha1.EphemeralRunner, secret *corev1.Secret, log logr.Logger) (ctrl.Result, error) {
@@ -651,7 +689,7 @@ func (r *EphemeralRunnerReconciler) createPod(ctx context.Context, runner *v1alp
} }
log.Info("Creating new pod for ephemeral runner") log.Info("Creating new pod for ephemeral runner")
newPod := r.newEphemeralRunnerPod(ctx, runner, secret, envs...) newPod := r.newEphemeralRunnerPod(runner, secret, envs...)
if err := ctrl.SetControllerReference(runner, newPod, r.Scheme); err != nil { if err := ctrl.SetControllerReference(runner, newPod, r.Scheme); err != nil {
log.Error(err, "Failed to set controller reference to a new pod") log.Error(err, "Failed to set controller reference to a new pod")
@@ -674,21 +712,21 @@ func (r *EphemeralRunnerReconciler) createPod(ctx context.Context, runner *v1alp
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
func (r *EphemeralRunnerReconciler) createSecret(ctx context.Context, runner *v1alpha1.EphemeralRunner, log logr.Logger) (*ctrl.Result, error) { func (r *EphemeralRunnerReconciler) createSecret(ctx context.Context, runner *v1alpha1.EphemeralRunner, jitConfig *actions.RunnerScaleSetJitRunnerConfig, log logr.Logger) (*corev1.Secret, error) {
log.Info("Creating new secret for ephemeral runner") log.Info("Creating new secret for ephemeral runner")
jitSecret := r.newEphemeralRunnerJitSecret(runner) jitSecret := r.newEphemeralRunnerJitSecret(runner, jitConfig)
if err := ctrl.SetControllerReference(runner, jitSecret, r.Scheme); err != nil { if err := ctrl.SetControllerReference(runner, jitSecret, r.Scheme); err != nil {
return &ctrl.Result{}, fmt.Errorf("failed to set controller reference: %w", err) return nil, fmt.Errorf("failed to set controller reference: %w", err)
} }
log.Info("Created new secret spec for ephemeral runner") log.Info("Created new secret spec for ephemeral runner")
if err := r.Create(ctx, jitSecret); err != nil { if err := r.Create(ctx, jitSecret); err != nil {
return &ctrl.Result{}, fmt.Errorf("failed to create jit secret: %w", err) return nil, fmt.Errorf("failed to create jit secret: %w", err)
} }
log.Info("Created ephemeral runner secret", "secretName", jitSecret.Name) log.Info("Created ephemeral runner secret", "secretName", jitSecret.Name)
return nil, nil return jitSecret, nil
} }
// updateRunStatusFromPod is responsible for updating non-exiting statuses. // updateRunStatusFromPod is responsible for updating non-exiting statuses.

View File

@@ -176,7 +176,7 @@ var _ = Describe("EphemeralRunner", func() {
).Should(BeEquivalentTo(ephemeralRunner.Name)) ).Should(BeEquivalentTo(ephemeralRunner.Name))
}) })
It("It should re-create pod on failure", func() { It("It should re-create pod on failure and no job assigned", func() {
pod := new(corev1.Pod) pod := new(corev1.Pod)
Eventually(func() (bool, error) { Eventually(func() (bool, error) {
if err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, pod); err != nil { if err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, pod); err != nil {
@@ -200,6 +200,67 @@ var _ = Describe("EphemeralRunner", func() {
).Should(BeEquivalentTo(true)) ).Should(BeEquivalentTo(true))
}) })
It("It should delete ephemeral runner on failure and job assigned", func() {
er := new(v1alpha1.EphemeralRunner)
// Check if finalizer is added
Eventually(
func() error {
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, er)
return err
},
ephemeralRunnerTimeout,
ephemeralRunnerInterval,
).Should(Succeed(), "failed to get ephemeral runner")
// update job id to simulate job assigned
er.Status.JobID = "1"
err := k8sClient.Status().Update(ctx, er)
Expect(err).To(BeNil(), "failed to update ephemeral runner status")
er = new(v1alpha1.EphemeralRunner)
Eventually(
func() (string, error) {
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, er)
if err != nil {
return "", err
}
return er.Status.JobID, nil
},
ephemeralRunnerTimeout,
ephemeralRunnerInterval,
).Should(BeEquivalentTo("1"))
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))
// delete pod to simulate failure
pod.Status.ContainerStatuses = append(pod.Status.ContainerStatuses, corev1.ContainerStatus{
Name: v1alpha1.EphemeralRunnerContainerName,
State: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
ExitCode: 1,
},
},
})
err = k8sClient.Status().Update(ctx, pod)
Expect(err).To(BeNil(), "Failed to update pod status")
er = new(v1alpha1.EphemeralRunner)
Eventually(
func() bool {
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, er)
return kerrors.IsNotFound(err)
},
ephemeralRunnerTimeout,
ephemeralRunnerInterval,
).Should(BeTrue(), "Ephemeral runner should eventually be deleted")
})
It("It should failed if a pod template is invalid", func() { It("It should failed if a pod template is invalid", func() {
invalideEphemeralRunner := newExampleRunner("invalid-ephemeral-runner", autoscalingNS.Name, configSecret.Name) invalideEphemeralRunner := newExampleRunner("invalid-ephemeral-runner", autoscalingNS.Name, configSecret.Name)
invalideEphemeralRunner.Spec.Spec.PriorityClassName = "notexist" invalideEphemeralRunner.Spec.Spec.PriorityClassName = "notexist"
@@ -208,13 +269,22 @@ var _ = Describe("EphemeralRunner", func() {
Expect(err).To(BeNil()) Expect(err).To(BeNil())
updated := new(v1alpha1.EphemeralRunner) updated := new(v1alpha1.EphemeralRunner)
Eventually(func() (corev1.PodPhase, error) { Eventually(
err := k8sClient.Get(ctx, client.ObjectKey{Name: invalideEphemeralRunner.Name, Namespace: invalideEphemeralRunner.Namespace}, updated) func() (corev1.PodPhase, error) {
if err != nil { err := k8sClient.Get(
return "", nil ctx,
} client.ObjectKey{Name: invalideEphemeralRunner.Name, Namespace: invalideEphemeralRunner.Namespace},
return updated.Status.Phase, nil updated,
}, ephemeralRunnerTimeout, ephemeralRunnerInterval).Should(BeEquivalentTo(corev1.PodFailed)) )
if err != nil {
return "", nil
}
return updated.Status.Phase, nil
},
ephemeralRunnerTimeout,
ephemeralRunnerInterval,
).Should(BeEquivalentTo(corev1.PodFailed))
Expect(updated.Status.Reason).Should(Equal("InvalidPod")) Expect(updated.Status.Reason).Should(Equal("InvalidPod"))
Expect(updated.Status.Message).Should(Equal("Failed to create the pod: pods \"invalid-ephemeral-runner\" is forbidden: no PriorityClass with name notexist was found")) Expect(updated.Status.Message).Should(Equal("Failed to create the pod: pods \"invalid-ephemeral-runner\" is forbidden: no PriorityClass with name notexist was found"))
}) })
@@ -775,7 +845,7 @@ var _ = Describe("EphemeralRunner", func() {
startManagers(GinkgoT(), mgr) startManagers(GinkgoT(), mgr)
}) })
It("It should set the Phase to Succeeded", func() { It("It should delete EphemeralRunner when pod exits successfully", func() {
ephemeralRunner := newExampleRunner("test-runner", autoscalingNS.Name, configSecret.Name) ephemeralRunner := newExampleRunner("test-runner", autoscalingNS.Name, configSecret.Name)
err := k8sClient.Create(ctx, ephemeralRunner) err := k8sClient.Create(ctx, ephemeralRunner)
@@ -801,13 +871,18 @@ var _ = Describe("EphemeralRunner", func() {
Expect(err).To(BeNil(), "failed to update pod status") Expect(err).To(BeNil(), "failed to update pod status")
updated := new(v1alpha1.EphemeralRunner) updated := new(v1alpha1.EphemeralRunner)
Eventually(func() (corev1.PodPhase, error) { Eventually(
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, updated) func() bool {
if err != nil { err := k8sClient.Get(
return "", nil ctx,
} client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace},
return updated.Status.Phase, nil updated,
}, ephemeralRunnerTimeout, ephemeralRunnerInterval).Should(BeEquivalentTo(corev1.PodSucceeded)) )
return kerrors.IsNotFound(err)
},
ephemeralRunnerTimeout,
ephemeralRunnerInterval,
).Should(BeTrue())
}) })
}) })

View File

@@ -453,8 +453,13 @@ func (r *EphemeralRunnerSetReconciler) deleteIdleEphemeralRunners(ctx context.Co
continue continue
} }
if !isDone && ephemeralRunner.Status.JobRequestId > 0 { if !isDone && ephemeralRunner.HasJob() {
log.Info("Skipping ephemeral runner since it is running a job", "name", ephemeralRunner.Name, "jobRequestId", ephemeralRunner.Status.JobRequestId) log.Info(
"Skipping ephemeral runner since it is running a job",
"name", ephemeralRunner.Name,
"workflowRunId", ephemeralRunner.Status.WorkflowRunId,
"jobId", ephemeralRunner.Status.JobID,
)
continue continue
} }

View File

@@ -32,9 +32,8 @@ import (
) )
const ( const (
ephemeralRunnerSetTestTimeout = time.Second * 20 ephemeralRunnerSetTestTimeout = time.Second * 20
ephemeralRunnerSetTestInterval = time.Millisecond * 250 ephemeralRunnerSetTestInterval = time.Millisecond * 250
ephemeralRunnerSetTestGitHubToken = "gh_token"
) )
func TestPrecomputedConstants(t *testing.T) { func TestPrecomputedConstants(t *testing.T) {
@@ -119,8 +118,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
Consistently( Consistently(
func() (int, error) { func() (int, error) {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
if err != nil {
return -1, err return -1, err
} }
@@ -153,8 +151,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
Eventually( Eventually(
func() (int, error) { func() (int, error) {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
if err != nil {
return -1, err return -1, err
} }
@@ -172,8 +169,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
} }
if refetch { if refetch {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
if err != nil {
return -1, err return -1, err
} }
} }
@@ -215,8 +211,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
Eventually( Eventually(
func() (int, error) { func() (int, error) {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
if err != nil {
return -1, err return -1, err
} }
@@ -234,8 +229,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
} }
if refetch { if refetch {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
if err != nil {
return -1, err return -1, err
} }
} }
@@ -253,8 +247,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
Eventually( Eventually(
func() (int, error) { func() (int, error) {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
if err != nil {
return -1, err return -1, err
} }
@@ -299,8 +292,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
if err != nil {
return -1, err return -1, err
} }
@@ -326,8 +318,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
if err != nil {
return -1, err return -1, err
} }
@@ -351,7 +342,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList = new(v1alpha1.EphemeralRunnerList) runnerList = new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -378,7 +369,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -403,7 +394,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList = new(v1alpha1.EphemeralRunnerList) runnerList = new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -429,7 +420,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList = new(v1alpha1.EphemeralRunnerList) runnerList = new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -456,7 +447,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -481,7 +472,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList = new(v1alpha1.EphemeralRunnerList) runnerList = new(v1alpha1.EphemeralRunnerList)
Consistently( Consistently(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -508,7 +499,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -545,7 +536,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
// We should have 3 runners, and have no Succeeded ones // We should have 3 runners, and have no Succeeded ones
Eventually( Eventually(
func() error { func() error {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return err return err
} }
@@ -582,7 +573,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -607,7 +598,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList = new(v1alpha1.EphemeralRunnerList) runnerList = new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() error { func() error {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return err return err
} }
@@ -648,7 +639,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
// We should have 1 runner up and pending // We should have 1 runner up and pending
Eventually( Eventually(
func() error { func() error {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return err return err
} }
@@ -675,7 +666,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
Eventually( Eventually(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -702,7 +693,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -728,7 +719,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList = new(v1alpha1.EphemeralRunnerList) runnerList = new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() error { func() error {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return err return err
} }
@@ -772,8 +763,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList = new(v1alpha1.EphemeralRunnerList) runnerList = new(v1alpha1.EphemeralRunnerList)
Consistently( Consistently(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
if err != nil {
return -1, err return -1, err
} }
@@ -799,7 +789,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList = new(v1alpha1.EphemeralRunnerList) runnerList = new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -826,7 +816,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() (int, error) { func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -853,7 +843,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList = new(v1alpha1.EphemeralRunnerList) runnerList = new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() error { func() error {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return err return err
} }
@@ -897,7 +887,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList = new(v1alpha1.EphemeralRunnerList) runnerList = new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() error { func() error {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return err return err
} }
@@ -938,7 +928,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
Eventually( Eventually(
func() (bool, error) { func() (bool, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -1046,7 +1036,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
Eventually( Eventually(
func() (int, error) { func() (int, error) {
runnerList = new(v1alpha1.EphemeralRunnerList) runnerList = new(v1alpha1.EphemeralRunnerList)
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -1208,7 +1198,7 @@ var _ = Describe("Test EphemeralRunnerSet controller with proxy settings", func(
Eventually(func(g Gomega) { Eventually(func(g Gomega) {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
g.Expect(err).NotTo(HaveOccurred(), "failed to list EphemeralRunners") g.Expect(err).NotTo(HaveOccurred(), "failed to list EphemeralRunners")
for _, runner := range runnerList.Items { for _, runner := range runnerList.Items {
@@ -1226,7 +1216,7 @@ var _ = Describe("Test EphemeralRunnerSet controller with proxy settings", func(
Eventually( Eventually(
func(g Gomega) (int, error) { func(g Gomega) (int, error) {
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -1245,7 +1235,7 @@ var _ = Describe("Test EphemeralRunnerSet controller with proxy settings", func(
} }
if refetch { if refetch {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -1260,6 +1250,18 @@ var _ = Describe("Test EphemeralRunnerSet controller with proxy settings", func(
err = k8sClient.Delete(ctx, ephemeralRunnerSet) err = k8sClient.Delete(ctx, ephemeralRunnerSet)
Expect(err).NotTo(HaveOccurred(), "failed to delete EphemeralRunnerSet") Expect(err).NotTo(HaveOccurred(), "failed to delete EphemeralRunnerSet")
Eventually(func(g Gomega) (int, error) {
runnerList := new(v1alpha1.EphemeralRunnerList)
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil {
return -1, err
}
return len(runnerList.Items), nil
},
ephemeralRunnerSetTestTimeout,
ephemeralRunnerSetTestInterval,
).Should(BeEquivalentTo(0), "EphemeralRunners should be deleted")
// Assert that the proxy secret is deleted // Assert that the proxy secret is deleted
Eventually(func(g Gomega) { Eventually(func(g Gomega) {
proxySecret := &corev1.Secret{} proxySecret := &corev1.Secret{}
@@ -1343,7 +1345,7 @@ var _ = Describe("Test EphemeralRunnerSet controller with proxy settings", func(
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
Eventually(func() (int, error) { Eventually(func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -1490,7 +1492,7 @@ var _ = Describe("Test EphemeralRunnerSet controller with custom root CA", func(
runnerList := new(v1alpha1.EphemeralRunnerList) runnerList := new(v1alpha1.EphemeralRunnerList)
Eventually(func() (int, error) { Eventually(func() (int, error) {
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@@ -1529,3 +1531,27 @@ var _ = Describe("Test EphemeralRunnerSet controller with custom root CA", func(
).Should(BeTrue(), "server was not called") ).Should(BeTrue(), "server was not called")
}) })
}) })
// helper function to remove ephemeral runners since in the test, ephemeral runner reconciler is not started
func listEphemeralRunnersAndRemoveFinalizers(ctx context.Context, k8sClient client.Client, list *v1alpha1.EphemeralRunnerList, namespace string) error {
err := k8sClient.List(ctx, list, client.InNamespace(namespace))
if err != nil {
return err
}
// Since we are not starting ephemeral runner reconciler, ignore
liveItems := make([]v1alpha1.EphemeralRunner, 0)
for _, item := range list.Items {
if !item.DeletionTimestamp.IsZero() {
if err := patch(ctx, k8sClient, &item, func(runner *v1alpha1.EphemeralRunner) {
runner.Finalizers = []string{}
}); err != nil {
return err
}
continue
}
liveItems = append(liveItems, item)
}
list.Items = liveItems
return nil
}

View File

@@ -0,0 +1,12 @@
package actionsgithubcom
type controllerError string
func (e controllerError) Error() string {
return string(e)
}
const (
retryableError = controllerError("retryable error")
fatalError = controllerError("fatal error")
)

View File

@@ -42,11 +42,11 @@ func createNamespace(t ginkgo.GinkgoTInterface, client client.Client) (*corev1.N
ObjectMeta: metav1.ObjectMeta{Name: "testns-autoscaling" + RandStringRunes(5)}, ObjectMeta: metav1.ObjectMeta{Name: "testns-autoscaling" + RandStringRunes(5)},
} }
err := k8sClient.Create(context.Background(), ns) err := client.Create(context.Background(), ns)
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() { t.Cleanup(func() {
err := k8sClient.Delete(context.Background(), ns) err := client.Delete(context.Background(), ns)
require.NoError(t, err) require.NoError(t, err)
}) })

View File

@@ -2,7 +2,6 @@ package actionsgithubcom
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"maps" "maps"
@@ -83,7 +82,7 @@ func boolPtr(v bool) *bool {
} }
func (b *ResourceBuilder) newAutoScalingListener(autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, ephemeralRunnerSet *v1alpha1.EphemeralRunnerSet, namespace, image string, imagePullSecrets []corev1.LocalObjectReference) (*v1alpha1.AutoscalingListener, error) { func (b *ResourceBuilder) newAutoScalingListener(autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, ephemeralRunnerSet *v1alpha1.EphemeralRunnerSet, namespace, image string, imagePullSecrets []corev1.LocalObjectReference) (*v1alpha1.AutoscalingListener, error) {
runnerScaleSetId, err := strconv.Atoi(autoscalingRunnerSet.Annotations[runnerScaleSetIdAnnotationKey]) runnerScaleSetID, err := strconv.Atoi(autoscalingRunnerSet.Annotations[runnerScaleSetIDAnnotationKey])
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -125,7 +124,7 @@ func (b *ResourceBuilder) newAutoScalingListener(autoscalingRunnerSet *v1alpha1.
GitHubConfigUrl: autoscalingRunnerSet.Spec.GitHubConfigUrl, GitHubConfigUrl: autoscalingRunnerSet.Spec.GitHubConfigUrl,
GitHubConfigSecret: autoscalingRunnerSet.Spec.GitHubConfigSecret, GitHubConfigSecret: autoscalingRunnerSet.Spec.GitHubConfigSecret,
VaultConfig: autoscalingRunnerSet.VaultConfig(), VaultConfig: autoscalingRunnerSet.VaultConfig(),
RunnerScaleSetId: runnerScaleSetId, RunnerScaleSetId: runnerScaleSetID,
AutoscalingRunnerSetNamespace: autoscalingRunnerSet.Namespace, AutoscalingRunnerSetNamespace: autoscalingRunnerSet.Namespace,
AutoscalingRunnerSetName: autoscalingRunnerSet.Name, AutoscalingRunnerSetName: autoscalingRunnerSet.Name,
EphemeralRunnerSetName: ephemeralRunnerSet.Name, EphemeralRunnerSetName: ephemeralRunnerSet.Name,
@@ -496,7 +495,7 @@ func (b *ResourceBuilder) newScaleSetListenerRoleBinding(autoscalingListener *v1
} }
func (b *ResourceBuilder) newEphemeralRunnerSet(autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet) (*v1alpha1.EphemeralRunnerSet, error) { func (b *ResourceBuilder) newEphemeralRunnerSet(autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet) (*v1alpha1.EphemeralRunnerSet, error) {
runnerScaleSetId, err := strconv.Atoi(autoscalingRunnerSet.Annotations[runnerScaleSetIdAnnotationKey]) runnerScaleSetID, err := strconv.Atoi(autoscalingRunnerSet.Annotations[runnerScaleSetIDAnnotationKey])
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -541,7 +540,7 @@ func (b *ResourceBuilder) newEphemeralRunnerSet(autoscalingRunnerSet *v1alpha1.A
Spec: v1alpha1.EphemeralRunnerSetSpec{ Spec: v1alpha1.EphemeralRunnerSetSpec{
Replicas: 0, Replicas: 0,
EphemeralRunnerSpec: v1alpha1.EphemeralRunnerSpec{ EphemeralRunnerSpec: v1alpha1.EphemeralRunnerSpec{
RunnerScaleSetId: runnerScaleSetId, RunnerScaleSetId: runnerScaleSetID,
GitHubConfigUrl: autoscalingRunnerSet.Spec.GitHubConfigUrl, GitHubConfigUrl: autoscalingRunnerSet.Spec.GitHubConfigUrl,
GitHubConfigSecret: autoscalingRunnerSet.Spec.GitHubConfigSecret, GitHubConfigSecret: autoscalingRunnerSet.Spec.GitHubConfigSecret,
Proxy: autoscalingRunnerSet.Spec.Proxy, Proxy: autoscalingRunnerSet.Spec.Proxy,
@@ -556,28 +555,23 @@ func (b *ResourceBuilder) newEphemeralRunnerSet(autoscalingRunnerSet *v1alpha1.A
} }
func (b *ResourceBuilder) newEphemeralRunner(ephemeralRunnerSet *v1alpha1.EphemeralRunnerSet) *v1alpha1.EphemeralRunner { func (b *ResourceBuilder) newEphemeralRunner(ephemeralRunnerSet *v1alpha1.EphemeralRunnerSet) *v1alpha1.EphemeralRunner {
labels := make(map[string]string) labels := make(map[string]string, len(ephemeralRunnerSet.Labels))
for k, v := range ephemeralRunnerSet.Labels { maps.Copy(labels, ephemeralRunnerSet.Labels)
if k == LabelKeyKubernetesComponent { labels[LabelKeyKubernetesComponent] = "runner"
labels[k] = "runner"
} else {
labels[k] = v
}
}
annotations := make(map[string]string)
for key, val := range ephemeralRunnerSet.Annotations {
annotations[key] = val
}
annotations := make(map[string]string, len(ephemeralRunnerSet.Annotations)+1)
maps.Copy(annotations, ephemeralRunnerSet.Annotations)
annotations[AnnotationKeyPatchID] = strconv.Itoa(ephemeralRunnerSet.Spec.PatchID) annotations[AnnotationKeyPatchID] = strconv.Itoa(ephemeralRunnerSet.Spec.PatchID)
return &v1alpha1.EphemeralRunner{ return &v1alpha1.EphemeralRunner{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
GenerateName: ephemeralRunnerSet.Name + "-runner-", GenerateName: ephemeralRunnerSet.Name + "-runner-",
Namespace: ephemeralRunnerSet.Namespace, Namespace: ephemeralRunnerSet.Namespace,
Labels: labels, Labels: labels,
Annotations: annotations, Annotations: annotations,
Finalizers: []string{
ephemeralRunnerFinalizerName,
ephemeralRunnerActionsFinalizerName,
},
OwnerReferences: []metav1.OwnerReference{ OwnerReferences: []metav1.OwnerReference{
{ {
APIVersion: ephemeralRunnerSet.GetObjectKind().GroupVersionKind().GroupVersion().String(), APIVersion: ephemeralRunnerSet.GetObjectKind().GroupVersionKind().GroupVersion().String(),
@@ -593,32 +587,22 @@ func (b *ResourceBuilder) newEphemeralRunner(ephemeralRunnerSet *v1alpha1.Epheme
} }
} }
func (b *ResourceBuilder) newEphemeralRunnerPod(ctx context.Context, runner *v1alpha1.EphemeralRunner, secret *corev1.Secret, envs ...corev1.EnvVar) *corev1.Pod { func (b *ResourceBuilder) newEphemeralRunnerPod(runner *v1alpha1.EphemeralRunner, secret *corev1.Secret, envs ...corev1.EnvVar) *corev1.Pod {
var newPod corev1.Pod var newPod corev1.Pod
labels := map[string]string{} annotations := make(map[string]string, len(runner.Annotations)+len(runner.Spec.Annotations))
annotations := map[string]string{} maps.Copy(annotations, runner.Annotations)
maps.Copy(annotations, runner.Spec.Annotations)
for k, v := range runner.Labels { labels := make(map[string]string, len(runner.Labels)+len(runner.Spec.Labels)+2)
labels[k] = v maps.Copy(labels, runner.Labels)
} maps.Copy(labels, runner.Spec.Labels)
for k, v := range runner.Spec.Labels {
labels[k] = v
}
labels["actions-ephemeral-runner"] = string(corev1.ConditionTrue) labels["actions-ephemeral-runner"] = string(corev1.ConditionTrue)
for k, v := range runner.Annotations {
annotations[k] = v
}
for k, v := range runner.Spec.Annotations {
annotations[k] = v
}
labels[LabelKeyPodTemplateHash] = hash.FNVHashStringObjects( labels[LabelKeyPodTemplateHash] = hash.FNVHashStringObjects(
FilterLabels(labels, LabelKeyRunnerTemplateHash), FilterLabels(labels, LabelKeyRunnerTemplateHash),
annotations, annotations,
runner.Spec, runner.Spec,
runner.Status.RunnerJITConfig, secret.Data,
) )
objectMeta := metav1.ObjectMeta{ objectMeta := metav1.ObjectMeta{
@@ -671,14 +655,17 @@ func (b *ResourceBuilder) newEphemeralRunnerPod(ctx context.Context, runner *v1a
return &newPod return &newPod
} }
func (b *ResourceBuilder) newEphemeralRunnerJitSecret(ephemeralRunner *v1alpha1.EphemeralRunner) *corev1.Secret { func (b *ResourceBuilder) newEphemeralRunnerJitSecret(ephemeralRunner *v1alpha1.EphemeralRunner, jitConfig *actions.RunnerScaleSetJitRunnerConfig) *corev1.Secret {
return &corev1.Secret{ return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: ephemeralRunner.Name, Name: ephemeralRunner.Name,
Namespace: ephemeralRunner.Namespace, Namespace: ephemeralRunner.Namespace,
}, },
Data: map[string][]byte{ Data: map[string][]byte{
jitTokenKey: []byte(ephemeralRunner.Status.RunnerJITConfig), jitTokenKey: []byte(jitConfig.EncodedJITConfig),
"runnerName": []byte(jitConfig.Runner.Name),
"runnerId": []byte(strconv.Itoa(jitConfig.Runner.Id)),
"scaleSetId": []byte(strconv.Itoa(jitConfig.Runner.RunnerScaleSetId)),
}, },
} }
} }
@@ -687,20 +674,28 @@ func scaleSetListenerConfigName(autoscalingListener *v1alpha1.AutoscalingListene
return fmt.Sprintf("%s-config", autoscalingListener.Name) return fmt.Sprintf("%s-config", autoscalingListener.Name)
} }
func scaleSetListenerName(autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet) string { func hashSuffix(namespace, runnerGroup, configURL string) string {
namespaceHash := hash.FNVHashString(autoscalingRunnerSet.Namespace) namespaceHash := hash.FNVHashString(namespace + "@" + runnerGroup + "@" + configURL)
if len(namespaceHash) > 8 { if len(namespaceHash) > 8 {
namespaceHash = namespaceHash[:8] namespaceHash = namespaceHash[:8]
} }
return fmt.Sprintf("%v-%v-listener", autoscalingRunnerSet.Name, namespaceHash) return namespaceHash
}
func scaleSetListenerName(autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet) string {
return fmt.Sprintf(
"%v-%v-listener",
autoscalingRunnerSet.Name,
hashSuffix(
autoscalingRunnerSet.Namespace,
autoscalingRunnerSet.Spec.RunnerGroup,
autoscalingRunnerSet.Spec.GitHubConfigUrl,
),
)
} }
func proxyListenerSecretName(autoscalingListener *v1alpha1.AutoscalingListener) string { func proxyListenerSecretName(autoscalingListener *v1alpha1.AutoscalingListener) string {
namespaceHash := hash.FNVHashString(autoscalingListener.Spec.AutoscalingRunnerSetNamespace) return autoscalingListener.Name + "-proxy"
if len(namespaceHash) > 8 {
namespaceHash = namespaceHash[:8]
}
return fmt.Sprintf("%v-%v-listener-proxy", autoscalingListener.Spec.AutoscalingRunnerSetName, namespaceHash)
} }
func proxyEphemeralRunnerSetSecretName(ephemeralRunnerSet *v1alpha1.EphemeralRunnerSet) string { func proxyEphemeralRunnerSetSecretName(ephemeralRunnerSet *v1alpha1.EphemeralRunnerSet) string {

View File

@@ -1,7 +1,6 @@
package actionsgithubcom package actionsgithubcom
import ( import (
"context"
"fmt" "fmt"
"strings" "strings"
"testing" "testing"
@@ -28,7 +27,7 @@ func TestLabelPropagation(t *testing.T) {
"directly.excluded.org/arbitrary": "not-excluded-value", "directly.excluded.org/arbitrary": "not-excluded-value",
}, },
Annotations: map[string]string{ Annotations: map[string]string{
runnerScaleSetIdAnnotationKey: "1", runnerScaleSetIDAnnotationKey: "1",
AnnotationKeyGitHubRunnerGroupName: "test-group", AnnotationKeyGitHubRunnerGroupName: "test-group",
AnnotationKeyGitHubRunnerScaleSetName: "test-scale-set", AnnotationKeyGitHubRunnerScaleSetName: "test-scale-set",
}, },
@@ -104,7 +103,7 @@ func TestLabelPropagation(t *testing.T) {
Name: "test", Name: "test",
}, },
} }
pod := b.newEphemeralRunnerPod(context.TODO(), ephemeralRunner, runnerSecret) pod := b.newEphemeralRunnerPod(ephemeralRunner, runnerSecret)
for key := range ephemeralRunner.Labels { for key := range ephemeralRunner.Labels {
assert.Equal(t, ephemeralRunner.Labels[key], pod.Labels[key]) assert.Equal(t, ephemeralRunner.Labels[key], pod.Labels[key])
} }
@@ -124,7 +123,7 @@ func TestGitHubURLTrimLabelValues(t *testing.T) {
LabelKeyKubernetesVersion: "0.2.0", LabelKeyKubernetesVersion: "0.2.0",
}, },
Annotations: map[string]string{ Annotations: map[string]string{
runnerScaleSetIdAnnotationKey: "1", runnerScaleSetIDAnnotationKey: "1",
AnnotationKeyGitHubRunnerGroupName: "test-group", AnnotationKeyGitHubRunnerGroupName: "test-group",
AnnotationKeyGitHubRunnerScaleSetName: "test-scale-set", AnnotationKeyGitHubRunnerScaleSetName: "test-scale-set",
}, },
@@ -190,7 +189,7 @@ func TestOwnershipRelationships(t *testing.T) {
LabelKeyKubernetesVersion: "0.2.0", LabelKeyKubernetesVersion: "0.2.0",
}, },
Annotations: map[string]string{ Annotations: map[string]string{
runnerScaleSetIdAnnotationKey: "1", runnerScaleSetIDAnnotationKey: "1",
AnnotationKeyGitHubRunnerGroupName: "test-group", AnnotationKeyGitHubRunnerGroupName: "test-group",
AnnotationKeyGitHubRunnerScaleSetName: "test-scale-set", AnnotationKeyGitHubRunnerScaleSetName: "test-scale-set",
annotationKeyValuesHash: "test-hash", annotationKeyValuesHash: "test-hash",
@@ -233,7 +232,7 @@ func TestOwnershipRelationships(t *testing.T) {
Name: "test-secret", Name: "test-secret",
}, },
} }
pod := b.newEphemeralRunnerPod(context.TODO(), ephemeralRunner, runnerSecret) pod := b.newEphemeralRunnerPod(ephemeralRunner, runnerSecret)
// Test EphemeralRunnerPod ownership // Test EphemeralRunnerPod ownership
require.Len(t, pod.OwnerReferences, 1, "EphemeralRunnerPod should have exactly one owner reference") require.Len(t, pod.OwnerReferences, 1, "EphemeralRunnerPod should have exactly one owner reference")

View File

@@ -321,26 +321,34 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) findHRAsByKey(ctx con
defaultListOpts = append(defaultListOpts, client.InNamespace(ns)) defaultListOpts = append(defaultListOpts, client.InNamespace(ns))
} }
var hras []v1alpha1.HorizontalRunnerAutoscaler // Get all HRAs since we can't use the index for repository/organization lookup anymore
var hraList v1alpha1.HorizontalRunnerAutoscalerList
if value != "" { if err := autoscaler.List(ctx, &hraList, defaultListOpts...); err != nil {
opts := append([]client.ListOption{}, defaultListOpts...) return nil, err
opts = append(opts, client.MatchingFields{scaleTargetKey: value})
if autoscaler.Namespace != "" {
opts = append(opts, client.InNamespace(autoscaler.Namespace))
}
var hraList v1alpha1.HorizontalRunnerAutoscalerList
if err := autoscaler.List(ctx, &hraList, opts...); err != nil {
return nil, err
}
hras = append(hras, hraList.Items...)
} }
return hras, nil var matchingHRAs []v1alpha1.HorizontalRunnerAutoscaler
if value == "" {
return matchingHRAs, nil
}
// For each HRA, resolve its ScaleTargetRef and check if it matches the requested value
for _, hra := range hraList.Items {
if hra.Spec.ScaleTargetRef.Name == "" {
continue
}
keys := autoscaler.getHRAKeys(ctx, &hra)
for _, key := range keys {
if key == value {
matchingHRAs = append(matchingHRAs, hra)
break
}
}
}
return matchingHRAs, nil
} }
type ScaleTarget struct { type ScaleTarget struct {
@@ -710,10 +718,36 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) indexer(rawObj client
return nil return nil
} }
// Return a simple key based on the ScaleTargetRef to avoid client calls in indexer
// The actual repository/organization resolution will be done later when needed
kind := hra.Spec.ScaleTargetRef.Kind
if kind == "" {
kind = "RunnerDeployment" // default
}
key := fmt.Sprintf("%s/%s/%s", kind, hra.Namespace, hra.Spec.ScaleTargetRef.Name)
autoscaler.Log.V(2).Info(fmt.Sprintf("HRA indexed for HRA %s with key: %s", hra.Name, key))
return []string{key}
}
func enterpriseKey(name string) string {
return keyPrefixEnterprise + name
}
func organizationalRunnerGroupKey(owner, group string) string {
return owner + keyRunnerGroup + group
}
func enterpriseRunnerGroupKey(enterprise, group string) string {
return keyPrefixEnterprise + enterprise + keyRunnerGroup + group
}
// getHRAKeys resolves the ScaleTargetRef and returns the repository/organization keys for an HRA
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getHRAKeys(ctx context.Context, hra *v1alpha1.HorizontalRunnerAutoscaler) []string {
switch hra.Spec.ScaleTargetRef.Kind { switch hra.Spec.ScaleTargetRef.Kind {
case "", "RunnerDeployment": case "", "RunnerDeployment":
var rd v1alpha1.RunnerDeployment var rd v1alpha1.RunnerDeployment
if err := autoscaler.Get(context.Background(), types.NamespacedName{Namespace: hra.Namespace, Name: hra.Spec.ScaleTargetRef.Name}, &rd); err != nil { if err := autoscaler.Get(ctx, types.NamespacedName{Namespace: hra.Namespace, Name: hra.Spec.ScaleTargetRef.Name}, &rd); err != nil {
autoscaler.Log.V(1).Info(fmt.Sprintf("RunnerDeployment not found with scale target ref name %s for hra %s", hra.Spec.ScaleTargetRef.Name, hra.Name)) autoscaler.Log.V(1).Info(fmt.Sprintf("RunnerDeployment not found with scale target ref name %s for hra %s", hra.Spec.ScaleTargetRef.Name, hra.Name))
return nil return nil
} }
@@ -736,11 +770,10 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) indexer(rawObj client
keys = append(keys, enterpriseKey(enterprise)) // Enterprise runners keys = append(keys, enterpriseKey(enterprise)) // Enterprise runners
} }
} }
autoscaler.Log.V(2).Info(fmt.Sprintf("HRA keys indexed for HRA %s: %v", hra.Name, keys))
return keys return keys
case "RunnerSet": case "RunnerSet":
var rs v1alpha1.RunnerSet var rs v1alpha1.RunnerSet
if err := autoscaler.Get(context.Background(), types.NamespacedName{Namespace: hra.Namespace, Name: hra.Spec.ScaleTargetRef.Name}, &rs); err != nil { if err := autoscaler.Get(ctx, types.NamespacedName{Namespace: hra.Namespace, Name: hra.Spec.ScaleTargetRef.Name}, &rs); err != nil {
autoscaler.Log.V(1).Info(fmt.Sprintf("RunnerSet not found with scale target ref name %s for hra %s", hra.Spec.ScaleTargetRef.Name, hra.Name)) autoscaler.Log.V(1).Info(fmt.Sprintf("RunnerSet not found with scale target ref name %s for hra %s", hra.Spec.ScaleTargetRef.Name, hra.Name))
return nil return nil
} }
@@ -761,21 +794,8 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) indexer(rawObj client
keys = append(keys, enterpriseRunnerGroupKey(enterprise, rs.Spec.Group)) // Enterprise runner groups keys = append(keys, enterpriseRunnerGroupKey(enterprise, rs.Spec.Group)) // Enterprise runner groups
} }
} }
autoscaler.Log.V(2).Info(fmt.Sprintf("HRA keys indexed for HRA %s: %v", hra.Name, keys))
return keys return keys
} }
return nil return nil
} }
func enterpriseKey(name string) string {
return keyPrefixEnterprise + name
}
func organizationalRunnerGroupKey(owner, group string) string {
return owner + keyRunnerGroup + group
}
func enterpriseRunnerGroupKey(enterprise, group string) string {
return keyPrefixEnterprise + enterprise + keyRunnerGroup + group
}

View File

@@ -9,6 +9,7 @@ import (
"net/http/httptest" "net/http/httptest"
"net/url" "net/url"
"os" "os"
"sync"
"testing" "testing"
"time" "time"
@@ -419,9 +420,14 @@ func TestGetValidCapacityReservations(t *testing.T) {
func installTestLogger(webhook *HorizontalRunnerAutoscalerGitHubWebhook) *bytes.Buffer { func installTestLogger(webhook *HorizontalRunnerAutoscalerGitHubWebhook) *bytes.Buffer {
logs := &bytes.Buffer{} logs := &bytes.Buffer{}
// Wrap the buffer with a synchronized writer to prevent race conditions
syncWriter := &syncWriter{
writer: logs,
}
sink := &testLogSink{ sink := &testLogSink{
name: "testlog", name: "testlog",
writer: logs, writer: syncWriter,
} }
log := logr.New(sink) log := logr.New(sink)
@@ -517,6 +523,18 @@ func sendWebhook(server *httptest.Server, eventType string, event interface{}) (
return http.DefaultClient.Do(req) return http.DefaultClient.Do(req)
} }
// syncWriter wraps an io.Writer with a mutex for thread-safe writes
type syncWriter struct {
writer io.Writer
mu sync.Mutex
}
func (sw *syncWriter) Write(p []byte) (n int, err error) {
sw.mu.Lock()
defer sw.mu.Unlock()
return sw.writer.Write(p)
}
// testLogSink is a sample logr.Logger that logs in-memory. // testLogSink is a sample logr.Logger that logs in-memory.
// It's only for testing log outputs. // It's only for testing log outputs.
type testLogSink struct { type testLogSink struct {

View File

@@ -1046,12 +1046,12 @@ func newRunnerPodWithContainerMode(containerMode string, template corev1.Pod, ru
// overridden // overridden
if ok, _ := envVarPresent("DOCKER_GROUP_GID", dockerdContainer.Env); !ok { if ok, _ := envVarPresent("DOCKER_GROUP_GID", dockerdContainer.Env); !ok {
gid := d.DockerGID gid := d.DockerGID
// We default to gid 121 for Ubuntu 22.04 images // We default to gid 121 for Ubuntu 22.04 and 24.04 images
// See below for more details // See below for more details
// - https://github.com/actions/actions-runner-controller/issues/2490#issuecomment-1501561923 // - https://github.com/actions/actions-runner-controller/issues/2490#issuecomment-1501561923
// - https://github.com/actions/actions-runner-controller/blob/8869ad28bb5a1daaedefe0e988571fe1fb36addd/runner/actions-runner.ubuntu-20.04.dockerfile#L14 // - https://github.com/actions/actions-runner-controller/blob/8869ad28bb5a1daaedefe0e988571fe1fb36addd/runner/actions-runner.ubuntu-20.04.dockerfile#L14
// - https://github.com/actions/actions-runner-controller/blob/8869ad28bb5a1daaedefe0e988571fe1fb36addd/runner/actions-runner.ubuntu-22.04.dockerfile#L12 // - https://github.com/actions/actions-runner-controller/blob/8869ad28bb5a1daaedefe0e988571fe1fb36addd/runner/actions-runner.ubuntu-22.04.dockerfile#L12
if strings.Contains(runnerContainer.Image, "22.04") { if strings.Contains(runnerContainer.Image, "22.04") || strings.Contains(runnerContainer.Image, "24.04") {
gid = "121" gid = "121"
} else if strings.Contains(runnerContainer.Image, "20.04") { } else if strings.Contains(runnerContainer.Image, "20.04") {
gid = "1001" gid = "1001"

View File

@@ -188,7 +188,7 @@ Create one using e.g. `eksctl`. You can refer to [the EKS documentation](https:/
Once you set up the service account, all you need is to add `serviceAccountName` and `fsGroup` to any pods that use the IAM-role enabled service account. Once you set up the service account, all you need is to add `serviceAccountName` and `fsGroup` to any pods that use the IAM-role enabled service account.
`fsGroup` needs to be set to the UID of the `runner` Linux user that runs the runner agent (and dockerd in case you use dind-runner). For anyone using an Ubuntu 20.04 runner image it's `1000` and for Ubuntu 22.04 one it's `1001`. `fsGroup` needs to be set to the UID of the `runner` Linux user that runs the runner agent (and dockerd in case you use dind-runner). For anyone using an Ubuntu 20.04 runner image it's `1000` and for Ubuntu 22.04 and 24.04 one it's `1001`.
For `RunnerDeployment`, you can set those two fields under the runner spec at `RunnerDeployment.Spec.Template`: For `RunnerDeployment`, you can set those two fields under the runner spec at `RunnerDeployment.Spec.Template`:
@@ -200,12 +200,12 @@ metadata:
spec: spec:
template: template:
spec: spec:
repository: USER/REO repository: USER/REPO
serviceAccountName: my-service-account serviceAccountName: my-service-account
securityContext: securityContext:
# For Ubuntu 20.04 runner # For Ubuntu 20.04 runner
fsGroup: 1000 fsGroup: 1000
# Use 1001 for Ubuntu 22.04 runner # Use 1001 for Ubuntu 22.04 and 24.04 runner
#fsGroup: 1001 #fsGroup: 1001
``` ```

View File

@@ -43,6 +43,22 @@ You can follow [this troubleshooting guide](https://docs.github.com/en/actions/h
## Changelog ## Changelog
### 0.13.0
1. Remove workflow actions version comments since upgrades are done via dependabot [#4161](https://github.com/actions/actions-runner-controller/pull/4161)
1. Fix image pull secrets list arguments in the chart [#4164](https://github.com/actions/actions-runner-controller/pull/4164)
1. Update example GitHub URLs in values.yaml to include an example for enterprise account-level runners [#4181](https://github.com/actions/actions-runner-controller/pull/4181)
1. docs: fix repo path typo [#4229](https://github.com/actions/actions-runner-controller/pull/4229)
1. Remove deprecated preserveUnknownFields from CRDs [#4135](https://github.com/actions/actions-runner-controller/pull/4135)
1. Add workflow name and target labels [#4240](https://github.com/actions/actions-runner-controller/pull/4240)
1. docs: fix broken Grafana dashboard JSON path [#4270](https://github.com/actions/actions-runner-controller/pull/4270)
1. Ensure ephemeral runner is deleted from the service on exit != 0 [#4260](https://github.com/actions/actions-runner-controller/pull/4260)
1. Remove JIT config from ephemeral runner status field [#4191](https://github.com/actions/actions-runner-controller/pull/4191)
1. Remove ephemeral runner when exit code != 0 and is patched with the job [#4239](https://github.com/actions/actions-runner-controller/pull/4239)
1. Bump the gomod group across 1 directory with 4 updates [#4277](https://github.com/actions/actions-runner-controller/pull/4277)
1. Bump all dependencies [#4266](https://github.com/actions/actions-runner-controller/pull/4266)
### 0.12.1 ### 0.12.1
1. Fix indentation of startupProbe attributes in dind sidecar [#4126](https://github.com/actions/actions-runner-controller/pull/4126) 1. Fix indentation of startupProbe attributes in dind sidecar [#4126](https://github.com/actions/actions-runner-controller/pull/4126)

View File

@@ -15,7 +15,7 @@ This sample dashboard shows how to visualize the metrics with [Grafana](https://
1. Make sure to have [Grafana](https://grafana.com/docs/grafana/latest/installation/) and [Prometheus](https://prometheus.io/docs/prometheus/latest/installation/) running in your cluster. 1. Make sure to have [Grafana](https://grafana.com/docs/grafana/latest/installation/) and [Prometheus](https://prometheus.io/docs/prometheus/latest/installation/) running in your cluster.
2. Make sure that Prometheus is properly scraping the metrics endpoints of the controller-manager and listeners. 2. Make sure that Prometheus is properly scraping the metrics endpoints of the controller-manager and listeners.
3. Import the [dashboard](ARC-Autoscaling-Runner-Set-Monitoring_1692627561838.json) into Grafana. 3. Import the [dashboard](ARC-Autoscaling-Runner-Set-Monitoring.json) into Grafana.
## Required metrics ## Required metrics

View File

@@ -37,7 +37,7 @@ type JobAssigned struct {
} }
type JobStarted struct { type JobStarted struct {
RunnerId int `json:"runnerId"` RunnerID int `json:"runnerId"`
RunnerName string `json:"runnerName"` RunnerName string `json:"runnerName"`
JobMessageBase JobMessageBase
} }
@@ -55,12 +55,13 @@ type JobMessageType struct {
type JobMessageBase struct { type JobMessageBase struct {
JobMessageType JobMessageType
RunnerRequestId int64 `json:"runnerRequestId"` RunnerRequestID int64 `json:"runnerRequestId"`
RepositoryName string `json:"repositoryName"` RepositoryName string `json:"repositoryName"`
OwnerName string `json:"ownerName"` OwnerName string `json:"ownerName"`
JobID string `json:"jobId"`
JobWorkflowRef string `json:"jobWorkflowRef"` JobWorkflowRef string `json:"jobWorkflowRef"`
JobDisplayName string `json:"jobDisplayName"` JobDisplayName string `json:"jobDisplayName"`
WorkflowRunId int64 `json:"workflowRunId"` WorkflowRunID int64 `json:"workflowRunId"`
EventName string `json:"eventName"` EventName string `json:"eventName"`
RequestLabels []string `json:"requestLabels"` RequestLabels []string `json:"requestLabels"`
QueueTime time.Time `json:"queueTime"` QueueTime time.Time `json:"queueTime"`

236
go.mod
View File

@@ -1,136 +1,142 @@
module github.com/actions/actions-runner-controller module github.com/actions/actions-runner-controller
go 1.24.3 go 1.25.1
require ( require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0 github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.4.0
github.com/bradleyfalzon/ghinstallation/v2 v2.14.0 github.com/bradleyfalzon/ghinstallation/v2 v2.17.0
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/evanphx/json-patch v5.9.11+incompatible github.com/evanphx/json-patch v5.9.11+incompatible
github.com/go-logr/logr v1.4.2 github.com/go-logr/logr v1.4.3
github.com/golang-jwt/jwt/v4 v4.5.2 github.com/golang-jwt/jwt/v4 v4.5.2
github.com/google/go-cmp v0.7.0 github.com/google/go-cmp v0.7.0
github.com/google/go-github/v52 v52.0.0 github.com/google/go-github/v52 v52.0.0
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/gorilla/mux v1.8.1 github.com/gorilla/mux v1.8.1
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79
github.com/gruntwork-io/terratest v0.48.2 github.com/gruntwork-io/terratest v0.54.0
github.com/hashicorp/go-retryablehttp v0.7.7 github.com/hashicorp/go-retryablehttp v0.7.8
github.com/kelseyhightower/envconfig v1.4.0 github.com/kelseyhightower/envconfig v1.4.0
github.com/onsi/ginkgo v1.16.5 github.com/onsi/ginkgo v1.16.5
github.com/onsi/ginkgo/v2 v2.23.3 github.com/onsi/ginkgo/v2 v2.27.2
github.com/onsi/gomega v1.36.3 github.com/onsi/gomega v1.38.2
github.com/prometheus/client_golang v1.21.1 github.com/prometheus/client_golang v1.23.2
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.11.1
github.com/teambition/rrule-go v1.8.2 github.com/teambition/rrule-go v1.8.2
go.uber.org/multierr v1.11.0 go.uber.org/multierr v1.11.0
go.uber.org/zap v1.27.0 go.uber.org/zap v1.27.1
golang.org/x/net v0.38.0 golang.org/x/net v0.47.0
golang.org/x/oauth2 v0.28.0 golang.org/x/oauth2 v0.33.0
golang.org/x/sync v0.12.0 golang.org/x/sync v0.18.0
gomodules.xyz/jsonpatch/v2 v2.5.0 gomodules.xyz/jsonpatch/v2 v2.5.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.32.3 k8s.io/api v0.34.2
k8s.io/apimachinery v0.32.3 k8s.io/apimachinery v0.34.2
k8s.io/client-go v0.32.3 k8s.io/client-go v0.34.2
k8s.io/utils v0.0.0-20241210054802-24370beab758 k8s.io/utils v0.0.0-20251002143259-bc988d571ff4
sigs.k8s.io/controller-runtime v0.20.4 sigs.k8s.io/controller-runtime v0.22.4
sigs.k8s.io/yaml v1.4.0 sigs.k8s.io/yaml v1.6.0
) )
require ( require (
filippo.io/edwards25519 v1.1.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect
github.com/BurntSushi/toml v1.4.0 // indirect github.com/BurntSushi/toml v1.5.0 // indirect
github.com/ProtonMail/go-crypto v1.1.6 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect github.com/ProtonMail/go-crypto v1.3.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect github.com/aws/aws-sdk-go-v2 v1.39.2 // indirect
github.com/aws/aws-sdk-go-v2/config v1.29.9 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.62 // indirect github.com/aws/aws-sdk-go-v2/config v1.31.12 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.18.16 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.65 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.19.11 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.9 // indirect
github.com/aws/aws-sdk-go-v2/service/acm v1.31.1 // indirect github.com/aws/aws-sdk-go-v2/service/acm v1.37.6 // indirect
github.com/aws/aws-sdk-go-v2/service/autoscaling v1.52.1 // indirect github.com/aws/aws-sdk-go-v2/service/autoscaling v1.59.3 // indirect
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.46.1 // indirect github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.58.2 // indirect
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.41.1 // indirect github.com/aws/aws-sdk-go-v2/service/dynamodb v1.51.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ec2 v1.208.0 // indirect github.com/aws/aws-sdk-go-v2/service/ec2 v1.254.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ecr v1.42.1 // indirect github.com/aws/aws-sdk-go-v2/service/ecr v1.50.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ecs v1.54.1 // indirect github.com/aws/aws-sdk-go-v2/service/ecs v1.65.1 // indirect
github.com/aws/aws-sdk-go-v2/service/iam v1.40.1 // indirect github.com/aws/aws-sdk-go-v2/service/iam v1.47.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.6.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15 // indirect github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.9 // indirect
github.com/aws/aws-sdk-go-v2/service/kms v1.38.1 // indirect github.com/aws/aws-sdk-go-v2/service/kms v1.45.6 // indirect
github.com/aws/aws-sdk-go-v2/service/lambda v1.70.1 // indirect github.com/aws/aws-sdk-go-v2/service/lambda v1.77.6 // indirect
github.com/aws/aws-sdk-go-v2/service/rds v1.94.1 // indirect github.com/aws/aws-sdk-go-v2/service/rds v1.108.0 // indirect
github.com/aws/aws-sdk-go-v2/service/route53 v1.49.1 // indirect github.com/aws/aws-sdk-go-v2/service/route53 v1.58.4 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.78.1 // indirect github.com/aws/aws-sdk-go-v2/service/s3 v1.88.3 // indirect
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.2 // indirect github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.39.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sns v1.34.2 // indirect github.com/aws/aws-sdk-go-v2/service/sns v1.38.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.1 // indirect github.com/aws/aws-sdk-go-v2/service/sqs v1.42.8 // indirect
github.com/aws/aws-sdk-go-v2/service/ssm v1.57.2 // indirect github.com/aws/aws-sdk-go-v2/service/ssm v1.65.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.29.6 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.38.6 // indirect
github.com/aws/smithy-go v1.22.3 // indirect github.com/aws/smithy-go v1.23.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/boombuler/barcode v1.0.2 // indirect github.com/boombuler/barcode v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudflare/circl v1.6.1 // indirect github.com/cloudflare/circl v1.6.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect
github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-errors/errors v1.5.1 // indirect github.com/go-errors/errors v1.5.1 // indirect
github.com/go-logr/zapr v1.3.0 // indirect github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonpointer v0.22.1 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.2 // indirect
github.com/go-openapi/swag v0.23.0 // indirect github.com/go-openapi/swag v0.25.1 // indirect
github.com/go-sql-driver/mysql v1.9.0 // indirect github.com/go-openapi/swag/cmdutils v0.25.1 // indirect
github.com/go-openapi/swag/conv v0.25.1 // indirect
github.com/go-openapi/swag/fileutils v0.25.1 // indirect
github.com/go-openapi/swag/jsonname v0.25.1 // indirect
github.com/go-openapi/swag/jsonutils v0.25.1 // indirect
github.com/go-openapi/swag/loading v0.25.1 // indirect
github.com/go-openapi/swag/mangling v0.25.1 // indirect
github.com/go-openapi/swag/netutils v0.25.1 // indirect
github.com/go-openapi/swag/stringutils v0.25.1 // indirect
github.com/go-openapi/swag/typeutils v0.25.1 // indirect
github.com/go-openapi/swag/yamlutils v0.25.1 // indirect
github.com/go-sql-driver/mysql v1.9.3 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect github.com/gonvenience/bunt v1.4.2 // indirect
github.com/gonvenience/bunt v1.4.0 // indirect github.com/gonvenience/idem v0.0.2 // indirect
github.com/gonvenience/idem v0.0.1 // indirect github.com/gonvenience/neat v1.3.16 // indirect
github.com/gonvenience/neat v1.3.15 // indirect github.com/gonvenience/term v1.0.4 // indirect
github.com/gonvenience/term v1.0.3 // indirect github.com/gonvenience/text v1.0.9 // indirect
github.com/gonvenience/text v1.0.8 // indirect github.com/gonvenience/ytbx v1.4.7 // indirect
github.com/gonvenience/ytbx v1.4.6 // indirect
github.com/google/btree v1.1.3 // indirect github.com/google/btree v1.1.3 // indirect
github.com/google/gnostic-models v0.6.9 // indirect github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/go-github/v69 v69.2.0 // indirect github.com/google/go-github/v75 v75.0.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20251002213607-436353cc1ee6 // indirect
github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7 // indirect github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/gruntwork-io/go-commons v0.17.2 // indirect github.com/gruntwork-io/go-commons v0.17.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/homeport/dyff v1.10.1 // indirect github.com/homeport/dyff v1.10.2 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.2 // indirect github.com/jackc/pgx/v5 v5.7.6 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3 // indirect github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-zglob v0.0.6 // indirect github.com/mattn/go-zglob v0.0.6 // indirect
@@ -139,42 +145,44 @@ require (
github.com/mitchellh/hashstructure v1.1.0 // indirect github.com/mitchellh/hashstructure v1.1.0 // indirect
github.com/moby/spdystream v0.5.0 // indirect github.com/moby/spdystream v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/pquerna/otp v1.4.0 // indirect github.com/pquerna/otp v1.5.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/procfs v0.17.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/sergi/go-diff v1.4.0 // indirect
github.com/spf13/pflag v1.0.6 // indirect github.com/spf13/pflag v1.0.10 // indirect
github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/objx v0.5.2 // indirect
github.com/texttheater/golang-levenshtein v1.0.1 // indirect github.com/texttheater/golang-levenshtein v1.0.1 // indirect
github.com/urfave/cli/v2 v2.27.6 // indirect github.com/urfave/cli/v2 v2.27.7 // indirect
github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 // indirect github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect
golang.org/x/crypto v0.36.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/sys v0.31.0 // indirect golang.org/x/crypto v0.45.0 // indirect
golang.org/x/term v0.30.0 // indirect golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect
golang.org/x/text v0.23.0 // indirect golang.org/x/mod v0.29.0 // indirect
golang.org/x/time v0.11.0 // indirect golang.org/x/sys v0.38.0 // indirect
golang.org/x/tools v0.31.0 // indirect golang.org/x/term v0.37.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect golang.org/x/text v0.31.0 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect golang.org/x/time v0.13.0 // indirect
golang.org/x/tools v0.38.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.32.2 // indirect k8s.io/apiextensions-apiserver v0.34.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20250304201544-e5f78fe3ede9 // indirect k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
) )
replace github.com/gregjones/httpcache => github.com/actions-runner-controller/httpcache v0.2.0 replace github.com/gregjones/httpcache => github.com/actions-runner-controller/httpcache v0.2.0

503
go.sum
View File

@@ -1,123 +1,123 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/Azure/azure-sdk-for-go v51.0.0+incompatible h1:p7blnyJSjJqf5jflHbSGhIhEpXIgIFmYZNg5uwqweso= github.com/Azure/azure-sdk-for-go v51.0.0+incompatible h1:p7blnyJSjJqf5jflHbSGhIhEpXIgIFmYZNg5uwqweso=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16APJ7jurfbY5jnfXpJoRMc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1 h1:1mvYtZfWQAnwNah/C+Z+Jb9rQH95LPE2vlmMuWAHJk8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1/go.mod h1:75I/mXtme1JyWFtz8GocPHVFyH421IBoZErnO16dd0k= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.1 h1:Bk5uOhSAenHyR5P61D/NzeQCv+4fEVV8mOkJ82NqpWw= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.1/go.mod h1:QZ4pw3or1WPmRBxf0cHd1tknzrT54WPBOQoGutCPvSU= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0 h1:WLUIpeyv04H0RCcQHaA4TNoyrQ39Ox7V+re+iaqzTe0= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.4.0 h1:/g8S6wk65vfC6m3FIxJ+i5QDyN9JWwXI8Hb0Img10hU=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0/go.mod h1:hd8hTTIY3VmUVPRHNH7GVCHO3SHgXkJKZHReby/bnUQ= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.4.0/go.mod h1:gpl+q95AzZlKVI3xSoseF9QPrypk0hQqBiJYeB/cR/I=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0 h1:eXnN9kaS8TiDwXjoie3hMRLuwdUBUMW9KRgOqB3mCaw= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 h1:nCYfgcSyHZXJI8J0IWE5MsCGlb2xp9fJiXyxWgmOFg4=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0/go.mod h1:XIpam8wumeZ5rVMuhdDQLMfIPDf1WO3IzrCRO3e3e3o= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0/go.mod h1:ucUjca2JtSZboY8IoUqyQyuuXvwbMBVwFOm0vdQPNhA=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 h1:kYRSnvJju5gYVyhkij+RTJ/VR6QIUaCfWeaFm2ycsjQ= github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
github.com/actions-runner-controller/httpcache v0.2.0 h1:hCNvYuVPJ2xxYBymqBvH0hSiQpqz4PHF/LbU3XghGNI= github.com/actions-runner-controller/httpcache v0.2.0 h1:hCNvYuVPJ2xxYBymqBvH0hSiQpqz4PHF/LbU3XghGNI=
github.com/actions-runner-controller/httpcache v0.2.0/go.mod h1:JLu9/2M/btPz1Zu/vTZ71XzukQHn2YeISPmJoM5exBI= github.com/actions-runner-controller/httpcache v0.2.0/go.mod h1:JLu9/2M/btPz1Zu/vTZ71XzukQHn2YeISPmJoM5exBI=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= github.com/aws/aws-sdk-go-v2 v1.39.2 h1:EJLg8IdbzgeD7xgvZ+I8M1e0fL0ptn/M47lianzth0I=
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= github.com/aws/aws-sdk-go-v2 v1.39.2/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 h1:zAybnyUQXIZ5mok5Jqwlf58/TFE7uvd3IAsa1aF9cXs= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.1 h1:i8p8P4diljCr60PpJp6qZXNlgX4m2yQFpYk+9ZT+J4E=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10/go.mod h1:qqvMj6gHLR/EXWZw4ZbqlPbQUyenf4h82UQUlKc+l14= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.1/go.mod h1:ddqbooRZYNoJ2dsTwOty16rM+/Aqmk/GOXrK8cg7V00=
github.com/aws/aws-sdk-go-v2/config v1.29.9 h1:Kg+fAYNaJeGXp1vmjtidss8O2uXIsXwaRqsQJKXVr+0= github.com/aws/aws-sdk-go-v2/config v1.31.12 h1:pYM1Qgy0dKZLHX2cXslNacbcEFMkDMl+Bcj5ROuS6p8=
github.com/aws/aws-sdk-go-v2/config v1.29.9/go.mod h1:oU3jj2O53kgOU4TXq/yipt6ryiooYjlkqqVaZk7gY/U= github.com/aws/aws-sdk-go-v2/config v1.31.12/go.mod h1:/MM0dyD7KSDPR+39p9ZNVKaHDLb9qnfDurvVS2KAhN8=
github.com/aws/aws-sdk-go-v2/credentials v1.17.62 h1:fvtQY3zFzYJ9CfixuAQ96IxDrBajbBWGqjNTCa79ocU= github.com/aws/aws-sdk-go-v2/credentials v1.18.16 h1:4JHirI4zp958zC026Sm+V4pSDwW4pwLefKrc0bF2lwI=
github.com/aws/aws-sdk-go-v2/credentials v1.17.62/go.mod h1:ElETBxIQqcxej++Cs8GyPBbgMys5DgQPTwo7cUPDKt8= github.com/aws/aws-sdk-go-v2/credentials v1.18.16/go.mod h1:qQMtGx9OSw7ty1yLclzLxXCRbrkjWAM7JnObZjmCB7I=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.9 h1:Mv4Bc0mWmv6oDuSWTKnk+wgeqPL5DRFu5bQL9BGPQ8Y=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.9/go.mod h1:IKlKfRppK2a1y0gy1yH6zD+yX5uplJ6UuPlgd48dJiQ=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.65 h1:03zF9oWZyXvw08Say761JGpE9PbeGPd4FAmdpgDAm/I= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.19.11 h1:w4GjasReY0m9vZA/3YhoBUBi1ZIWUHYQRm61v0BKcZg=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.65/go.mod h1:hBobvLKm46Igpcw6tkq9hFUmU14iAOrC5KL6EyYYckA= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.19.11/go.mod h1:IPS1CSYQ8lfLYGytpMEPW4erZmVFUdxLpC0RCI/RCn8=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9 h1:se2vOWGD3dWQUtfn4wEjRQJb1HK1XsNIt825gskZ970=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9/go.mod h1:hijCGH2VfbZQxqCDN7bwz/4dzxV+hkyhjawAtdPWKZA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9 h1:6RBnKZLkJM4hQ+kN6E7yWFveOTg8NLPHAkqrs4ZPlTU=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9/go.mod h1:V9rQKRmK7AWuEsOMnHzKj8WyrIir1yUJbZxDuZLFvXI=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 h1:ZNTqv4nIdE/DiBfUUfXcLZ/Spcuz+RjeziUtNJackkM= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.9 h1:w9LnHqTq8MEdlnyhV4Bwfizd65lfNCNgdlNC6mM5paE=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.9/go.mod h1:LGEP6EK4nj+bwWNdrvX/FnDTFowdBNwcSPuZu/ouFys=
github.com/aws/aws-sdk-go-v2/service/acm v1.31.1 h1:FB1PgU6vlXbqehxZiHuYQRWo5Ou6sQrFJcUaRe27lRo= github.com/aws/aws-sdk-go-v2/service/acm v1.37.6 h1:48oGbMpBSzihrU145gpjrxySIs+VNGCXu9kLTLAdJJg=
github.com/aws/aws-sdk-go-v2/service/acm v1.31.1/go.mod h1:3sKYAgRbuBa2QMYGh/WEclwnmfx+QoPhhX25PdSQSQM= github.com/aws/aws-sdk-go-v2/service/acm v1.37.6/go.mod h1:4Xgg9iUMFMpWd19UokmUwBCU6fqNJ7LPo11YYt3/xl4=
github.com/aws/aws-sdk-go-v2/service/autoscaling v1.52.1 h1:wj4AION3NjQvjOiI8wm+TVU8y+8EsTl7fSgJAzk9cgc= github.com/aws/aws-sdk-go-v2/service/autoscaling v1.59.3 h1:2tVkkifL19ZmmCRJyOudUuTNRzA1SYN7D32iEkB8CvE=
github.com/aws/aws-sdk-go-v2/service/autoscaling v1.52.1/go.mod h1:CDqMoc3KRdZJ8qziW96J35lKH01Wq3B2aihtHj2JbRs= github.com/aws/aws-sdk-go-v2/service/autoscaling v1.59.3/go.mod h1:/Utcw7rzRwiW7C9ypYInnEtgyU7Nr8eG3+RFUUvuE1o=
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.46.1 h1:pYm/RS3V/UaSAkHAGZUJuECz7f9y8WTPmu9Q+4JcigE= github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.58.2 h1:JPW6ND8muLsBwALrf/VXikyokUmGWNKZa88qZWwFGWA=
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.46.1/go.mod h1:uo14VBn5cNk/BPGTPz3kyLBxgpgOObgO8lmz+H7Z4Ck= github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.58.2/go.mod h1:3Dh12t3s/KrpEm7HNfg5RH+XWzi9LW2QI7velkc61ac=
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.41.1 h1:DEys4E5Q2p735j56lteNVyByIBDAlMrO5VIEd9RC0/4= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.51.0 h1:TfglMkeRNYNGkyJ+XOTQJJ/RQb+MBlkiMn2H7DYuZok=
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.41.1/go.mod h1:yYaWRnVSPyAmexW5t7G3TcuYoalYfT+xQwzWsvtUQ7M= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.51.0/go.mod h1:AdM9p8Ytg90UaNYrZIsOivYeC5cDvTPC2Mqw4/2f2aM=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.208.0 h1:qzT4wyLo7ssa4QU8Xcf+h+iyCF4WTeQtM8fjr+UUKyI= github.com/aws/aws-sdk-go-v2/service/ec2 v1.254.1 h1:7p9bJCZ/b3EJXXARW7JMEs2IhsnI4YFHpfXQfgMh0eg=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.208.0/go.mod h1:ouvGEfHbLaIlWwpDpOVWPWR+YwO0HDv3vm5tYLq8ImY= github.com/aws/aws-sdk-go-v2/service/ec2 v1.254.1/go.mod h1:M8WWWIfXmxA4RgTXcI/5cSByxRqjgne32Sh0VIbrn0A=
github.com/aws/aws-sdk-go-v2/service/ecr v1.42.1 h1:mgtRN6wS2Frq29O7YNTn18ieokL193RFpLhUbsvs7o0= github.com/aws/aws-sdk-go-v2/service/ecr v1.50.5 h1:jzjNyiIrXJHumV1hwofcQLpIZtcDw+vPQL00rLI3s4g=
github.com/aws/aws-sdk-go-v2/service/ecr v1.42.1/go.mod h1:iQ1skgw1XRK+6Lgkb0I9ODatAP72WoTILh0zXQ5DtbU= github.com/aws/aws-sdk-go-v2/service/ecr v1.50.5/go.mod h1:UtPKcYVHY6RrV9EaaM1KZGNaf9dgviFdsT6xoFMLQsM=
github.com/aws/aws-sdk-go-v2/service/ecs v1.54.1 h1:h0D7tqShlfhcTT6FGbE7IFsCIZLCmLXpYnYORZqg37I= github.com/aws/aws-sdk-go-v2/service/ecs v1.65.1 h1:pBbXc1fGRbrYl7NFujuubMmEFEp7CJiKTBsoDOIUkuk=
github.com/aws/aws-sdk-go-v2/service/ecs v1.54.1/go.mod h1:wAtdeFanDuF9Re/ge4DRDaYe3Wy1OGrU7jG042UcuI4= github.com/aws/aws-sdk-go-v2/service/ecs v1.65.1/go.mod h1:fu6WrWUHYyPRjzYO13UDXA7O6OShI8QbH5YSl9SOJwQ=
github.com/aws/aws-sdk-go-v2/service/iam v1.40.1 h1:PaHCkW8rtLrA89xM/0LsY/NSIQETqmN+f1vt70EmpB8= github.com/aws/aws-sdk-go-v2/service/iam v1.47.7 h1:0EDAdmMTzsgXl++8a0JZ+Yx0/dOqT8o/EONknxlQK94=
github.com/aws/aws-sdk-go-v2/service/iam v1.40.1/go.mod h1:mPJkGQzeCoPs82ElNILor2JzZgYENr4UaSKUT8K27+c= github.com/aws/aws-sdk-go-v2/service/iam v1.47.7/go.mod h1:NkNbn/8/mFrPUq0Kg6EM6c0+GaTLG+aPzXxwB7RF5xo=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 h1:oegbebPEMA/1Jny7kvwejowCaHz1FWZAQ94WXFNCyTM=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1/go.mod h1:kemo5Myr9ac0U9JfSjMo9yHLtw+pECEHsFtJ9tqCEI8=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.6.2 h1:t/gZFyrijKuSU0elA5kRngP/oU3mc0I+Dvp8HwRE4c0= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.9 h1:by3nYZLR9l8bUH7kgaMU4dJgYFjyRdFEfORlDpPILB4=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.6.2/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.9/go.mod h1:IWjQYlqw4EX9jw2g3qnEPPWvCE6bS8fKzhMed1OK7c8=
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15 h1:M1R1rud7HzDrfCdlBQ7NjnRsDNEhXO/vGhuD189Ggmk= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.9 h1:7ILIzhRlYbHmZDdkF15B+RGEO8sGbdSe0RelD0RcV6M=
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15/go.mod h1:uvFKBSq9yMPV4LGAi7N4awn4tLY+hKE35f8THes2mzQ= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.9/go.mod h1:6LLPgzztobazqK65Q5qYsFnxwsN0v6cktuIvLC5M7DM=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.9 h1:5r34CgVOD4WZudeEKZ9/iKpiT6cM1JyEROpXjOcdWv8=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.9/go.mod h1:dB12CEbNWPbzO2uC6QSWHteqOg4JfBVJOojbAoAUb5I=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 h1:moLQUoVq91LiqT1nbvzDukyqAlCv89ZmwaHw/ZFlFZg= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.9 h1:wuZ5uW2uhJR63zwNlqWH2W4aL4ZjeJP3o92/W+odDY4=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.9/go.mod h1:/G58M2fGszCrOzvJUkDdY8O9kycodunH4VdT5oBAqls=
github.com/aws/aws-sdk-go-v2/service/kms v1.38.1 h1:tecq7+mAav5byF+Mr+iONJnCBf4B4gon8RSp4BrweSc= github.com/aws/aws-sdk-go-v2/service/kms v1.45.6 h1:Br3kil4j7RPW+7LoLVkYt8SuhIWlg6ylmbmzXJ7PgXY=
github.com/aws/aws-sdk-go-v2/service/kms v1.38.1/go.mod h1:cQn6tAF77Di6m4huxovNM7NVAozWTZLsDRp9t8Z/WYk= github.com/aws/aws-sdk-go-v2/service/kms v1.45.6/go.mod h1:FKXkHzw1fJZtg1P1qoAIiwen5thz/cDRTTDCIu8ljxc=
github.com/aws/aws-sdk-go-v2/service/lambda v1.70.1 h1:EabaKQAptxXAeSL0sXKqfupPe/CpH965wqoloUK0aMM= github.com/aws/aws-sdk-go-v2/service/lambda v1.77.6 h1:bU48NwA1e9jFkng1qYUVQjdJFEIv0oxhDO/Zz57M5IU=
github.com/aws/aws-sdk-go-v2/service/lambda v1.70.1/go.mod h1:c27kk10S36lBYgbG1jR3opn4OAS5Y/4wjJa1GiHK/X4= github.com/aws/aws-sdk-go-v2/service/lambda v1.77.6/go.mod h1:LFNm6TvaFI2Li7U18hJB++k+qH5nK3TveIFD7x9TFHc=
github.com/aws/aws-sdk-go-v2/service/rds v1.94.1 h1:OxrMHbabEdgwKLdMYvnHJju4XFyemN+rknceKU3lyvE= github.com/aws/aws-sdk-go-v2/service/rds v1.108.0 h1:YjrOsnMMAv01zkaBxbGzEm2gy4/mrFfSiIlbYLAf8ZQ=
github.com/aws/aws-sdk-go-v2/service/rds v1.94.1/go.mod h1:CXiHj5rVyQ5Q3zNSoYzwaJfWm8IGDweyyCGfO8ei5fQ= github.com/aws/aws-sdk-go-v2/service/rds v1.108.0/go.mod h1:VOBL5tbhS7AF0m5YpfwLuRBpb5QVp4EWSPizUr/D6iE=
github.com/aws/aws-sdk-go-v2/service/route53 v1.49.1 h1:krDhGq5RpSgpfPB9riTYLLSoCB8bNBhtdva6t1HDEWc= github.com/aws/aws-sdk-go-v2/service/route53 v1.58.4 h1:KycXrohD5OxAZ5h02YechO2gevvoHfAPAaJM5l8zqb0=
github.com/aws/aws-sdk-go-v2/service/route53 v1.49.1/go.mod h1:kGYOjvTa0Vw0qxrqrOLut1vMnui6qLxqv/SX3vYeM8Y= github.com/aws/aws-sdk-go-v2/service/route53 v1.58.4/go.mod h1:xNLZLn4SusktBQ5moqUOgiDKGz3a7vHwF4W0KD+WBPc=
github.com/aws/aws-sdk-go-v2/service/s3 v1.78.1 h1:1M0gSbyP6q06gl3384wpoKPaH9G16NPqZFieEhLboSU= github.com/aws/aws-sdk-go-v2/service/s3 v1.88.3 h1:P18I4ipbk+b/3dZNq5YYh+Hq6XC0vp5RWkLp1tJldDA=
github.com/aws/aws-sdk-go-v2/service/s3 v1.78.1/go.mod h1:4qzsZSzB/KiX2EzDjs9D7A8rI/WGJxZceVJIHqtJjIU= github.com/aws/aws-sdk-go-v2/service/s3 v1.88.3/go.mod h1:Rm3gw2Jov6e6kDuamDvyIlZJDMYk97VeCZ82wz/mVZ0=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.2 h1:vlYXbindmagyVA3RS2SPd47eKZ00GZZQcr+etTviHtc= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.39.6 h1:9PWl450XOG+m5lKv+qg5BXso1eLxpsZLqq7VPug5km0=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.2/go.mod h1:yGhDiLKguA3iFJYxbrQkQiNzuy+ddxesSZYWVeeEH5Q= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.39.6/go.mod h1:hwt7auGsDcaNQ8pzLgE2kCNyIWouYlAKSjuUu5Dqr7I=
github.com/aws/aws-sdk-go-v2/service/sns v1.34.2 h1:PajtbJ/5bEo6iUAIGMYnK8ljqg2F1h4mMCGh1acjN30= github.com/aws/aws-sdk-go-v2/service/sns v1.38.5 h1:c0hINjMfDQvQLJJxfNNcIaLYVLC7E0W2zOQOVVKLnnU=
github.com/aws/aws-sdk-go-v2/service/sns v1.34.2/go.mod h1:PJtxxMdj747j8DeZENRTTYAz/lx/pADn/U0k7YNNiUY= github.com/aws/aws-sdk-go-v2/service/sns v1.38.5/go.mod h1:E427ZzdOMWh/4KtD48AGfbWLX14iyw9URVOdIwtv80o=
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.1 h1:ZtgZeMPJH8+/vNs9vJFFLI0QEzYbcN0p7x1/FFwyROc= github.com/aws/aws-sdk-go-v2/service/sqs v1.42.8 h1:cWiY+//XL5QOYKJyf4Pvt+oE/5wSIi095+bS+ME2lGw=
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.1/go.mod h1:Bar4MrRxeqdn6XIh8JGfiXuFRmyrrsZNTJotxEJmWW0= github.com/aws/aws-sdk-go-v2/service/sqs v1.42.8/go.mod h1:sLvnKf0p0sMQ33nkJGP2NpYyWHMojpL0O9neiCGc9lc=
github.com/aws/aws-sdk-go-v2/service/ssm v1.57.2 h1:3//q1r7gW/kpiWiPfFILw+N81rangyyMJV6vrznFyvw= github.com/aws/aws-sdk-go-v2/service/ssm v1.65.1 h1:TFg6XiS7EsHN0/jpV3eVNczZi/sPIVP5jxIs+euIESQ=
github.com/aws/aws-sdk-go-v2/service/ssm v1.57.2/go.mod h1:PUWUl5MDiYNQkUHN9Pyd9kgtA/YhbxnSnHP+yQqzrM8= github.com/aws/aws-sdk-go-v2/service/ssm v1.65.1/go.mod h1:OIezd9K0sM/64DDP4kXx/i0NdgXu6R5KE6SCsIPJsjc=
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 h1:8JdC7Gr9NROg1Rusk25IcZeTO59zLxsKgE0gkh5O6h0= github.com/aws/aws-sdk-go-v2/service/sso v1.29.6 h1:A1oRkiSQOWstGh61y4Wc/yQ04sqrQZr1Si/oAXj20/s=
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI= github.com/aws/aws-sdk-go-v2/service/sso v1.29.6/go.mod h1:5PfYspyCU5Vw1wNPsxi15LZovOnULudOQuVxphSflQA=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 h1:KwuLovgQPcdjNMfFt9OhUd9a2OwcOKhxfvF4glTzLuA= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.1 h1:5fm5RTONng73/QA73LhCNR7UT9RpFH3hR6HWL6bIgVY=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.1/go.mod h1:xBEjWD13h+6nq+z4AkqSfSvqRKFgDIQeaMguAJndOWo=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 h1:PZV5W8yk4OtH1JAuhV2PXwwO9v5G5Aoj+eMCn4T+1Kc= github.com/aws/aws-sdk-go-v2/service/sts v1.38.6 h1:p3jIvqYwUZgu/XYeI48bJxOhvm47hZb5HUQ0tn6Q9kA=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4= github.com/aws/aws-sdk-go-v2/service/sts v1.38.6/go.mod h1:WtKK+ppze5yKPkZ0XwqIVWD4beCwv056ZbPQNoeHqM8=
github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k= github.com/aws/smithy-go v1.23.0 h1:8n6I3gXzWJB2DxBDnfxgBaSX6oe0d/t10qGz7OKqMCE=
github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/aws/smithy-go v1.23.0/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/boombuler/barcode v1.0.2 h1:79yrbttoZrLGkL/oOI8hBrUKucwOL0oOjUgEguGMcJ4= github.com/boombuler/barcode v1.1.0 h1:ChaYjBR63fr4LFyGn8E8nt7dBSt3MiU3zMOZqFvVkHo=
github.com/boombuler/barcode v1.0.2/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.1.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bradleyfalzon/ghinstallation/v2 v2.14.0 h1:0D4vKCHOvYrDU8u61TnE2JfNT4VRrBLphmxtqazTO+M= github.com/bradleyfalzon/ghinstallation/v2 v2.17.0 h1:SmbUK/GxpAspRjSQbB6ARvH+ArzlNzTtHydNyXUQ6zg=
github.com/bradleyfalzon/ghinstallation/v2 v2.14.0/go.mod h1:LOVmdZYVZ8jqdr4n9wWm1ocDiMz9IfMGfRkaYC1a52A= github.com/bradleyfalzon/ghinstallation/v2 v2.17.0/go.mod h1:vuD/xvJT9Y+ZVZRv4HQ42cMyPFIYqpc7AbB4Gvt/DlY=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8= github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
@@ -126,35 +126,65 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE=
github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc=
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU=
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.25.1 h1:6uwVsx+/OuvFVPqfQmOOPsqTcm5/GkBhNwLqIR916n8=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-openapi/swag v0.25.1/go.mod h1:bzONdGlT0fkStgGPd3bhZf1MnuPkf2YAys6h+jZipOo=
github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo= github.com/go-openapi/swag/cmdutils v0.25.1 h1:nDke3nAFDArAa631aitksFGj2omusks88GF1VwdYqPY=
github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw= github.com/go-openapi/swag/cmdutils v0.25.1/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
github.com/go-openapi/swag/conv v0.25.1 h1:+9o8YUg6QuqqBM5X6rYL/p1dpWeZRhoIt9x7CCP+he0=
github.com/go-openapi/swag/conv v0.25.1/go.mod h1:Z1mFEGPfyIKPu0806khI3zF+/EUXde+fdeksUl2NiDs=
github.com/go-openapi/swag/fileutils v0.25.1 h1:rSRXapjQequt7kqalKXdcpIegIShhTPXx7yw0kek2uU=
github.com/go-openapi/swag/fileutils v0.25.1/go.mod h1:+NXtt5xNZZqmpIpjqcujqojGFek9/w55b3ecmOdtg8M=
github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU=
github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo=
github.com/go-openapi/swag/jsonutils v0.25.1 h1:AihLHaD0brrkJoMqEZOBNzTLnk81Kg9cWr+SPtxtgl8=
github.com/go-openapi/swag/jsonutils v0.25.1/go.mod h1:JpEkAjxQXpiaHmRO04N1zE4qbUEg3b7Udll7AMGTNOo=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1 h1:DSQGcdB6G0N9c/KhtpYc71PzzGEIc/fZ1no35x4/XBY=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1/go.mod h1:kjmweouyPwRUEYMSrbAidoLMGeJ5p6zdHi9BgZiqmsg=
github.com/go-openapi/swag/loading v0.25.1 h1:6OruqzjWoJyanZOim58iG2vj934TysYVptyaoXS24kw=
github.com/go-openapi/swag/loading v0.25.1/go.mod h1:xoIe2EG32NOYYbqxvXgPzne989bWvSNoWoyQVWEZicc=
github.com/go-openapi/swag/mangling v0.25.1 h1:XzILnLzhZPZNtmxKaz/2xIGPQsBsvmCjrJOWGNz/ync=
github.com/go-openapi/swag/mangling v0.25.1/go.mod h1:CdiMQ6pnfAgyQGSOIYnZkXvqhnnwOn997uXZMAd/7mQ=
github.com/go-openapi/swag/netutils v0.25.1 h1:2wFLYahe40tDUHfKT1GRC4rfa5T1B4GWZ+msEFA4Fl4=
github.com/go-openapi/swag/netutils v0.25.1/go.mod h1:CAkkvqnUJX8NV96tNhEQvKz8SQo2KF0f7LleiJwIeRE=
github.com/go-openapi/swag/stringutils v0.25.1 h1:Xasqgjvk30eUe8VKdmyzKtjkVjeiXx1Iz0zDfMNpPbw=
github.com/go-openapi/swag/stringutils v0.25.1/go.mod h1:JLdSAq5169HaiDUbTvArA2yQxmgn4D6h4A+4HqVvAYg=
github.com/go-openapi/swag/typeutils v0.25.1 h1:rD/9HsEQieewNt6/k+JBwkxuAHktFtH3I3ysiFZqukA=
github.com/go-openapi/swag/typeutils v0.25.1/go.mod h1:9McMC/oCdS4BKwk2shEB7x17P6HmMmA6dQRtAkSnNb8=
github.com/go-openapi/swag/yamlutils v0.25.1 h1:mry5ez8joJwzvMbaTGLhw8pXUnhDK91oSJLDPF1bmGk=
github.com/go-openapi/swag/yamlutils v0.25.1/go.mod h1:cm9ywbzncy3y6uPm/97ysW8+wZ09qsks+9RS8fLWKqg=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -162,52 +192,49 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/gonvenience/bunt v1.4.2 h1:nTgkFZsw38SIJKABhLj8aXj2rqion9Zo1so/EBkbFBY=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/gonvenience/bunt v1.4.2/go.mod h1:WjyEO2rSYR+OLZg67Ucl+gjdXPs8GpFl63SCA02XDyI=
github.com/gonvenience/bunt v1.4.0 h1:xRAANCgSmQwGoHIyWg80yFgomTiblBayUUSBBPjDHK4= github.com/gonvenience/idem v0.0.2 h1:jWHknjPfSbiWgYKre9wB2FhMgVLd1RWXCXzVq+7VIWg=
github.com/gonvenience/bunt v1.4.0/go.mod h1:J9S2b1ZmUKdvybPxhq0hhrIvAwxcUXJjerudNa2Fhdw= github.com/gonvenience/idem v0.0.2/go.mod h1:0Xv1MpnNL40+dsyOxaJFa7L8ekeTRr63WaWXpiWLFFM=
github.com/gonvenience/idem v0.0.1 h1:SMqv4DI2ErBOsoohVyqBOeCCLrag6N7iClwJbmZBTYo= github.com/gonvenience/neat v1.3.16 h1:Vb0iCkSHGWaA+ry69RY3HpQ6Ooo6o/g2wjI80db8DjI=
github.com/gonvenience/idem v0.0.1/go.mod h1:Br/o1pWtrbiPTuZrn7nPV6TJQL0qbaoGNmJZ8+A7MyU= github.com/gonvenience/neat v1.3.16/go.mod h1:sLxdQNNluxbpROxTTHs3XBSJX8fwFX5toEULUy74ODA=
github.com/gonvenience/neat v1.3.15 h1:qRMZzVP/HtLsQLKZGW8NGZIXdH1TMHsPjMJe2tvzDqk= github.com/gonvenience/term v1.0.4 h1:qkCGfmUtpzs9W4jWgNijaGF6dg3oSIh+kZCzT5cPNZY=
github.com/gonvenience/neat v1.3.15/go.mod h1:TMdu+WVzfRU46GvcMAYALdvlWxiUxP1yqpZn/hKUhP8= github.com/gonvenience/term v1.0.4/go.mod h1:OzNdQC5NVBou9AifaHd1QG6EP8iDdpaT7GFm1bVgslg=
github.com/gonvenience/term v1.0.3 h1:8MleXhMCCzLeWXmiEA/IQ/ZoaKBL5mHrmRVJsU1nWtI= github.com/gonvenience/text v1.0.9 h1:U29BxT3NZnNPcfiEnAwt6yHXe38fQs2Q+WTqs1X+atI=
github.com/gonvenience/term v1.0.3/go.mod h1:VJaaP9pwAlSYSlyv1O7schD/GZJRg8HUmiulQmGOABw= github.com/gonvenience/text v1.0.9/go.mod h1:JQF1ifXNRaa66jnPLqoITA+y8WATlG0eJzFC9ElJS3s=
github.com/gonvenience/text v1.0.8 h1:yIxiyXnKDqfe8JDPldZYaeYHU19XOPNN5VFPETCyNI0= github.com/gonvenience/ytbx v1.4.7 h1:3wJ7EOfdv3Lg+h0mzKo7f8d1zMY1EJtVzzYrA3UhjHQ=
github.com/gonvenience/text v1.0.8/go.mod h1:pUCCo022AtxoY2LJfJPNBzBc0oC2/Vp+tx8UaIc5RR8= github.com/gonvenience/ytbx v1.4.7/go.mod h1:ZmAU727eOTYeC4aUJuqyb9vogNAN7NiSKfw6Aoxbqys=
github.com/gonvenience/ytbx v1.4.6 h1:sXf0/kCBEAbrOBsj8aRpDvdRRkVl/3UZmNLKy4oFY+I=
github.com/gonvenience/ytbx v1.4.6/go.mod h1:LHhrtuB5ghXlU+l1NJJR3Wt1ZnpbQScqyshpXisYplE=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-github/v52 v52.0.0 h1:uyGWOY+jMQ8GVGSX8dkSwCzlehU3WfdxQ7GweO/JP7M= github.com/google/go-github/v52 v52.0.0 h1:uyGWOY+jMQ8GVGSX8dkSwCzlehU3WfdxQ7GweO/JP7M=
github.com/google/go-github/v52 v52.0.0/go.mod h1:WJV6VEEUPuMo5pXqqa2ZCZEdbQqua4zAk2MZTIo+m+4= github.com/google/go-github/v52 v52.0.0/go.mod h1:WJV6VEEUPuMo5pXqqa2ZCZEdbQqua4zAk2MZTIo+m+4=
github.com/google/go-github/v69 v69.2.0 h1:wR+Wi/fN2zdUx9YxSmYE0ktiX9IAR/BeePzeaUUbEHE= github.com/google/go-github/v75 v75.0.0 h1:k7q8Bvg+W5KxRl9Tjq16a9XEgVY1pwuiG5sIL7435Ic=
github.com/google/go-github/v69 v69.2.0/go.mod h1:xne4jymxLR6Uj9b7J7PyTpkMYstEMMwGZa0Aehh1azM= github.com/google/go-github/v75 v75.0.0/go.mod h1:H3LUJEA1TCrzuUqtdAQniBNwuKiQIqdGKgBo1/M/uqI=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7 h1:+J3r2e8+RsmN3vKfo75g0YSY61ms37qzPglu4p0sGro= github.com/google/pprof v0.0.0-20251002213607-436353cc1ee6 h1:/WHh/1k4thM/w+PAZEIiZK9NwCMFahw5tUzKUCnUtds=
github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/pprof v0.0.0-20251002213607-436353cc1ee6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/gruntwork-io/go-commons v0.17.2 h1:14dsCJ7M5Vv2X3BIPKeG9Kdy6vTMGhM8L4WZazxfTuY= github.com/gruntwork-io/go-commons v0.17.2 h1:14dsCJ7M5Vv2X3BIPKeG9Kdy6vTMGhM8L4WZazxfTuY=
github.com/gruntwork-io/go-commons v0.17.2/go.mod h1:zs7Q2AbUKuTarBPy19CIxJVUX/rBamfW8IwuWKniWkE= github.com/gruntwork-io/go-commons v0.17.2/go.mod h1:zs7Q2AbUKuTarBPy19CIxJVUX/rBamfW8IwuWKniWkE=
github.com/gruntwork-io/terratest v0.48.2 h1:+VwfODchq8jxZZWD+s8gBlhD1z6/C4bFLNrhpm9ONrs= github.com/gruntwork-io/terratest v0.54.0 h1:JOVATYDpU0NAPbEkgYUP50BR2m45UGiR4dbs20sKzck=
github.com/gruntwork-io/terratest v0.48.2/go.mod h1:Y5ETyD4ZQ2MZhasPno272fWuCpKwvTPYDi8Y0tIMqTE= github.com/gruntwork-io/terratest v0.54.0/go.mod h1:QvwQWZMTJmJB4E0d1Uc18quQm7+X53liKKp+fJSuaKA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -217,27 +244,27 @@ github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB1
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=
github.com/homeport/dyff v1.10.1 h1:D5Ydf++licJ1WblIGh8oSw2p1oBg9P6M8wAJcKuyjX0= github.com/homeport/dyff v1.10.2 h1:XyB+D0KVwjbUFTZYIkvPtsImwkfh+ObH2CEdEHTqdr4=
github.com/homeport/dyff v1.10.1/go.mod h1:RvQm7AT4Sx0RI8C5/xCc+6QvKuSjc4aX53qarA2PnZU= github.com/homeport/dyff v1.10.2/go.mod h1:0kIjL/JOGaXigzrLY6kcl5esSStbAa99r6GzEvr7lrs=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
@@ -251,10 +278,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3 h1:BXxTozrOU8zgC5dkpn3J6NTRdoP+hjok/e+ACr4Hibk= github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3 h1:BXxTozrOU8zgC5dkpn3J6NTRdoP+hjok/e+ACr4Hibk=
github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3/go.mod h1:x1uk6vxTiVuNt6S5R2UYgdhpj3oKojXvOXauHZ7dEnI= github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3/go.mod h1:x1uk6vxTiVuNt6S5R2UYgdhpj3oKojXvOXauHZ7dEnI=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -263,6 +290,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-zglob v0.0.6 h1:mP8RnmCgho4oaUYDIDn6GNxYk+qJGUs8fJLn+twYj2A= github.com/mattn/go-zglob v0.0.6 h1:mP8RnmCgho4oaUYDIDn6GNxYk+qJGUs8fJLn+twYj2A=
github.com/mattn/go-zglob v0.0.6/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY= github.com/mattn/go-zglob v0.0.6/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY=
github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE=
github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
@@ -274,8 +303,9 @@ github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVO
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
@@ -286,12 +316,12 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns=
github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU= github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -299,26 +329,24 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
@@ -326,53 +354,67 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/teambition/rrule-go v1.8.2 h1:lIjpjvWTj9fFUZCmuoVDrKVOtdiyzbzc93qTmRVe/J8= github.com/teambition/rrule-go v1.8.2 h1:lIjpjvWTj9fFUZCmuoVDrKVOtdiyzbzc93qTmRVe/J8=
github.com/teambition/rrule-go v1.8.2/go.mod h1:Ieq5AbrKGciP1V//Wq8ktsTXwSwJHDD5mD/wLBGl3p4= github.com/teambition/rrule-go v1.8.2/go.mod h1:Ieq5AbrKGciP1V//Wq8ktsTXwSwJHDD5mD/wLBGl3p4=
github.com/texttheater/golang-levenshtein v1.0.1 h1:+cRNoVrfiwufQPhoMzB6N0Yf/Mqajr6t1lOv8GyGE2U= github.com/texttheater/golang-levenshtein v1.0.1 h1:+cRNoVrfiwufQPhoMzB6N0Yf/Mqajr6t1lOv8GyGE2U=
github.com/texttheater/golang-levenshtein v1.0.1/go.mod h1:PYAKrbF5sAiq9wd+H82hs7gNaen0CplQ9uvm6+enD/8= github.com/texttheater/golang-levenshtein v1.0.1/go.mod h1:PYAKrbF5sAiq9wd+H82hs7gNaen0CplQ9uvm6+enD/8=
github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=
github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=
github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 h1:JwtAtbp7r/7QSyGz8mKUbYJBg2+6Cd7OjM8o/GNOcVo= github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 h1:JwtAtbp7r/7QSyGz8mKUbYJBg2+6Cd7OjM8o/GNOcVo=
github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74/go.mod h1:RmMWU37GKR2s6pgrIEB4ixgpVCt/cf7dnJv3fuH1J1c= github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74/go.mod h1:RmMWU37GKR2s6pgrIEB4ixgpVCt/cf7dnJv3fuH1J1c=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 h1:TQwNpfvNkxAVlItJf6Cr5JTsVZoC/Sj7K3OZv2Pc14A=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo=
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -384,23 +426,23 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -413,14 +455,14 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
@@ -433,28 +475,27 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY=
k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw=
k8s.io/apiextensions-apiserver v0.32.2 h1:2YMk285jWMk2188V2AERy5yDwBYrjgWYggscghPCvV4= k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI=
k8s.io/apiextensions-apiserver v0.32.2/go.mod h1:GPwf8sph7YlJT3H6aKUWtd0E+oyShk/YHWQHf/OOgCA= k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4=
k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M=
k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250304201544-e5f78fe3ede9 h1:t0huyHnz6HsokckRxAF1bY0cqPFwzINKCL7yltEjZQc= k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
k8s.io/kube-openapi v0.0.0-20250304201544-e5f78fe3ede9/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU= sigs.k8s.io/controller-runtime v0.22.4 h1:GEjV7KV3TY8e+tJ2LCTxUTanW4z/FmNB7l327UfMq9A=
sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= sigs.k8s.io/controller-runtime v0.22.4/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=

93
hack/e2e-test.sh Executable file
View File

@@ -0,0 +1,93 @@
#!/bin/bash
DIR="$(dirname "${BASH_SOURCE[0]}")"
DIR="$(realpath "${DIR}")"
TEST_DIR="$(realpath "${DIR}/../test/actions.github.com")"
export PLATFORMS="linux/amd64"
TARGETS=()
function set_targets() {
local cases
cases="$(find "${TEST_DIR}" -name '*.test.sh' | sed "s#^${TEST_DIR}/##g")"
mapfile -t TARGETS < <(echo "${cases}")
echo "${TARGETS[@]}"
}
function env_test() {
if [[ -z "${GITHUB_TOKEN}" ]]; then
echo "Error: GITHUB_TOKEN is not set"
exit 1
fi
if [[ -z "${TARGET_ORG}" ]]; then
echo "Error: TARGET_ORG is not set"
exit 1
fi
if [[ -z "${TARGET_REPO}" ]]; then
echo "Error: TARGET_REPO is not set"
exit 1
fi
}
function usage() {
echo "Usage: $0 [test_name]"
echo " test_name: the name of the test to run"
echo " if not specified, all tests will be run"
echo " test_name should be the name of the test file without the .test.sh suffix"
echo ""
exit 1
}
function main() {
local failed=()
env_test
if [[ -z "${1}" ]]; then
echo "Running all tests"
set_targets
elif [[ -f "${TEST_DIR}/${1}.test.sh" ]]; then
echo "Running test ${1}"
TARGETS=("${1}.test.sh")
else
usage
fi
for target in "${TARGETS[@]}"; do
echo "============================================================"
test="${TEST_DIR}/${target}"
if [[ ! -x "${test}" ]]; then
echo "Error: test ${test} is not executable or not found"
failed+=("${test}")
continue
fi
echo "Running test ${target}"
if ! "${test}"; then
failed+=("${target}")
echo "---------------------------------"
echo "FAILED: ${target}"
else
echo "---------------------------------"
echo "PASSED: ${target}"
fi
echo "============================================================"
done
if [[ "${#failed[@]}" -gt 0 ]]; then
echo "Failed tests:"
for fail in "${failed[@]}"; do
echo " ${fail}"
done
exit 1
fi
}
main "$@"

View File

@@ -124,7 +124,7 @@ func main() {
flag.StringVar(&leaderElectionId, "leader-election-id", "actions-runner-controller", "Controller id for leader election.") flag.StringVar(&leaderElectionId, "leader-election-id", "actions-runner-controller", "Controller id for leader election.")
flag.StringVar(&runnerPodDefaults.RunnerImage, "runner-image", defaultRunnerImage, "The image name of self-hosted runner container to use by default if one isn't defined in yaml.") flag.StringVar(&runnerPodDefaults.RunnerImage, "runner-image", defaultRunnerImage, "The image name of self-hosted runner container to use by default if one isn't defined in yaml.")
flag.StringVar(&runnerPodDefaults.DockerImage, "docker-image", defaultDockerImage, "The image name of docker sidecar container to use by default if one isn't defined in yaml.") flag.StringVar(&runnerPodDefaults.DockerImage, "docker-image", defaultDockerImage, "The image name of docker sidecar container to use by default if one isn't defined in yaml.")
flag.StringVar(&runnerPodDefaults.DockerGID, "docker-gid", defaultDockerGID, "The default GID of docker group in the docker sidecar container. Use 1001 for dockerd sidecars of Ubuntu 20.04 runners 121 for Ubuntu 22.04.") flag.StringVar(&runnerPodDefaults.DockerGID, "docker-gid", defaultDockerGID, "The default GID of docker group in the docker sidecar container. Use 1001 for dockerd sidecars of Ubuntu 20.04 runners 121 for Ubuntu 22.04 and 24.04.")
flag.Var(&runnerImagePullSecrets, "runner-image-pull-secret", "The default image-pull secret name for self-hosted runner container.") flag.Var(&runnerImagePullSecrets, "runner-image-pull-secret", "The default image-pull secret name for self-hosted runner container.")
flag.StringVar(&runnerPodDefaults.DockerRegistryMirror, "docker-registry-mirror", "", "The default Docker Registry Mirror used by runners.") flag.StringVar(&runnerPodDefaults.DockerRegistryMirror, "docker-registry-mirror", "", "The default Docker Registry Mirror used by runners.")
flag.StringVar(&c.Token, "github-token", c.Token, "The personal access token of GitHub.") flag.StringVar(&c.Token, "github-token", c.Token, "The personal access token of GitHub.")

View File

@@ -6,9 +6,9 @@ DIND_ROOTLESS_RUNNER_NAME ?= ${DOCKER_USER}/actions-runner-dind-rootless
OS_IMAGE ?= ubuntu-22.04 OS_IMAGE ?= ubuntu-22.04
TARGETPLATFORM ?= $(shell arch) TARGETPLATFORM ?= $(shell arch)
RUNNER_VERSION ?= 2.325.0 RUNNER_VERSION ?= 2.330.0
RUNNER_CONTAINER_HOOKS_VERSION ?= 0.7.0 RUNNER_CONTAINER_HOOKS_VERSION ?= 0.8.0
DOCKER_VERSION ?= 24.0.7 DOCKER_VERSION ?= 28.0.4
# default list of platforms for which multiarch image is built # default list of platforms for which multiarch image is built
ifeq (${PLATFORMS}, ) ifeq (${PLATFORMS}, )

View File

@@ -1,2 +1,2 @@
RUNNER_VERSION=2.325.0 RUNNER_VERSION=2.330.0
RUNNER_CONTAINER_HOOKS_VERSION=0.7.0 RUNNER_CONTAINER_HOOKS_VERSION=0.8.0

View File

@@ -5,7 +5,7 @@ ARG RUNNER_VERSION
ARG RUNNER_CONTAINER_HOOKS_VERSION ARG RUNNER_CONTAINER_HOOKS_VERSION
# Docker and Docker Compose arguments # Docker and Docker Compose arguments
ENV CHANNEL=stable ENV CHANNEL=stable
ARG DOCKER_COMPOSE_VERSION=v2.23.0 ARG DOCKER_COMPOSE_VERSION=v2.38.2
ARG DUMB_INIT_VERSION=1.2.5 ARG DUMB_INIT_VERSION=1.2.5
# Other arguments # Other arguments

View File

@@ -5,7 +5,7 @@ ARG RUNNER_VERSION
ARG RUNNER_CONTAINER_HOOKS_VERSION ARG RUNNER_CONTAINER_HOOKS_VERSION
# Docker and Docker Compose arguments # Docker and Docker Compose arguments
ENV CHANNEL=stable ENV CHANNEL=stable
ARG DOCKER_COMPOSE_VERSION=v2.23.0 ARG DOCKER_COMPOSE_VERSION=v2.38.2
ARG DUMB_INIT_VERSION=1.2.5 ARG DUMB_INIT_VERSION=1.2.5
ARG RUNNER_USER_UID=1001 ARG RUNNER_USER_UID=1001

View File

@@ -0,0 +1,135 @@
FROM ubuntu:24.04
ARG TARGETPLATFORM
ARG RUNNER_VERSION
ARG RUNNER_CONTAINER_HOOKS_VERSION
# Docker and Docker Compose arguments
ENV CHANNEL=stable
ARG DOCKER_COMPOSE_VERSION=v2.38.2
ARG DUMB_INIT_VERSION=1.2.5
ARG RUNNER_USER_UID=1001
# Other arguments
ARG DEBUG=false
RUN test -n "$TARGETPLATFORM" || (echo "TARGETPLATFORM must be set" && false)
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y \
&& apt-get install -y software-properties-common \
&& add-apt-repository -y ppa:git-core/ppa \
&& apt-get update -y \
&& apt-get install -y --no-install-recommends \
curl \
ca-certificates \
git \
iproute2 \
iptables \
jq \
sudo \
uidmap \
unzip \
zip \
fuse-overlayfs \
&& rm -rf /var/lib/apt/lists/*
# Download latest git-lfs version
RUN curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \
apt-get install -y --no-install-recommends git-lfs
# Runner user
RUN adduser --disabled-password --gecos "" --uid $RUNNER_USER_UID runner
ENV HOME=/home/runner
# Set-up subuid and subgid so that "--userns-remap=default" works
RUN set -eux; \
addgroup --system dockremap; \
adduser --system --ingroup dockremap dockremap; \
echo 'dockremap:165536:65536' >> /etc/subuid; \
echo 'dockremap:165536:65536' >> /etc/subgid
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x86_64 ; fi \
&& curl -fLo /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_${ARCH} \
&& chmod +x /usr/bin/dumb-init
ENV RUNNER_ASSETS_DIR=/runnertmp
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x64 ; fi \
&& mkdir -p "$RUNNER_ASSETS_DIR" \
&& cd "$RUNNER_ASSETS_DIR" \
&& curl -fLo runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${ARCH}-${RUNNER_VERSION}.tar.gz \
&& tar xzf ./runner.tar.gz \
&& rm runner.tar.gz \
&& ./bin/installdependencies.sh \
&& mv ./externals ./externalstmp \
# libyaml-dev is required for ruby/setup-ruby action.
# It is installed after installdependencies.sh and before removing /var/lib/apt/lists
# to avoid rerunning apt-update on its own.
&& apt-get install -y libyaml-dev \
&& rm -rf /var/lib/apt/lists/*
ENV RUNNER_TOOL_CACHE=/opt/hostedtoolcache
RUN mkdir /opt/hostedtoolcache \
&& chgrp runner /opt/hostedtoolcache \
&& chmod g+rwx /opt/hostedtoolcache
RUN cd "$RUNNER_ASSETS_DIR" \
&& curl -fLo runner-container-hooks.zip https://github.com/actions/runner-container-hooks/releases/download/v${RUNNER_CONTAINER_HOOKS_VERSION}/actions-runner-hooks-k8s-${RUNNER_CONTAINER_HOOKS_VERSION}.zip \
&& unzip ./runner-container-hooks.zip -d ./k8s \
&& rm -f runner-container-hooks.zip
# Make the rootless runner directory executable
RUN mkdir /run/user/1000 \
&& chown runner:runner /run/user/1000 \
&& chmod a+x /run/user/1000
# We place the scripts in `/usr/bin` so that users who extend this image can
# override them with scripts of the same name placed in `/usr/local/bin`.
COPY entrypoint-dind-rootless.sh startup.sh logger.sh graceful-stop.sh update-status /usr/bin/
RUN chmod +x /usr/bin/entrypoint-dind-rootless.sh /usr/bin/startup.sh
# Copy the docker shim which propagates the docker MTU to underlying networks
# to replace the docker binary in the PATH.
COPY docker-shim.sh /usr/local/bin/docker
# Configure hooks folder structure.
COPY hooks /etc/arc/hooks/
# Add the Python "User Script Directory" to the PATH
ENV PATH="${PATH}:${HOME}/.local/bin:/home/runner/bin"
ENV ImageOS=ubuntu22
ENV DOCKER_HOST=unix:///run/user/1000/docker.sock
ENV XDG_RUNTIME_DIR=/run/user/1000
RUN echo "PATH=${PATH}" > /etc/environment \
&& echo "ImageOS=${ImageOS}" >> /etc/environment \
&& echo "DOCKER_HOST=${DOCKER_HOST}" >> /etc/environment \
&& echo "XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR}" >> /etc/environment
# No group definition, as that makes it harder to run docker.
USER runner
# This will install docker under $HOME/bin according to the content of the script
RUN export SKIP_IPTABLES=1 \
&& curl -fsSL https://get.docker.com/rootless | sh \
&& /home/runner/bin/docker -v
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x86_64 ; fi \
&& mkdir -p /home/runner/.docker/cli-plugins \
&& curl -fLo /home/runner/.docker/cli-plugins/docker-compose https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-${ARCH} \
&& chmod +x /home/runner/.docker/cli-plugins/docker-compose \
&& ln -s /home/runner/.docker/cli-plugins/docker-compose /home/runner/bin/docker-compose \
&& which docker-compose \
&& docker compose version
# Create folder structure here to avoid permission issues
# when mounting the daemon.json file from a configmap.
RUN mkdir -p /home/runner/.config/docker
ENTRYPOINT ["/bin/bash", "-c"]
CMD ["entrypoint-dind-rootless.sh"]

View File

@@ -5,8 +5,8 @@ ARG RUNNER_VERSION
ARG RUNNER_CONTAINER_HOOKS_VERSION ARG RUNNER_CONTAINER_HOOKS_VERSION
# Docker and Docker Compose arguments # Docker and Docker Compose arguments
ARG CHANNEL=stable ARG CHANNEL=stable
ARG DOCKER_VERSION=24.0.7 ARG DOCKER_VERSION=28.0.4
ARG DOCKER_COMPOSE_VERSION=v2.23.0 ARG DOCKER_COMPOSE_VERSION=v2.38.2
ARG DUMB_INIT_VERSION=1.2.5 ARG DUMB_INIT_VERSION=1.2.5
# Use 1001 and 121 for compatibility with GitHub-hosted runners # Use 1001 and 121 for compatibility with GitHub-hosted runners

View File

@@ -5,8 +5,8 @@ ARG RUNNER_VERSION
ARG RUNNER_CONTAINER_HOOKS_VERSION ARG RUNNER_CONTAINER_HOOKS_VERSION
# Docker and Docker Compose arguments # Docker and Docker Compose arguments
ARG CHANNEL=stable ARG CHANNEL=stable
ARG DOCKER_VERSION=24.0.7 ARG DOCKER_VERSION=28.0.4
ARG DOCKER_COMPOSE_VERSION=v2.23.0 ARG DOCKER_COMPOSE_VERSION=v2.38.2
ARG DUMB_INIT_VERSION=1.2.5 ARG DUMB_INIT_VERSION=1.2.5
ARG RUNNER_USER_UID=1001 ARG RUNNER_USER_UID=1001
ARG DOCKER_GROUP_GID=121 ARG DOCKER_GROUP_GID=121

View File

@@ -0,0 +1,120 @@
FROM ubuntu:24.04
ARG TARGETPLATFORM
ARG RUNNER_VERSION
ARG RUNNER_CONTAINER_HOOKS_VERSION
# Docker and Docker Compose arguments
ARG CHANNEL=stable
ARG DOCKER_VERSION=28.0.4
ARG DOCKER_COMPOSE_VERSION=v2.38.2
ARG DUMB_INIT_VERSION=1.2.5
ARG RUNNER_USER_UID=1001
ARG DOCKER_GROUP_GID=121
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y \
&& apt-get install -y software-properties-common \
&& add-apt-repository -y ppa:git-core/ppa \
&& apt-get update -y \
&& apt-get install -y --no-install-recommends \
curl \
ca-certificates \
git \
iptables \
jq \
software-properties-common \
sudo \
unzip \
zip \
&& rm -rf /var/lib/apt/lists/*
# Download latest git-lfs version
RUN curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \
apt-get install -y --no-install-recommends git-lfs
# Runner user
RUN adduser --disabled-password --gecos "" --uid $RUNNER_USER_UID runner \
&& groupadd docker --gid $DOCKER_GROUP_GID \
&& usermod -aG sudo runner \
&& usermod -aG docker runner \
&& echo "%sudo ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers \
&& echo "Defaults env_keep += \"DEBIAN_FRONTEND\"" >> /etc/sudoers
ENV HOME=/home/runner
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x86_64 ; fi \
&& curl -fLo /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_${ARCH} \
&& chmod +x /usr/bin/dumb-init
ENV RUNNER_ASSETS_DIR=/runnertmp
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x64 ; fi \
&& mkdir -p "$RUNNER_ASSETS_DIR" \
&& cd "$RUNNER_ASSETS_DIR" \
&& curl -fLo runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${ARCH}-${RUNNER_VERSION}.tar.gz \
&& tar xzf ./runner.tar.gz \
&& rm -f runner.tar.gz \
&& ./bin/installdependencies.sh \
# libyaml-dev is required for ruby/setup-ruby action.
# It is installed after installdependencies.sh and before removing /var/lib/apt/lists
# to avoid rerunning apt-update on its own.
&& apt-get install -y libyaml-dev \
&& rm -rf /var/lib/apt/lists/*
ENV RUNNER_TOOL_CACHE=/opt/hostedtoolcache
RUN mkdir /opt/hostedtoolcache \
&& chgrp docker /opt/hostedtoolcache \
&& chmod g+rwx /opt/hostedtoolcache
RUN cd "$RUNNER_ASSETS_DIR" \
&& curl -fLo runner-container-hooks.zip https://github.com/actions/runner-container-hooks/releases/download/v${RUNNER_CONTAINER_HOOKS_VERSION}/actions-runner-hooks-k8s-${RUNNER_CONTAINER_HOOKS_VERSION}.zip \
&& unzip ./runner-container-hooks.zip -d ./k8s \
&& rm -f runner-container-hooks.zip
RUN set -vx; \
export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x86_64 ; fi \
&& curl -fLo docker.tgz https://download.docker.com/linux/static/${CHANNEL}/${ARCH}/docker-${DOCKER_VERSION}.tgz \
&& tar zxvf docker.tgz \
&& install -o root -g root -m 755 docker/* /usr/bin/ \
&& rm -rf docker docker.tgz
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x86_64 ; fi \
&& mkdir -p /usr/libexec/docker/cli-plugins \
&& curl -fLo /usr/libexec/docker/cli-plugins/docker-compose https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-${ARCH} \
&& chmod +x /usr/libexec/docker/cli-plugins/docker-compose \
&& ln -s /usr/libexec/docker/cli-plugins/docker-compose /usr/bin/docker-compose \
&& which docker-compose \
&& docker compose version
# We place the scripts in `/usr/bin` so that users who extend this image can
# override them with scripts of the same name placed in `/usr/local/bin`.
COPY entrypoint-dind.sh startup.sh logger.sh wait.sh graceful-stop.sh update-status /usr/bin/
RUN chmod +x /usr/bin/entrypoint-dind.sh /usr/bin/startup.sh
# Copy the docker shim which propagates the docker MTU to underlying networks
# to replace the docker binary in the PATH.
COPY docker-shim.sh /usr/local/bin/docker
# Configure hooks folder structure.
COPY hooks /etc/arc/hooks/
VOLUME /var/lib/docker
# Add the Python "User Script Directory" to the PATH
ENV PATH="${PATH}:${HOME}/.local/bin"
ENV ImageOS=ubuntu24
RUN echo "PATH=${PATH}" > /etc/environment \
&& echo "ImageOS=${ImageOS}" >> /etc/environment
# No group definition, as that makes it harder to run docker.
USER runner
ENTRYPOINT ["/bin/bash", "-c"]
CMD ["entrypoint-dind.sh"]

View File

@@ -5,8 +5,8 @@ ARG RUNNER_VERSION
ARG RUNNER_CONTAINER_HOOKS_VERSION ARG RUNNER_CONTAINER_HOOKS_VERSION
# Docker and Docker Compose arguments # Docker and Docker Compose arguments
ARG CHANNEL=stable ARG CHANNEL=stable
ARG DOCKER_VERSION=24.0.7 ARG DOCKER_VERSION=28.0.4
ARG DOCKER_COMPOSE_VERSION=v2.23.0 ARG DOCKER_COMPOSE_VERSION=v2.38.2
ARG DUMB_INIT_VERSION=1.2.5 ARG DUMB_INIT_VERSION=1.2.5
# Use 1001 and 121 for compatibility with GitHub-hosted runners # Use 1001 and 121 for compatibility with GitHub-hosted runners

View File

@@ -5,8 +5,8 @@ ARG RUNNER_VERSION
ARG RUNNER_CONTAINER_HOOKS_VERSION ARG RUNNER_CONTAINER_HOOKS_VERSION
# Docker and Docker Compose arguments # Docker and Docker Compose arguments
ARG CHANNEL=stable ARG CHANNEL=stable
ARG DOCKER_VERSION=24.0.7 ARG DOCKER_VERSION=28.0.4
ARG DOCKER_COMPOSE_VERSION=v2.23.0 ARG DOCKER_COMPOSE_VERSION=v2.38.2
ARG DUMB_INIT_VERSION=1.2.5 ARG DUMB_INIT_VERSION=1.2.5
ARG RUNNER_USER_UID=1001 ARG RUNNER_USER_UID=1001
ARG DOCKER_GROUP_GID=121 ARG DOCKER_GROUP_GID=121

View File

@@ -0,0 +1,114 @@
FROM ubuntu:24.04
ARG TARGETPLATFORM
ARG RUNNER_VERSION
ARG RUNNER_CONTAINER_HOOKS_VERSION
# Docker and Docker Compose arguments
ARG CHANNEL=stable
ARG DOCKER_VERSION=28.0.4
ARG DOCKER_COMPOSE_VERSION=v2.38.2
ARG DUMB_INIT_VERSION=1.2.5
ARG RUNNER_USER_UID=1001
ARG DOCKER_GROUP_GID=121
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y \
&& apt-get install -y software-properties-common \
&& add-apt-repository -y ppa:git-core/ppa \
&& apt-get update -y \
&& apt-get install -y --no-install-recommends \
curl \
ca-certificates \
git \
jq \
sudo \
unzip \
zip \
&& rm -rf /var/lib/apt/lists/*
# Download latest git-lfs version
RUN curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \
apt-get install -y --no-install-recommends git-lfs
RUN adduser --disabled-password --gecos "" --uid $RUNNER_USER_UID runner \
&& groupadd docker --gid $DOCKER_GROUP_GID \
&& usermod -aG sudo runner \
&& usermod -aG docker runner \
&& echo "%sudo ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers \
&& echo "Defaults env_keep += \"DEBIAN_FRONTEND\"" >> /etc/sudoers
ENV HOME=/home/runner
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x86_64 ; fi \
&& curl -fLo /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_${ARCH} \
&& chmod +x /usr/bin/dumb-init
ENV RUNNER_ASSETS_DIR=/runnertmp
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x64 ; fi \
&& mkdir -p "$RUNNER_ASSETS_DIR" \
&& cd "$RUNNER_ASSETS_DIR" \
&& curl -fLo runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${ARCH}-${RUNNER_VERSION}.tar.gz \
&& tar xzf ./runner.tar.gz \
&& rm runner.tar.gz \
&& ./bin/installdependencies.sh \
&& mv ./externals ./externalstmp \
# libyaml-dev is required for ruby/setup-ruby action.
# It is installed after installdependencies.sh and before removing /var/lib/apt/lists
# to avoid rerunning apt-update on its own.
&& apt-get install -y libyaml-dev \
&& rm -rf /var/lib/apt/lists/*
ENV RUNNER_TOOL_CACHE=/opt/hostedtoolcache
RUN mkdir /opt/hostedtoolcache \
&& chgrp docker /opt/hostedtoolcache \
&& chmod g+rwx /opt/hostedtoolcache
RUN cd "$RUNNER_ASSETS_DIR" \
&& curl -fLo runner-container-hooks.zip https://github.com/actions/runner-container-hooks/releases/download/v${RUNNER_CONTAINER_HOOKS_VERSION}/actions-runner-hooks-k8s-${RUNNER_CONTAINER_HOOKS_VERSION}.zip \
&& unzip ./runner-container-hooks.zip -d ./k8s \
&& rm -f runner-container-hooks.zip
RUN set -vx; \
export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x86_64 ; fi \
&& curl -fLo docker.tgz https://download.docker.com/linux/static/${CHANNEL}/${ARCH}/docker-${DOCKER_VERSION}.tgz \
&& tar zxvf docker.tgz \
&& install -o root -g root -m 755 docker/docker /usr/bin/docker \
&& rm -rf docker docker.tgz
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x86_64 ; fi \
&& mkdir -p /usr/libexec/docker/cli-plugins \
&& curl -fLo /usr/libexec/docker/cli-plugins/docker-compose https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-${ARCH} \
&& chmod +x /usr/libexec/docker/cli-plugins/docker-compose \
&& ln -s /usr/libexec/docker/cli-plugins/docker-compose /usr/bin/docker-compose \
&& which docker-compose \
&& docker compose version
# We place the scripts in `/usr/bin` so that users who extend this image can
# override them with scripts of the same name placed in `/usr/local/bin`.
COPY entrypoint.sh startup.sh logger.sh graceful-stop.sh update-status /usr/bin/
# Copy the docker shim which propagates the docker MTU to underlying networks
# to replace the docker binary in the PATH.
COPY docker-shim.sh /usr/local/bin/docker
# Configure hooks folder structure.
COPY hooks /etc/arc/hooks/
# Add the Python "User Script Directory" to the PATH
ENV PATH="${PATH}:${HOME}/.local/bin/"
ENV ImageOS=ubuntu24
RUN echo "PATH=${PATH}" > /etc/environment \
&& echo "ImageOS=${ImageOS}" >> /etc/environment
USER runner
ENTRYPOINT ["/bin/bash", "-c"]
CMD ["entrypoint.sh"]

View File

@@ -0,0 +1,31 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: squid
spec:
replicas: 1
selector:
matchLabels:
app: squid
template:
metadata:
labels:
app: squid
spec:
containers:
- name: squid
image: ubuntu/squid:latest
ports:
- containerPort: 3128
---
apiVersion: v1
kind: Service
metadata:
name: squid
spec:
selector:
app: squid
ports:
- protocol: TCP
port: 3128
targetPort: 3128

View File

@@ -0,0 +1,87 @@
#!/bin/bash
set -euo pipefail
DIR="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
ROOT_DIR="$(realpath "${DIR}/../..")"
source "${DIR}/helper.sh"
SCALE_SET_NAME="anonymous-proxy-$(date +'%M%S')$(((RANDOM + 100) % 100 + 1))"
SCALE_SET_NAMESPACE="arc-runners"
WORKFLOW_FILE="arc-test-workflow.yaml"
ARC_NAME="arc"
ARC_NAMESPACE="arc-systems"
function install_arc() {
echo "Creating namespace ${ARC_NAMESPACE}"
kubectl create namespace "${SCALE_SET_NAMESPACE}"
echo "Installing ARC"
helm install "${ARC_NAME}" \
--namespace "${ARC_NAMESPACE}" \
--create-namespace \
--set image.repository="${IMAGE_NAME}" \
--set image.tag="${IMAGE_TAG}" \
"${ROOT_DIR}/charts/gha-runner-scale-set-controller" \
--debug
if ! NAME="${ARC_NAME}" NAMESPACE="${ARC_NAMESPACE}" wait_for_arc; then
NAMESPACE="${ARC_NAMESPACE}" log_arc
return 1
fi
}
function install_squid() {
echo "Starting squid-proxy"
kubectl apply -f "${DIR}/anonymous-proxy-setup.squid.yaml"
}
function install_scale_set() {
echo "Installing scale set ${SCALE_SET_NAMESPACE}/${SCALE_SET_NAME}"
helm install "${SCALE_SET_NAME}" \
--namespace "${SCALE_SET_NAMESPACE}" \
--create-namespace \
--set githubConfigUrl="https://github.com/${TARGET_ORG}/${TARGET_REPO}" \
--set githubConfigSecret.github_token="${GITHUB_TOKEN}" \
--set proxy.https.url="http://squid.default.svc.cluster.local:3128" \
--set "proxy.noProxy[0]=10.96.0.1:443" \
"${ROOT_DIR}/charts/gha-runner-scale-set" \
--debug
if ! NAME="${SCALE_SET_NAME}" NAMESPACE="${ARC_NAMESPACE}" wait_for_scale_set; then
NAMESPACE="${ARC_NAMESPACE}" log_arc
return 1
fi
}
function main() {
local failed=()
build_image
create_cluster
install_arc
install_squid
install_scale_set || {
echo "Scale set installation failed"
NAMESPACE="${ARC_NAMESPACE}" log_arc
delete_cluster
exit 1
}
WORKFLOW_FILE="${WORKFLOW_FILE}" SCALE_SET_NAME="${SCALE_SET_NAME}" run_workflow || failed+=("run_workflow")
INSTALLATION_NAME="${SCALE_SET_NAME}" NAMESPACE="${SCALE_SET_NAMESPACE}" cleanup_scale_set || failed+=("cleanup_scale_set")
NAMESPACE="${ARC_NAMESPACE}" log_arc || failed+=("log_arc")
delete_cluster
print_results "${failed[@]}"
}
main

View File

@@ -0,0 +1,31 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: squid
spec:
replicas: 1
selector:
matchLabels:
app: squid
template:
metadata:
labels:
app: squid
spec:
containers:
- name: squid
image: huangtingluo/squid-proxy:latest
ports:
- containerPort: 3128
---
apiVersion: v1
kind: Service
metadata:
name: squid
spec:
selector:
app: squid
ports:
- protocol: TCP
port: 3128
targetPort: 3128

View File

@@ -0,0 +1,102 @@
#!/bin/bash
set -euo pipefail
DIR="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
ROOT_DIR="$(realpath "${DIR}/../..")"
source "${DIR}/helper.sh"
SCALE_SET_NAME="default-$(date +'%M%S')$(((RANDOM + 100) % 100 + 1))"
SCALE_SET_NAMESPACE="arc-runners"
WORKFLOW_FILE="arc-test-workflow.yaml"
ARC_NAME="arc"
ARC_NAMESPACE="arc-systems"
function install_arc() {
install_openebs || {
echo "OpenEBS installation failed"
return 1
}
echo "Creating namespace ${ARC_NAMESPACE}"
kubectl create namespace "${SCALE_SET_NAMESPACE}"
echo "Installing ARC"
helm install "${ARC_NAME}" \
--namespace "${ARC_NAMESPACE}" \
--create-namespace \
--set image.repository="${IMAGE_NAME}" \
--set image.tag="${IMAGE_TAG}" \
"${ROOT_DIR}/charts/gha-runner-scale-set-controller" \
--debug
if ! NAME="${ARC_NAME}" NAMESPACE="${ARC_NAMESPACE}" wait_for_arc; then
NAMESPACE="${ARC_NAMESPACE}" log_arc
return 1
fi
}
function install_squid() {
echo "Starting squid-proxy"
kubectl apply -f "${DIR}/auth-proxy-setup.squid.yaml"
echo "Creating scale set namespace"
kubectl create namespace "${SCALE_SET_NAMESPACE}" || true
echo "Creating squid proxy secret"
kubectl create secret generic proxy-auth \
--namespace=arc-runners \
--from-literal=username=github \
--from-literal=password='actions'
}
function install_scale_set() {
echo "Installing scale set ${SCALE_SET_NAMESPACE}/${SCALE_SET_NAME}"
helm install "${SCALE_SET_NAME}" \
--namespace "${SCALE_SET_NAMESPACE}" \
--create-namespace \
--set githubConfigUrl="https://github.com/${TARGET_ORG}/${TARGET_REPO}" \
--set githubConfigSecret.github_token="${GITHUB_TOKEN}" \
--set proxy.https.url="http://squid.default.svc.cluster.local:3128" \
--set proxy.https.credentialSecretRef="proxy-auth" \
--set "proxy.noProxy[0]=10.96.0.1:443" \
"${ROOT_DIR}/charts/gha-runner-scale-set" \
--version="${VERSION}" \
--debug
if ! NAME="${SCALE_SET_NAME}" NAMESPACE="${ARC_NAMESPACE}" wait_for_scale_set; then
NAMESPACE="${ARC_NAMESPACE}" log_arc
return 1
fi
}
function main() {
local failed=()
build_image
create_cluster
install_arc
install_squid
install_scale_set || {
echo "Scale set installation failed"
NAMESPACE="${ARC_NAMESPACE}" log_arc
delete_cluster
exit 1
}
WORKFLOW_FILE="${WORKFLOW_FILE}" SCALE_SET_NAME="${SCALE_SET_NAME}" run_workflow || failed+=("run_workflow")
INSTALLATION_NAME="${SCALE_SET_NAME}" NAMESPACE="${SCALE_SET_NAMESPACE}" cleanup_scale_set || failed+=("cleanup_scale_set")
NAMESPACE="${ARC_NAMESPACE}" log_arc || failed+=("log_arc")
delete_cluster
print_results "${failed[@]}"
}
main

Some files were not shown because too many files have changed in this diff Show More