mirror of
https://github.com/actions/actions-runner-controller.git
synced 2025-12-11 12:06:57 +00:00
Compare commits
1 Commits
d0c3d38903
...
update-run
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e85311142 |
4
.github/actions/setup-arc-e2e/action.yaml
vendored
4
.github/actions/setup-arc-e2e/action.yaml
vendored
@@ -36,8 +36,8 @@ runs:
|
|||||||
driver-opts: image=moby/buildkit:v0.10.6
|
driver-opts: image=moby/buildkit:v0.10.6
|
||||||
|
|
||||||
- name: Build controller image
|
- name: Build controller image
|
||||||
# https://github.com/docker/build-push-action/releases/tag/v6.18.0
|
# https://github.com/docker/build-push-action/releases/tag/v6.15.0
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
|
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4
|
||||||
with:
|
with:
|
||||||
file: Dockerfile
|
file: Dockerfile
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
|
|||||||
20
.github/workflows/arc-publish-chart.yaml
vendored
20
.github/workflows/arc-publish-chart.yaml
vendored
@@ -40,12 +40,13 @@ 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@v5
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Helm
|
- name: Set up Helm
|
||||||
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4
|
# Using https://github.com/Azure/setup-helm/releases/tag/v4.2.0
|
||||||
|
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814
|
||||||
with:
|
with:
|
||||||
version: ${{ env.HELM_VERSION }}
|
version: ${{ env.HELM_VERSION }}
|
||||||
|
|
||||||
@@ -58,12 +59,13 @@ 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@v6
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
|
|
||||||
- name: Set up chart-testing
|
- name: Set up chart-testing
|
||||||
uses: helm/chart-testing-action@6ec842c01de15ebb84c8627d2744a0c2f2755c9f
|
# https://github.com/helm/chart-testing-action/releases/tag/v2.7.0
|
||||||
|
uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b
|
||||||
|
|
||||||
- name: Run chart-testing (list-changed)
|
- name: Run chart-testing (list-changed)
|
||||||
id: list-changed
|
id: list-changed
|
||||||
@@ -79,7 +81,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Create kind cluster
|
- name: Create kind cluster
|
||||||
if: steps.list-changed.outputs.changed == 'true'
|
if: steps.list-changed.outputs.changed == 'true'
|
||||||
uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab
|
# https://github.com/helm/kind-action/releases/tag/v1.12.0
|
||||||
|
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
|
||||||
@@ -134,7 +137,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
@@ -145,7 +148,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Get Token
|
- name: Get Token
|
||||||
id: get_workflow_token
|
id: get_workflow_token
|
||||||
uses: peter-murray/workflow-application-token-action@d17e3a9a36850ea89f35db16c1067dd2b68ee343
|
# https://github.com/peter-murray/workflow-application-token-action/releases/tag/v3.0.0
|
||||||
|
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 }}
|
||||||
@@ -184,7 +188,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@v5
|
uses: actions/checkout@v4
|
||||||
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 }}
|
||||||
|
|||||||
7
.github/workflows/arc-publish.yaml
vendored
7
.github/workflows/arc-publish.yaml
vendored
@@ -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@v5
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: "go.mod"
|
go-version-file: "go.mod"
|
||||||
|
|
||||||
@@ -73,7 +73,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Get Token
|
- name: Get Token
|
||||||
id: get_workflow_token
|
id: get_workflow_token
|
||||||
uses: peter-murray/workflow-application-token-action@d17e3a9a36850ea89f35db16c1067dd2b68ee343
|
# https://github.com/peter-murray/workflow-application-token-action/releases/tag/v3.0.0
|
||||||
|
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 }}
|
||||||
|
|||||||
9
.github/workflows/arc-release-runners.yaml
vendored
9
.github/workflows/arc-release-runners.yaml
vendored
@@ -1,6 +1,4 @@
|
|||||||
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
|
||||||
@@ -19,7 +17,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: 28.0.4
|
DOCKER_VERSION: 24.0.7
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}
|
group: ${{ github.workflow }}
|
||||||
@@ -30,7 +28,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@v5
|
- uses: actions/checkout@v4
|
||||||
- name: Get runner version
|
- name: Get runner version
|
||||||
id: versions
|
id: versions
|
||||||
run: |
|
run: |
|
||||||
@@ -41,7 +39,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Get Token
|
- name: Get Token
|
||||||
id: get_workflow_token
|
id: get_workflow_token
|
||||||
uses: peter-murray/workflow-application-token-action@d17e3a9a36850ea89f35db16c1067dd2b68ee343
|
# https://github.com/peter-murray/workflow-application-token-action/releases/tag/v3.0.0
|
||||||
|
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 }}
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
# 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:
|
||||||
@@ -24,7 +21,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@v5
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Get runner current and latest versions
|
- name: Get runner current and latest versions
|
||||||
id: runner_versions
|
id: runner_versions
|
||||||
@@ -53,8 +50,6 @@ 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:
|
||||||
@@ -69,7 +64,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@v5
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: PR Name
|
- name: PR Name
|
||||||
id: pr_name
|
id: pr_name
|
||||||
@@ -124,7 +119,7 @@ jobs:
|
|||||||
PR_NAME: ${{ needs.check_pr.outputs.pr_name }}
|
PR_NAME: ${{ needs.check_pr.outputs.pr_name }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- 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)"
|
||||||
|
|||||||
13
.github/workflows/arc-validate-chart.yaml
vendored
13
.github/workflows/arc-validate-chart.yaml
vendored
@@ -40,22 +40,24 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Helm
|
- name: Set up Helm
|
||||||
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4
|
# Using https://github.com/Azure/setup-helm/releases/tag/v4.2.0
|
||||||
|
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@v6
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
|
|
||||||
- name: Set up chart-testing
|
- name: Set up chart-testing
|
||||||
uses: helm/chart-testing-action@6ec842c01de15ebb84c8627d2744a0c2f2755c9f
|
# https://github.com/helm/chart-testing-action/releases/tag/v2.7.0
|
||||||
|
uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b
|
||||||
|
|
||||||
- name: Run chart-testing (list-changed)
|
- name: Run chart-testing (list-changed)
|
||||||
id: list-changed
|
id: list-changed
|
||||||
@@ -70,7 +72,8 @@ 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
|
||||||
uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab
|
# https://github.com/helm/kind-action/releases/tag/v1.12.0
|
||||||
|
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
|
||||||
|
|||||||
4
.github/workflows/arc-validate-runners.yaml
vendored
4
.github/workflows/arc-validate-runners.yaml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
name: runner / shellcheck
|
name: runner / shellcheck
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
- 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@v5
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
229
.github/workflows/gha-e2e-tests.yaml
vendored
229
.github/workflows/gha-e2e-tests.yaml
vendored
@@ -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.13.0"
|
IMAGE_VERSION: "0.11.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,29 +26,6 @@ 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
|
||||||
@@ -56,7 +33,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
WORKFLOW_FILE: "arc-test-workflow.yaml"
|
WORKFLOW_FILE: "arc-test-workflow.yaml"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{github.head_ref}}
|
ref: ${{github.head_ref}}
|
||||||
|
|
||||||
@@ -140,29 +117,6 @@ 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
|
||||||
@@ -170,7 +124,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
WORKFLOW_FILE: "arc-test-workflow.yaml"
|
WORKFLOW_FILE: "arc-test-workflow.yaml"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{github.head_ref}}
|
ref: ${{github.head_ref}}
|
||||||
|
|
||||||
@@ -256,29 +210,6 @@ 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
|
||||||
@@ -286,7 +217,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
WORKFLOW_FILE: arc-test-dind-workflow.yaml
|
WORKFLOW_FILE: arc-test-dind-workflow.yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{github.head_ref}}
|
ref: ${{github.head_ref}}
|
||||||
|
|
||||||
@@ -371,29 +302,6 @@ 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
|
||||||
@@ -401,7 +309,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
WORKFLOW_FILE: "arc-test-kubernetes-workflow.yaml"
|
WORKFLOW_FILE: "arc-test-kubernetes-workflow.yaml"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{github.head_ref}}
|
ref: ${{github.head_ref}}
|
||||||
|
|
||||||
@@ -495,29 +403,6 @@ 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
|
||||||
@@ -525,7 +410,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
WORKFLOW_FILE: "arc-test-workflow.yaml"
|
WORKFLOW_FILE: "arc-test-workflow.yaml"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{github.head_ref}}
|
ref: ${{github.head_ref}}
|
||||||
|
|
||||||
@@ -621,29 +506,6 @@ 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
|
||||||
@@ -651,7 +513,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
WORKFLOW_FILE: "arc-test-workflow.yaml"
|
WORKFLOW_FILE: "arc-test-workflow.yaml"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{github.head_ref}}
|
ref: ${{github.head_ref}}
|
||||||
|
|
||||||
@@ -741,29 +603,6 @@ 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
|
||||||
@@ -771,7 +610,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
WORKFLOW_FILE: "arc-test-workflow.yaml"
|
WORKFLOW_FILE: "arc-test-workflow.yaml"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{github.head_ref}}
|
ref: ${{github.head_ref}}
|
||||||
|
|
||||||
@@ -886,29 +725,6 @@ 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
|
||||||
@@ -916,7 +732,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
WORKFLOW_FILE: "arc-test-sleepy-matrix.yaml"
|
WORKFLOW_FILE: "arc-test-sleepy-matrix.yaml"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{github.head_ref}}
|
ref: ${{github.head_ref}}
|
||||||
|
|
||||||
@@ -1081,29 +897,6 @@ 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
|
||||||
@@ -1111,7 +904,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
WORKFLOW_FILE: arc-test-workflow.yaml
|
WORKFLOW_FILE: arc-test-workflow.yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.head_ref }}
|
ref: ${{ github.head_ref }}
|
||||||
|
|
||||||
@@ -1191,7 +984,7 @@ jobs:
|
|||||||
echo "5 pods are up!"
|
echo "5 pods are up!"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
if [[ "$count" -ge 30 ]]; then
|
if [[ "$count" -ge 12 ]]; 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
|
||||||
|
|||||||
25
.github/workflows/gha-publish-chart.yaml
vendored
25
.github/workflows/gha-publish-chart.yaml
vendored
@@ -45,7 +45,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v4
|
||||||
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,10 +72,11 @@ 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
|
||||||
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130
|
# https://github.com/docker/setup-qemu-action/releases/tag/v3.6.0
|
||||||
|
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
|
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2
|
||||||
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
|
||||||
@@ -84,14 +85,16 @@ 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
|
||||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef
|
# https://github.com/docker/login-action/releases/tag/v3.4.0
|
||||||
|
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
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
|
# https://github.com/docker/build-push-action/releases/tag/v6.15.0
|
||||||
|
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4
|
||||||
with:
|
with:
|
||||||
file: Dockerfile
|
file: Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
@@ -100,6 +103,8 @@ jobs:
|
|||||||
tags: |
|
tags: |
|
||||||
ghcr.io/${{ steps.resolve_parameters.outputs.repository_owner }}/gha-runner-scale-set-controller:${{ inputs.release_tag_name }}
|
ghcr.io/${{ steps.resolve_parameters.outputs.repository_owner }}/gha-runner-scale-set-controller:${{ inputs.release_tag_name }}
|
||||||
ghcr.io/${{ steps.resolve_parameters.outputs.repository_owner }}/gha-runner-scale-set-controller:${{ inputs.release_tag_name }}-${{ steps.resolve_parameters.outputs.short_sha }}
|
ghcr.io/${{ steps.resolve_parameters.outputs.repository_owner }}/gha-runner-scale-set-controller:${{ inputs.release_tag_name }}-${{ steps.resolve_parameters.outputs.short_sha }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
- name: Job summary
|
- name: Job summary
|
||||||
run: |
|
run: |
|
||||||
@@ -119,7 +124,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v4
|
||||||
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 }}
|
||||||
@@ -138,7 +143,8 @@ 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
|
||||||
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4
|
# Using https://github.com/Azure/setup-helm/releases/tag/v4.2.0
|
||||||
|
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814
|
||||||
with:
|
with:
|
||||||
version: ${{ env.HELM_VERSION }}
|
version: ${{ env.HELM_VERSION }}
|
||||||
|
|
||||||
@@ -166,7 +172,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v4
|
||||||
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 }}
|
||||||
@@ -185,7 +191,8 @@ 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
|
||||||
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4
|
# Using https://github.com/Azure/setup-helm/releases/tag/v4.2.0
|
||||||
|
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814
|
||||||
with:
|
with:
|
||||||
version: ${{ env.HELM_VERSION }}
|
version: ${{ env.HELM_VERSION }}
|
||||||
|
|
||||||
|
|||||||
22
.github/workflows/gha-validate-chart.yaml
vendored
22
.github/workflows/gha-validate-chart.yaml
vendored
@@ -36,22 +36,24 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Helm
|
- name: Set up Helm
|
||||||
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4
|
# Using https://github.com/Azure/setup-helm/releases/tag/v4.2.0
|
||||||
|
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@v6
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
|
|
||||||
- name: Set up chart-testing
|
- name: Set up chart-testing
|
||||||
uses: helm/chart-testing-action@6ec842c01de15ebb84c8627d2744a0c2f2755c9f
|
# https://github.com/helm/chart-testing-action/releases/tag/v2.7.0
|
||||||
|
uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b
|
||||||
|
|
||||||
- name: Run chart-testing (list-changed)
|
- name: Run chart-testing (list-changed)
|
||||||
id: list-changed
|
id: list-changed
|
||||||
@@ -67,13 +69,14 @@ 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@e468171a9de216ec08956ac3ada2f0791b6bd435
|
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2
|
||||||
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
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
|
# https://github.com/docker/build-push-action/releases/tag/v6.15.0
|
||||||
|
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4
|
||||||
if: steps.list-changed.outputs.changed == 'true'
|
if: steps.list-changed.outputs.changed == 'true'
|
||||||
with:
|
with:
|
||||||
file: Dockerfile
|
file: Dockerfile
|
||||||
@@ -88,7 +91,8 @@ jobs:
|
|||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
- name: Create kind cluster
|
- name: Create kind cluster
|
||||||
uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab
|
# https://github.com/helm/kind-action/releases/tag/v1.12.0
|
||||||
|
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
|
||||||
@@ -111,8 +115,8 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: "go.mod"
|
go-version-file: "go.mod"
|
||||||
cache: false
|
cache: false
|
||||||
|
|||||||
19
.github/workflows/global-publish-canary.yaml
vendored
19
.github/workflows/global-publish-canary.yaml
vendored
@@ -55,11 +55,12 @@ jobs:
|
|||||||
TARGET_REPO: actions-runner-controller
|
TARGET_REPO: actions-runner-controller
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Get Token
|
- name: Get Token
|
||||||
id: get_workflow_token
|
id: get_workflow_token
|
||||||
uses: peter-murray/workflow-application-token-action@d17e3a9a36850ea89f35db16c1067dd2b68ee343
|
# https://github.com/peter-murray/workflow-application-token-action/releases/tag/v3.0.0
|
||||||
|
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 }}
|
||||||
@@ -90,10 +91,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef
|
# https://github.com/docker/login-action/releases/tag/v3.4.0
|
||||||
|
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
@@ -110,16 +112,19 @@ 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
|
||||||
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130
|
# https://github.com/docker/setup-qemu-action/releases/tag/v3.6.0
|
||||||
|
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
|
# https://github.com/docker/setup-buildx-action/releases/tag/v3.10.0
|
||||||
|
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
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
|
# https://github.com/docker/build-push-action/releases/tag/v6.15.0
|
||||||
|
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
|||||||
12
.github/workflows/global-run-codeql.yaml
vendored
12
.github/workflows/global-run-codeql.yaml
vendored
@@ -25,20 +25,20 @@ jobs:
|
|||||||
security-events: write
|
security-events: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v4
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: go, actions
|
languages: go
|
||||||
|
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v4
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v4
|
uses: github/codeql-action/analyze@v2
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
name: First Interaction
|
name: First Interaction
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
issues:
|
issues:
|
||||||
types: [opened]
|
types: [opened]
|
||||||
@@ -16,19 +11,19 @@ jobs:
|
|||||||
check_for_first_interaction:
|
check_for_first_interaction:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/first-interaction@v3
|
- uses: actions/first-interaction@main
|
||||||
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.
|
||||||
|
|||||||
2
.github/workflows/global-run-stale.yaml
vendored
2
.github/workflows/global-run-stale.yaml
vendored
@@ -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@v10
|
- uses: actions/stale@v6
|
||||||
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
|
||||||
|
|||||||
23
.github/workflows/go.yaml
vendored
23
.github/workflows/go.yaml
vendored
@@ -29,8 +29,8 @@ jobs:
|
|||||||
fmt:
|
fmt:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: "go.mod"
|
go-version-file: "go.mod"
|
||||||
cache: false
|
cache: false
|
||||||
@@ -42,22 +42,23 @@ jobs:
|
|||||||
lint:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: "go.mod"
|
go-version-file: "go.mod"
|
||||||
cache: false
|
cache: false
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@0a35821d5c230e903fcfe077583637dea1b27b47
|
# https://github.com/golangci/golangci-lint-action/releases/tag/v7.0.0
|
||||||
|
uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd
|
||||||
with:
|
with:
|
||||||
only-new-issues: true
|
only-new-issues: true
|
||||||
version: v2.5.0
|
version: v2.1.2
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: "go.mod"
|
go-version-file: "go.mod"
|
||||||
cache: false
|
cache: false
|
||||||
@@ -69,8 +70,8 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: "go.mod"
|
go-version-file: "go.mod"
|
||||||
- run: make manifests
|
- run: make manifests
|
||||||
@@ -78,7 +79,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.30.0-linux-amd64.tar.gz" -o kubebuilder-tools
|
curl -D headers.txt -fsL "https://storage.googleapis.com/kubebuilder-tools/kubebuilder-tools-1.26.1-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
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
# actions-runner-controller maintainers
|
# actions-runner-controller maintainers
|
||||||
* @mumoshu @toast-gear @actions/actions-launch @actions/actions-compute @nikola-jokic @rentziass
|
* @mumoshu @toast-gear @actions/actions-launch @nikola-jokic @rentziass
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Build the manager binary
|
# Build the manager binary
|
||||||
FROM --platform=$BUILDPLATFORM golang:1.25.1 AS builder
|
FROM --platform=$BUILDPLATFORM golang:1.24.0 as builder
|
||||||
|
|
||||||
WORKDIR /workspace
|
WORKDIR /workspace
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ ARG TARGETPLATFORM TARGETOS TARGETARCH TARGETVARIANT VERSION=dev COMMIT_SHA=dev
|
|||||||
# to avoid https://github.com/moby/buildkit/issues/2334
|
# to avoid https://github.com/moby/buildkit/issues/2334
|
||||||
# We can use docker layer cache so the build is fast enogh anyway
|
# We can use docker layer cache so the build is fast enogh anyway
|
||||||
# We also use per-platform GOCACHE for the same reason.
|
# We also use per-platform GOCACHE for the same reason.
|
||||||
ENV GOCACHE="/build/${TARGETPLATFORM}/root/.cache/go-build"
|
ENV GOCACHE /build/${TARGETPLATFORM}/root/.cache/go-build
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
RUN --mount=target=. \
|
RUN --mount=target=. \
|
||||||
|
|||||||
17
Makefile
17
Makefile
@@ -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.330.0
|
RUNNER_VERSION ?= 2.323.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.5.0 golangci-lint run
|
docker run --rm -v $(PWD):/app -w /app golangci/golangci-lint:v2.1.2 golangci-lint run
|
||||||
|
|
||||||
GO_TEST_ARGS ?= -short
|
GO_TEST_ARGS ?= -short
|
||||||
|
|
||||||
@@ -117,6 +117,9 @@ 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
|
||||||
|
|
||||||
@@ -210,6 +213,8 @@ 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}" \
|
||||||
@@ -295,10 +300,6 @@ 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/
|
||||||
@@ -309,7 +310,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.8.0 is needed due to https://github.com/kubernetes-sigs/controller-tools/issues/448
|
# Note that controller-gen newer than 0.7.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))
|
||||||
@@ -319,7 +320,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.19.0 ;\
|
go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.17.2 ;\
|
||||||
rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
|
rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
|
||||||
}
|
}
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
package appconfig
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AppConfig struct {
|
|
||||||
AppID string `json:"github_app_id"`
|
|
||||||
AppInstallationID int64 `json:"github_app_installation_id"`
|
|
||||||
AppPrivateKey string `json:"github_app_private_key"`
|
|
||||||
|
|
||||||
Token string `json:"github_token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *AppConfig) tidy() *AppConfig {
|
|
||||||
if len(c.Token) > 0 {
|
|
||||||
return &AppConfig{
|
|
||||||
Token: c.Token,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &AppConfig{
|
|
||||||
AppID: c.AppID,
|
|
||||||
AppInstallationID: c.AppInstallationID,
|
|
||||||
AppPrivateKey: c.AppPrivateKey,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *AppConfig) Validate() error {
|
|
||||||
if c == nil {
|
|
||||||
return fmt.Errorf("missing app config")
|
|
||||||
}
|
|
||||||
hasToken := len(c.Token) > 0
|
|
||||||
hasGitHubAppAuth := c.hasGitHubAppAuth()
|
|
||||||
if hasToken && hasGitHubAppAuth {
|
|
||||||
return fmt.Errorf("both PAT and GitHub App credentials provided. should only provide one")
|
|
||||||
}
|
|
||||||
if !hasToken && !hasGitHubAppAuth {
|
|
||||||
return fmt.Errorf("no credentials provided: either a PAT or GitHub App credentials should be provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *AppConfig) hasGitHubAppAuth() bool {
|
|
||||||
return len(c.AppID) > 0 && c.AppInstallationID > 0 && len(c.AppPrivateKey) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func FromSecret(secret *corev1.Secret) (*AppConfig, error) {
|
|
||||||
var appInstallationID int64
|
|
||||||
if v := string(secret.Data["github_app_installation_id"]); v != "" {
|
|
||||||
val, err := strconv.ParseInt(v, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
appInstallationID = val
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg := &AppConfig{
|
|
||||||
Token: string(secret.Data["github_token"]),
|
|
||||||
AppID: string(secret.Data["github_app_id"]),
|
|
||||||
AppInstallationID: appInstallationID,
|
|
||||||
AppPrivateKey: string(secret.Data["github_app_private_key"]),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cfg.Validate(); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to validate config: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cfg.tidy(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func FromJSONString(v string) (*AppConfig, error) {
|
|
||||||
var appConfig AppConfig
|
|
||||||
if err := json.NewDecoder(bytes.NewBufferString(v)).Decode(&appConfig); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := appConfig.Validate(); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to validate app config decoded from string: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return appConfig.tidy(), nil
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
package appconfig
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAppConfigValidate_invalid(t *testing.T) {
|
|
||||||
tt := map[string]*AppConfig{
|
|
||||||
"empty": {},
|
|
||||||
"token and app config": {
|
|
||||||
AppID: "1",
|
|
||||||
AppInstallationID: 2,
|
|
||||||
AppPrivateKey: "private key",
|
|
||||||
Token: "token",
|
|
||||||
},
|
|
||||||
"app id not set": {
|
|
||||||
AppInstallationID: 2,
|
|
||||||
AppPrivateKey: "private key",
|
|
||||||
},
|
|
||||||
"app installation id not set": {
|
|
||||||
AppID: "2",
|
|
||||||
AppPrivateKey: "private key",
|
|
||||||
},
|
|
||||||
"private key empty": {
|
|
||||||
AppID: "2",
|
|
||||||
AppInstallationID: 1,
|
|
||||||
AppPrivateKey: "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, cfg := range tt {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
err := cfg.Validate()
|
|
||||||
require.Error(t, err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppConfigValidate_valid(t *testing.T) {
|
|
||||||
tt := map[string]*AppConfig{
|
|
||||||
"token": {
|
|
||||||
Token: "token",
|
|
||||||
},
|
|
||||||
"app ID": {
|
|
||||||
AppID: "1",
|
|
||||||
AppInstallationID: 2,
|
|
||||||
AppPrivateKey: "private key",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, cfg := range tt {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
err := cfg.Validate()
|
|
||||||
require.NoError(t, err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppConfigFromSecret_invalid(t *testing.T) {
|
|
||||||
tt := map[string]map[string]string{
|
|
||||||
"empty": {},
|
|
||||||
"token and app provided": {
|
|
||||||
"github_token": "token",
|
|
||||||
"github_app_id": "2",
|
|
||||||
"githu_app_installation_id": "3",
|
|
||||||
"github_app_private_key": "private key",
|
|
||||||
},
|
|
||||||
"invalid app id": {
|
|
||||||
"github_app_id": "abc",
|
|
||||||
"githu_app_installation_id": "3",
|
|
||||||
"github_app_private_key": "private key",
|
|
||||||
},
|
|
||||||
"invalid app installation_id": {
|
|
||||||
"github_app_id": "1",
|
|
||||||
"githu_app_installation_id": "abc",
|
|
||||||
"github_app_private_key": "private key",
|
|
||||||
},
|
|
||||||
"empty private key": {
|
|
||||||
"github_app_id": "1",
|
|
||||||
"githu_app_installation_id": "2",
|
|
||||||
"github_app_private_key": "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, data := range tt {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
secret := &corev1.Secret{
|
|
||||||
StringData: data,
|
|
||||||
}
|
|
||||||
|
|
||||||
appConfig, err := FromSecret(secret)
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Nil(t, appConfig)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppConfigFromSecret_valid(t *testing.T) {
|
|
||||||
tt := map[string]map[string]string{
|
|
||||||
"with token": {
|
|
||||||
"github_token": "token",
|
|
||||||
},
|
|
||||||
"app config": {
|
|
||||||
"github_app_id": "2",
|
|
||||||
"githu_app_installation_id": "3",
|
|
||||||
"github_app_private_key": "private key",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, data := range tt {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
secret := &corev1.Secret{
|
|
||||||
StringData: data,
|
|
||||||
}
|
|
||||||
|
|
||||||
appConfig, err := FromSecret(secret)
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Nil(t, appConfig)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppConfigFromString_valid(t *testing.T) {
|
|
||||||
tt := map[string]*AppConfig{
|
|
||||||
"token": {
|
|
||||||
Token: "token",
|
|
||||||
},
|
|
||||||
"app ID": {
|
|
||||||
AppID: "1",
|
|
||||||
AppInstallationID: 2,
|
|
||||||
AppPrivateKey: "private key",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, cfg := range tt {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
bytes, err := json.Marshal(cfg)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
got, err := FromJSONString(string(bytes))
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
want := cfg.tidy()
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -59,10 +59,7 @@ type AutoscalingListenerSpec struct {
|
|||||||
Proxy *ProxyConfig `json:"proxy,omitempty"`
|
Proxy *ProxyConfig `json:"proxy,omitempty"`
|
||||||
|
|
||||||
// +optional
|
// +optional
|
||||||
GitHubServerTLS *TLSConfig `json:"githubServerTLS,omitempty"`
|
GitHubServerTLS *GitHubServerTLSConfig `json:"githubServerTLS,omitempty"`
|
||||||
|
|
||||||
// +optional
|
|
||||||
VaultConfig *VaultConfig `json:"vaultConfig,omitempty"`
|
|
||||||
|
|
||||||
// +optional
|
// +optional
|
||||||
Metrics *MetricsConfig `json:"metrics,omitempty"`
|
Metrics *MetricsConfig `json:"metrics,omitempty"`
|
||||||
@@ -90,6 +87,7 @@ type AutoscalingListener struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:object:root=true
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
// AutoscalingListenerList contains a list of AutoscalingListener
|
// AutoscalingListenerList contains a list of AutoscalingListener
|
||||||
type AutoscalingListenerList struct {
|
type AutoscalingListenerList struct {
|
||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/actions/actions-runner-controller/hash"
|
"github.com/actions/actions-runner-controller/hash"
|
||||||
"github.com/actions/actions-runner-controller/vault"
|
|
||||||
"golang.org/x/net/http/httpproxy"
|
"golang.org/x/net/http/httpproxy"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@@ -70,10 +69,7 @@ type AutoscalingRunnerSetSpec struct {
|
|||||||
Proxy *ProxyConfig `json:"proxy,omitempty"`
|
Proxy *ProxyConfig `json:"proxy,omitempty"`
|
||||||
|
|
||||||
// +optional
|
// +optional
|
||||||
GitHubServerTLS *TLSConfig `json:"githubServerTLS,omitempty"`
|
GitHubServerTLS *GitHubServerTLSConfig `json:"githubServerTLS,omitempty"`
|
||||||
|
|
||||||
// +optional
|
|
||||||
VaultConfig *VaultConfig `json:"vaultConfig,omitempty"`
|
|
||||||
|
|
||||||
// Required
|
// Required
|
||||||
Template corev1.PodTemplateSpec `json:"template,omitempty"`
|
Template corev1.PodTemplateSpec `json:"template,omitempty"`
|
||||||
@@ -93,12 +89,12 @@ type AutoscalingRunnerSetSpec struct {
|
|||||||
MinRunners *int `json:"minRunners,omitempty"`
|
MinRunners *int `json:"minRunners,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TLSConfig struct {
|
type GitHubServerTLSConfig struct {
|
||||||
// Required
|
// Required
|
||||||
CertificateFrom *TLSCertificateSource `json:"certificateFrom,omitempty"`
|
CertificateFrom *TLSCertificateSource `json:"certificateFrom,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TLSConfig) ToCertPool(keyFetcher func(name, key string) ([]byte, error)) (*x509.CertPool, error) {
|
func (c *GitHubServerTLSConfig) ToCertPool(keyFetcher func(name, key string) ([]byte, error)) (*x509.CertPool, error) {
|
||||||
if c.CertificateFrom == nil {
|
if c.CertificateFrom == nil {
|
||||||
return nil, fmt.Errorf("certificateFrom not specified")
|
return nil, fmt.Errorf("certificateFrom not specified")
|
||||||
}
|
}
|
||||||
@@ -146,7 +142,7 @@ type ProxyConfig struct {
|
|||||||
NoProxy []string `json:"noProxy,omitempty"`
|
NoProxy []string `json:"noProxy,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ProxyConfig) ToHTTPProxyConfig(secretFetcher func(string) (*corev1.Secret, error)) (*httpproxy.Config, error) {
|
func (c *ProxyConfig) toHTTPProxyConfig(secretFetcher func(string) (*corev1.Secret, error)) (*httpproxy.Config, error) {
|
||||||
config := &httpproxy.Config{
|
config := &httpproxy.Config{
|
||||||
NoProxy: strings.Join(c.NoProxy, ","),
|
NoProxy: strings.Join(c.NoProxy, ","),
|
||||||
}
|
}
|
||||||
@@ -205,7 +201,7 @@ func (c *ProxyConfig) ToHTTPProxyConfig(secretFetcher func(string) (*corev1.Secr
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ProxyConfig) ToSecretData(secretFetcher func(string) (*corev1.Secret, error)) (map[string][]byte, error) {
|
func (c *ProxyConfig) ToSecretData(secretFetcher func(string) (*corev1.Secret, error)) (map[string][]byte, error) {
|
||||||
config, err := c.ToHTTPProxyConfig(secretFetcher)
|
config, err := c.toHTTPProxyConfig(secretFetcher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -219,7 +215,7 @@ func (c *ProxyConfig) ToSecretData(secretFetcher func(string) (*corev1.Secret, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ProxyConfig) ProxyFunc(secretFetcher func(string) (*corev1.Secret, error)) (func(*http.Request) (*url.URL, error), error) {
|
func (c *ProxyConfig) ProxyFunc(secretFetcher func(string) (*corev1.Secret, error)) (func(*http.Request) (*url.URL, error), error) {
|
||||||
config, err := c.ToHTTPProxyConfig(secretFetcher)
|
config, err := c.toHTTPProxyConfig(secretFetcher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -239,26 +235,6 @@ type ProxyServerConfig struct {
|
|||||||
CredentialSecretRef string `json:"credentialSecretRef,omitempty"`
|
CredentialSecretRef string `json:"credentialSecretRef,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type VaultConfig struct {
|
|
||||||
// +optional
|
|
||||||
Type vault.VaultType `json:"type,omitempty"`
|
|
||||||
// +optional
|
|
||||||
AzureKeyVault *AzureKeyVaultConfig `json:"azureKeyVault,omitempty"`
|
|
||||||
// +optional
|
|
||||||
Proxy *ProxyConfig `json:"proxy,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AzureKeyVaultConfig struct {
|
|
||||||
// +required
|
|
||||||
URL string `json:"url,omitempty"`
|
|
||||||
// +required
|
|
||||||
TenantID string `json:"tenantId,omitempty"`
|
|
||||||
// +required
|
|
||||||
ClientID string `json:"clientId,omitempty"`
|
|
||||||
// +required
|
|
||||||
CertificatePath string `json:"certificatePath,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MetricsConfig holds configuration parameters for each metric type
|
// MetricsConfig holds configuration parameters for each metric type
|
||||||
type MetricsConfig struct {
|
type MetricsConfig struct {
|
||||||
// +optional
|
// +optional
|
||||||
@@ -309,33 +285,6 @@ func (ars *AutoscalingRunnerSet) ListenerSpecHash() string {
|
|||||||
return hash.ComputeTemplateHash(&spec)
|
return hash.ComputeTemplateHash(&spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ars *AutoscalingRunnerSet) GitHubConfigSecret() string {
|
|
||||||
return ars.Spec.GitHubConfigSecret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ars *AutoscalingRunnerSet) GitHubConfigUrl() string {
|
|
||||||
return ars.Spec.GitHubConfigUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ars *AutoscalingRunnerSet) GitHubProxy() *ProxyConfig {
|
|
||||||
return ars.Spec.Proxy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ars *AutoscalingRunnerSet) GitHubServerTLS() *TLSConfig {
|
|
||||||
return ars.Spec.GitHubServerTLS
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ars *AutoscalingRunnerSet) VaultConfig() *VaultConfig {
|
|
||||||
return ars.Spec.VaultConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ars *AutoscalingRunnerSet) VaultProxy() *ProxyConfig {
|
|
||||||
if ars.Spec.VaultConfig != nil {
|
|
||||||
return ars.Spec.VaultConfig.Proxy
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ars *AutoscalingRunnerSet) RunnerSetSpecHash() string {
|
func (ars *AutoscalingRunnerSet) RunnerSetSpecHash() string {
|
||||||
type runnerSetSpec struct {
|
type runnerSetSpec struct {
|
||||||
GitHubConfigUrl string
|
GitHubConfigUrl string
|
||||||
@@ -343,7 +292,7 @@ func (ars *AutoscalingRunnerSet) RunnerSetSpecHash() string {
|
|||||||
RunnerGroup string
|
RunnerGroup string
|
||||||
RunnerScaleSetName string
|
RunnerScaleSetName string
|
||||||
Proxy *ProxyConfig
|
Proxy *ProxyConfig
|
||||||
GitHubServerTLS *TLSConfig
|
GitHubServerTLS *GitHubServerTLSConfig
|
||||||
Template corev1.PodTemplateSpec
|
Template corev1.PodTemplateSpec
|
||||||
}
|
}
|
||||||
spec := &runnerSetSpec{
|
spec := &runnerSetSpec{
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ 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"
|
||||||
|
|
||||||
@@ -51,10 +50,6 @@ 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 {
|
||||||
@@ -72,33 +67,6 @@ func (er *EphemeralRunner) HasContainerHookConfigured() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (er *EphemeralRunner) GitHubConfigSecret() string {
|
|
||||||
return er.Spec.GitHubConfigSecret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (er *EphemeralRunner) GitHubConfigUrl() string {
|
|
||||||
return er.Spec.GitHubConfigUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
func (er *EphemeralRunner) GitHubProxy() *ProxyConfig {
|
|
||||||
return er.Spec.Proxy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (er *EphemeralRunner) GitHubServerTLS() *TLSConfig {
|
|
||||||
return er.Spec.GitHubServerTLS
|
|
||||||
}
|
|
||||||
|
|
||||||
func (er *EphemeralRunner) VaultConfig() *VaultConfig {
|
|
||||||
return er.Spec.VaultConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (er *EphemeralRunner) VaultProxy() *ProxyConfig {
|
|
||||||
if er.Spec.VaultConfig != nil {
|
|
||||||
return er.Spec.VaultConfig.Proxy
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EphemeralRunnerSpec defines the desired state of EphemeralRunner
|
// EphemeralRunnerSpec defines the desired state of EphemeralRunner
|
||||||
type EphemeralRunnerSpec struct {
|
type EphemeralRunnerSpec struct {
|
||||||
// +required
|
// +required
|
||||||
@@ -107,9 +75,6 @@ type EphemeralRunnerSpec struct {
|
|||||||
// +required
|
// +required
|
||||||
GitHubConfigSecret string `json:"githubConfigSecret,omitempty"`
|
GitHubConfigSecret string `json:"githubConfigSecret,omitempty"`
|
||||||
|
|
||||||
// +optional
|
|
||||||
GitHubServerTLS *TLSConfig `json:"githubServerTLS,omitempty"`
|
|
||||||
|
|
||||||
// +required
|
// +required
|
||||||
RunnerScaleSetId int `json:"runnerScaleSetId,omitempty"`
|
RunnerScaleSetId int `json:"runnerScaleSetId,omitempty"`
|
||||||
|
|
||||||
@@ -120,7 +85,7 @@ type EphemeralRunnerSpec struct {
|
|||||||
ProxySecretRef string `json:"proxySecretRef,omitempty"`
|
ProxySecretRef string `json:"proxySecretRef,omitempty"`
|
||||||
|
|
||||||
// +optional
|
// +optional
|
||||||
VaultConfig *VaultConfig `json:"vaultConfig,omitempty"`
|
GitHubServerTLS *GitHubServerTLSConfig `json:"githubServerTLS,omitempty"`
|
||||||
|
|
||||||
corev1.PodTemplateSpec `json:",inline"`
|
corev1.PodTemplateSpec `json:",inline"`
|
||||||
}
|
}
|
||||||
@@ -150,16 +115,15 @@ 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]bool `json:"failures,omitempty"`
|
||||||
|
|
||||||
// +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"`
|
||||||
|
|
||||||
@@ -173,20 +137,6 @@ type EphemeralRunnerStatus struct {
|
|||||||
JobDisplayName string `json:"jobDisplayName,omitempty"`
|
JobDisplayName string `json:"jobDisplayName,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *EphemeralRunnerStatus) LastFailure() metav1.Time {
|
|
||||||
var maxTime metav1.Time
|
|
||||||
if len(s.Failures) == 0 {
|
|
||||||
return maxTime
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ts := range s.Failures {
|
|
||||||
if ts.After(maxTime.Time) {
|
|
||||||
maxTime = ts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return maxTime
|
|
||||||
}
|
|
||||||
|
|
||||||
// +kubebuilder:object:root=true
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
// EphemeralRunnerList contains a list of EphemeralRunner
|
// EphemeralRunnerList contains a list of EphemeralRunner
|
||||||
|
|||||||
@@ -60,35 +60,9 @@ type EphemeralRunnerSet struct {
|
|||||||
Status EphemeralRunnerSetStatus `json:"status,omitempty"`
|
Status EphemeralRunnerSetStatus `json:"status,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ers *EphemeralRunnerSet) GitHubConfigSecret() string {
|
// +kubebuilder:object:root=true
|
||||||
return ers.Spec.EphemeralRunnerSpec.GitHubConfigSecret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ers *EphemeralRunnerSet) GitHubConfigUrl() string {
|
|
||||||
return ers.Spec.EphemeralRunnerSpec.GitHubConfigUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ers *EphemeralRunnerSet) GitHubProxy() *ProxyConfig {
|
|
||||||
return ers.Spec.EphemeralRunnerSpec.Proxy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ers *EphemeralRunnerSet) GitHubServerTLS() *TLSConfig {
|
|
||||||
return ers.Spec.EphemeralRunnerSpec.GitHubServerTLS
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ers *EphemeralRunnerSet) VaultConfig() *VaultConfig {
|
|
||||||
return ers.Spec.EphemeralRunnerSpec.VaultConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ers *EphemeralRunnerSet) VaultProxy() *ProxyConfig {
|
|
||||||
if ers.Spec.EphemeralRunnerSpec.VaultConfig != nil {
|
|
||||||
return ers.Spec.EphemeralRunnerSpec.VaultConfig.Proxy
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EphemeralRunnerSetList contains a list of EphemeralRunnerSet
|
// EphemeralRunnerSetList contains a list of EphemeralRunnerSet
|
||||||
// +kubebuilder:object:root=true
|
|
||||||
type EphemeralRunnerSetList struct {
|
type EphemeralRunnerSetList struct {
|
||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
metav1.ListMeta `json:"metadata,omitempty"`
|
metav1.ListMeta `json:"metadata,omitempty"`
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
|
|
||||||
func TestGitHubServerTLSConfig_ToCertPool(t *testing.T) {
|
func TestGitHubServerTLSConfig_ToCertPool(t *testing.T) {
|
||||||
t.Run("returns an error if CertificateFrom not specified", func(t *testing.T) {
|
t.Run("returns an error if CertificateFrom not specified", func(t *testing.T) {
|
||||||
c := &v1alpha1.TLSConfig{
|
c := &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: nil,
|
CertificateFrom: nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ func TestGitHubServerTLSConfig_ToCertPool(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("returns an error if CertificateFrom.ConfigMapKeyRef not specified", func(t *testing.T) {
|
t.Run("returns an error if CertificateFrom.ConfigMapKeyRef not specified", func(t *testing.T) {
|
||||||
c := &v1alpha1.TLSConfig{
|
c := &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: &v1alpha1.TLSCertificateSource{},
|
CertificateFrom: &v1alpha1.TLSCertificateSource{},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ func TestGitHubServerTLSConfig_ToCertPool(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("returns a valid cert pool with correct configuration", func(t *testing.T) {
|
t.Run("returns a valid cert pool with correct configuration", func(t *testing.T) {
|
||||||
c := &v1alpha1.TLSConfig{
|
c := &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &v1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &v1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: v1.LocalObjectReference{
|
LocalObjectReference: v1.LocalObjectReference{
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
package v1alpha1
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
func IsVersionAllowed(resourceVersion, buildVersion string) bool {
|
|
||||||
if buildVersion == "dev" || resourceVersion == buildVersion || strings.HasPrefix(buildVersion, "canary-") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
rv, ok := parseSemver(resourceVersion)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
bv, ok := parseSemver(buildVersion)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return rv.major == bv.major && rv.minor == bv.minor
|
|
||||||
}
|
|
||||||
|
|
||||||
type semver struct {
|
|
||||||
major string
|
|
||||||
minor string
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseSemver(v string) (p semver, ok bool) {
|
|
||||||
if v == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.major, v, ok = parseInt(v)
|
|
||||||
if !ok {
|
|
||||||
return p, false
|
|
||||||
}
|
|
||||||
if v == "" {
|
|
||||||
p.minor = "0"
|
|
||||||
return p, true
|
|
||||||
}
|
|
||||||
if v[0] != '.' {
|
|
||||||
return p, false
|
|
||||||
}
|
|
||||||
p.minor, v, ok = parseInt(v[1:])
|
|
||||||
if !ok {
|
|
||||||
return p, false
|
|
||||||
}
|
|
||||||
if v == "" {
|
|
||||||
return p, true
|
|
||||||
}
|
|
||||||
if v[0] != '.' {
|
|
||||||
return p, false
|
|
||||||
}
|
|
||||||
if _, _, ok = parseInt(v[1:]); !ok {
|
|
||||||
return p, false
|
|
||||||
}
|
|
||||||
return p, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseInt(v string) (t, rest string, ok bool) {
|
|
||||||
if v == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v[0] < '0' || '9' < v[0] {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
i := 1
|
|
||||||
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if v[0] == '0' && i != 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return v[:i], v[i:], true
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package v1alpha1_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestIsVersionAllowed(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
tt := map[string]struct {
|
|
||||||
resourceVersion string
|
|
||||||
buildVersion string
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
"dev should always be allowed": {
|
|
||||||
resourceVersion: "0.11.0",
|
|
||||||
buildVersion: "dev",
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
"resourceVersion is not semver": {
|
|
||||||
resourceVersion: "dev",
|
|
||||||
buildVersion: "0.11.0",
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
"buildVersion is not semver": {
|
|
||||||
resourceVersion: "0.11.0",
|
|
||||||
buildVersion: "NA",
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
"major version mismatch": {
|
|
||||||
resourceVersion: "0.11.0",
|
|
||||||
buildVersion: "1.11.0",
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
"minor version mismatch": {
|
|
||||||
resourceVersion: "0.11.0",
|
|
||||||
buildVersion: "0.10.0",
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
"patch version mismatch": {
|
|
||||||
resourceVersion: "0.11.1",
|
|
||||||
buildVersion: "0.11.0",
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
"arbitrary version match": {
|
|
||||||
resourceVersion: "abc",
|
|
||||||
buildVersion: "abc",
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, tc := range tt {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
got := v1alpha1.IsVersionAllowed(tc.resourceVersion, tc.buildVersion)
|
|
||||||
assert.Equal(t, tc.want, got)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -22,7 +22,6 @@ package v1alpha1
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -100,12 +99,7 @@ func (in *AutoscalingListenerSpec) DeepCopyInto(out *AutoscalingListenerSpec) {
|
|||||||
}
|
}
|
||||||
if in.GitHubServerTLS != nil {
|
if in.GitHubServerTLS != nil {
|
||||||
in, out := &in.GitHubServerTLS, &out.GitHubServerTLS
|
in, out := &in.GitHubServerTLS, &out.GitHubServerTLS
|
||||||
*out = new(TLSConfig)
|
*out = new(GitHubServerTLSConfig)
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
if in.VaultConfig != nil {
|
|
||||||
in, out := &in.VaultConfig, &out.VaultConfig
|
|
||||||
*out = new(VaultConfig)
|
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
if in.Metrics != nil {
|
if in.Metrics != nil {
|
||||||
@@ -214,12 +208,7 @@ func (in *AutoscalingRunnerSetSpec) DeepCopyInto(out *AutoscalingRunnerSetSpec)
|
|||||||
}
|
}
|
||||||
if in.GitHubServerTLS != nil {
|
if in.GitHubServerTLS != nil {
|
||||||
in, out := &in.GitHubServerTLS, &out.GitHubServerTLS
|
in, out := &in.GitHubServerTLS, &out.GitHubServerTLS
|
||||||
*out = new(TLSConfig)
|
*out = new(GitHubServerTLSConfig)
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
if in.VaultConfig != nil {
|
|
||||||
in, out := &in.VaultConfig, &out.VaultConfig
|
|
||||||
*out = new(VaultConfig)
|
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
in.Template.DeepCopyInto(&out.Template)
|
in.Template.DeepCopyInto(&out.Template)
|
||||||
@@ -270,21 +259,6 @@ func (in *AutoscalingRunnerSetStatus) DeepCopy() *AutoscalingRunnerSetStatus {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *AzureKeyVaultConfig) DeepCopyInto(out *AzureKeyVaultConfig) {
|
|
||||||
*out = *in
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureKeyVaultConfig.
|
|
||||||
func (in *AzureKeyVaultConfig) DeepCopy() *AzureKeyVaultConfig {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(AzureKeyVaultConfig)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CounterMetric) DeepCopyInto(out *CounterMetric) {
|
func (in *CounterMetric) DeepCopyInto(out *CounterMetric) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@@ -457,19 +431,14 @@ func (in *EphemeralRunnerSetStatus) DeepCopy() *EphemeralRunnerSetStatus {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *EphemeralRunnerSpec) DeepCopyInto(out *EphemeralRunnerSpec) {
|
func (in *EphemeralRunnerSpec) DeepCopyInto(out *EphemeralRunnerSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.GitHubServerTLS != nil {
|
|
||||||
in, out := &in.GitHubServerTLS, &out.GitHubServerTLS
|
|
||||||
*out = new(TLSConfig)
|
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
if in.Proxy != nil {
|
if in.Proxy != nil {
|
||||||
in, out := &in.Proxy, &out.Proxy
|
in, out := &in.Proxy, &out.Proxy
|
||||||
*out = new(ProxyConfig)
|
*out = new(ProxyConfig)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
if in.VaultConfig != nil {
|
if in.GitHubServerTLS != nil {
|
||||||
in, out := &in.VaultConfig, &out.VaultConfig
|
in, out := &in.GitHubServerTLS, &out.GitHubServerTLS
|
||||||
*out = new(VaultConfig)
|
*out = new(GitHubServerTLSConfig)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
in.PodTemplateSpec.DeepCopyInto(&out.PodTemplateSpec)
|
in.PodTemplateSpec.DeepCopyInto(&out.PodTemplateSpec)
|
||||||
@@ -490,9 +459,9 @@ func (in *EphemeralRunnerStatus) DeepCopyInto(out *EphemeralRunnerStatus) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
if in.Failures != nil {
|
if in.Failures != nil {
|
||||||
in, out := &in.Failures, &out.Failures
|
in, out := &in.Failures, &out.Failures
|
||||||
*out = make(map[string]metav1.Time, len(*in))
|
*out = make(map[string]bool, len(*in))
|
||||||
for key, val := range *in {
|
for key, val := range *in {
|
||||||
(*out)[key] = *val.DeepCopy()
|
(*out)[key] = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,6 +496,26 @@ func (in *GaugeMetric) DeepCopy() *GaugeMetric {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *GitHubServerTLSConfig) DeepCopyInto(out *GitHubServerTLSConfig) {
|
||||||
|
*out = *in
|
||||||
|
if in.CertificateFrom != nil {
|
||||||
|
in, out := &in.CertificateFrom, &out.CertificateFrom
|
||||||
|
*out = new(TLSCertificateSource)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubServerTLSConfig.
|
||||||
|
func (in *GitHubServerTLSConfig) DeepCopy() *GitHubServerTLSConfig {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(GitHubServerTLSConfig)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *HistogramMetric) DeepCopyInto(out *HistogramMetric) {
|
func (in *HistogramMetric) DeepCopyInto(out *HistogramMetric) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@@ -679,48 +668,3 @@ func (in *TLSCertificateSource) DeepCopy() *TLSCertificateSource {
|
|||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *TLSConfig) DeepCopyInto(out *TLSConfig) {
|
|
||||||
*out = *in
|
|
||||||
if in.CertificateFrom != nil {
|
|
||||||
in, out := &in.CertificateFrom, &out.CertificateFrom
|
|
||||||
*out = new(TLSCertificateSource)
|
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig.
|
|
||||||
func (in *TLSConfig) DeepCopy() *TLSConfig {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(TLSConfig)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *VaultConfig) DeepCopyInto(out *VaultConfig) {
|
|
||||||
*out = *in
|
|
||||||
if in.AzureKeyVault != nil {
|
|
||||||
in, out := &in.AzureKeyVault, &out.AzureKeyVault
|
|
||||||
*out = new(AzureKeyVaultConfig)
|
|
||||||
**out = **in
|
|
||||||
}
|
|
||||||
if in.Proxy != nil {
|
|
||||||
in, out := &in.Proxy, &out.Proxy
|
|
||||||
*out = new(ProxyConfig)
|
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultConfig.
|
|
||||||
func (in *VaultConfig) DeepCopy() *VaultConfig {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(VaultConfig)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ All additional docs are kept in the `docs/` folder, this README is solely for do
|
|||||||
| `image.pullPolicy` | The pull policy of the controller image | IfNotPresent |
|
| `image.pullPolicy` | The pull policy of the controller image | IfNotPresent |
|
||||||
| `metrics.serviceMonitor.enable` | Deploy serviceMonitor kind for for use with prometheus-operator CRDs | false |
|
| `metrics.serviceMonitor.enable` | Deploy serviceMonitor kind for for use with prometheus-operator CRDs | false |
|
||||||
| `metrics.serviceMonitor.interval` | Configure the interval that Prometheus should scrap the controller's metrics | 1m |
|
| `metrics.serviceMonitor.interval` | Configure the interval that Prometheus should scrap the controller's metrics | 1m |
|
||||||
| `metrics.serviceMonitor.namespace` | Namespace which Prometheus is running in | `Release.Namespace` (the default namespace of the helm chart). |
|
| `metrics.serviceMonitor.namespace | Namespace which Prometheus is running in | `Release.Namespace` (the default namespace of the helm chart). |
|
||||||
| `metrics.serviceMonitor.timeout` | Configure the timeout the timeout of Prometheus scrapping. | 30s |
|
| `metrics.serviceMonitor.timeout` | Configure the timeout the timeout of Prometheus scrapping. | 30s |
|
||||||
| `metrics.serviceAnnotations` | Set annotations for the provisioned metrics service resource | |
|
| `metrics.serviceAnnotations` | Set annotations for the provisioned metrics service resource | |
|
||||||
| `metrics.port` | Set port of metrics service | 8443 |
|
| `metrics.port` | Set port of metrics service | 8443 |
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.19.0
|
controller-gen.kubebuilder.io/version: v0.17.2
|
||||||
name: horizontalrunnerautoscalers.actions.summerwind.dev
|
name: horizontalrunnerautoscalers.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
group: actions.summerwind.dev
|
group: actions.summerwind.dev
|
||||||
@@ -12,313 +12,306 @@ 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
|
description: HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler API
|
||||||
API
|
properties:
|
||||||
properties:
|
apiVersion:
|
||||||
apiVersion:
|
description: |-
|
||||||
description: |-
|
APIVersion defines the versioned schema of this representation of an object.
|
||||||
APIVersion defines the versioned schema of this representation of an object.
|
Servers should convert recognized schemas to the latest internal value, and
|
||||||
Servers should convert recognized schemas to the latest internal value, and
|
may reject unrecognized values.
|
||||||
may reject unrecognized values.
|
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
type: string
|
||||||
type: string
|
kind:
|
||||||
kind:
|
description: |-
|
||||||
description: |-
|
Kind is a string value representing the REST resource this object represents.
|
||||||
Kind is a string value representing the REST resource this object represents.
|
Servers may infer this from the endpoint the client submits requests to.
|
||||||
Servers may infer this from the endpoint the client submits requests to.
|
Cannot be updated.
|
||||||
Cannot be updated.
|
In CamelCase.
|
||||||
In CamelCase.
|
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
type: string
|
||||||
type: string
|
metadata:
|
||||||
metadata:
|
type: object
|
||||||
type: object
|
spec:
|
||||||
spec:
|
description: HorizontalRunnerAutoscalerSpec defines the desired state of HorizontalRunnerAutoscaler
|
||||||
description: HorizontalRunnerAutoscalerSpec defines the desired state
|
properties:
|
||||||
of HorizontalRunnerAutoscaler
|
capacityReservations:
|
||||||
properties:
|
items:
|
||||||
capacityReservations:
|
description: |-
|
||||||
items:
|
CapacityReservation specifies the number of replicas temporarily added
|
||||||
description: |-
|
to the scale target until ExpirationTime.
|
||||||
CapacityReservation specifies the number of replicas temporarily added
|
|
||||||
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:
|
properties:
|
||||||
|
effectiveTime:
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
expirationTime:
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
required:
|
replicas:
|
||||||
- name
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: array
|
||||||
maxReplicas:
|
githubAPICredentialsFrom:
|
||||||
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:
|
properties:
|
||||||
repositoryNames:
|
secretRef:
|
||||||
description: |-
|
properties:
|
||||||
RepositoryNames is the list of repository names to be used for calculating the metric.
|
name:
|
||||||
For example, a repository name is the REPO part of `github.com/USER/REPO`.
|
type: string
|
||||||
items:
|
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
|
type: string
|
||||||
type: array
|
scaleDownThreshold:
|
||||||
scaleDownAdjustment:
|
description: |-
|
||||||
description: |-
|
ScaleDownThreshold is the percentage of busy runners less than which will
|
||||||
ScaleDownAdjustment is the number of runners removed on scale-down.
|
trigger the hpa to scale the runners down.
|
||||||
You can only specify either ScaleDownFactor or ScaleDownAdjustment.
|
type: string
|
||||||
type: integer
|
scaleUpAdjustment:
|
||||||
scaleDownFactor:
|
description: |-
|
||||||
description: |-
|
ScaleUpAdjustment is the number of runners added on scale-up.
|
||||||
ScaleDownFactor is the multiplicative factor applied to the current number of runners used
|
You can only specify either ScaleUpFactor or ScaleUpAdjustment.
|
||||||
to determine how many pods should be removed.
|
type: integer
|
||||||
type: string
|
scaleUpFactor:
|
||||||
scaleDownThreshold:
|
description: |-
|
||||||
description: |-
|
ScaleUpFactor is the multiplicative factor applied to the current number of runners used
|
||||||
ScaleDownThreshold is the percentage of busy runners less than which will
|
to determine how many pods should be added.
|
||||||
trigger the hpa to scale the runners down.
|
type: string
|
||||||
type: string
|
scaleUpThreshold:
|
||||||
scaleUpAdjustment:
|
description: |-
|
||||||
description: |-
|
ScaleUpThreshold is the percentage of busy runners greater than which will
|
||||||
ScaleUpAdjustment is the number of runners added on scale-up.
|
trigger the hpa to scale runners up.
|
||||||
You can only specify either ScaleUpFactor or ScaleUpAdjustment.
|
type: string
|
||||||
type: integer
|
type:
|
||||||
scaleUpFactor:
|
description: |-
|
||||||
description: |-
|
Type is the type of metric to be used for autoscaling.
|
||||||
ScaleUpFactor is the multiplicative factor applied to the current number of runners used
|
It can be TotalNumberOfQueuedAndInProgressWorkflowRuns or PercentageRunnersBusy.
|
||||||
to determine how many pods should be added.
|
type: string
|
||||||
type: string
|
type: object
|
||||||
scaleUpThreshold:
|
type: array
|
||||||
description: |-
|
minReplicas:
|
||||||
ScaleUpThreshold is the percentage of busy runners greater than which will
|
description: MinReplicas is the minimum number of replicas the deployment is allowed to scale
|
||||||
trigger the hpa to scale runners up.
|
type: integer
|
||||||
type: string
|
scaleDownDelaySecondsAfterScaleOut:
|
||||||
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: |-
|
||||||
ScheduledOverride can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule.
|
ScaleDownDelaySecondsAfterScaleUp is the approximate delay for a scale down followed by a scale up
|
||||||
A schedule can optionally be recurring, so that the corresponding override happens every day, week, month, or year.
|
Used to prevent flapping (down->up->down->... loop)
|
||||||
|
type: integer
|
||||||
|
scaleTargetRef:
|
||||||
|
description: ScaleTargetRef is the reference to scaled resource like RunnerDeployment
|
||||||
properties:
|
properties:
|
||||||
endTime:
|
kind:
|
||||||
description: EndTime is the time at which the first override
|
description: Kind is the type of resource being referenced
|
||||||
ends.
|
enum:
|
||||||
format: date-time
|
- RunnerDeployment
|
||||||
|
- RunnerSet
|
||||||
type: string
|
type: string
|
||||||
minReplicas:
|
name:
|
||||||
description: |-
|
description: Name is the name of resource being referenced
|
||||||
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:
|
|
||||||
- endTime
|
|
||||||
- startTime
|
|
||||||
type: object
|
type: object
|
||||||
type: array
|
scaleUpTriggers:
|
||||||
type: object
|
description: |-
|
||||||
status:
|
ScaleUpTriggers is an experimental feature to increase the desired replicas by 1
|
||||||
properties:
|
on each webhook requested received by the webhookBasedAutoscaler.
|
||||||
cacheEntries:
|
|
||||||
items:
|
This feature requires you to also enable and deploy the webhookBasedAutoscaler onto your cluster.
|
||||||
properties:
|
|
||||||
expirationTime:
|
Note that the added runners remain until the next sync period at least,
|
||||||
format: date-time
|
and they may or may not be used by GitHub Actions depending on the timing.
|
||||||
type: string
|
They are intended to be used to gain "resource slack" immediately after you
|
||||||
key:
|
receive a webhook from GitHub, so that you can loosely expect MinReplicas runners to be always available.
|
||||||
type: string
|
items:
|
||||||
value:
|
properties:
|
||||||
type: integer
|
amount:
|
||||||
type: object
|
type: integer
|
||||||
type: array
|
duration:
|
||||||
desiredReplicas:
|
type: string
|
||||||
description: |-
|
githubEvent:
|
||||||
DesiredReplicas is the total number of desired, non-terminated and latest pods to be set for the primary RunnerSet
|
properties:
|
||||||
This doesn't include outdated pods while upgrading the deployment and replacing the runnerset.
|
checkRun:
|
||||||
type: integer
|
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#check_run
|
||||||
lastSuccessfulScaleOutTime:
|
properties:
|
||||||
format: date-time
|
names:
|
||||||
nullable: true
|
description: |-
|
||||||
type: string
|
Names is a list of GitHub Actions glob patterns.
|
||||||
observedGeneration:
|
Any check_run event whose name matches one of patterns in the list can trigger autoscaling.
|
||||||
description: |-
|
Note that check_run name seem to equal to the job name you've defined in your actions workflow yaml file.
|
||||||
ObservedGeneration is the most recent generation observed for the target. It corresponds to e.g.
|
So it is very likely that you can utilize this to trigger depending on the job.
|
||||||
RunnerDeployment's generation, which is updated on mutation by the API Server.
|
items:
|
||||||
format: int64
|
type: string
|
||||||
type: integer
|
type: array
|
||||||
scheduledOverridesSummary:
|
repositories:
|
||||||
description: |-
|
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
|
Repositories is a list of GitHub repositories.
|
||||||
for observability.
|
Any check_run event whose repository matches one of repositories in the list can trigger autoscaling.
|
||||||
type: string
|
items:
|
||||||
type: object
|
type: string
|
||||||
type: object
|
type: array
|
||||||
served: true
|
status:
|
||||||
storage: true
|
type: string
|
||||||
subresources:
|
types:
|
||||||
status: {}
|
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
|
||||||
|
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: {}
|
||||||
|
preserveUnknownFields: false
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.19.0
|
controller-gen.kubebuilder.io/version: v0.17.2
|
||||||
name: runnersets.actions.summerwind.dev
|
name: runnersets.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
group: actions.summerwind.dev
|
group: actions.summerwind.dev
|
||||||
@@ -554,6 +554,7 @@ 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
|
||||||
@@ -568,6 +569,7 @@ 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
|
||||||
@@ -728,6 +730,7 @@ 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
|
||||||
@@ -742,6 +745,7 @@ 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
|
||||||
@@ -830,8 +834,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 subtracting
|
compute a sum by iterating through the elements of this field and adding
|
||||||
"weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
|
"weight" to 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)
|
||||||
@@ -895,6 +899,7 @@ 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
|
||||||
@@ -909,6 +914,7 @@ 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
|
||||||
@@ -1069,6 +1075,7 @@ 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
|
||||||
@@ -1083,6 +1090,7 @@ 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
|
||||||
@@ -1209,9 +1217,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -1265,42 +1271,6 @@ 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
|
||||||
@@ -1356,13 +1326,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -1382,9 +1352,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -1633,12 +1601,6 @@ 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: |-
|
||||||
@@ -2029,7 +1991,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -2080,10 +2042,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 overrides the pod-level restart policy. When this field is not specified,
|
This field may only be set for init containers, and the only allowed value is "Always".
|
||||||
|
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.
|
||||||
Additionally, setting the RestartPolicy as "Always" for the init container will
|
Setting the RestartPolicy as "Always" for the init container will have the following effect:
|
||||||
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"
|
||||||
@@ -2095,57 +2057,6 @@ 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.
|
||||||
@@ -2743,9 +2654,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -2799,42 +2708,6 @@ 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
|
||||||
@@ -2890,13 +2763,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -2916,9 +2789,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -3163,12 +3034,6 @@ 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.
|
||||||
@@ -3542,7 +3407,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -3594,51 +3459,9 @@ 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.
|
||||||
You cannot set this field on ephemeral containers.
|
This may only be set for init containers. You cannot set this field on
|
||||||
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.
|
ephemeral containers.
|
||||||
items:
|
type: string
|
||||||
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.
|
||||||
@@ -4157,9 +3980,7 @@ 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.
|
||||||
When using HostNetwork you should specify ports so the scheduler is aware.
|
If this option is set, the ports that will be used must be specified.
|
||||||
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:
|
||||||
@@ -4184,19 +4005,6 @@ 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.
|
||||||
@@ -4232,7 +4040,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
|
||||||
that value or the sum of the normal containers. Limits are applied to init containers
|
of 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.
|
||||||
@@ -4276,9 +4084,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -4332,42 +4138,6 @@ 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
|
||||||
@@ -4423,13 +4193,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -4449,9 +4219,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -4700,12 +4468,6 @@ 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: |-
|
||||||
@@ -5096,7 +4858,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -5147,10 +4909,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 overrides the pod-level restart policy. When this field is not specified,
|
This field may only be set for init containers, and the only allowed value is "Always".
|
||||||
|
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.
|
||||||
Additionally, setting the RestartPolicy as "Always" for the init container will
|
Setting the RestartPolicy as "Always" for the init container will have the following effect:
|
||||||
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"
|
||||||
@@ -5162,57 +4924,6 @@ 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.
|
||||||
@@ -5726,7 +5437,6 @@ 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
|
||||||
@@ -5878,7 +5588,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", "memory" and "hugepages-" resource names only. ResourceClaims are not supported.
|
"cpu" and "memory" 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.
|
||||||
@@ -5891,7 +5601,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -6416,6 +6126,7 @@ 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: |-
|
||||||
@@ -6426,6 +6137,7 @@ 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: |-
|
||||||
@@ -7131,13 +6843,15 @@ 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 or nil value indicates that no
|
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass
|
||||||
VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
|
will be applied to the claim but it's not allowed to reset this field to empty string once it is set.
|
||||||
this field can be reset to its previous value (including nil) to cancel the modification.
|
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass
|
||||||
|
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: |-
|
||||||
@@ -7311,9 +7025,12 @@ 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: endpoints is the endpoint name that details Glusterfs topology.
|
description: |-
|
||||||
|
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: |-
|
||||||
@@ -7367,7 +7084,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) before 1.33.
|
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath).
|
||||||
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:
|
||||||
@@ -7392,7 +7109,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://kubernetes.io/docs/concepts/storage/volumes/#iscsi
|
More info: https://examples.k8s.io/volumes/iscsi/README.md
|
||||||
properties:
|
properties:
|
||||||
chapAuthDiscovery:
|
chapAuthDiscovery:
|
||||||
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
|
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
|
||||||
@@ -7782,110 +7499,6 @@ 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:
|
||||||
@@ -8015,6 +7628,7 @@ 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: |-
|
||||||
@@ -8556,13 +8170,15 @@ 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 or nil value indicates that no
|
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass
|
||||||
VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
|
will be applied to the claim but it's not allowed to reset this field to empty string once it is set.
|
||||||
this field can be reset to its previous value (including nil) to cancel the modification.
|
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass
|
||||||
|
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: |-
|
||||||
@@ -8662,11 +8278,13 @@ 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."
|
||||||
@@ -8737,6 +8355,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- selector
|
- selector
|
||||||
|
- serviceName
|
||||||
- template
|
- template
|
||||||
type: object
|
type: object
|
||||||
status:
|
status:
|
||||||
@@ -8770,3 +8389,4 @@ spec:
|
|||||||
storage: true
|
storage: true
|
||||||
subresources:
|
subresources:
|
||||||
status: {}
|
status: {}
|
||||||
|
preserveUnknownFields: false
|
||||||
|
|||||||
@@ -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.13.0
|
version: 0.11.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.13.0"
|
appVersion: "0.11.0"
|
||||||
|
|
||||||
home: https://github.com/actions/actions-runner-controller
|
home: https://github.com/actions/actions-runner-controller
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.19.0
|
controller-gen.kubebuilder.io/version: v0.17.2
|
||||||
name: ephemeralrunners.actions.github.com
|
name: ephemeralrunners.actions.github.com
|
||||||
spec:
|
spec:
|
||||||
group: actions.github.com
|
group: actions.github.com
|
||||||
@@ -36,9 +36,6 @@ 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
|
||||||
@@ -430,6 +427,7 @@ 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
|
||||||
@@ -444,6 +442,7 @@ 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
|
||||||
@@ -604,6 +603,7 @@ 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,6 +618,7 @@ 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
|
||||||
@@ -706,8 +707,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 subtracting
|
compute a sum by iterating through the elements of this field and adding
|
||||||
"weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
|
"weight" to 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)
|
||||||
@@ -771,6 +772,7 @@ 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
|
||||||
@@ -785,6 +787,7 @@ 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
|
||||||
@@ -945,6 +948,7 @@ 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
|
||||||
@@ -959,6 +963,7 @@ 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
|
||||||
@@ -1085,9 +1090,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -1141,42 +1144,6 @@ 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
|
||||||
@@ -1232,13 +1199,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -1258,9 +1225,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -1509,12 +1474,6 @@ 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: |-
|
||||||
@@ -1905,7 +1864,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -1956,10 +1915,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 overrides the pod-level restart policy. When this field is not specified,
|
This field may only be set for init containers, and the only allowed value is "Always".
|
||||||
|
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.
|
||||||
Additionally, setting the RestartPolicy as "Always" for the init container will
|
Setting the RestartPolicy as "Always" for the init container will have the following effect:
|
||||||
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"
|
||||||
@@ -1971,57 +1930,6 @@ 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.
|
||||||
@@ -2619,9 +2527,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -2675,42 +2581,6 @@ 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
|
||||||
@@ -2766,13 +2636,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -2792,9 +2662,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -3039,12 +2907,6 @@ 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.
|
||||||
@@ -3418,7 +3280,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -3470,51 +3332,9 @@ 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.
|
||||||
You cannot set this field on ephemeral containers.
|
This may only be set for init containers. You cannot set this field on
|
||||||
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.
|
ephemeral containers.
|
||||||
items:
|
type: string
|
||||||
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.
|
||||||
@@ -4033,9 +3853,7 @@ 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.
|
||||||
When using HostNetwork you should specify ports so the scheduler is aware.
|
If this option is set, the ports that will be used must be specified.
|
||||||
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:
|
||||||
@@ -4060,19 +3878,6 @@ 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.
|
||||||
@@ -4108,7 +3913,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
|
||||||
that value or the sum of the normal containers. Limits are applied to init containers
|
of 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.
|
||||||
@@ -4152,9 +3957,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -4208,42 +4011,6 @@ 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
|
||||||
@@ -4299,13 +4066,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -4325,9 +4092,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -4576,12 +4341,6 @@ 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: |-
|
||||||
@@ -4972,7 +4731,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -5023,10 +4782,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 overrides the pod-level restart policy. When this field is not specified,
|
This field may only be set for init containers, and the only allowed value is "Always".
|
||||||
|
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.
|
||||||
Additionally, setting the RestartPolicy as "Always" for the init container will
|
Setting the RestartPolicy as "Always" for the init container will have the following effect:
|
||||||
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"
|
||||||
@@ -5038,57 +4797,6 @@ 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.
|
||||||
@@ -5602,7 +5310,6 @@ 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
|
||||||
@@ -5754,7 +5461,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", "memory" and "hugepages-" resource names only. ResourceClaims are not supported.
|
"cpu" and "memory" 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.
|
||||||
@@ -5767,7 +5474,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -6295,6 +6002,7 @@ 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: |-
|
||||||
@@ -6305,6 +6013,7 @@ 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: |-
|
||||||
@@ -7010,13 +6719,15 @@ 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 or nil value indicates that no
|
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass
|
||||||
VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
|
will be applied to the claim but it's not allowed to reset this field to empty string once it is set.
|
||||||
this field can be reset to its previous value (including nil) to cancel the modification.
|
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass
|
||||||
|
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: |-
|
||||||
@@ -7190,9 +6901,12 @@ 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: endpoints is the endpoint name that details Glusterfs topology.
|
description: |-
|
||||||
|
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: |-
|
||||||
@@ -7246,7 +6960,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) before 1.33.
|
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath).
|
||||||
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:
|
||||||
@@ -7271,7 +6985,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://kubernetes.io/docs/concepts/storage/volumes/#iscsi
|
More info: https://examples.k8s.io/volumes/iscsi/README.md
|
||||||
properties:
|
properties:
|
||||||
chapAuthDiscovery:
|
chapAuthDiscovery:
|
||||||
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
|
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
|
||||||
@@ -7661,110 +7375,6 @@ 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:
|
||||||
@@ -7894,6 +7504,7 @@ 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: |-
|
||||||
@@ -8173,53 +7784,6 @@ spec:
|
|||||||
required:
|
required:
|
||||||
- containers
|
- containers
|
||||||
type: object
|
type: object
|
||||||
vaultConfig:
|
|
||||||
properties:
|
|
||||||
azureKeyVault:
|
|
||||||
properties:
|
|
||||||
certificatePath:
|
|
||||||
type: string
|
|
||||||
clientId:
|
|
||||||
type: string
|
|
||||||
tenantId:
|
|
||||||
type: string
|
|
||||||
url:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- certificatePath
|
|
||||||
- clientId
|
|
||||||
- tenantId
|
|
||||||
- url
|
|
||||||
type: object
|
|
||||||
proxy:
|
|
||||||
properties:
|
|
||||||
http:
|
|
||||||
properties:
|
|
||||||
credentialSecretRef:
|
|
||||||
type: string
|
|
||||||
url:
|
|
||||||
description: Required
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
https:
|
|
||||||
properties:
|
|
||||||
credentialSecretRef:
|
|
||||||
type: string
|
|
||||||
url:
|
|
||||||
description: Required
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
noProxy:
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
type: object
|
|
||||||
type:
|
|
||||||
description: |-
|
|
||||||
VaultType represents the type of vault that can be used in the application.
|
|
||||||
It is used to identify which vault integration should be used to resolve secrets.
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
required:
|
required:
|
||||||
- githubConfigSecret
|
- githubConfigSecret
|
||||||
- githubConfigUrl
|
- githubConfigUrl
|
||||||
@@ -8230,13 +7794,10 @@ spec:
|
|||||||
properties:
|
properties:
|
||||||
failures:
|
failures:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
format: date-time
|
type: boolean
|
||||||
type: string
|
|
||||||
type: object
|
type: object
|
||||||
jobDisplayName:
|
jobDisplayName:
|
||||||
type: string
|
type: string
|
||||||
jobId:
|
|
||||||
type: string
|
|
||||||
jobRepositoryName:
|
jobRepositoryName:
|
||||||
type: string
|
type: string
|
||||||
jobRequestId:
|
jobRequestId:
|
||||||
@@ -8265,6 +7826,8 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
runnerId:
|
runnerId:
|
||||||
type: integer
|
type: integer
|
||||||
|
runnerJITConfig:
|
||||||
|
type: string
|
||||||
runnerName:
|
runnerName:
|
||||||
type: string
|
type: string
|
||||||
workflowRunId:
|
workflowRunId:
|
||||||
@@ -8276,3 +7839,4 @@ spec:
|
|||||||
storage: true
|
storage: true
|
||||||
subresources:
|
subresources:
|
||||||
status: {}
|
status: {}
|
||||||
|
preserveUnknownFields: false
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.19.0
|
controller-gen.kubebuilder.io/version: v0.17.2
|
||||||
name: ephemeralrunnersets.actions.github.com
|
name: ephemeralrunnersets.actions.github.com
|
||||||
spec:
|
spec:
|
||||||
group: actions.github.com
|
group: actions.github.com
|
||||||
@@ -421,6 +421,7 @@ 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
|
||||||
@@ -435,6 +436,7 @@ 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
|
||||||
@@ -595,6 +597,7 @@ 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
|
||||||
@@ -609,6 +612,7 @@ 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
|
||||||
@@ -697,8 +701,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 subtracting
|
compute a sum by iterating through the elements of this field and adding
|
||||||
"weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
|
"weight" to 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)
|
||||||
@@ -762,6 +766,7 @@ 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
|
||||||
@@ -776,6 +781,7 @@ 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
|
||||||
@@ -936,6 +942,7 @@ 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
|
||||||
@@ -950,6 +957,7 @@ 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
|
||||||
@@ -1076,9 +1084,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -1132,42 +1138,6 @@ 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
|
||||||
@@ -1223,13 +1193,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -1249,9 +1219,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -1500,12 +1468,6 @@ 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: |-
|
||||||
@@ -1896,7 +1858,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -1947,10 +1909,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 overrides the pod-level restart policy. When this field is not specified,
|
This field may only be set for init containers, and the only allowed value is "Always".
|
||||||
|
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.
|
||||||
Additionally, setting the RestartPolicy as "Always" for the init container will
|
Setting the RestartPolicy as "Always" for the init container will have the following effect:
|
||||||
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"
|
||||||
@@ -1962,57 +1924,6 @@ 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.
|
||||||
@@ -2610,9 +2521,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -2666,42 +2575,6 @@ 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
|
||||||
@@ -2757,13 +2630,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -2783,9 +2656,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -3030,12 +2901,6 @@ 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.
|
||||||
@@ -3409,7 +3274,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -3461,51 +3326,9 @@ 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.
|
||||||
You cannot set this field on ephemeral containers.
|
This may only be set for init containers. You cannot set this field on
|
||||||
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.
|
ephemeral containers.
|
||||||
items:
|
type: string
|
||||||
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.
|
||||||
@@ -4024,9 +3847,7 @@ 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.
|
||||||
When using HostNetwork you should specify ports so the scheduler is aware.
|
If this option is set, the ports that will be used must be specified.
|
||||||
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:
|
||||||
@@ -4051,19 +3872,6 @@ 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.
|
||||||
@@ -4099,7 +3907,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
|
||||||
that value or the sum of the normal containers. Limits are applied to init containers
|
of 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.
|
||||||
@@ -4143,9 +3951,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -4199,42 +4005,6 @@ 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
|
||||||
@@ -4290,13 +4060,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -4316,9 +4086,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -4567,12 +4335,6 @@ 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: |-
|
||||||
@@ -4963,7 +4725,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -5014,10 +4776,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 overrides the pod-level restart policy. When this field is not specified,
|
This field may only be set for init containers, and the only allowed value is "Always".
|
||||||
|
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.
|
||||||
Additionally, setting the RestartPolicy as "Always" for the init container will
|
Setting the RestartPolicy as "Always" for the init container will have the following effect:
|
||||||
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"
|
||||||
@@ -5029,57 +4791,6 @@ 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.
|
||||||
@@ -5593,7 +5304,6 @@ 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
|
||||||
@@ -5745,7 +5455,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", "memory" and "hugepages-" resource names only. ResourceClaims are not supported.
|
"cpu" and "memory" 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.
|
||||||
@@ -5758,7 +5468,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -6286,6 +5996,7 @@ 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: |-
|
||||||
@@ -6296,6 +6007,7 @@ 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: |-
|
||||||
@@ -7001,13 +6713,15 @@ 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 or nil value indicates that no
|
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass
|
||||||
VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
|
will be applied to the claim but it's not allowed to reset this field to empty string once it is set.
|
||||||
this field can be reset to its previous value (including nil) to cancel the modification.
|
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass
|
||||||
|
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: |-
|
||||||
@@ -7181,9 +6895,12 @@ 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: endpoints is the endpoint name that details Glusterfs topology.
|
description: |-
|
||||||
|
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: |-
|
||||||
@@ -7237,7 +6954,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) before 1.33.
|
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath).
|
||||||
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:
|
||||||
@@ -7262,7 +6979,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://kubernetes.io/docs/concepts/storage/volumes/#iscsi
|
More info: https://examples.k8s.io/volumes/iscsi/README.md
|
||||||
properties:
|
properties:
|
||||||
chapAuthDiscovery:
|
chapAuthDiscovery:
|
||||||
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
|
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
|
||||||
@@ -7652,110 +7369,6 @@ 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:
|
||||||
@@ -7885,6 +7498,7 @@ 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: |-
|
||||||
@@ -8164,53 +7778,6 @@ spec:
|
|||||||
required:
|
required:
|
||||||
- containers
|
- containers
|
||||||
type: object
|
type: object
|
||||||
vaultConfig:
|
|
||||||
properties:
|
|
||||||
azureKeyVault:
|
|
||||||
properties:
|
|
||||||
certificatePath:
|
|
||||||
type: string
|
|
||||||
clientId:
|
|
||||||
type: string
|
|
||||||
tenantId:
|
|
||||||
type: string
|
|
||||||
url:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- certificatePath
|
|
||||||
- clientId
|
|
||||||
- tenantId
|
|
||||||
- url
|
|
||||||
type: object
|
|
||||||
proxy:
|
|
||||||
properties:
|
|
||||||
http:
|
|
||||||
properties:
|
|
||||||
credentialSecretRef:
|
|
||||||
type: string
|
|
||||||
url:
|
|
||||||
description: Required
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
https:
|
|
||||||
properties:
|
|
||||||
credentialSecretRef:
|
|
||||||
type: string
|
|
||||||
url:
|
|
||||||
description: Required
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
noProxy:
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
type: object
|
|
||||||
type:
|
|
||||||
description: |-
|
|
||||||
VaultType represents the type of vault that can be used in the application.
|
|
||||||
It is used to identify which vault integration should be used to resolve secrets.
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
required:
|
required:
|
||||||
- githubConfigSecret
|
- githubConfigSecret
|
||||||
- githubConfigUrl
|
- githubConfigUrl
|
||||||
@@ -8245,3 +7812,4 @@ spec:
|
|||||||
storage: true
|
storage: true
|
||||||
subresources:
|
subresources:
|
||||||
status: {}
|
status: {}
|
||||||
|
preserveUnknownFields: false
|
||||||
|
|||||||
@@ -129,3 +129,11 @@ 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 }}
|
||||||
|
|||||||
@@ -54,9 +54,7 @@ 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 }}
|
||||||
{{- range . }}
|
- "--auto-scaler-image-pull-secrets={{ include "gha-runner-scale-set-controller.imagePullSecretsNames" . }}"
|
||||||
- "--auto-scaler-image-pull-secrets={{- .name -}}"
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- with .Values.flags.logLevel }}
|
{{- with .Values.flags.logLevel }}
|
||||||
- "--log-level={{ . }}"
|
- "--log-level={{ . }}"
|
||||||
|
|||||||
@@ -683,8 +683,7 @@ 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",
|
"--auto-scaler-image-pull-secrets=dockerhub,ghcr",
|
||||||
"--auto-scaler-image-pull-secrets=ghcr",
|
|
||||||
"--log-level=debug",
|
"--log-level=debug",
|
||||||
"--log-format=text",
|
"--log-format=text",
|
||||||
"--update-strategy=immediate",
|
"--update-strategy=immediate",
|
||||||
@@ -1080,7 +1079,6 @@ 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()
|
||||||
|
|
||||||
|
|||||||
@@ -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.13.0
|
version: 0.11.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.13.0"
|
appVersion: "0.11.0"
|
||||||
|
|
||||||
home: https://github.com/actions/actions-runner-controller
|
home: https://github.com/actions/actions-runner-controller
|
||||||
|
|
||||||
|
|||||||
@@ -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" . | replace "_" "-" }}-github-secret
|
{{- include "gha-runner-scale-set.fullname" . }}-github-secret
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- define "gha-runner-scale-set.noPermissionServiceAccountName" -}}
|
{{- define "gha-runner-scale-set.noPermissionServiceAccountName" -}}
|
||||||
{{- include "gha-runner-scale-set.fullname" . | replace "_" "-" }}-no-permission
|
{{- include "gha-runner-scale-set.fullname" . }}-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" . | replace "_" "-" }}-kube-mode
|
{{- include "gha-runner-scale-set.fullname" . }}-kube-mode
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- define "gha-runner-scale-set.dind-init-container" -}}
|
{{- define "gha-runner-scale-set.dind-init-container" -}}
|
||||||
@@ -106,17 +106,6 @@ env:
|
|||||||
value: "123"
|
value: "123"
|
||||||
securityContext:
|
securityContext:
|
||||||
privileged: true
|
privileged: true
|
||||||
{{- if (ge (.Capabilities.KubeVersion.Minor | int) 29) }}
|
|
||||||
restartPolicy: Always
|
|
||||||
startupProbe:
|
|
||||||
exec:
|
|
||||||
command:
|
|
||||||
- docker
|
|
||||||
- info
|
|
||||||
initialDelaySeconds: 0
|
|
||||||
failureThreshold: 24
|
|
||||||
periodSeconds: 5
|
|
||||||
{{- end }}
|
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: work
|
- name: work
|
||||||
mountPath: /home/runner/_work
|
mountPath: /home/runner/_work
|
||||||
@@ -377,101 +366,6 @@ 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 }}
|
||||||
|
|||||||
@@ -8,45 +8,26 @@ 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" . | replace "_" "-" }}
|
name: {{ include "gha-runner-scale-set.scale-set-name" . }}
|
||||||
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 }}
|
||||||
{{- range $k, $v := . }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- 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 }}
|
||||||
{{- range $k, $v := . }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- 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 }}
|
||||||
{{- range $k, $v := . }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- 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 }}
|
||||||
{{- range $k, $v := . }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- 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 }}
|
||||||
@@ -56,15 +37,14 @@ 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 (or (eq $containerMode.type "kubernetes") (eq $containerMode.type "kubernetes-novolume")) (not .Values.template.spec.serviceAccountName) }}
|
{{- if and $containerMode (eq $containerMode.type "kubernetes") (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") (ne $containerMode.type "kubernetes-novolume") (not .Values.template.spec.serviceAccountName) }}
|
{{- if and (ne $containerMode.type "kubernetes") (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 }}
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
githubConfigUrl: {{ required ".Values.githubConfigUrl is required" (trimSuffix "/" .Values.githubConfigUrl) }}
|
githubConfigUrl: {{ required ".Values.githubConfigUrl is required" (trimSuffix "/" .Values.githubConfigUrl) }}
|
||||||
githubConfigSecret: {{ include "gha-runner-scale-set.githubsecret" . }}
|
githubConfigSecret: {{ include "gha-runner-scale-set.githubsecret" . }}
|
||||||
@@ -85,24 +65,6 @@ spec:
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- if and .Values.keyVault .Values.keyVault.type }}
|
|
||||||
vaultConfig:
|
|
||||||
type: {{ .Values.keyVault.type }}
|
|
||||||
{{- if .Values.keyVault.proxy }}
|
|
||||||
proxy: {{- toYaml .Values.keyVault.proxy | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if eq .Values.keyVault.type "azure_key_vault" }}
|
|
||||||
azureKeyVault:
|
|
||||||
url: {{ .Values.keyVault.azureKeyVault.url }}
|
|
||||||
tenantId: {{ .Values.keyVault.azureKeyVault.tenantId }}
|
|
||||||
clientId: {{ .Values.keyVault.azureKeyVault.clientId }}
|
|
||||||
certificatePath: {{ .Values.keyVault.azureKeyVault.certificatePath }}
|
|
||||||
secretKey: {{ .Values.keyVault.azureKeyVault.secretKey }}
|
|
||||||
{{- else }}
|
|
||||||
{{- fail "Unsupported keyVault type: " .Values.keyVault.type }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- if .Values.proxy }}
|
{{- if .Values.proxy }}
|
||||||
proxy:
|
proxy:
|
||||||
{{- if .Values.proxy.http }}
|
{{- if .Values.proxy.http }}
|
||||||
@@ -176,7 +138,7 @@ spec:
|
|||||||
restartPolicy: Never
|
restartPolicy: Never
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- $containerMode := .Values.containerMode }}
|
{{- $containerMode := .Values.containerMode }}
|
||||||
{{- if or (eq $containerMode.type "kubernetes") (eq $containerMode.type "kubernetes-novolume") }}
|
{{- if eq $containerMode.type "kubernetes" }}
|
||||||
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 }}
|
||||||
@@ -185,11 +147,7 @@ spec:
|
|||||||
initContainers:
|
initContainers:
|
||||||
{{- if eq $containerMode.type "dind" }}
|
{{- if eq $containerMode.type "dind" }}
|
||||||
- name: init-dind-externals
|
- name: init-dind-externals
|
||||||
{{- include "gha-runner-scale-set.dind-init-container" . | nindent 8 }}
|
{{- include "gha-runner-scale-set.dind-init-container" . | nindent 8 }}
|
||||||
{{- if (ge (.Capabilities.KubeVersion.Minor | int) 29) }}
|
|
||||||
- name: dind
|
|
||||||
{{- include "gha-runner-scale-set.dind-container" . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- with .Values.template.spec.initContainers }}
|
{{- with .Values.template.spec.initContainers }}
|
||||||
{{- toYaml . | nindent 6 }}
|
{{- toYaml . | nindent 6 }}
|
||||||
@@ -199,24 +157,18 @@ spec:
|
|||||||
{{- if eq $containerMode.type "dind" }}
|
{{- if eq $containerMode.type "dind" }}
|
||||||
- name: runner
|
- name: runner
|
||||||
{{- include "gha-runner-scale-set.dind-runner-container" . | nindent 8 }}
|
{{- include "gha-runner-scale-set.dind-runner-container" . | nindent 8 }}
|
||||||
{{- if not (ge (.Capabilities.KubeVersion.Minor | int) 29) }}
|
|
||||||
- name: dind
|
- name: dind
|
||||||
{{- include "gha-runner-scale-set.dind-container" . | nindent 8 }}
|
{{- include "gha-runner-scale-set.dind-container" . | nindent 8 }}
|
||||||
{{- end }}
|
|
||||||
{{- include "gha-runner-scale-set.non-runner-non-dind-containers" . | nindent 6 }}
|
{{- include "gha-runner-scale-set.non-runner-non-dind-containers" . | nindent 6 }}
|
||||||
{{- else if eq $containerMode.type "kubernetes" }}
|
{{- else if eq $containerMode.type "kubernetes" }}
|
||||||
- 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") (eq $containerMode.type "kubernetes-novolume") $tlsConfig.runnerMountPath }}
|
{{- if or .Values.template.spec.volumes (eq $containerMode.type "dind") (eq $containerMode.type "kubernetes") $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 }}
|
||||||
|
|||||||
@@ -6,15 +6,8 @@ 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 }}
|
||||||
{{- range $k, $v := . }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- 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 }}
|
||||||
|
|||||||
@@ -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 (or (eq $containerMode.type "kubernetes") (eq $containerMode.type "kubernetes-novolume")) (not .Values.template.spec.serviceAccountName) }}
|
{{- if and (eq $containerMode.type "kubernetes") (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,15 +8,8 @@ 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 }}
|
||||||
{{- range $k, $v := . }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- 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 }}
|
||||||
@@ -36,24 +29,19 @@ 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",]
|
||||||
{{- if ne $containerMode.type "kubernetes-novolume" }}
|
- apiGroups: ["batch"]
|
||||||
- apiGroups: ["batch"]
|
resources: ["jobs"]
|
||||||
resources: ["jobs"]
|
verbs: ["get", "list", "create", "delete"]
|
||||||
verbs: ["get", "list", "create", "delete"]
|
- apiGroups: [""]
|
||||||
{{- end }}
|
resources: ["secrets"]
|
||||||
- apiGroups: [""]
|
verbs: ["get", "list", "create", "delete"]
|
||||||
resources: ["secrets"]
|
|
||||||
verbs: ["get", "list", "create", "delete"]
|
|
||||||
{{- with $containerMode.kubernetesModeAdditionalRoleRules}}
|
|
||||||
{{- toYaml . | nindent 2}}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,21 +1,14 @@
|
|||||||
{{- $containerMode := .Values.containerMode }}
|
{{- $containerMode := .Values.containerMode }}
|
||||||
{{- $hasCustomResourceMeta := (and .Values.resourceMeta .Values.resourceMeta.kubernetesModeRoleBinding) }}
|
{{- $hasCustomResourceMeta := (and .Values.resourceMeta .Values.resourceMeta.kubernetesModeRoleBinding) }}
|
||||||
{{- if and (or (eq $containerMode.type "kubernetes") (eq $containerMode.type "kubernetes-novolume")) (not .Values.template.spec.serviceAccountName) }}
|
{{- if and (eq $containerMode.type "kubernetes") (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 }}
|
||||||
{{- range $k, $v := . }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- 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 }}
|
||||||
|
|||||||
@@ -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 (or (eq $containerMode.type "kubernetes") (eq $containerMode.type "kubernetes-novolume")) (not .Values.template.spec.serviceAccountName) }}
|
{{- if and (eq $containerMode.type "kubernetes") (not .Values.template.spec.serviceAccountName) }}
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
metadata:
|
metadata:
|
||||||
@@ -18,15 +18,8 @@ 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 }}
|
||||||
{{- range $k, $v := . }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- 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 }}
|
||||||
|
|||||||
@@ -5,15 +5,8 @@ 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 }}
|
||||||
{{- range $k, $v := . }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- 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 }}
|
||||||
|
|||||||
@@ -5,15 +5,8 @@ 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 }}
|
||||||
{{- range $k, $v := . }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- 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 }}
|
||||||
|
|||||||
@@ -7,15 +7,8 @@ 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 }}
|
||||||
{{- range $k, $v := . }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- 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 }}
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ 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)
|
||||||
@@ -269,72 +270,6 @@ 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()
|
||||||
|
|
||||||
@@ -793,20 +728,20 @@ func TestTemplateRenderedAutoScalingRunnerSet_DinD_ExtraInitContainers(t *testin
|
|||||||
var ars v1alpha1.AutoscalingRunnerSet
|
var ars v1alpha1.AutoscalingRunnerSet
|
||||||
helm.UnmarshalK8SYaml(t, output, &ars)
|
helm.UnmarshalK8SYaml(t, output, &ars)
|
||||||
|
|
||||||
assert.Len(t, ars.Spec.Template.Spec.InitContainers, 4, "InitContainers should be 4")
|
assert.Len(t, ars.Spec.Template.Spec.InitContainers, 3, "InitContainers should be 3")
|
||||||
assert.Equal(t, "kube-init", ars.Spec.Template.Spec.InitContainers[2].Name, "InitContainers[1] Name should be kube-init")
|
assert.Equal(t, "kube-init", ars.Spec.Template.Spec.InitContainers[1].Name, "InitContainers[1] Name should be kube-init")
|
||||||
assert.Equal(t, "runner-image:latest", ars.Spec.Template.Spec.InitContainers[2].Image, "InitContainers[1] Image should be runner-image:latest")
|
assert.Equal(t, "runner-image:latest", ars.Spec.Template.Spec.InitContainers[1].Image, "InitContainers[1] Image should be runner-image:latest")
|
||||||
assert.Equal(t, "sudo", ars.Spec.Template.Spec.InitContainers[2].Command[0], "InitContainers[1] Command[0] should be sudo")
|
assert.Equal(t, "sudo", ars.Spec.Template.Spec.InitContainers[1].Command[0], "InitContainers[1] Command[0] should be sudo")
|
||||||
assert.Equal(t, "chown", ars.Spec.Template.Spec.InitContainers[2].Command[1], "InitContainers[1] Command[1] should be chown")
|
assert.Equal(t, "chown", ars.Spec.Template.Spec.InitContainers[1].Command[1], "InitContainers[1] Command[1] should be chown")
|
||||||
assert.Equal(t, "-R", ars.Spec.Template.Spec.InitContainers[2].Command[2], "InitContainers[1] Command[2] should be -R")
|
assert.Equal(t, "-R", ars.Spec.Template.Spec.InitContainers[1].Command[2], "InitContainers[1] Command[2] should be -R")
|
||||||
assert.Equal(t, "1001:123", ars.Spec.Template.Spec.InitContainers[2].Command[3], "InitContainers[1] Command[3] should be 1001:123")
|
assert.Equal(t, "1001:123", ars.Spec.Template.Spec.InitContainers[1].Command[3], "InitContainers[1] Command[3] should be 1001:123")
|
||||||
assert.Equal(t, "/home/runner/_work", ars.Spec.Template.Spec.InitContainers[2].Command[4], "InitContainers[1] Command[4] should be /home/runner/_work")
|
assert.Equal(t, "/home/runner/_work", ars.Spec.Template.Spec.InitContainers[1].Command[4], "InitContainers[1] Command[4] should be /home/runner/_work")
|
||||||
assert.Equal(t, "work", ars.Spec.Template.Spec.InitContainers[2].VolumeMounts[0].Name, "InitContainers[1] VolumeMounts[0] Name should be work")
|
assert.Equal(t, "work", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[0].Name, "InitContainers[1] VolumeMounts[0] Name should be work")
|
||||||
assert.Equal(t, "/home/runner/_work", ars.Spec.Template.Spec.InitContainers[2].VolumeMounts[0].MountPath, "InitContainers[1] VolumeMounts[0] MountPath should be /home/runner/_work")
|
assert.Equal(t, "/home/runner/_work", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[0].MountPath, "InitContainers[1] VolumeMounts[0] MountPath should be /home/runner/_work")
|
||||||
|
|
||||||
assert.Equal(t, "ls", ars.Spec.Template.Spec.InitContainers[3].Name, "InitContainers[2] Name should be ls")
|
assert.Equal(t, "ls", ars.Spec.Template.Spec.InitContainers[2].Name, "InitContainers[2] Name should be ls")
|
||||||
assert.Equal(t, "ubuntu:latest", ars.Spec.Template.Spec.InitContainers[3].Image, "InitContainers[2] Image should be ubuntu:latest")
|
assert.Equal(t, "ubuntu:latest", ars.Spec.Template.Spec.InitContainers[2].Image, "InitContainers[2] Image should be ubuntu:latest")
|
||||||
assert.Equal(t, "ls", ars.Spec.Template.Spec.InitContainers[3].Command[0], "InitContainers[2] Command[0] should be ls")
|
assert.Equal(t, "ls", ars.Spec.Template.Spec.InitContainers[2].Command[0], "InitContainers[2] Command[0] should be ls")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTemplateRenderedAutoScalingRunnerSet_DinD_ExtraVolumes(t *testing.T) {
|
func TestTemplateRenderedAutoScalingRunnerSet_DinD_ExtraVolumes(t *testing.T) {
|
||||||
@@ -925,26 +860,13 @@ func TestTemplateRenderedAutoScalingRunnerSet_EnableDinD(t *testing.T) {
|
|||||||
|
|
||||||
assert.NotNil(t, ars.Spec.Template.Spec, "Template.Spec should not be nil")
|
assert.NotNil(t, ars.Spec.Template.Spec, "Template.Spec should not be nil")
|
||||||
|
|
||||||
assert.Len(t, ars.Spec.Template.Spec.InitContainers, 2, "Template.Spec should have 2 init container")
|
assert.Len(t, ars.Spec.Template.Spec.InitContainers, 1, "Template.Spec should have 1 init container")
|
||||||
assert.Equal(t, "init-dind-externals", ars.Spec.Template.Spec.InitContainers[0].Name)
|
assert.Equal(t, "init-dind-externals", ars.Spec.Template.Spec.InitContainers[0].Name)
|
||||||
assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.InitContainers[0].Image)
|
assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.InitContainers[0].Image)
|
||||||
assert.Equal(t, "cp", ars.Spec.Template.Spec.InitContainers[0].Command[0])
|
assert.Equal(t, "cp", ars.Spec.Template.Spec.InitContainers[0].Command[0])
|
||||||
assert.Equal(t, "-r /home/runner/externals/. /home/runner/tmpDir/", strings.Join(ars.Spec.Template.Spec.InitContainers[0].Args, " "))
|
assert.Equal(t, "-r /home/runner/externals/. /home/runner/tmpDir/", strings.Join(ars.Spec.Template.Spec.InitContainers[0].Args, " "))
|
||||||
|
|
||||||
assert.Equal(t, "dind", ars.Spec.Template.Spec.InitContainers[1].Name)
|
assert.Len(t, ars.Spec.Template.Spec.Containers, 2, "Template.Spec should have 2 container")
|
||||||
assert.Equal(t, "docker:dind", ars.Spec.Template.Spec.InitContainers[1].Image)
|
|
||||||
assert.True(t, *ars.Spec.Template.Spec.InitContainers[1].SecurityContext.Privileged)
|
|
||||||
assert.Len(t, ars.Spec.Template.Spec.InitContainers[1].VolumeMounts, 3, "The dind container should have 3 volume mounts, dind-sock, work and externals")
|
|
||||||
assert.Equal(t, "work", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[0].Name)
|
|
||||||
assert.Equal(t, "/home/runner/_work", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[0].MountPath)
|
|
||||||
|
|
||||||
assert.Equal(t, "dind-sock", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[1].Name)
|
|
||||||
assert.Equal(t, "/var/run", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[1].MountPath)
|
|
||||||
|
|
||||||
assert.Equal(t, "dind-externals", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[2].Name)
|
|
||||||
assert.Equal(t, "/home/runner/externals", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[2].MountPath)
|
|
||||||
|
|
||||||
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, "runner", ars.Spec.Template.Spec.Containers[0].Name)
|
||||||
assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.Containers[0].Image)
|
assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.Containers[0].Image)
|
||||||
assert.Len(t, ars.Spec.Template.Spec.Containers[0].Env, 2, "The runner container should have 2 env vars, DOCKER_HOST and RUNNER_WAIT_FOR_DOCKER_IN_SECONDS")
|
assert.Len(t, ars.Spec.Template.Spec.Containers[0].Env, 2, "The runner container should have 2 env vars, DOCKER_HOST and RUNNER_WAIT_FOR_DOCKER_IN_SECONDS")
|
||||||
@@ -961,6 +883,19 @@ func TestTemplateRenderedAutoScalingRunnerSet_EnableDinD(t *testing.T) {
|
|||||||
assert.Equal(t, "dind-sock", ars.Spec.Template.Spec.Containers[0].VolumeMounts[1].Name)
|
assert.Equal(t, "dind-sock", ars.Spec.Template.Spec.Containers[0].VolumeMounts[1].Name)
|
||||||
assert.Equal(t, "/var/run", ars.Spec.Template.Spec.Containers[0].VolumeMounts[1].MountPath)
|
assert.Equal(t, "/var/run", ars.Spec.Template.Spec.Containers[0].VolumeMounts[1].MountPath)
|
||||||
|
|
||||||
|
assert.Equal(t, "dind", ars.Spec.Template.Spec.Containers[1].Name)
|
||||||
|
assert.Equal(t, "docker:dind", ars.Spec.Template.Spec.Containers[1].Image)
|
||||||
|
assert.True(t, *ars.Spec.Template.Spec.Containers[1].SecurityContext.Privileged)
|
||||||
|
assert.Len(t, ars.Spec.Template.Spec.Containers[1].VolumeMounts, 3, "The dind container should have 3 volume mounts, dind-sock, work and externals")
|
||||||
|
assert.Equal(t, "work", ars.Spec.Template.Spec.Containers[1].VolumeMounts[0].Name)
|
||||||
|
assert.Equal(t, "/home/runner/_work", ars.Spec.Template.Spec.Containers[1].VolumeMounts[0].MountPath)
|
||||||
|
|
||||||
|
assert.Equal(t, "dind-sock", ars.Spec.Template.Spec.Containers[1].VolumeMounts[1].Name)
|
||||||
|
assert.Equal(t, "/var/run", ars.Spec.Template.Spec.Containers[1].VolumeMounts[1].MountPath)
|
||||||
|
|
||||||
|
assert.Equal(t, "dind-externals", ars.Spec.Template.Spec.Containers[1].VolumeMounts[2].Name)
|
||||||
|
assert.Equal(t, "/home/runner/externals", ars.Spec.Template.Spec.Containers[1].VolumeMounts[2].MountPath)
|
||||||
|
|
||||||
assert.Len(t, ars.Spec.Template.Spec.Volumes, 3, "Volumes should be 3")
|
assert.Len(t, ars.Spec.Template.Spec.Volumes, 3, "Volumes should be 3")
|
||||||
assert.Equal(t, "dind-sock", ars.Spec.Template.Spec.Volumes[0].Name, "Volume name should be dind-sock")
|
assert.Equal(t, "dind-sock", ars.Spec.Template.Spec.Volumes[0].Name, "Volume name should be dind-sock")
|
||||||
assert.Equal(t, "dind-externals", ars.Spec.Template.Spec.Volumes[1].Name, "Volume name should be dind-externals")
|
assert.Equal(t, "dind-externals", ars.Spec.Template.Spec.Volumes[1].Name, "Volume name should be dind-externals")
|
||||||
@@ -1026,65 +961,6 @@ 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()
|
||||||
|
|
||||||
@@ -1264,7 +1140,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{
|
||||||
@@ -1282,7 +1158,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
|
|||||||
ars := render(t, options)
|
ars := render(t, options)
|
||||||
|
|
||||||
require.NotNil(t, ars.Spec.GitHubServerTLS)
|
require.NotNil(t, ars.Spec.GitHubServerTLS)
|
||||||
expected := &v1alpha1.TLSConfig{
|
expected := &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
@@ -1323,7 +1199,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{
|
||||||
@@ -1342,7 +1218,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
|
|||||||
ars := render(t, options)
|
ars := render(t, options)
|
||||||
|
|
||||||
require.NotNil(t, ars.Spec.GitHubServerTLS)
|
require.NotNil(t, ars.Spec.GitHubServerTLS)
|
||||||
expected := &v1alpha1.TLSConfig{
|
expected := &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
@@ -1383,7 +1259,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{
|
||||||
@@ -1402,67 +1278,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
|
|||||||
ars := render(t, options)
|
ars := render(t, options)
|
||||||
|
|
||||||
require.NotNil(t, ars.Spec.GitHubServerTLS)
|
require.NotNil(t, ars.Spec.GitHubServerTLS)
|
||||||
expected := &v1alpha1.TLSConfig{
|
expected := &v1alpha1.GitHubServerTLSConfig{
|
||||||
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("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{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
@@ -1505,7 +1321,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
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{
|
||||||
@@ -1522,7 +1338,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
|
|||||||
ars := render(t, options)
|
ars := render(t, options)
|
||||||
|
|
||||||
require.NotNil(t, ars.Spec.GitHubServerTLS)
|
require.NotNil(t, ars.Spec.GitHubServerTLS)
|
||||||
expected := &v1alpha1.TLSConfig{
|
expected := &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
@@ -1560,7 +1376,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{
|
||||||
@@ -1578,7 +1394,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
|
|||||||
ars := render(t, options)
|
ars := render(t, options)
|
||||||
|
|
||||||
require.NotNil(t, ars.Spec.GitHubServerTLS)
|
require.NotNil(t, ars.Spec.GitHubServerTLS)
|
||||||
expected := &v1alpha1.TLSConfig{
|
expected := &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
@@ -1616,7 +1432,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{
|
||||||
@@ -1634,63 +1450,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) {
|
|||||||
ars := render(t, options)
|
ars := render(t, options)
|
||||||
|
|
||||||
require.NotNil(t, ars.Spec.GitHubServerTLS)
|
require.NotNil(t, ars.Spec.GitHubServerTLS)
|
||||||
expected := &v1alpha1.TLSConfig{
|
expected := &v1alpha1.GitHubServerTLSConfig{
|
||||||
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",
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
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{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
@@ -2066,7 +1826,7 @@ func TestTemplateRenderedAutoScalingRunnerSet_DinDMergePodSpec(t *testing.T) {
|
|||||||
var ars v1alpha1.AutoscalingRunnerSet
|
var ars v1alpha1.AutoscalingRunnerSet
|
||||||
helm.UnmarshalK8SYaml(t, output, &ars)
|
helm.UnmarshalK8SYaml(t, output, &ars)
|
||||||
|
|
||||||
assert.Len(t, ars.Spec.Template.Spec.Containers, 1, "There should be 1 containers")
|
assert.Len(t, ars.Spec.Template.Spec.Containers, 2, "There should be 2 containers")
|
||||||
assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name, "Container name should be runner")
|
assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name, "Container name should be runner")
|
||||||
assert.Equal(t, "250m", ars.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().String(), "CPU Limit should be set")
|
assert.Equal(t, "250m", ars.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().String(), "CPU Limit should be set")
|
||||||
assert.Equal(t, "64Mi", ars.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().String(), "Memory Limit should be set")
|
assert.Equal(t, "64Mi", ars.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().String(), "Memory Limit should be set")
|
||||||
@@ -2191,44 +1951,40 @@ func TestTemplateRenderedAutoscalingRunnerSetAnnotation_GitHubSecret(t *testing.
|
|||||||
func TestTemplateRenderedAutoscalingRunnerSetAnnotation_KubernetesModeCleanup(t *testing.T) {
|
func TestTemplateRenderedAutoscalingRunnerSetAnnotation_KubernetesModeCleanup(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
for _, mode := range []string{"kubernetes", "kubernetes-novolume"} {
|
// Path to the helm chart we will test
|
||||||
t.Run("containerMode "+mode, func(t *testing.T) {
|
helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
|
||||||
// Path to the helm chart we will test
|
require.NoError(t, err)
|
||||||
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": mode,
|
"containerMode.type": "kubernetes",
|
||||||
},
|
},
|
||||||
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))
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2660,21 +2416,6 @@ 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{
|
||||||
@@ -2690,21 +2431,6 @@ 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{
|
||||||
@@ -2720,21 +2446,6 @@ 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 {
|
||||||
@@ -2757,43 +2468,3 @@ func TestNamespaceOverride(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAutoscalingRunnerSetCustomAnnotationsAndLabelsApplied(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",
|
|
||||||
"controllerServiceAccount.name": "arc",
|
|
||||||
"controllerServiceAccount.namespace": "arc-system",
|
|
||||||
"annotations.actions\\.github\\.com/vault": "azure_key_vault",
|
|
||||||
"annotations.actions\\.github\\.com/cleanup-manager-role-name": "not-propagated",
|
|
||||||
"labels.custom": "custom",
|
|
||||||
"labels.app\\.kubernetes\\.io/component": "not-propagated",
|
|
||||||
},
|
|
||||||
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
|
|
||||||
}
|
|
||||||
|
|
||||||
output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
|
|
||||||
|
|
||||||
var autoscalingRunnerSet v1alpha1.AutoscalingRunnerSet
|
|
||||||
helm.UnmarshalK8SYaml(t, output, &autoscalingRunnerSet)
|
|
||||||
|
|
||||||
vault := autoscalingRunnerSet.Annotations["actions.github.com/vault"]
|
|
||||||
assert.Equal(t, "azure_key_vault", vault)
|
|
||||||
|
|
||||||
custom := autoscalingRunnerSet.Labels["custom"]
|
|
||||||
assert.Equal(t, "custom", custom)
|
|
||||||
|
|
||||||
assert.NotEqual(t, "not-propagated", autoscalingRunnerSet.Annotations["actions.github.com/cleanup-manager-role-name"])
|
|
||||||
assert.NotEqual(t, "not-propagated", autoscalingRunnerSet.Labels["app.kubernetes.io/component"])
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
## 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 or https://github.com/enterprises/myenterprise
|
## ex: https://github.com/myorg/myrepo or https://github.com/myorg
|
||||||
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.
|
||||||
## You can choose to supply:
|
## You can choose to supply:
|
||||||
## A) a PAT token,
|
## A) a PAT token,
|
||||||
## B) a GitHub App, or
|
## B) a GitHub App, or
|
||||||
## C) a pre-defined secret.
|
## C) a pre-defined Kubernetes secret.
|
||||||
## The syntax for each of these variations is documented below.
|
## The syntax for each of these variations is documented below.
|
||||||
## (Variation A) When using a PAT token, the syntax is as follows:
|
## (Variation A) When using a PAT token, the syntax is as follows:
|
||||||
githubConfigSecret:
|
githubConfigSecret:
|
||||||
@@ -17,7 +17,6 @@ githubConfigSecret:
|
|||||||
## (Variation B) When using a GitHub App, the syntax is as follows:
|
## (Variation B) When using a GitHub App, the syntax is as follows:
|
||||||
# githubConfigSecret:
|
# githubConfigSecret:
|
||||||
# # NOTE: IDs MUST be strings, use quotes
|
# # NOTE: IDs MUST be strings, use quotes
|
||||||
# # The github_app_id can be an app_id or the client_id
|
|
||||||
# github_app_id: ""
|
# github_app_id: ""
|
||||||
# github_app_installation_id: ""
|
# github_app_installation_id: ""
|
||||||
# github_app_private_key: |
|
# github_app_private_key: |
|
||||||
@@ -28,11 +27,8 @@ githubConfigSecret:
|
|||||||
# .
|
# .
|
||||||
# private key line N
|
# private key line N
|
||||||
#
|
#
|
||||||
## (Variation C) When using a pre-defined secret.
|
## (Variation C) When using a pre-defined Kubernetes secret in the same namespace that the gha-runner-scale-set is going to deploy,
|
||||||
## The secret can be pulled either directly from Kubernetes, or from the vault, depending on configuration.
|
## the syntax is as follows:
|
||||||
## Kubernetes secret in the same namespace that the gha-runner-scale-set is going to deploy.
|
|
||||||
## On the other hand, if the vault is configured, secret name will be used to fetch the app configuration.
|
|
||||||
## The syntax is as follows:
|
|
||||||
# githubConfigSecret: pre-defined-secret
|
# githubConfigSecret: pre-defined-secret
|
||||||
## Notes on using pre-defined Kubernetes secrets:
|
## Notes on using pre-defined Kubernetes secrets:
|
||||||
## You need to make sure your predefined secret has all the required secret data set properly.
|
## You need to make sure your predefined secret has all the required secret data set properly.
|
||||||
@@ -88,26 +84,6 @@ githubConfigSecret:
|
|||||||
# key: ca.crt
|
# key: ca.crt
|
||||||
# runnerMountPath: /usr/local/share/ca-certificates/
|
# runnerMountPath: /usr/local/share/ca-certificates/
|
||||||
|
|
||||||
# keyVault:
|
|
||||||
# Available values: "azure_key_vault"
|
|
||||||
# type: ""
|
|
||||||
# Configuration related to azure key vault
|
|
||||||
# azure_key_vault:
|
|
||||||
# url: ""
|
|
||||||
# client_id: ""
|
|
||||||
# tenant_id: ""
|
|
||||||
# certificate_path: ""
|
|
||||||
# proxy:
|
|
||||||
# http:
|
|
||||||
# url: http://proxy.com:1234
|
|
||||||
# credentialSecretRef: proxy-auth # a secret with `username` and `password` keys
|
|
||||||
# https:
|
|
||||||
# url: http://proxy.com:1234
|
|
||||||
# credentialSecretRef: proxy-auth # a secret with `username` and `password` keys
|
|
||||||
# noProxy:
|
|
||||||
# - example.com
|
|
||||||
# - example.org
|
|
||||||
|
|
||||||
## Container mode is an object that provides out-of-box configuration
|
## Container mode is an object that provides out-of-box configuration
|
||||||
## for dind and kubernetes mode. Template will be modified as documented under the
|
## for dind and kubernetes mode. Template will be modified as documented under the
|
||||||
## template object.
|
## template object.
|
||||||
@@ -115,7 +91,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", "kubernetes", or "kubernetes-novolume"
|
# type: "dind" ## type can be set to dind or kubernetes
|
||||||
# ## the following is required when containerMode.type=kubernetes
|
# ## the following is required when containerMode.type=kubernetes
|
||||||
# kubernetesModeWorkVolumeClaim:
|
# kubernetesModeWorkVolumeClaim:
|
||||||
# accessModes: ["ReadWriteOnce"]
|
# accessModes: ["ReadWriteOnce"]
|
||||||
@@ -124,7 +100,6 @@ 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
|
||||||
@@ -155,7 +130,7 @@ githubConfigSecret:
|
|||||||
# counters:
|
# counters:
|
||||||
# gha_started_jobs_total:
|
# gha_started_jobs_total:
|
||||||
# labels:
|
# labels:
|
||||||
# ["repository", "organization", "enterprise", "job_name", "event_name", "job_workflow_ref", "job_workflow_name", "job_workflow_target"]
|
# ["repository", "organization", "enterprise", "job_name", "event_name"]
|
||||||
# gha_completed_jobs_total:
|
# gha_completed_jobs_total:
|
||||||
# labels:
|
# labels:
|
||||||
# [
|
# [
|
||||||
@@ -165,9 +140,6 @@ githubConfigSecret:
|
|||||||
# "job_name",
|
# "job_name",
|
||||||
# "event_name",
|
# "event_name",
|
||||||
# "job_result",
|
# "job_result",
|
||||||
# "job_workflow_ref",
|
|
||||||
# "job_workflow_name",
|
|
||||||
# "job_workflow_target",
|
|
||||||
# ]
|
# ]
|
||||||
# gauges:
|
# gauges:
|
||||||
# gha_assigned_jobs:
|
# gha_assigned_jobs:
|
||||||
@@ -189,7 +161,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", "job_workflow_name", "job_workflow_target"]
|
# ["repository", "organization", "enterprise", "job_name", "event_name"]
|
||||||
# buckets:
|
# buckets:
|
||||||
# [
|
# [
|
||||||
# 0.01,
|
# 0.01,
|
||||||
@@ -247,9 +219,6 @@ githubConfigSecret:
|
|||||||
# "job_name",
|
# "job_name",
|
||||||
# "event_name",
|
# "event_name",
|
||||||
# "job_result",
|
# "job_result",
|
||||||
# "job_workflow_ref",
|
|
||||||
# "job_workflow_name",
|
|
||||||
# "job_workflow_target"
|
|
||||||
# ]
|
# ]
|
||||||
# buckets:
|
# buckets:
|
||||||
# [
|
# [
|
||||||
@@ -314,6 +283,18 @@ template:
|
|||||||
## volumeMounts:
|
## volumeMounts:
|
||||||
## - name: dind-externals
|
## - name: dind-externals
|
||||||
## mountPath: /home/runner/tmpDir
|
## mountPath: /home/runner/tmpDir
|
||||||
|
## containers:
|
||||||
|
## - name: runner
|
||||||
|
## image: ghcr.io/actions/actions-runner:latest
|
||||||
|
## command: ["/home/runner/run.sh"]
|
||||||
|
## env:
|
||||||
|
## - name: DOCKER_HOST
|
||||||
|
## value: unix:///var/run/docker.sock
|
||||||
|
## volumeMounts:
|
||||||
|
## - name: work
|
||||||
|
## mountPath: /home/runner/_work
|
||||||
|
## - name: dind-sock
|
||||||
|
## mountPath: /var/run
|
||||||
## - name: dind
|
## - name: dind
|
||||||
## image: docker:dind
|
## image: docker:dind
|
||||||
## args:
|
## args:
|
||||||
@@ -325,15 +306,6 @@ template:
|
|||||||
## value: "123"
|
## value: "123"
|
||||||
## securityContext:
|
## securityContext:
|
||||||
## privileged: true
|
## privileged: true
|
||||||
## restartPolicy: Always
|
|
||||||
## startupProbe:
|
|
||||||
## exec:
|
|
||||||
## command:
|
|
||||||
## - docker
|
|
||||||
## - info
|
|
||||||
## initialDelaySeconds: 0
|
|
||||||
## failureThreshold: 24
|
|
||||||
## periodSeconds: 5
|
|
||||||
## volumeMounts:
|
## volumeMounts:
|
||||||
## - name: work
|
## - name: work
|
||||||
## mountPath: /home/runner/_work
|
## mountPath: /home/runner/_work
|
||||||
@@ -341,20 +313,6 @@ template:
|
|||||||
## mountPath: /var/run
|
## mountPath: /var/run
|
||||||
## - name: dind-externals
|
## - name: dind-externals
|
||||||
## mountPath: /home/runner/externals
|
## mountPath: /home/runner/externals
|
||||||
## containers:
|
|
||||||
## - name: runner
|
|
||||||
## image: ghcr.io/actions/actions-runner:latest
|
|
||||||
## command: ["/home/runner/run.sh"]
|
|
||||||
## env:
|
|
||||||
## - name: DOCKER_HOST
|
|
||||||
## value: unix:///var/run/docker.sock
|
|
||||||
## - name: RUNNER_WAIT_FOR_DOCKER_IN_SECONDS
|
|
||||||
## value: "120"
|
|
||||||
## volumeMounts:
|
|
||||||
## - name: work
|
|
||||||
## mountPath: /home/runner/_work
|
|
||||||
## - name: dind-sock
|
|
||||||
## mountPath: /var/run
|
|
||||||
## volumes:
|
## volumes:
|
||||||
## - name: work
|
## - name: work
|
||||||
## emptyDir: {}
|
## emptyDir: {}
|
||||||
@@ -392,25 +350,6 @@ 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
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
// App is responsible for initializing required components and running the app.
|
// App is responsible for initializing required components and running the app.
|
||||||
type App struct {
|
type App struct {
|
||||||
// configured fields
|
// configured fields
|
||||||
config *config.Config
|
config config.Config
|
||||||
logger logr.Logger
|
logger logr.Logger
|
||||||
|
|
||||||
// initialized fields
|
// initialized fields
|
||||||
@@ -38,12 +38,8 @@ type Worker interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func New(config config.Config) (*App, error) {
|
func New(config config.Config) (*App, error) {
|
||||||
if err := config.Validate(); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to validate config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
app := &App{
|
app := &App{
|
||||||
config: &config,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
||||||
ghConfig, err := actions.ParseGitHubConfigFromURL(config.ConfigureUrl)
|
ghConfig, err := actions.ParseGitHubConfigFromURL(config.ConfigureUrl)
|
||||||
@@ -73,8 +69,8 @@ func New(config config.Config) (*App, error) {
|
|||||||
Repository: ghConfig.Repository,
|
Repository: ghConfig.Repository,
|
||||||
ServerAddr: config.MetricsAddr,
|
ServerAddr: config.MetricsAddr,
|
||||||
ServerEndpoint: config.MetricsEndpoint,
|
ServerEndpoint: config.MetricsEndpoint,
|
||||||
Metrics: config.Metrics,
|
|
||||||
Logger: app.logger.WithName("metrics exporter"),
|
Logger: app.logger.WithName("metrics exporter"),
|
||||||
|
Metrics: *config.Metrics,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -10,26 +9,19 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
||||||
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1/appconfig"
|
|
||||||
"github.com/actions/actions-runner-controller/build"
|
"github.com/actions/actions-runner-controller/build"
|
||||||
"github.com/actions/actions-runner-controller/github/actions"
|
"github.com/actions/actions-runner-controller/github/actions"
|
||||||
"github.com/actions/actions-runner-controller/logging"
|
"github.com/actions/actions-runner-controller/logging"
|
||||||
"github.com/actions/actions-runner-controller/vault"
|
|
||||||
"github.com/actions/actions-runner-controller/vault/azurekeyvault"
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
"golang.org/x/net/http/httpproxy"
|
"golang.org/x/net/http/httpproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ConfigureUrl string `json:"configure_url"`
|
ConfigureUrl string `json:"configure_url"`
|
||||||
VaultType vault.VaultType `json:"vault_type"`
|
AppID int64 `json:"app_id"`
|
||||||
VaultLookupKey string `json:"vault_lookup_key"`
|
AppInstallationID int64 `json:"app_installation_id"`
|
||||||
// If the VaultType is set to "azure_key_vault", this field must be populated.
|
AppPrivateKey string `json:"app_private_key"`
|
||||||
AzureKeyVaultConfig *azurekeyvault.Config `json:"azure_key_vault,omitempty"`
|
Token string `json:"token"`
|
||||||
// AppConfig contains the GitHub App configuration.
|
|
||||||
// It is initially set to nil if VaultType is set.
|
|
||||||
// Otherwise, it is populated with the GitHub App credentials from the GitHub secret.
|
|
||||||
*appconfig.AppConfig
|
|
||||||
EphemeralRunnerSetNamespace string `json:"ephemeral_runner_set_namespace"`
|
EphemeralRunnerSetNamespace string `json:"ephemeral_runner_set_namespace"`
|
||||||
EphemeralRunnerSetName string `json:"ephemeral_runner_set_name"`
|
EphemeralRunnerSetName string `json:"ephemeral_runner_set_name"`
|
||||||
MaxRunners int `json:"max_runners"`
|
MaxRunners int `json:"max_runners"`
|
||||||
@@ -44,58 +36,23 @@ type Config struct {
|
|||||||
Metrics *v1alpha1.MetricsConfig `json:"metrics"`
|
Metrics *v1alpha1.MetricsConfig `json:"metrics"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Read(ctx context.Context, configPath string) (*Config, error) {
|
func Read(path string) (Config, error) {
|
||||||
f, err := os.Open(configPath)
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return Config{}, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
var config Config
|
var config Config
|
||||||
if err := json.NewDecoder(f).Decode(&config); err != nil {
|
if err := json.NewDecoder(f).Decode(&config); err != nil {
|
||||||
return nil, fmt.Errorf("failed to decode config: %w", err)
|
return Config{}, fmt.Errorf("failed to decode config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var vault vault.Vault
|
|
||||||
switch config.VaultType {
|
|
||||||
case "":
|
|
||||||
if err := config.Validate(); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to validate configuration: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &config, nil
|
|
||||||
case "azure_key_vault":
|
|
||||||
akv, err := azurekeyvault.New(*config.AzureKeyVaultConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create Azure Key Vault client: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
vault = akv
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported vault type: %s", config.VaultType)
|
|
||||||
}
|
|
||||||
|
|
||||||
appConfigRaw, err := vault.GetSecret(ctx, config.VaultLookupKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get app config from vault: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
appConfig, err := appconfig.FromJSONString(appConfigRaw)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read app config from string: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config.AppConfig = appConfig
|
|
||||||
|
|
||||||
if err := config.Validate(); err != nil {
|
if err := config.Validate(); err != nil {
|
||||||
return nil, fmt.Errorf("config validation failed: %w", err)
|
return Config{}, fmt.Errorf("failed to validate config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.Err() != nil {
|
return config, nil
|
||||||
return nil, ctx.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
return &config, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate checks the configuration for errors.
|
// Validate checks the configuration for errors.
|
||||||
@@ -105,30 +62,26 @@ func (c *Config) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(c.EphemeralRunnerSetNamespace) == 0 || len(c.EphemeralRunnerSetName) == 0 {
|
if len(c.EphemeralRunnerSetNamespace) == 0 || len(c.EphemeralRunnerSetName) == 0 {
|
||||||
return fmt.Errorf("EphemeralRunnerSetNamespace %q or EphemeralRunnerSetName %q is missing", c.EphemeralRunnerSetNamespace, c.EphemeralRunnerSetName)
|
return fmt.Errorf("EphemeralRunnerSetNamespace '%s' or EphemeralRunnerSetName '%s' is missing", c.EphemeralRunnerSetNamespace, c.EphemeralRunnerSetName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.RunnerScaleSetId == 0 {
|
if c.RunnerScaleSetId == 0 {
|
||||||
return fmt.Errorf(`RunnerScaleSetId "%d" is missing`, c.RunnerScaleSetId)
|
return fmt.Errorf("RunnerScaleSetId '%d' is missing", c.RunnerScaleSetId)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.MaxRunners < c.MinRunners {
|
if c.MaxRunners < c.MinRunners {
|
||||||
return fmt.Errorf(`MinRunners "%d" cannot be greater than MaxRunners "%d"`, c.MinRunners, c.MaxRunners)
|
return fmt.Errorf("MinRunners '%d' cannot be greater than MaxRunners '%d'", c.MinRunners, c.MaxRunners)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.VaultType != "" {
|
hasToken := len(c.Token) > 0
|
||||||
if err := c.VaultType.Validate(); err != nil {
|
hasPrivateKeyConfig := c.AppID > 0 && c.AppPrivateKey != ""
|
||||||
return fmt.Errorf("VaultType validation failed: %w", err)
|
|
||||||
}
|
if !hasToken && !hasPrivateKeyConfig {
|
||||||
if c.VaultLookupKey == "" {
|
return fmt.Errorf("GitHub auth credential is missing, token length: '%d', appId: '%d', installationId: '%d', private key length: '%d", len(c.Token), c.AppID, c.AppInstallationID, len(c.AppPrivateKey))
|
||||||
return fmt.Errorf("VaultLookupKey is required when VaultType is set to %q", c.VaultType)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.VaultType == "" && c.VaultLookupKey == "" {
|
if hasToken && hasPrivateKeyConfig {
|
||||||
if err := c.AppConfig.Validate(); err != nil {
|
return fmt.Errorf("only one GitHub auth method supported at a time. Have both PAT and App auth: token length: '%d', appId: '%d', installationId: '%d', private key length: '%d", len(c.Token), c.AppID, c.AppInstallationID, len(c.AppPrivateKey))
|
||||||
return fmt.Errorf("AppConfig validation failed: %w", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1/appconfig"
|
|
||||||
"github.com/actions/actions-runner-controller/cmd/ghalistener/config"
|
"github.com/actions/actions-runner-controller/cmd/ghalistener/config"
|
||||||
"github.com/actions/actions-runner-controller/github/actions"
|
"github.com/actions/actions-runner-controller/github/actions"
|
||||||
"github.com/actions/actions-runner-controller/github/actions/testserver"
|
"github.com/actions/actions-runner-controller/github/actions/testserver"
|
||||||
@@ -54,9 +53,7 @@ func TestCustomerServerRootCA(t *testing.T) {
|
|||||||
config := config.Config{
|
config := config.Config{
|
||||||
ConfigureUrl: server.ConfigURLForOrg("myorg"),
|
ConfigureUrl: server.ConfigURLForOrg("myorg"),
|
||||||
ServerRootCA: certsString,
|
ServerRootCA: certsString,
|
||||||
AppConfig: &appconfig.AppConfig{
|
Token: "token",
|
||||||
Token: "token",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := config.ActionsClient(logr.Discard())
|
client, err := config.ActionsClient(logr.Discard())
|
||||||
@@ -83,9 +80,7 @@ func TestProxySettings(t *testing.T) {
|
|||||||
|
|
||||||
config := config.Config{
|
config := config.Config{
|
||||||
ConfigureUrl: "https://github.com/org/repo",
|
ConfigureUrl: "https://github.com/org/repo",
|
||||||
AppConfig: &appconfig.AppConfig{
|
Token: "token",
|
||||||
Token: "token",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := config.ActionsClient(logr.Discard())
|
client, err := config.ActionsClient(logr.Discard())
|
||||||
@@ -115,9 +110,7 @@ func TestProxySettings(t *testing.T) {
|
|||||||
|
|
||||||
config := config.Config{
|
config := config.Config{
|
||||||
ConfigureUrl: "https://github.com/org/repo",
|
ConfigureUrl: "https://github.com/org/repo",
|
||||||
AppConfig: &appconfig.AppConfig{
|
Token: "token",
|
||||||
Token: "token",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := config.ActionsClient(logr.Discard(), actions.WithRetryMax(0))
|
client, err := config.ActionsClient(logr.Discard(), actions.WithRetryMax(0))
|
||||||
@@ -152,9 +145,7 @@ func TestProxySettings(t *testing.T) {
|
|||||||
|
|
||||||
config := config.Config{
|
config := config.Config{
|
||||||
ConfigureUrl: "https://github.com/org/repo",
|
ConfigureUrl: "https://github.com/org/repo",
|
||||||
AppConfig: &appconfig.AppConfig{
|
Token: "token",
|
||||||
Token: "token",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := config.ActionsClient(logr.Discard())
|
client, err := config.ActionsClient(logr.Discard())
|
||||||
|
|||||||
92
cmd/ghalistener/config/config_test.go
Normal file
92
cmd/ghalistener/config/config_test.go
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConfigValidationMinMax(t *testing.T) {
|
||||||
|
config := &Config{
|
||||||
|
ConfigureUrl: "github.com/some_org/some_repo",
|
||||||
|
EphemeralRunnerSetNamespace: "namespace",
|
||||||
|
EphemeralRunnerSetName: "deployment",
|
||||||
|
RunnerScaleSetId: 1,
|
||||||
|
MinRunners: 5,
|
||||||
|
MaxRunners: 2,
|
||||||
|
Token: "token",
|
||||||
|
}
|
||||||
|
err := config.Validate()
|
||||||
|
assert.ErrorContains(t, err, "MinRunners '5' cannot be greater than MaxRunners '2", "Expected error about MinRunners > MaxRunners")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigValidationMissingToken(t *testing.T) {
|
||||||
|
config := &Config{
|
||||||
|
ConfigureUrl: "github.com/some_org/some_repo",
|
||||||
|
EphemeralRunnerSetNamespace: "namespace",
|
||||||
|
EphemeralRunnerSetName: "deployment",
|
||||||
|
RunnerScaleSetId: 1,
|
||||||
|
}
|
||||||
|
err := config.Validate()
|
||||||
|
expectedError := fmt.Sprintf("GitHub auth credential is missing, token length: '%d', appId: '%d', installationId: '%d', private key length: '%d", len(config.Token), config.AppID, config.AppInstallationID, len(config.AppPrivateKey))
|
||||||
|
assert.ErrorContains(t, err, expectedError, "Expected error about missing auth")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigValidationAppKey(t *testing.T) {
|
||||||
|
config := &Config{
|
||||||
|
AppID: 1,
|
||||||
|
AppInstallationID: 10,
|
||||||
|
ConfigureUrl: "github.com/some_org/some_repo",
|
||||||
|
EphemeralRunnerSetNamespace: "namespace",
|
||||||
|
EphemeralRunnerSetName: "deployment",
|
||||||
|
RunnerScaleSetId: 1,
|
||||||
|
}
|
||||||
|
err := config.Validate()
|
||||||
|
expectedError := fmt.Sprintf("GitHub auth credential is missing, token length: '%d', appId: '%d', installationId: '%d', private key length: '%d", len(config.Token), config.AppID, config.AppInstallationID, len(config.AppPrivateKey))
|
||||||
|
assert.ErrorContains(t, err, expectedError, "Expected error about missing auth")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigValidationOnlyOneTypeOfCredentials(t *testing.T) {
|
||||||
|
config := &Config{
|
||||||
|
AppID: 1,
|
||||||
|
AppInstallationID: 10,
|
||||||
|
AppPrivateKey: "asdf",
|
||||||
|
Token: "asdf",
|
||||||
|
ConfigureUrl: "github.com/some_org/some_repo",
|
||||||
|
EphemeralRunnerSetNamespace: "namespace",
|
||||||
|
EphemeralRunnerSetName: "deployment",
|
||||||
|
RunnerScaleSetId: 1,
|
||||||
|
}
|
||||||
|
err := config.Validate()
|
||||||
|
expectedError := fmt.Sprintf("only one GitHub auth method supported at a time. Have both PAT and App auth: token length: '%d', appId: '%d', installationId: '%d', private key length: '%d", len(config.Token), config.AppID, config.AppInstallationID, len(config.AppPrivateKey))
|
||||||
|
assert.ErrorContains(t, err, expectedError, "Expected error about missing auth")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigValidation(t *testing.T) {
|
||||||
|
config := &Config{
|
||||||
|
ConfigureUrl: "https://github.com/actions",
|
||||||
|
EphemeralRunnerSetNamespace: "namespace",
|
||||||
|
EphemeralRunnerSetName: "deployment",
|
||||||
|
RunnerScaleSetId: 1,
|
||||||
|
MinRunners: 1,
|
||||||
|
MaxRunners: 5,
|
||||||
|
Token: "asdf",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := config.Validate()
|
||||||
|
|
||||||
|
assert.NoError(t, err, "Expected no error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigValidationConfigUrl(t *testing.T) {
|
||||||
|
config := &Config{
|
||||||
|
EphemeralRunnerSetNamespace: "namespace",
|
||||||
|
EphemeralRunnerSetName: "deployment",
|
||||||
|
RunnerScaleSetId: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := config.Validate()
|
||||||
|
|
||||||
|
assert.ErrorContains(t, err, "GitHubConfigUrl is not provided", "Expected error about missing ConfigureUrl")
|
||||||
|
}
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1/appconfig"
|
|
||||||
"github.com/actions/actions-runner-controller/vault"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConfigValidationMinMax(t *testing.T) {
|
|
||||||
config := &Config{
|
|
||||||
ConfigureUrl: "github.com/some_org/some_repo",
|
|
||||||
EphemeralRunnerSetNamespace: "namespace",
|
|
||||||
EphemeralRunnerSetName: "deployment",
|
|
||||||
RunnerScaleSetId: 1,
|
|
||||||
MinRunners: 5,
|
|
||||||
MaxRunners: 2,
|
|
||||||
AppConfig: &appconfig.AppConfig{
|
|
||||||
Token: "token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err := config.Validate()
|
|
||||||
assert.ErrorContains(t, err, `MinRunners "5" cannot be greater than MaxRunners "2"`, "Expected error about MinRunners > MaxRunners")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConfigValidationMissingToken(t *testing.T) {
|
|
||||||
config := &Config{
|
|
||||||
ConfigureUrl: "github.com/some_org/some_repo",
|
|
||||||
EphemeralRunnerSetNamespace: "namespace",
|
|
||||||
EphemeralRunnerSetName: "deployment",
|
|
||||||
RunnerScaleSetId: 1,
|
|
||||||
}
|
|
||||||
err := config.Validate()
|
|
||||||
expectedError := "AppConfig validation failed: missing app config"
|
|
||||||
assert.ErrorContains(t, err, expectedError, "Expected error about missing auth")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConfigValidationAppKey(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
t.Run("app id integer", func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
config := &Config{
|
|
||||||
AppConfig: &appconfig.AppConfig{
|
|
||||||
AppID: "1",
|
|
||||||
AppInstallationID: 10,
|
|
||||||
},
|
|
||||||
ConfigureUrl: "github.com/some_org/some_repo",
|
|
||||||
EphemeralRunnerSetNamespace: "namespace",
|
|
||||||
EphemeralRunnerSetName: "deployment",
|
|
||||||
RunnerScaleSetId: 1,
|
|
||||||
}
|
|
||||||
err := config.Validate()
|
|
||||||
expectedError := "AppConfig validation failed: no credentials provided: either a PAT or GitHub App credentials should be provided"
|
|
||||||
assert.ErrorContains(t, err, expectedError, "Expected error about missing auth")
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("app id as client id", func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
config := &Config{
|
|
||||||
AppConfig: &appconfig.AppConfig{
|
|
||||||
AppID: "Iv23f8doAlphaNumer1c",
|
|
||||||
AppInstallationID: 10,
|
|
||||||
},
|
|
||||||
ConfigureUrl: "github.com/some_org/some_repo",
|
|
||||||
EphemeralRunnerSetNamespace: "namespace",
|
|
||||||
EphemeralRunnerSetName: "deployment",
|
|
||||||
RunnerScaleSetId: 1,
|
|
||||||
}
|
|
||||||
err := config.Validate()
|
|
||||||
expectedError := "AppConfig validation failed: no credentials provided: either a PAT or GitHub App credentials should be provided"
|
|
||||||
assert.ErrorContains(t, err, expectedError, "Expected error about missing auth")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConfigValidationOnlyOneTypeOfCredentials(t *testing.T) {
|
|
||||||
config := &Config{
|
|
||||||
AppConfig: &appconfig.AppConfig{
|
|
||||||
AppID: "1",
|
|
||||||
AppInstallationID: 10,
|
|
||||||
AppPrivateKey: "asdf",
|
|
||||||
Token: "asdf",
|
|
||||||
},
|
|
||||||
ConfigureUrl: "github.com/some_org/some_repo",
|
|
||||||
EphemeralRunnerSetNamespace: "namespace",
|
|
||||||
EphemeralRunnerSetName: "deployment",
|
|
||||||
RunnerScaleSetId: 1,
|
|
||||||
}
|
|
||||||
err := config.Validate()
|
|
||||||
expectedError := "AppConfig validation failed: both PAT and GitHub App credentials provided. should only provide one"
|
|
||||||
assert.ErrorContains(t, err, expectedError, "Expected error about missing auth")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConfigValidation(t *testing.T) {
|
|
||||||
config := &Config{
|
|
||||||
ConfigureUrl: "https://github.com/actions",
|
|
||||||
EphemeralRunnerSetNamespace: "namespace",
|
|
||||||
EphemeralRunnerSetName: "deployment",
|
|
||||||
RunnerScaleSetId: 1,
|
|
||||||
MinRunners: 1,
|
|
||||||
MaxRunners: 5,
|
|
||||||
AppConfig: &appconfig.AppConfig{
|
|
||||||
Token: "asdf",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := config.Validate()
|
|
||||||
|
|
||||||
assert.NoError(t, err, "Expected no error")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConfigValidationConfigUrl(t *testing.T) {
|
|
||||||
config := &Config{
|
|
||||||
EphemeralRunnerSetNamespace: "namespace",
|
|
||||||
EphemeralRunnerSetName: "deployment",
|
|
||||||
RunnerScaleSetId: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := config.Validate()
|
|
||||||
|
|
||||||
assert.ErrorContains(t, err, "GitHubConfigUrl is not provided", "Expected error about missing ConfigureUrl")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConfigValidationWithVaultConfig(t *testing.T) {
|
|
||||||
t.Run("valid", func(t *testing.T) {
|
|
||||||
config := &Config{
|
|
||||||
ConfigureUrl: "https://github.com/actions",
|
|
||||||
EphemeralRunnerSetNamespace: "namespace",
|
|
||||||
EphemeralRunnerSetName: "deployment",
|
|
||||||
RunnerScaleSetId: 1,
|
|
||||||
MinRunners: 1,
|
|
||||||
MaxRunners: 5,
|
|
||||||
VaultType: vault.VaultTypeAzureKeyVault,
|
|
||||||
VaultLookupKey: "testkey",
|
|
||||||
}
|
|
||||||
err := config.Validate()
|
|
||||||
assert.NoError(t, err, "Expected no error for valid vault type")
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("invalid vault type", func(t *testing.T) {
|
|
||||||
config := &Config{
|
|
||||||
ConfigureUrl: "https://github.com/actions",
|
|
||||||
EphemeralRunnerSetNamespace: "namespace",
|
|
||||||
EphemeralRunnerSetName: "deployment",
|
|
||||||
RunnerScaleSetId: 1,
|
|
||||||
MinRunners: 1,
|
|
||||||
MaxRunners: 5,
|
|
||||||
VaultType: vault.VaultType("invalid_vault_type"),
|
|
||||||
VaultLookupKey: "testkey",
|
|
||||||
}
|
|
||||||
err := config.Validate()
|
|
||||||
assert.ErrorContains(t, err, `unknown vault type: "invalid_vault_type"`, "Expected error for invalid vault type")
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("vault type set without lookup key", func(t *testing.T) {
|
|
||||||
config := &Config{
|
|
||||||
ConfigureUrl: "https://github.com/actions",
|
|
||||||
EphemeralRunnerSetNamespace: "namespace",
|
|
||||||
EphemeralRunnerSetName: "deployment",
|
|
||||||
RunnerScaleSetId: 1,
|
|
||||||
MinRunners: 1,
|
|
||||||
MaxRunners: 5,
|
|
||||||
VaultType: vault.VaultTypeAzureKeyVault,
|
|
||||||
VaultLookupKey: "",
|
|
||||||
}
|
|
||||||
err := config.Validate()
|
|
||||||
assert.ErrorContains(t, err, `VaultLookupKey is required when VaultType is set to "azure_key_vault"`, "Expected error for vault type without lookup key")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -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.JobID)
|
l.logger.Info("Job available message received", "jobId", jobAvailable.RunnerRequestId)
|
||||||
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.JobID)
|
l.logger.Info("Job assigned message received", "jobId", jobAssigned.RunnerRequestId)
|
||||||
|
|
||||||
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.", "JobID", jobStarted.JobID, "RunnerId", jobStarted.RunnerID)
|
l.logger.Info("Job started message received.", "RequestId", jobStarted.RunnerRequestId, "RunnerId", jobStarted.RunnerId)
|
||||||
parsedMsg.jobsStarted = append(parsedMsg.jobsStarted, &jobStarted)
|
parsedMsg.jobsStarted = append(parsedMsg.jobsStarted, &jobStarted)
|
||||||
|
|
||||||
case messageTypeJobCompleted:
|
case messageTypeJobCompleted:
|
||||||
@@ -386,13 +386,7 @@ 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(
|
l.logger.Info("Job completed message received.", "RequestId", jobCompleted.RunnerRequestId, "Result", jobCompleted.Result, "RunnerId", jobCompleted.RunnerId, "RunnerName", jobCompleted.RunnerName)
|
||||||
"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:
|
||||||
@@ -406,7 +400,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))
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -13,27 +13,26 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
|
||||||
defer stop()
|
|
||||||
|
|
||||||
configPath, ok := os.LookupEnv("LISTENER_CONFIG_PATH")
|
configPath, ok := os.LookupEnv("LISTENER_CONFIG_PATH")
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Fprintf(os.Stderr, "Error: LISTENER_CONFIG_PATH environment variable is not set\n")
|
fmt.Fprintf(os.Stderr, "Error: LISTENER_CONFIG_PATH environment variable is not set\n")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
config, err := config.Read(configPath)
|
||||||
config, err := config.Read(ctx, configPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to read config: %v", err)
|
log.Printf("Failed to read config: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
app, err := app.New(*config)
|
app, err := app.New(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to initialize app: %v", err)
|
log.Printf("Failed to initialize app: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
if err := app.Run(ctx); err != nil {
|
if err := app.Run(ctx); err != nil {
|
||||||
log.Printf("Application returned an error: %v", err)
|
log.Printf("Application returned an error: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|||||||
@@ -21,9 +21,6 @@ const (
|
|||||||
labelKeyOrganization = "organization"
|
labelKeyOrganization = "organization"
|
||||||
labelKeyRepository = "repository"
|
labelKeyRepository = "repository"
|
||||||
labelKeyJobName = "job_name"
|
labelKeyJobName = "job_name"
|
||||||
labelKeyJobWorkflowRef = "job_workflow_ref"
|
|
||||||
labelKeyJobWorkflowName = "job_workflow_name"
|
|
||||||
labelKeyJobWorkflowTarget = "job_workflow_target"
|
|
||||||
labelKeyEventName = "event_name"
|
labelKeyEventName = "event_name"
|
||||||
labelKeyJobResult = "job_result"
|
labelKeyJobResult = "job_result"
|
||||||
)
|
)
|
||||||
@@ -77,16 +74,12 @@ 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,
|
labelKeyEventName: jobBase.EventName,
|
||||||
labelKeyJobWorkflowName: workflowRefInfo.Name,
|
|
||||||
labelKeyJobWorkflowTarget: workflowRefInfo.Target,
|
|
||||||
labelKeyEventName: jobBase.EventName,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,148 +152,13 @@ type ExporterConfig struct {
|
|||||||
ServerAddr string
|
ServerAddr string
|
||||||
ServerEndpoint string
|
ServerEndpoint string
|
||||||
Logger logr.Logger
|
Logger logr.Logger
|
||||||
Metrics *v1alpha1.MetricsConfig
|
Metrics v1alpha1.MetricsConfig
|
||||||
}
|
|
||||||
|
|
||||||
var defaultMetrics = v1alpha1.MetricsConfig{
|
|
||||||
Counters: map[string]*v1alpha1.CounterMetric{
|
|
||||||
MetricStartedJobsTotal: {
|
|
||||||
Labels: []string{
|
|
||||||
labelKeyEnterprise,
|
|
||||||
labelKeyOrganization,
|
|
||||||
labelKeyRepository,
|
|
||||||
labelKeyJobName,
|
|
||||||
labelKeyEventName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MetricCompletedJobsTotal: {
|
|
||||||
Labels: []string{
|
|
||||||
labelKeyEnterprise,
|
|
||||||
labelKeyOrganization,
|
|
||||||
labelKeyRepository,
|
|
||||||
labelKeyJobName,
|
|
||||||
labelKeyEventName,
|
|
||||||
labelKeyJobResult,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Gauges: map[string]*v1alpha1.GaugeMetric{
|
|
||||||
MetricAssignedJobs: {
|
|
||||||
Labels: []string{
|
|
||||||
labelKeyEnterprise,
|
|
||||||
labelKeyOrganization,
|
|
||||||
labelKeyRepository,
|
|
||||||
labelKeyRunnerScaleSetName,
|
|
||||||
labelKeyRunnerScaleSetNamespace,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MetricRunningJobs: {
|
|
||||||
Labels: []string{
|
|
||||||
labelKeyEnterprise,
|
|
||||||
labelKeyOrganization,
|
|
||||||
labelKeyRepository,
|
|
||||||
labelKeyRunnerScaleSetName,
|
|
||||||
labelKeyRunnerScaleSetNamespace,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MetricRegisteredRunners: {
|
|
||||||
Labels: []string{
|
|
||||||
labelKeyEnterprise,
|
|
||||||
labelKeyOrganization,
|
|
||||||
labelKeyRepository,
|
|
||||||
labelKeyRunnerScaleSetName,
|
|
||||||
labelKeyRunnerScaleSetNamespace,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MetricBusyRunners: {
|
|
||||||
Labels: []string{
|
|
||||||
labelKeyEnterprise,
|
|
||||||
labelKeyOrganization,
|
|
||||||
labelKeyRepository,
|
|
||||||
labelKeyRunnerScaleSetName,
|
|
||||||
labelKeyRunnerScaleSetNamespace,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MetricMinRunners: {
|
|
||||||
Labels: []string{
|
|
||||||
labelKeyEnterprise,
|
|
||||||
labelKeyOrganization,
|
|
||||||
labelKeyRepository,
|
|
||||||
labelKeyRunnerScaleSetName,
|
|
||||||
labelKeyRunnerScaleSetNamespace,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MetricMaxRunners: {
|
|
||||||
Labels: []string{
|
|
||||||
labelKeyEnterprise,
|
|
||||||
labelKeyOrganization,
|
|
||||||
labelKeyRepository,
|
|
||||||
labelKeyRunnerScaleSetName,
|
|
||||||
labelKeyRunnerScaleSetNamespace,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MetricDesiredRunners: {
|
|
||||||
Labels: []string{
|
|
||||||
labelKeyEnterprise,
|
|
||||||
labelKeyOrganization,
|
|
||||||
labelKeyRepository,
|
|
||||||
labelKeyRunnerScaleSetName,
|
|
||||||
labelKeyRunnerScaleSetNamespace,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MetricIdleRunners: {
|
|
||||||
Labels: []string{
|
|
||||||
labelKeyEnterprise,
|
|
||||||
labelKeyOrganization,
|
|
||||||
labelKeyRepository,
|
|
||||||
labelKeyRunnerScaleSetName,
|
|
||||||
labelKeyRunnerScaleSetNamespace,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Histograms: map[string]*v1alpha1.HistogramMetric{
|
|
||||||
MetricJobStartupDurationSeconds: {
|
|
||||||
Labels: []string{
|
|
||||||
labelKeyEnterprise,
|
|
||||||
labelKeyOrganization,
|
|
||||||
labelKeyRepository,
|
|
||||||
labelKeyJobName,
|
|
||||||
labelKeyEventName,
|
|
||||||
},
|
|
||||||
Buckets: defaultRuntimeBuckets,
|
|
||||||
},
|
|
||||||
MetricJobExecutionDurationSeconds: {
|
|
||||||
Labels: []string{
|
|
||||||
labelKeyEnterprise,
|
|
||||||
labelKeyOrganization,
|
|
||||||
labelKeyRepository,
|
|
||||||
labelKeyJobName,
|
|
||||||
labelKeyEventName,
|
|
||||||
labelKeyJobResult,
|
|
||||||
},
|
|
||||||
Buckets: defaultRuntimeBuckets,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ExporterConfig) defaults() {
|
|
||||||
if e.ServerAddr == "" {
|
|
||||||
e.ServerAddr = ":8080"
|
|
||||||
}
|
|
||||||
if e.ServerEndpoint == "" {
|
|
||||||
e.ServerEndpoint = "/metrics"
|
|
||||||
}
|
|
||||||
if e.Metrics == nil {
|
|
||||||
defaultMetrics := defaultMetrics
|
|
||||||
e.Metrics = &defaultMetrics
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExporter(config ExporterConfig) ServerExporter {
|
func NewExporter(config ExporterConfig) ServerExporter {
|
||||||
config.defaults()
|
|
||||||
reg := prometheus.NewRegistry()
|
reg := prometheus.NewRegistry()
|
||||||
|
|
||||||
metrics := installMetrics(*config.Metrics, reg, config.Logger)
|
metrics := installMetrics(config.Metrics, reg, config.Logger)
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.Handle(
|
mux.Handle(
|
||||||
@@ -473,7 +331,7 @@ func (e *exporter) PublishStatistics(stats *actions.RunnerScaleSetStatistic) {
|
|||||||
e.setGauge(MetricAssignedJobs, e.scaleSetLabels, float64(stats.TotalAssignedJobs))
|
e.setGauge(MetricAssignedJobs, e.scaleSetLabels, float64(stats.TotalAssignedJobs))
|
||||||
e.setGauge(MetricRunningJobs, e.scaleSetLabels, float64(stats.TotalRunningJobs))
|
e.setGauge(MetricRunningJobs, e.scaleSetLabels, float64(stats.TotalRunningJobs))
|
||||||
e.setGauge(MetricRegisteredRunners, e.scaleSetLabels, float64(stats.TotalRegisteredRunners))
|
e.setGauge(MetricRegisteredRunners, e.scaleSetLabels, float64(stats.TotalRegisteredRunners))
|
||||||
e.setGauge(MetricBusyRunners, e.scaleSetLabels, float64(stats.TotalBusyRunners))
|
e.setGauge(MetricBusyRunners, e.scaleSetLabels, float64(float64(stats.TotalBusyRunners)))
|
||||||
e.setGauge(MetricIdleRunners, e.scaleSetLabels, float64(stats.TotalIdleRunners))
|
e.setGauge(MetricIdleRunners, e.scaleSetLabels, float64(stats.TotalIdleRunners))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInstallMetrics(t *testing.T) {
|
func TestInstallMetrics(t *testing.T) {
|
||||||
@@ -87,179 +86,3 @@ func TestInstallMetrics(t *testing.T) {
|
|||||||
assert.Equal(t, duration.config.Labels, metricsConfig.Histograms[MetricJobStartupDurationSeconds].Labels)
|
assert.Equal(t, duration.config.Labels, metricsConfig.Histograms[MetricJobStartupDurationSeconds].Labels)
|
||||||
assert.Equal(t, duration.config.Buckets, defaultRuntimeBuckets)
|
assert.Equal(t, duration.config.Buckets, defaultRuntimeBuckets)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewExporter(t *testing.T) {
|
|
||||||
t.Run("with defaults metrics applied", func(t *testing.T) {
|
|
||||||
config := ExporterConfig{
|
|
||||||
ScaleSetName: "test-scale-set",
|
|
||||||
ScaleSetNamespace: "test-namespace",
|
|
||||||
Enterprise: "",
|
|
||||||
Organization: "org",
|
|
||||||
Repository: "repo",
|
|
||||||
ServerAddr: ":6060",
|
|
||||||
ServerEndpoint: "/metrics",
|
|
||||||
Logger: logr.Discard(),
|
|
||||||
Metrics: nil, // when metrics is nil, all default metrics should be registered
|
|
||||||
}
|
|
||||||
|
|
||||||
exporter, ok := NewExporter(config).(*exporter)
|
|
||||||
require.True(t, ok, "expected exporter to be of type *exporter")
|
|
||||||
require.NotNil(t, exporter)
|
|
||||||
|
|
||||||
reg := prometheus.NewRegistry()
|
|
||||||
wantMetrics := installMetrics(defaultMetrics, reg, config.Logger)
|
|
||||||
|
|
||||||
assert.Equal(t, len(wantMetrics.counters), len(exporter.counters))
|
|
||||||
for k, v := range wantMetrics.counters {
|
|
||||||
assert.Contains(t, exporter.counters, k)
|
|
||||||
assert.Equal(t, v.config, exporter.counters[k].config)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, len(wantMetrics.gauges), len(exporter.gauges))
|
|
||||||
for k, v := range wantMetrics.gauges {
|
|
||||||
assert.Contains(t, exporter.gauges, k)
|
|
||||||
assert.Equal(t, v.config, exporter.gauges[k].config)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, len(wantMetrics.histograms), len(exporter.histograms))
|
|
||||||
for k, v := range wantMetrics.histograms {
|
|
||||||
assert.Contains(t, exporter.histograms, k)
|
|
||||||
assert.Equal(t, v.config, exporter.histograms[k].config)
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NotNil(t, exporter.srv)
|
|
||||||
assert.Equal(t, config.ServerAddr, exporter.srv.Addr)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("with default server URL", func(t *testing.T) {
|
|
||||||
config := ExporterConfig{
|
|
||||||
ScaleSetName: "test-scale-set",
|
|
||||||
ScaleSetNamespace: "test-namespace",
|
|
||||||
Enterprise: "",
|
|
||||||
Organization: "org",
|
|
||||||
Repository: "repo",
|
|
||||||
ServerAddr: "", // empty ServerAddr should default to ":8080"
|
|
||||||
ServerEndpoint: "",
|
|
||||||
Logger: logr.Discard(),
|
|
||||||
Metrics: nil, // when metrics is nil, all default metrics should be registered
|
|
||||||
}
|
|
||||||
|
|
||||||
exporter, ok := NewExporter(config).(*exporter)
|
|
||||||
require.True(t, ok, "expected exporter to be of type *exporter")
|
|
||||||
require.NotNil(t, exporter)
|
|
||||||
|
|
||||||
reg := prometheus.NewRegistry()
|
|
||||||
wantMetrics := installMetrics(defaultMetrics, reg, config.Logger)
|
|
||||||
|
|
||||||
assert.Equal(t, len(wantMetrics.counters), len(exporter.counters))
|
|
||||||
for k, v := range wantMetrics.counters {
|
|
||||||
assert.Contains(t, exporter.counters, k)
|
|
||||||
assert.Equal(t, v.config, exporter.counters[k].config)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, len(wantMetrics.gauges), len(exporter.gauges))
|
|
||||||
for k, v := range wantMetrics.gauges {
|
|
||||||
assert.Contains(t, exporter.gauges, k)
|
|
||||||
assert.Equal(t, v.config, exporter.gauges[k].config)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, len(wantMetrics.histograms), len(exporter.histograms))
|
|
||||||
for k, v := range wantMetrics.histograms {
|
|
||||||
assert.Contains(t, exporter.histograms, k)
|
|
||||||
assert.Equal(t, v.config, exporter.histograms[k].config)
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NotNil(t, exporter.srv)
|
|
||||||
assert.Equal(t, exporter.srv.Addr, ":8080")
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("with metrics configured", func(t *testing.T) {
|
|
||||||
metricsConfig := v1alpha1.MetricsConfig{
|
|
||||||
Counters: map[string]*v1alpha1.CounterMetric{
|
|
||||||
MetricStartedJobsTotal: {
|
|
||||||
Labels: []string{labelKeyRepository},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Gauges: map[string]*v1alpha1.GaugeMetric{
|
|
||||||
MetricAssignedJobs: {
|
|
||||||
Labels: []string{labelKeyRepository},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Histograms: map[string]*v1alpha1.HistogramMetric{
|
|
||||||
MetricJobExecutionDurationSeconds: {
|
|
||||||
Labels: []string{labelKeyRepository},
|
|
||||||
Buckets: []float64{0.1, 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
config := ExporterConfig{
|
|
||||||
ScaleSetName: "test-scale-set",
|
|
||||||
ScaleSetNamespace: "test-namespace",
|
|
||||||
Enterprise: "",
|
|
||||||
Organization: "org",
|
|
||||||
Repository: "repo",
|
|
||||||
ServerAddr: ":6060",
|
|
||||||
ServerEndpoint: "/metrics",
|
|
||||||
Logger: logr.Discard(),
|
|
||||||
Metrics: &metricsConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
exporter, ok := NewExporter(config).(*exporter)
|
|
||||||
require.True(t, ok, "expected exporter to be of type *exporter")
|
|
||||||
require.NotNil(t, exporter)
|
|
||||||
|
|
||||||
reg := prometheus.NewRegistry()
|
|
||||||
wantMetrics := installMetrics(metricsConfig, reg, config.Logger)
|
|
||||||
|
|
||||||
assert.Equal(t, len(wantMetrics.counters), len(exporter.counters))
|
|
||||||
for k, v := range wantMetrics.counters {
|
|
||||||
assert.Contains(t, exporter.counters, k)
|
|
||||||
assert.Equal(t, v.config, exporter.counters[k].config)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, len(wantMetrics.gauges), len(exporter.gauges))
|
|
||||||
for k, v := range wantMetrics.gauges {
|
|
||||||
assert.Contains(t, exporter.gauges, k)
|
|
||||||
assert.Equal(t, v.config, exporter.gauges[k].config)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, len(wantMetrics.histograms), len(exporter.histograms))
|
|
||||||
for k, v := range wantMetrics.histograms {
|
|
||||||
assert.Contains(t, exporter.histograms, k)
|
|
||||||
assert.Equal(t, v.config, exporter.histograms[k].config)
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NotNil(t, exporter.srv)
|
|
||||||
assert.Equal(t, config.ServerAddr, exporter.srv.Addr)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExporterConfigDefaults(t *testing.T) {
|
|
||||||
config := ExporterConfig{
|
|
||||||
ScaleSetName: "test-scale-set",
|
|
||||||
ScaleSetNamespace: "test-namespace",
|
|
||||||
Enterprise: "",
|
|
||||||
Organization: "org",
|
|
||||||
Repository: "repo",
|
|
||||||
ServerAddr: "",
|
|
||||||
ServerEndpoint: "",
|
|
||||||
Logger: logr.Discard(),
|
|
||||||
Metrics: nil, // when metrics is nil, all default metrics should be registered
|
|
||||||
}
|
|
||||||
|
|
||||||
config.defaults()
|
|
||||||
want := ExporterConfig{
|
|
||||||
ScaleSetName: "test-scale-set",
|
|
||||||
ScaleSetNamespace: "test-namespace",
|
|
||||||
Enterprise: "",
|
|
||||||
Organization: "org",
|
|
||||||
Repository: "repo",
|
|
||||||
ServerAddr: ":8080", // default server address
|
|
||||||
ServerEndpoint: "/metrics", // default server endpoint
|
|
||||||
Logger: logr.Discard(),
|
|
||||||
Metrics: &defaultMetrics, // when metrics is nil, all default metrics should be registered
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, want, config)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -100,11 +100,10 @@ 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 {
|
||||||
@@ -114,10 +113,9 @@ 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),
|
||||||
JobID: jobInfo.JobID,
|
WorkflowRunId: jobInfo.WorkflowRunId,
|
||||||
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
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.19.0
|
controller-gen.kubebuilder.io/version: v0.17.2
|
||||||
name: ephemeralrunners.actions.github.com
|
name: ephemeralrunners.actions.github.com
|
||||||
spec:
|
spec:
|
||||||
group: actions.github.com
|
group: actions.github.com
|
||||||
@@ -36,9 +36,6 @@ 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
|
||||||
@@ -430,6 +427,7 @@ 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
|
||||||
@@ -444,6 +442,7 @@ 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
|
||||||
@@ -604,6 +603,7 @@ 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,6 +618,7 @@ 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
|
||||||
@@ -706,8 +707,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 subtracting
|
compute a sum by iterating through the elements of this field and adding
|
||||||
"weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
|
"weight" to 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)
|
||||||
@@ -771,6 +772,7 @@ 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
|
||||||
@@ -785,6 +787,7 @@ 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
|
||||||
@@ -945,6 +948,7 @@ 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
|
||||||
@@ -959,6 +963,7 @@ 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
|
||||||
@@ -1085,9 +1090,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -1141,42 +1144,6 @@ 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
|
||||||
@@ -1232,13 +1199,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -1258,9 +1225,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -1509,12 +1474,6 @@ 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: |-
|
||||||
@@ -1905,7 +1864,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -1956,10 +1915,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 overrides the pod-level restart policy. When this field is not specified,
|
This field may only be set for init containers, and the only allowed value is "Always".
|
||||||
|
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.
|
||||||
Additionally, setting the RestartPolicy as "Always" for the init container will
|
Setting the RestartPolicy as "Always" for the init container will have the following effect:
|
||||||
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"
|
||||||
@@ -1971,57 +1930,6 @@ 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.
|
||||||
@@ -2619,9 +2527,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -2675,42 +2581,6 @@ 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
|
||||||
@@ -2766,13 +2636,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -2792,9 +2662,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -3039,12 +2907,6 @@ 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.
|
||||||
@@ -3418,7 +3280,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -3470,51 +3332,9 @@ 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.
|
||||||
You cannot set this field on ephemeral containers.
|
This may only be set for init containers. You cannot set this field on
|
||||||
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.
|
ephemeral containers.
|
||||||
items:
|
type: string
|
||||||
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.
|
||||||
@@ -4033,9 +3853,7 @@ 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.
|
||||||
When using HostNetwork you should specify ports so the scheduler is aware.
|
If this option is set, the ports that will be used must be specified.
|
||||||
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:
|
||||||
@@ -4060,19 +3878,6 @@ 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.
|
||||||
@@ -4108,7 +3913,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
|
||||||
that value or the sum of the normal containers. Limits are applied to init containers
|
of 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.
|
||||||
@@ -4152,9 +3957,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -4208,42 +4011,6 @@ 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
|
||||||
@@ -4299,13 +4066,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -4325,9 +4092,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -4576,12 +4341,6 @@ 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: |-
|
||||||
@@ -4972,7 +4731,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -5023,10 +4782,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 overrides the pod-level restart policy. When this field is not specified,
|
This field may only be set for init containers, and the only allowed value is "Always".
|
||||||
|
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.
|
||||||
Additionally, setting the RestartPolicy as "Always" for the init container will
|
Setting the RestartPolicy as "Always" for the init container will have the following effect:
|
||||||
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"
|
||||||
@@ -5038,57 +4797,6 @@ 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.
|
||||||
@@ -5602,7 +5310,6 @@ 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
|
||||||
@@ -5754,7 +5461,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", "memory" and "hugepages-" resource names only. ResourceClaims are not supported.
|
"cpu" and "memory" 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.
|
||||||
@@ -5767,7 +5474,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -6295,6 +6002,7 @@ 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: |-
|
||||||
@@ -6305,6 +6013,7 @@ 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: |-
|
||||||
@@ -7010,13 +6719,15 @@ 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 or nil value indicates that no
|
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass
|
||||||
VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
|
will be applied to the claim but it's not allowed to reset this field to empty string once it is set.
|
||||||
this field can be reset to its previous value (including nil) to cancel the modification.
|
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass
|
||||||
|
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: |-
|
||||||
@@ -7190,9 +6901,12 @@ 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: endpoints is the endpoint name that details Glusterfs topology.
|
description: |-
|
||||||
|
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: |-
|
||||||
@@ -7246,7 +6960,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) before 1.33.
|
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath).
|
||||||
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:
|
||||||
@@ -7271,7 +6985,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://kubernetes.io/docs/concepts/storage/volumes/#iscsi
|
More info: https://examples.k8s.io/volumes/iscsi/README.md
|
||||||
properties:
|
properties:
|
||||||
chapAuthDiscovery:
|
chapAuthDiscovery:
|
||||||
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
|
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
|
||||||
@@ -7661,110 +7375,6 @@ 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:
|
||||||
@@ -7894,6 +7504,7 @@ 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: |-
|
||||||
@@ -8173,53 +7784,6 @@ spec:
|
|||||||
required:
|
required:
|
||||||
- containers
|
- containers
|
||||||
type: object
|
type: object
|
||||||
vaultConfig:
|
|
||||||
properties:
|
|
||||||
azureKeyVault:
|
|
||||||
properties:
|
|
||||||
certificatePath:
|
|
||||||
type: string
|
|
||||||
clientId:
|
|
||||||
type: string
|
|
||||||
tenantId:
|
|
||||||
type: string
|
|
||||||
url:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- certificatePath
|
|
||||||
- clientId
|
|
||||||
- tenantId
|
|
||||||
- url
|
|
||||||
type: object
|
|
||||||
proxy:
|
|
||||||
properties:
|
|
||||||
http:
|
|
||||||
properties:
|
|
||||||
credentialSecretRef:
|
|
||||||
type: string
|
|
||||||
url:
|
|
||||||
description: Required
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
https:
|
|
||||||
properties:
|
|
||||||
credentialSecretRef:
|
|
||||||
type: string
|
|
||||||
url:
|
|
||||||
description: Required
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
noProxy:
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
type: object
|
|
||||||
type:
|
|
||||||
description: |-
|
|
||||||
VaultType represents the type of vault that can be used in the application.
|
|
||||||
It is used to identify which vault integration should be used to resolve secrets.
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
required:
|
required:
|
||||||
- githubConfigSecret
|
- githubConfigSecret
|
||||||
- githubConfigUrl
|
- githubConfigUrl
|
||||||
@@ -8230,13 +7794,10 @@ spec:
|
|||||||
properties:
|
properties:
|
||||||
failures:
|
failures:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
format: date-time
|
type: boolean
|
||||||
type: string
|
|
||||||
type: object
|
type: object
|
||||||
jobDisplayName:
|
jobDisplayName:
|
||||||
type: string
|
type: string
|
||||||
jobId:
|
|
||||||
type: string
|
|
||||||
jobRepositoryName:
|
jobRepositoryName:
|
||||||
type: string
|
type: string
|
||||||
jobRequestId:
|
jobRequestId:
|
||||||
@@ -8265,6 +7826,8 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
runnerId:
|
runnerId:
|
||||||
type: integer
|
type: integer
|
||||||
|
runnerJITConfig:
|
||||||
|
type: string
|
||||||
runnerName:
|
runnerName:
|
||||||
type: string
|
type: string
|
||||||
workflowRunId:
|
workflowRunId:
|
||||||
@@ -8276,3 +7839,4 @@ spec:
|
|||||||
storage: true
|
storage: true
|
||||||
subresources:
|
subresources:
|
||||||
status: {}
|
status: {}
|
||||||
|
preserveUnknownFields: false
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.19.0
|
controller-gen.kubebuilder.io/version: v0.17.2
|
||||||
name: ephemeralrunnersets.actions.github.com
|
name: ephemeralrunnersets.actions.github.com
|
||||||
spec:
|
spec:
|
||||||
group: actions.github.com
|
group: actions.github.com
|
||||||
@@ -421,6 +421,7 @@ 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
|
||||||
@@ -435,6 +436,7 @@ 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
|
||||||
@@ -595,6 +597,7 @@ 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
|
||||||
@@ -609,6 +612,7 @@ 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
|
||||||
@@ -697,8 +701,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 subtracting
|
compute a sum by iterating through the elements of this field and adding
|
||||||
"weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
|
"weight" to 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)
|
||||||
@@ -762,6 +766,7 @@ 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
|
||||||
@@ -776,6 +781,7 @@ 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
|
||||||
@@ -936,6 +942,7 @@ 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
|
||||||
@@ -950,6 +957,7 @@ 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
|
||||||
@@ -1076,9 +1084,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -1132,42 +1138,6 @@ 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
|
||||||
@@ -1223,13 +1193,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -1249,9 +1219,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -1500,12 +1468,6 @@ 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: |-
|
||||||
@@ -1896,7 +1858,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -1947,10 +1909,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 overrides the pod-level restart policy. When this field is not specified,
|
This field may only be set for init containers, and the only allowed value is "Always".
|
||||||
|
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.
|
||||||
Additionally, setting the RestartPolicy as "Always" for the init container will
|
Setting the RestartPolicy as "Always" for the init container will have the following effect:
|
||||||
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"
|
||||||
@@ -1962,57 +1924,6 @@ 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.
|
||||||
@@ -2610,9 +2521,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -2666,42 +2575,6 @@ 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
|
||||||
@@ -2757,13 +2630,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -2783,9 +2656,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -3030,12 +2901,6 @@ 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.
|
||||||
@@ -3409,7 +3274,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -3461,51 +3326,9 @@ 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.
|
||||||
You cannot set this field on ephemeral containers.
|
This may only be set for init containers. You cannot set this field on
|
||||||
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.
|
ephemeral containers.
|
||||||
items:
|
type: string
|
||||||
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.
|
||||||
@@ -4024,9 +3847,7 @@ 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.
|
||||||
When using HostNetwork you should specify ports so the scheduler is aware.
|
If this option is set, the ports that will be used must be specified.
|
||||||
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:
|
||||||
@@ -4051,19 +3872,6 @@ 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.
|
||||||
@@ -4099,7 +3907,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
|
||||||
that value or the sum of the normal containers. Limits are applied to init containers
|
of 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.
|
||||||
@@ -4143,9 +3951,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -4199,42 +4005,6 @@ 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
|
||||||
@@ -4290,13 +4060,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -4316,9 +4086,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -4567,12 +4335,6 @@ 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: |-
|
||||||
@@ -4963,7 +4725,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -5014,10 +4776,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 overrides the pod-level restart policy. When this field is not specified,
|
This field may only be set for init containers, and the only allowed value is "Always".
|
||||||
|
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.
|
||||||
Additionally, setting the RestartPolicy as "Always" for the init container will
|
Setting the RestartPolicy as "Always" for the init container will have the following effect:
|
||||||
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"
|
||||||
@@ -5029,57 +4791,6 @@ 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.
|
||||||
@@ -5593,7 +5304,6 @@ 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
|
||||||
@@ -5745,7 +5455,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", "memory" and "hugepages-" resource names only. ResourceClaims are not supported.
|
"cpu" and "memory" 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.
|
||||||
@@ -5758,7 +5468,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -6286,6 +5996,7 @@ 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: |-
|
||||||
@@ -6296,6 +6007,7 @@ 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: |-
|
||||||
@@ -7001,13 +6713,15 @@ 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 or nil value indicates that no
|
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass
|
||||||
VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
|
will be applied to the claim but it's not allowed to reset this field to empty string once it is set.
|
||||||
this field can be reset to its previous value (including nil) to cancel the modification.
|
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass
|
||||||
|
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: |-
|
||||||
@@ -7181,9 +6895,12 @@ 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: endpoints is the endpoint name that details Glusterfs topology.
|
description: |-
|
||||||
|
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: |-
|
||||||
@@ -7237,7 +6954,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) before 1.33.
|
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath).
|
||||||
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:
|
||||||
@@ -7262,7 +6979,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://kubernetes.io/docs/concepts/storage/volumes/#iscsi
|
More info: https://examples.k8s.io/volumes/iscsi/README.md
|
||||||
properties:
|
properties:
|
||||||
chapAuthDiscovery:
|
chapAuthDiscovery:
|
||||||
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
|
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
|
||||||
@@ -7652,110 +7369,6 @@ 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:
|
||||||
@@ -7885,6 +7498,7 @@ 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: |-
|
||||||
@@ -8164,53 +7778,6 @@ spec:
|
|||||||
required:
|
required:
|
||||||
- containers
|
- containers
|
||||||
type: object
|
type: object
|
||||||
vaultConfig:
|
|
||||||
properties:
|
|
||||||
azureKeyVault:
|
|
||||||
properties:
|
|
||||||
certificatePath:
|
|
||||||
type: string
|
|
||||||
clientId:
|
|
||||||
type: string
|
|
||||||
tenantId:
|
|
||||||
type: string
|
|
||||||
url:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- certificatePath
|
|
||||||
- clientId
|
|
||||||
- tenantId
|
|
||||||
- url
|
|
||||||
type: object
|
|
||||||
proxy:
|
|
||||||
properties:
|
|
||||||
http:
|
|
||||||
properties:
|
|
||||||
credentialSecretRef:
|
|
||||||
type: string
|
|
||||||
url:
|
|
||||||
description: Required
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
https:
|
|
||||||
properties:
|
|
||||||
credentialSecretRef:
|
|
||||||
type: string
|
|
||||||
url:
|
|
||||||
description: Required
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
noProxy:
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
type: object
|
|
||||||
type:
|
|
||||||
description: |-
|
|
||||||
VaultType represents the type of vault that can be used in the application.
|
|
||||||
It is used to identify which vault integration should be used to resolve secrets.
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
required:
|
required:
|
||||||
- githubConfigSecret
|
- githubConfigSecret
|
||||||
- githubConfigUrl
|
- githubConfigUrl
|
||||||
@@ -8245,3 +7812,4 @@ spec:
|
|||||||
storage: true
|
storage: true
|
||||||
subresources:
|
subresources:
|
||||||
status: {}
|
status: {}
|
||||||
|
preserveUnknownFields: false
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.19.0
|
controller-gen.kubebuilder.io/version: v0.17.2
|
||||||
name: horizontalrunnerautoscalers.actions.summerwind.dev
|
name: horizontalrunnerautoscalers.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
group: actions.summerwind.dev
|
group: actions.summerwind.dev
|
||||||
@@ -12,313 +12,306 @@ 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
|
description: HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler API
|
||||||
API
|
properties:
|
||||||
properties:
|
apiVersion:
|
||||||
apiVersion:
|
description: |-
|
||||||
description: |-
|
APIVersion defines the versioned schema of this representation of an object.
|
||||||
APIVersion defines the versioned schema of this representation of an object.
|
Servers should convert recognized schemas to the latest internal value, and
|
||||||
Servers should convert recognized schemas to the latest internal value, and
|
may reject unrecognized values.
|
||||||
may reject unrecognized values.
|
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
type: string
|
||||||
type: string
|
kind:
|
||||||
kind:
|
description: |-
|
||||||
description: |-
|
Kind is a string value representing the REST resource this object represents.
|
||||||
Kind is a string value representing the REST resource this object represents.
|
Servers may infer this from the endpoint the client submits requests to.
|
||||||
Servers may infer this from the endpoint the client submits requests to.
|
Cannot be updated.
|
||||||
Cannot be updated.
|
In CamelCase.
|
||||||
In CamelCase.
|
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
type: string
|
||||||
type: string
|
metadata:
|
||||||
metadata:
|
type: object
|
||||||
type: object
|
spec:
|
||||||
spec:
|
description: HorizontalRunnerAutoscalerSpec defines the desired state of HorizontalRunnerAutoscaler
|
||||||
description: HorizontalRunnerAutoscalerSpec defines the desired state
|
properties:
|
||||||
of HorizontalRunnerAutoscaler
|
capacityReservations:
|
||||||
properties:
|
items:
|
||||||
capacityReservations:
|
description: |-
|
||||||
items:
|
CapacityReservation specifies the number of replicas temporarily added
|
||||||
description: |-
|
to the scale target until ExpirationTime.
|
||||||
CapacityReservation specifies the number of replicas temporarily added
|
|
||||||
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:
|
properties:
|
||||||
|
effectiveTime:
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
expirationTime:
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
required:
|
replicas:
|
||||||
- name
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: array
|
||||||
maxReplicas:
|
githubAPICredentialsFrom:
|
||||||
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:
|
properties:
|
||||||
repositoryNames:
|
secretRef:
|
||||||
description: |-
|
properties:
|
||||||
RepositoryNames is the list of repository names to be used for calculating the metric.
|
name:
|
||||||
For example, a repository name is the REPO part of `github.com/USER/REPO`.
|
type: string
|
||||||
items:
|
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
|
type: string
|
||||||
type: array
|
scaleDownThreshold:
|
||||||
scaleDownAdjustment:
|
description: |-
|
||||||
description: |-
|
ScaleDownThreshold is the percentage of busy runners less than which will
|
||||||
ScaleDownAdjustment is the number of runners removed on scale-down.
|
trigger the hpa to scale the runners down.
|
||||||
You can only specify either ScaleDownFactor or ScaleDownAdjustment.
|
type: string
|
||||||
type: integer
|
scaleUpAdjustment:
|
||||||
scaleDownFactor:
|
description: |-
|
||||||
description: |-
|
ScaleUpAdjustment is the number of runners added on scale-up.
|
||||||
ScaleDownFactor is the multiplicative factor applied to the current number of runners used
|
You can only specify either ScaleUpFactor or ScaleUpAdjustment.
|
||||||
to determine how many pods should be removed.
|
type: integer
|
||||||
type: string
|
scaleUpFactor:
|
||||||
scaleDownThreshold:
|
description: |-
|
||||||
description: |-
|
ScaleUpFactor is the multiplicative factor applied to the current number of runners used
|
||||||
ScaleDownThreshold is the percentage of busy runners less than which will
|
to determine how many pods should be added.
|
||||||
trigger the hpa to scale the runners down.
|
type: string
|
||||||
type: string
|
scaleUpThreshold:
|
||||||
scaleUpAdjustment:
|
description: |-
|
||||||
description: |-
|
ScaleUpThreshold is the percentage of busy runners greater than which will
|
||||||
ScaleUpAdjustment is the number of runners added on scale-up.
|
trigger the hpa to scale runners up.
|
||||||
You can only specify either ScaleUpFactor or ScaleUpAdjustment.
|
type: string
|
||||||
type: integer
|
type:
|
||||||
scaleUpFactor:
|
description: |-
|
||||||
description: |-
|
Type is the type of metric to be used for autoscaling.
|
||||||
ScaleUpFactor is the multiplicative factor applied to the current number of runners used
|
It can be TotalNumberOfQueuedAndInProgressWorkflowRuns or PercentageRunnersBusy.
|
||||||
to determine how many pods should be added.
|
type: string
|
||||||
type: string
|
type: object
|
||||||
scaleUpThreshold:
|
type: array
|
||||||
description: |-
|
minReplicas:
|
||||||
ScaleUpThreshold is the percentage of busy runners greater than which will
|
description: MinReplicas is the minimum number of replicas the deployment is allowed to scale
|
||||||
trigger the hpa to scale runners up.
|
type: integer
|
||||||
type: string
|
scaleDownDelaySecondsAfterScaleOut:
|
||||||
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: |-
|
||||||
ScheduledOverride can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule.
|
ScaleDownDelaySecondsAfterScaleUp is the approximate delay for a scale down followed by a scale up
|
||||||
A schedule can optionally be recurring, so that the corresponding override happens every day, week, month, or year.
|
Used to prevent flapping (down->up->down->... loop)
|
||||||
|
type: integer
|
||||||
|
scaleTargetRef:
|
||||||
|
description: ScaleTargetRef is the reference to scaled resource like RunnerDeployment
|
||||||
properties:
|
properties:
|
||||||
endTime:
|
kind:
|
||||||
description: EndTime is the time at which the first override
|
description: Kind is the type of resource being referenced
|
||||||
ends.
|
enum:
|
||||||
format: date-time
|
- RunnerDeployment
|
||||||
|
- RunnerSet
|
||||||
type: string
|
type: string
|
||||||
minReplicas:
|
name:
|
||||||
description: |-
|
description: Name is the name of resource being referenced
|
||||||
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:
|
|
||||||
- endTime
|
|
||||||
- startTime
|
|
||||||
type: object
|
type: object
|
||||||
type: array
|
scaleUpTriggers:
|
||||||
type: object
|
description: |-
|
||||||
status:
|
ScaleUpTriggers is an experimental feature to increase the desired replicas by 1
|
||||||
properties:
|
on each webhook requested received by the webhookBasedAutoscaler.
|
||||||
cacheEntries:
|
|
||||||
items:
|
This feature requires you to also enable and deploy the webhookBasedAutoscaler onto your cluster.
|
||||||
properties:
|
|
||||||
expirationTime:
|
Note that the added runners remain until the next sync period at least,
|
||||||
format: date-time
|
and they may or may not be used by GitHub Actions depending on the timing.
|
||||||
type: string
|
They are intended to be used to gain "resource slack" immediately after you
|
||||||
key:
|
receive a webhook from GitHub, so that you can loosely expect MinReplicas runners to be always available.
|
||||||
type: string
|
items:
|
||||||
value:
|
properties:
|
||||||
type: integer
|
amount:
|
||||||
type: object
|
type: integer
|
||||||
type: array
|
duration:
|
||||||
desiredReplicas:
|
type: string
|
||||||
description: |-
|
githubEvent:
|
||||||
DesiredReplicas is the total number of desired, non-terminated and latest pods to be set for the primary RunnerSet
|
properties:
|
||||||
This doesn't include outdated pods while upgrading the deployment and replacing the runnerset.
|
checkRun:
|
||||||
type: integer
|
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#check_run
|
||||||
lastSuccessfulScaleOutTime:
|
properties:
|
||||||
format: date-time
|
names:
|
||||||
nullable: true
|
description: |-
|
||||||
type: string
|
Names is a list of GitHub Actions glob patterns.
|
||||||
observedGeneration:
|
Any check_run event whose name matches one of patterns in the list can trigger autoscaling.
|
||||||
description: |-
|
Note that check_run name seem to equal to the job name you've defined in your actions workflow yaml file.
|
||||||
ObservedGeneration is the most recent generation observed for the target. It corresponds to e.g.
|
So it is very likely that you can utilize this to trigger depending on the job.
|
||||||
RunnerDeployment's generation, which is updated on mutation by the API Server.
|
items:
|
||||||
format: int64
|
type: string
|
||||||
type: integer
|
type: array
|
||||||
scheduledOverridesSummary:
|
repositories:
|
||||||
description: |-
|
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
|
Repositories is a list of GitHub repositories.
|
||||||
for observability.
|
Any check_run event whose repository matches one of repositories in the list can trigger autoscaling.
|
||||||
type: string
|
items:
|
||||||
type: object
|
type: string
|
||||||
type: object
|
type: array
|
||||||
served: true
|
status:
|
||||||
storage: true
|
type: string
|
||||||
subresources:
|
types:
|
||||||
status: {}
|
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
|
||||||
|
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: {}
|
||||||
|
preserveUnknownFields: false
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.19.0
|
controller-gen.kubebuilder.io/version: v0.17.2
|
||||||
name: runnersets.actions.summerwind.dev
|
name: runnersets.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
group: actions.summerwind.dev
|
group: actions.summerwind.dev
|
||||||
@@ -554,6 +554,7 @@ 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
|
||||||
@@ -568,6 +569,7 @@ 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
|
||||||
@@ -728,6 +730,7 @@ 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
|
||||||
@@ -742,6 +745,7 @@ 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
|
||||||
@@ -830,8 +834,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 subtracting
|
compute a sum by iterating through the elements of this field and adding
|
||||||
"weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
|
"weight" to 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)
|
||||||
@@ -895,6 +899,7 @@ 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
|
||||||
@@ -909,6 +914,7 @@ 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
|
||||||
@@ -1069,6 +1075,7 @@ 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
|
||||||
@@ -1083,6 +1090,7 @@ 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
|
||||||
@@ -1209,9 +1217,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -1265,42 +1271,6 @@ 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
|
||||||
@@ -1356,13 +1326,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -1382,9 +1352,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -1633,12 +1601,6 @@ 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: |-
|
||||||
@@ -2029,7 +1991,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -2080,10 +2042,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 overrides the pod-level restart policy. When this field is not specified,
|
This field may only be set for init containers, and the only allowed value is "Always".
|
||||||
|
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.
|
||||||
Additionally, setting the RestartPolicy as "Always" for the init container will
|
Setting the RestartPolicy as "Always" for the init container will have the following effect:
|
||||||
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"
|
||||||
@@ -2095,57 +2057,6 @@ 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.
|
||||||
@@ -2743,9 +2654,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -2799,42 +2708,6 @@ 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
|
||||||
@@ -2890,13 +2763,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -2916,9 +2789,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -3163,12 +3034,6 @@ 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.
|
||||||
@@ -3542,7 +3407,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -3594,51 +3459,9 @@ 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.
|
||||||
You cannot set this field on ephemeral containers.
|
This may only be set for init containers. You cannot set this field on
|
||||||
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.
|
ephemeral containers.
|
||||||
items:
|
type: string
|
||||||
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.
|
||||||
@@ -4157,9 +3980,7 @@ 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.
|
||||||
When using HostNetwork you should specify ports so the scheduler is aware.
|
If this option is set, the ports that will be used must be specified.
|
||||||
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:
|
||||||
@@ -4184,19 +4005,6 @@ 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.
|
||||||
@@ -4232,7 +4040,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
|
||||||
that value or the sum of the normal containers. Limits are applied to init containers
|
of 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.
|
||||||
@@ -4276,9 +4084,7 @@ 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: |-
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
Name of the environment variable.
|
|
||||||
May consist of any printable ASCII characters except '='.
|
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -4332,42 +4138,6 @@ 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
|
||||||
@@ -4423,13 +4193,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 may consist of any printable ASCII characters except '='.
|
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
|
||||||
When a key exists in multiple
|
will be reported as an event when the container is starting. 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 or Secrets
|
description: EnvFromSource represents the source of a set of ConfigMaps
|
||||||
properties:
|
properties:
|
||||||
configMapRef:
|
configMapRef:
|
||||||
description: The ConfigMap to select from
|
description: The ConfigMap to select from
|
||||||
@@ -4449,9 +4219,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
x-kubernetes-map-type: atomic
|
x-kubernetes-map-type: atomic
|
||||||
prefix:
|
prefix:
|
||||||
description: |-
|
description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||||
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
|
||||||
@@ -4700,12 +4468,6 @@ 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: |-
|
||||||
@@ -5096,7 +4858,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -5147,10 +4909,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 overrides the pod-level restart policy. When this field is not specified,
|
This field may only be set for init containers, and the only allowed value is "Always".
|
||||||
|
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.
|
||||||
Additionally, setting the RestartPolicy as "Always" for the init container will
|
Setting the RestartPolicy as "Always" for the init container will have the following effect:
|
||||||
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"
|
||||||
@@ -5162,57 +4924,6 @@ 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.
|
||||||
@@ -5726,7 +5437,6 @@ 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
|
||||||
@@ -5878,7 +5588,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", "memory" and "hugepages-" resource names only. ResourceClaims are not supported.
|
"cpu" and "memory" 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.
|
||||||
@@ -5891,7 +5601,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 field depends on the
|
This is an alpha field and requires enabling 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.
|
||||||
@@ -6416,6 +6126,7 @@ 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: |-
|
||||||
@@ -6426,6 +6137,7 @@ 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: |-
|
||||||
@@ -7131,13 +6843,15 @@ 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 or nil value indicates that no
|
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass
|
||||||
VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
|
will be applied to the claim but it's not allowed to reset this field to empty string once it is set.
|
||||||
this field can be reset to its previous value (including nil) to cancel the modification.
|
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass
|
||||||
|
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: |-
|
||||||
@@ -7311,9 +7025,12 @@ 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: endpoints is the endpoint name that details Glusterfs topology.
|
description: |-
|
||||||
|
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: |-
|
||||||
@@ -7367,7 +7084,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) before 1.33.
|
Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath).
|
||||||
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:
|
||||||
@@ -7392,7 +7109,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://kubernetes.io/docs/concepts/storage/volumes/#iscsi
|
More info: https://examples.k8s.io/volumes/iscsi/README.md
|
||||||
properties:
|
properties:
|
||||||
chapAuthDiscovery:
|
chapAuthDiscovery:
|
||||||
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
|
description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication
|
||||||
@@ -7782,110 +7499,6 @@ 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:
|
||||||
@@ -8015,6 +7628,7 @@ 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: |-
|
||||||
@@ -8556,13 +8170,15 @@ 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 or nil value indicates that no
|
it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass
|
||||||
VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
|
will be applied to the claim but it's not allowed to reset this field to empty string once it is set.
|
||||||
this field can be reset to its previous value (including nil) to cancel the modification.
|
If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass
|
||||||
|
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: |-
|
||||||
@@ -8662,11 +8278,13 @@ 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."
|
||||||
@@ -8737,6 +8355,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- selector
|
- selector
|
||||||
|
- serviceName
|
||||||
- template
|
- template
|
||||||
type: object
|
type: object
|
||||||
status:
|
status:
|
||||||
@@ -8770,3 +8389,4 @@ spec:
|
|||||||
storage: true
|
storage: true
|
||||||
subresources:
|
subresources:
|
||||||
status: {}
|
status: {}
|
||||||
|
preserveUnknownFields: false
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ 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"
|
||||||
@@ -33,7 +32,6 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
|
|
||||||
v1alpha1 "github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
v1alpha1 "github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
||||||
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1/appconfig"
|
|
||||||
"github.com/actions/actions-runner-controller/controllers/actions.github.com/metrics"
|
"github.com/actions/actions-runner-controller/controllers/actions.github.com/metrics"
|
||||||
"github.com/actions/actions-runner-controller/github/actions"
|
"github.com/actions/actions-runner-controller/github/actions"
|
||||||
hash "github.com/actions/actions-runner-controller/hash"
|
hash "github.com/actions/actions-runner-controller/hash"
|
||||||
@@ -85,14 +83,14 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Deleting resources")
|
log.Info("Deleting resources")
|
||||||
requeue, err := r.cleanupResources(ctx, autoscalingListener, log)
|
done, 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 requeue {
|
if !done {
|
||||||
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, RequeueAfter: time.Second}, nil
|
return ctrl.Result{Requeue: true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Removing finalizer")
|
log.Info("Removing finalizer")
|
||||||
@@ -130,24 +128,41 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
|||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
appConfig, err := r.GetAppConfig(ctx, &autoscalingRunnerSet)
|
// Check if the GitHub config secret exists
|
||||||
if err != nil {
|
secret := new(corev1.Secret)
|
||||||
log.Error(
|
if err := r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, Name: autoscalingListener.Spec.GitHubConfigSecret}, secret); err != nil {
|
||||||
err,
|
log.Error(err, "Failed to find GitHub config secret.",
|
||||||
"Failed to get app config for AutoscalingRunnerSet.",
|
"namespace", autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||||
"namespace",
|
"name", autoscalingListener.Spec.GitHubConfigSecret)
|
||||||
autoscalingRunnerSet.Namespace,
|
|
||||||
"name",
|
|
||||||
autoscalingRunnerSet.GitHubConfigSecret,
|
|
||||||
)
|
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a mirror secret in the same namespace as the AutoscalingListener
|
||||||
|
mirrorSecret := new(corev1.Secret)
|
||||||
|
if err := r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Namespace, Name: scaleSetListenerSecretMirrorName(autoscalingListener)}, mirrorSecret); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) {
|
||||||
|
log.Error(err, "Unable to get listener secret mirror", "namespace", autoscalingListener.Namespace, "name", scaleSetListenerSecretMirrorName(autoscalingListener))
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a mirror secret for the listener pod in the Controller namespace for listener pod to use
|
||||||
|
log.Info("Creating a mirror listener secret for the listener pod")
|
||||||
|
return r.createSecretsForListener(ctx, autoscalingListener, secret, log)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure the mirror secret is up to date
|
||||||
|
mirrorSecretDataHash := mirrorSecret.Labels["secret-data-hash"]
|
||||||
|
secretDataHash := hash.ComputeTemplateHash(secret.Data)
|
||||||
|
if mirrorSecretDataHash != secretDataHash {
|
||||||
|
log.Info("Updating mirror listener secret for the listener pod", "mirrorSecretDataHash", mirrorSecretDataHash, "secretDataHash", secretDataHash)
|
||||||
|
return r.updateSecretsForListener(ctx, secret, mirrorSecret, log)
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure the runner scale set listener service account is created for the listener pod in the controller namespace
|
// Make sure the runner scale set listener service account is created for the listener pod in the controller namespace
|
||||||
serviceAccount := new(corev1.ServiceAccount)
|
serviceAccount := new(corev1.ServiceAccount)
|
||||||
if err := r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Namespace, Name: autoscalingListener.Name}, serviceAccount); err != nil {
|
if err := r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Namespace, Name: scaleSetListenerServiceAccountName(autoscalingListener)}, serviceAccount); err != nil {
|
||||||
if !kerrors.IsNotFound(err) {
|
if !kerrors.IsNotFound(err) {
|
||||||
log.Error(err, "Unable to get listener service accounts", "namespace", autoscalingListener.Namespace, "name", autoscalingListener.Name)
|
log.Error(err, "Unable to get listener service accounts", "namespace", autoscalingListener.Namespace, "name", scaleSetListenerServiceAccountName(autoscalingListener))
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,9 +175,9 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
|||||||
|
|
||||||
// Make sure the runner scale set listener role is created in the AutoscalingRunnerSet namespace
|
// Make sure the runner scale set listener role is created in the AutoscalingRunnerSet namespace
|
||||||
listenerRole := new(rbacv1.Role)
|
listenerRole := new(rbacv1.Role)
|
||||||
if err := r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, Name: autoscalingListener.Name}, listenerRole); err != nil {
|
if err := r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, Name: scaleSetListenerRoleName(autoscalingListener)}, listenerRole); err != nil {
|
||||||
if !kerrors.IsNotFound(err) {
|
if !kerrors.IsNotFound(err) {
|
||||||
log.Error(err, "Unable to get listener role", "namespace", autoscalingListener.Spec.AutoscalingRunnerSetNamespace, "name", autoscalingListener.Name)
|
log.Error(err, "Unable to get listener role", "namespace", autoscalingListener.Spec.AutoscalingRunnerSetNamespace, "name", scaleSetListenerRoleName(autoscalingListener))
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,9 +197,9 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
|||||||
|
|
||||||
// Make sure the runner scale set listener role binding is created
|
// Make sure the runner scale set listener role binding is created
|
||||||
listenerRoleBinding := new(rbacv1.RoleBinding)
|
listenerRoleBinding := new(rbacv1.RoleBinding)
|
||||||
if err := r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, Name: autoscalingListener.Name}, listenerRoleBinding); err != nil {
|
if err := r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, Name: scaleSetListenerRoleName(autoscalingListener)}, listenerRoleBinding); err != nil {
|
||||||
if !kerrors.IsNotFound(err) {
|
if !kerrors.IsNotFound(err) {
|
||||||
log.Error(err, "Unable to get listener role binding", "namespace", autoscalingListener.Spec.AutoscalingRunnerSetNamespace, "name", autoscalingListener.Name)
|
log.Error(err, "Unable to get listener role binding", "namespace", autoscalingListener.Spec.AutoscalingRunnerSetNamespace, "name", scaleSetListenerRoleName(autoscalingListener))
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +239,7 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
|||||||
|
|
||||||
// Create a listener pod in the controller namespace
|
// Create a listener pod in the controller namespace
|
||||||
log.Info("Creating a listener pod")
|
log.Info("Creating a listener pod")
|
||||||
return r.createListenerPod(ctx, &autoscalingRunnerSet, autoscalingListener, serviceAccount, appConfig, log)
|
return r.createListenerPod(ctx, &autoscalingRunnerSet, autoscalingListener, serviceAccount, mirrorSecret, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := listenerContainerStatus(listenerPod)
|
cs := listenerContainerStatus(listenerPod)
|
||||||
@@ -245,19 +260,6 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
|||||||
log.Error(err, "Unable to delete the listener pod", "namespace", listenerPod.Namespace, "name", listenerPod.Name)
|
log.Error(err, "Unable to delete the listener pod", "namespace", listenerPod.Namespace, "name", listenerPod.Name)
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete the listener config secret as well, so it gets recreated when the listener pod is recreated, with any new data if it exists
|
|
||||||
var configSecret corev1.Secret
|
|
||||||
err := r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Namespace, Name: scaleSetListenerConfigName(autoscalingListener)}, &configSecret)
|
|
||||||
switch {
|
|
||||||
case err == nil && configSecret.DeletionTimestamp.IsZero():
|
|
||||||
log.Info("Deleting the listener config secret")
|
|
||||||
if err := r.Delete(ctx, &configSecret); err != nil {
|
|
||||||
return ctrl.Result{}, fmt.Errorf("failed to delete listener config secret: %w", err)
|
|
||||||
}
|
|
||||||
case !kerrors.IsNotFound(err):
|
|
||||||
return ctrl.Result{}, fmt.Errorf("failed to get the listener config secret: %w", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
case cs.State.Running != nil:
|
case cs.State.Running != nil:
|
||||||
@@ -273,7 +275,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) (requeue bool, err error) {
|
func (r *AutoscalingListenerReconciler) cleanupResources(ctx context.Context, autoscalingListener *v1alpha1.AutoscalingListener, logger logr.Logger) (done 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)
|
||||||
@@ -285,7 +287,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requeue = true
|
return false, nil
|
||||||
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:
|
||||||
@@ -303,7 +305,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requeue = true
|
return false, nil
|
||||||
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)
|
||||||
}
|
}
|
||||||
@@ -320,7 +322,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requeue = true
|
return false, nil
|
||||||
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)
|
||||||
}
|
}
|
||||||
@@ -328,7 +330,7 @@ func (r *AutoscalingListenerReconciler) cleanupResources(ctx context.Context, au
|
|||||||
}
|
}
|
||||||
|
|
||||||
listenerRoleBinding := new(rbacv1.RoleBinding)
|
listenerRoleBinding := new(rbacv1.RoleBinding)
|
||||||
err = r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, Name: autoscalingListener.Name}, listenerRoleBinding)
|
err = r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, Name: scaleSetListenerRoleName(autoscalingListener)}, listenerRoleBinding)
|
||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
if listenerRoleBinding.DeletionTimestamp.IsZero() {
|
if listenerRoleBinding.DeletionTimestamp.IsZero() {
|
||||||
@@ -337,14 +339,14 @@ 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requeue = true
|
return false, nil
|
||||||
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)
|
||||||
}
|
}
|
||||||
logger.Info("Listener role binding is deleted")
|
logger.Info("Listener role binding is deleted")
|
||||||
|
|
||||||
listenerRole := new(rbacv1.Role)
|
listenerRole := new(rbacv1.Role)
|
||||||
err = r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, Name: autoscalingListener.Name}, listenerRole)
|
err = r.Get(ctx, types.NamespacedName{Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, Name: scaleSetListenerRoleName(autoscalingListener)}, listenerRole)
|
||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
if listenerRole.DeletionTimestamp.IsZero() {
|
if listenerRole.DeletionTimestamp.IsZero() {
|
||||||
@@ -353,7 +355,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requeue = true
|
return false, nil
|
||||||
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)
|
||||||
}
|
}
|
||||||
@@ -361,7 +363,7 @@ func (r *AutoscalingListenerReconciler) cleanupResources(ctx context.Context, au
|
|||||||
|
|
||||||
logger.Info("Cleaning up the listener service account")
|
logger.Info("Cleaning up the listener service account")
|
||||||
listenerSa := new(corev1.ServiceAccount)
|
listenerSa := new(corev1.ServiceAccount)
|
||||||
err = r.Get(ctx, types.NamespacedName{Name: autoscalingListener.Name, Namespace: autoscalingListener.Namespace}, listenerSa)
|
err = r.Get(ctx, types.NamespacedName{Name: scaleSetListenerServiceAccountName(autoscalingListener), Namespace: autoscalingListener.Namespace}, listenerSa)
|
||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
if listenerSa.DeletionTimestamp.IsZero() {
|
if listenerSa.DeletionTimestamp.IsZero() {
|
||||||
@@ -370,13 +372,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requeue = true
|
return false, nil
|
||||||
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 requeue, nil
|
return true, 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) {
|
||||||
@@ -396,7 +398,7 @@ func (r *AutoscalingListenerReconciler) createServiceAccountForListener(ctx cont
|
|||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *AutoscalingListenerReconciler) createListenerPod(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, autoscalingListener *v1alpha1.AutoscalingListener, serviceAccount *corev1.ServiceAccount, appConfig *appconfig.AppConfig, logger logr.Logger) (ctrl.Result, error) {
|
func (r *AutoscalingListenerReconciler) createListenerPod(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, autoscalingListener *v1alpha1.AutoscalingListener, serviceAccount *corev1.ServiceAccount, secret *corev1.Secret, logger logr.Logger) (ctrl.Result, error) {
|
||||||
var envs []corev1.EnvVar
|
var envs []corev1.EnvVar
|
||||||
if autoscalingListener.Spec.Proxy != nil {
|
if autoscalingListener.Spec.Proxy != nil {
|
||||||
httpURL := corev1.EnvVar{
|
httpURL := corev1.EnvVar{
|
||||||
@@ -465,7 +467,7 @@ func (r *AutoscalingListenerReconciler) createListenerPod(ctx context.Context, a
|
|||||||
|
|
||||||
logger.Info("Creating listener config secret")
|
logger.Info("Creating listener config secret")
|
||||||
|
|
||||||
podConfig, err := r.newScaleSetListenerConfig(autoscalingListener, appConfig, metricsConfig, cert)
|
podConfig, err := r.newScaleSetListenerConfig(autoscalingListener, secret, metricsConfig, cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "Failed to build listener config secret")
|
logger.Error(err, "Failed to build listener config secret")
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
@@ -484,7 +486,7 @@ func (r *AutoscalingListenerReconciler) createListenerPod(ctx context.Context, a
|
|||||||
return ctrl.Result{Requeue: true}, nil
|
return ctrl.Result{Requeue: true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
newPod, err := r.newScaleSetListenerPod(autoscalingListener, &podConfig, serviceAccount, metricsConfig, envs...)
|
newPod, err := r.newScaleSetListenerPod(autoscalingListener, &podConfig, serviceAccount, secret, metricsConfig, envs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "Failed to build listener pod")
|
logger.Error(err, "Failed to build listener pod")
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
@@ -543,6 +545,23 @@ func (r *AutoscalingListenerReconciler) certificate(ctx context.Context, autosca
|
|||||||
return certificate, nil
|
return certificate, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *AutoscalingListenerReconciler) createSecretsForListener(ctx context.Context, autoscalingListener *v1alpha1.AutoscalingListener, secret *corev1.Secret, logger logr.Logger) (ctrl.Result, error) {
|
||||||
|
newListenerSecret := r.newScaleSetListenerSecretMirror(autoscalingListener, secret)
|
||||||
|
|
||||||
|
if err := ctrl.SetControllerReference(autoscalingListener, newListenerSecret, r.Scheme); err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Creating listener secret", "namespace", newListenerSecret.Namespace, "name", newListenerSecret.Name)
|
||||||
|
if err := r.Create(ctx, newListenerSecret); err != nil {
|
||||||
|
logger.Error(err, "Unable to create listener secret", "namespace", newListenerSecret.Namespace, "name", newListenerSecret.Name)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Created listener secret", "namespace", newListenerSecret.Namespace, "name", newListenerSecret.Name)
|
||||||
|
return ctrl.Result{Requeue: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *AutoscalingListenerReconciler) createProxySecret(ctx context.Context, autoscalingListener *v1alpha1.AutoscalingListener, logger logr.Logger) (ctrl.Result, error) {
|
func (r *AutoscalingListenerReconciler) createProxySecret(ctx context.Context, autoscalingListener *v1alpha1.AutoscalingListener, logger logr.Logger) (ctrl.Result, error) {
|
||||||
data, err := autoscalingListener.Spec.Proxy.ToSecretData(func(s string) (*corev1.Secret, error) {
|
data, err := autoscalingListener.Spec.Proxy.ToSecretData(func(s string) (*corev1.Secret, error) {
|
||||||
var secret corev1.Secret
|
var secret corev1.Secret
|
||||||
@@ -582,6 +601,22 @@ func (r *AutoscalingListenerReconciler) createProxySecret(ctx context.Context, a
|
|||||||
return ctrl.Result{Requeue: true}, nil
|
return ctrl.Result{Requeue: true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *AutoscalingListenerReconciler) updateSecretsForListener(ctx context.Context, secret *corev1.Secret, mirrorSecret *corev1.Secret, logger logr.Logger) (ctrl.Result, error) {
|
||||||
|
dataHash := hash.ComputeTemplateHash(secret.Data)
|
||||||
|
updatedMirrorSecret := mirrorSecret.DeepCopy()
|
||||||
|
updatedMirrorSecret.Labels["secret-data-hash"] = dataHash
|
||||||
|
updatedMirrorSecret.Data = secret.Data
|
||||||
|
|
||||||
|
logger.Info("Updating listener mirror secret", "namespace", updatedMirrorSecret.Namespace, "name", updatedMirrorSecret.Name, "hash", dataHash)
|
||||||
|
if err := r.Update(ctx, updatedMirrorSecret); err != nil {
|
||||||
|
logger.Error(err, "Unable to update listener mirror secret", "namespace", updatedMirrorSecret.Namespace, "name", updatedMirrorSecret.Name)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Updated listener mirror secret", "namespace", updatedMirrorSecret.Namespace, "name", updatedMirrorSecret.Name, "hash", dataHash)
|
||||||
|
return ctrl.Result{Requeue: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *AutoscalingListenerReconciler) createRoleForListener(ctx context.Context, autoscalingListener *v1alpha1.AutoscalingListener, logger logr.Logger) (ctrl.Result, error) {
|
func (r *AutoscalingListenerReconciler) createRoleForListener(ctx context.Context, autoscalingListener *v1alpha1.AutoscalingListener, logger logr.Logger) (ctrl.Result, error) {
|
||||||
newRole := r.newScaleSetListenerRole(autoscalingListener)
|
newRole := r.newScaleSetListenerRole(autoscalingListener)
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
|
||||||
ghalistenerconfig "github.com/actions/actions-runner-controller/cmd/ghalistener/config"
|
listenerconfig "github.com/actions/actions-runner-controller/cmd/ghalistener/config"
|
||||||
"github.com/actions/actions-runner-controller/github/actions/fake"
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
@@ -26,8 +25,9 @@ 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() {
|
||||||
@@ -43,17 +43,10 @@ var _ = Describe("Test AutoScalingListener controller", func() {
|
|||||||
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
||||||
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
||||||
|
|
||||||
secretResolver := NewSecretResolver(mgr.GetClient(), fake.NewMultiClient())
|
|
||||||
|
|
||||||
rb := ResourceBuilder{
|
|
||||||
SecretResolver: secretResolver,
|
|
||||||
}
|
|
||||||
|
|
||||||
controller := &AutoscalingListenerReconciler{
|
controller := &AutoscalingListenerReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ResourceBuilder: rb,
|
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -141,25 +134,37 @@ var _ = Describe("Test AutoScalingListener controller", func() {
|
|||||||
autoscalingListenerTestTimeout,
|
autoscalingListenerTestTimeout,
|
||||||
autoscalingListenerTestInterval).Should(BeEquivalentTo(autoscalingListenerFinalizerName), "AutoScalingListener should have a finalizer")
|
autoscalingListenerTestInterval).Should(BeEquivalentTo(autoscalingListenerFinalizerName), "AutoScalingListener should have a finalizer")
|
||||||
|
|
||||||
|
// Check if secret is created
|
||||||
|
mirrorSecret := new(corev1.Secret)
|
||||||
|
Eventually(
|
||||||
|
func() (string, error) {
|
||||||
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: scaleSetListenerSecretMirrorName(autoscalingListener), Namespace: autoscalingListener.Namespace}, mirrorSecret)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(mirrorSecret.Data["github_token"]), nil
|
||||||
|
},
|
||||||
|
autoscalingListenerTestTimeout,
|
||||||
|
autoscalingListenerTestInterval).Should(BeEquivalentTo(autoscalingListenerTestGitHubToken), "Mirror secret should be created")
|
||||||
|
|
||||||
// Check if service account is created
|
// Check if service account is created
|
||||||
serviceAccount := new(corev1.ServiceAccount)
|
serviceAccount := new(corev1.ServiceAccount)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (string, error) {
|
func() (string, error) {
|
||||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: autoscalingListener.Name, Namespace: autoscalingListener.Namespace}, serviceAccount)
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: scaleSetListenerServiceAccountName(autoscalingListener), Namespace: autoscalingListener.Namespace}, serviceAccount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return serviceAccount.Name, nil
|
return serviceAccount.Name, nil
|
||||||
},
|
},
|
||||||
autoscalingListenerTestTimeout,
|
autoscalingListenerTestTimeout,
|
||||||
autoscalingListenerTestInterval,
|
autoscalingListenerTestInterval).Should(BeEquivalentTo(scaleSetListenerServiceAccountName(autoscalingListener)), "Service account should be created")
|
||||||
).Should(BeEquivalentTo(autoscalingListener.Name), "Service account should be created")
|
|
||||||
|
|
||||||
// Check if role is created
|
// Check if role is created
|
||||||
role := new(rbacv1.Role)
|
role := new(rbacv1.Role)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() ([]rbacv1.PolicyRule, error) {
|
func() ([]rbacv1.PolicyRule, error) {
|
||||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: autoscalingListener.Name, Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace}, role)
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: scaleSetListenerRoleName(autoscalingListener), Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace}, role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -173,7 +178,7 @@ var _ = Describe("Test AutoScalingListener controller", func() {
|
|||||||
roleBinding := new(rbacv1.RoleBinding)
|
roleBinding := new(rbacv1.RoleBinding)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (string, error) {
|
func() (string, error) {
|
||||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: autoscalingListener.Name, Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace}, roleBinding)
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: scaleSetListenerRoleName(autoscalingListener), Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace}, roleBinding)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -181,7 +186,7 @@ var _ = Describe("Test AutoScalingListener controller", func() {
|
|||||||
return roleBinding.RoleRef.Name, nil
|
return roleBinding.RoleRef.Name, nil
|
||||||
},
|
},
|
||||||
autoscalingListenerTestTimeout,
|
autoscalingListenerTestTimeout,
|
||||||
autoscalingListenerTestInterval).Should(BeEquivalentTo(autoscalingListener.Name), "Rolebinding should be created")
|
autoscalingListenerTestInterval).Should(BeEquivalentTo(scaleSetListenerRoleName(autoscalingListener)), "Rolebinding should be created")
|
||||||
|
|
||||||
// Check if pod is created
|
// Check if pod is created
|
||||||
pod := new(corev1.Pod)
|
pod := new(corev1.Pod)
|
||||||
@@ -243,7 +248,7 @@ var _ = Describe("Test AutoScalingListener controller", func() {
|
|||||||
Eventually(
|
Eventually(
|
||||||
func() bool {
|
func() bool {
|
||||||
roleBinding := new(rbacv1.RoleBinding)
|
roleBinding := new(rbacv1.RoleBinding)
|
||||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: autoscalingListener.Name, Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace}, roleBinding)
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: scaleSetListenerRoleName(autoscalingListener), Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace}, roleBinding)
|
||||||
return kerrors.IsNotFound(err)
|
return kerrors.IsNotFound(err)
|
||||||
},
|
},
|
||||||
autoscalingListenerTestTimeout,
|
autoscalingListenerTestTimeout,
|
||||||
@@ -254,7 +259,7 @@ var _ = Describe("Test AutoScalingListener controller", func() {
|
|||||||
Eventually(
|
Eventually(
|
||||||
func() bool {
|
func() bool {
|
||||||
role := new(rbacv1.Role)
|
role := new(rbacv1.Role)
|
||||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: autoscalingListener.Name, Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace}, role)
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: scaleSetListenerRoleName(autoscalingListener), Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace}, role)
|
||||||
return kerrors.IsNotFound(err)
|
return kerrors.IsNotFound(err)
|
||||||
},
|
},
|
||||||
autoscalingListenerTestTimeout,
|
autoscalingListenerTestTimeout,
|
||||||
@@ -335,7 +340,7 @@ var _ = Describe("Test AutoScalingListener controller", func() {
|
|||||||
role := new(rbacv1.Role)
|
role := new(rbacv1.Role)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() ([]rbacv1.PolicyRule, error) {
|
func() ([]rbacv1.PolicyRule, error) {
|
||||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: autoscalingListener.Name, Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace}, role)
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: scaleSetListenerRoleName(autoscalingListener), Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace}, role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -346,7 +351,7 @@ var _ = Describe("Test AutoScalingListener controller", func() {
|
|||||||
autoscalingListenerTestInterval).Should(BeEquivalentTo(rulesForListenerRole([]string{updated.Spec.EphemeralRunnerSetName})), "Role should be updated")
|
autoscalingListenerTestInterval).Should(BeEquivalentTo(rulesForListenerRole([]string{updated.Spec.EphemeralRunnerSetName})), "Role should be updated")
|
||||||
})
|
})
|
||||||
|
|
||||||
It("It should re-create pod and config secret whenever listener container is terminated", func() {
|
It("It should re-create pod whenever listener container is terminated", func() {
|
||||||
// Waiting for the pod is created
|
// Waiting for the pod is created
|
||||||
pod := new(corev1.Pod)
|
pod := new(corev1.Pod)
|
||||||
Eventually(
|
Eventually(
|
||||||
@@ -362,18 +367,7 @@ var _ = Describe("Test AutoScalingListener controller", func() {
|
|||||||
autoscalingListenerTestInterval,
|
autoscalingListenerTestInterval,
|
||||||
).Should(BeEquivalentTo(autoscalingListener.Name), "Pod should be created")
|
).Should(BeEquivalentTo(autoscalingListener.Name), "Pod should be created")
|
||||||
|
|
||||||
secret := new(corev1.Secret)
|
|
||||||
Eventually(
|
|
||||||
func() error {
|
|
||||||
return k8sClient.Get(ctx, client.ObjectKey{Name: scaleSetListenerConfigName(autoscalingListener), Namespace: autoscalingListener.Namespace}, secret)
|
|
||||||
},
|
|
||||||
autoscalingListenerTestTimeout,
|
|
||||||
autoscalingListenerTestInterval,
|
|
||||||
).Should(Succeed(), "Config secret should be created")
|
|
||||||
|
|
||||||
oldPodUID := string(pod.UID)
|
oldPodUID := string(pod.UID)
|
||||||
oldSecretUID := string(secret.UID)
|
|
||||||
|
|
||||||
updated := pod.DeepCopy()
|
updated := pod.DeepCopy()
|
||||||
updated.Status.ContainerStatuses = []corev1.ContainerStatus{
|
updated.Status.ContainerStatuses = []corev1.ContainerStatus{
|
||||||
{
|
{
|
||||||
@@ -402,21 +396,75 @@ var _ = Describe("Test AutoScalingListener controller", func() {
|
|||||||
autoscalingListenerTestTimeout,
|
autoscalingListenerTestTimeout,
|
||||||
autoscalingListenerTestInterval,
|
autoscalingListenerTestInterval,
|
||||||
).ShouldNot(BeEquivalentTo(oldPodUID), "Pod should be re-created")
|
).ShouldNot(BeEquivalentTo(oldPodUID), "Pod should be re-created")
|
||||||
|
})
|
||||||
|
|
||||||
// Check if config secret is re-created
|
It("It should update mirror secrets to match secret used by AutoScalingRunnerSet", func() {
|
||||||
|
// Waiting for the pod is created
|
||||||
|
pod := new(corev1.Pod)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (string, error) {
|
func() (string, error) {
|
||||||
secret := new(corev1.Secret)
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: autoscalingListener.Name, Namespace: autoscalingListener.Namespace}, pod)
|
||||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: scaleSetListenerConfigName(autoscalingListener), Namespace: autoscalingListener.Namespace}, secret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return string(secret.UID), nil
|
return pod.Name, nil
|
||||||
},
|
},
|
||||||
autoscalingListenerTestTimeout,
|
autoscalingListenerTestTimeout,
|
||||||
autoscalingListenerTestInterval,
|
autoscalingListenerTestInterval).Should(BeEquivalentTo(autoscalingListener.Name), "Pod should be created")
|
||||||
).ShouldNot(BeEquivalentTo(oldSecretUID), "Config secret should be re-created")
|
|
||||||
|
// Update the secret
|
||||||
|
updatedSecret := configSecret.DeepCopy()
|
||||||
|
updatedSecret.Data["github_token"] = []byte(autoscalingListenerTestGitHubToken + "_updated")
|
||||||
|
err := k8sClient.Update(ctx, updatedSecret)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "failed to update test secret")
|
||||||
|
|
||||||
|
updatedPod := pod.DeepCopy()
|
||||||
|
// Ignore status running and consult the container state
|
||||||
|
updatedPod.Status.Phase = corev1.PodRunning
|
||||||
|
updatedPod.Status.ContainerStatuses = []corev1.ContainerStatus{
|
||||||
|
{
|
||||||
|
Name: autoscalingListenerContainerName,
|
||||||
|
State: corev1.ContainerState{
|
||||||
|
Terminated: &corev1.ContainerStateTerminated{
|
||||||
|
ExitCode: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = k8sClient.Status().Update(ctx, updatedPod)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "failed to update test pod to failed")
|
||||||
|
|
||||||
|
// Check if mirror secret is updated with right data
|
||||||
|
mirrorSecret := new(corev1.Secret)
|
||||||
|
Eventually(
|
||||||
|
func() (map[string][]byte, error) {
|
||||||
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: scaleSetListenerSecretMirrorName(autoscalingListener), Namespace: autoscalingListener.Namespace}, mirrorSecret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mirrorSecret.Data, nil
|
||||||
|
},
|
||||||
|
autoscalingListenerTestTimeout,
|
||||||
|
autoscalingListenerTestInterval).Should(BeEquivalentTo(updatedSecret.Data), "Mirror secret should be updated")
|
||||||
|
|
||||||
|
// Check if we re-created a new pod
|
||||||
|
Eventually(
|
||||||
|
func() error {
|
||||||
|
latestPod := new(corev1.Pod)
|
||||||
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: autoscalingListener.Name, Namespace: autoscalingListener.Namespace}, latestPod)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if latestPod.UID == pod.UID {
|
||||||
|
return fmt.Errorf("Pod should be recreated")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
autoscalingListenerTestTimeout,
|
||||||
|
autoscalingListenerTestInterval).Should(Succeed(), "Pod should be recreated")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -459,17 +507,10 @@ var _ = Describe("Test AutoScalingListener customization", func() {
|
|||||||
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
||||||
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
||||||
|
|
||||||
secretResolver := NewSecretResolver(mgr.GetClient(), fake.NewMultiClient())
|
|
||||||
|
|
||||||
rb := ResourceBuilder{
|
|
||||||
SecretResolver: secretResolver,
|
|
||||||
}
|
|
||||||
|
|
||||||
controller := &AutoscalingListenerReconciler{
|
controller := &AutoscalingListenerReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ResourceBuilder: rb,
|
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -739,17 +780,11 @@ var _ = Describe("Test AutoScalingListener controller with proxy", func() {
|
|||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
||||||
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
||||||
secretResolver := NewSecretResolver(mgr.GetClient(), fake.NewMultiClient())
|
|
||||||
|
|
||||||
rb := ResourceBuilder{
|
|
||||||
SecretResolver: secretResolver,
|
|
||||||
}
|
|
||||||
|
|
||||||
controller := &AutoscalingListenerReconciler{
|
controller := &AutoscalingListenerReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ResourceBuilder: rb,
|
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -942,17 +977,10 @@ var _ = Describe("Test AutoScalingListener controller with template modification
|
|||||||
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
||||||
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
||||||
|
|
||||||
secretResolver := NewSecretResolver(mgr.GetClient(), fake.NewMultiClient())
|
|
||||||
|
|
||||||
rb := ResourceBuilder{
|
|
||||||
SecretResolver: secretResolver,
|
|
||||||
}
|
|
||||||
|
|
||||||
controller := &AutoscalingListenerReconciler{
|
controller := &AutoscalingListenerReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ResourceBuilder: rb,
|
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -1045,12 +1073,6 @@ var _ = Describe("Test GitHub Server TLS configuration", func() {
|
|||||||
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
||||||
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
||||||
|
|
||||||
secretResolver := NewSecretResolver(mgr.GetClient(), fake.NewMultiClient())
|
|
||||||
|
|
||||||
rb := ResourceBuilder{
|
|
||||||
SecretResolver: secretResolver,
|
|
||||||
}
|
|
||||||
|
|
||||||
cert, err := os.ReadFile(filepath.Join(
|
cert, err := os.ReadFile(filepath.Join(
|
||||||
"../../",
|
"../../",
|
||||||
"github",
|
"github",
|
||||||
@@ -1072,10 +1094,9 @@ var _ = Describe("Test GitHub Server TLS configuration", func() {
|
|||||||
Expect(err).NotTo(HaveOccurred(), "failed to create configmap with root CAs")
|
Expect(err).NotTo(HaveOccurred(), "failed to create configmap with root CAs")
|
||||||
|
|
||||||
controller := &AutoscalingListenerReconciler{
|
controller := &AutoscalingListenerReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ResourceBuilder: rb,
|
|
||||||
}
|
}
|
||||||
err = controller.SetupWithManager(mgr)
|
err = controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -1090,7 +1111,7 @@ var _ = Describe("Test GitHub Server TLS configuration", func() {
|
|||||||
Spec: v1alpha1.AutoscalingRunnerSetSpec{
|
Spec: v1alpha1.AutoscalingRunnerSetSpec{
|
||||||
GitHubConfigUrl: "https://github.com/owner/repo",
|
GitHubConfigUrl: "https://github.com/owner/repo",
|
||||||
GitHubConfigSecret: configSecret.Name,
|
GitHubConfigSecret: configSecret.Name,
|
||||||
GitHubServerTLS: &v1alpha1.TLSConfig{
|
GitHubServerTLS: &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
@@ -1126,7 +1147,7 @@ var _ = Describe("Test GitHub Server TLS configuration", func() {
|
|||||||
Spec: v1alpha1.AutoscalingListenerSpec{
|
Spec: v1alpha1.AutoscalingListenerSpec{
|
||||||
GitHubConfigUrl: "https://github.com/owner/repo",
|
GitHubConfigUrl: "https://github.com/owner/repo",
|
||||||
GitHubConfigSecret: configSecret.Name,
|
GitHubConfigSecret: configSecret.Name,
|
||||||
GitHubServerTLS: &v1alpha1.TLSConfig{
|
GitHubServerTLS: &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
@@ -1170,7 +1191,7 @@ var _ = Describe("Test GitHub Server TLS configuration", func() {
|
|||||||
|
|
||||||
g.Expect(config.Data["config.json"]).ToNot(BeEmpty(), "listener configuration file should not be empty")
|
g.Expect(config.Data["config.json"]).ToNot(BeEmpty(), "listener configuration file should not be empty")
|
||||||
|
|
||||||
var listenerConfig ghalistenerconfig.Config
|
var listenerConfig listenerconfig.Config
|
||||||
err = json.Unmarshal(config.Data["config.json"], &listenerConfig)
|
err = json.Unmarshal(config.Data["config.json"], &listenerConfig)
|
||||||
g.Expect(err).NotTo(HaveOccurred(), "failed to parse listener configuration file")
|
g.Expect(err).NotTo(HaveOccurred(), "failed to parse listener configuration 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
|
||||||
@@ -151,7 +151,7 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl
|
|||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !v1alpha1.IsVersionAllowed(autoscalingRunnerSet.Labels[LabelKeyKubernetesVersion], build.Version) {
|
if autoscalingRunnerSet.Labels[LabelKeyKubernetesVersion] != build.Version {
|
||||||
if err := r.Delete(ctx, autoscalingRunnerSet); err != nil {
|
if err := r.Delete(ctx, autoscalingRunnerSet); err != nil {
|
||||||
log.Error(err, "Failed to delete autoscaling runner set on version mismatch",
|
log.Error(err, "Failed to delete autoscaling runner set on version mismatch",
|
||||||
"buildVersion", build.Version,
|
"buildVersion", build.Version,
|
||||||
@@ -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)
|
||||||
@@ -207,6 +207,14 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl
|
|||||||
return r.updateRunnerScaleSetName(ctx, autoscalingRunnerSet, log)
|
return r.updateRunnerScaleSetName(ctx, autoscalingRunnerSet, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
secret := new(corev1.Secret)
|
||||||
|
if err := r.Get(ctx, types.NamespacedName{Namespace: autoscalingRunnerSet.Namespace, Name: autoscalingRunnerSet.Spec.GitHubConfigSecret}, secret); err != nil {
|
||||||
|
log.Error(err, "Failed to find GitHub config secret.",
|
||||||
|
"namespace", autoscalingRunnerSet.Namespace,
|
||||||
|
"name", autoscalingRunnerSet.Spec.GitHubConfigSecret)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
existingRunnerSets, err := r.listEphemeralRunnerSets(ctx, autoscalingRunnerSet)
|
existingRunnerSets, err := r.listEphemeralRunnerSets(ctx, autoscalingRunnerSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "Failed to list existing ephemeral runner sets")
|
log.Error(err, "Failed to list existing ephemeral runner sets")
|
||||||
@@ -394,16 +402,16 @@ func (r *AutoscalingRunnerSetReconciler) removeFinalizersFromDependentResources(
|
|||||||
|
|
||||||
func (r *AutoscalingRunnerSetReconciler) createRunnerScaleSet(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, logger logr.Logger) (ctrl.Result, error) {
|
func (r *AutoscalingRunnerSetReconciler) createRunnerScaleSet(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, logger logr.Logger) (ctrl.Result, error) {
|
||||||
logger.Info("Creating a new runner scale set")
|
logger.Info("Creating a new runner scale set")
|
||||||
actionsClient, err := r.GetActionsService(ctx, autoscalingRunnerSet)
|
actionsClient, err := r.actionsClientFor(ctx, autoscalingRunnerSet)
|
||||||
if len(autoscalingRunnerSet.Spec.RunnerScaleSetName) == 0 {
|
if len(autoscalingRunnerSet.Spec.RunnerScaleSetName) == 0 {
|
||||||
autoscalingRunnerSet.Spec.RunnerScaleSetName = autoscalingRunnerSet.Name
|
autoscalingRunnerSet.Spec.RunnerScaleSetName = autoscalingRunnerSet.Name
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "Failed to initialize Actions service client for creating a new runner scale set", "error", err.Error())
|
logger.Error(err, "Failed to initialize Actions service client for creating a new runner scale set")
|
||||||
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 +419,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 +437,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 +474,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,19 +492,19 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
actionsClient, err := r.GetActionsService(ctx, autoscalingRunnerSet)
|
actionsClient, err := r.actionsClientFor(ctx, autoscalingRunnerSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "Failed to initialize Actions service client for updating a existing runner scale set")
|
logger.Error(err, "Failed to initialize Actions service client for updating a existing runner scale set")
|
||||||
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 +512,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 +535,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
|
||||||
@@ -538,15 +546,15 @@ func (r *AutoscalingRunnerSetReconciler) updateRunnerScaleSetName(ctx context.Co
|
|||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
actionsClient, err := r.GetActionsService(ctx, autoscalingRunnerSet)
|
actionsClient, err := r.actionsClientFor(ctx, autoscalingRunnerSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "Failed to initialize Actions service client for updating a existing runner scale set")
|
logger.Error(err, "Failed to initialize Actions service client for updating a existing runner scale set")
|
||||||
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 +571,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 +588,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.
|
||||||
@@ -589,23 +597,23 @@ func (r *AutoscalingRunnerSetReconciler) deleteRunnerScaleSet(ctx context.Contex
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
actionsClient, err := r.GetActionsService(ctx, autoscalingRunnerSet)
|
actionsClient, err := r.actionsClientFor(ctx, autoscalingRunnerSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "Failed to initialize Actions service client for updating a existing runner scale set")
|
logger.Error(err, "Failed to initialize Actions service client for updating a existing runner scale set")
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,6 +676,74 @@ func (r *AutoscalingRunnerSetReconciler) listEphemeralRunnerSets(ctx context.Con
|
|||||||
return &EphemeralRunnerSets{list: list}, nil
|
return &EphemeralRunnerSets{list: list}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *AutoscalingRunnerSetReconciler) actionsClientFor(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet) (actions.ActionsService, error) {
|
||||||
|
var configSecret corev1.Secret
|
||||||
|
if err := r.Get(ctx, types.NamespacedName{Namespace: autoscalingRunnerSet.Namespace, Name: autoscalingRunnerSet.Spec.GitHubConfigSecret}, &configSecret); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to find GitHub config secret: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := r.actionsClientOptionsFor(ctx, autoscalingRunnerSet)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get actions client options: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.ActionsClient.GetClientFromSecret(
|
||||||
|
ctx,
|
||||||
|
autoscalingRunnerSet.Spec.GitHubConfigUrl,
|
||||||
|
autoscalingRunnerSet.Namespace,
|
||||||
|
configSecret.Data,
|
||||||
|
opts...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *AutoscalingRunnerSetReconciler) actionsClientOptionsFor(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet) ([]actions.ClientOption, error) {
|
||||||
|
var options []actions.ClientOption
|
||||||
|
|
||||||
|
if autoscalingRunnerSet.Spec.Proxy != nil {
|
||||||
|
proxyFunc, err := autoscalingRunnerSet.Spec.Proxy.ProxyFunc(func(s string) (*corev1.Secret, error) {
|
||||||
|
var secret corev1.Secret
|
||||||
|
err := r.Get(ctx, types.NamespacedName{Namespace: autoscalingRunnerSet.Namespace, Name: s}, &secret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get proxy secret %s: %w", s, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &secret, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get proxy func: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
options = append(options, actions.WithProxy(proxyFunc))
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfig := autoscalingRunnerSet.Spec.GitHubServerTLS
|
||||||
|
if tlsConfig != nil {
|
||||||
|
pool, err := tlsConfig.ToCertPool(func(name, key string) ([]byte, error) {
|
||||||
|
var configmap corev1.ConfigMap
|
||||||
|
err := r.Get(
|
||||||
|
ctx,
|
||||||
|
types.NamespacedName{
|
||||||
|
Namespace: autoscalingRunnerSet.Namespace,
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
&configmap,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get configmap %s: %w", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(configmap.Data[key]), nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get tls config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
options = append(options, actions.WithRootCAs(pool))
|
||||||
|
}
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetupWithManager sets up the controller with the Manager.
|
// SetupWithManager sets up the controller with the Manager.
|
||||||
func (r *AutoscalingRunnerSetReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
func (r *AutoscalingRunnerSetReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
@@ -1006,7 +1082,6 @@ 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
|
||||||
|
|||||||
@@ -34,8 +34,9 @@ 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() {
|
||||||
@@ -69,12 +70,7 @@ var _ = Describe("Test AutoScalingRunnerSet controller", Ordered, func() {
|
|||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ControllerNamespace: autoscalingNS.Name,
|
ControllerNamespace: autoscalingNS.Name,
|
||||||
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: fake.NewMultiClient(),
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: k8sClient,
|
|
||||||
multiClient: fake.NewMultiClient(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -140,7 +136,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +144,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")
|
||||||
@@ -681,40 +677,33 @@ var _ = Describe("Test AutoScalingController updates", Ordered, func() {
|
|||||||
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
||||||
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
||||||
|
|
||||||
multiClient := fake.NewMultiClient(
|
|
||||||
fake.WithDefaultClient(
|
|
||||||
fake.NewFakeClient(
|
|
||||||
fake.WithUpdateRunnerScaleSet(
|
|
||||||
&actions.RunnerScaleSet{
|
|
||||||
Id: 1,
|
|
||||||
Name: "testset_update",
|
|
||||||
RunnerGroupId: 1,
|
|
||||||
RunnerGroupName: "testgroup",
|
|
||||||
Labels: []actions.Label{{Type: "test", Name: "test"}},
|
|
||||||
RunnerSetting: actions.RunnerSetting{},
|
|
||||||
CreatedOn: time.Now(),
|
|
||||||
RunnerJitConfigUrl: "test.test.test",
|
|
||||||
Statistics: nil,
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
nil,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
controller := &AutoscalingRunnerSetReconciler{
|
controller := &AutoscalingRunnerSetReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ControllerNamespace: autoscalingNS.Name,
|
ControllerNamespace: autoscalingNS.Name,
|
||||||
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: fake.NewMultiClient(
|
||||||
SecretResolver: &SecretResolver{
|
fake.WithDefaultClient(
|
||||||
k8sClient: k8sClient,
|
fake.NewFakeClient(
|
||||||
multiClient: multiClient,
|
fake.WithUpdateRunnerScaleSet(
|
||||||
},
|
&actions.RunnerScaleSet{
|
||||||
},
|
Id: 1,
|
||||||
|
Name: "testset_update",
|
||||||
|
RunnerGroupId: 1,
|
||||||
|
RunnerGroupName: "testgroup",
|
||||||
|
Labels: []actions.Label{{Type: "test", Name: "test"}},
|
||||||
|
RunnerSetting: actions.RunnerSetting{},
|
||||||
|
CreatedOn: time.Now(),
|
||||||
|
RunnerJitConfigUrl: "test.test.test",
|
||||||
|
Statistics: nil,
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -829,12 +818,7 @@ var _ = Describe("Test AutoscalingController creation failures", Ordered, func()
|
|||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ControllerNamespace: autoscalingNS.Name,
|
ControllerNamespace: autoscalingNS.Name,
|
||||||
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: fake.NewMultiClient(),
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: k8sClient,
|
|
||||||
multiClient: fake.NewMultiClient(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -953,19 +937,14 @@ var _ = Describe("Test client optional configuration", Ordered, func() {
|
|||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
||||||
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
||||||
multiClient := actions.NewMultiClient(logr.Discard())
|
|
||||||
controller = &AutoscalingRunnerSetReconciler{
|
controller = &AutoscalingRunnerSetReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ControllerNamespace: autoscalingNS.Name,
|
ControllerNamespace: autoscalingNS.Name,
|
||||||
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: actions.NewMultiClient(logr.Discard()),
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: k8sClient,
|
|
||||||
multiClient: multiClient,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
@@ -1148,12 +1127,7 @@ var _ = Describe("Test client optional configuration", Ordered, func() {
|
|||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ControllerNamespace: autoscalingNS.Name,
|
ControllerNamespace: autoscalingNS.Name,
|
||||||
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: fake.NewMultiClient(),
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: k8sClient,
|
|
||||||
multiClient: fake.NewMultiClient(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
err = controller.SetupWithManager(mgr)
|
err = controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -1162,10 +1136,7 @@ var _ = Describe("Test client optional configuration", Ordered, func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("should be able to make requests to a server using root CAs", func() {
|
It("should be able to make requests to a server using root CAs", func() {
|
||||||
controller.SecretResolver = &SecretResolver{
|
controller.ActionsClient = actions.NewMultiClient(logr.Discard())
|
||||||
k8sClient: k8sClient,
|
|
||||||
multiClient: actions.NewMultiClient(logr.Discard()),
|
|
||||||
}
|
|
||||||
|
|
||||||
certsFolder := filepath.Join(
|
certsFolder := filepath.Join(
|
||||||
"../../",
|
"../../",
|
||||||
@@ -1200,7 +1171,7 @@ var _ = Describe("Test client optional configuration", Ordered, func() {
|
|||||||
Spec: v1alpha1.AutoscalingRunnerSetSpec{
|
Spec: v1alpha1.AutoscalingRunnerSetSpec{
|
||||||
GitHubConfigUrl: server.ConfigURLForOrg("my-org"),
|
GitHubConfigUrl: server.ConfigURLForOrg("my-org"),
|
||||||
GitHubConfigSecret: configSecret.Name,
|
GitHubConfigSecret: configSecret.Name,
|
||||||
GitHubServerTLS: &v1alpha1.TLSConfig{
|
GitHubServerTLS: &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
@@ -1253,7 +1224,7 @@ var _ = Describe("Test client optional configuration", Ordered, func() {
|
|||||||
Spec: v1alpha1.AutoscalingRunnerSetSpec{
|
Spec: v1alpha1.AutoscalingRunnerSetSpec{
|
||||||
GitHubConfigUrl: "https://github.com/owner/repo",
|
GitHubConfigUrl: "https://github.com/owner/repo",
|
||||||
GitHubConfigSecret: configSecret.Name,
|
GitHubConfigSecret: configSecret.Name,
|
||||||
GitHubServerTLS: &v1alpha1.TLSConfig{
|
GitHubServerTLS: &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
@@ -1317,7 +1288,7 @@ var _ = Describe("Test client optional configuration", Ordered, func() {
|
|||||||
Spec: v1alpha1.AutoscalingRunnerSetSpec{
|
Spec: v1alpha1.AutoscalingRunnerSetSpec{
|
||||||
GitHubConfigUrl: "https://github.com/owner/repo",
|
GitHubConfigUrl: "https://github.com/owner/repo",
|
||||||
GitHubConfigSecret: configSecret.Name,
|
GitHubConfigSecret: configSecret.Name,
|
||||||
GitHubServerTLS: &v1alpha1.TLSConfig{
|
GitHubServerTLS: &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
@@ -1390,12 +1361,7 @@ var _ = Describe("Test external permissions cleanup", Ordered, func() {
|
|||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ControllerNamespace: autoscalingNS.Name,
|
ControllerNamespace: autoscalingNS.Name,
|
||||||
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: fake.NewMultiClient(),
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: k8sClient,
|
|
||||||
multiClient: fake.NewMultiClient(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -1553,12 +1519,7 @@ var _ = Describe("Test external permissions cleanup", Ordered, func() {
|
|||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ControllerNamespace: autoscalingNS.Name,
|
ControllerNamespace: autoscalingNS.Name,
|
||||||
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: fake.NewMultiClient(),
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: k8sClient,
|
|
||||||
multiClient: fake.NewMultiClient(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -1766,12 +1727,7 @@ var _ = Describe("Test resource version and build version mismatch", func() {
|
|||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ControllerNamespace: autoscalingNS.Name,
|
ControllerNamespace: autoscalingNS.Name,
|
||||||
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
DefaultRunnerScaleSetListenerImage: "ghcr.io/actions/arc",
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: fake.NewMultiClient(),
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: k8sClient,
|
|
||||||
multiClient: fake.NewMultiClient(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
|
|||||||
@@ -36,8 +36,7 @@ const (
|
|||||||
LabelKeyGitHubRepository = "actions.github.com/repository"
|
LabelKeyGitHubRepository = "actions.github.com/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AutoscalingRunnerSetCleanupFinalizerName is a finalizer used to protect resources
|
// Finalizer used to protect resources from deletion while AutoscalingRunnerSet is running
|
||||||
// from deletion while AutoscalingRunnerSet is running
|
|
||||||
const AutoscalingRunnerSetCleanupFinalizerName = "actions.github.com/cleanup-protection"
|
const AutoscalingRunnerSetCleanupFinalizerName = "actions.github.com/cleanup-protection"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ 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"
|
||||||
@@ -30,7 +28,6 @@ import (
|
|||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
@@ -47,24 +44,12 @@ const (
|
|||||||
// EphemeralRunnerReconciler reconciles a EphemeralRunner object
|
// EphemeralRunnerReconciler reconciles a EphemeralRunner object
|
||||||
type EphemeralRunnerReconciler struct {
|
type EphemeralRunnerReconciler struct {
|
||||||
client.Client
|
client.Client
|
||||||
Log logr.Logger
|
Log logr.Logger
|
||||||
Scheme *runtime.Scheme
|
Scheme *runtime.Scheme
|
||||||
|
ActionsClient actions.MultiClient
|
||||||
ResourceBuilder
|
ResourceBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
// precompute backoff durations for failed ephemeral runners
|
|
||||||
// the len(failedRunnerBackoff) must be equal to maxFailures + 1
|
|
||||||
var failedRunnerBackoff = []time.Duration{
|
|
||||||
0,
|
|
||||||
5 * time.Second,
|
|
||||||
10 * time.Second,
|
|
||||||
20 * time.Second,
|
|
||||||
40 * time.Second,
|
|
||||||
80 * time.Second,
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxFailures = 5
|
|
||||||
|
|
||||||
// +kubebuilder:rbac:groups=actions.github.com,resources=ephemeralrunners,verbs=get;list;watch;create;update;patch;delete
|
// +kubebuilder:rbac:groups=actions.github.com,resources=ephemeralrunners,verbs=get;list;watch;create;update;patch;delete
|
||||||
// +kubebuilder:rbac:groups=actions.github.com,resources=ephemeralrunners/status,verbs=get;update;patch
|
// +kubebuilder:rbac:groups=actions.github.com,resources=ephemeralrunners/status,verbs=get;update;patch
|
||||||
// +kubebuilder:rbac:groups=actions.github.com,resources=ephemeralrunners/finalizers,verbs=get;list;watch;create;update;patch;delete
|
// +kubebuilder:rbac:groups=actions.github.com,resources=ephemeralrunners/finalizers,verbs=get;list;watch;create;update;patch;delete
|
||||||
@@ -154,17 +139,38 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
|||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
addFinalizers := !controllerutil.ContainsFinalizer(ephemeralRunner, ephemeralRunnerFinalizerName) || !controllerutil.ContainsFinalizer(ephemeralRunner, ephemeralRunnerActionsFinalizerName)
|
if !controllerutil.ContainsFinalizer(ephemeralRunner, ephemeralRunnerFinalizerName) {
|
||||||
if addFinalizers {
|
log.Info("Adding finalizer")
|
||||||
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) {
|
||||||
|
log.Info("Adding runner registration finalizer")
|
||||||
|
err := patch(ctx, r.Client, ephemeralRunner, func(obj *v1alpha1.EphemeralRunner) {
|
||||||
|
controllerutil.AddFinalizer(obj, ephemeralRunnerActionsFinalizerName)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err, "Failed to update with runner registration finalizer set")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Successfully added runner registration finalizer")
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ephemeralRunner.Status.RunnerId == 0 {
|
||||||
|
log.Info("Creating new ephemeral runner registration and updating status with runner config")
|
||||||
|
if r, err := r.updateStatusWithRunnerConfig(ctx, ephemeralRunner, log); r != nil {
|
||||||
|
return *r, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
secret := new(corev1.Secret)
|
secret := new(corev1.Secret)
|
||||||
@@ -173,140 +179,56 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
|||||||
log.Error(err, "Failed to fetch secret")
|
log.Error(err, "Failed to fetch secret")
|
||||||
return ctrl.Result{}, err
|
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
|
||||||
|
}
|
||||||
|
|
||||||
jitConfig, err := r.createRunnerJitConfig(ctx, ephemeralRunner, log)
|
// Retry to get the secret that was just created.
|
||||||
switch {
|
// Otherwise, even though we want to continue to create the pod,
|
||||||
case err == nil:
|
// it fails due to the missing secret resulting in an invalid pod spec.
|
||||||
// create secret if not created
|
if err := r.Get(ctx, req.NamespacedName, secret); err != nil {
|
||||||
log.Info("Creating new ephemeral runner secret for jitconfig.")
|
log.Error(err, "Failed to fetch secret")
|
||||||
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
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ephemeralRunner.Status.RunnerId == 0 {
|
|
||||||
log.Info("Updating ephemeral runner status with runnerId and runnerName")
|
|
||||||
runnerID, err := strconv.Atoi(string(secret.Data["runnerId"]))
|
|
||||||
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 {
|
|
||||||
log.Info(fmt.Sprintf("EphemeralRunner has failed more than %d times. Deleting ephemeral runner so it can be re-created", maxFailures))
|
|
||||||
if err := r.Delete(ctx, ephemeralRunner); err != nil {
|
|
||||||
log.Error(fmt.Errorf("failed to delete ephemeral runner after %d failures: %w", maxFailures, err), "Failed to delete ephemeral runner")
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
now := metav1.Now()
|
|
||||||
lastFailure := ephemeralRunner.Status.LastFailure()
|
|
||||||
backoffDuration := failedRunnerBackoff[len(ephemeralRunner.Status.Failures)]
|
|
||||||
nextReconciliation := lastFailure.Add(backoffDuration)
|
|
||||||
if !lastFailure.IsZero() && now.Before(&metav1.Time{Time: nextReconciliation}) {
|
|
||||||
requeueAfter := nextReconciliation.Sub(now.Time)
|
|
||||||
log.Info("Backing off the next reconciliation due to failure",
|
|
||||||
"lastFailure", lastFailure,
|
|
||||||
"nextReconciliation", nextReconciliation,
|
|
||||||
"requeueAfter", requeueAfter,
|
|
||||||
)
|
|
||||||
return ctrl.Result{
|
|
||||||
Requeue: true,
|
|
||||||
RequeueAfter: requeueAfter,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
switch {
|
||||||
|
case !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")
|
|
||||||
|
|
||||||
result, err := r.createPod(ctx, ephemeralRunner, secret, log)
|
case len(ephemeralRunner.Status.Failures) > 5:
|
||||||
switch {
|
log.Info("EphemeralRunner has failed more than 5 times. Marking it as failed")
|
||||||
case err == nil:
|
errMessage := fmt.Sprintf("Pod has failed to start more than 5 times: %s", pod.Status.Message)
|
||||||
return result, nil
|
if err := r.markAsFailed(ctx, ephemeralRunner, errMessage, ReasonTooManyPodFailures, log); err != nil {
|
||||||
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")
|
|
||||||
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")
|
log.Error(err, "Failed to set ephemeral runner to phase Failed")
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Error(err, "Failed to create the pod")
|
// Pod was not found. Create if the pod has never been created
|
||||||
return ctrl.Result{}, err
|
log.Info("Creating new EphemeralRunner pod.")
|
||||||
|
result, err := r.createPod(ctx, ephemeralRunner, secret, log)
|
||||||
|
switch {
|
||||||
|
case err == nil:
|
||||||
|
return result, nil
|
||||||
|
case kerrors.IsInvalid(err) || kerrors.IsForbidden(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
|
||||||
|
default:
|
||||||
|
log.Error(err, "Failed to create the pod")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,41 +262,34 @@ 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
|
||||||
}
|
}
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
|
|
||||||
default: // succeeded
|
default:
|
||||||
log.Info("Ephemeral runner has finished successfully, deleting ephemeral runner", "exitCode", cs.State.Terminated.ExitCode)
|
// pod succeeded. We double-check with the service if the runner exists.
|
||||||
if err := r.Delete(ctx, ephemeralRunner); err != nil {
|
// The reason is that image can potentially finish with status 0, but not pick up the job.
|
||||||
log.Error(err, "Failed to delete ephemeral runner after successful completion")
|
existsInService, err := r.runnerRegisteredWithService(ctx, ephemeralRunner.DeepCopy(), log)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err, "Failed to check if runner is registered with the service")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
if !existsInService {
|
||||||
|
// the runner does not exist in the service, so it must be done
|
||||||
|
log.Info("Ephemeral runner has finished since it does not exist in the service anymore")
|
||||||
|
if err := r.markAsFinished(ctx, ephemeralRunner, log); err != nil {
|
||||||
|
log.Error(err, "Failed to mark ephemeral runner as finished")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// The runner still exists. This can happen if the pod exited with 0 but fails to start
|
||||||
|
log.Info("Ephemeral runner pod has finished, but the runner still exists in the service. Deleting the pod to restart it.")
|
||||||
|
if err := r.deletePodAsFailed(ctx, ephemeralRunner, pod, log); err != nil {
|
||||||
|
log.Error(err, "failed to delete a pod that still exists in the service")
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
@@ -544,6 +459,18 @@ 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 {
|
||||||
@@ -557,9 +484,9 @@ func (r *EphemeralRunnerReconciler) deletePodAsFailed(ctx context.Context, ephem
|
|||||||
log.Info("Updating ephemeral runner status to track the failure count")
|
log.Info("Updating ephemeral runner status to track the failure count")
|
||||||
if err := patchSubResource(ctx, r.Status(), ephemeralRunner, func(obj *v1alpha1.EphemeralRunner) {
|
if err := patchSubResource(ctx, r.Status(), ephemeralRunner, func(obj *v1alpha1.EphemeralRunner) {
|
||||||
if obj.Status.Failures == nil {
|
if obj.Status.Failures == nil {
|
||||||
obj.Status.Failures = make(map[string]metav1.Time)
|
obj.Status.Failures = make(map[string]bool)
|
||||||
}
|
}
|
||||||
obj.Status.Failures[string(pod.UID)] = metav1.Now()
|
obj.Status.Failures[string(pod.UID)] = true
|
||||||
obj.Status.Ready = false
|
obj.Status.Ready = false
|
||||||
obj.Status.Reason = pod.Status.Reason
|
obj.Status.Reason = pod.Status.Reason
|
||||||
obj.Status.Message = pod.Status.Message
|
obj.Status.Message = pod.Status.Message
|
||||||
@@ -571,12 +498,14 @@ func (r *EphemeralRunnerReconciler) deletePodAsFailed(ctx context.Context, ephem
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *EphemeralRunnerReconciler) createRunnerJitConfig(ctx context.Context, ephemeralRunner *v1alpha1.EphemeralRunner, log logr.Logger) (*actions.RunnerScaleSetJitRunnerConfig, error) {
|
// updateStatusWithRunnerConfig fetches runtime configuration needed by the runner
|
||||||
|
// 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.actionsClientFor(ctx, ephemeralRunner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get actions client for generating JIT config: %w", err)
|
return &ctrl.Result{}, fmt.Errorf("failed to get actions client for generating JIT config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
jitSettings := &actions.RunnerScaleSetJitRunnerSetting{
|
jitSettings := &actions.RunnerScaleSetJitRunnerSetting{
|
||||||
@@ -591,52 +520,74 @@ func (r *EphemeralRunnerReconciler) createRunnerJitConfig(ctx context.Context, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
return nil, fmt.Errorf("failed to get runner by name: %w", err)
|
actionsError := &actions.ActionsError{}
|
||||||
}
|
if !errors.As(err, &actionsError) {
|
||||||
|
return &ctrl.Result{}, fmt.Errorf("failed to generate JIT config with generic error: %w", err)
|
||||||
if existingRunner == nil {
|
|
||||||
log.Info("Runner with the same name does not exist anymore, re-queuing the reconciliation")
|
|
||||||
return nil, fmt.Errorf("%w: runner existed, retry configuration", retryableError)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 nil, fmt.Errorf("failed to remove runner from the service: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Removed the runner with the same name, re-queuing the reconciliation")
|
if actionsError.StatusCode != http.StatusConflict ||
|
||||||
return nil, fmt.Errorf("%w: runner existed belonging to the scale set, retry configuration", retryableError)
|
!actionsError.IsException("AgentExistsException") {
|
||||||
|
return &ctrl.Result{}, 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 {
|
||||||
|
return &ctrl.Result{}, fmt.Errorf("failed to get runner by name: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if existingRunner == nil {
|
||||||
|
log.Info("Runner with the same name does not exist, re-queuing the reconciliation")
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("%w: runner with the same name but doesn't belong to this RunnerScaleSet: %w", fatalError, err)
|
// We want to continue without a requeue for faster pod creation.
|
||||||
|
//
|
||||||
|
// 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) {
|
||||||
@@ -689,7 +640,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(runner, secret, envs...)
|
newPod := r.newEphemeralRunnerPod(ctx, 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")
|
||||||
@@ -712,21 +663,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, jitConfig *actions.RunnerScaleSetJitRunnerConfig, log logr.Logger) (*corev1.Secret, error) {
|
func (r *EphemeralRunnerReconciler) createSecret(ctx context.Context, runner *v1alpha1.EphemeralRunner, log logr.Logger) (*ctrl.Result, error) {
|
||||||
log.Info("Creating new secret for ephemeral runner")
|
log.Info("Creating new secret for ephemeral runner")
|
||||||
jitSecret := r.newEphemeralRunnerJitSecret(runner, jitConfig)
|
jitSecret := r.newEphemeralRunnerJitSecret(runner)
|
||||||
|
|
||||||
if err := ctrl.SetControllerReference(runner, jitSecret, r.Scheme); err != nil {
|
if err := ctrl.SetControllerReference(runner, jitSecret, r.Scheme); err != nil {
|
||||||
return nil, fmt.Errorf("failed to set controller reference: %w", err)
|
return &ctrl.Result{}, 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 nil, fmt.Errorf("failed to create jit secret: %w", err)
|
return &ctrl.Result{}, 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 jitSecret, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateRunStatusFromPod is responsible for updating non-exiting statuses.
|
// updateRunStatusFromPod is responsible for updating non-exiting statuses.
|
||||||
@@ -776,8 +727,104 @@ func (r *EphemeralRunnerReconciler) updateRunStatusFromPod(ctx context.Context,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *EphemeralRunnerReconciler) actionsClientFor(ctx context.Context, runner *v1alpha1.EphemeralRunner) (actions.ActionsService, error) {
|
||||||
|
secret := new(corev1.Secret)
|
||||||
|
if err := r.Get(ctx, types.NamespacedName{Namespace: runner.Namespace, Name: runner.Spec.GitHubConfigSecret}, secret); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get secret: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := r.actionsClientOptionsFor(ctx, runner)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get actions client options: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.ActionsClient.GetClientFromSecret(
|
||||||
|
ctx,
|
||||||
|
runner.Spec.GitHubConfigUrl,
|
||||||
|
runner.Namespace,
|
||||||
|
secret.Data,
|
||||||
|
opts...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *EphemeralRunnerReconciler) actionsClientOptionsFor(ctx context.Context, runner *v1alpha1.EphemeralRunner) ([]actions.ClientOption, error) {
|
||||||
|
var opts []actions.ClientOption
|
||||||
|
if runner.Spec.Proxy != nil {
|
||||||
|
proxyFunc, err := runner.Spec.Proxy.ProxyFunc(func(s string) (*corev1.Secret, error) {
|
||||||
|
var secret corev1.Secret
|
||||||
|
err := r.Get(ctx, types.NamespacedName{Namespace: runner.Namespace, Name: s}, &secret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get proxy secret %s: %w", s, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &secret, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get proxy func: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = append(opts, actions.WithProxy(proxyFunc))
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfig := runner.Spec.GitHubServerTLS
|
||||||
|
if tlsConfig != nil {
|
||||||
|
pool, err := tlsConfig.ToCertPool(func(name, key string) ([]byte, error) {
|
||||||
|
var configmap corev1.ConfigMap
|
||||||
|
err := r.Get(
|
||||||
|
ctx,
|
||||||
|
types.NamespacedName{
|
||||||
|
Namespace: runner.Namespace,
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
&configmap,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get configmap %s: %w", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(configmap.Data[key]), nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get tls config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = append(opts, actions.WithRootCAs(pool))
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// runnerRegisteredWithService checks if the runner is still registered with the service
|
||||||
|
// Returns found=false and err=nil if ephemeral runner does not exist in GitHub service and should be deleted
|
||||||
|
func (r EphemeralRunnerReconciler) runnerRegisteredWithService(ctx context.Context, runner *v1alpha1.EphemeralRunner, log logr.Logger) (found bool, err error) {
|
||||||
|
actionsClient, err := r.actionsClientFor(ctx, runner)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("failed to get Actions client for ScaleSet: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Checking if runner exists in GitHub service", "runnerId", runner.Status.RunnerId)
|
||||||
|
_, err = actionsClient.GetRunner(ctx, int64(runner.Status.RunnerId))
|
||||||
|
if err != nil {
|
||||||
|
actionsError := &actions.ActionsError{}
|
||||||
|
if !errors.As(err, &actionsError) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if actionsError.StatusCode != http.StatusNotFound ||
|
||||||
|
!actionsError.IsException("AgentNotFoundException") {
|
||||||
|
return false, fmt.Errorf("failed to check if runner exists in GitHub service: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Runner does not exist in GitHub service", "runnerId", runner.Status.RunnerId)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Runner exists in GitHub service", "runnerId", runner.Status.RunnerId)
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *EphemeralRunnerReconciler) deleteRunnerFromService(ctx context.Context, ephemeralRunner *v1alpha1.EphemeralRunner, log logr.Logger) error {
|
func (r *EphemeralRunnerReconciler) deleteRunnerFromService(ctx context.Context, ephemeralRunner *v1alpha1.EphemeralRunner, log logr.Logger) error {
|
||||||
client, err := r.GetActionsService(ctx, ephemeralRunner)
|
client, err := r.actionsClientFor(ctx, ephemeralRunner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get actions client for runner: %w", err)
|
return fmt.Errorf("failed to get actions client for runner: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
ephemeralRunnerTimeout = time.Second * 20
|
ephemeralRunnerTimeout = time.Second * 20
|
||||||
ephemeralRunnerInterval = time.Millisecond * 10
|
ephemeralRunnerInterval = time.Millisecond * 250
|
||||||
runnerImage = "ghcr.io/actions/actions-runner:latest"
|
runnerImage = "ghcr.io/actions/actions-runner:latest"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -107,15 +107,10 @@ var _ = Describe("EphemeralRunner", func() {
|
|||||||
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
||||||
|
|
||||||
controller = &EphemeralRunnerReconciler{
|
controller = &EphemeralRunnerReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: fake.NewMultiClient(),
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: mgr.GetClient(),
|
|
||||||
multiClient: fake.NewMultiClient(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
@@ -176,7 +171,7 @@ var _ = Describe("EphemeralRunner", func() {
|
|||||||
).Should(BeEquivalentTo(ephemeralRunner.Name))
|
).Should(BeEquivalentTo(ephemeralRunner.Name))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("It should re-create pod on failure and no job assigned", func() {
|
It("It should re-create pod on failure", 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,67 +195,6 @@ 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"
|
||||||
@@ -269,22 +203,13 @@ var _ = Describe("EphemeralRunner", func() {
|
|||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
updated := new(v1alpha1.EphemeralRunner)
|
updated := new(v1alpha1.EphemeralRunner)
|
||||||
Eventually(
|
Eventually(func() (corev1.PodPhase, error) {
|
||||||
func() (corev1.PodPhase, error) {
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: invalideEphemeralRunner.Name, Namespace: invalideEphemeralRunner.Namespace}, updated)
|
||||||
err := k8sClient.Get(
|
if err != nil {
|
||||||
ctx,
|
return "", nil
|
||||||
client.ObjectKey{Name: invalideEphemeralRunner.Name, Namespace: invalideEphemeralRunner.Namespace},
|
}
|
||||||
updated,
|
return updated.Status.Phase, nil
|
||||||
)
|
}, 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"))
|
||||||
})
|
})
|
||||||
@@ -603,26 +528,44 @@ var _ = Describe("EphemeralRunner", func() {
|
|||||||
).Should(BeEquivalentTo(""))
|
).Should(BeEquivalentTo(""))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("It should eventually delete ephemeral runner after consecutive failures", func() {
|
It("It should not re-create pod indefinitely", func() {
|
||||||
updated := new(v1alpha1.EphemeralRunner)
|
updated := new(v1alpha1.EphemeralRunner)
|
||||||
|
pod := new(corev1.Pod)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() error {
|
func() (bool, error) {
|
||||||
return k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, updated)
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, updated)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, pod)
|
||||||
|
if err != nil {
|
||||||
|
if kerrors.IsNotFound(err) && len(updated.Status.Failures) > 5 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
return false, fmt.Errorf("pod haven't failed for 5 times.")
|
||||||
},
|
},
|
||||||
ephemeralRunnerTimeout,
|
ephemeralRunnerTimeout,
|
||||||
ephemeralRunnerInterval,
|
ephemeralRunnerInterval,
|
||||||
).Should(Succeed(), "failed to get ephemeral runner")
|
).Should(BeEquivalentTo(true), "we should stop creating pod after 5 failures")
|
||||||
|
|
||||||
failEphemeralRunnerPod := func() *corev1.Pod {
|
|
||||||
pod := new(corev1.Pod)
|
|
||||||
Eventually(
|
|
||||||
func() error {
|
|
||||||
return k8sClient.Get(ctx, client.ObjectKey{Name: updated.Name, Namespace: updated.Namespace}, pod)
|
|
||||||
},
|
|
||||||
ephemeralRunnerTimeout,
|
|
||||||
ephemeralRunnerInterval,
|
|
||||||
).Should(Succeed(), "failed to get ephemeral runner pod")
|
|
||||||
|
|
||||||
|
// In case we still have pod created due to controller-runtime cache delay, mark the container as exited
|
||||||
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, pod)
|
||||||
|
if err == nil {
|
||||||
pod.Status.ContainerStatuses = append(pod.Status.ContainerStatuses, corev1.ContainerStatus{
|
pod.Status.ContainerStatuses = append(pod.Status.ContainerStatuses, corev1.ContainerStatus{
|
||||||
Name: v1alpha1.EphemeralRunnerContainerName,
|
Name: v1alpha1.EphemeralRunnerContainerName,
|
||||||
State: corev1.ContainerState{
|
State: corev1.ContainerState{
|
||||||
@@ -633,70 +576,25 @@ var _ = Describe("EphemeralRunner", func() {
|
|||||||
})
|
})
|
||||||
err := k8sClient.Status().Update(ctx, pod)
|
err := k8sClient.Status().Update(ctx, pod)
|
||||||
Expect(err).To(BeNil(), "Failed to update pod status")
|
Expect(err).To(BeNil(), "Failed to update pod status")
|
||||||
|
|
||||||
return pod
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range 5 {
|
// EphemeralRunner should failed with reason TooManyPodFailures
|
||||||
pod := failEphemeralRunnerPod()
|
Eventually(func() (string, error) {
|
||||||
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, updated)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return updated.Status.Reason, nil
|
||||||
|
}, ephemeralRunnerTimeout, ephemeralRunnerInterval).Should(BeEquivalentTo("TooManyPodFailures"), "Reason should be TooManyPodFailures")
|
||||||
|
|
||||||
Eventually(
|
// EphemeralRunner should not have any pod
|
||||||
func() (int, error) {
|
Eventually(func() (bool, error) {
|
||||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, updated)
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, pod)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return 0, err
|
return false, nil
|
||||||
}
|
}
|
||||||
return len(updated.Status.Failures), nil
|
return kerrors.IsNotFound(err), nil
|
||||||
},
|
}, ephemeralRunnerTimeout, ephemeralRunnerInterval).Should(BeEquivalentTo(true))
|
||||||
ephemeralRunnerTimeout,
|
|
||||||
ephemeralRunnerInterval,
|
|
||||||
).Should(BeEquivalentTo(i + 1))
|
|
||||||
|
|
||||||
Eventually(
|
|
||||||
func() error {
|
|
||||||
nextPod := new(corev1.Pod)
|
|
||||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: pod.Name, Namespace: pod.Namespace}, nextPod)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if nextPod.UID != pod.UID {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("pod not recreated")
|
|
||||||
},
|
|
||||||
).WithTimeout(20*time.Second).WithPolling(10*time.Millisecond).Should(Succeed(), "pod should be recreated")
|
|
||||||
|
|
||||||
Eventually(
|
|
||||||
func() (bool, error) {
|
|
||||||
pod := new(corev1.Pod)
|
|
||||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, pod)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
for _, cs := range pod.Status.ContainerStatuses {
|
|
||||||
if cs.Name == v1alpha1.EphemeralRunnerContainerName {
|
|
||||||
return cs.State.Terminated == nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
},
|
|
||||||
).WithTimeout(20*time.Second).WithPolling(10*time.Millisecond).Should(BeEquivalentTo(true), "pod should be terminated")
|
|
||||||
}
|
|
||||||
|
|
||||||
failEphemeralRunnerPod()
|
|
||||||
|
|
||||||
Eventually(
|
|
||||||
func() (bool, error) {
|
|
||||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, updated)
|
|
||||||
if kerrors.IsNotFound(err) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, err
|
|
||||||
},
|
|
||||||
ephemeralRunnerTimeout,
|
|
||||||
ephemeralRunnerInterval,
|
|
||||||
).Should(BeTrue(), "Ephemeral runner should eventually be deleted")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("It should re-create pod on eviction", func() {
|
It("It should re-create pod on eviction", func() {
|
||||||
@@ -745,6 +643,53 @@ var _ = Describe("EphemeralRunner", func() {
|
|||||||
).Should(BeEquivalentTo(true))
|
).Should(BeEquivalentTo(true))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("It should re-create pod on exit status 0, but runner exists within the service", func() {
|
||||||
|
pod := new(corev1.Pod)
|
||||||
|
Eventually(
|
||||||
|
func() (bool, error) {
|
||||||
|
if err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, pod); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
},
|
||||||
|
ephemeralRunnerTimeout,
|
||||||
|
ephemeralRunnerInterval,
|
||||||
|
).Should(BeEquivalentTo(true))
|
||||||
|
|
||||||
|
pod.Status.ContainerStatuses = append(pod.Status.ContainerStatuses, corev1.ContainerStatus{
|
||||||
|
Name: v1alpha1.EphemeralRunnerContainerName,
|
||||||
|
State: corev1.ContainerState{
|
||||||
|
Terminated: &corev1.ContainerStateTerminated{
|
||||||
|
ExitCode: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
err := k8sClient.Status().Update(ctx, pod)
|
||||||
|
Expect(err).To(BeNil(), "failed to update pod status")
|
||||||
|
|
||||||
|
updated := new(v1alpha1.EphemeralRunner)
|
||||||
|
Eventually(func() (bool, error) {
|
||||||
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, updated)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return len(updated.Status.Failures) == 1, nil
|
||||||
|
}, ephemeralRunnerTimeout, ephemeralRunnerInterval).Should(BeEquivalentTo(true))
|
||||||
|
|
||||||
|
// should re-create after failure
|
||||||
|
Eventually(
|
||||||
|
func() (bool, error) {
|
||||||
|
pod := new(corev1.Pod)
|
||||||
|
if err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, pod); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
},
|
||||||
|
ephemeralRunnerTimeout,
|
||||||
|
ephemeralRunnerInterval,
|
||||||
|
).Should(BeEquivalentTo(true))
|
||||||
|
})
|
||||||
|
|
||||||
It("It should not set the phase to succeeded without pod termination status", func() {
|
It("It should not set the phase to succeeded without pod termination status", func() {
|
||||||
pod := new(corev1.Pod)
|
pod := new(corev1.Pod)
|
||||||
Eventually(
|
Eventually(
|
||||||
@@ -817,27 +762,22 @@ var _ = Describe("EphemeralRunner", func() {
|
|||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: fake.NewMultiClient(
|
||||||
SecretResolver: &SecretResolver{
|
fake.WithDefaultClient(
|
||||||
k8sClient: mgr.GetClient(),
|
fake.NewFakeClient(
|
||||||
multiClient: fake.NewMultiClient(
|
fake.WithGetRunner(
|
||||||
fake.WithDefaultClient(
|
|
||||||
fake.NewFakeClient(
|
|
||||||
fake.WithGetRunner(
|
|
||||||
nil,
|
|
||||||
&actions.ActionsError{
|
|
||||||
StatusCode: http.StatusNotFound,
|
|
||||||
Err: &actions.ActionsExceptionError{
|
|
||||||
ExceptionName: "AgentNotFoundException",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
nil,
|
nil,
|
||||||
|
&actions.ActionsError{
|
||||||
|
StatusCode: http.StatusNotFound,
|
||||||
|
Err: &actions.ActionsExceptionError{
|
||||||
|
ExceptionName: "AgentNotFoundException",
|
||||||
|
},
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
nil,
|
||||||
},
|
),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).To(BeNil(), "failed to setup controller")
|
Expect(err).To(BeNil(), "failed to setup controller")
|
||||||
@@ -845,7 +785,7 @@ var _ = Describe("EphemeralRunner", func() {
|
|||||||
startManagers(GinkgoT(), mgr)
|
startManagers(GinkgoT(), mgr)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("It should delete EphemeralRunner when pod exits successfully", func() {
|
It("It should set the Phase to Succeeded", 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)
|
||||||
@@ -871,18 +811,13 @@ 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(
|
Eventually(func() (corev1.PodPhase, error) {
|
||||||
func() bool {
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, updated)
|
||||||
err := k8sClient.Get(
|
if err != nil {
|
||||||
ctx,
|
return "", nil
|
||||||
client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace},
|
}
|
||||||
updated,
|
return updated.Status.Phase, nil
|
||||||
)
|
}, ephemeralRunnerTimeout, ephemeralRunnerInterval).Should(BeEquivalentTo(corev1.PodSucceeded))
|
||||||
return kerrors.IsNotFound(err)
|
|
||||||
},
|
|
||||||
ephemeralRunnerTimeout,
|
|
||||||
ephemeralRunnerInterval,
|
|
||||||
).Should(BeTrue())
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -899,15 +834,10 @@ var _ = Describe("EphemeralRunner", func() {
|
|||||||
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoScalingNS.Name)
|
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoScalingNS.Name)
|
||||||
|
|
||||||
controller = &EphemeralRunnerReconciler{
|
controller = &EphemeralRunnerReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: fake.NewMultiClient(),
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: mgr.GetClient(),
|
|
||||||
multiClient: fake.NewMultiClient(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).To(BeNil(), "failed to setup controller")
|
Expect(err).To(BeNil(), "failed to setup controller")
|
||||||
@@ -917,12 +847,7 @@ var _ = Describe("EphemeralRunner", func() {
|
|||||||
|
|
||||||
It("uses an actions client with proxy transport", func() {
|
It("uses an actions client with proxy transport", func() {
|
||||||
// Use an actual client
|
// Use an actual client
|
||||||
controller.ResourceBuilder = ResourceBuilder{
|
controller.ActionsClient = actions.NewMultiClient(logr.Discard())
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: mgr.GetClient(),
|
|
||||||
multiClient: actions.NewMultiClient(logr.Discard()),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
proxySuccessfulllyCalled := false
|
proxySuccessfulllyCalled := false
|
||||||
proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -1073,15 +998,10 @@ var _ = Describe("EphemeralRunner", func() {
|
|||||||
Expect(err).NotTo(HaveOccurred(), "failed to create configmap with root CAs")
|
Expect(err).NotTo(HaveOccurred(), "failed to create configmap with root CAs")
|
||||||
|
|
||||||
controller = &EphemeralRunnerReconciler{
|
controller = &EphemeralRunnerReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: fake.NewMultiClient(),
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: mgr.GetClient(),
|
|
||||||
multiClient: fake.NewMultiClient(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = controller.SetupWithManager(mgr)
|
err = controller.SetupWithManager(mgr)
|
||||||
@@ -1112,16 +1032,11 @@ var _ = Describe("EphemeralRunner", func() {
|
|||||||
server.StartTLS()
|
server.StartTLS()
|
||||||
|
|
||||||
// Use an actual client
|
// Use an actual client
|
||||||
controller.ResourceBuilder = ResourceBuilder{
|
controller.ActionsClient = actions.NewMultiClient(logr.Discard())
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: mgr.GetClient(),
|
|
||||||
multiClient: actions.NewMultiClient(logr.Discard()),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
ephemeralRunner := newExampleRunner("test-runner", autoScalingNS.Name, configSecret.Name)
|
ephemeralRunner := newExampleRunner("test-runner", autoScalingNS.Name, configSecret.Name)
|
||||||
ephemeralRunner.Spec.GitHubConfigUrl = server.ConfigURLForOrg("my-org")
|
ephemeralRunner.Spec.GitHubConfigUrl = server.ConfigURLForOrg("my-org")
|
||||||
ephemeralRunner.Spec.GitHubServerTLS = &v1alpha1.TLSConfig{
|
ephemeralRunner.Spec.GitHubServerTLS = &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ func (r *EphemeralRunnerSetReconciler) cleanUpEphemeralRunners(ctx context.Conte
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
actionsClient, err := r.GetActionsService(ctx, ephemeralRunnerSet)
|
actionsClient, err := r.actionsClientFor(ctx, ephemeralRunnerSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -439,7 +439,7 @@ func (r *EphemeralRunnerSetReconciler) deleteIdleEphemeralRunners(ctx context.Co
|
|||||||
log.Info("No pending or running ephemeral runners running at this time for scale down")
|
log.Info("No pending or running ephemeral runners running at this time for scale down")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
actionsClient, err := r.GetActionsService(ctx, ephemeralRunnerSet)
|
actionsClient, err := r.actionsClientFor(ctx, ephemeralRunnerSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create actions client for ephemeral runner replica set: %w", err)
|
return fmt.Errorf("failed to create actions client for ephemeral runner replica set: %w", err)
|
||||||
}
|
}
|
||||||
@@ -453,13 +453,8 @@ func (r *EphemeralRunnerSetReconciler) deleteIdleEphemeralRunners(ctx context.Co
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isDone && ephemeralRunner.HasJob() {
|
if !isDone && ephemeralRunner.Status.JobRequestId > 0 {
|
||||||
log.Info(
|
log.Info("Skipping ephemeral runner since it is running a job", "name", ephemeralRunner.Name, "jobRequestId", ephemeralRunner.Status.JobRequestId)
|
||||||
"Skipping ephemeral runner since it is running a job",
|
|
||||||
"name", ephemeralRunner.Name,
|
|
||||||
"workflowRunId", ephemeralRunner.Status.WorkflowRunId,
|
|
||||||
"jobId", ephemeralRunner.Status.JobID,
|
|
||||||
)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,6 +502,73 @@ func (r *EphemeralRunnerSetReconciler) deleteEphemeralRunnerWithActionsClient(ct
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *EphemeralRunnerSetReconciler) actionsClientFor(ctx context.Context, rs *v1alpha1.EphemeralRunnerSet) (actions.ActionsService, error) {
|
||||||
|
secret := new(corev1.Secret)
|
||||||
|
if err := r.Get(ctx, types.NamespacedName{Namespace: rs.Namespace, Name: rs.Spec.EphemeralRunnerSpec.GitHubConfigSecret}, secret); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get secret: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := r.actionsClientOptionsFor(ctx, rs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get actions client options: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.ActionsClient.GetClientFromSecret(
|
||||||
|
ctx,
|
||||||
|
rs.Spec.EphemeralRunnerSpec.GitHubConfigUrl,
|
||||||
|
rs.Namespace,
|
||||||
|
secret.Data,
|
||||||
|
opts...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *EphemeralRunnerSetReconciler) actionsClientOptionsFor(ctx context.Context, rs *v1alpha1.EphemeralRunnerSet) ([]actions.ClientOption, error) {
|
||||||
|
var opts []actions.ClientOption
|
||||||
|
if rs.Spec.EphemeralRunnerSpec.Proxy != nil {
|
||||||
|
proxyFunc, err := rs.Spec.EphemeralRunnerSpec.Proxy.ProxyFunc(func(s string) (*corev1.Secret, error) {
|
||||||
|
var secret corev1.Secret
|
||||||
|
err := r.Get(ctx, types.NamespacedName{Namespace: rs.Namespace, Name: s}, &secret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get secret %s: %w", s, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &secret, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get proxy func: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = append(opts, actions.WithProxy(proxyFunc))
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfig := rs.Spec.EphemeralRunnerSpec.GitHubServerTLS
|
||||||
|
if tlsConfig != nil {
|
||||||
|
pool, err := tlsConfig.ToCertPool(func(name, key string) ([]byte, error) {
|
||||||
|
var configmap corev1.ConfigMap
|
||||||
|
err := r.Get(
|
||||||
|
ctx,
|
||||||
|
types.NamespacedName{
|
||||||
|
Namespace: rs.Namespace,
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
&configmap,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get configmap %s: %w", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(configmap.Data[key]), nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get tls config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = append(opts, actions.WithRootCAs(pool))
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetupWithManager sets up the controller with the Manager.
|
// SetupWithManager sets up the controller with the Manager.
|
||||||
func (r *EphemeralRunnerSetReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
func (r *EphemeralRunnerSetReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
@@ -22,7 +21,6 @@ import (
|
|||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
||||||
@@ -32,14 +30,11 @@ 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) {
|
|
||||||
require.Equal(t, len(failedRunnerBackoff), maxFailures+1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
||||||
var ctx context.Context
|
var ctx context.Context
|
||||||
var mgr ctrl.Manager
|
var mgr ctrl.Manager
|
||||||
@@ -53,15 +48,10 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
||||||
|
|
||||||
controller := &EphemeralRunnerSetReconciler{
|
controller := &EphemeralRunnerSetReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: fake.NewMultiClient(),
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: mgr.GetClient(),
|
|
||||||
multiClient: fake.NewMultiClient(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -118,7 +108,8 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
Consistently(
|
Consistently(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
runnerList := new(v1alpha1.EphemeralRunnerList)
|
runnerList := new(v1alpha1.EphemeralRunnerList)
|
||||||
if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +142,8 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
runnerList := new(v1alpha1.EphemeralRunnerList)
|
runnerList := new(v1alpha1.EphemeralRunnerList)
|
||||||
if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +161,8 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if refetch {
|
if refetch {
|
||||||
if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,7 +204,8 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
runnerList := new(v1alpha1.EphemeralRunnerList)
|
runnerList := new(v1alpha1.EphemeralRunnerList)
|
||||||
if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +223,8 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if refetch {
|
if refetch {
|
||||||
if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,7 +242,8 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
runnerList := new(v1alpha1.EphemeralRunnerList)
|
runnerList := new(v1alpha1.EphemeralRunnerList)
|
||||||
if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,7 +288,8 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList := new(v1alpha1.EphemeralRunnerList)
|
runnerList := new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +315,8 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList := new(v1alpha1.EphemeralRunnerList)
|
runnerList := new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,7 +340,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList = new(v1alpha1.EphemeralRunnerList)
|
runnerList = new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -369,7 +367,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList := new(v1alpha1.EphemeralRunnerList)
|
runnerList := new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -394,7 +392,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList = new(v1alpha1.EphemeralRunnerList)
|
runnerList = new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -420,7 +418,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList = new(v1alpha1.EphemeralRunnerList)
|
runnerList = new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -447,7 +445,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList := new(v1alpha1.EphemeralRunnerList)
|
runnerList := new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -472,7 +470,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList = new(v1alpha1.EphemeralRunnerList)
|
runnerList = new(v1alpha1.EphemeralRunnerList)
|
||||||
Consistently(
|
Consistently(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -499,7 +497,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList := new(v1alpha1.EphemeralRunnerList)
|
runnerList := new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -536,7 +534,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 := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -573,7 +571,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList := new(v1alpha1.EphemeralRunnerList)
|
runnerList := new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -598,7 +596,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList = new(v1alpha1.EphemeralRunnerList)
|
runnerList = new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() error {
|
func() error {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -639,7 +637,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 := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -666,7 +664,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
|
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -693,7 +691,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList := new(v1alpha1.EphemeralRunnerList)
|
runnerList := new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -719,7 +717,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList = new(v1alpha1.EphemeralRunnerList)
|
runnerList = new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() error {
|
func() error {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -763,7 +761,8 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList = new(v1alpha1.EphemeralRunnerList)
|
runnerList = new(v1alpha1.EphemeralRunnerList)
|
||||||
Consistently(
|
Consistently(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
if err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace); err != nil {
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -789,7 +788,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList = new(v1alpha1.EphemeralRunnerList)
|
runnerList = new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -816,7 +815,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList := new(v1alpha1.EphemeralRunnerList)
|
runnerList := new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -843,7 +842,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList = new(v1alpha1.EphemeralRunnerList)
|
runnerList = new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() error {
|
func() error {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -887,7 +886,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList = new(v1alpha1.EphemeralRunnerList)
|
runnerList = new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() error {
|
func() error {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -928,7 +927,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
runnerList := new(v1alpha1.EphemeralRunnerList)
|
runnerList := new(v1alpha1.EphemeralRunnerList)
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (bool, error) {
|
func() (bool, error) {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -1036,7 +1035,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
|||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (int, error) {
|
||||||
runnerList = new(v1alpha1.EphemeralRunnerList)
|
runnerList = new(v1alpha1.EphemeralRunnerList)
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -1099,15 +1098,10 @@ var _ = Describe("Test EphemeralRunnerSet controller with proxy settings", func(
|
|||||||
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
||||||
|
|
||||||
controller := &EphemeralRunnerSetReconciler{
|
controller := &EphemeralRunnerSetReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: actions.NewMultiClient(logr.Discard()),
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: mgr.GetClient(),
|
|
||||||
multiClient: actions.NewMultiClient(logr.Discard()),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
err := controller.SetupWithManager(mgr)
|
err := controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -1198,7 +1192,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 := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(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 {
|
||||||
@@ -1216,7 +1210,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 := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -1235,7 +1229,7 @@ var _ = Describe("Test EphemeralRunnerSet controller with proxy settings", func(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if refetch {
|
if refetch {
|
||||||
err := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -1250,18 +1244,6 @@ 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{}
|
||||||
@@ -1345,7 +1327,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 := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -1415,15 +1397,10 @@ var _ = Describe("Test EphemeralRunnerSet controller with custom root CA", func(
|
|||||||
Expect(err).NotTo(HaveOccurred(), "failed to create configmap with root CAs")
|
Expect(err).NotTo(HaveOccurred(), "failed to create configmap with root CAs")
|
||||||
|
|
||||||
controller := &EphemeralRunnerSetReconciler{
|
controller := &EphemeralRunnerSetReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
Log: logf.Log,
|
Log: logf.Log,
|
||||||
ResourceBuilder: ResourceBuilder{
|
ActionsClient: actions.NewMultiClient(logr.Discard()),
|
||||||
SecretResolver: &SecretResolver{
|
|
||||||
k8sClient: mgr.GetClient(),
|
|
||||||
multiClient: actions.NewMultiClient(logr.Discard()),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
err = controller.SetupWithManager(mgr)
|
err = controller.SetupWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
|
||||||
@@ -1462,7 +1439,7 @@ var _ = Describe("Test EphemeralRunnerSet controller with custom root CA", func(
|
|||||||
EphemeralRunnerSpec: v1alpha1.EphemeralRunnerSpec{
|
EphemeralRunnerSpec: v1alpha1.EphemeralRunnerSpec{
|
||||||
GitHubConfigUrl: server.ConfigURLForOrg("my-org"),
|
GitHubConfigUrl: server.ConfigURLForOrg("my-org"),
|
||||||
GitHubConfigSecret: configSecret.Name,
|
GitHubConfigSecret: configSecret.Name,
|
||||||
GitHubServerTLS: &v1alpha1.TLSConfig{
|
GitHubServerTLS: &v1alpha1.GitHubServerTLSConfig{
|
||||||
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
CertificateFrom: &v1alpha1.TLSCertificateSource{
|
||||||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
@@ -1492,7 +1469,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 := listEphemeralRunnersAndRemoveFinalizers(ctx, k8sClient, runnerList, ephemeralRunnerSet.Namespace)
|
err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -1531,27 +1508,3 @@ 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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
package actionsgithubcom
|
|
||||||
|
|
||||||
type controllerError string
|
|
||||||
|
|
||||||
func (e controllerError) Error() string {
|
|
||||||
return string(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
retryableError = controllerError("retryable error")
|
|
||||||
fatalError = controllerError("fatal error")
|
|
||||||
)
|
|
||||||
@@ -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 := client.Create(context.Background(), ns)
|
err := k8sClient.Create(context.Background(), ns)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
err := client.Delete(context.Background(), ns)
|
err := k8sClient.Delete(context.Background(), ns)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -2,22 +2,20 @@ package actionsgithubcom
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
||||||
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1/appconfig"
|
|
||||||
"github.com/actions/actions-runner-controller/build"
|
"github.com/actions/actions-runner-controller/build"
|
||||||
ghalistenerconfig "github.com/actions/actions-runner-controller/cmd/ghalistener/config"
|
listenerconfig "github.com/actions/actions-runner-controller/cmd/ghalistener/config"
|
||||||
"github.com/actions/actions-runner-controller/github/actions"
|
"github.com/actions/actions-runner-controller/github/actions"
|
||||||
"github.com/actions/actions-runner-controller/hash"
|
"github.com/actions/actions-runner-controller/hash"
|
||||||
"github.com/actions/actions-runner-controller/logging"
|
"github.com/actions/actions-runner-controller/logging"
|
||||||
"github.com/actions/actions-runner-controller/vault/azurekeyvault"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
rbacv1 "k8s.io/api/rbac/v1"
|
rbacv1 "k8s.io/api/rbac/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@@ -73,7 +71,6 @@ func SetListenerEntrypoint(entrypoint string) {
|
|||||||
|
|
||||||
type ResourceBuilder struct {
|
type ResourceBuilder struct {
|
||||||
ExcludeLabelPropagationPrefixes []string
|
ExcludeLabelPropagationPrefixes []string
|
||||||
*SecretResolver
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// boolPtr returns a pointer to a bool value
|
// boolPtr returns a pointer to a bool value
|
||||||
@@ -82,7 +79,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
|
||||||
}
|
}
|
||||||
@@ -123,8 +120,7 @@ func (b *ResourceBuilder) newAutoScalingListener(autoscalingRunnerSet *v1alpha1.
|
|||||||
Spec: v1alpha1.AutoscalingListenerSpec{
|
Spec: v1alpha1.AutoscalingListenerSpec{
|
||||||
GitHubConfigUrl: autoscalingRunnerSet.Spec.GitHubConfigUrl,
|
GitHubConfigUrl: autoscalingRunnerSet.Spec.GitHubConfigUrl,
|
||||||
GitHubConfigSecret: autoscalingRunnerSet.Spec.GitHubConfigSecret,
|
GitHubConfigSecret: autoscalingRunnerSet.Spec.GitHubConfigSecret,
|
||||||
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,
|
||||||
@@ -163,7 +159,7 @@ func (lm *listenerMetricsServerConfig) containerPort() (corev1.ContainerPort, er
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ResourceBuilder) newScaleSetListenerConfig(autoscalingListener *v1alpha1.AutoscalingListener, appConfig *appconfig.AppConfig, metricsConfig *listenerMetricsServerConfig, cert string) (*corev1.Secret, error) {
|
func (b *ResourceBuilder) newScaleSetListenerConfig(autoscalingListener *v1alpha1.AutoscalingListener, secret *corev1.Secret, metricsConfig *listenerMetricsServerConfig, cert string) (*corev1.Secret, error) {
|
||||||
var (
|
var (
|
||||||
metricsAddr = ""
|
metricsAddr = ""
|
||||||
metricsEndpoint = ""
|
metricsEndpoint = ""
|
||||||
@@ -173,8 +169,30 @@ func (b *ResourceBuilder) newScaleSetListenerConfig(autoscalingListener *v1alpha
|
|||||||
metricsEndpoint = metricsConfig.endpoint
|
metricsEndpoint = metricsConfig.endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
config := ghalistenerconfig.Config{
|
var appID int64
|
||||||
|
if id, ok := secret.Data["github_app_id"]; ok {
|
||||||
|
var err error
|
||||||
|
appID, err = strconv.ParseInt(string(id), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to convert github_app_id to int: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var appInstallationID int64
|
||||||
|
if id, ok := secret.Data["github_app_installation_id"]; ok {
|
||||||
|
var err error
|
||||||
|
appInstallationID, err = strconv.ParseInt(string(id), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to convert github_app_installation_id to int: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config := listenerconfig.Config{
|
||||||
ConfigureUrl: autoscalingListener.Spec.GitHubConfigUrl,
|
ConfigureUrl: autoscalingListener.Spec.GitHubConfigUrl,
|
||||||
|
AppID: appID,
|
||||||
|
AppInstallationID: appInstallationID,
|
||||||
|
AppPrivateKey: string(secret.Data["github_app_private_key"]),
|
||||||
|
Token: string(secret.Data["github_token"]),
|
||||||
EphemeralRunnerSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
EphemeralRunnerSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||||
EphemeralRunnerSetName: autoscalingListener.Spec.EphemeralRunnerSetName,
|
EphemeralRunnerSetName: autoscalingListener.Spec.EphemeralRunnerSetName,
|
||||||
MaxRunners: autoscalingListener.Spec.MaxRunners,
|
MaxRunners: autoscalingListener.Spec.MaxRunners,
|
||||||
@@ -189,24 +207,6 @@ func (b *ResourceBuilder) newScaleSetListenerConfig(autoscalingListener *v1alpha
|
|||||||
Metrics: autoscalingListener.Spec.Metrics,
|
Metrics: autoscalingListener.Spec.Metrics,
|
||||||
}
|
}
|
||||||
|
|
||||||
vault := autoscalingListener.Spec.VaultConfig
|
|
||||||
if vault == nil {
|
|
||||||
config.AppConfig = appConfig
|
|
||||||
} else {
|
|
||||||
config.VaultType = vault.Type
|
|
||||||
config.VaultLookupKey = autoscalingListener.Spec.GitHubConfigSecret
|
|
||||||
config.AzureKeyVaultConfig = &azurekeyvault.Config{
|
|
||||||
TenantID: vault.AzureKeyVault.TenantID,
|
|
||||||
ClientID: vault.AzureKeyVault.ClientID,
|
|
||||||
URL: vault.AzureKeyVault.URL,
|
|
||||||
CertificatePath: vault.AzureKeyVault.CertificatePath,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := config.Validate(); err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid listener config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := json.NewEncoder(&buf).Encode(config); err != nil {
|
if err := json.NewEncoder(&buf).Encode(config); err != nil {
|
||||||
return nil, fmt.Errorf("failed to encode config: %w", err)
|
return nil, fmt.Errorf("failed to encode config: %w", err)
|
||||||
@@ -223,7 +223,7 @@ func (b *ResourceBuilder) newScaleSetListenerConfig(autoscalingListener *v1alpha
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ResourceBuilder) newScaleSetListenerPod(autoscalingListener *v1alpha1.AutoscalingListener, podConfig *corev1.Secret, serviceAccount *corev1.ServiceAccount, metricsConfig *listenerMetricsServerConfig, envs ...corev1.EnvVar) (*corev1.Pod, error) {
|
func (b *ResourceBuilder) newScaleSetListenerPod(autoscalingListener *v1alpha1.AutoscalingListener, podConfig *corev1.Secret, serviceAccount *corev1.ServiceAccount, secret *corev1.Secret, metricsConfig *listenerMetricsServerConfig, envs ...corev1.EnvVar) (*corev1.Pod, error) {
|
||||||
listenerEnv := []corev1.EnvVar{
|
listenerEnv := []corev1.EnvVar{
|
||||||
{
|
{
|
||||||
Name: "LISTENER_CONFIG_PATH",
|
Name: "LISTENER_CONFIG_PATH",
|
||||||
@@ -278,7 +278,9 @@ func (b *ResourceBuilder) newScaleSetListenerPod(autoscalingListener *v1alpha1.A
|
|||||||
}
|
}
|
||||||
|
|
||||||
labels := make(map[string]string, len(autoscalingListener.Labels))
|
labels := make(map[string]string, len(autoscalingListener.Labels))
|
||||||
maps.Copy(labels, autoscalingListener.Labels)
|
for key, val := range autoscalingListener.Labels {
|
||||||
|
labels[key] = val
|
||||||
|
}
|
||||||
|
|
||||||
newRunnerScaleSetListenerPod := &corev1.Pod{
|
newRunnerScaleSetListenerPod := &corev1.Pod{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
@@ -427,7 +429,7 @@ func mergeListenerContainer(base, from *corev1.Container) {
|
|||||||
func (b *ResourceBuilder) newScaleSetListenerServiceAccount(autoscalingListener *v1alpha1.AutoscalingListener) *corev1.ServiceAccount {
|
func (b *ResourceBuilder) newScaleSetListenerServiceAccount(autoscalingListener *v1alpha1.AutoscalingListener) *corev1.ServiceAccount {
|
||||||
return &corev1.ServiceAccount{
|
return &corev1.ServiceAccount{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: autoscalingListener.Name,
|
Name: scaleSetListenerServiceAccountName(autoscalingListener),
|
||||||
Namespace: autoscalingListener.Namespace,
|
Namespace: autoscalingListener.Namespace,
|
||||||
Labels: b.mergeLabels(autoscalingListener.Labels, map[string]string{
|
Labels: b.mergeLabels(autoscalingListener.Labels, map[string]string{
|
||||||
LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||||
@@ -442,7 +444,7 @@ func (b *ResourceBuilder) newScaleSetListenerRole(autoscalingListener *v1alpha1.
|
|||||||
rulesHash := hash.ComputeTemplateHash(&rules)
|
rulesHash := hash.ComputeTemplateHash(&rules)
|
||||||
newRole := &rbacv1.Role{
|
newRole := &rbacv1.Role{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: autoscalingListener.Name,
|
Name: scaleSetListenerRoleName(autoscalingListener),
|
||||||
Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||||
Labels: b.mergeLabels(autoscalingListener.Labels, map[string]string{
|
Labels: b.mergeLabels(autoscalingListener.Labels, map[string]string{
|
||||||
LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||||
@@ -476,7 +478,7 @@ func (b *ResourceBuilder) newScaleSetListenerRoleBinding(autoscalingListener *v1
|
|||||||
|
|
||||||
newRoleBinding := &rbacv1.RoleBinding{
|
newRoleBinding := &rbacv1.RoleBinding{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: autoscalingListener.Name,
|
Name: scaleSetListenerRoleName(autoscalingListener),
|
||||||
Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||||
Labels: b.mergeLabels(autoscalingListener.Labels, map[string]string{
|
Labels: b.mergeLabels(autoscalingListener.Labels, map[string]string{
|
||||||
LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||||
@@ -494,8 +496,27 @@ func (b *ResourceBuilder) newScaleSetListenerRoleBinding(autoscalingListener *v1
|
|||||||
return newRoleBinding
|
return newRoleBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *ResourceBuilder) newScaleSetListenerSecretMirror(autoscalingListener *v1alpha1.AutoscalingListener, secret *corev1.Secret) *corev1.Secret {
|
||||||
|
dataHash := hash.ComputeTemplateHash(&secret.Data)
|
||||||
|
|
||||||
|
newListenerSecret := &corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: scaleSetListenerSecretMirrorName(autoscalingListener),
|
||||||
|
Namespace: autoscalingListener.Namespace,
|
||||||
|
Labels: b.mergeLabels(autoscalingListener.Labels, map[string]string{
|
||||||
|
LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||||
|
LabelKeyGitHubScaleSetName: autoscalingListener.Spec.AutoscalingRunnerSetName,
|
||||||
|
"secret-data-hash": dataHash,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Data: secret.DeepCopy().Data,
|
||||||
|
}
|
||||||
|
|
||||||
|
return newListenerSecret
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
@@ -540,13 +561,12 @@ 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,
|
||||||
GitHubServerTLS: autoscalingRunnerSet.Spec.GitHubServerTLS,
|
GitHubServerTLS: autoscalingRunnerSet.Spec.GitHubServerTLS,
|
||||||
PodTemplateSpec: autoscalingRunnerSet.Spec.Template,
|
PodTemplateSpec: autoscalingRunnerSet.Spec.Template,
|
||||||
VaultConfig: autoscalingRunnerSet.VaultConfig(),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -555,23 +575,27 @@ 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, len(ephemeralRunnerSet.Labels))
|
labels := make(map[string]string)
|
||||||
maps.Copy(labels, ephemeralRunnerSet.Labels)
|
for k, v := range ephemeralRunnerSet.Labels {
|
||||||
labels[LabelKeyKubernetesComponent] = "runner"
|
if k == LabelKeyKubernetesComponent {
|
||||||
|
labels[k] = "runner"
|
||||||
|
} else {
|
||||||
|
labels[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
annotations := make(map[string]string, len(ephemeralRunnerSet.Annotations)+1)
|
annotations := make(map[string]string)
|
||||||
maps.Copy(annotations, ephemeralRunnerSet.Annotations)
|
for key, val := range ephemeralRunnerSet.Annotations {
|
||||||
|
annotations[key] = val
|
||||||
|
}
|
||||||
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(),
|
||||||
@@ -587,22 +611,32 @@ func (b *ResourceBuilder) newEphemeralRunner(ephemeralRunnerSet *v1alpha1.Epheme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ResourceBuilder) newEphemeralRunnerPod(runner *v1alpha1.EphemeralRunner, secret *corev1.Secret, envs ...corev1.EnvVar) *corev1.Pod {
|
func (b *ResourceBuilder) newEphemeralRunnerPod(ctx context.Context, runner *v1alpha1.EphemeralRunner, secret *corev1.Secret, envs ...corev1.EnvVar) *corev1.Pod {
|
||||||
var newPod corev1.Pod
|
var newPod corev1.Pod
|
||||||
|
|
||||||
annotations := make(map[string]string, len(runner.Annotations)+len(runner.Spec.Annotations))
|
labels := map[string]string{}
|
||||||
maps.Copy(annotations, runner.Annotations)
|
annotations := map[string]string{}
|
||||||
maps.Copy(annotations, runner.Spec.Annotations)
|
|
||||||
|
|
||||||
labels := make(map[string]string, len(runner.Labels)+len(runner.Spec.Labels)+2)
|
for k, v := range runner.Labels {
|
||||||
maps.Copy(labels, runner.Labels)
|
labels[k] = v
|
||||||
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,
|
||||||
secret.Data,
|
runner.Status.RunnerJITConfig,
|
||||||
)
|
)
|
||||||
|
|
||||||
objectMeta := metav1.ObjectMeta{
|
objectMeta := metav1.ObjectMeta{
|
||||||
@@ -655,17 +689,14 @@ func (b *ResourceBuilder) newEphemeralRunnerPod(runner *v1alpha1.EphemeralRunner
|
|||||||
return &newPod
|
return &newPod
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ResourceBuilder) newEphemeralRunnerJitSecret(ephemeralRunner *v1alpha1.EphemeralRunner, jitConfig *actions.RunnerScaleSetJitRunnerConfig) *corev1.Secret {
|
func (b *ResourceBuilder) newEphemeralRunnerJitSecret(ephemeralRunner *v1alpha1.EphemeralRunner) *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(jitConfig.EncodedJITConfig),
|
jitTokenKey: []byte(ephemeralRunner.Status.RunnerJITConfig),
|
||||||
"runnerName": []byte(jitConfig.Runner.Name),
|
|
||||||
"runnerId": []byte(strconv.Itoa(jitConfig.Runner.Id)),
|
|
||||||
"scaleSetId": []byte(strconv.Itoa(jitConfig.Runner.RunnerScaleSetId)),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -674,28 +705,44 @@ func scaleSetListenerConfigName(autoscalingListener *v1alpha1.AutoscalingListene
|
|||||||
return fmt.Sprintf("%s-config", autoscalingListener.Name)
|
return fmt.Sprintf("%s-config", autoscalingListener.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashSuffix(namespace, runnerGroup, configURL string) string {
|
func scaleSetListenerName(autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet) string {
|
||||||
namespaceHash := hash.FNVHashString(namespace + "@" + runnerGroup + "@" + configURL)
|
namespaceHash := hash.FNVHashString(autoscalingRunnerSet.Namespace)
|
||||||
if len(namespaceHash) > 8 {
|
if len(namespaceHash) > 8 {
|
||||||
namespaceHash = namespaceHash[:8]
|
namespaceHash = namespaceHash[:8]
|
||||||
}
|
}
|
||||||
return namespaceHash
|
return fmt.Sprintf("%v-%v-listener", autoscalingRunnerSet.Name, namespaceHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func scaleSetListenerName(autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet) string {
|
func scaleSetListenerServiceAccountName(autoscalingListener *v1alpha1.AutoscalingListener) string {
|
||||||
return fmt.Sprintf(
|
namespaceHash := hash.FNVHashString(autoscalingListener.Spec.AutoscalingRunnerSetNamespace)
|
||||||
"%v-%v-listener",
|
if len(namespaceHash) > 8 {
|
||||||
autoscalingRunnerSet.Name,
|
namespaceHash = namespaceHash[:8]
|
||||||
hashSuffix(
|
}
|
||||||
autoscalingRunnerSet.Namespace,
|
return fmt.Sprintf("%v-%v-listener", autoscalingListener.Spec.AutoscalingRunnerSetName, namespaceHash)
|
||||||
autoscalingRunnerSet.Spec.RunnerGroup,
|
}
|
||||||
autoscalingRunnerSet.Spec.GitHubConfigUrl,
|
|
||||||
),
|
func scaleSetListenerRoleName(autoscalingListener *v1alpha1.AutoscalingListener) string {
|
||||||
)
|
namespaceHash := hash.FNVHashString(autoscalingListener.Spec.AutoscalingRunnerSetNamespace)
|
||||||
|
if len(namespaceHash) > 8 {
|
||||||
|
namespaceHash = namespaceHash[:8]
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v-%v-listener", autoscalingListener.Spec.AutoscalingRunnerSetName, namespaceHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func scaleSetListenerSecretMirrorName(autoscalingListener *v1alpha1.AutoscalingListener) string {
|
||||||
|
namespaceHash := hash.FNVHashString(autoscalingListener.Spec.AutoscalingRunnerSetNamespace)
|
||||||
|
if len(namespaceHash) > 8 {
|
||||||
|
namespaceHash = namespaceHash[:8]
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v-%v-listener", autoscalingListener.Spec.AutoscalingRunnerSetName, namespaceHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func proxyListenerSecretName(autoscalingListener *v1alpha1.AutoscalingListener) string {
|
func proxyListenerSecretName(autoscalingListener *v1alpha1.AutoscalingListener) string {
|
||||||
return autoscalingListener.Name + "-proxy"
|
namespaceHash := hash.FNVHashString(autoscalingListener.Spec.AutoscalingRunnerSetNamespace)
|
||||||
|
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 {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package actionsgithubcom
|
package actionsgithubcom
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -27,7 +28,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",
|
||||||
},
|
},
|
||||||
@@ -81,7 +82,12 @@ func TestLabelPropagation(t *testing.T) {
|
|||||||
Name: "test",
|
Name: "test",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
listenerPod, err := b.newScaleSetListenerPod(listener, &corev1.Secret{}, listenerServiceAccount, nil)
|
listenerSecret := &corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
listenerPod, err := b.newScaleSetListenerPod(listener, &corev1.Secret{}, listenerServiceAccount, listenerSecret, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, listenerPod.Labels, listener.Labels)
|
assert.Equal(t, listenerPod.Labels, listener.Labels)
|
||||||
|
|
||||||
@@ -103,7 +109,7 @@ func TestLabelPropagation(t *testing.T) {
|
|||||||
Name: "test",
|
Name: "test",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
pod := b.newEphemeralRunnerPod(ephemeralRunner, runnerSecret)
|
pod := b.newEphemeralRunnerPod(context.TODO(), 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])
|
||||||
}
|
}
|
||||||
@@ -123,7 +129,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",
|
||||||
},
|
},
|
||||||
@@ -189,7 +195,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",
|
||||||
@@ -232,7 +238,7 @@ func TestOwnershipRelationships(t *testing.T) {
|
|||||||
Name: "test-secret",
|
Name: "test-secret",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
pod := b.newEphemeralRunnerPod(ephemeralRunner, runnerSecret)
|
pod := b.newEphemeralRunnerPod(context.TODO(), 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")
|
||||||
|
|||||||
@@ -1,280 +0,0 @@
|
|||||||
package actionsgithubcom
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
|
||||||
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1/appconfig"
|
|
||||||
"github.com/actions/actions-runner-controller/github/actions"
|
|
||||||
"github.com/actions/actions-runner-controller/vault"
|
|
||||||
"github.com/actions/actions-runner-controller/vault/azurekeyvault"
|
|
||||||
"golang.org/x/net/http/httpproxy"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SecretResolver struct {
|
|
||||||
k8sClient client.Client
|
|
||||||
multiClient actions.MultiClient
|
|
||||||
}
|
|
||||||
|
|
||||||
type SecretResolverOption func(*SecretResolver)
|
|
||||||
|
|
||||||
func NewSecretResolver(k8sClient client.Client, multiClient actions.MultiClient, opts ...SecretResolverOption) *SecretResolver {
|
|
||||||
if k8sClient == nil {
|
|
||||||
panic("k8sClient must not be nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
secretResolver := &SecretResolver{
|
|
||||||
k8sClient: k8sClient,
|
|
||||||
multiClient: multiClient,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(secretResolver)
|
|
||||||
}
|
|
||||||
|
|
||||||
return secretResolver
|
|
||||||
}
|
|
||||||
|
|
||||||
type ActionsGitHubObject interface {
|
|
||||||
client.Object
|
|
||||||
GitHubConfigUrl() string
|
|
||||||
GitHubConfigSecret() string
|
|
||||||
GitHubProxy() *v1alpha1.ProxyConfig
|
|
||||||
GitHubServerTLS() *v1alpha1.TLSConfig
|
|
||||||
VaultConfig() *v1alpha1.VaultConfig
|
|
||||||
VaultProxy() *v1alpha1.ProxyConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *SecretResolver) GetAppConfig(ctx context.Context, obj ActionsGitHubObject) (*appconfig.AppConfig, error) {
|
|
||||||
resolver, err := sr.resolverForObject(ctx, obj)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get resolver for object: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
appConfig, err := resolver.appConfig(ctx, obj.GitHubConfigSecret())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to resolve app config: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return appConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *SecretResolver) GetActionsService(ctx context.Context, obj ActionsGitHubObject) (actions.ActionsService, error) {
|
|
||||||
resolver, err := sr.resolverForObject(ctx, obj)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get resolver for object: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
appConfig, err := resolver.appConfig(ctx, obj.GitHubConfigSecret())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to resolve app config: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var clientOptions []actions.ClientOption
|
|
||||||
if proxy := obj.GitHubProxy(); proxy != nil {
|
|
||||||
config := &httpproxy.Config{
|
|
||||||
NoProxy: strings.Join(proxy.NoProxy, ","),
|
|
||||||
}
|
|
||||||
|
|
||||||
if proxy.HTTP != nil {
|
|
||||||
u, err := url.Parse(proxy.HTTP.Url)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to parse proxy http url %q: %w", proxy.HTTP.Url, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ref := proxy.HTTP.CredentialSecretRef; ref != "" {
|
|
||||||
u.User, err = resolver.proxyCredentials(ctx, ref)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to resolve proxy credentials: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config.HTTPProxy = u.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
if proxy.HTTPS != nil {
|
|
||||||
u, err := url.Parse(proxy.HTTPS.Url)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to parse proxy https url %q: %w", proxy.HTTPS.Url, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ref := proxy.HTTPS.CredentialSecretRef; ref != "" {
|
|
||||||
u.User, err = resolver.proxyCredentials(ctx, ref)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to resolve proxy credentials: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config.HTTPSProxy = u.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
|
||||||
return config.ProxyFunc()(req.URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
clientOptions = append(clientOptions, actions.WithProxy(proxyFunc))
|
|
||||||
}
|
|
||||||
|
|
||||||
tlsConfig := obj.GitHubServerTLS()
|
|
||||||
if tlsConfig != nil {
|
|
||||||
pool, err := tlsConfig.ToCertPool(func(name, key string) ([]byte, error) {
|
|
||||||
var configmap corev1.ConfigMap
|
|
||||||
err := sr.k8sClient.Get(
|
|
||||||
ctx,
|
|
||||||
types.NamespacedName{
|
|
||||||
Namespace: obj.GetNamespace(),
|
|
||||||
Name: name,
|
|
||||||
},
|
|
||||||
&configmap,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get configmap %s: %w", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return []byte(configmap.Data[key]), nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get tls config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
clientOptions = append(clientOptions, actions.WithRootCAs(pool))
|
|
||||||
}
|
|
||||||
|
|
||||||
return sr.multiClient.GetClientFor(
|
|
||||||
ctx,
|
|
||||||
obj.GitHubConfigUrl(),
|
|
||||||
appConfig,
|
|
||||||
obj.GetNamespace(),
|
|
||||||
clientOptions...,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *SecretResolver) resolverForObject(ctx context.Context, obj ActionsGitHubObject) (resolver, error) {
|
|
||||||
vaultConfig := obj.VaultConfig()
|
|
||||||
if vaultConfig == nil || vaultConfig.Type == "" {
|
|
||||||
return &k8sResolver{
|
|
||||||
namespace: obj.GetNamespace(),
|
|
||||||
client: sr.k8sClient,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var proxy *httpproxy.Config
|
|
||||||
if vaultProxy := obj.VaultProxy(); vaultProxy != nil {
|
|
||||||
p, err := vaultProxy.ToHTTPProxyConfig(func(s string) (*corev1.Secret, error) {
|
|
||||||
var secret corev1.Secret
|
|
||||||
err := sr.k8sClient.Get(ctx, types.NamespacedName{Name: s, Namespace: obj.GetNamespace()}, &secret)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get secret %s: %w", s, err)
|
|
||||||
}
|
|
||||||
return &secret, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create proxy config: %v", err)
|
|
||||||
}
|
|
||||||
proxy = p
|
|
||||||
}
|
|
||||||
|
|
||||||
switch vaultConfig.Type {
|
|
||||||
case vault.VaultTypeAzureKeyVault:
|
|
||||||
akv, err := azurekeyvault.New(azurekeyvault.Config{
|
|
||||||
TenantID: vaultConfig.AzureKeyVault.TenantID,
|
|
||||||
ClientID: vaultConfig.AzureKeyVault.ClientID,
|
|
||||||
URL: vaultConfig.AzureKeyVault.URL,
|
|
||||||
CertificatePath: vaultConfig.AzureKeyVault.CertificatePath,
|
|
||||||
Proxy: proxy,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create Azure Key Vault client: %v", err)
|
|
||||||
}
|
|
||||||
return &vaultResolver{
|
|
||||||
vault: akv,
|
|
||||||
}, nil
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknown vault type %q", vaultConfig.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type resolver interface {
|
|
||||||
appConfig(ctx context.Context, key string) (*appconfig.AppConfig, error)
|
|
||||||
proxyCredentials(ctx context.Context, key string) (*url.Userinfo, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type k8sResolver struct {
|
|
||||||
namespace string
|
|
||||||
client client.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *k8sResolver) appConfig(ctx context.Context, key string) (*appconfig.AppConfig, error) {
|
|
||||||
nsName := types.NamespacedName{
|
|
||||||
Namespace: r.namespace,
|
|
||||||
Name: key,
|
|
||||||
}
|
|
||||||
secret := new(corev1.Secret)
|
|
||||||
if err := r.client.Get(
|
|
||||||
ctx,
|
|
||||||
nsName,
|
|
||||||
secret,
|
|
||||||
); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get kubernetes secret: %q", nsName.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return appconfig.FromSecret(secret)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *k8sResolver) proxyCredentials(ctx context.Context, key string) (*url.Userinfo, error) {
|
|
||||||
nsName := types.NamespacedName{Namespace: r.namespace, Name: key}
|
|
||||||
secret := new(corev1.Secret)
|
|
||||||
if err := r.client.Get(
|
|
||||||
ctx,
|
|
||||||
nsName,
|
|
||||||
secret,
|
|
||||||
); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get kubernetes secret: %q", nsName.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return url.UserPassword(
|
|
||||||
string(secret.Data["username"]),
|
|
||||||
string(secret.Data["password"]),
|
|
||||||
), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type vaultResolver struct {
|
|
||||||
vault vault.Vault
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *vaultResolver) appConfig(ctx context.Context, key string) (*appconfig.AppConfig, error) {
|
|
||||||
val, err := r.vault.GetSecret(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to resolve secret: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return appconfig.FromJSONString(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *vaultResolver) proxyCredentials(ctx context.Context, key string) (*url.Userinfo, error) {
|
|
||||||
val, err := r.vault.GetSecret(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to resolve secret: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
type info struct {
|
|
||||||
Username string `json:"username"`
|
|
||||||
Password string `json:"password"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var i info
|
|
||||||
if err := json.Unmarshal([]byte(val), &i); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to unmarshal info: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return url.UserPassword(i.Username, i.Password), nil
|
|
||||||
}
|
|
||||||
@@ -20,7 +20,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/onsi/ginkgo/config"
|
"github.com/onsi/ginkgo/config"
|
||||||
|
|
||||||
@@ -80,15 +79,6 @@ var _ = BeforeSuite(func() {
|
|||||||
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
|
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(k8sClient).ToNot(BeNil())
|
Expect(k8sClient).ToNot(BeNil())
|
||||||
|
|
||||||
failedRunnerBackoff = []time.Duration{
|
|
||||||
20 * time.Millisecond,
|
|
||||||
20 * time.Millisecond,
|
|
||||||
20 * time.Millisecond,
|
|
||||||
20 * time.Millisecond,
|
|
||||||
20 * time.Millisecond,
|
|
||||||
20 * time.Millisecond,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
var _ = AfterSuite(func() {
|
var _ = AfterSuite(func() {
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ func (r *HorizontalRunnerAutoscalerReconciler) suggestReplicasByQueuedAndInProgr
|
|||||||
jobs, resp, err := ghc.Actions.ListWorkflowJobs(context.TODO(), user, repoName, runID, &opt)
|
jobs, resp, err := ghc.Actions.ListWorkflowJobs(context.TODO(), user, repoName, runID, &opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Log.Error(err, "Error listing workflow jobs")
|
r.Log.Error(err, "Error listing workflow jobs")
|
||||||
return // err
|
return //err
|
||||||
}
|
}
|
||||||
allJobs = append(allJobs, jobs.Jobs...)
|
allJobs = append(allJobs, jobs.Jobs...)
|
||||||
if resp.NextPage == 0 {
|
if resp.NextPage == 0 {
|
||||||
|
|||||||
@@ -321,34 +321,26 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) findHRAsByKey(ctx con
|
|||||||
defaultListOpts = append(defaultListOpts, client.InNamespace(ns))
|
defaultListOpts = append(defaultListOpts, client.InNamespace(ns))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all HRAs since we can't use the index for repository/organization lookup anymore
|
var hras []v1alpha1.HorizontalRunnerAutoscaler
|
||||||
var hraList v1alpha1.HorizontalRunnerAutoscalerList
|
|
||||||
if err := autoscaler.List(ctx, &hraList, defaultListOpts...); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var matchingHRAs []v1alpha1.HorizontalRunnerAutoscaler
|
if value != "" {
|
||||||
|
opts := append([]client.ListOption{}, defaultListOpts...)
|
||||||
|
opts = append(opts, client.MatchingFields{scaleTargetKey: value})
|
||||||
|
|
||||||
if value == "" {
|
if autoscaler.Namespace != "" {
|
||||||
return matchingHRAs, nil
|
opts = append(opts, client.InNamespace(autoscaler.Namespace))
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
var hraList v1alpha1.HorizontalRunnerAutoscalerList
|
||||||
for _, key := range keys {
|
|
||||||
if key == value {
|
if err := autoscaler.List(ctx, &hraList, opts...); err != nil {
|
||||||
matchingHRAs = append(matchingHRAs, hra)
|
return nil, err
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hras = append(hras, hraList.Items...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return matchingHRAs, nil
|
return hras, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScaleTarget struct {
|
type ScaleTarget struct {
|
||||||
@@ -718,36 +710,10 @@ 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(ctx, types.NamespacedName{Namespace: hra.Namespace, Name: hra.Spec.ScaleTargetRef.Name}, &rd); err != nil {
|
if err := autoscaler.Get(context.Background(), 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
|
||||||
}
|
}
|
||||||
@@ -770,10 +736,11 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getHRAKeys(ctx contex
|
|||||||
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(ctx, types.NamespacedName{Namespace: hra.Namespace, Name: hra.Spec.ScaleTargetRef.Name}, &rs); err != nil {
|
if err := autoscaler.Get(context.Background(), 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
|
||||||
}
|
}
|
||||||
@@ -794,8 +761,21 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getHRAKeys(ctx contex
|
|||||||
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -420,14 +419,9 @@ 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: syncWriter,
|
writer: logs,
|
||||||
}
|
}
|
||||||
|
|
||||||
log := logr.New(sink)
|
log := logr.New(sink)
|
||||||
@@ -523,18 +517,6 @@ 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 {
|
||||||
|
|||||||
@@ -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 and 24.04 images
|
// We default to gid 121 for Ubuntu 22.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") || strings.Contains(runnerContainer.Image, "24.04") {
|
if strings.Contains(runnerContainer.Image, "22.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"
|
||||||
|
|||||||
@@ -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 and 24.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 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/REPO
|
repository: USER/REO
|
||||||
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 and 24.04 runner
|
# Use 1001 for Ubuntu 22.04 runner
|
||||||
#fsGroup: 1001
|
#fsGroup: 1001
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -43,53 +43,6 @@ 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
|
|
||||||
|
|
||||||
1. Fix indentation of startupProbe attributes in dind sidecar [#4126](https://github.com/actions/actions-runner-controller/pull/4126)
|
|
||||||
1. Remove duplicate float64 call [#4139](https://github.com/actions/actions-runner-controller/pull/4139)
|
|
||||||
1. Fix dind sidecar template [#4128](https://github.com/actions/actions-runner-controller/pull/4128)
|
|
||||||
1. Remove check if runner exists after exit code 0 [#4142](https://github.com/actions/actions-runner-controller/pull/4142)
|
|
||||||
1. Explicitly requeue during backoff ephemeral runner [#4152](https://github.com/actions/actions-runner-controller/pull/4152)
|
|
||||||
|
|
||||||
### 0.12.0
|
|
||||||
|
|
||||||
1. Allow use of client id as an app id [#4057](https://github.com/actions/actions-runner-controller/pull/4057)
|
|
||||||
1. Relax version requirements to allow patch version mismatch [#4080](https://github.com/actions/actions-runner-controller/pull/4080)
|
|
||||||
1. Refactor resource naming removing unnecessary calculations [#4076](https://github.com/actions/actions-runner-controller/pull/4076)
|
|
||||||
1. Fix busy runners metric [#4016](https://github.com/actions/actions-runner-controller/pull/4016)
|
|
||||||
1. Include more context to errors raised by github/actions client [#4032](https://github.com/actions/actions-runner-controller/pull/4032)
|
|
||||||
1. Revised dashboard [#4022](https://github.com/actions/actions-runner-controller/pull/4022)
|
|
||||||
1. feat(helm): move dind to sidecar [#3842](https://github.com/actions/actions-runner-controller/pull/3842)
|
|
||||||
1. Pin third party actions [#3981](https://github.com/actions/actions-runner-controller/pull/3981)
|
|
||||||
1. Fix docker lint warnings [#4074](https://github.com/actions/actions-runner-controller/pull/4074)
|
|
||||||
1. Bump the gomod group across 1 directory with 7 updates [#4008](https://github.com/actions/actions-runner-controller/pull/4008)
|
|
||||||
1. Bump go version [#4075](https://github.com/actions/actions-runner-controller/pull/4075)
|
|
||||||
1. Add job_workflow_ref label to listener metrics [#4054](https://github.com/actions/actions-runner-controller/pull/4054)
|
|
||||||
1. Bump github.com/cloudflare/circl from 1.6.0 to 1.6.1 [#4118](https://github.com/actions/actions-runner-controller/pull/4118)
|
|
||||||
1. Avoid nil point when config.Metrics is nil and expose all metrics if none are configured [#4101](https://github.com/actions/actions-runner-controller/pull/4101)
|
|
||||||
1. Bump github.com/golang-jwt/jwt/v5 from 5.2.1 to 5.2.2 [#4120](https://github.com/actions/actions-runner-controller/pull/4120)
|
|
||||||
1. Add startup probe to dind side-car [#4117](https://github.com/actions/actions-runner-controller/pull/4117)
|
|
||||||
1. Delete config secret when listener pod gets deleted [#4033](https://github.com/actions/actions-runner-controller/pull/4033)
|
|
||||||
1. Add response body to error when fetching access token [#4005](https://github.com/actions/actions-runner-controller/pull/4005)
|
|
||||||
1. Azure Key Vault integration to resolve secrets [#4090](https://github.com/actions/actions-runner-controller/pull/4090)
|
|
||||||
1. Create backoff mechanism for failed runners and allow re-creation of failed ephemeral runners [#4059](https://github.com/actions/actions-runner-controller/pull/4059)
|
|
||||||
|
|
||||||
### 0.11.0
|
### 0.11.0
|
||||||
|
|
||||||
1. Add events role permission to leader_election_role [#3988](https://github.com/actions/actions-runner-controller/pull/3988)
|
1. Add events role permission to leader_election_role [#3988](https://github.com/actions/actions-runner-controller/pull/3988)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user