mirror of
https://github.com/actions/actions-runner-controller.git
synced 2025-12-10 11:41:27 +00:00
Compare commits
192 Commits
actions-ru
...
actions-ru
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67031acdc4 | ||
|
|
b1bfa8787f | ||
|
|
c78116b0f9 | ||
|
|
4ec57d3e39 | ||
|
|
79543add3f | ||
|
|
7722730dc0 | ||
|
|
044f4ad4ea | ||
|
|
20394be04d | ||
|
|
7a305d2892 | ||
|
|
927d6f03ce | ||
|
|
127a9aa7c4 | ||
|
|
2703fa75d6 | ||
|
|
605ec158f4 | ||
|
|
3b45d1b334 | ||
|
|
acb906164b | ||
|
|
98da4c2adb | ||
|
|
9e1c28fcff | ||
|
|
774db3fef4 | ||
|
|
8b90b0f0e3 | ||
|
|
a277489003 | ||
|
|
1084a37174 | ||
|
|
9e4dbf497c | ||
|
|
af0ca03752 | ||
|
|
37d9599dca | ||
|
|
08a676cfd4 | ||
|
|
f2e2060ff8 | ||
|
|
dc5f90025c | ||
|
|
8566a4f453 | ||
|
|
3366dc9a63 | ||
|
|
fa94799ec8 | ||
|
|
c424d1afee | ||
|
|
99f83a9bf0 | ||
|
|
aa7d4c5ecc | ||
|
|
552ee28072 | ||
|
|
fa77facacd | ||
|
|
5b28f3d964 | ||
|
|
c36748b8bc | ||
|
|
f16f5b0aa4 | ||
|
|
c889b92f45 | ||
|
|
46be20976a | ||
|
|
8c42f99d0b | ||
|
|
a93fd21f21 | ||
|
|
7523ea44f1 | ||
|
|
30ab0c0b71 | ||
|
|
a72f190ef6 | ||
|
|
cb60c1ec3b | ||
|
|
e108e04dda | ||
|
|
2e083bca28 | ||
|
|
198b13324d | ||
|
|
605dae3995 | ||
|
|
d2b0920454 | ||
|
|
2cbeca0e7c | ||
|
|
859e04a680 | ||
|
|
c0821d4ede | ||
|
|
c3a6e45920 | ||
|
|
818dfd6515 | ||
|
|
726b39aedd | ||
|
|
7638c21e92 | ||
|
|
c09d6075c6 | ||
|
|
39d37a7d28 | ||
|
|
de0315380d | ||
|
|
906ddacbc6 | ||
|
|
c388446668 | ||
|
|
d56971ca7c | ||
|
|
cb14d7530b | ||
|
|
fbb24c8c0a | ||
|
|
0b88b246d3 | ||
|
|
a4631f345b | ||
|
|
7be31ce3e5 | ||
|
|
57a7b8076f | ||
|
|
5309b1c02c | ||
|
|
ae09e6ebb7 | ||
|
|
3cd124dce3 | ||
|
|
25f5817a5e | ||
|
|
0510f19607 | ||
|
|
9d961c58ff | ||
|
|
ab25907050 | ||
|
|
6cbba80df1 | ||
|
|
082245c5db | ||
|
|
a82e020daa | ||
|
|
c8c2d44a5c | ||
|
|
4e7b8b57c0 | ||
|
|
e7020c7c0f | ||
|
|
cb54864387 | ||
|
|
0e0f385f72 | ||
|
|
b3cae25741 | ||
|
|
469b117a09 | ||
|
|
5f59734078 | ||
|
|
e00b3b9714 | ||
|
|
588872a316 | ||
|
|
a0feee257f | ||
|
|
a18ac330bb | ||
|
|
0901456320 | ||
|
|
dbd7b486d2 | ||
|
|
7e766282aa | ||
|
|
ba175148c8 | ||
|
|
358146ee54 | ||
|
|
e9dd16b023 | ||
|
|
1ba4098648 | ||
|
|
05fb8569b3 | ||
|
|
db45a375d0 | ||
|
|
81dd47a893 | ||
|
|
6b77a2a5a8 | ||
|
|
dc4cf3f57b | ||
|
|
d810b579a5 | ||
|
|
47c8de9dc3 | ||
|
|
74a53bde5e | ||
|
|
aad2615487 | ||
|
|
03d9b6a09f | ||
|
|
5d280cc8c8 | ||
|
|
133c4fb21e | ||
|
|
3b2d2c052e | ||
|
|
37c2a62fa8 | ||
|
|
2eeb56d1c8 | ||
|
|
a612b38f9b | ||
|
|
1c67ea65d9 | ||
|
|
c26fb5ad5f | ||
|
|
325c2cc385 | ||
|
|
2e551c9d0a | ||
|
|
7b44454d01 | ||
|
|
f2680b2f2d | ||
|
|
b42b8406a2 | ||
|
|
3c125e2191 | ||
|
|
9ed245c85e | ||
|
|
5b7807d54b | ||
|
|
156e2c1987 | ||
|
|
da4dfb3fdf | ||
|
|
0783ffe989 | ||
|
|
374105c1f3 | ||
|
|
bc6e499e4f | ||
|
|
07f822bb08 | ||
|
|
3a0332dfdc | ||
|
|
f6ab66c55b | ||
|
|
d874a5cfda | ||
|
|
c424215044 | ||
|
|
c5fdfd63db | ||
|
|
23a45eaf87 | ||
|
|
dee997b44e | ||
|
|
2929a739e3 | ||
|
|
3cccca8d09 | ||
|
|
7a7086e7aa | ||
|
|
565b14a148 | ||
|
|
ecc441de3f | ||
|
|
25335bb3c3 | ||
|
|
9b871567b1 | ||
|
|
264cf494e3 | ||
|
|
3f23501b8e | ||
|
|
5530030c67 | ||
|
|
8d3a83b07a | ||
|
|
a6270b44d5 | ||
|
|
2273b198a1 | ||
|
|
3d62e73f8c | ||
|
|
f5c639ae28 | ||
|
|
81016154c0 | ||
|
|
728829be7b | ||
|
|
c0b8f9d483 | ||
|
|
ced1c2321a | ||
|
|
1b8a656051 | ||
|
|
1753fa3530 | ||
|
|
8c0f3dfc79 | ||
|
|
dbda292f54 | ||
|
|
550a864198 | ||
|
|
4fa5315311 | ||
|
|
11e58fcc41 | ||
|
|
f220fefe92 | ||
|
|
56b4598d1d | ||
|
|
8f977dbe48 | ||
|
|
9ae3551744 | ||
|
|
05ad3f5469 | ||
|
|
9c7372a8e0 | ||
|
|
584590e97c | ||
|
|
d18884a0b9 | ||
|
|
f987571b64 | ||
|
|
450e384c4c | ||
|
|
e9eef04993 | ||
|
|
598dd1d9fe | ||
|
|
9890a90e69 | ||
|
|
9da123ae5e | ||
|
|
4d4137aa28 | ||
|
|
022007078e | ||
|
|
31e5e61155 | ||
|
|
1d1453c5f2 | ||
|
|
e44e53b88e | ||
|
|
398791241e | ||
|
|
991535e567 | ||
|
|
2d7fbbfb68 | ||
|
|
dd0b9f3e95 | ||
|
|
7cb2bc84c8 | ||
|
|
b0e74bebab | ||
|
|
dfbe53dcca | ||
|
|
ebc3970b84 | ||
|
|
1ddcf6946a |
13
.dockerignore
Normal file
13
.dockerignore
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Makefile
|
||||||
|
acceptance
|
||||||
|
runner
|
||||||
|
hack
|
||||||
|
test-assets
|
||||||
|
config
|
||||||
|
charts
|
||||||
|
.github
|
||||||
|
.envrc
|
||||||
|
.env
|
||||||
|
*.md
|
||||||
|
*.txt
|
||||||
|
*.sh
|
||||||
36
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**Checks**
|
||||||
|
|
||||||
|
- [ ] My actions-runner-controller version (v0.x.y) does support the feature
|
||||||
|
- [ ] I'm using an unreleased version of the controller I built from HEAD of the default branch
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Environment (please complete the following information):**
|
||||||
|
- Controller Version [e.g. 0.18.2]
|
||||||
|
- Deployment Method [e.g. Helm and Kustomize ]
|
||||||
|
- Helm Chart Version [e.g. 0.11.0, if applicable]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
19
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
19
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
34
.github/RELEASE_NOTE_TEMPLATE.md
vendored
Normal file
34
.github/RELEASE_NOTE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Release Note Template
|
||||||
|
|
||||||
|
This is the template of actions-runner-controller's release notes.
|
||||||
|
|
||||||
|
Whenever a new release is made, I start by manually copy-pasting this template onto the GitHub UI for creating the release.
|
||||||
|
|
||||||
|
I then walk-through all the changes, take sometime to think abount best one-sentence explanations to tell the users about changes, write it all,
|
||||||
|
and click the publish button.
|
||||||
|
|
||||||
|
If you think you can improve future release notes in any way, please do submit a pull request to change the template below.
|
||||||
|
|
||||||
|
Note that even though it looks like a Go template, I don't use any templating to generate the changelog.
|
||||||
|
It's just that I'm used to reading and intepreting Go template by myself, not a computer program :)
|
||||||
|
|
||||||
|
**Title**:
|
||||||
|
|
||||||
|
```
|
||||||
|
v{{ .Version }}: {{ .TitlesOfImportantChanges }}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Body**:
|
||||||
|
|
||||||
|
```
|
||||||
|
**CAUTION:** If you're using the Helm chart, beware to review changes to CRDs and do manually upgrade CRDs! Helm installs CRDs only on installing a chart. It doesn't automatically upgrade CRDs. Otherwise you end up with troubles like #427, #467, and #468. Please refer to the [UPGRADING](charts/actions-runner-controller/docs/UPGRADING.md) docs for the latest process.
|
||||||
|
|
||||||
|
This release includes the following changes from contributors. Thank you!
|
||||||
|
|
||||||
|
- @{{ .GitHubUser }} fixed {{ .Feature }} to not break when ... (#{{ .PullRequestNumber }})
|
||||||
|
- @{{ .GitHubUser }} enhanced {{ .Feature }} to ... (#{{ .PullRequestNumber }})
|
||||||
|
- @{{ .GitHubUser }} added {{ .Feature }} for ... (#{{ .PullRequestNumber }})
|
||||||
|
- @{{ .GitHubUser }} fixed {{ .Topic }} in the documentation so that ... (#{{ .PullRequestNumber }})
|
||||||
|
- @{{ .GitHubUser }} added {{ .Topic }} to the documentation (#{{ .PullRequestNumber }})
|
||||||
|
- @{{ .GitHubUser }} improved the documentation about {{ .Topic }} to also cover ... (#{{ .PullRequestNumber }})
|
||||||
|
```
|
||||||
25
.github/lock.yml
vendored
Normal file
25
.github/lock.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Configuration for Lock Threads
|
||||||
|
# Repo: https://github.com/dessant/lock-threads-app
|
||||||
|
# App: https://github.com/apps/lock
|
||||||
|
|
||||||
|
# Number of days of inactivity before a closed issue or pull request is locked
|
||||||
|
daysUntilLock: 7
|
||||||
|
|
||||||
|
# Skip issues and pull requests created before a given timestamp. Timestamp must
|
||||||
|
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
|
||||||
|
skipCreatedBefore: false
|
||||||
|
|
||||||
|
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
|
||||||
|
exemptLabels: []
|
||||||
|
|
||||||
|
# Label to add before locking, such as `outdated`. Set to `false` to disable
|
||||||
|
lockLabel: false
|
||||||
|
|
||||||
|
# Comment to post before locking. Set to `false` to disable
|
||||||
|
lockComment: >
|
||||||
|
This thread has been automatically locked since there has not been
|
||||||
|
any recent activity after it was closed. Please open a new issue for
|
||||||
|
related bugs.
|
||||||
|
|
||||||
|
# Assign `resolved` as the reason for locking. Set to `false` to disable
|
||||||
|
setLockReason: true
|
||||||
66
.github/stale.yml
vendored
Normal file
66
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# Configuration for probot-stale - https://github.com/probot/stale
|
||||||
|
|
||||||
|
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||||
|
daysUntilStale: 30
|
||||||
|
|
||||||
|
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||||
|
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
|
||||||
|
daysUntilClose: 14
|
||||||
|
|
||||||
|
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
|
||||||
|
onlyLabels: []
|
||||||
|
|
||||||
|
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
||||||
|
exemptLabels:
|
||||||
|
- pinned
|
||||||
|
- security
|
||||||
|
- enhancement
|
||||||
|
- refactor
|
||||||
|
- documentation
|
||||||
|
- chore
|
||||||
|
- needs-investigation
|
||||||
|
- bug
|
||||||
|
|
||||||
|
# Set to true to ignore issues in a project (defaults to false)
|
||||||
|
exemptProjects: false
|
||||||
|
|
||||||
|
# Set to true to ignore issues in a milestone (defaults to false)
|
||||||
|
exemptMilestones: false
|
||||||
|
|
||||||
|
# Set to true to ignore issues with an assignee (defaults to false)
|
||||||
|
exemptAssignees: false
|
||||||
|
|
||||||
|
# Label to use when marking as stale
|
||||||
|
staleLabel: stale
|
||||||
|
|
||||||
|
# Comment to post when marking as stale. Set to `false` to disable
|
||||||
|
markComment: >
|
||||||
|
This issue has been automatically marked as stale because it has not had
|
||||||
|
recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
|
for your contributions.
|
||||||
|
|
||||||
|
# Comment to post when removing the stale label.
|
||||||
|
# unmarkComment: >
|
||||||
|
# Your comment here.
|
||||||
|
|
||||||
|
# Comment to post when closing a stale Issue or Pull Request.
|
||||||
|
# closeComment: >
|
||||||
|
# Your comment here.
|
||||||
|
|
||||||
|
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||||
|
limitPerRun: 30
|
||||||
|
|
||||||
|
# Limit to only `issues` or `pulls`
|
||||||
|
# only: issues
|
||||||
|
|
||||||
|
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
||||||
|
# pulls:
|
||||||
|
# daysUntilStale: 30
|
||||||
|
# markComment: >
|
||||||
|
# This pull request has been automatically marked as stale because it has not had
|
||||||
|
# recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
|
# for your contributions.
|
||||||
|
|
||||||
|
# issues:
|
||||||
|
# exemptLabels:
|
||||||
|
# - confirmed
|
||||||
71
.github/workflows/build-and-release-runners.yml
vendored
71
.github/workflows/build-and-release-runners.yml
vendored
@@ -13,25 +13,31 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- runner/patched/*
|
- runner/patched/*
|
||||||
- runner/Dockerfile
|
- runner/Dockerfile
|
||||||
- runner/dindrunner.Dockerfile
|
- runner/Dockerfile.ubuntu.1804
|
||||||
|
- runner/Dockerfile.dindrunner
|
||||||
- runner/entrypoint.sh
|
- runner/entrypoint.sh
|
||||||
- .github/workflows/build-and-release-runners.yml
|
- .github/workflows/build-and-release-runners.yml
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Build ${{ matrix.name }}
|
name: Build ${{ matrix.name }}-ubuntu-${{ matrix.os-version }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- name: actions-runner
|
- name: actions-runner
|
||||||
|
os-version: 20.04
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
- name: actions-runner
|
||||||
|
os-version: 18.04
|
||||||
|
dockerfile: Dockerfile.ubuntu.1804
|
||||||
- name: actions-runner-dind
|
- name: actions-runner-dind
|
||||||
dockerfile: dindrunner.Dockerfile
|
os-version: 20.04
|
||||||
|
dockerfile: Dockerfile.dindrunner
|
||||||
env:
|
env:
|
||||||
RUNNER_VERSION: 2.277.1
|
RUNNER_VERSION: 2.278.0
|
||||||
DOCKER_VERSION: 19.03.12
|
DOCKER_VERSION: 19.03.12
|
||||||
DOCKERHUB_USERNAME: ${{ github.repository_owner }}
|
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USER }}
|
||||||
steps:
|
steps:
|
||||||
- name: Set outputs
|
- name: Set outputs
|
||||||
id: vars
|
id: vars
|
||||||
@@ -52,19 +58,66 @@ jobs:
|
|||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v1
|
||||||
if: ${{ github.event_name == 'push' || github.event_name == 'release' }}
|
if: ${{ github.event_name == 'push' || github.event_name == 'release' }}
|
||||||
with:
|
with:
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ secrets.DOCKER_USER }}
|
||||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
|
||||||
- name: Build and Push
|
- name: Build and Push Versioned Tags
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: ./runner
|
context: ./runner
|
||||||
file: ./runner/${{ matrix.dockerfile }}
|
file: ./runner/${{ matrix.dockerfile }}
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
|
build-args: |
|
||||||
|
RUNNER_VERSION=${{ env.RUNNER_VERSION }}
|
||||||
|
DOCKER_VERSION=${{ env.DOCKER_VERSION }}
|
||||||
|
tags: |
|
||||||
|
${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:v${{ env.RUNNER_VERSION }}-ubuntu-${{ matrix.os-version }}
|
||||||
|
${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:v${{ env.RUNNER_VERSION }}-ubuntu-${{ matrix.os-version }}-${{ steps.vars.outputs.sha_short }}
|
||||||
|
|
||||||
|
latest-tags:
|
||||||
|
if: ${{ github.event_name == 'push' || github.event_name == 'release' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Build ${{ matrix.name }}-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- name: actions-runner
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
- name: actions-runner-dind
|
||||||
|
dockerfile: Dockerfile.dindrunner
|
||||||
|
env:
|
||||||
|
RUNNER_VERSION: 2.277.1
|
||||||
|
DOCKER_VERSION: 19.03.12
|
||||||
|
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USER }}
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USER }}
|
||||||
|
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and Push Latest Tag
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: ./runner
|
||||||
|
file: ./runner/${{ matrix.dockerfile }}
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
build-args: |
|
build-args: |
|
||||||
RUNNER_VERSION=${{ env.RUNNER_VERSION }}
|
RUNNER_VERSION=${{ env.RUNNER_VERSION }}
|
||||||
DOCKER_VERSION=${{ env.DOCKER_VERSION }}
|
DOCKER_VERSION=${{ env.DOCKER_VERSION }}
|
||||||
tags: |
|
tags: |
|
||||||
${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:v${{ env.RUNNER_VERSION }}
|
|
||||||
${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:v${{ env.RUNNER_VERSION }}-${{ steps.vars.outputs.sha_short }}
|
|
||||||
${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:latest
|
${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:latest
|
||||||
|
|||||||
4
.github/workflows/on-push-lint-charts.yml
vendored
4
.github/workflows/on-push-lint-charts.yml
vendored
@@ -4,9 +4,11 @@ on:
|
|||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
- 'charts/**'
|
- 'charts/**'
|
||||||
|
- '!charts/actions-runner-controller/docs/**'
|
||||||
|
- '!charts/actions-runner-controller/*.md'
|
||||||
- '.github/**'
|
- '.github/**'
|
||||||
|
- '!.github/*.md'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
KUBE_SCORE_VERSION: 1.10.0
|
KUBE_SCORE_VERSION: 1.10.0
|
||||||
HELM_VERSION: v3.4.1
|
HELM_VERSION: v3.4.1
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ on:
|
|||||||
- main # assume that the branch name may change in future
|
- main # assume that the branch name may change in future
|
||||||
paths:
|
paths:
|
||||||
- 'charts/**'
|
- 'charts/**'
|
||||||
|
- '!charts/actions-runner-controller/docs/**'
|
||||||
- '.github/**'
|
- '.github/**'
|
||||||
|
- '!**.md'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
|||||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -7,7 +7,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Release
|
name: Release
|
||||||
env:
|
env:
|
||||||
DOCKERHUB_USERNAME: ${{ github.repository_owner }}
|
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USER }}
|
||||||
steps:
|
steps:
|
||||||
- name: Set outputs
|
- name: Set outputs
|
||||||
id: vars
|
id: vars
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ secrets.DOCKER_USER }}
|
||||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
|
||||||
- name: Build and Push
|
- name: Build and Push
|
||||||
|
|||||||
12
.github/workflows/test.yaml
vendored
12
.github/workflows/test.yaml
vendored
@@ -7,6 +7,8 @@ on:
|
|||||||
paths-ignore:
|
paths-ignore:
|
||||||
- 'runner/**'
|
- 'runner/**'
|
||||||
- .github/workflows/build-and-release-runners.yml
|
- .github/workflows/build-and-release-runners.yml
|
||||||
|
- '*.md'
|
||||||
|
- '.gitignore'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
@@ -15,11 +17,15 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: '^1.16.5'
|
||||||
|
- run: go version
|
||||||
- name: Install kubebuilder
|
- name: Install kubebuilder
|
||||||
run: |
|
run: |
|
||||||
curl -L -O https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.2.0/kubebuilder_2.2.0_linux_amd64.tar.gz
|
curl -L -O https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.3.2/kubebuilder_2.3.2_linux_amd64.tar.gz
|
||||||
tar zxvf kubebuilder_2.2.0_linux_amd64.tar.gz
|
tar zxvf kubebuilder_2.3.2_linux_amd64.tar.gz
|
||||||
sudo mv kubebuilder_2.2.0_linux_amd64 /usr/local/kubebuilder
|
sudo mv kubebuilder_2.3.2_linux_amd64 /usr/local/kubebuilder
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: make test
|
run: make test
|
||||||
- name: Verify manifests are up-to-date
|
- name: Verify manifests are up-to-date
|
||||||
|
|||||||
6
.github/workflows/wip.yml
vendored
6
.github/workflows/wip.yml
vendored
@@ -4,13 +4,15 @@ on:
|
|||||||
- master
|
- master
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- "runner/**"
|
- "runner/**"
|
||||||
|
- "**.md"
|
||||||
|
- ".gitignore"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: release-latest
|
name: release-latest
|
||||||
env:
|
env:
|
||||||
DOCKERHUB_USERNAME: ${{ github.repository_owner }}
|
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USER }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -27,7 +29,7 @@ jobs:
|
|||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ secrets.DOCKER_USER }}
|
||||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
|
||||||
# Considered unstable builds
|
# Considered unstable builds
|
||||||
|
|||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
# Deploy Assets
|
||||||
release
|
release
|
||||||
|
|
||||||
# Binaries for programs and plugins
|
# Binaries for programs and plugins
|
||||||
@@ -15,17 +16,21 @@ bin
|
|||||||
*.out
|
*.out
|
||||||
|
|
||||||
# Kubernetes Generated files - skip generated files, except for vendored files
|
# Kubernetes Generated files - skip generated files, except for vendored files
|
||||||
|
|
||||||
!vendor/**/zz_generated.*
|
!vendor/**/zz_generated.*
|
||||||
|
|
||||||
# editor and IDE paraphernalia
|
# editor and IDE paraphernalia
|
||||||
|
.vscode
|
||||||
.idea
|
.idea
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
*~
|
*~
|
||||||
|
|
||||||
.envrc
|
.envrc
|
||||||
|
.env
|
||||||
|
.test.env
|
||||||
*.pem
|
*.pem
|
||||||
|
|
||||||
# OS
|
# OS
|
||||||
.DS_STORE
|
.DS_STORE
|
||||||
|
|
||||||
|
/test-assets
|
||||||
|
|||||||
142
CONTRIBUTING.md
Normal file
142
CONTRIBUTING.md
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
## Contributing
|
||||||
|
|
||||||
|
### How to Contribute a Patch
|
||||||
|
|
||||||
|
Depending on what you are patching depends on how you should go about it. Below are some guides on how to test patches locally as well as develop the controller and runners.
|
||||||
|
|
||||||
|
When sumitting a PR for a change please provide evidence that your change works as we still need to work on improving the CI of the project. Some resources are provided for helping achieve this, see this guide for details.
|
||||||
|
|
||||||
|
#### Running an End to End Test
|
||||||
|
|
||||||
|
> **Notes for Ubuntu 20.04+ users**
|
||||||
|
>
|
||||||
|
> If you're using Ubuntu 20.04 or greater, you might have installed `docker` with `snap`.
|
||||||
|
>
|
||||||
|
> If you want to stick with `snap`-provided `docker`, do not forget to set `TMPDIR` to
|
||||||
|
> somewhere under `$HOME`.
|
||||||
|
> Otherwise `kind load docker-image` fail while running `docker save`.
|
||||||
|
> See https://kind.sigs.k8s.io/docs/user/known-issues/#docker-installed-with-snap for more information.
|
||||||
|
|
||||||
|
To test your local changes against both PAT and App based authentication please run the `acceptance` make target with the authentication configuration details provided:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# This sets `VERSION` envvar to some appropriate value
|
||||||
|
. hack/make-env.sh
|
||||||
|
|
||||||
|
DOCKER_USER=*** \
|
||||||
|
GITHUB_TOKEN=*** \
|
||||||
|
APP_ID=*** \
|
||||||
|
PRIVATE_KEY_FILE_PATH=path/to/pem/file \
|
||||||
|
INSTALLATION_ID=*** \
|
||||||
|
make acceptance
|
||||||
|
```
|
||||||
|
|
||||||
|
**Rerunning a failed test**
|
||||||
|
|
||||||
|
When one of tests run by `make acceptance` failed, you'd probably like to rerun only the failed one.
|
||||||
|
|
||||||
|
It can be done by `make acceptance/run` and by setting the combination of `ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm|kubectl` and `ACCEPTANCE_TEST_SECRET_TYPE=token|app` values that failed (note, you just need to set the corresponding authentication configuration in this circumstance)
|
||||||
|
|
||||||
|
In the example below, we rerun the test for the combination `ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm ACCEPTANCE_TEST_SECRET_TYPE=token` only:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
DOCKER_USER=*** \
|
||||||
|
GITHUB_TOKEN=*** \
|
||||||
|
ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm
|
||||||
|
ACCEPTANCE_TEST_SECRET_TYPE=token \
|
||||||
|
make acceptance/run
|
||||||
|
```
|
||||||
|
|
||||||
|
**Testing in a non-kind cluster**
|
||||||
|
|
||||||
|
If you prefer to test in a non-kind cluster, you can instead run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
KUBECONFIG=path/to/kubeconfig \
|
||||||
|
DOCKER_USER=*** \
|
||||||
|
GITHUB_TOKEN=*** \
|
||||||
|
APP_ID=*** \
|
||||||
|
PRIVATE_KEY_FILE_PATH=path/to/pem/file \
|
||||||
|
INSTALLATION_ID=*** \
|
||||||
|
ACCEPTANCE_TEST_SECRET_TYPE=token \
|
||||||
|
make docker-build acceptance/setup \
|
||||||
|
acceptance/deploy \
|
||||||
|
acceptance/tests
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Developing the Controller
|
||||||
|
|
||||||
|
Rerunning the whole acceptance test suite from scratch on every little change to the controller, the runner, and the chart would be counter-productive.
|
||||||
|
|
||||||
|
To make your development cycle faster, use the below command to update deploy and update all the three:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Let assume we have all other envvars like DOCKER_USER, GITHUB_TOKEN already set,
|
||||||
|
# The below command will (re)build `actions-runner-controller:controller1` and `actions-runner:runner1`,
|
||||||
|
# load those into kind nodes, and then rerun kubectl or helm to install/upgrade the controller,
|
||||||
|
# and finally upgrade the runner deployment to use the new runner image.
|
||||||
|
#
|
||||||
|
# As helm 3 and kubectl is unable to recreate a pod when no tag change,
|
||||||
|
# you either need to bump VERSION and RUNNER_TAG on each run,
|
||||||
|
# or manually run `kubectl delete pod $POD` on respective pods for changes to actually take effect.
|
||||||
|
|
||||||
|
VERSION=controller1 \
|
||||||
|
RUNNER_TAG=runner1 \
|
||||||
|
make acceptance/pull acceptance/kind docker-build acceptance/load acceptance/deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
If you've already deployed actions-runner-controller and only want to recreate pods to use the newer image, you can run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
NAME=$DOCKER_USER/actions-runner-controller \
|
||||||
|
make docker-build acceptance/load && \
|
||||||
|
kubectl -n actions-runner-system delete po $(kubectl -n actions-runner-system get po -ojsonpath={.items[*].metadata.name})
|
||||||
|
```
|
||||||
|
|
||||||
|
Similarly, if you'd like to recreate runner pods with the newer runner image,
|
||||||
|
|
||||||
|
```shell
|
||||||
|
NAME=$DOCKER_USER/actions-runner make \
|
||||||
|
-C runner docker-{build,push}-ubuntu && \
|
||||||
|
(kubectl get po -ojsonpath={.items[*].metadata.name} | xargs -n1 kubectl delete po)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Developing the Runners
|
||||||
|
|
||||||
|
**Tests**
|
||||||
|
|
||||||
|
A set of example pipelines (./acceptance/pipelines) are provided in this repository which you can use to validate your runners are working as expected. When raising a PR please run the relevant suites to prove your change hasn't broken anything.
|
||||||
|
|
||||||
|
**Running Ginkgo Tests**
|
||||||
|
|
||||||
|
You can run the integration test suite that is written in Ginkgo with:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
make test-with-deps
|
||||||
|
```
|
||||||
|
|
||||||
|
This will firstly install a few binaries required to setup the integration test environment and then runs `go test` to start the Ginkgo test.
|
||||||
|
|
||||||
|
If you don't want to use `make`, like when you're running tests from your IDE, install required binaries to `/usr/local/kubebuilder/bin`. That's the directory in which controller-runtime's `envtest` framework locates the binaries.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sudo mkdir -p /usr/local/kubebuilder/bin
|
||||||
|
make kube-apiserver etcd
|
||||||
|
sudo mv test-assets/{etcd,kube-apiserver} /usr/local/kubebuilder/bin/
|
||||||
|
go test -v -run TestAPIs github.com/actions-runner-controller/actions-runner-controller/controllers
|
||||||
|
```
|
||||||
|
|
||||||
|
To run Ginkgo tests selectively, set the pattern of target test names to `GINKGO_FOCUS`.
|
||||||
|
All the Ginkgo test that matches `GINKGO_FOCUS` will be run.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
GINKGO_FOCUS='[It] should create a new Runner resource from the specified template, add a another Runner on replicas increased, and removes all the replicas when set to 0' \
|
||||||
|
go test -v -run TestAPIs github.com/actions-runner-controller/actions-runner-controller/controllers
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Helm Version Bumps
|
||||||
|
|
||||||
|
**Chart Version :** When bumping the chart version follow semantic versioning https://semver.org/<br />
|
||||||
|
**App Version :** When bumping the app version you will also need to bump the chart version too. Again, follow semantic versioning when bumping the chart.
|
||||||
|
|
||||||
|
To determine if you need to bump the MAJOR, MINOR or PATCH versions you will need to review the changes between the previous app version and the new app version and / or ask for a maintainer to advise.
|
||||||
189
Makefile
189
Makefile
@@ -1,11 +1,30 @@
|
|||||||
|
ifdef DOCKER_USER
|
||||||
|
NAME ?= ${DOCKER_USER}/actions-runner-controller
|
||||||
|
else
|
||||||
NAME ?= summerwind/actions-runner-controller
|
NAME ?= summerwind/actions-runner-controller
|
||||||
|
endif
|
||||||
|
DOCKER_USER ?= $(shell echo ${NAME} | cut -d / -f1)
|
||||||
VERSION ?= latest
|
VERSION ?= latest
|
||||||
|
RUNNER_NAME ?= ${DOCKER_USER}/actions-runner
|
||||||
|
RUNNER_TAG ?= ${VERSION}
|
||||||
|
TEST_REPO ?= ${DOCKER_USER}/actions-runner-controller
|
||||||
|
TEST_ORG ?=
|
||||||
|
TEST_ORG_REPO ?=
|
||||||
|
SYNC_PERIOD ?= 5m
|
||||||
|
USE_RUNNERSET ?=
|
||||||
|
KUBECONTEXT ?= kind-acceptance
|
||||||
|
CLUSTER ?= acceptance
|
||||||
|
CERT_MANAGER_VERSION ?= v1.1.1
|
||||||
|
|
||||||
# From https://github.com/VictoriaMetrics/operator/pull/44
|
# From https://github.com/VictoriaMetrics/operator/pull/44
|
||||||
YAML_DROP=$(YQ) delete --inplace
|
YAML_DROP=$(YQ) delete --inplace
|
||||||
YAML_DROP_PREFIX=spec.validation.openAPIV3Schema.properties.spec.properties
|
|
||||||
|
# If you encounter errors like the below, you are very likely to update this to follow e.g. CRD version change:
|
||||||
|
# CustomResourceDefinition.apiextensions.k8s.io "runners.actions.summerwind.dev" is invalid: spec.preserveUnknownFields: Invalid value: true: must be false in order to use defaults in the schema
|
||||||
|
YAML_DROP_PREFIX=spec.versions[0].schema.openAPIV3Schema.properties.spec.properties
|
||||||
|
|
||||||
# Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
|
# Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
|
||||||
CRD_OPTIONS ?= "crd:trivialVersions=true"
|
CRD_OPTIONS ?= "crd:trivialVersions=true,generateEmbeddedObjectMeta=true"
|
||||||
|
|
||||||
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
|
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
|
||||||
ifeq (,$(shell go env GOBIN))
|
ifeq (,$(shell go env GOBIN))
|
||||||
@@ -14,6 +33,8 @@ else
|
|||||||
GOBIN=$(shell go env GOBIN)
|
GOBIN=$(shell go env GOBIN)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
TEST_ASSETS=$(PWD)/test-assets
|
||||||
|
|
||||||
# default list of platforms for which multiarch image is built
|
# default list of platforms for which multiarch image is built
|
||||||
ifeq (${PLATFORMS}, )
|
ifeq (${PLATFORMS}, )
|
||||||
export PLATFORMS="linux/amd64,linux/arm64"
|
export PLATFORMS="linux/amd64,linux/arm64"
|
||||||
@@ -33,9 +54,18 @@ endif
|
|||||||
|
|
||||||
all: manager
|
all: manager
|
||||||
|
|
||||||
|
GO_TEST_ARGS ?= -short
|
||||||
|
|
||||||
# Run tests
|
# Run tests
|
||||||
test: generate fmt vet manifests
|
test: generate fmt vet manifests
|
||||||
go test ./... -coverprofile cover.out
|
go test $(GO_TEST_ARGS) ./... -coverprofile cover.out
|
||||||
|
|
||||||
|
test-with-deps: kube-apiserver etcd kubectl
|
||||||
|
# See https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest#pkg-constants
|
||||||
|
TEST_ASSET_KUBE_APISERVER=$(KUBE_APISERVER_BIN) \
|
||||||
|
TEST_ASSET_ETCD=$(ETCD_BIN) \
|
||||||
|
TEST_ASSET_KUBECTL=$(KUBECTL_BIN) \
|
||||||
|
make test
|
||||||
|
|
||||||
# Build manager binary
|
# Build manager binary
|
||||||
manager: generate fmt vet
|
manager: generate fmt vet
|
||||||
@@ -96,12 +126,9 @@ generate: controller-gen
|
|||||||
$(CONTROLLER_GEN) object:headerFile=./hack/boilerplate.go.txt paths="./..."
|
$(CONTROLLER_GEN) object:headerFile=./hack/boilerplate.go.txt paths="./..."
|
||||||
|
|
||||||
# Build the docker image
|
# Build the docker image
|
||||||
docker-build: test
|
docker-build:
|
||||||
docker build . -t ${NAME}:${VERSION}
|
docker build . -t ${NAME}:${VERSION}
|
||||||
|
docker build runner -t ${RUNNER_NAME}:${RUNNER_TAG} --build-arg TARGETPLATFORM=$(shell arch)
|
||||||
# Push the docker image
|
|
||||||
docker-push:
|
|
||||||
docker push ${NAME}:${VERSION}
|
|
||||||
|
|
||||||
docker-buildx:
|
docker-buildx:
|
||||||
export DOCKER_CLI_EXPERIMENTAL=enabled
|
export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
@@ -115,6 +142,11 @@ docker-buildx:
|
|||||||
-f Dockerfile \
|
-f Dockerfile \
|
||||||
. ${PUSH_ARG}
|
. ${PUSH_ARG}
|
||||||
|
|
||||||
|
# Push the docker image
|
||||||
|
docker-push:
|
||||||
|
docker push ${NAME}:${VERSION}
|
||||||
|
docker push ${RUNNER_NAME}:${RUNNER_TAG}
|
||||||
|
|
||||||
# Generate the release manifest file
|
# Generate the release manifest file
|
||||||
release: manifests
|
release: manifests
|
||||||
cd config/manager && kustomize edit set image controller=${NAME}:${VERSION}
|
cd config/manager && kustomize edit set image controller=${NAME}:${VERSION}
|
||||||
@@ -126,19 +158,41 @@ release/clean:
|
|||||||
rm -rf release
|
rm -rf release
|
||||||
|
|
||||||
.PHONY: acceptance
|
.PHONY: acceptance
|
||||||
acceptance: release/clean docker-build docker-push release
|
acceptance: release/clean acceptance/pull docker-build release
|
||||||
ACCEPTANCE_TEST_SECRET_TYPE=token make acceptance/kind acceptance/setup acceptance/tests acceptance/teardown
|
ACCEPTANCE_TEST_SECRET_TYPE=token make acceptance/run
|
||||||
ACCEPTANCE_TEST_SECRET_TYPE=app make acceptance/kind acceptance/setup acceptance/tests acceptance/teardown
|
ACCEPTANCE_TEST_SECRET_TYPE=app make acceptance/run
|
||||||
ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm ACCEPTANCE_TEST_SECRET_TYPE=token make acceptance/kind acceptance/setup acceptance/tests acceptance/teardown
|
ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm ACCEPTANCE_TEST_SECRET_TYPE=token make acceptance/run
|
||||||
ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm ACCEPTANCE_TEST_SECRET_TYPE=app make acceptance/kind acceptance/setup acceptance/tests acceptance/teardown
|
ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm ACCEPTANCE_TEST_SECRET_TYPE=app make acceptance/run
|
||||||
|
|
||||||
|
acceptance/run: acceptance/kind acceptance/load acceptance/setup acceptance/deploy acceptance/tests acceptance/teardown
|
||||||
|
|
||||||
acceptance/kind:
|
acceptance/kind:
|
||||||
kind create cluster --name acceptance
|
kind create cluster --name ${CLUSTER} --config acceptance/kind.yaml
|
||||||
kubectl cluster-info --context kind-acceptance
|
|
||||||
|
# Set TMPDIR to somewhere under $HOME when you use docker installed with Ubuntu snap
|
||||||
|
# Otherwise `load docker-image` fail while running `docker save`.
|
||||||
|
# See https://kind.sigs.k8s.io/docs/user/known-issues/#docker-installed-with-snap
|
||||||
|
acceptance/load:
|
||||||
|
kind load docker-image ${NAME}:${VERSION} --name ${CLUSTER}
|
||||||
|
kind load docker-image quay.io/brancz/kube-rbac-proxy:v0.10.0 --name ${CLUSTER}
|
||||||
|
kind load docker-image ${RUNNER_NAME}:${RUNNER_TAG} --name ${CLUSTER}
|
||||||
|
kind load docker-image docker:dind --name ${CLUSTER}
|
||||||
|
kind load docker-image quay.io/jetstack/cert-manager-controller:$(CERT_MANAGER_VERSION) --name ${CLUSTER}
|
||||||
|
kind load docker-image quay.io/jetstack/cert-manager-cainjector:$(CERT_MANAGER_VERSION) --name ${CLUSTER}
|
||||||
|
kind load docker-image quay.io/jetstack/cert-manager-webhook:$(CERT_MANAGER_VERSION) --name ${CLUSTER}
|
||||||
|
kubectl cluster-info --context ${KUBECONTEXT}
|
||||||
|
|
||||||
|
# Pull the docker images for acceptance
|
||||||
|
acceptance/pull:
|
||||||
|
docker pull quay.io/brancz/kube-rbac-proxy:v0.10.0
|
||||||
|
docker pull docker:dind
|
||||||
|
docker pull quay.io/jetstack/cert-manager-controller:$(CERT_MANAGER_VERSION)
|
||||||
|
docker pull quay.io/jetstack/cert-manager-cainjector:$(CERT_MANAGER_VERSION)
|
||||||
|
docker pull quay.io/jetstack/cert-manager-webhook:$(CERT_MANAGER_VERSION)
|
||||||
|
|
||||||
acceptance/setup:
|
acceptance/setup:
|
||||||
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.0.4/cert-manager.yaml #kubectl create namespace actions-runner-system
|
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/$(CERT_MANAGER_VERSION)/cert-manager.yaml #kubectl create namespace actions-runner-system
|
||||||
kubectl -n cert-manager wait deploy/cert-manager-cainjector --for condition=available --timeout 60s
|
kubectl -n cert-manager wait deploy/cert-manager-cainjector --for condition=available --timeout 90s
|
||||||
kubectl -n cert-manager wait deploy/cert-manager-webhook --for condition=available --timeout 60s
|
kubectl -n cert-manager wait deploy/cert-manager-webhook --for condition=available --timeout 60s
|
||||||
kubectl -n cert-manager wait deploy/cert-manager --for condition=available --timeout 60s
|
kubectl -n cert-manager wait deploy/cert-manager --for condition=available --timeout 60s
|
||||||
kubectl create namespace actions-runner-system || true
|
kubectl create namespace actions-runner-system || true
|
||||||
@@ -146,18 +200,35 @@ acceptance/setup:
|
|||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
acceptance/teardown:
|
acceptance/teardown:
|
||||||
kind delete cluster --name acceptance
|
kind delete cluster --name ${CLUSTER}
|
||||||
|
|
||||||
|
acceptance/deploy:
|
||||||
|
NAME=${NAME} DOCKER_USER=${DOCKER_USER} VERSION=${VERSION} RUNNER_NAME=${RUNNER_NAME} RUNNER_TAG=${RUNNER_TAG} TEST_REPO=${TEST_REPO} \
|
||||||
|
TEST_ORG=${TEST_ORG} TEST_ORG_REPO=${TEST_ORG_REPO} SYNC_PERIOD=${SYNC_PERIOD} \
|
||||||
|
USE_RUNNERSET=${USE_RUNNERSET} \
|
||||||
|
acceptance/deploy.sh
|
||||||
|
|
||||||
acceptance/tests:
|
acceptance/tests:
|
||||||
acceptance/deploy.sh
|
|
||||||
acceptance/checks.sh
|
acceptance/checks.sh
|
||||||
|
|
||||||
|
# We use -count=1 instead of `go clean -testcache`
|
||||||
|
# See https://terratest.gruntwork.io/docs/testing-best-practices/avoid-test-caching/
|
||||||
|
.PHONY: e2e
|
||||||
|
e2e:
|
||||||
|
go test -count=1 -v -timeout 600s -run '^TestE2E$$' ./test/e2e
|
||||||
|
|
||||||
# Upload release file to GitHub.
|
# Upload release file to GitHub.
|
||||||
github-release: release
|
github-release: release
|
||||||
ghr ${VERSION} release/
|
ghr ${VERSION} release/
|
||||||
|
|
||||||
# find or download controller-gen
|
# Find or download controller-gen
|
||||||
# download controller-gen if necessary
|
#
|
||||||
|
# Note that controller-gen newer than 0.4.1 is needed for https://github.com/kubernetes-sigs/controller-tools/issues/444#issuecomment-680168439
|
||||||
|
# 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]
|
||||||
|
#
|
||||||
|
# Note that controller-gen newer than 0.6.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.
|
||||||
controller-gen:
|
controller-gen:
|
||||||
ifeq (, $(shell which controller-gen))
|
ifeq (, $(shell which controller-gen))
|
||||||
ifeq (, $(wildcard $(GOBIN)/controller-gen))
|
ifeq (, $(wildcard $(GOBIN)/controller-gen))
|
||||||
@@ -166,7 +237,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 get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.3.0 ;\
|
go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.6.0 ;\
|
||||||
rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
|
rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
|
||||||
}
|
}
|
||||||
endif
|
endif
|
||||||
@@ -191,3 +262,77 @@ ifeq (, $(wildcard $(GOBIN)/yq))
|
|||||||
}
|
}
|
||||||
endif
|
endif
|
||||||
YQ=$(GOBIN)/yq
|
YQ=$(GOBIN)/yq
|
||||||
|
|
||||||
|
OS_NAME := $(shell uname -s | tr A-Z a-z)
|
||||||
|
|
||||||
|
# find or download etcd
|
||||||
|
etcd:
|
||||||
|
ifeq (, $(shell which etcd))
|
||||||
|
ifeq (, $(wildcard $(TEST_ASSETS)/etcd))
|
||||||
|
@{ \
|
||||||
|
set -xe ;\
|
||||||
|
INSTALL_TMP_DIR=$$(mktemp -d) ;\
|
||||||
|
cd $$INSTALL_TMP_DIR ;\
|
||||||
|
wget https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.3.2/kubebuilder_2.3.2_$(OS_NAME)_amd64.tar.gz ;\
|
||||||
|
mkdir -p $(TEST_ASSETS) ;\
|
||||||
|
tar zxvf kubebuilder_2.3.2_$(OS_NAME)_amd64.tar.gz ;\
|
||||||
|
mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/etcd $(TEST_ASSETS)/etcd ;\
|
||||||
|
mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/kube-apiserver $(TEST_ASSETS)/kube-apiserver ;\
|
||||||
|
mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/kubectl $(TEST_ASSETS)/kubectl ;\
|
||||||
|
rm -rf $$INSTALL_TMP_DIR ;\
|
||||||
|
}
|
||||||
|
ETCD_BIN=$(TEST_ASSETS)/etcd
|
||||||
|
else
|
||||||
|
ETCD_BIN=$(TEST_ASSETS)/etcd
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
ETCD_BIN=$(shell which etcd)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# find or download kube-apiserver
|
||||||
|
kube-apiserver:
|
||||||
|
ifeq (, $(shell which kube-apiserver))
|
||||||
|
ifeq (, $(wildcard $(TEST_ASSETS)/kube-apiserver))
|
||||||
|
@{ \
|
||||||
|
set -xe ;\
|
||||||
|
INSTALL_TMP_DIR=$$(mktemp -d) ;\
|
||||||
|
cd $$INSTALL_TMP_DIR ;\
|
||||||
|
wget https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.3.2/kubebuilder_2.3.2_$(OS_NAME)_amd64.tar.gz ;\
|
||||||
|
mkdir -p $(TEST_ASSETS) ;\
|
||||||
|
tar zxvf kubebuilder_2.3.2_$(OS_NAME)_amd64.tar.gz ;\
|
||||||
|
mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/etcd $(TEST_ASSETS)/etcd ;\
|
||||||
|
mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/kube-apiserver $(TEST_ASSETS)/kube-apiserver ;\
|
||||||
|
mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/kubectl $(TEST_ASSETS)/kubectl ;\
|
||||||
|
rm -rf $$INSTALL_TMP_DIR ;\
|
||||||
|
}
|
||||||
|
KUBE_APISERVER_BIN=$(TEST_ASSETS)/kube-apiserver
|
||||||
|
else
|
||||||
|
KUBE_APISERVER_BIN=$(TEST_ASSETS)/kube-apiserver
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
KUBE_APISERVER_BIN=$(shell which kube-apiserver)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# find or download kubectl
|
||||||
|
kubectl:
|
||||||
|
ifeq (, $(shell which kubectl))
|
||||||
|
ifeq (, $(wildcard $(TEST_ASSETS)/kubectl))
|
||||||
|
@{ \
|
||||||
|
set -xe ;\
|
||||||
|
INSTALL_TMP_DIR=$$(mktemp -d) ;\
|
||||||
|
cd $$INSTALL_TMP_DIR ;\
|
||||||
|
wget https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.3.2/kubebuilder_2.3.2_$(OS_NAME)_amd64.tar.gz ;\
|
||||||
|
mkdir -p $(TEST_ASSETS) ;\
|
||||||
|
tar zxvf kubebuilder_2.3.2_$(OS_NAME)_amd64.tar.gz ;\
|
||||||
|
mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/etcd $(TEST_ASSETS)/etcd ;\
|
||||||
|
mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/kube-apiserver $(TEST_ASSETS)/kube-apiserver ;\
|
||||||
|
mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/kubectl $(TEST_ASSETS)/kubectl ;\
|
||||||
|
rm -rf $$INSTALL_TMP_DIR ;\
|
||||||
|
}
|
||||||
|
KUBECTL_BIN=$(TEST_ASSETS)/kubectl
|
||||||
|
else
|
||||||
|
KUBECTL_BIN=$(TEST_ASSETS)/kubectl
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
KUBECTL_BIN=$(shell which kubectl)
|
||||||
|
endif
|
||||||
|
|||||||
2
PROJECT
2
PROJECT
@@ -1,5 +1,5 @@
|
|||||||
domain: summerwind.dev
|
domain: summerwind.dev
|
||||||
repo: github.com/summerwind/actions-runner-controller
|
repo: github.com/actions-runner-controller/actions-runner-controller
|
||||||
resources:
|
resources:
|
||||||
- group: actions
|
- group: actions
|
||||||
kind: Runner
|
kind: Runner
|
||||||
|
|||||||
@@ -1,29 +1,84 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -e
|
set +e
|
||||||
|
|
||||||
|
repo_runnerdeployment_passed="skipped"
|
||||||
|
repo_runnerset_passed="skipped"
|
||||||
|
|
||||||
|
echo "Checking if RunnerDeployment repo test is set"
|
||||||
|
if [ "${TEST_REPO}" ] && [ ! "${USE_RUNNERSET}" ]; then
|
||||||
runner_name=
|
runner_name=
|
||||||
|
count=0
|
||||||
while [ -z "${runner_name}" ]; do
|
while [ $count -le 30 ]; do
|
||||||
echo Finding the runner... 1>&2
|
echo "Finding Runner ..."
|
||||||
sleep 1
|
|
||||||
runner_name=$(kubectl get runner --output=jsonpath="{.items[*].metadata.name}")
|
runner_name=$(kubectl get runner --output=jsonpath="{.items[*].metadata.name}")
|
||||||
done
|
if [ "${runner_name}" ]; then
|
||||||
|
while [ $count -le 30 ]; do
|
||||||
echo Found runner ${runner_name}.
|
runner_pod_name=
|
||||||
|
echo "Found Runner \""${runner_name}"\""
|
||||||
pod_name=
|
echo "Finding underlying pod ..."
|
||||||
|
runner_pod_name=$(kubectl get pod --output=jsonpath="{.items[*].metadata.name}" | grep ${runner_name})
|
||||||
while [ -z "${pod_name}" ]; do
|
if [ "${runner_pod_name}" ]; then
|
||||||
echo Finding the runner pod... 1>&2
|
echo "Found underlying pod \""${runner_pod_name}"\""
|
||||||
|
echo "Waiting for pod \""${runner_pod_name}"\" to become ready..."
|
||||||
|
kubectl wait pod/${runner_pod_name} --for condition=ready --timeout 270s
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
sleep 1
|
sleep 1
|
||||||
pod_name=$(kubectl get pod --output=jsonpath="{.items[*].metadata.name}" | grep ${runner_name})
|
let "count=count+1"
|
||||||
done
|
done
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
let "count=count+1"
|
||||||
|
done
|
||||||
|
if [ $count -ge 30 ]; then
|
||||||
|
repo_runnerdeployment_passed=false
|
||||||
|
else
|
||||||
|
repo_runnerdeployment_passed=true
|
||||||
|
fi
|
||||||
|
echo "Checking if RunnerSet repo test is set"
|
||||||
|
elif [ "${TEST_REPO}" ] && [ "${USE_RUNNERSET}" ]; then
|
||||||
|
runnerset_name=
|
||||||
|
count=0
|
||||||
|
while [ $count -le 30 ]; do
|
||||||
|
echo "Finding RunnerSet ..."
|
||||||
|
runnerset_name=$(kubectl get runnerset --output=jsonpath="{.items[*].metadata.name}")
|
||||||
|
if [ "${runnerset_name}" ]; then
|
||||||
|
while [ $count -le 30 ]; do
|
||||||
|
runnerset_pod_name=
|
||||||
|
echo "Found RunnerSet \""${runnerset_name}"\""
|
||||||
|
echo "Finding underlying pod ..."
|
||||||
|
runnerset_pod_name=$(kubectl get pod --output=jsonpath="{.items[*].metadata.name}" | grep ${runnerset_name})
|
||||||
|
echo "BEFORE IF"
|
||||||
|
if [ "${runnerset_pod_name}" ]; then
|
||||||
|
echo "AFTER IF"
|
||||||
|
echo "Found underlying pod \""${runnerset_pod_name}"\""
|
||||||
|
echo "Waiting for pod \""${runnerset_pod_name}"\" to become ready..."
|
||||||
|
kubectl wait pod/${runnerset_pod_name} --for condition=ready --timeout 270s
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
let "count=count+1"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
let "count=count+1"
|
||||||
|
done
|
||||||
|
if [ $count -ge 30 ]; then
|
||||||
|
repo_runnerset_passed=false
|
||||||
|
else
|
||||||
|
repo_runnerset_passed=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo Found pod ${pod_name}.
|
if [ ${repo_runnerset_passed} == true ] || [ ${repo_runnerset_passed} == "skipped" ] && \
|
||||||
|
[ ${repo_runnerdeployment_passed} == true ] || [ ${repo_runnerdeployment_passed} == "skipped" ]; then
|
||||||
echo Waiting for pod ${runner_name} to become ready... 1>&2
|
echo "INFO : All tests passed or skipped"
|
||||||
|
echo "RunnerSet Repo Test Status : ${repo_runnerset_passed}"
|
||||||
kubectl wait pod/${runner_name} --for condition=ready --timeout 180s
|
echo "RunnerDeployment Repo Test Status : ${repo_runnerdeployment_passed}"
|
||||||
|
else
|
||||||
echo All tests passed. 1>&2
|
echo "ERROR : Some tests failed"
|
||||||
|
echo "RunnerSet Repo Test Status : ${repo_runnerset_passed}"
|
||||||
|
echo "RunnerDeployment Repo Test Status : ${repo_runnerdeployment_passed}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -4,10 +4,14 @@ set -e
|
|||||||
|
|
||||||
tpe=${ACCEPTANCE_TEST_SECRET_TYPE}
|
tpe=${ACCEPTANCE_TEST_SECRET_TYPE}
|
||||||
|
|
||||||
|
VALUES_FILE=${VALUES_FILE:-$(dirname $0)/values.yaml}
|
||||||
|
|
||||||
if [ "${tpe}" == "token" ]; then
|
if [ "${tpe}" == "token" ]; then
|
||||||
|
if ! kubectl get secret controller-manager -n actions-runner-system >/dev/null; then
|
||||||
kubectl create secret generic controller-manager \
|
kubectl create secret generic controller-manager \
|
||||||
-n actions-runner-system \
|
-n actions-runner-system \
|
||||||
--from-literal=github_token=${GITHUB_TOKEN:?GITHUB_TOKEN must not be empty}
|
--from-literal=github_token=${GITHUB_TOKEN:?GITHUB_TOKEN must not be empty}
|
||||||
|
fi
|
||||||
elif [ "${tpe}" == "app" ]; then
|
elif [ "${tpe}" == "app" ]; then
|
||||||
kubectl create secret generic controller-manager \
|
kubectl create secret generic controller-manager \
|
||||||
-n actions-runner-system \
|
-n actions-runner-system \
|
||||||
@@ -26,17 +30,46 @@ if [ "${tool}" == "helm" ]; then
|
|||||||
charts/actions-runner-controller \
|
charts/actions-runner-controller \
|
||||||
-n actions-runner-system \
|
-n actions-runner-system \
|
||||||
--create-namespace \
|
--create-namespace \
|
||||||
--set syncPeriod=5m
|
--set syncPeriod=${SYNC_PERIOD} \
|
||||||
kubectl -n actions-runner-system wait deploy/actions-runner-controller --for condition=available
|
--set authSecret.create=false \
|
||||||
|
--set image.repository=${NAME} \
|
||||||
|
--set image.tag=${VERSION} \
|
||||||
|
-f ${VALUES_FILE}
|
||||||
|
kubectl apply -f charts/actions-runner-controller/crds
|
||||||
|
kubectl -n actions-runner-system wait deploy/actions-runner-controller --for condition=available --timeout 60s
|
||||||
else
|
else
|
||||||
kubectl apply \
|
kubectl apply \
|
||||||
-n actions-runner-system \
|
-n actions-runner-system \
|
||||||
-f release/actions-runner-controller.yaml
|
-f release/actions-runner-controller.yaml
|
||||||
kubectl -n actions-runner-system wait deploy/controller-manager --for condition=available --timeout 60s
|
kubectl -n actions-runner-system wait deploy/controller-manager --for condition=available --timeout 120s
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Adhocly wait for some time until actions-runner-controller's admission webhook gets ready
|
# Adhocly wait for some time until actions-runner-controller's admission webhook gets ready
|
||||||
sleep 20
|
sleep 20
|
||||||
|
|
||||||
kubectl apply \
|
RUNNER_LABEL=${RUNNER_LABEL:-self-hosted}
|
||||||
-f acceptance/testdata/runnerdeploy.yaml
|
|
||||||
|
if [ -n "${TEST_REPO}" ]; then
|
||||||
|
if [ -n "USE_RUNNERSET" ]; then
|
||||||
|
cat acceptance/testdata/repo.runnerset.yaml | envsubst | kubectl apply -f -
|
||||||
|
cat acceptance/testdata/repo.runnerset.hra.yaml | envsubst | kubectl apply -f -
|
||||||
|
else
|
||||||
|
echo 'Deploying runnerdeployment and hra. Set USE_RUNNERSET if you want to deploy runnerset instead.'
|
||||||
|
cat acceptance/testdata/repo.runnerdeploy.yaml | envsubst | kubectl apply -f -
|
||||||
|
cat acceptance/testdata/repo.hra.yaml | envsubst | kubectl apply -f -
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo 'Skipped deploying runnerdeployment and hra. Set TEST_REPO to "yourorg/yourrepo" to deploy.'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${TEST_ORG}" ]; then
|
||||||
|
cat acceptance/testdata/org.runnerdeploy.yaml | envsubst | kubectl apply -f -
|
||||||
|
|
||||||
|
if [ -n "${TEST_ORG_REPO}" ]; then
|
||||||
|
cat acceptance/testdata/org.hra.yaml | envsubst | kubectl apply -f -
|
||||||
|
else
|
||||||
|
echo 'Skipped deploying organizational hra. Set TEST_ORG_REPO to "yourorg/yourrepo" to deploy.'
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo 'Skipped deploying organizational runnerdeployment. Set TEST_ORG to deploy.'
|
||||||
|
fi
|
||||||
|
|||||||
10
acceptance/kind.yaml
Normal file
10
acceptance/kind.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
apiVersion: kind.x-k8s.io/v1alpha4
|
||||||
|
kind: Cluster
|
||||||
|
nodes:
|
||||||
|
- role: control-plane
|
||||||
|
extraPortMappings:
|
||||||
|
- containerPort: 31000
|
||||||
|
hostPort: 31000
|
||||||
|
listenAddress: "0.0.0.0"
|
||||||
|
protocol: tcp
|
||||||
|
#- role: worker
|
||||||
36
acceptance/pipelines/eks-integration-tests.yaml
Normal file
36
acceptance/pipelines/eks-integration-tests.yaml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
name: EKS Integration Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
IRSA_ROLE_ARN:
|
||||||
|
ASSUME_ROLE_ARN:
|
||||||
|
AWS_REGION:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
assume-role-in-runner-test:
|
||||||
|
runs-on: ['self-hosted', 'Linux']
|
||||||
|
steps:
|
||||||
|
- name: Test aws-actions/configure-aws-credentials Action
|
||||||
|
uses: aws-actions/configure-aws-credentials@v1
|
||||||
|
with:
|
||||||
|
aws-region: ${{ env.AWS_REGION }}
|
||||||
|
role-to-assume: ${{ env.ASSUME_ROLE_ARN }}
|
||||||
|
role-duration-seconds: 900
|
||||||
|
assume-role-in-container-test:
|
||||||
|
runs-on: ['self-hosted', 'Linux']
|
||||||
|
container:
|
||||||
|
image: amazon/aws-cli
|
||||||
|
env:
|
||||||
|
AWS_WEB_IDENTITY_TOKEN_FILE: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
|
||||||
|
AWS_ROLE_ARN: ${{ env.IRSA_ROLE_ARN }}
|
||||||
|
volumes:
|
||||||
|
- /var/run/secrets/eks.amazonaws.com/serviceaccount/token:/var/run/secrets/eks.amazonaws.com/serviceaccount/token
|
||||||
|
steps:
|
||||||
|
- name: Test aws-actions/configure-aws-credentials Action in container
|
||||||
|
uses: aws-actions/configure-aws-credentials@v1
|
||||||
|
with:
|
||||||
|
aws-region: ${{ env.AWS_REGION }}
|
||||||
|
role-to-assume: ${{ env.ASSUME_ROLE_ARN }}
|
||||||
|
role-duration-seconds: 900
|
||||||
83
acceptance/pipelines/runner-integration-tests.yaml
Normal file
83
acceptance/pipelines/runner-integration-tests.yaml
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
name: Runner Integration Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
ImageOS: ubuntu18 # Used by ruby/setup-ruby action | Update me for the runner OS version you are testing against
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run-step-in-container-test:
|
||||||
|
runs-on: ['self-hosted', 'Linux']
|
||||||
|
container:
|
||||||
|
image: alpine
|
||||||
|
steps:
|
||||||
|
- name: Test we are working in the container
|
||||||
|
run: |
|
||||||
|
if [[ $(sed -n '2p' < /etc/os-release | cut -d "=" -f2) != "alpine" ]]; then
|
||||||
|
echo "::error ::Failed OS detection test, could not match /etc/os-release with alpine. Are we really running in the container?"
|
||||||
|
echo "/etc/os-release below:"
|
||||||
|
cat /etc/os-release
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
setup-python-test:
|
||||||
|
runs-on: ['self-hosted', 'Linux']
|
||||||
|
steps:
|
||||||
|
- name: Print native Python environment
|
||||||
|
run: |
|
||||||
|
which python
|
||||||
|
python --version
|
||||||
|
- uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.9
|
||||||
|
- name: Test actions/setup-python works
|
||||||
|
run: |
|
||||||
|
VERSION=$(python --version 2>&1 | cut -d ' ' -f2 | cut -d '.' -f1-2)
|
||||||
|
if [[ $VERSION != '3.9' ]]; then
|
||||||
|
echo "Python version detected : $(python --version 2>&1)"
|
||||||
|
echo "::error ::Detected python failed setup version test, could not match version with version specified in the setup action"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Python version detected : $(python --version 2>&1)"
|
||||||
|
fi
|
||||||
|
setup-node-test:
|
||||||
|
runs-on: ['self-hosted', 'Linux']
|
||||||
|
steps:
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: '12'
|
||||||
|
- name: Test actions/setup-node works
|
||||||
|
run: |
|
||||||
|
VERSION=$(node --version | cut -c 2- | cut -d '.' -f1)
|
||||||
|
if [[ $VERSION != '12' ]]; then
|
||||||
|
echo "Node version detected : $(node --version 2>&1)"
|
||||||
|
echo "::error ::Detected node failed setup version test, could not match version with version specified in the setup action"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Node version detected : $(node --version 2>&1)"
|
||||||
|
fi
|
||||||
|
setup-ruby-test:
|
||||||
|
runs-on: ['self-hosted', 'Linux']
|
||||||
|
steps:
|
||||||
|
- uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
ruby-version: 3.0
|
||||||
|
bundler-cache: true
|
||||||
|
- name: Test ruby/setup-ruby works
|
||||||
|
run: |
|
||||||
|
VERSION=$(ruby --version | cut -d ' ' -f2 | cut -d '.' -f1-2)
|
||||||
|
if [[ $VERSION != '3.0' ]]; then
|
||||||
|
echo "Ruby version detected : $(ruby --version 2>&1)"
|
||||||
|
echo "::error ::Detected ruby failed setup version test, could not match version with version specified in the setup action"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Ruby version detected : $(ruby --version 2>&1)"
|
||||||
|
fi
|
||||||
|
python-shell-test:
|
||||||
|
runs-on: ['self-hosted', 'Linux']
|
||||||
|
steps:
|
||||||
|
- name: Test Python shell works
|
||||||
|
run: |
|
||||||
|
import os
|
||||||
|
print(os.environ['PATH'])
|
||||||
|
shell: python
|
||||||
36
acceptance/testdata/org.hra.yaml
vendored
Normal file
36
acceptance/testdata/org.hra.yaml
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: HorizontalRunnerAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: org
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
name: org-runnerdeploy
|
||||||
|
scaleUpTriggers:
|
||||||
|
- githubEvent:
|
||||||
|
checkRun:
|
||||||
|
types: ["created"]
|
||||||
|
status: "queued"
|
||||||
|
amount: 1
|
||||||
|
duration: "1m"
|
||||||
|
scheduledOverrides:
|
||||||
|
- startTime: "2021-05-11T16:05:00+09:00"
|
||||||
|
endTime: "2021-05-11T16:40:00+09:00"
|
||||||
|
minReplicas: 2
|
||||||
|
- startTime: "2021-05-01T00:00:00+09:00"
|
||||||
|
endTime: "2021-05-03T00:00:00+09:00"
|
||||||
|
recurrenceRule:
|
||||||
|
frequency: Weekly
|
||||||
|
untilTime: "2022-05-01T00:00:00+09:00"
|
||||||
|
minReplicas: 0
|
||||||
|
minReplicas: 0
|
||||||
|
maxReplicas: 5
|
||||||
|
# Used to test that HRA is working for org runners
|
||||||
|
metrics:
|
||||||
|
- type: PercentageRunnersBusy
|
||||||
|
scaleUpThreshold: '0.75'
|
||||||
|
scaleDownThreshold: '0.3'
|
||||||
|
scaleUpFactor: '2'
|
||||||
|
scaleDownFactor: '0.5'
|
||||||
|
- type: TotalNumberOfQueuedAndInProgressWorkflowRuns
|
||||||
|
repositoryNames:
|
||||||
|
- ${TEST_ORG_REPO}
|
||||||
37
acceptance/testdata/org.runnerdeploy.yaml
vendored
Normal file
37
acceptance/testdata/org.runnerdeploy.yaml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: RunnerDeployment
|
||||||
|
metadata:
|
||||||
|
name: org-runnerdeploy
|
||||||
|
spec:
|
||||||
|
# replicas: 1
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
organization: ${TEST_ORG}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Custom runner image
|
||||||
|
#
|
||||||
|
image: ${RUNNER_NAME}:${RUNNER_TAG}
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
#
|
||||||
|
# dockerd within runner container
|
||||||
|
#
|
||||||
|
## Replace `mumoshu/actions-runner-dind:dev` with your dind image
|
||||||
|
#dockerdWithinRunnerContainer: true
|
||||||
|
#image: mumoshu/actions-runner-dind:dev
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set the MTU used by dockerd-managed network interfaces (including docker-build-ubuntu)
|
||||||
|
#
|
||||||
|
#dockerMTU: 1450
|
||||||
|
|
||||||
|
#Runner group
|
||||||
|
# labels:
|
||||||
|
# - "mylabel 1"
|
||||||
|
# - "mylabel 2"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Non-standard working directory
|
||||||
|
#
|
||||||
|
# workDir: "/"
|
||||||
25
acceptance/testdata/repo.hra.yaml
vendored
Normal file
25
acceptance/testdata/repo.hra.yaml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: HorizontalRunnerAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: actions-runner-aos-autoscaler
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
name: example-runnerdeploy
|
||||||
|
scaleUpTriggers:
|
||||||
|
- githubEvent:
|
||||||
|
checkRun:
|
||||||
|
types: ["created"]
|
||||||
|
status: "queued"
|
||||||
|
amount: 1
|
||||||
|
duration: "1m"
|
||||||
|
minReplicas: 0
|
||||||
|
maxReplicas: 5
|
||||||
|
metrics:
|
||||||
|
- type: PercentageRunnersBusy
|
||||||
|
scaleUpThreshold: '0.75'
|
||||||
|
scaleDownThreshold: '0.3'
|
||||||
|
scaleUpFactor: '2'
|
||||||
|
scaleDownFactor: '0.5'
|
||||||
|
- type: TotalNumberOfQueuedAndInProgressWorkflowRuns
|
||||||
|
repositoryNames:
|
||||||
|
- ${TEST_REPO}
|
||||||
37
acceptance/testdata/repo.runnerdeploy.yaml
vendored
Normal file
37
acceptance/testdata/repo.runnerdeploy.yaml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: RunnerDeployment
|
||||||
|
metadata:
|
||||||
|
name: example-runnerdeploy
|
||||||
|
spec:
|
||||||
|
# replicas: 1
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
repository: ${TEST_REPO}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Custom runner image
|
||||||
|
#
|
||||||
|
image: ${RUNNER_NAME}:${RUNNER_TAG}
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
#
|
||||||
|
# dockerd within runner container
|
||||||
|
#
|
||||||
|
## Replace `mumoshu/actions-runner-dind:dev` with your dind image
|
||||||
|
#dockerdWithinRunnerContainer: true
|
||||||
|
#image: mumoshu/actions-runner-dind:dev
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set the MTU used by dockerd-managed network interfaces (including docker-build-ubuntu)
|
||||||
|
#
|
||||||
|
#dockerMTU: 1450
|
||||||
|
|
||||||
|
#Runner group
|
||||||
|
# labels:
|
||||||
|
# - "mylabel 1"
|
||||||
|
# - "mylabel 2"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Non-standard working directory
|
||||||
|
#
|
||||||
|
# workDir: "/"
|
||||||
29
acceptance/testdata/repo.runnerset.hra.yaml
vendored
Normal file
29
acceptance/testdata/repo.runnerset.hra.yaml
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: HorizontalRunnerAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: example-runnerset
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
kind: RunnerSet
|
||||||
|
name: example-runnerset
|
||||||
|
scaleUpTriggers:
|
||||||
|
- githubEvent:
|
||||||
|
checkRun:
|
||||||
|
types: ["created"]
|
||||||
|
status: "queued"
|
||||||
|
amount: 1
|
||||||
|
duration: "1m"
|
||||||
|
# RunnerSet doesn't support scale from/to zero yet
|
||||||
|
minReplicas: 1
|
||||||
|
maxReplicas: 5
|
||||||
|
# This should be less than 600(seconds, the default) for faster testing
|
||||||
|
scaleDownDelaySecondsAfterScaleOut: 60
|
||||||
|
metrics:
|
||||||
|
- type: PercentageRunnersBusy
|
||||||
|
scaleUpThreshold: '0.75'
|
||||||
|
scaleDownThreshold: '0.3'
|
||||||
|
scaleUpFactor: '2'
|
||||||
|
scaleDownFactor: '0.5'
|
||||||
|
- type: TotalNumberOfQueuedAndInProgressWorkflowRuns
|
||||||
|
repositoryNames:
|
||||||
|
- ${TEST_REPO}
|
||||||
56
acceptance/testdata/repo.runnerset.yaml
vendored
Normal file
56
acceptance/testdata/repo.runnerset.yaml
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: RunnerSet
|
||||||
|
metadata:
|
||||||
|
name: example-runnerset
|
||||||
|
spec:
|
||||||
|
# MANDATORY because it is based on StatefulSet: Results in a below error when omitted:
|
||||||
|
# missing required field "selector" in dev.summerwind.actions.v1alpha1.RunnerSet.spec
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: example-runnerset
|
||||||
|
|
||||||
|
# MANDATORY because it is based on StatefulSet: Results in a below error when omitted:
|
||||||
|
# missing required field "serviceName" in dev.summerwind.actions.v1alpha1.RunnerSet.spec]
|
||||||
|
serviceName: example-runnerset
|
||||||
|
|
||||||
|
#replicas: 1
|
||||||
|
|
||||||
|
# From my limited testing, `ephemeral: true` is more reliable.
|
||||||
|
# Seomtimes, updating already deployed runners from `ephemeral: false` to `ephemeral: true` seems to
|
||||||
|
# result in queued jobs hanging forever.
|
||||||
|
ephemeral: false
|
||||||
|
|
||||||
|
repository: ${TEST_REPO}
|
||||||
|
#
|
||||||
|
# Custom runner image
|
||||||
|
#
|
||||||
|
image: ${RUNNER_NAME}:${RUNNER_TAG}
|
||||||
|
#
|
||||||
|
# dockerd within runner container
|
||||||
|
#
|
||||||
|
## Replace `mumoshu/actions-runner-dind:dev` with your dind image
|
||||||
|
#dockerdWithinRunnerContainer: true
|
||||||
|
#
|
||||||
|
# Set the MTU used by dockerd-managed network interfaces (including docker-build-ubuntu)
|
||||||
|
#
|
||||||
|
#dockerMTU: 1450
|
||||||
|
#Runner group
|
||||||
|
# labels:
|
||||||
|
# - "mylabel 1"
|
||||||
|
# - "mylabel 2"
|
||||||
|
labels:
|
||||||
|
- "${RUNNER_LABEL}"
|
||||||
|
#
|
||||||
|
# Non-standard working directory
|
||||||
|
#
|
||||||
|
# workDir: "/"
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: example-runnerset
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: runner
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
#- name: docker
|
||||||
|
# #image: mumoshu/actions-runner-dind:dev
|
||||||
9
acceptance/testdata/runnerdeploy.yaml
vendored
9
acceptance/testdata/runnerdeploy.yaml
vendored
@@ -1,9 +0,0 @@
|
|||||||
apiVersion: actions.summerwind.dev/v1alpha1
|
|
||||||
kind: RunnerDeployment
|
|
||||||
metadata:
|
|
||||||
name: example-runnerdeploy
|
|
||||||
spec:
|
|
||||||
# replicas: 1
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
repository: mumoshu/actions-runner-controller-ci
|
|
||||||
20
acceptance/values.yaml
Normal file
20
acceptance/values.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Set actions-runner-controller settings for testing
|
||||||
|
githubAPICacheDuration: 10s
|
||||||
|
githubWebhookServer:
|
||||||
|
enabled: true
|
||||||
|
labels: {}
|
||||||
|
replicaCount: 1
|
||||||
|
syncPeriod: 10m
|
||||||
|
secret:
|
||||||
|
create: true
|
||||||
|
name: "github-webhook-server"
|
||||||
|
### GitHub Webhook Configuration
|
||||||
|
#github_webhook_secret_token: ""
|
||||||
|
service:
|
||||||
|
type: NodePort
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
nodePort: 31000
|
||||||
@@ -54,6 +54,12 @@ type HorizontalRunnerAutoscalerSpec struct {
|
|||||||
ScaleUpTriggers []ScaleUpTrigger `json:"scaleUpTriggers,omitempty"`
|
ScaleUpTriggers []ScaleUpTrigger `json:"scaleUpTriggers,omitempty"`
|
||||||
|
|
||||||
CapacityReservations []CapacityReservation `json:"capacityReservations,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
|
CapacityReservations []CapacityReservation `json:"capacityReservations,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// +optional
|
||||||
|
ScheduledOverrides []ScheduledOverride `json:"scheduledOverrides,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScaleUpTrigger struct {
|
type ScaleUpTrigger struct {
|
||||||
@@ -72,6 +78,12 @@ type GitHubEventScaleUpTriggerSpec struct {
|
|||||||
type CheckRunSpec struct {
|
type CheckRunSpec struct {
|
||||||
Types []string `json:"types,omitempty"`
|
Types []string `json:"types,omitempty"`
|
||||||
Status string `json:"status,omitempty"`
|
Status string `json:"status,omitempty"`
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
Names []string `json:"names,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request
|
// https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request
|
||||||
@@ -94,6 +106,12 @@ type CapacityReservation struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ScaleTargetRef struct {
|
type ScaleTargetRef struct {
|
||||||
|
// Kind is the type of resource being referenced
|
||||||
|
// +optional
|
||||||
|
// +kubebuilder:validation:Enum=RunnerDeployment;RunnerSet
|
||||||
|
Kind string `json:"kind,omitempty"`
|
||||||
|
|
||||||
|
// Name is the name of resource being referenced
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,6 +156,40 @@ type MetricSpec struct {
|
|||||||
ScaleDownAdjustment int `json:"scaleDownAdjustment,omitempty"`
|
ScaleDownAdjustment int `json:"scaleDownAdjustment,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ScheduledOverride can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule.
|
||||||
|
// A schedule can optionally be recurring, so that the correspoding override happens every day, week, month, or year.
|
||||||
|
type ScheduledOverride struct {
|
||||||
|
// StartTime is the time at which the first override starts.
|
||||||
|
StartTime metav1.Time `json:"startTime"`
|
||||||
|
|
||||||
|
// EndTime is the time at which the first override ends.
|
||||||
|
EndTime metav1.Time `json:"endTime"`
|
||||||
|
|
||||||
|
// MinReplicas is the number of runners while overriding.
|
||||||
|
// If omitted, it doesn't override minReplicas.
|
||||||
|
// +optional
|
||||||
|
// +nullable
|
||||||
|
// +kubebuilder:validation:Minimum=0
|
||||||
|
MinReplicas *int `json:"minReplicas,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
RecurrenceRule RecurrenceRule `json:"recurrenceRule,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RecurrenceRule struct {
|
||||||
|
// 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.
|
||||||
|
// +optional
|
||||||
|
// +kubebuilder:validation:Enum=Daily;Weekly;Monthly;Yearly
|
||||||
|
Frequency string `json:"frequency,omitempty"`
|
||||||
|
|
||||||
|
// UntilTime is the time of the final recurrence.
|
||||||
|
// If empty, the schedule recurs forever.
|
||||||
|
// +optional
|
||||||
|
UntilTime metav1.Time `json:"untilTime,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type HorizontalRunnerAutoscalerStatus struct {
|
type HorizontalRunnerAutoscalerStatus struct {
|
||||||
// ObservedGeneration is the most recent generation observed for the target. It corresponds to e.g.
|
// 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.
|
// RunnerDeployment's generation, which is updated on mutation by the API Server.
|
||||||
@@ -150,10 +202,16 @@ type HorizontalRunnerAutoscalerStatus struct {
|
|||||||
DesiredReplicas *int `json:"desiredReplicas,omitempty"`
|
DesiredReplicas *int `json:"desiredReplicas,omitempty"`
|
||||||
|
|
||||||
// +optional
|
// +optional
|
||||||
|
// +nullable
|
||||||
LastSuccessfulScaleOutTime *metav1.Time `json:"lastSuccessfulScaleOutTime,omitempty"`
|
LastSuccessfulScaleOutTime *metav1.Time `json:"lastSuccessfulScaleOutTime,omitempty"`
|
||||||
|
|
||||||
// +optional
|
// +optional
|
||||||
CacheEntries []CacheEntry `json:"cacheEntries,omitempty"`
|
CacheEntries []CacheEntry `json:"cacheEntries,omitempty"`
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// +optional
|
||||||
|
ScheduledOverridesSummary *string `json:"scheduledOverridesSummary,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const CacheEntryKeyDesiredReplicas = "desiredReplicas"
|
const CacheEntryKeyDesiredReplicas = "desiredReplicas"
|
||||||
@@ -169,6 +227,7 @@ type CacheEntry struct {
|
|||||||
// +kubebuilder:printcolumn:JSONPath=".spec.minReplicas",name=Min,type=number
|
// +kubebuilder:printcolumn:JSONPath=".spec.minReplicas",name=Min,type=number
|
||||||
// +kubebuilder:printcolumn:JSONPath=".spec.maxReplicas",name=Max,type=number
|
// +kubebuilder:printcolumn:JSONPath=".spec.maxReplicas",name=Max,type=number
|
||||||
// +kubebuilder:printcolumn:JSONPath=".status.desiredReplicas",name=Desired,type=number
|
// +kubebuilder:printcolumn:JSONPath=".status.desiredReplicas",name=Desired,type=number
|
||||||
|
// +kubebuilder:printcolumn:JSONPath=".status.scheduledOverridesSummary",name=Schedule,type=string
|
||||||
|
|
||||||
// HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler API
|
// HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler API
|
||||||
type HorizontalRunnerAutoscaler struct {
|
type HorizontalRunnerAutoscaler struct {
|
||||||
|
|||||||
@@ -19,12 +19,19 @@ package v1alpha1
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
|
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunnerSpec defines the desired state of Runner
|
// RunnerSpec defines the desired state of Runner
|
||||||
type RunnerSpec struct {
|
type RunnerSpec struct {
|
||||||
|
RunnerConfig `json:",inline"`
|
||||||
|
RunnerPodSpec `json:",inline"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RunnerConfig struct {
|
||||||
// +optional
|
// +optional
|
||||||
// +kubebuilder:validation:Pattern=`^[^/]+$`
|
// +kubebuilder:validation:Pattern=`^[^/]+$`
|
||||||
Enterprise string `json:"enterprise,omitempty"`
|
Enterprise string `json:"enterprise,omitempty"`
|
||||||
@@ -44,54 +51,98 @@ type RunnerSpec struct {
|
|||||||
Group string `json:"group,omitempty"`
|
Group string `json:"group,omitempty"`
|
||||||
|
|
||||||
// +optional
|
// +optional
|
||||||
Containers []corev1.Container `json:"containers,omitempty"`
|
Ephemeral *bool `json:"ephemeral,omitempty"`
|
||||||
// +optional
|
|
||||||
DockerdContainerResources corev1.ResourceRequirements `json:"dockerdContainerResources,omitempty"`
|
|
||||||
// +optional
|
|
||||||
Resources corev1.ResourceRequirements `json:"resources,omitempty"`
|
|
||||||
// +optional
|
|
||||||
VolumeMounts []corev1.VolumeMount `json:"volumeMounts,omitempty"`
|
|
||||||
// +optional
|
|
||||||
EnvFrom []corev1.EnvFromSource `json:"envFrom,omitempty"`
|
|
||||||
|
|
||||||
// +optional
|
// +optional
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
// +optional
|
|
||||||
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
|
|
||||||
// +optional
|
|
||||||
Env []corev1.EnvVar `json:"env,omitempty"`
|
|
||||||
|
|
||||||
// +optional
|
|
||||||
Volumes []corev1.Volume `json:"volumes,omitempty"`
|
|
||||||
// +optional
|
// +optional
|
||||||
WorkDir string `json:"workDir,omitempty"`
|
WorkDir string `json:"workDir,omitempty"`
|
||||||
|
|
||||||
// +optional
|
|
||||||
InitContainers []corev1.Container `json:"initContainers,omitempty"`
|
|
||||||
// +optional
|
|
||||||
SidecarContainers []corev1.Container `json:"sidecarContainers,omitempty"`
|
|
||||||
// +optional
|
|
||||||
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
|
|
||||||
// +optional
|
|
||||||
ServiceAccountName string `json:"serviceAccountName,omitempty"`
|
|
||||||
// +optional
|
|
||||||
AutomountServiceAccountToken *bool `json:"automountServiceAccountToken,omitempty"`
|
|
||||||
// +optional
|
|
||||||
SecurityContext *corev1.PodSecurityContext `json:"securityContext,omitempty"`
|
|
||||||
// +optional
|
|
||||||
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
|
|
||||||
// +optional
|
|
||||||
Affinity *corev1.Affinity `json:"affinity,omitempty"`
|
|
||||||
// +optional
|
|
||||||
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
|
|
||||||
// +optional
|
|
||||||
EphemeralContainers []corev1.EphemeralContainer `json:"ephemeralContainers,omitempty"`
|
|
||||||
// +optional
|
|
||||||
TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"`
|
|
||||||
// +optional
|
// +optional
|
||||||
DockerdWithinRunnerContainer *bool `json:"dockerdWithinRunnerContainer,omitempty"`
|
DockerdWithinRunnerContainer *bool `json:"dockerdWithinRunnerContainer,omitempty"`
|
||||||
// +optional
|
// +optional
|
||||||
DockerEnabled *bool `json:"dockerEnabled,omitempty"`
|
DockerEnabled *bool `json:"dockerEnabled,omitempty"`
|
||||||
|
// +optional
|
||||||
|
DockerMTU *int64 `json:"dockerMTU,omitempty"`
|
||||||
|
// +optional
|
||||||
|
DockerRegistryMirror *string `json:"dockerRegistryMirror,omitempty"`
|
||||||
|
// +optional
|
||||||
|
VolumeSizeLimit *resource.Quantity `json:"volumeSizeLimit,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunnerPodSpec defines the desired pod spec fields of the runner pod
|
||||||
|
type RunnerPodSpec struct {
|
||||||
|
// +optional
|
||||||
|
DockerdContainerResources corev1.ResourceRequirements `json:"dockerdContainerResources,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
DockerVolumeMounts []corev1.VolumeMount `json:"dockerVolumeMounts,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
Containers []corev1.Container `json:"containers,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
Env []corev1.EnvVar `json:"env,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
EnvFrom []corev1.EnvFromSource `json:"envFrom,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
Resources corev1.ResourceRequirements `json:"resources,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
VolumeMounts []corev1.VolumeMount `json:"volumeMounts,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
Volumes []corev1.Volume `json:"volumes,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
EnableServiceLinks *bool `json:"enableServiceLinks,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
InitContainers []corev1.Container `json:"initContainers,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
ServiceAccountName string `json:"serviceAccountName,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
AutomountServiceAccountToken *bool `json:"automountServiceAccountToken,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
SidecarContainers []corev1.Container `json:"sidecarContainers,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
SecurityContext *corev1.PodSecurityContext `json:"securityContext,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
Affinity *corev1.Affinity `json:"affinity,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
EphemeralContainers []corev1.EphemeralContainer `json:"ephemeralContainers,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
HostAliases []corev1.HostAlias `json:"hostAliases,omitempty"`
|
||||||
|
|
||||||
|
// RuntimeClassName is the container runtime configuration that containers should run under.
|
||||||
|
// More info: https://kubernetes.io/docs/concepts/containers/runtime-class
|
||||||
|
// +optional
|
||||||
|
RuntimeClassName *string `json:"runtimeClassName,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateRepository validates repository field.
|
// ValidateRepository validates repository field.
|
||||||
@@ -119,10 +170,17 @@ func (rs *RunnerSpec) ValidateRepository() error {
|
|||||||
|
|
||||||
// RunnerStatus defines the observed state of Runner
|
// RunnerStatus defines the observed state of Runner
|
||||||
type RunnerStatus struct {
|
type RunnerStatus struct {
|
||||||
|
// +optional
|
||||||
Registration RunnerStatusRegistration `json:"registration"`
|
Registration RunnerStatusRegistration `json:"registration"`
|
||||||
Phase string `json:"phase"`
|
// +optional
|
||||||
Reason string `json:"reason"`
|
Phase string `json:"phase,omitempty"`
|
||||||
Message string `json:"message"`
|
// +optional
|
||||||
|
Reason string `json:"reason,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
// +optional
|
||||||
|
// +nullable
|
||||||
|
LastRegistrationCheckTime *metav1.Time `json:"lastRegistrationCheckTime,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunnerStatusRegistration contains runner registration status
|
// RunnerStatusRegistration contains runner registration status
|
||||||
@@ -142,6 +200,7 @@ type RunnerStatusRegistration struct {
|
|||||||
// +kubebuilder:printcolumn:JSONPath=".spec.repository",name=Repository,type=string
|
// +kubebuilder:printcolumn:JSONPath=".spec.repository",name=Repository,type=string
|
||||||
// +kubebuilder:printcolumn:JSONPath=".spec.labels",name=Labels,type=string
|
// +kubebuilder:printcolumn:JSONPath=".spec.labels",name=Labels,type=string
|
||||||
// +kubebuilder:printcolumn:JSONPath=".status.phase",name=Status,type=string
|
// +kubebuilder:printcolumn:JSONPath=".status.phase",name=Status,type=string
|
||||||
|
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
|
||||||
|
|
||||||
// Runner is the Schema for the runners API
|
// Runner is the Schema for the runners API
|
||||||
type Runner struct {
|
type Runner struct {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ func (r *Runner) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
|||||||
Complete()
|
Complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:webhook:path=/mutate-actions-summerwind-dev-v1alpha1-runner,verbs=create;update,mutating=true,failurePolicy=fail,groups=actions.summerwind.dev,resources=runners,versions=v1alpha1,name=mutate.runner.actions.summerwind.dev
|
// +kubebuilder:webhook:path=/mutate-actions-summerwind-dev-v1alpha1-runner,verbs=create;update,mutating=true,failurePolicy=fail,groups=actions.summerwind.dev,resources=runners,versions=v1alpha1,name=mutate.runner.actions.summerwind.dev,sideEffects=None,webhookVersions=v1beta1
|
||||||
|
|
||||||
var _ webhook.Defaulter = &Runner{}
|
var _ webhook.Defaulter = &Runner{}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ func (r *Runner) Default() {
|
|||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:webhook:path=/validate-actions-summerwind-dev-v1alpha1-runner,verbs=create;update,mutating=false,failurePolicy=fail,groups=actions.summerwind.dev,resources=runners,versions=v1alpha1,name=validate.runner.actions.summerwind.dev
|
// +kubebuilder:webhook:path=/validate-actions-summerwind-dev-v1alpha1-runner,verbs=create;update,mutating=false,failurePolicy=fail,groups=actions.summerwind.dev,resources=runners,versions=v1alpha1,name=validate.runner.actions.summerwind.dev,sideEffects=None,webhookVersions=v1beta1
|
||||||
|
|
||||||
var _ webhook.Validator = &Runner{}
|
var _ webhook.Validator = &Runner{}
|
||||||
|
|
||||||
|
|||||||
@@ -25,30 +25,54 @@ const (
|
|||||||
AutoscalingMetricTypePercentageRunnersBusy = "PercentageRunnersBusy"
|
AutoscalingMetricTypePercentageRunnersBusy = "PercentageRunnersBusy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunnerReplicaSetSpec defines the desired state of RunnerDeployment
|
// RunnerDeploymentSpec defines the desired state of RunnerDeployment
|
||||||
type RunnerDeploymentSpec struct {
|
type RunnerDeploymentSpec struct {
|
||||||
// +optional
|
// +optional
|
||||||
// +nullable
|
// +nullable
|
||||||
Replicas *int `json:"replicas,omitempty"`
|
Replicas *int `json:"replicas,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
// +nullable
|
||||||
|
Selector *metav1.LabelSelector `json:"selector"`
|
||||||
Template RunnerTemplate `json:"template"`
|
Template RunnerTemplate `json:"template"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RunnerDeploymentStatus struct {
|
type RunnerDeploymentStatus struct {
|
||||||
AvailableReplicas int `json:"availableReplicas"`
|
// See K8s deployment controller code for reference
|
||||||
ReadyReplicas int `json:"readyReplicas"`
|
// https://github.com/kubernetes/kubernetes/blob/ea0764452222146c47ec826977f49d7001b0ea8c/pkg/controller/deployment/sync.go#L487-L505
|
||||||
|
|
||||||
// Replicas is the total number of desired, non-terminated and latest pods to be set for the primary RunnerSet
|
// AvailableReplicas is the total number of available runners which have been successfully registered to GitHub and still running.
|
||||||
|
// This corresponds to the sum of status.availableReplicas of all the runner replica sets.
|
||||||
|
// +optional
|
||||||
|
AvailableReplicas *int `json:"availableReplicas"`
|
||||||
|
|
||||||
|
// ReadyReplicas is the total number of available runners which have been successfully registered to GitHub and still running.
|
||||||
|
// This corresponds to the sum of status.readyReplicas of all the runner replica sets.
|
||||||
|
// +optional
|
||||||
|
ReadyReplicas *int `json:"readyReplicas"`
|
||||||
|
|
||||||
|
// ReadyReplicas is the total number of available runners which have been successfully registered to GitHub and still running.
|
||||||
|
// This corresponds to status.replicas of the runner replica set that has the desired template hash.
|
||||||
|
// +optional
|
||||||
|
UpdatedReplicas *int `json:"updatedReplicas"`
|
||||||
|
|
||||||
|
// 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.
|
// This doesn't include outdated pods while upgrading the deployment and replacing the runnerset.
|
||||||
// +optional
|
// +optional
|
||||||
Replicas *int `json:"desiredReplicas,omitempty"`
|
DesiredReplicas *int `json:"desiredReplicas"`
|
||||||
|
|
||||||
|
// Replicas is the total number of replicas
|
||||||
|
// +optional
|
||||||
|
Replicas *int `json:"replicas"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:object:root=true
|
// +kubebuilder:object:root=true
|
||||||
// +kubebuilder:subresource:status
|
// +kubebuilder:subresource:status
|
||||||
// +kubebuilder:printcolumn:JSONPath=".spec.replicas",name=Desired,type=number
|
// +kubebuilder:printcolumn:JSONPath=".spec.replicas",name=Desired,type=number
|
||||||
// +kubebuilder:printcolumn:JSONPath=".status.availableReplicas",name=Current,type=number
|
// +kubebuilder:printcolumn:JSONPath=".status.replicas",name=Current,type=number
|
||||||
// +kubebuilder:printcolumn:JSONPath=".status.readyReplicas",name=Ready,type=number
|
// +kubebuilder:printcolumn:JSONPath=".status.updatedReplicas",name=Up-To-Date,type=number
|
||||||
|
// +kubebuilder:printcolumn:JSONPath=".status.availableReplicas",name=Available,type=number
|
||||||
|
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
|
||||||
|
|
||||||
// RunnerDeployment is the Schema for the runnerdeployments API
|
// RunnerDeployment is the Schema for the runnerdeployments API
|
||||||
type RunnerDeployment struct {
|
type RunnerDeployment struct {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ func (r *RunnerDeployment) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
|||||||
Complete()
|
Complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:webhook:path=/mutate-actions-summerwind-dev-v1alpha1-runnerdeployment,verbs=create;update,mutating=true,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerdeployments,versions=v1alpha1,name=mutate.runnerdeployment.actions.summerwind.dev
|
// +kubebuilder:webhook:path=/mutate-actions-summerwind-dev-v1alpha1-runnerdeployment,verbs=create;update,mutating=true,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerdeployments,versions=v1alpha1,name=mutate.runnerdeployment.actions.summerwind.dev,webhookVersions=v1beta1
|
||||||
|
|
||||||
var _ webhook.Defaulter = &RunnerDeployment{}
|
var _ webhook.Defaulter = &RunnerDeployment{}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ func (r *RunnerDeployment) Default() {
|
|||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:webhook:path=/validate-actions-summerwind-dev-v1alpha1-runnerdeployment,verbs=create;update,mutating=false,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerdeployments,versions=v1alpha1,name=validate.runnerdeployment.actions.summerwind.dev
|
// +kubebuilder:webhook:path=/validate-actions-summerwind-dev-v1alpha1-runnerdeployment,verbs=create;update,mutating=false,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerdeployments,versions=v1alpha1,name=validate.runnerdeployment.actions.summerwind.dev,webhookVersions=v1beta1
|
||||||
|
|
||||||
var _ webhook.Validator = &RunnerDeployment{}
|
var _ webhook.Validator = &RunnerDeployment{}
|
||||||
|
|
||||||
|
|||||||
@@ -26,12 +26,26 @@ type RunnerReplicaSetSpec struct {
|
|||||||
// +nullable
|
// +nullable
|
||||||
Replicas *int `json:"replicas,omitempty"`
|
Replicas *int `json:"replicas,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
// +nullable
|
||||||
|
Selector *metav1.LabelSelector `json:"selector"`
|
||||||
Template RunnerTemplate `json:"template"`
|
Template RunnerTemplate `json:"template"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RunnerReplicaSetStatus struct {
|
type RunnerReplicaSetStatus struct {
|
||||||
AvailableReplicas int `json:"availableReplicas"`
|
// See K8s replicaset controller code for reference
|
||||||
ReadyReplicas int `json:"readyReplicas"`
|
// https://github.com/kubernetes/kubernetes/blob/ea0764452222146c47ec826977f49d7001b0ea8c/pkg/controller/replicaset/replica_set_utils.go#L101-L106
|
||||||
|
|
||||||
|
// Replicas is the number of runners that are created and still being managed by this runner replica set.
|
||||||
|
// +optional
|
||||||
|
Replicas *int `json:"replicas"`
|
||||||
|
|
||||||
|
// ReadyReplicas is the number of runners that are created and Runnning.
|
||||||
|
ReadyReplicas *int `json:"readyReplicas"`
|
||||||
|
|
||||||
|
// AvailableReplicas is the number of runners that are created and Runnning.
|
||||||
|
// This is currently same as ReadyReplicas but perserved for future use.
|
||||||
|
AvailableReplicas *int `json:"availableReplicas"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RunnerTemplate struct {
|
type RunnerTemplate struct {
|
||||||
@@ -43,8 +57,9 @@ type RunnerTemplate struct {
|
|||||||
// +kubebuilder:object:root=true
|
// +kubebuilder:object:root=true
|
||||||
// +kubebuilder:subresource:status
|
// +kubebuilder:subresource:status
|
||||||
// +kubebuilder:printcolumn:JSONPath=".spec.replicas",name=Desired,type=number
|
// +kubebuilder:printcolumn:JSONPath=".spec.replicas",name=Desired,type=number
|
||||||
// +kubebuilder:printcolumn:JSONPath=".status.availableReplicas",name=Current,type=number
|
// +kubebuilder:printcolumn:JSONPath=".status.replicas",name=Current,type=number
|
||||||
// +kubebuilder:printcolumn:JSONPath=".status.readyReplicas",name=Ready,type=number
|
// +kubebuilder:printcolumn:JSONPath=".status.readyReplicas",name=Ready,type=number
|
||||||
|
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
|
||||||
|
|
||||||
// RunnerReplicaSet is the Schema for the runnerreplicasets API
|
// RunnerReplicaSet is the Schema for the runnerreplicasets API
|
||||||
type RunnerReplicaSet struct {
|
type RunnerReplicaSet struct {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ func (r *RunnerReplicaSet) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
|||||||
Complete()
|
Complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:webhook:path=/mutate-actions-summerwind-dev-v1alpha1-runnerreplicaset,verbs=create;update,mutating=true,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerreplicasets,versions=v1alpha1,name=mutate.runnerreplicaset.actions.summerwind.dev
|
// +kubebuilder:webhook:path=/mutate-actions-summerwind-dev-v1alpha1-runnerreplicaset,verbs=create;update,mutating=true,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerreplicasets,versions=v1alpha1,name=mutate.runnerreplicaset.actions.summerwind.dev,sideEffects=None,webhookVersions=v1beta1
|
||||||
|
|
||||||
var _ webhook.Defaulter = &RunnerReplicaSet{}
|
var _ webhook.Defaulter = &RunnerReplicaSet{}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ func (r *RunnerReplicaSet) Default() {
|
|||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:webhook:path=/validate-actions-summerwind-dev-v1alpha1-runnerreplicaset,verbs=create;update,mutating=false,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerreplicasets,versions=v1alpha1,name=validate.runnerreplicaset.actions.summerwind.dev
|
// +kubebuilder:webhook:path=/validate-actions-summerwind-dev-v1alpha1-runnerreplicaset,verbs=create;update,mutating=false,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerreplicasets,versions=v1alpha1,name=validate.runnerreplicaset.actions.summerwind.dev,sideEffects=None,webhookVersions=v1beta1
|
||||||
|
|
||||||
var _ webhook.Validator = &RunnerReplicaSet{}
|
var _ webhook.Validator = &RunnerReplicaSet{}
|
||||||
|
|
||||||
|
|||||||
88
api/v1alpha1/runnerset_types.go
Normal file
88
api/v1alpha1/runnerset_types.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2021 The actions-runner-controller authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RunnerSetSpec defines the desired state of RunnerSet
|
||||||
|
type RunnerSetSpec struct {
|
||||||
|
RunnerConfig `json:",inline"`
|
||||||
|
|
||||||
|
appsv1.StatefulSetSpec `json:",inline"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RunnerSetStatus struct {
|
||||||
|
// See K8s deployment controller code for reference
|
||||||
|
// https://github.com/kubernetes/kubernetes/blob/ea0764452222146c47ec826977f49d7001b0ea8c/pkg/controller/deployment/sync.go#L487-L505
|
||||||
|
|
||||||
|
// AvailableReplicas is the total number of available runners which have been successfully registered to GitHub and still running.
|
||||||
|
// This corresponds to the sum of status.availableReplicas of all the runner replica sets.
|
||||||
|
// +optional
|
||||||
|
CurrentReplicas *int `json:"availableReplicas"`
|
||||||
|
|
||||||
|
// ReadyReplicas is the total number of available runners which have been successfully registered to GitHub and still running.
|
||||||
|
// This corresponds to the sum of status.readyReplicas of all the runner replica sets.
|
||||||
|
// +optional
|
||||||
|
ReadyReplicas *int `json:"readyReplicas"`
|
||||||
|
|
||||||
|
// ReadyReplicas is the total number of available runners which have been successfully registered to GitHub and still running.
|
||||||
|
// This corresponds to status.replicas of the runner replica set that has the desired template hash.
|
||||||
|
// +optional
|
||||||
|
UpdatedReplicas *int `json:"updatedReplicas"`
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// +optional
|
||||||
|
DesiredReplicas *int `json:"desiredReplicas"`
|
||||||
|
|
||||||
|
// Replicas is the total number of replicas
|
||||||
|
// +optional
|
||||||
|
Replicas *int `json:"replicas"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
// +kubebuilder:subresource:status
|
||||||
|
// +kubebuilder:printcolumn:JSONPath=".spec.replicas",name=Desired,type=number
|
||||||
|
// +kubebuilder:printcolumn:JSONPath=".status.replicas",name=Current,type=number
|
||||||
|
// +kubebuilder:printcolumn:JSONPath=".status.updatedReplicas",name=Up-To-Date,type=number
|
||||||
|
// +kubebuilder:printcolumn:JSONPath=".status.availableReplicas",name=Available,type=number
|
||||||
|
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
|
||||||
|
|
||||||
|
// RunnerSet is the Schema for the runnersets API
|
||||||
|
type RunnerSet struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
Spec RunnerSetSpec `json:"spec,omitempty"`
|
||||||
|
Status RunnerSetStatus `json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
|
// RunnerList contains a list of Runner
|
||||||
|
type RunnerSetList struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ListMeta `json:"metadata,omitempty"`
|
||||||
|
Items []RunnerSet `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SchemeBuilder.Register(&RunnerSet{}, &RunnerSetList{})
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ package v1alpha1
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -65,6 +66,11 @@ func (in *CheckRunSpec) DeepCopyInto(out *CheckRunSpec) {
|
|||||||
*out = make([]string, len(*in))
|
*out = make([]string, len(*in))
|
||||||
copy(*out, *in)
|
copy(*out, *in)
|
||||||
}
|
}
|
||||||
|
if in.Names != nil {
|
||||||
|
in, out := &in.Names, &out.Names
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheckRunSpec.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheckRunSpec.
|
||||||
@@ -206,6 +212,13 @@ func (in *HorizontalRunnerAutoscalerSpec) DeepCopyInto(out *HorizontalRunnerAuto
|
|||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if in.ScheduledOverrides != nil {
|
||||||
|
in, out := &in.ScheduledOverrides, &out.ScheduledOverrides
|
||||||
|
*out = make([]ScheduledOverride, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HorizontalRunnerAutoscalerSpec.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HorizontalRunnerAutoscalerSpec.
|
||||||
@@ -237,6 +250,11 @@ func (in *HorizontalRunnerAutoscalerStatus) DeepCopyInto(out *HorizontalRunnerAu
|
|||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if in.ScheduledOverridesSummary != nil {
|
||||||
|
in, out := &in.ScheduledOverridesSummary, &out.ScheduledOverridesSummary
|
||||||
|
*out = new(string)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HorizontalRunnerAutoscalerStatus.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HorizontalRunnerAutoscalerStatus.
|
||||||
@@ -309,6 +327,22 @@ func (in *PushSpec) DeepCopy() *PushSpec {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *RecurrenceRule) DeepCopyInto(out *RecurrenceRule) {
|
||||||
|
*out = *in
|
||||||
|
in.UntilTime.DeepCopyInto(&out.UntilTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecurrenceRule.
|
||||||
|
func (in *RecurrenceRule) DeepCopy() *RecurrenceRule {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(RecurrenceRule)
|
||||||
|
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 *Runner) DeepCopyInto(out *Runner) {
|
func (in *Runner) DeepCopyInto(out *Runner) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@@ -336,6 +370,56 @@ func (in *Runner) DeepCopyObject() runtime.Object {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *RunnerConfig) DeepCopyInto(out *RunnerConfig) {
|
||||||
|
*out = *in
|
||||||
|
if in.Labels != nil {
|
||||||
|
in, out := &in.Labels, &out.Labels
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Ephemeral != nil {
|
||||||
|
in, out := &in.Ephemeral, &out.Ephemeral
|
||||||
|
*out = new(bool)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.DockerdWithinRunnerContainer != nil {
|
||||||
|
in, out := &in.DockerdWithinRunnerContainer, &out.DockerdWithinRunnerContainer
|
||||||
|
*out = new(bool)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.DockerEnabled != nil {
|
||||||
|
in, out := &in.DockerEnabled, &out.DockerEnabled
|
||||||
|
*out = new(bool)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.DockerMTU != nil {
|
||||||
|
in, out := &in.DockerMTU, &out.DockerMTU
|
||||||
|
*out = new(int64)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.DockerRegistryMirror != nil {
|
||||||
|
in, out := &in.DockerRegistryMirror, &out.DockerRegistryMirror
|
||||||
|
*out = new(string)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.VolumeSizeLimit != nil {
|
||||||
|
in, out := &in.VolumeSizeLimit, &out.VolumeSizeLimit
|
||||||
|
x := (*in).DeepCopy()
|
||||||
|
*out = &x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerConfig.
|
||||||
|
func (in *RunnerConfig) DeepCopy() *RunnerConfig {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(RunnerConfig)
|
||||||
|
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 *RunnerDeployment) DeepCopyInto(out *RunnerDeployment) {
|
func (in *RunnerDeployment) DeepCopyInto(out *RunnerDeployment) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@@ -403,6 +487,11 @@ func (in *RunnerDeploymentSpec) DeepCopyInto(out *RunnerDeploymentSpec) {
|
|||||||
*out = new(int)
|
*out = new(int)
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
|
if in.Selector != nil {
|
||||||
|
in, out := &in.Selector, &out.Selector
|
||||||
|
*out = new(metav1.LabelSelector)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
in.Template.DeepCopyInto(&out.Template)
|
in.Template.DeepCopyInto(&out.Template)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,6 +508,26 @@ func (in *RunnerDeploymentSpec) DeepCopy() *RunnerDeploymentSpec {
|
|||||||
// 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 *RunnerDeploymentStatus) DeepCopyInto(out *RunnerDeploymentStatus) {
|
func (in *RunnerDeploymentStatus) DeepCopyInto(out *RunnerDeploymentStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
if in.AvailableReplicas != nil {
|
||||||
|
in, out := &in.AvailableReplicas, &out.AvailableReplicas
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.ReadyReplicas != nil {
|
||||||
|
in, out := &in.ReadyReplicas, &out.ReadyReplicas
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.UpdatedReplicas != nil {
|
||||||
|
in, out := &in.UpdatedReplicas, &out.UpdatedReplicas
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.DesiredReplicas != nil {
|
||||||
|
in, out := &in.DesiredReplicas, &out.DesiredReplicas
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
if in.Replicas != nil {
|
if in.Replicas != nil {
|
||||||
in, out := &in.Replicas, &out.Replicas
|
in, out := &in.Replicas, &out.Replicas
|
||||||
*out = new(int)
|
*out = new(int)
|
||||||
@@ -468,13 +577,149 @@ func (in *RunnerList) DeepCopyObject() runtime.Object {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *RunnerPodSpec) DeepCopyInto(out *RunnerPodSpec) {
|
||||||
|
*out = *in
|
||||||
|
in.DockerdContainerResources.DeepCopyInto(&out.DockerdContainerResources)
|
||||||
|
if in.DockerVolumeMounts != nil {
|
||||||
|
in, out := &in.DockerVolumeMounts, &out.DockerVolumeMounts
|
||||||
|
*out = make([]v1.VolumeMount, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.Containers != nil {
|
||||||
|
in, out := &in.Containers, &out.Containers
|
||||||
|
*out = make([]v1.Container, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.Env != nil {
|
||||||
|
in, out := &in.Env, &out.Env
|
||||||
|
*out = make([]v1.EnvVar, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.EnvFrom != nil {
|
||||||
|
in, out := &in.EnvFrom, &out.EnvFrom
|
||||||
|
*out = make([]v1.EnvFromSource, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in.Resources.DeepCopyInto(&out.Resources)
|
||||||
|
if in.VolumeMounts != nil {
|
||||||
|
in, out := &in.VolumeMounts, &out.VolumeMounts
|
||||||
|
*out = make([]v1.VolumeMount, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.Volumes != nil {
|
||||||
|
in, out := &in.Volumes, &out.Volumes
|
||||||
|
*out = make([]v1.Volume, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.EnableServiceLinks != nil {
|
||||||
|
in, out := &in.EnableServiceLinks, &out.EnableServiceLinks
|
||||||
|
*out = new(bool)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.InitContainers != nil {
|
||||||
|
in, out := &in.InitContainers, &out.InitContainers
|
||||||
|
*out = make([]v1.Container, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.NodeSelector != nil {
|
||||||
|
in, out := &in.NodeSelector, &out.NodeSelector
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.AutomountServiceAccountToken != nil {
|
||||||
|
in, out := &in.AutomountServiceAccountToken, &out.AutomountServiceAccountToken
|
||||||
|
*out = new(bool)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.SidecarContainers != nil {
|
||||||
|
in, out := &in.SidecarContainers, &out.SidecarContainers
|
||||||
|
*out = make([]v1.Container, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.SecurityContext != nil {
|
||||||
|
in, out := &in.SecurityContext, &out.SecurityContext
|
||||||
|
*out = new(v1.PodSecurityContext)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.ImagePullSecrets != nil {
|
||||||
|
in, out := &in.ImagePullSecrets, &out.ImagePullSecrets
|
||||||
|
*out = make([]v1.LocalObjectReference, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Affinity != nil {
|
||||||
|
in, out := &in.Affinity, &out.Affinity
|
||||||
|
*out = new(v1.Affinity)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.Tolerations != nil {
|
||||||
|
in, out := &in.Tolerations, &out.Tolerations
|
||||||
|
*out = make([]v1.Toleration, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.TerminationGracePeriodSeconds != nil {
|
||||||
|
in, out := &in.TerminationGracePeriodSeconds, &out.TerminationGracePeriodSeconds
|
||||||
|
*out = new(int64)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.EphemeralContainers != nil {
|
||||||
|
in, out := &in.EphemeralContainers, &out.EphemeralContainers
|
||||||
|
*out = make([]v1.EphemeralContainer, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.HostAliases != nil {
|
||||||
|
in, out := &in.HostAliases, &out.HostAliases
|
||||||
|
*out = make([]v1.HostAlias, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.RuntimeClassName != nil {
|
||||||
|
in, out := &in.RuntimeClassName, &out.RuntimeClassName
|
||||||
|
*out = new(string)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerPodSpec.
|
||||||
|
func (in *RunnerPodSpec) DeepCopy() *RunnerPodSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(RunnerPodSpec)
|
||||||
|
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 *RunnerReplicaSet) DeepCopyInto(out *RunnerReplicaSet) {
|
func (in *RunnerReplicaSet) DeepCopyInto(out *RunnerReplicaSet) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
in.Spec.DeepCopyInto(&out.Spec)
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
out.Status = in.Status
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerReplicaSet.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerReplicaSet.
|
||||||
@@ -535,6 +780,11 @@ func (in *RunnerReplicaSetSpec) DeepCopyInto(out *RunnerReplicaSetSpec) {
|
|||||||
*out = new(int)
|
*out = new(int)
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
|
if in.Selector != nil {
|
||||||
|
in, out := &in.Selector, &out.Selector
|
||||||
|
*out = new(metav1.LabelSelector)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
in.Template.DeepCopyInto(&out.Template)
|
in.Template.DeepCopyInto(&out.Template)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,6 +801,21 @@ func (in *RunnerReplicaSetSpec) DeepCopy() *RunnerReplicaSetSpec {
|
|||||||
// 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 *RunnerReplicaSetStatus) DeepCopyInto(out *RunnerReplicaSetStatus) {
|
func (in *RunnerReplicaSetStatus) DeepCopyInto(out *RunnerReplicaSetStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
if in.Replicas != nil {
|
||||||
|
in, out := &in.Replicas, &out.Replicas
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.ReadyReplicas != nil {
|
||||||
|
in, out := &in.ReadyReplicas, &out.ReadyReplicas
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.AvailableReplicas != nil {
|
||||||
|
in, out := &in.AvailableReplicas, &out.AvailableReplicas
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerReplicaSetStatus.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerReplicaSetStatus.
|
||||||
@@ -563,121 +828,127 @@ func (in *RunnerReplicaSetStatus) DeepCopy() *RunnerReplicaSetStatus {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *RunnerSet) DeepCopyInto(out *RunnerSet) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerSet.
|
||||||
|
func (in *RunnerSet) DeepCopy() *RunnerSet {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(RunnerSet)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *RunnerSet) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *RunnerSetList) DeepCopyInto(out *RunnerSetList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]RunnerSet, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerSetList.
|
||||||
|
func (in *RunnerSetList) DeepCopy() *RunnerSetList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(RunnerSetList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *RunnerSetList) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *RunnerSetSpec) DeepCopyInto(out *RunnerSetSpec) {
|
||||||
|
*out = *in
|
||||||
|
in.RunnerConfig.DeepCopyInto(&out.RunnerConfig)
|
||||||
|
in.StatefulSetSpec.DeepCopyInto(&out.StatefulSetSpec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerSetSpec.
|
||||||
|
func (in *RunnerSetSpec) DeepCopy() *RunnerSetSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(RunnerSetSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *RunnerSetStatus) DeepCopyInto(out *RunnerSetStatus) {
|
||||||
|
*out = *in
|
||||||
|
if in.CurrentReplicas != nil {
|
||||||
|
in, out := &in.CurrentReplicas, &out.CurrentReplicas
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.ReadyReplicas != nil {
|
||||||
|
in, out := &in.ReadyReplicas, &out.ReadyReplicas
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.UpdatedReplicas != nil {
|
||||||
|
in, out := &in.UpdatedReplicas, &out.UpdatedReplicas
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.DesiredReplicas != nil {
|
||||||
|
in, out := &in.DesiredReplicas, &out.DesiredReplicas
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.Replicas != nil {
|
||||||
|
in, out := &in.Replicas, &out.Replicas
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerSetStatus.
|
||||||
|
func (in *RunnerSetStatus) DeepCopy() *RunnerSetStatus {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(RunnerSetStatus)
|
||||||
|
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 *RunnerSpec) DeepCopyInto(out *RunnerSpec) {
|
func (in *RunnerSpec) DeepCopyInto(out *RunnerSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.Labels != nil {
|
in.RunnerConfig.DeepCopyInto(&out.RunnerConfig)
|
||||||
in, out := &in.Labels, &out.Labels
|
in.RunnerPodSpec.DeepCopyInto(&out.RunnerPodSpec)
|
||||||
*out = make([]string, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
if in.Containers != nil {
|
|
||||||
in, out := &in.Containers, &out.Containers
|
|
||||||
*out = make([]v1.Container, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
in.DockerdContainerResources.DeepCopyInto(&out.DockerdContainerResources)
|
|
||||||
in.Resources.DeepCopyInto(&out.Resources)
|
|
||||||
if in.VolumeMounts != nil {
|
|
||||||
in, out := &in.VolumeMounts, &out.VolumeMounts
|
|
||||||
*out = make([]v1.VolumeMount, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if in.EnvFrom != nil {
|
|
||||||
in, out := &in.EnvFrom, &out.EnvFrom
|
|
||||||
*out = make([]v1.EnvFromSource, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if in.Env != nil {
|
|
||||||
in, out := &in.Env, &out.Env
|
|
||||||
*out = make([]v1.EnvVar, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if in.Volumes != nil {
|
|
||||||
in, out := &in.Volumes, &out.Volumes
|
|
||||||
*out = make([]v1.Volume, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if in.InitContainers != nil {
|
|
||||||
in, out := &in.InitContainers, &out.InitContainers
|
|
||||||
*out = make([]v1.Container, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if in.SidecarContainers != nil {
|
|
||||||
in, out := &in.SidecarContainers, &out.SidecarContainers
|
|
||||||
*out = make([]v1.Container, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if in.NodeSelector != nil {
|
|
||||||
in, out := &in.NodeSelector, &out.NodeSelector
|
|
||||||
*out = make(map[string]string, len(*in))
|
|
||||||
for key, val := range *in {
|
|
||||||
(*out)[key] = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if in.AutomountServiceAccountToken != nil {
|
|
||||||
in, out := &in.AutomountServiceAccountToken, &out.AutomountServiceAccountToken
|
|
||||||
*out = new(bool)
|
|
||||||
**out = **in
|
|
||||||
}
|
|
||||||
if in.SecurityContext != nil {
|
|
||||||
in, out := &in.SecurityContext, &out.SecurityContext
|
|
||||||
*out = new(v1.PodSecurityContext)
|
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
if in.ImagePullSecrets != nil {
|
|
||||||
in, out := &in.ImagePullSecrets, &out.ImagePullSecrets
|
|
||||||
*out = make([]v1.LocalObjectReference, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
if in.Affinity != nil {
|
|
||||||
in, out := &in.Affinity, &out.Affinity
|
|
||||||
*out = new(v1.Affinity)
|
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
if in.Tolerations != nil {
|
|
||||||
in, out := &in.Tolerations, &out.Tolerations
|
|
||||||
*out = make([]v1.Toleration, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if in.EphemeralContainers != nil {
|
|
||||||
in, out := &in.EphemeralContainers, &out.EphemeralContainers
|
|
||||||
*out = make([]v1.EphemeralContainer, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if in.TerminationGracePeriodSeconds != nil {
|
|
||||||
in, out := &in.TerminationGracePeriodSeconds, &out.TerminationGracePeriodSeconds
|
|
||||||
*out = new(int64)
|
|
||||||
**out = **in
|
|
||||||
}
|
|
||||||
if in.DockerdWithinRunnerContainer != nil {
|
|
||||||
in, out := &in.DockerdWithinRunnerContainer, &out.DockerdWithinRunnerContainer
|
|
||||||
*out = new(bool)
|
|
||||||
**out = **in
|
|
||||||
}
|
|
||||||
if in.DockerEnabled != nil {
|
|
||||||
in, out := &in.DockerEnabled, &out.DockerEnabled
|
|
||||||
*out = new(bool)
|
|
||||||
**out = **in
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerSpec.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerSpec.
|
||||||
@@ -694,6 +965,10 @@ func (in *RunnerSpec) DeepCopy() *RunnerSpec {
|
|||||||
func (in *RunnerStatus) DeepCopyInto(out *RunnerStatus) {
|
func (in *RunnerStatus) DeepCopyInto(out *RunnerStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
in.Registration.DeepCopyInto(&out.Registration)
|
in.Registration.DeepCopyInto(&out.Registration)
|
||||||
|
if in.LastRegistrationCheckTime != nil {
|
||||||
|
in, out := &in.LastRegistrationCheckTime, &out.LastRegistrationCheckTime
|
||||||
|
*out = (*in).DeepCopy()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerStatus.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerStatus.
|
||||||
@@ -779,3 +1054,26 @@ func (in *ScaleUpTrigger) DeepCopy() *ScaleUpTrigger {
|
|||||||
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 *ScheduledOverride) DeepCopyInto(out *ScheduledOverride) {
|
||||||
|
*out = *in
|
||||||
|
in.StartTime.DeepCopyInto(&out.StartTime)
|
||||||
|
in.EndTime.DeepCopyInto(&out.EndTime)
|
||||||
|
if in.MinReplicas != nil {
|
||||||
|
in, out := &in.MinReplicas, &out.MinReplicas
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
in.RecurrenceRule.DeepCopyInto(&out.RecurrenceRule)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScheduledOverride.
|
||||||
|
func (in *ScheduledOverride) DeepCopy() *ScheduledOverride {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ScheduledOverride)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,3 +21,5 @@
|
|||||||
.idea/
|
.idea/
|
||||||
*.tmproj
|
*.tmproj
|
||||||
.vscode/
|
.vscode/
|
||||||
|
# Docs
|
||||||
|
docs/
|
||||||
@@ -15,17 +15,16 @@ 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.5.2
|
version: 0.12.6
|
||||||
|
|
||||||
home: https://github.com/summerwind/actions-runner-controller
|
# Used as the default manager tag value when no tag property is provided in the values.yaml
|
||||||
|
appVersion: 0.19.0
|
||||||
|
|
||||||
|
home: https://github.com/actions-runner-controller/actions-runner-controller
|
||||||
|
|
||||||
sources:
|
sources:
|
||||||
- https://github.com/summerwind/actions-runner-controller
|
- https://github.com/actions-runner-controller/actions-runner-controller
|
||||||
|
|
||||||
maintainers:
|
maintainers:
|
||||||
- name: summerwind
|
- name: actions-runner-controller
|
||||||
email: contact@summerwind.jp
|
url: https://github.com/actions-runner-controller
|
||||||
url: https://github.com/summerwind
|
|
||||||
- name: funkypenguin
|
|
||||||
email: davidy@funkypenguin.co.nz
|
|
||||||
url: https://www.funkypenguin.co.nz
|
|
||||||
|
|||||||
84
charts/actions-runner-controller/README.md
Normal file
84
charts/actions-runner-controller/README.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
## Docs
|
||||||
|
|
||||||
|
All additional docs are kept in the `docs/` folder, this README is solely for documenting the values.yaml keys and values
|
||||||
|
|
||||||
|
## Values
|
||||||
|
|
||||||
|
_The values are documented as of HEAD_
|
||||||
|
|
||||||
|
_Default values are the defaults set in the charts values.yaml, some properties have default configurations in the code for when the property is omitted or invalid_
|
||||||
|
|
||||||
|
| Key | Description | Default |
|
||||||
|
|----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------|
|
||||||
|
| `labels` | Set labels to apply to all resources in the chart | |
|
||||||
|
| `replicaCount` | Set the number of controller pods | 1 |
|
||||||
|
| `syncPeriod` | Set the period in which the controler reconciles the desired runners count | 10m |
|
||||||
|
| `githubAPICacheDuration` | Set the cache period for API calls | |
|
||||||
|
| `githubEnterpriseServerURL` | Set the URL for a self-hosted GitHub Enterprise Server | |
|
||||||
|
| `logLevel` | Set the log level of the controller container | |
|
||||||
|
| `authSecret.create` | Deploy the controller auth secret | false |
|
||||||
|
| `authSecret.name` | Set the name of the auth secret | controller-manager |
|
||||||
|
| `authSecret.github_app_id` | The ID of your GitHub App. **This can't be set at the same time as `authSecret.github_token`** | |
|
||||||
|
| `authSecret.github_app_installation_id` | The ID of your GitHub App installation. **This can't be set at the same time as `authSecret.github_token`** | |
|
||||||
|
| `authSecret.github_app_private_key` | The multiline string of your GitHub App's private key. **This can't be set at the same time as `authSecret.github_token`** | |
|
||||||
|
| `authSecret.github_token` | Your chosen GitHub PAT token. **This can't be set at the same time as the `authSecret.github_app_*`** | |
|
||||||
|
| `image.repository` | The "repository/image" of the controller container | summerwind/actions-runner-controller |
|
||||||
|
| `image.tag` | The tag of the controller container | |
|
||||||
|
| `image.actionsRunnerRepositoryAndTag` | The "repository/image" of the actions runner container | summerwind/actions-runner:latest |
|
||||||
|
| `image.dindSidecarRepositoryAndTag` | The "repository/image" of the dind sidecar container | docker:dind |
|
||||||
|
| `image.pullPolicy` | The pull policy of the controller image | IfNotPresent |
|
||||||
|
| `metrics.serviceMonitor` | Deploy serviceMonitor kind for for use with prometheus-operator CRDs | false |
|
||||||
|
| `metrics.port` | Set port of metrics service | 8443 |
|
||||||
|
| `metrics.proxy.enabled` | Deploy kube-rbac-proxy container in controller pod | true |
|
||||||
|
| `metrics.proxy.image.repository` | The "repository/image" of the kube-proxy container | quay.io/brancz/kube-rbac-proxy |
|
||||||
|
| `metrics.proxy.image.tag` | The tag of the kube-proxy image to use when pulling the container | v0.10.0 |
|
||||||
|
| `imagePullSecrets` | Specifies the secret to be used when pulling the controller pod containers | |
|
||||||
|
| `fullNameOverride` | Override the full resource names | |
|
||||||
|
| `nameOverride` | Override the resource name prefix | |
|
||||||
|
| `serviceAccont.annotations` | Set annotations to the service account | |
|
||||||
|
| `serviceAccount.create` | Deploy the controller pod under a service account | true |
|
||||||
|
| `podAnnotations` | Set annotations for the controller pod | |
|
||||||
|
| `podLabels` | Set labels for the controller pod | |
|
||||||
|
| `serviceAccount.name` | Set the name of the service account | |
|
||||||
|
| `securityContext` | Set the security context for each container in the controller pod | |
|
||||||
|
| `podSecurityContext` | Set the security context to controller pod | |
|
||||||
|
| `service.port` | Set controller service type | |
|
||||||
|
| `service.type` | Set controller service ports | |
|
||||||
|
| `topologySpreadConstraints` | Set the controller pod topologySpreadConstraints | |
|
||||||
|
| `nodeSelector` | Set the controller pod nodeSelector | |
|
||||||
|
| `resources` | Set the controller pod resources | |
|
||||||
|
| `affinity` | Set the controller pod affinity rules | |
|
||||||
|
| `tolerations` | Set the controller pod tolerations | |
|
||||||
|
| `env` | Set environment variables for the controller container | |
|
||||||
|
| `priorityClassName` | Set the controller pod priorityClassName | |
|
||||||
|
| `scope.watchNamespace` | Tells the controller which namespace to watch if `scope.singleNamespace` is true | |
|
||||||
|
| `scope.singleNamespace` | Limit the controller to watch a single namespace | false |
|
||||||
|
| `githubWebhookServer.logLevel` | Set the log level of the githubWebhookServer container | |
|
||||||
|
| `githubWebhookServer.replicaCount` | Set the number of webhook server pods | 1 |
|
||||||
|
| `githubWebhookServer.syncPeriod` | Set the period in which the controller reconciles the resources | 10m |
|
||||||
|
| `githubWebhookServer.enabled` | Deploy the webhook server pod | false |
|
||||||
|
| `githubWebhookServer.secret.create` | Deploy the webhook hook secret | false |
|
||||||
|
| `githubWebhookServer.secret.name` | Set the name of the webhook hook secret | github-webhook-server |
|
||||||
|
| `githubWebhookServer.secret.github_webhook_secret_token` | Set the webhook secret token value | |
|
||||||
|
| `githubWebhookServer.imagePullSecrets` | Specifies the secret to be used when pulling the githubWebhookServer pod containers | |
|
||||||
|
| `githubWebhookServer.nameOveride` | Override the resource name prefix | |
|
||||||
|
| `githubWebhookServer.fullNameOveride` | Override the full resource names | |
|
||||||
|
| `githubWebhookServer.serviceAccount.create` | Deploy the githubWebhookServer under a service account | true |
|
||||||
|
| `githubWebhookServer.serviceAccount.annotations` | Set annotations for the service account | |
|
||||||
|
| `githubWebhookServer.serviceAccount.name` | Set the service account name | |
|
||||||
|
| `githubWebhookServer.podAnnotations` | Set annotations for the githubWebhookServer pod | |
|
||||||
|
| `githubWebhookServer.podLabels` | Set labels for the githubWebhookServer pod | |
|
||||||
|
| `githubWebhookServer.podSecurityContext` | Set the security context to githubWebhookServer pod | |
|
||||||
|
| `githubWebhookServer.securityContext` | Set the security context for each container in the githubWebhookServer pod | |
|
||||||
|
| `githubWebhookServer.resources` | Set the githubWebhookServer pod resources | |
|
||||||
|
| `githubWebhookServer.topologySpreadConstraints` | Set the githubWebhookServer pod topologySpreadConstraints | |
|
||||||
|
| `githubWebhookServer.nodeSelector` | Set the githubWebhookServer pod nodeSelector | |
|
||||||
|
| `githubWebhookServer.tolerations` | Set the githubWebhookServer pod tolerations | |
|
||||||
|
| `githubWebhookServer.affinity` | Set the githubWebhookServer pod affinity rules | |
|
||||||
|
| `githubWebhookServer.priorityClassName` | Set the githubWebhookServer pod priorityClassName | |
|
||||||
|
| `githubWebhookServer.service.type` | Set githubWebhookServer service type | |
|
||||||
|
| `githubWebhookServer.service.ports` | Set githubWebhookServer service ports | `[{"port":80, "targetPort:"http", "protocol":"TCP", "name":"http"}]` |
|
||||||
|
| `githubWebhookServer.ingress.enabled` | Deploy an ingress kind for the githubWebhookServer | false |
|
||||||
|
| `githubWebhookServer.ingress.annotations` | Set annotations for the ingress kind | |
|
||||||
|
| `githubWebhookServer.ingress.hosts` | Set hosts configuration for ingress | `[{"host": "chart-example.local", "paths": []}]` |
|
||||||
|
| `githubWebhookServer.ingress.tls` | Set tls configuration for ingress | |
|
||||||
@@ -22,6 +22,9 @@ resources:
|
|||||||
cpu: 100m
|
cpu: 100m
|
||||||
memory: 128Mi
|
memory: 128Mi
|
||||||
|
|
||||||
|
authSecret:
|
||||||
|
create: false
|
||||||
|
|
||||||
# Set the following to true to create a dummy secret, allowing the manager pod to start
|
# Set the following to true to create a dummy secret, allowing the manager pod to start
|
||||||
# This is only useful in CI
|
# This is only useful in CI
|
||||||
createDummySecret: true
|
createDummySecret: true
|
||||||
@@ -1,23 +1,13 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: apiextensions.k8s.io/v1beta1
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.3.0
|
controller-gen.kubebuilder.io/version: v0.6.0
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: horizontalrunnerautoscalers.actions.summerwind.dev
|
name: horizontalrunnerautoscalers.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
additionalPrinterColumns:
|
|
||||||
- JSONPath: .spec.minReplicas
|
|
||||||
name: Min
|
|
||||||
type: number
|
|
||||||
- JSONPath: .spec.maxReplicas
|
|
||||||
name: Max
|
|
||||||
type: number
|
|
||||||
- JSONPath: .status.desiredReplicas
|
|
||||||
name: Desired
|
|
||||||
type: number
|
|
||||||
group: actions.summerwind.dev
|
group: actions.summerwind.dev
|
||||||
names:
|
names:
|
||||||
kind: HorizontalRunnerAutoscaler
|
kind: HorizontalRunnerAutoscaler
|
||||||
@@ -25,9 +15,22 @@ spec:
|
|||||||
plural: horizontalrunnerautoscalers
|
plural: horizontalrunnerautoscalers
|
||||||
singular: horizontalrunnerautoscaler
|
singular: horizontalrunnerautoscaler
|
||||||
scope: Namespaced
|
scope: Namespaced
|
||||||
subresources:
|
versions:
|
||||||
status: {}
|
- additionalPrinterColumns:
|
||||||
validation:
|
- jsonPath: .spec.minReplicas
|
||||||
|
name: Min
|
||||||
|
type: number
|
||||||
|
- jsonPath: .spec.maxReplicas
|
||||||
|
name: Max
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.desiredReplicas
|
||||||
|
name: Desired
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.scheduledOverridesSummary
|
||||||
|
name: Schedule
|
||||||
|
type: string
|
||||||
|
name: v1alpha1
|
||||||
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler
|
description: HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler
|
||||||
API
|
API
|
||||||
@@ -45,8 +48,8 @@ spec:
|
|||||||
metadata:
|
metadata:
|
||||||
type: object
|
type: object
|
||||||
spec:
|
spec:
|
||||||
description: HorizontalRunnerAutoscalerSpec defines the desired state of
|
description: HorizontalRunnerAutoscalerSpec defines the desired state
|
||||||
HorizontalRunnerAutoscaler
|
of HorizontalRunnerAutoscaler
|
||||||
properties:
|
properties:
|
||||||
capacityReservations:
|
capacityReservations:
|
||||||
items:
|
items:
|
||||||
@@ -72,16 +75,16 @@ spec:
|
|||||||
items:
|
items:
|
||||||
properties:
|
properties:
|
||||||
repositoryNames:
|
repositoryNames:
|
||||||
description: RepositoryNames is the list of repository names to
|
description: RepositoryNames is the list of repository names
|
||||||
be used for calculating the metric. For example, a repository
|
to be used for calculating the metric. For example, a repository
|
||||||
name is the REPO part of `github.com/USER/REPO`.
|
name is the REPO part of `github.com/USER/REPO`.
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
scaleDownAdjustment:
|
scaleDownAdjustment:
|
||||||
description: ScaleDownAdjustment is the number of runners removed
|
description: ScaleDownAdjustment is the number of runners removed
|
||||||
on scale-down. You can only specify either ScaleDownFactor or
|
on scale-down. You can only specify either ScaleDownFactor
|
||||||
ScaleDownAdjustment.
|
or ScaleDownAdjustment.
|
||||||
type: integer
|
type: integer
|
||||||
scaleDownFactor:
|
scaleDownFactor:
|
||||||
description: ScaleDownFactor is the multiplicative factor applied
|
description: ScaleDownFactor is the multiplicative factor applied
|
||||||
@@ -90,11 +93,13 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
scaleDownThreshold:
|
scaleDownThreshold:
|
||||||
description: ScaleDownThreshold is the percentage of busy runners
|
description: ScaleDownThreshold is the percentage of busy runners
|
||||||
less than which will trigger the hpa to scale the runners down.
|
less than which will trigger the hpa to scale the runners
|
||||||
|
down.
|
||||||
type: string
|
type: string
|
||||||
scaleUpAdjustment:
|
scaleUpAdjustment:
|
||||||
description: ScaleUpAdjustment is the number of runners added
|
description: ScaleUpAdjustment is the number of runners added
|
||||||
on scale-up. You can only specify either ScaleUpFactor or ScaleUpAdjustment.
|
on scale-up. You can only specify either ScaleUpFactor or
|
||||||
|
ScaleUpAdjustment.
|
||||||
type: integer
|
type: integer
|
||||||
scaleUpFactor:
|
scaleUpFactor:
|
||||||
description: ScaleUpFactor is the multiplicative factor applied
|
description: ScaleUpFactor is the multiplicative factor applied
|
||||||
@@ -116,27 +121,34 @@ spec:
|
|||||||
is allowed to scale
|
is allowed to scale
|
||||||
type: integer
|
type: integer
|
||||||
scaleDownDelaySecondsAfterScaleOut:
|
scaleDownDelaySecondsAfterScaleOut:
|
||||||
description: ScaleDownDelaySecondsAfterScaleUp is the approximate delay
|
description: ScaleDownDelaySecondsAfterScaleUp is the approximate
|
||||||
for a scale down followed by a scale up Used to prevent flapping (down->up->down->...
|
delay for a scale down followed by a scale up Used to prevent flapping
|
||||||
loop)
|
(down->up->down->... loop)
|
||||||
type: integer
|
type: integer
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
description: ScaleTargetRef sis the reference to scaled resource like
|
description: ScaleTargetRef sis the reference to scaled resource like
|
||||||
RunnerDeployment
|
RunnerDeployment
|
||||||
properties:
|
properties:
|
||||||
|
kind:
|
||||||
|
description: Kind is the type of resource being referenced
|
||||||
|
enum:
|
||||||
|
- RunnerDeployment
|
||||||
|
- RunnerSet
|
||||||
|
type: string
|
||||||
name:
|
name:
|
||||||
|
description: Name is the name of resource being referenced
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
scaleUpTriggers:
|
scaleUpTriggers:
|
||||||
description: "ScaleUpTriggers is an experimental feature to increase
|
description: "ScaleUpTriggers is an experimental feature to increase
|
||||||
the desired replicas by 1 on each webhook requested received by the
|
the desired replicas by 1 on each webhook requested received by
|
||||||
webhookBasedAutoscaler. \n This feature requires you to also enable
|
the webhookBasedAutoscaler. \n This feature requires you to also
|
||||||
and deploy the webhookBasedAutoscaler onto your cluster. \n Note that
|
enable and deploy the webhookBasedAutoscaler onto your cluster.
|
||||||
the added runners remain until the next sync period at least, and
|
\n Note that the added runners remain until the next sync period
|
||||||
they may or may not be used by GitHub Actions depending on the timing.
|
at least, and they may or may not be used by GitHub Actions depending
|
||||||
They are intended to be used to gain \"resource slack\" immediately
|
on the timing. They are intended to be used to gain \"resource slack\"
|
||||||
after you receive a webhook from GitHub, so that you can loosely expect
|
immediately after you receive a webhook from GitHub, so that you
|
||||||
MinReplicas runners to be always available."
|
can loosely expect MinReplicas runners to be always available."
|
||||||
items:
|
items:
|
||||||
properties:
|
properties:
|
||||||
amount:
|
amount:
|
||||||
@@ -148,6 +160,17 @@ spec:
|
|||||||
checkRun:
|
checkRun:
|
||||||
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#check_run
|
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#check_run
|
||||||
properties:
|
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
|
||||||
status:
|
status:
|
||||||
type: string
|
type: string
|
||||||
types:
|
types:
|
||||||
@@ -174,6 +197,57 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
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 correspoding 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
|
type: object
|
||||||
status:
|
status:
|
||||||
properties:
|
properties:
|
||||||
@@ -191,11 +265,13 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
desiredReplicas:
|
desiredReplicas:
|
||||||
description: DesiredReplicas is the total number of desired, non-terminated
|
description: DesiredReplicas is the total number of desired, non-terminated
|
||||||
and latest pods to be set for the primary RunnerSet This doesn't include
|
and latest pods to be set for the primary RunnerSet This doesn't
|
||||||
outdated pods while upgrading the deployment and replacing the runnerset.
|
include outdated pods while upgrading the deployment and replacing
|
||||||
|
the runnerset.
|
||||||
type: integer
|
type: integer
|
||||||
lastSuccessfulScaleOutTime:
|
lastSuccessfulScaleOutTime:
|
||||||
format: date-time
|
format: date-time
|
||||||
|
nullable: true
|
||||||
type: string
|
type: string
|
||||||
observedGeneration:
|
observedGeneration:
|
||||||
description: ObservedGeneration is the most recent generation observed
|
description: ObservedGeneration is the most recent generation observed
|
||||||
@@ -203,13 +279,17 @@ spec:
|
|||||||
which is updated on mutation by the API Server.
|
which is updated on mutation by the API Server.
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
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
|
||||||
type: object
|
type: object
|
||||||
version: v1alpha1
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
served: true
|
||||||
storage: true
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
status:
|
status:
|
||||||
acceptedNames:
|
acceptedNames:
|
||||||
kind: ""
|
kind: ""
|
||||||
|
|||||||
@@ -1,21 +1,11 @@
|
|||||||
apiVersion: apiextensions.k8s.io/v1beta1
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.3.0
|
controller-gen.kubebuilder.io/version: v0.6.0
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: runnerdeployments.actions.summerwind.dev
|
name: runnerdeployments.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
additionalPrinterColumns:
|
|
||||||
- JSONPath: .spec.replicas
|
|
||||||
name: Desired
|
|
||||||
type: number
|
|
||||||
- JSONPath: .status.availableReplicas
|
|
||||||
name: Current
|
|
||||||
type: number
|
|
||||||
- JSONPath: .status.readyReplicas
|
|
||||||
name: Ready
|
|
||||||
type: number
|
|
||||||
group: actions.summerwind.dev
|
group: actions.summerwind.dev
|
||||||
names:
|
names:
|
||||||
kind: RunnerDeployment
|
kind: RunnerDeployment
|
||||||
@@ -23,9 +13,25 @@ spec:
|
|||||||
plural: runnerdeployments
|
plural: runnerdeployments
|
||||||
singular: runnerdeployment
|
singular: runnerdeployment
|
||||||
scope: Namespaced
|
scope: Namespaced
|
||||||
subresources:
|
versions:
|
||||||
status: {}
|
- additionalPrinterColumns:
|
||||||
validation:
|
- jsonPath: .spec.replicas
|
||||||
|
name: Desired
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.replicas
|
||||||
|
name: Current
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.updatedReplicas
|
||||||
|
name: Up-To-Date
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.availableReplicas
|
||||||
|
name: Available
|
||||||
|
type: number
|
||||||
|
- jsonPath: .metadata.creationTimestamp
|
||||||
|
name: Age
|
||||||
|
type: date
|
||||||
|
name: v1alpha1
|
||||||
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: RunnerDeployment is the Schema for the runnerdeployments API
|
description: RunnerDeployment is the Schema for the runnerdeployments API
|
||||||
properties:
|
properties:
|
||||||
@@ -38,14 +44,62 @@ spec:
|
|||||||
metadata:
|
metadata:
|
||||||
type: object
|
type: object
|
||||||
spec:
|
spec:
|
||||||
description: RunnerReplicaSetSpec defines the desired state of RunnerDeployment
|
description: RunnerDeploymentSpec defines the desired state of RunnerDeployment
|
||||||
properties:
|
properties:
|
||||||
replicas:
|
replicas:
|
||||||
nullable: true
|
nullable: true
|
||||||
type: integer
|
type: integer
|
||||||
|
selector:
|
||||||
|
description: A label selector is a label query over a set of resources. The result of matchLabels and matchExpressions are ANDed. An empty label selector matches all objects. A null label selector matches no objects.
|
||||||
|
nullable: true
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
template:
|
template:
|
||||||
properties:
|
properties:
|
||||||
metadata:
|
metadata:
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
finalizers:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
labels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
spec:
|
spec:
|
||||||
description: RunnerSpec defines the desired state of Runner
|
description: RunnerSpec defines the desired state of Runner
|
||||||
@@ -213,8 +267,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -268,8 +352,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -322,8 +436,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -377,8 +521,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -402,6 +576,38 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
dockerEnabled:
|
dockerEnabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
dockerMTU:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
dockerRegistryMirror:
|
||||||
|
type: string
|
||||||
|
dockerVolumeMounts:
|
||||||
|
items:
|
||||||
|
description: VolumeMount describes a mounting of a Volume within a container.
|
||||||
|
properties:
|
||||||
|
mountPath:
|
||||||
|
description: Path within the container at which the volume should be mounted. Must not contain ':'.
|
||||||
|
type: string
|
||||||
|
mountPropagation:
|
||||||
|
description: mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: This must match the Name of a Volume.
|
||||||
|
type: string
|
||||||
|
readOnly:
|
||||||
|
description: Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.
|
||||||
|
type: boolean
|
||||||
|
subPath:
|
||||||
|
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
||||||
|
type: string
|
||||||
|
subPathExpr:
|
||||||
|
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- mountPath
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
dockerdContainerResources:
|
dockerdContainerResources:
|
||||||
description: ResourceRequirements describes the compute resource requirements.
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
properties:
|
properties:
|
||||||
@@ -412,7 +618,7 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
requests:
|
requests:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@@ -421,11 +627,13 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
dockerdWithinRunnerContainer:
|
dockerdWithinRunnerContainer:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
enableServiceLinks:
|
||||||
|
type: boolean
|
||||||
enterprise:
|
enterprise:
|
||||||
pattern: ^[^/]+$
|
pattern: ^[^/]+$
|
||||||
type: string
|
type: string
|
||||||
@@ -458,7 +666,7 @@ spec:
|
|||||||
- key
|
- key
|
||||||
type: object
|
type: object
|
||||||
fieldRef:
|
fieldRef:
|
||||||
description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP.'
|
description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels[''<KEY>'']`, `metadata.annotations[''<KEY>'']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.'
|
||||||
properties:
|
properties:
|
||||||
apiVersion:
|
apiVersion:
|
||||||
description: Version of the schema the FieldPath is written in terms of, defaults to "v1".
|
description: Version of the schema the FieldPath is written in terms of, defaults to "v1".
|
||||||
@@ -537,6 +745,8 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
ephemeral:
|
||||||
|
type: boolean
|
||||||
ephemeralContainers:
|
ephemeralContainers:
|
||||||
items:
|
items:
|
||||||
description: An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.
|
description: An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.
|
||||||
@@ -546,6 +756,20 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
group:
|
group:
|
||||||
type: string
|
type: string
|
||||||
|
hostAliases:
|
||||||
|
items:
|
||||||
|
description: HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the pod's hosts file.
|
||||||
|
properties:
|
||||||
|
hostnames:
|
||||||
|
description: Hostnames for the above IP address.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
ip:
|
||||||
|
description: IP address of the host file entry.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
image:
|
image:
|
||||||
type: string
|
type: string
|
||||||
imagePullPolicy:
|
imagePullPolicy:
|
||||||
@@ -591,7 +815,7 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
requests:
|
requests:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@@ -600,9 +824,12 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
runtimeClassName:
|
||||||
|
description: 'RuntimeClassName is the container runtime configuration that containers should run under. More info: https://kubernetes.io/docs/concepts/containers/runtime-class'
|
||||||
|
type: string
|
||||||
securityContext:
|
securityContext:
|
||||||
description: PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.
|
description: PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.
|
||||||
properties:
|
properties:
|
||||||
@@ -610,6 +837,9 @@ spec:
|
|||||||
description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: \n 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- \n If unset, the Kubelet will not modify the ownership and permissions of any volume."
|
description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: \n 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- \n If unset, the Kubelet will not modify the ownership and permissions of any volume."
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
type: integer
|
||||||
|
fsGroupChangePolicy:
|
||||||
|
description: 'fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.'
|
||||||
|
type: string
|
||||||
runAsGroup:
|
runAsGroup:
|
||||||
description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.
|
description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.
|
||||||
format: int64
|
format: int64
|
||||||
@@ -637,6 +867,18 @@ spec:
|
|||||||
description: User is a SELinux user label that applies to the container.
|
description: User is a SELinux user label that applies to the container.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
seccompProfile:
|
||||||
|
description: The seccomp options to use by the containers in this pod.
|
||||||
|
properties:
|
||||||
|
localhostProfile:
|
||||||
|
description: localhostProfile indicates a profile defined in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must only be set if type is "Localhost".
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: "type indicates which kind of seccomp profile will be applied. Valid options are: \n Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied."
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
supplementalGroups:
|
supplementalGroups:
|
||||||
description: A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.
|
description: A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.
|
||||||
items:
|
items:
|
||||||
@@ -663,13 +905,13 @@ spec:
|
|||||||
description: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
description: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||||
properties:
|
properties:
|
||||||
gmsaCredentialSpec:
|
gmsaCredentialSpec:
|
||||||
description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.
|
description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field.
|
||||||
type: string
|
type: string
|
||||||
gmsaCredentialSpecName:
|
gmsaCredentialSpecName:
|
||||||
description: GMSACredentialSpecName is the name of the GMSA credential spec to use. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.
|
description: GMSACredentialSpecName is the name of the GMSA credential spec to use.
|
||||||
type: string
|
type: string
|
||||||
runAsUserName:
|
runAsUserName:
|
||||||
description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. This field is alpha-level and it is only honored by servers that enable the WindowsRunAsUserName feature flag.
|
description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
@@ -727,13 +969,19 @@ spec:
|
|||||||
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
||||||
type: string
|
type: string
|
||||||
subPathExpr:
|
subPathExpr:
|
||||||
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive. This field is beta in 1.15.
|
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive.
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- mountPath
|
- mountPath
|
||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
volumeSizeLimit:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
volumes:
|
volumes:
|
||||||
items:
|
items:
|
||||||
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||||
@@ -854,7 +1102,7 @@ spec:
|
|||||||
description: ConfigMap represents a configMap that should populate this volume
|
description: ConfigMap represents a configMap that should populate this volume
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -866,7 +1114,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -885,7 +1133,7 @@ spec:
|
|||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
csi:
|
csi:
|
||||||
description: CSI (Container Storage Interface) represents storage that is handled by an external CSI driver (Alpha feature).
|
description: CSI (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).
|
||||||
properties:
|
properties:
|
||||||
driver:
|
driver:
|
||||||
description: Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.
|
description: Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.
|
||||||
@@ -915,7 +1163,7 @@ spec:
|
|||||||
description: DownwardAPI represents downward API about the pod that should populate this volume
|
description: DownwardAPI represents downward API about the pod that should populate this volume
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits to use on created files by default. Must be a Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -936,7 +1184,7 @@ spec:
|
|||||||
- fieldPath
|
- fieldPath
|
||||||
type: object
|
type: object
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -980,6 +1228,122 @@ spec:
|
|||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
type: object
|
type: object
|
||||||
|
ephemeral:
|
||||||
|
description: "Ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. \n Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity tracking are needed, c) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through a PersistentVolumeClaim (see EphemeralVolumeSource for more information on the connection between this volume type and PersistentVolumeClaim). \n Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. \n Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. \n A pod can use both types of ephemeral volumes and persistent volumes at the same time. \n This is a beta feature and only available when the GenericEphemeralVolume feature gate is enabled."
|
||||||
|
properties:
|
||||||
|
volumeClaimTemplate:
|
||||||
|
description: "Will be used to create a stand-alone PVC to provision the volume. The pod in which this EphemeralVolumeSource is embedded will be the owner of the PVC, i.e. the PVC will be deleted together with the pod. The name of the PVC will be `<pod name>-<volume name>` where `<volume name>` is the name from the `PodSpec.Volumes` array entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). \n An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until the unrelated PVC is removed. If such a pre-created PVC is meant to be used by the pod, the PVC has to updated with an owner reference to the pod once the pod exists. Normally this should not be necessary, but it may be useful when manually reconstructing a broken cluster. \n This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. \n Required, must not be nil."
|
||||||
|
properties:
|
||||||
|
metadata:
|
||||||
|
description: May contain labels and annotations that will be copied into the PVC when creating it. No other fields are allowed and will be rejected during validation.
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
finalizers:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
labels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
description: The specification for the PersistentVolumeClaim. The entire content is copied unchanged into the PVC that gets created from this template. The same fields as in a PersistentVolumeClaim are also valid here.
|
||||||
|
properties:
|
||||||
|
accessModes:
|
||||||
|
description: 'AccessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
dataSource:
|
||||||
|
description: 'This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source.'
|
||||||
|
properties:
|
||||||
|
apiGroup:
|
||||||
|
description: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required.
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: Kind is the type of resource being referenced
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: Name is the name of resource being referenced
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- kind
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
resources:
|
||||||
|
description: 'Resources represents the minimum resources the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
|
||||||
|
properties:
|
||||||
|
limits:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
|
type: object
|
||||||
|
requests:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
selector:
|
||||||
|
description: A label query over volumes to consider for binding.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
storageClassName:
|
||||||
|
description: 'Name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
|
||||||
|
type: string
|
||||||
|
volumeMode:
|
||||||
|
description: volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec.
|
||||||
|
type: string
|
||||||
|
volumeName:
|
||||||
|
description: VolumeName is the binding reference to the PersistentVolume backing this claim.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- spec
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
fc:
|
fc:
|
||||||
description: FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
description: FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
||||||
properties:
|
properties:
|
||||||
@@ -1213,7 +1577,7 @@ spec:
|
|||||||
description: Items for all in one resources secrets, configmaps, and downward API
|
description: Items for all in one resources secrets, configmaps, and downward API
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.
|
description: Mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
sources:
|
sources:
|
||||||
@@ -1233,7 +1597,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1272,7 +1636,7 @@ spec:
|
|||||||
- fieldPath
|
- fieldPath
|
||||||
type: object
|
type: object
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1314,7 +1678,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1350,8 +1714,6 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
required:
|
|
||||||
- sources
|
|
||||||
type: object
|
type: object
|
||||||
quobyte:
|
quobyte:
|
||||||
description: Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
description: Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||||
@@ -1461,7 +1823,7 @@ spec:
|
|||||||
description: 'Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
|
description: 'Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -1473,7 +1835,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1546,22 +1908,26 @@ spec:
|
|||||||
status:
|
status:
|
||||||
properties:
|
properties:
|
||||||
availableReplicas:
|
availableReplicas:
|
||||||
|
description: AvailableReplicas is the total number of available runners which have been successfully registered to GitHub and still running. This corresponds to the sum of status.availableReplicas of all the runner replica sets.
|
||||||
type: integer
|
type: integer
|
||||||
desiredReplicas:
|
desiredReplicas:
|
||||||
description: Replicas 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.
|
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
|
type: integer
|
||||||
readyReplicas:
|
readyReplicas:
|
||||||
|
description: ReadyReplicas is the total number of available runners which have been successfully registered to GitHub and still running. This corresponds to the sum of status.readyReplicas of all the runner replica sets.
|
||||||
|
type: integer
|
||||||
|
replicas:
|
||||||
|
description: Replicas is the total number of replicas
|
||||||
|
type: integer
|
||||||
|
updatedReplicas:
|
||||||
|
description: ReadyReplicas is the total number of available runners which have been successfully registered to GitHub and still running. This corresponds to status.replicas of the runner replica set that has the desired template hash.
|
||||||
type: integer
|
type: integer
|
||||||
required:
|
|
||||||
- availableReplicas
|
|
||||||
- readyReplicas
|
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
version: v1alpha1
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
served: true
|
||||||
storage: true
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
status:
|
status:
|
||||||
acceptedNames:
|
acceptedNames:
|
||||||
kind: ""
|
kind: ""
|
||||||
|
|||||||
@@ -1,21 +1,11 @@
|
|||||||
apiVersion: apiextensions.k8s.io/v1beta1
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.3.0
|
controller-gen.kubebuilder.io/version: v0.6.0
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: runnerreplicasets.actions.summerwind.dev
|
name: runnerreplicasets.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
additionalPrinterColumns:
|
|
||||||
- JSONPath: .spec.replicas
|
|
||||||
name: Desired
|
|
||||||
type: number
|
|
||||||
- JSONPath: .status.availableReplicas
|
|
||||||
name: Current
|
|
||||||
type: number
|
|
||||||
- JSONPath: .status.readyReplicas
|
|
||||||
name: Ready
|
|
||||||
type: number
|
|
||||||
group: actions.summerwind.dev
|
group: actions.summerwind.dev
|
||||||
names:
|
names:
|
||||||
kind: RunnerReplicaSet
|
kind: RunnerReplicaSet
|
||||||
@@ -23,9 +13,22 @@ spec:
|
|||||||
plural: runnerreplicasets
|
plural: runnerreplicasets
|
||||||
singular: runnerreplicaset
|
singular: runnerreplicaset
|
||||||
scope: Namespaced
|
scope: Namespaced
|
||||||
subresources:
|
versions:
|
||||||
status: {}
|
- additionalPrinterColumns:
|
||||||
validation:
|
- jsonPath: .spec.replicas
|
||||||
|
name: Desired
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.replicas
|
||||||
|
name: Current
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.readyReplicas
|
||||||
|
name: Ready
|
||||||
|
type: number
|
||||||
|
- jsonPath: .metadata.creationTimestamp
|
||||||
|
name: Age
|
||||||
|
type: date
|
||||||
|
name: v1alpha1
|
||||||
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: RunnerReplicaSet is the Schema for the runnerreplicasets API
|
description: RunnerReplicaSet is the Schema for the runnerreplicasets API
|
||||||
properties:
|
properties:
|
||||||
@@ -43,9 +46,57 @@ spec:
|
|||||||
replicas:
|
replicas:
|
||||||
nullable: true
|
nullable: true
|
||||||
type: integer
|
type: integer
|
||||||
|
selector:
|
||||||
|
description: A label selector is a label query over a set of resources. The result of matchLabels and matchExpressions are ANDed. An empty label selector matches all objects. A null label selector matches no objects.
|
||||||
|
nullable: true
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
template:
|
template:
|
||||||
properties:
|
properties:
|
||||||
metadata:
|
metadata:
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
finalizers:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
labels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
spec:
|
spec:
|
||||||
description: RunnerSpec defines the desired state of Runner
|
description: RunnerSpec defines the desired state of Runner
|
||||||
@@ -213,8 +264,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -268,8 +349,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -322,8 +433,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -377,8 +518,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -402,6 +573,38 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
dockerEnabled:
|
dockerEnabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
dockerMTU:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
dockerRegistryMirror:
|
||||||
|
type: string
|
||||||
|
dockerVolumeMounts:
|
||||||
|
items:
|
||||||
|
description: VolumeMount describes a mounting of a Volume within a container.
|
||||||
|
properties:
|
||||||
|
mountPath:
|
||||||
|
description: Path within the container at which the volume should be mounted. Must not contain ':'.
|
||||||
|
type: string
|
||||||
|
mountPropagation:
|
||||||
|
description: mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: This must match the Name of a Volume.
|
||||||
|
type: string
|
||||||
|
readOnly:
|
||||||
|
description: Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.
|
||||||
|
type: boolean
|
||||||
|
subPath:
|
||||||
|
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
||||||
|
type: string
|
||||||
|
subPathExpr:
|
||||||
|
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- mountPath
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
dockerdContainerResources:
|
dockerdContainerResources:
|
||||||
description: ResourceRequirements describes the compute resource requirements.
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
properties:
|
properties:
|
||||||
@@ -412,7 +615,7 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
requests:
|
requests:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@@ -421,11 +624,13 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
dockerdWithinRunnerContainer:
|
dockerdWithinRunnerContainer:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
enableServiceLinks:
|
||||||
|
type: boolean
|
||||||
enterprise:
|
enterprise:
|
||||||
pattern: ^[^/]+$
|
pattern: ^[^/]+$
|
||||||
type: string
|
type: string
|
||||||
@@ -458,7 +663,7 @@ spec:
|
|||||||
- key
|
- key
|
||||||
type: object
|
type: object
|
||||||
fieldRef:
|
fieldRef:
|
||||||
description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP.'
|
description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels[''<KEY>'']`, `metadata.annotations[''<KEY>'']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.'
|
||||||
properties:
|
properties:
|
||||||
apiVersion:
|
apiVersion:
|
||||||
description: Version of the schema the FieldPath is written in terms of, defaults to "v1".
|
description: Version of the schema the FieldPath is written in terms of, defaults to "v1".
|
||||||
@@ -537,6 +742,8 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
ephemeral:
|
||||||
|
type: boolean
|
||||||
ephemeralContainers:
|
ephemeralContainers:
|
||||||
items:
|
items:
|
||||||
description: An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.
|
description: An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.
|
||||||
@@ -546,6 +753,20 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
group:
|
group:
|
||||||
type: string
|
type: string
|
||||||
|
hostAliases:
|
||||||
|
items:
|
||||||
|
description: HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the pod's hosts file.
|
||||||
|
properties:
|
||||||
|
hostnames:
|
||||||
|
description: Hostnames for the above IP address.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
ip:
|
||||||
|
description: IP address of the host file entry.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
image:
|
image:
|
||||||
type: string
|
type: string
|
||||||
imagePullPolicy:
|
imagePullPolicy:
|
||||||
@@ -591,7 +812,7 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
requests:
|
requests:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@@ -600,9 +821,12 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
runtimeClassName:
|
||||||
|
description: 'RuntimeClassName is the container runtime configuration that containers should run under. More info: https://kubernetes.io/docs/concepts/containers/runtime-class'
|
||||||
|
type: string
|
||||||
securityContext:
|
securityContext:
|
||||||
description: PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.
|
description: PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.
|
||||||
properties:
|
properties:
|
||||||
@@ -610,6 +834,9 @@ spec:
|
|||||||
description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: \n 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- \n If unset, the Kubelet will not modify the ownership and permissions of any volume."
|
description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: \n 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- \n If unset, the Kubelet will not modify the ownership and permissions of any volume."
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
type: integer
|
||||||
|
fsGroupChangePolicy:
|
||||||
|
description: 'fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.'
|
||||||
|
type: string
|
||||||
runAsGroup:
|
runAsGroup:
|
||||||
description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.
|
description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.
|
||||||
format: int64
|
format: int64
|
||||||
@@ -637,6 +864,18 @@ spec:
|
|||||||
description: User is a SELinux user label that applies to the container.
|
description: User is a SELinux user label that applies to the container.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
seccompProfile:
|
||||||
|
description: The seccomp options to use by the containers in this pod.
|
||||||
|
properties:
|
||||||
|
localhostProfile:
|
||||||
|
description: localhostProfile indicates a profile defined in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must only be set if type is "Localhost".
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: "type indicates which kind of seccomp profile will be applied. Valid options are: \n Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied."
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
supplementalGroups:
|
supplementalGroups:
|
||||||
description: A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.
|
description: A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.
|
||||||
items:
|
items:
|
||||||
@@ -663,13 +902,13 @@ spec:
|
|||||||
description: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
description: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||||
properties:
|
properties:
|
||||||
gmsaCredentialSpec:
|
gmsaCredentialSpec:
|
||||||
description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.
|
description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field.
|
||||||
type: string
|
type: string
|
||||||
gmsaCredentialSpecName:
|
gmsaCredentialSpecName:
|
||||||
description: GMSACredentialSpecName is the name of the GMSA credential spec to use. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.
|
description: GMSACredentialSpecName is the name of the GMSA credential spec to use.
|
||||||
type: string
|
type: string
|
||||||
runAsUserName:
|
runAsUserName:
|
||||||
description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. This field is alpha-level and it is only honored by servers that enable the WindowsRunAsUserName feature flag.
|
description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
@@ -727,13 +966,19 @@ spec:
|
|||||||
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
||||||
type: string
|
type: string
|
||||||
subPathExpr:
|
subPathExpr:
|
||||||
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive. This field is beta in 1.15.
|
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive.
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- mountPath
|
- mountPath
|
||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
volumeSizeLimit:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
volumes:
|
volumes:
|
||||||
items:
|
items:
|
||||||
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||||
@@ -854,7 +1099,7 @@ spec:
|
|||||||
description: ConfigMap represents a configMap that should populate this volume
|
description: ConfigMap represents a configMap that should populate this volume
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -866,7 +1111,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -885,7 +1130,7 @@ spec:
|
|||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
csi:
|
csi:
|
||||||
description: CSI (Container Storage Interface) represents storage that is handled by an external CSI driver (Alpha feature).
|
description: CSI (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).
|
||||||
properties:
|
properties:
|
||||||
driver:
|
driver:
|
||||||
description: Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.
|
description: Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.
|
||||||
@@ -915,7 +1160,7 @@ spec:
|
|||||||
description: DownwardAPI represents downward API about the pod that should populate this volume
|
description: DownwardAPI represents downward API about the pod that should populate this volume
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits to use on created files by default. Must be a Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -936,7 +1181,7 @@ spec:
|
|||||||
- fieldPath
|
- fieldPath
|
||||||
type: object
|
type: object
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -980,6 +1225,122 @@ spec:
|
|||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
type: object
|
type: object
|
||||||
|
ephemeral:
|
||||||
|
description: "Ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. \n Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity tracking are needed, c) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through a PersistentVolumeClaim (see EphemeralVolumeSource for more information on the connection between this volume type and PersistentVolumeClaim). \n Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. \n Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. \n A pod can use both types of ephemeral volumes and persistent volumes at the same time. \n This is a beta feature and only available when the GenericEphemeralVolume feature gate is enabled."
|
||||||
|
properties:
|
||||||
|
volumeClaimTemplate:
|
||||||
|
description: "Will be used to create a stand-alone PVC to provision the volume. The pod in which this EphemeralVolumeSource is embedded will be the owner of the PVC, i.e. the PVC will be deleted together with the pod. The name of the PVC will be `<pod name>-<volume name>` where `<volume name>` is the name from the `PodSpec.Volumes` array entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). \n An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until the unrelated PVC is removed. If such a pre-created PVC is meant to be used by the pod, the PVC has to updated with an owner reference to the pod once the pod exists. Normally this should not be necessary, but it may be useful when manually reconstructing a broken cluster. \n This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. \n Required, must not be nil."
|
||||||
|
properties:
|
||||||
|
metadata:
|
||||||
|
description: May contain labels and annotations that will be copied into the PVC when creating it. No other fields are allowed and will be rejected during validation.
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
finalizers:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
labels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
description: The specification for the PersistentVolumeClaim. The entire content is copied unchanged into the PVC that gets created from this template. The same fields as in a PersistentVolumeClaim are also valid here.
|
||||||
|
properties:
|
||||||
|
accessModes:
|
||||||
|
description: 'AccessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
dataSource:
|
||||||
|
description: 'This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source.'
|
||||||
|
properties:
|
||||||
|
apiGroup:
|
||||||
|
description: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required.
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: Kind is the type of resource being referenced
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: Name is the name of resource being referenced
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- kind
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
resources:
|
||||||
|
description: 'Resources represents the minimum resources the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
|
||||||
|
properties:
|
||||||
|
limits:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
|
type: object
|
||||||
|
requests:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
selector:
|
||||||
|
description: A label query over volumes to consider for binding.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
storageClassName:
|
||||||
|
description: 'Name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
|
||||||
|
type: string
|
||||||
|
volumeMode:
|
||||||
|
description: volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec.
|
||||||
|
type: string
|
||||||
|
volumeName:
|
||||||
|
description: VolumeName is the binding reference to the PersistentVolume backing this claim.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- spec
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
fc:
|
fc:
|
||||||
description: FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
description: FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
||||||
properties:
|
properties:
|
||||||
@@ -1213,7 +1574,7 @@ spec:
|
|||||||
description: Items for all in one resources secrets, configmaps, and downward API
|
description: Items for all in one resources secrets, configmaps, and downward API
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.
|
description: Mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
sources:
|
sources:
|
||||||
@@ -1233,7 +1594,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1272,7 +1633,7 @@ spec:
|
|||||||
- fieldPath
|
- fieldPath
|
||||||
type: object
|
type: object
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1314,7 +1675,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1350,8 +1711,6 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
required:
|
|
||||||
- sources
|
|
||||||
type: object
|
type: object
|
||||||
quobyte:
|
quobyte:
|
||||||
description: Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
description: Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||||
@@ -1461,7 +1820,7 @@ spec:
|
|||||||
description: 'Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
|
description: 'Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -1473,7 +1832,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1546,19 +1905,23 @@ spec:
|
|||||||
status:
|
status:
|
||||||
properties:
|
properties:
|
||||||
availableReplicas:
|
availableReplicas:
|
||||||
|
description: AvailableReplicas is the number of runners that are created and Runnning. This is currently same as ReadyReplicas but perserved for future use.
|
||||||
type: integer
|
type: integer
|
||||||
readyReplicas:
|
readyReplicas:
|
||||||
|
description: ReadyReplicas is the number of runners that are created and Runnning.
|
||||||
|
type: integer
|
||||||
|
replicas:
|
||||||
|
description: Replicas is the number of runners that are created and still being managed by this runner replica set.
|
||||||
type: integer
|
type: integer
|
||||||
required:
|
required:
|
||||||
- availableReplicas
|
- availableReplicas
|
||||||
- readyReplicas
|
- readyReplicas
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
version: v1alpha1
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
served: true
|
||||||
storage: true
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
status:
|
status:
|
||||||
acceptedNames:
|
acceptedNames:
|
||||||
kind: ""
|
kind: ""
|
||||||
|
|||||||
@@ -1,27 +1,11 @@
|
|||||||
apiVersion: apiextensions.k8s.io/v1beta1
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.3.0
|
controller-gen.kubebuilder.io/version: v0.6.0
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: runners.actions.summerwind.dev
|
name: runners.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
additionalPrinterColumns:
|
|
||||||
- JSONPath: .spec.enterprise
|
|
||||||
name: Enterprise
|
|
||||||
type: string
|
|
||||||
- JSONPath: .spec.organization
|
|
||||||
name: Organization
|
|
||||||
type: string
|
|
||||||
- JSONPath: .spec.repository
|
|
||||||
name: Repository
|
|
||||||
type: string
|
|
||||||
- JSONPath: .spec.labels
|
|
||||||
name: Labels
|
|
||||||
type: string
|
|
||||||
- JSONPath: .status.phase
|
|
||||||
name: Status
|
|
||||||
type: string
|
|
||||||
group: actions.summerwind.dev
|
group: actions.summerwind.dev
|
||||||
names:
|
names:
|
||||||
kind: Runner
|
kind: Runner
|
||||||
@@ -29,9 +13,28 @@ spec:
|
|||||||
plural: runners
|
plural: runners
|
||||||
singular: runner
|
singular: runner
|
||||||
scope: Namespaced
|
scope: Namespaced
|
||||||
subresources:
|
versions:
|
||||||
status: {}
|
- additionalPrinterColumns:
|
||||||
validation:
|
- jsonPath: .spec.enterprise
|
||||||
|
name: Enterprise
|
||||||
|
type: string
|
||||||
|
- jsonPath: .spec.organization
|
||||||
|
name: Organization
|
||||||
|
type: string
|
||||||
|
- jsonPath: .spec.repository
|
||||||
|
name: Repository
|
||||||
|
type: string
|
||||||
|
- jsonPath: .spec.labels
|
||||||
|
name: Labels
|
||||||
|
type: string
|
||||||
|
- jsonPath: .status.phase
|
||||||
|
name: Status
|
||||||
|
type: string
|
||||||
|
- jsonPath: .metadata.creationTimestamp
|
||||||
|
name: Age
|
||||||
|
type: date
|
||||||
|
name: v1alpha1
|
||||||
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: Runner is the Schema for the runners API
|
description: Runner is the Schema for the runners API
|
||||||
properties:
|
properties:
|
||||||
@@ -209,8 +212,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -264,8 +297,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -318,8 +381,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -373,8 +466,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -398,6 +521,38 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
dockerEnabled:
|
dockerEnabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
dockerMTU:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
dockerRegistryMirror:
|
||||||
|
type: string
|
||||||
|
dockerVolumeMounts:
|
||||||
|
items:
|
||||||
|
description: VolumeMount describes a mounting of a Volume within a container.
|
||||||
|
properties:
|
||||||
|
mountPath:
|
||||||
|
description: Path within the container at which the volume should be mounted. Must not contain ':'.
|
||||||
|
type: string
|
||||||
|
mountPropagation:
|
||||||
|
description: mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: This must match the Name of a Volume.
|
||||||
|
type: string
|
||||||
|
readOnly:
|
||||||
|
description: Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.
|
||||||
|
type: boolean
|
||||||
|
subPath:
|
||||||
|
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
||||||
|
type: string
|
||||||
|
subPathExpr:
|
||||||
|
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- mountPath
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
dockerdContainerResources:
|
dockerdContainerResources:
|
||||||
description: ResourceRequirements describes the compute resource requirements.
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
properties:
|
properties:
|
||||||
@@ -408,7 +563,7 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
requests:
|
requests:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@@ -417,11 +572,13 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
dockerdWithinRunnerContainer:
|
dockerdWithinRunnerContainer:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
enableServiceLinks:
|
||||||
|
type: boolean
|
||||||
enterprise:
|
enterprise:
|
||||||
pattern: ^[^/]+$
|
pattern: ^[^/]+$
|
||||||
type: string
|
type: string
|
||||||
@@ -454,7 +611,7 @@ spec:
|
|||||||
- key
|
- key
|
||||||
type: object
|
type: object
|
||||||
fieldRef:
|
fieldRef:
|
||||||
description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP.'
|
description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels[''<KEY>'']`, `metadata.annotations[''<KEY>'']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.'
|
||||||
properties:
|
properties:
|
||||||
apiVersion:
|
apiVersion:
|
||||||
description: Version of the schema the FieldPath is written in terms of, defaults to "v1".
|
description: Version of the schema the FieldPath is written in terms of, defaults to "v1".
|
||||||
@@ -533,6 +690,8 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
ephemeral:
|
||||||
|
type: boolean
|
||||||
ephemeralContainers:
|
ephemeralContainers:
|
||||||
items:
|
items:
|
||||||
description: An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.
|
description: An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.
|
||||||
@@ -542,6 +701,20 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
group:
|
group:
|
||||||
type: string
|
type: string
|
||||||
|
hostAliases:
|
||||||
|
items:
|
||||||
|
description: HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the pod's hosts file.
|
||||||
|
properties:
|
||||||
|
hostnames:
|
||||||
|
description: Hostnames for the above IP address.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
ip:
|
||||||
|
description: IP address of the host file entry.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
image:
|
image:
|
||||||
type: string
|
type: string
|
||||||
imagePullPolicy:
|
imagePullPolicy:
|
||||||
@@ -587,7 +760,7 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
requests:
|
requests:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@@ -596,9 +769,12 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
runtimeClassName:
|
||||||
|
description: 'RuntimeClassName is the container runtime configuration that containers should run under. More info: https://kubernetes.io/docs/concepts/containers/runtime-class'
|
||||||
|
type: string
|
||||||
securityContext:
|
securityContext:
|
||||||
description: PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.
|
description: PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.
|
||||||
properties:
|
properties:
|
||||||
@@ -606,6 +782,9 @@ spec:
|
|||||||
description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: \n 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- \n If unset, the Kubelet will not modify the ownership and permissions of any volume."
|
description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: \n 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- \n If unset, the Kubelet will not modify the ownership and permissions of any volume."
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
type: integer
|
||||||
|
fsGroupChangePolicy:
|
||||||
|
description: 'fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.'
|
||||||
|
type: string
|
||||||
runAsGroup:
|
runAsGroup:
|
||||||
description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.
|
description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.
|
||||||
format: int64
|
format: int64
|
||||||
@@ -633,6 +812,18 @@ spec:
|
|||||||
description: User is a SELinux user label that applies to the container.
|
description: User is a SELinux user label that applies to the container.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
seccompProfile:
|
||||||
|
description: The seccomp options to use by the containers in this pod.
|
||||||
|
properties:
|
||||||
|
localhostProfile:
|
||||||
|
description: localhostProfile indicates a profile defined in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must only be set if type is "Localhost".
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: "type indicates which kind of seccomp profile will be applied. Valid options are: \n Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied."
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
supplementalGroups:
|
supplementalGroups:
|
||||||
description: A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.
|
description: A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.
|
||||||
items:
|
items:
|
||||||
@@ -659,13 +850,13 @@ spec:
|
|||||||
description: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
description: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||||
properties:
|
properties:
|
||||||
gmsaCredentialSpec:
|
gmsaCredentialSpec:
|
||||||
description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.
|
description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field.
|
||||||
type: string
|
type: string
|
||||||
gmsaCredentialSpecName:
|
gmsaCredentialSpecName:
|
||||||
description: GMSACredentialSpecName is the name of the GMSA credential spec to use. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.
|
description: GMSACredentialSpecName is the name of the GMSA credential spec to use.
|
||||||
type: string
|
type: string
|
||||||
runAsUserName:
|
runAsUserName:
|
||||||
description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. This field is alpha-level and it is only honored by servers that enable the WindowsRunAsUserName feature flag.
|
description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
@@ -723,13 +914,19 @@ spec:
|
|||||||
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
||||||
type: string
|
type: string
|
||||||
subPathExpr:
|
subPathExpr:
|
||||||
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive. This field is beta in 1.15.
|
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive.
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- mountPath
|
- mountPath
|
||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
volumeSizeLimit:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
volumes:
|
volumes:
|
||||||
items:
|
items:
|
||||||
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||||
@@ -850,7 +1047,7 @@ spec:
|
|||||||
description: ConfigMap represents a configMap that should populate this volume
|
description: ConfigMap represents a configMap that should populate this volume
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -862,7 +1059,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -881,7 +1078,7 @@ spec:
|
|||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
csi:
|
csi:
|
||||||
description: CSI (Container Storage Interface) represents storage that is handled by an external CSI driver (Alpha feature).
|
description: CSI (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).
|
||||||
properties:
|
properties:
|
||||||
driver:
|
driver:
|
||||||
description: Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.
|
description: Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.
|
||||||
@@ -911,7 +1108,7 @@ spec:
|
|||||||
description: DownwardAPI represents downward API about the pod that should populate this volume
|
description: DownwardAPI represents downward API about the pod that should populate this volume
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits to use on created files by default. Must be a Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -932,7 +1129,7 @@ spec:
|
|||||||
- fieldPath
|
- fieldPath
|
||||||
type: object
|
type: object
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -976,6 +1173,122 @@ spec:
|
|||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
type: object
|
type: object
|
||||||
|
ephemeral:
|
||||||
|
description: "Ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. \n Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity tracking are needed, c) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through a PersistentVolumeClaim (see EphemeralVolumeSource for more information on the connection between this volume type and PersistentVolumeClaim). \n Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. \n Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. \n A pod can use both types of ephemeral volumes and persistent volumes at the same time. \n This is a beta feature and only available when the GenericEphemeralVolume feature gate is enabled."
|
||||||
|
properties:
|
||||||
|
volumeClaimTemplate:
|
||||||
|
description: "Will be used to create a stand-alone PVC to provision the volume. The pod in which this EphemeralVolumeSource is embedded will be the owner of the PVC, i.e. the PVC will be deleted together with the pod. The name of the PVC will be `<pod name>-<volume name>` where `<volume name>` is the name from the `PodSpec.Volumes` array entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). \n An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until the unrelated PVC is removed. If such a pre-created PVC is meant to be used by the pod, the PVC has to updated with an owner reference to the pod once the pod exists. Normally this should not be necessary, but it may be useful when manually reconstructing a broken cluster. \n This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. \n Required, must not be nil."
|
||||||
|
properties:
|
||||||
|
metadata:
|
||||||
|
description: May contain labels and annotations that will be copied into the PVC when creating it. No other fields are allowed and will be rejected during validation.
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
finalizers:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
labels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
description: The specification for the PersistentVolumeClaim. The entire content is copied unchanged into the PVC that gets created from this template. The same fields as in a PersistentVolumeClaim are also valid here.
|
||||||
|
properties:
|
||||||
|
accessModes:
|
||||||
|
description: 'AccessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
dataSource:
|
||||||
|
description: 'This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source.'
|
||||||
|
properties:
|
||||||
|
apiGroup:
|
||||||
|
description: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required.
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: Kind is the type of resource being referenced
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: Name is the name of resource being referenced
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- kind
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
resources:
|
||||||
|
description: 'Resources represents the minimum resources the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
|
||||||
|
properties:
|
||||||
|
limits:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
|
type: object
|
||||||
|
requests:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
selector:
|
||||||
|
description: A label query over volumes to consider for binding.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
storageClassName:
|
||||||
|
description: 'Name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
|
||||||
|
type: string
|
||||||
|
volumeMode:
|
||||||
|
description: volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec.
|
||||||
|
type: string
|
||||||
|
volumeName:
|
||||||
|
description: VolumeName is the binding reference to the PersistentVolume backing this claim.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- spec
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
fc:
|
fc:
|
||||||
description: FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
description: FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
||||||
properties:
|
properties:
|
||||||
@@ -1209,7 +1522,7 @@ spec:
|
|||||||
description: Items for all in one resources secrets, configmaps, and downward API
|
description: Items for all in one resources secrets, configmaps, and downward API
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.
|
description: Mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
sources:
|
sources:
|
||||||
@@ -1229,7 +1542,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1268,7 +1581,7 @@ spec:
|
|||||||
- fieldPath
|
- fieldPath
|
||||||
type: object
|
type: object
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1310,7 +1623,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1346,8 +1659,6 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
required:
|
|
||||||
- sources
|
|
||||||
type: object
|
type: object
|
||||||
quobyte:
|
quobyte:
|
||||||
description: Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
description: Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||||
@@ -1457,7 +1768,7 @@ spec:
|
|||||||
description: 'Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
|
description: 'Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -1469,7 +1780,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1538,6 +1849,10 @@ spec:
|
|||||||
status:
|
status:
|
||||||
description: RunnerStatus defines the observed state of Runner
|
description: RunnerStatus defines the observed state of Runner
|
||||||
properties:
|
properties:
|
||||||
|
lastRegistrationCheckTime:
|
||||||
|
format: date-time
|
||||||
|
nullable: true
|
||||||
|
type: string
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
phase:
|
phase:
|
||||||
@@ -1566,18 +1881,12 @@ spec:
|
|||||||
- expiresAt
|
- expiresAt
|
||||||
- token
|
- token
|
||||||
type: object
|
type: object
|
||||||
required:
|
|
||||||
- message
|
|
||||||
- phase
|
|
||||||
- reason
|
|
||||||
- registration
|
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
version: v1alpha1
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
served: true
|
||||||
storage: true
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
status:
|
status:
|
||||||
acceptedNames:
|
acceptedNames:
|
||||||
kind: ""
|
kind: ""
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
40
charts/actions-runner-controller/docs/UPGRADING.md
Normal file
40
charts/actions-runner-controller/docs/UPGRADING.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
## Upgrading
|
||||||
|
|
||||||
|
This project makes extensive use of CRDs to provide much of its functionality. Helm unfortunately does not support [managing](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/) CRDs by design:
|
||||||
|
|
||||||
|
_The full breakdown as to how they came to this decision and why they have taken the approach they have for dealing with CRDs can be found in [Helm Improvement Proposal 11](https://github.com/helm/community/blob/main/hips/hip-0011.md)_
|
||||||
|
|
||||||
|
```
|
||||||
|
There is no support at this time for upgrading or deleting CRDs using Helm. This was an explicit decision after much
|
||||||
|
community discussion due to the danger for unintentional data loss. Furthermore, there is currently no community
|
||||||
|
consensus around how to handle CRDs and their lifecycle. As this evolves, Helm will add support for those use cases.
|
||||||
|
```
|
||||||
|
|
||||||
|
Helm will do an initial install of CRDs but it will not touch them afterwards (update or delete).
|
||||||
|
|
||||||
|
Additionally, because the project leverages CRDs so extensively you **MUST** run the matching controller app container with its matching CRDs i.e. always redeploy your CRDs if you are changing the app version.
|
||||||
|
|
||||||
|
Due to the above you can't just do a `helm upgrade` to release the latest version of the chart, the best practice steps are recorded below:
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
1. Upgrade CRDs
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# REMEMBER TO UPDATE THE CHART_VERSION TO RELEVANT CHART VERISON!!!!
|
||||||
|
CHART_VERSION=0.11.0
|
||||||
|
|
||||||
|
curl -L https://github.com/actions-runner-controller/actions-runner-controller/releases/download/actions-runner-controller-${CHART_VERSION}/actions-runner-controller-${CHART_VERSION}.tgz | tar zxv --strip 1 actions-runner-controller/crds
|
||||||
|
|
||||||
|
kubectl apply -f crds/
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Upgrade the Helm release
|
||||||
|
|
||||||
|
```shell
|
||||||
|
helm upgrade --install \
|
||||||
|
--namespace actions-runner-system \
|
||||||
|
--version ${CHART_VERSION} \
|
||||||
|
actions-runner-controller/actions-runner-controller \
|
||||||
|
actions-runner-controller
|
||||||
|
```
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
1. Get the application URL by running these commands:
|
1. Get the application URL by running these commands:
|
||||||
{{- if .Values.ingress.enabled }}
|
{{- if .Values.githubWebhookServer.ingress.enabled }}
|
||||||
{{- range $host := .Values.ingress.hosts }}
|
{{- range $host := .Values.githubWebhookServer.ingress.hosts }}
|
||||||
{{- range .paths }}
|
{{- range .paths }}
|
||||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }}
|
http{{ if $.Values.githubWebhookServer.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- else if contains "NodePort" .Values.service.type }}
|
{{- else if contains "NodePort" .Values.service.type }}
|
||||||
|
|||||||
@@ -47,6 +47,14 @@ Create the name of the service account to use
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "actions-runner-controller-github-webhook-server.secretName" -}}
|
||||||
|
{{- default (include "actions-runner-controller-github-webhook-server.fullname" .) .Values.githubWebhookServer.secret.name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
{{- define "actions-runner-controller-github-webhook-server.roleName" -}}
|
{{- define "actions-runner-controller-github-webhook-server.roleName" -}}
|
||||||
{{- include "actions-runner-controller-github-webhook-server.fullname" . }}
|
{{- include "actions-runner-controller-github-webhook-server.fullname" . }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "actions-runner-controller-github-webhook-server.serviceMonitorName" -}}
|
||||||
|
{{- include "actions-runner-controller-github-webhook-server.fullname" . | trunc 47 }}-service-monitor
|
||||||
|
{{- end }}
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ Create the name of the service account to use
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "actions-runner-controller.secretName" -}}
|
||||||
|
{{- default (include "actions-runner-controller.fullname" .) .Values.authSecret.name -}}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
{{- define "actions-runner-controller.leaderElectionRoleName" -}}
|
{{- define "actions-runner-controller.leaderElectionRoleName" -}}
|
||||||
{{- include "actions-runner-controller.fullname" . }}-leader-election
|
{{- include "actions-runner-controller.fullname" . }}-leader-election
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -88,10 +92,14 @@ Create the name of the service account to use
|
|||||||
{{- include "actions-runner-controller.fullname" . | trunc 55 }}-webhook
|
{{- include "actions-runner-controller.fullname" . | trunc 55 }}-webhook
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- define "actions-runner-controller.authProxyServiceName" -}}
|
{{- define "actions-runner-controller.metricsServiceName" -}}
|
||||||
{{- include "actions-runner-controller.fullname" . | trunc 47 }}-metrics-service
|
{{- include "actions-runner-controller.fullname" . | trunc 47 }}-metrics-service
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "actions-runner-controller.serviceMonitorName" -}}
|
||||||
|
{{- include "actions-runner-controller.fullname" . | trunc 47 }}-service-monitor
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
{{- define "actions-runner-controller.selfsignedIssuerName" -}}
|
{{- define "actions-runner-controller.selfsignedIssuerName" -}}
|
||||||
{{- include "actions-runner-controller.fullname" . }}-selfsigned-issuer
|
{{- include "actions-runner-controller.fullname" . }}-selfsigned-issuer
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{{- if .Values.metrics.proxy.enabled }}
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRole
|
kind: ClusterRole
|
||||||
metadata:
|
metadata:
|
||||||
@@ -11,3 +12,4 @@ rules:
|
|||||||
resources:
|
resources:
|
||||||
- subjectaccessreviews
|
- subjectaccessreviews
|
||||||
verbs: ["create"]
|
verbs: ["create"]
|
||||||
|
{{- end }}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{{- if .Values.metrics.proxy.enabled }}
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
metadata:
|
metadata:
|
||||||
@@ -10,3 +11,4 @@ subjects:
|
|||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: {{ include "actions-runner-controller.serviceAccountName" . }}
|
name: {{ include "actions-runner-controller.serviceAccountName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
|
{{- end }}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ apiVersion: cert-manager.io/v1
|
|||||||
kind: Issuer
|
kind: Issuer
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "actions-runner-controller.selfsignedIssuerName" . }}
|
name: {{ include "actions-runner-controller.selfsignedIssuerName" . }}
|
||||||
namespace: {{ .Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
spec:
|
spec:
|
||||||
selfSigned: {}
|
selfSigned: {}
|
||||||
---
|
---
|
||||||
@@ -13,7 +13,7 @@ apiVersion: cert-manager.io/v1
|
|||||||
kind: Certificate
|
kind: Certificate
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "actions-runner-controller.servingCertName" . }}
|
name: {{ include "actions-runner-controller.servingCertName" . }}
|
||||||
namespace: {{ .Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
spec:
|
spec:
|
||||||
dnsNames:
|
dnsNames:
|
||||||
- {{ include "actions-runner-controller.webhookServiceName" . }}.{{ .Release.Namespace }}.svc
|
- {{ include "actions-runner-controller.webhookServiceName" . }}.{{ .Release.Namespace }}.svc
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ kind: Service
|
|||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
name: {{ include "actions-runner-controller.authProxyServiceName" . }}
|
name: {{ include "actions-runner-controller.metricsServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
spec:
|
spec:
|
||||||
ports:
|
ports:
|
||||||
- name: https
|
- name: metrics-port
|
||||||
port: 8443
|
port: {{ .Values.metrics.port }}
|
||||||
targetPort: https
|
targetPort: metrics-port
|
||||||
selector:
|
selector:
|
||||||
{{- include "actions-runner-controller.selectorLabels" . | nindent 4 }}
|
{{- include "actions-runner-controller.selectorLabels" . | nindent 4 }}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{{- if .Values.metrics.serviceMonitor }}
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: ServiceMonitor
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
|
name: {{ include "actions-runner-controller.serviceMonitorName" . }}
|
||||||
|
spec:
|
||||||
|
endpoints:
|
||||||
|
- path: /metrics
|
||||||
|
port: metrics-port
|
||||||
|
{{- if .Values.metrics.proxy.enabled }}
|
||||||
|
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
|
||||||
|
scheme: https
|
||||||
|
tlsConfig:
|
||||||
|
insecureSkipVerify: true
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "actions-runner-controller.selectorLabels" . | nindent 6 }}
|
||||||
|
{{- end }}
|
||||||
@@ -6,6 +6,7 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
spec:
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
{{- include "actions-runner-controller.selectorLabels" . | nindent 6 }}
|
{{- include "actions-runner-controller.selectorLabels" . | nindent 6 }}
|
||||||
@@ -17,6 +18,9 @@ spec:
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
labels:
|
labels:
|
||||||
{{- include "actions-runner-controller.selectorLabels" . | nindent 8 }}
|
{{- include "actions-runner-controller.selectorLabels" . | nindent 8 }}
|
||||||
|
{{- with .Values.podLabels }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
spec:
|
spec:
|
||||||
{{- with .Values.imagePullSecrets }}
|
{{- with .Values.imagePullSecrets }}
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
@@ -30,30 +34,46 @@ spec:
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
containers:
|
containers:
|
||||||
- args:
|
- args:
|
||||||
- "--metrics-addr=127.0.0.1:8080"
|
{{- $metricsHost := .Values.metrics.proxy.enabled | ternary "127.0.0.1" "0.0.0.0" }}
|
||||||
|
{{- $metricsPort := .Values.metrics.proxy.enabled | ternary "8080" .Values.metrics.port }}
|
||||||
|
- "--metrics-addr={{ $metricsHost }}:{{ $metricsPort }}"
|
||||||
- "--enable-leader-election"
|
- "--enable-leader-election"
|
||||||
- "--sync-period={{ .Values.syncPeriod }}"
|
- "--sync-period={{ .Values.syncPeriod }}"
|
||||||
- "--docker-image={{ .Values.image.dindSidecarRepositoryAndTag }}"
|
- "--docker-image={{ .Values.image.dindSidecarRepositoryAndTag }}"
|
||||||
|
- "--runner-image={{ .Values.image.actionsRunnerRepositoryAndTag }}"
|
||||||
|
{{- if .Values.scope.singleNamespace }}
|
||||||
|
- "--watch-namespace={{ default .Release.Namespace .Values.scope.watchNamespace }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.githubAPICacheDuration }}
|
||||||
|
- "--github-api-cache-duration={{ .Values.githubAPICacheDuration }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.logLevel }}
|
||||||
|
- "--log-level={{ .Values.logLevel }}"
|
||||||
|
{{- end }}
|
||||||
command:
|
command:
|
||||||
- "/manager"
|
- "/manager"
|
||||||
env:
|
env:
|
||||||
|
{{- if .Values.githubEnterpriseServerURL }}
|
||||||
|
- name: GITHUB_ENTERPRISE_URL
|
||||||
|
value: {{ .Values.githubEnterpriseServerURL }}
|
||||||
|
{{- end }}
|
||||||
- name: GITHUB_TOKEN
|
- name: GITHUB_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
key: github_token
|
key: github_token
|
||||||
name: controller-manager
|
name: {{ include "actions-runner-controller.secretName" . }}
|
||||||
optional: true
|
optional: true
|
||||||
- name: GITHUB_APP_ID
|
- name: GITHUB_APP_ID
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
key: github_app_id
|
key: github_app_id
|
||||||
name: controller-manager
|
name: {{ include "actions-runner-controller.secretName" . }}
|
||||||
optional: true
|
optional: true
|
||||||
- name: GITHUB_APP_INSTALLATION_ID
|
- name: GITHUB_APP_INSTALLATION_ID
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
key: github_app_installation_id
|
key: github_app_installation_id
|
||||||
name: controller-manager
|
name: {{ include "actions-runner-controller.secretName" . }}
|
||||||
optional: true
|
optional: true
|
||||||
- name: GITHUB_APP_PRIVATE_KEY
|
- name: GITHUB_APP_PRIVATE_KEY
|
||||||
value: /etc/actions-runner-controller/github_app_private_key
|
value: /etc/actions-runner-controller/github_app_private_key
|
||||||
@@ -68,39 +88,46 @@ spec:
|
|||||||
- containerPort: 9443
|
- containerPort: 9443
|
||||||
name: webhook-server
|
name: webhook-server
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
|
{{- if not .Values.metrics.proxy.enabled }}
|
||||||
|
- containerPort: {{ .Values.metrics.port }}
|
||||||
|
name: metrics-port
|
||||||
|
protocol: TCP
|
||||||
|
{{- end }}
|
||||||
resources:
|
resources:
|
||||||
{{- toYaml .Values.resources | nindent 12 }}
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
securityContext:
|
securityContext:
|
||||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- mountPath: "/etc/actions-runner-controller"
|
- mountPath: "/etc/actions-runner-controller"
|
||||||
name: controller-manager
|
name: secret
|
||||||
readOnly: true
|
readOnly: true
|
||||||
- mountPath: /tmp
|
- mountPath: /tmp
|
||||||
name: tmp
|
name: tmp
|
||||||
- mountPath: /tmp/k8s-webhook-server/serving-certs
|
- mountPath: /tmp/k8s-webhook-server/serving-certs
|
||||||
name: cert
|
name: cert
|
||||||
readOnly: true
|
readOnly: true
|
||||||
|
{{- if .Values.metrics.proxy.enabled }}
|
||||||
- args:
|
- args:
|
||||||
- "--secure-listen-address=0.0.0.0:8443"
|
- "--secure-listen-address=0.0.0.0:{{ .Values.metrics.port }}"
|
||||||
- "--upstream=http://127.0.0.1:8080/"
|
- "--upstream=http://127.0.0.1:8080/"
|
||||||
- "--logtostderr=true"
|
- "--logtostderr=true"
|
||||||
- "--v=10"
|
- "--v=10"
|
||||||
image: "{{ .Values.kube_rbac_proxy.image.repository }}:{{ .Values.kube_rbac_proxy.image.tag }}"
|
image: "{{ .Values.metrics.proxy.image.repository }}:{{ .Values.metrics.proxy.image.tag }}"
|
||||||
name: kube-rbac-proxy
|
name: kube-rbac-proxy
|
||||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8443
|
- containerPort: {{ .Values.metrics.port }}
|
||||||
name: https
|
name: metrics-port
|
||||||
resources:
|
resources:
|
||||||
{{- toYaml .Values.resources | nindent 12 }}
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
securityContext:
|
securityContext:
|
||||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
terminationGracePeriodSeconds: 10
|
terminationGracePeriodSeconds: 10
|
||||||
volumes:
|
volumes:
|
||||||
- name: controller-manager
|
- name: secret
|
||||||
secret:
|
secret:
|
||||||
secretName: controller-manager
|
secretName: {{ include "actions-runner-controller.secretName" . }}
|
||||||
- name: cert
|
- name: cert
|
||||||
secret:
|
secret:
|
||||||
defaultMode: 420
|
defaultMode: 420
|
||||||
@@ -119,3 +146,7 @@ spec:
|
|||||||
tolerations:
|
tolerations:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- with .Values.topologySpreadConstraints }}
|
||||||
|
topologySpreadConstraints:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
spec:
|
spec:
|
||||||
|
replicas: {{ .Values.githubWebhookServer.replicaCount }}
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
{{- include "actions-runner-controller-github-webhook-server.selectorLabels" . | nindent 6 }}
|
{{- include "actions-runner-controller-github-webhook-server.selectorLabels" . | nindent 6 }}
|
||||||
@@ -18,6 +19,9 @@ spec:
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
labels:
|
labels:
|
||||||
{{- include "actions-runner-controller-github-webhook-server.selectorLabels" . | nindent 8 }}
|
{{- include "actions-runner-controller-github-webhook-server.selectorLabels" . | nindent 8 }}
|
||||||
|
{{- with .Values.githubWebhookServer.podLabels }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
spec:
|
spec:
|
||||||
{{- with .Values.githubWebhookServer.imagePullSecrets }}
|
{{- with .Values.githubWebhookServer.imagePullSecrets }}
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
@@ -31,8 +35,13 @@ spec:
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
containers:
|
containers:
|
||||||
- args:
|
- args:
|
||||||
- "--metrics-addr=127.0.0.1:8080"
|
{{- $metricsHost := .Values.metrics.proxy.enabled | ternary "127.0.0.1" "0.0.0.0" }}
|
||||||
|
{{- $metricsPort := .Values.metrics.proxy.enabled | ternary "8080" .Values.metrics.port }}
|
||||||
|
- "--metrics-addr={{ $metricsHost }}:{{ $metricsPort }}"
|
||||||
- "--sync-period={{ .Values.githubWebhookServer.syncPeriod }}"
|
- "--sync-period={{ .Values.githubWebhookServer.syncPeriod }}"
|
||||||
|
{{- if .Values.githubWebhookServer.logLevel }}
|
||||||
|
- "--log-level={{ .Values.githubWebhookServer.logLevel }}"
|
||||||
|
{{- end }}
|
||||||
command:
|
command:
|
||||||
- "/github-webhook-server"
|
- "/github-webhook-server"
|
||||||
env:
|
env:
|
||||||
@@ -40,43 +49,46 @@ spec:
|
|||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
key: github_webhook_secret_token
|
key: github_webhook_secret_token
|
||||||
name: github-webhook-server
|
name: {{ include "actions-runner-controller-github-webhook-server.secretName" . }}
|
||||||
optional: true
|
optional: true
|
||||||
{{- range $key, $val := .Values.githubWebhookServer.env }}
|
{{- range $key, $val := .Values.githubWebhookServer.env }}
|
||||||
- name: {{ $key }}
|
- name: {{ $key }}
|
||||||
value: {{ $val | quote }}
|
value: {{ $val | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
image: "{{ .Values.githubWebhookServer.image.repository }}:{{ .Values.githubWebhookServer.image.tag | default (cat "v" .Chart.AppVersion | replace " " "") }}"
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default (cat "v" .Chart.AppVersion | replace " " "") }}"
|
||||||
name: github-webhook-server
|
name: github-webhook-server
|
||||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8000
|
- containerPort: 8000
|
||||||
name: http
|
name: http
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
|
{{- if not .Values.metrics.proxy.enabled }}
|
||||||
|
- containerPort: {{ .Values.metrics.port }}
|
||||||
|
name: metrics-port
|
||||||
|
protocol: TCP
|
||||||
|
{{- end }}
|
||||||
resources:
|
resources:
|
||||||
{{- toYaml .Values.githubWebhookServer.resources | nindent 12 }}
|
{{- toYaml .Values.githubWebhookServer.resources | nindent 12 }}
|
||||||
securityContext:
|
securityContext:
|
||||||
{{- toYaml .Values.githubWebhookServer.securityContext | nindent 12 }}
|
{{- toYaml .Values.githubWebhookServer.securityContext | nindent 12 }}
|
||||||
|
{{- if .Values.metrics.proxy.enabled }}
|
||||||
- args:
|
- args:
|
||||||
- "--secure-listen-address=0.0.0.0:8443"
|
- "--secure-listen-address=0.0.0.0:{{ .Values.metrics.port }}"
|
||||||
- "--upstream=http://127.0.0.1:8080/"
|
- "--upstream=http://127.0.0.1:8080/"
|
||||||
- "--logtostderr=true"
|
- "--logtostderr=true"
|
||||||
- "--v=10"
|
- "--v=10"
|
||||||
image: "{{ .Values.kube_rbac_proxy.image.repository }}:{{ .Values.kube_rbac_proxy.image.tag }}"
|
image: "{{ .Values.metrics.proxy.image.repository }}:{{ .Values.metrics.proxy.image.tag }}"
|
||||||
name: kube-rbac-proxy
|
name: kube-rbac-proxy
|
||||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8443
|
- containerPort: {{ .Values.metrics.port }}
|
||||||
name: https
|
name: metrics-port
|
||||||
resources:
|
resources:
|
||||||
{{- toYaml .Values.resources | nindent 12 }}
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
securityContext:
|
securityContext:
|
||||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
terminationGracePeriodSeconds: 10
|
terminationGracePeriodSeconds: 10
|
||||||
volumes:
|
|
||||||
- name: github-webhook-server
|
|
||||||
secret:
|
|
||||||
secretName: github-webhook-server
|
|
||||||
{{- with .Values.githubWebhookServer.nodeSelector }}
|
{{- with .Values.githubWebhookServer.nodeSelector }}
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
@@ -89,4 +101,8 @@ spec:
|
|||||||
tolerations:
|
tolerations:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- with .Values.githubWebhookServer.topologySpreadConstraints }}
|
||||||
|
topologySpreadConstraints:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
{{- if .Values.githubWebhookServer.ingress.enabled -}}
|
||||||
|
{{- $fullName := include "actions-runner-controller-github-webhook-server.fullname" . -}}
|
||||||
|
{{- $svcPort := (index .Values.githubWebhookServer.service.ports 0).port -}}
|
||||||
|
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||||
|
apiVersion: networking.k8s.io/v1beta1
|
||||||
|
{{- else -}}
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
{{- end }}
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
labels:
|
||||||
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.githubWebhookServer.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.githubWebhookServer.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.githubWebhookServer.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.githubWebhookServer.ingress.hosts }}
|
||||||
|
- host: {{ .host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
backend:
|
||||||
|
serviceName: {{ $fullName }}
|
||||||
|
servicePort: {{ $svcPort }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
{{- if .Values.githubWebhookServer.enabled }}
|
{{- if .Values.githubWebhookServer.enabled }}
|
||||||
{{- if .Values.githubWebhookServer.secret.enabled }}
|
{{- if .Values.githubWebhookServer.secret.create }}
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: github-webhook-server
|
name: {{ include "actions-runner-controller-github-webhook-server.secretName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
labels:
|
labels:
|
||||||
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
data:
|
||||||
{{- range $k, $v := .Values.githubWebhookServer.secret }}
|
{{- if .Values.githubWebhookServer.secret.github_webhook_secret_token }}
|
||||||
{{ $k }}: {{ $v | toString | b64enc }}
|
github_webhook_secret_token: {{ .Values.githubWebhookServer.secret.github_webhook_secret_token | toString | b64enc }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -6,12 +6,21 @@ metadata:
|
|||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
labels:
|
labels:
|
||||||
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
|
{{- if .Values.githubWebhookServer.service.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{ toYaml .Values.githubWebhookServer.service.annotations | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
spec:
|
spec:
|
||||||
type: {{ .Values.githubWebhookServer.service.type }}
|
type: {{ .Values.githubWebhookServer.service.type }}
|
||||||
ports:
|
ports:
|
||||||
{{ range $_, $port := .Values.githubWebhookServer.service.ports -}}
|
{{ range $_, $port := .Values.githubWebhookServer.service.ports -}}
|
||||||
- {{ $port | toYaml | nindent 6 }}
|
- {{ $port | toYaml | nindent 6 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.metrics.serviceMonitor }}
|
||||||
|
- name: metrics-port
|
||||||
|
port: {{ .Values.metrics.port }}
|
||||||
|
targetPort: metrics-port
|
||||||
|
{{- end }}
|
||||||
selector:
|
selector:
|
||||||
{{- include "actions-runner-controller-github-webhook-server.selectorLabels" . | nindent 4 }}
|
{{- include "actions-runner-controller-github-webhook-server.selectorLabels" . | nindent 4 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{{- if and .Values.githubWebhookServer.enabled .Values.metrics.serviceMonitor }}
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: ServiceMonitor
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
|
name: {{ include "actions-runner-controller-github-webhook-server.serviceMonitorName" . }}
|
||||||
|
spec:
|
||||||
|
endpoints:
|
||||||
|
- path: /metrics
|
||||||
|
port: metrics-port
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "actions-runner-controller-github-webhook-server.selectorLabels" . | nindent 6 }}
|
||||||
|
{{- end }}
|
||||||
@@ -132,6 +132,62 @@ rules:
|
|||||||
- get
|
- get
|
||||||
- patch
|
- patch
|
||||||
- update
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- actions.summerwind.dev
|
||||||
|
resources:
|
||||||
|
- runnersets
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- actions.summerwind.dev
|
||||||
|
resources:
|
||||||
|
- runnersets/finalizers
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- actions.summerwind.dev
|
||||||
|
resources:
|
||||||
|
- runnersets/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- "apps"
|
||||||
|
resources:
|
||||||
|
- statefulsets
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- "apps"
|
||||||
|
resources:
|
||||||
|
- statefulsets/finalizers
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- ""
|
||||||
resources:
|
resources:
|
||||||
@@ -139,6 +195,15 @@ rules:
|
|||||||
verbs:
|
verbs:
|
||||||
- create
|
- create
|
||||||
- patch
|
- patch
|
||||||
|
- apiGroups:
|
||||||
|
- coordination.k8s.io
|
||||||
|
resources:
|
||||||
|
- leases
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- update
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- ""
|
||||||
resources:
|
resources:
|
||||||
|
|||||||
@@ -1,14 +1,23 @@
|
|||||||
{{- if or .Values.authSecret.enabled }}
|
{{- if .Values.authSecret.create }}
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: controller-manager
|
name: {{ include "actions-runner-controller.secretName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
labels:
|
labels:
|
||||||
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
data:
|
||||||
{{- range $k, $v := .Values.authSecret }}
|
{{- if .Values.authSecret.github_app_id }}
|
||||||
{{ $k }}: {{ $v | toString | b64enc }}
|
github_app_id: {{ .Values.authSecret.github_app_id | toString | b64enc }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.authSecret.github_app_installation_id }}
|
||||||
|
github_app_installation_id: {{ .Values.authSecret.github_app_installation_id | toString | b64enc }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.authSecret.github_app_private_key }}
|
||||||
|
github_app_private_key: {{ .Values.authSecret.github_app_private_key | toString | b64enc }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.authSecret.github_token }}
|
||||||
|
github_token: {{ .Values.authSecret.github_token | toString | b64enc }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -9,7 +9,6 @@ metadata:
|
|||||||
cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "actions-runner-controller.servingCertName" . }}
|
cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "actions-runner-controller.servingCertName" . }}
|
||||||
webhooks:
|
webhooks:
|
||||||
- clientConfig:
|
- clientConfig:
|
||||||
caBundle: Cg==
|
|
||||||
service:
|
service:
|
||||||
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -26,8 +25,8 @@ webhooks:
|
|||||||
- UPDATE
|
- UPDATE
|
||||||
resources:
|
resources:
|
||||||
- runners
|
- runners
|
||||||
|
sideEffects: None
|
||||||
- clientConfig:
|
- clientConfig:
|
||||||
caBundle: Cg==
|
|
||||||
service:
|
service:
|
||||||
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -44,8 +43,8 @@ webhooks:
|
|||||||
- UPDATE
|
- UPDATE
|
||||||
resources:
|
resources:
|
||||||
- runnerdeployments
|
- runnerdeployments
|
||||||
|
sideEffects: None
|
||||||
- clientConfig:
|
- clientConfig:
|
||||||
caBundle: Cg==
|
|
||||||
service:
|
service:
|
||||||
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -62,7 +61,27 @@ webhooks:
|
|||||||
- UPDATE
|
- UPDATE
|
||||||
resources:
|
resources:
|
||||||
- runnerreplicasets
|
- runnerreplicasets
|
||||||
|
sideEffects: None
|
||||||
|
- clientConfig:
|
||||||
|
service:
|
||||||
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
path: /mutate-runner-set-pod
|
||||||
|
failurePolicy: Fail
|
||||||
|
name: mutate-runner-pod.webhook.actions.summerwind.dev
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
apiVersions:
|
||||||
|
- v1
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
resources:
|
||||||
|
- pods
|
||||||
|
sideEffects: None
|
||||||
|
objectSelector:
|
||||||
|
matchLabels:
|
||||||
|
"actions-runner-controller/inject-registration-token": "true"
|
||||||
---
|
---
|
||||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||||
kind: ValidatingWebhookConfiguration
|
kind: ValidatingWebhookConfiguration
|
||||||
@@ -73,7 +92,6 @@ metadata:
|
|||||||
cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "actions-runner-controller.servingCertName" . }}
|
cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "actions-runner-controller.servingCertName" . }}
|
||||||
webhooks:
|
webhooks:
|
||||||
- clientConfig:
|
- clientConfig:
|
||||||
caBundle: Cg==
|
|
||||||
service:
|
service:
|
||||||
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -90,8 +108,8 @@ webhooks:
|
|||||||
- UPDATE
|
- UPDATE
|
||||||
resources:
|
resources:
|
||||||
- runners
|
- runners
|
||||||
|
sideEffects: None
|
||||||
- clientConfig:
|
- clientConfig:
|
||||||
caBundle: Cg==
|
|
||||||
service:
|
service:
|
||||||
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -108,8 +126,8 @@ webhooks:
|
|||||||
- UPDATE
|
- UPDATE
|
||||||
resources:
|
resources:
|
||||||
- runnerdeployments
|
- runnerdeployments
|
||||||
|
sideEffects: None
|
||||||
- clientConfig:
|
- clientConfig:
|
||||||
caBundle: Cg==
|
|
||||||
service:
|
service:
|
||||||
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -126,3 +144,4 @@ webhooks:
|
|||||||
- UPDATE
|
- UPDATE
|
||||||
resources:
|
resources:
|
||||||
- runnerreplicasets
|
- runnerreplicasets
|
||||||
|
sideEffects: None
|
||||||
|
|||||||
@@ -8,10 +8,19 @@ replicaCount: 1
|
|||||||
|
|
||||||
syncPeriod: 10m
|
syncPeriod: 10m
|
||||||
|
|
||||||
|
# The controller tries its best not to repeat the duplicate GitHub API call
|
||||||
|
# within this duration.
|
||||||
|
# Defaults to syncPeriod - 10s.
|
||||||
|
#githubAPICacheDuration: 30s
|
||||||
|
|
||||||
|
# The URL of your GitHub Enterprise server, if you're using one.
|
||||||
|
#githubEnterpriseServerURL: https://github.example.com
|
||||||
|
|
||||||
# Only 1 authentication method can be deployed at a time
|
# Only 1 authentication method can be deployed at a time
|
||||||
# Uncomment the configuration you are applying and fill in the details
|
# Uncomment the configuration you are applying and fill in the details
|
||||||
authSecret:
|
authSecret:
|
||||||
enabled: false
|
create: false
|
||||||
|
name: "controller-manager"
|
||||||
### GitHub Apps Configuration
|
### GitHub Apps Configuration
|
||||||
#github_app_id: ""
|
#github_app_id: ""
|
||||||
#github_app_installation_id: ""
|
#github_app_installation_id: ""
|
||||||
@@ -20,17 +29,11 @@ authSecret:
|
|||||||
#github_token: ""
|
#github_token: ""
|
||||||
|
|
||||||
image:
|
image:
|
||||||
repository: summerwind/actions-runner-controller
|
repository: "summerwind/actions-runner-controller"
|
||||||
# Overrides the manager image tag whose default is the chart appVersion if the tag key is commented out
|
actionsRunnerRepositoryAndTag: "summerwind/actions-runner:latest"
|
||||||
tag: "latest"
|
|
||||||
dindSidecarRepositoryAndTag: "docker:dind"
|
dindSidecarRepositoryAndTag: "docker:dind"
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
kube_rbac_proxy:
|
|
||||||
image:
|
|
||||||
repository: quay.io/brancz/kube-rbac-proxy
|
|
||||||
tag: v0.8.0
|
|
||||||
|
|
||||||
imagePullSecrets: []
|
imagePullSecrets: []
|
||||||
nameOverride: ""
|
nameOverride: ""
|
||||||
fullnameOverride: ""
|
fullnameOverride: ""
|
||||||
@@ -46,10 +49,14 @@ serviceAccount:
|
|||||||
|
|
||||||
podAnnotations: {}
|
podAnnotations: {}
|
||||||
|
|
||||||
podSecurityContext: {}
|
podLabels: {}
|
||||||
|
|
||||||
|
podSecurityContext:
|
||||||
|
{}
|
||||||
# fsGroup: 2000
|
# fsGroup: 2000
|
||||||
|
|
||||||
securityContext: {}
|
securityContext:
|
||||||
|
{}
|
||||||
# capabilities:
|
# capabilities:
|
||||||
# drop:
|
# drop:
|
||||||
# - ALL
|
# - ALL
|
||||||
@@ -61,20 +68,17 @@ service:
|
|||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
port: 443
|
port: 443
|
||||||
|
|
||||||
ingress:
|
metrics:
|
||||||
enabled: false
|
serviceMonitor: false
|
||||||
annotations: {}
|
port: 8443
|
||||||
# kubernetes.io/ingress.class: nginx
|
proxy:
|
||||||
# kubernetes.io/tls-acme: "true"
|
enabled: true
|
||||||
hosts:
|
image:
|
||||||
- host: chart-example.local
|
repository: quay.io/brancz/kube-rbac-proxy
|
||||||
paths: []
|
tag: v0.10.0
|
||||||
tls: []
|
|
||||||
# - secretName: chart-example-tls
|
|
||||||
# hosts:
|
|
||||||
# - chart-example.local
|
|
||||||
|
|
||||||
resources: {}
|
resources:
|
||||||
|
{}
|
||||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||||
# choice for the user. This also increases chances charts run on environments with little
|
# choice for the user. This also increases chances charts run on environments with little
|
||||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||||
@@ -86,13 +90,6 @@ resources: {}
|
|||||||
# cpu: 100m
|
# cpu: 100m
|
||||||
# memory: 128Mi
|
# memory: 128Mi
|
||||||
|
|
||||||
autoscaling:
|
|
||||||
enabled: false
|
|
||||||
minReplicas: 1
|
|
||||||
maxReplicas: 100
|
|
||||||
targetCPUUtilizationPercentage: 80
|
|
||||||
# targetMemoryUtilizationPercentage: 80
|
|
||||||
|
|
||||||
nodeSelector: {}
|
nodeSelector: {}
|
||||||
|
|
||||||
tolerations: []
|
tolerations: []
|
||||||
@@ -104,25 +101,28 @@ affinity: {}
|
|||||||
# PriorityClass: system-cluster-critical
|
# PriorityClass: system-cluster-critical
|
||||||
priorityClassName: ""
|
priorityClassName: ""
|
||||||
|
|
||||||
env: {}
|
env:
|
||||||
|
{}
|
||||||
# http_proxy: "proxy.com:8080"
|
# http_proxy: "proxy.com:8080"
|
||||||
# https_proxy: "proxy.com:8080"
|
# https_proxy: "proxy.com:8080"
|
||||||
# no_proxy: ""
|
# no_proxy: ""
|
||||||
|
|
||||||
|
scope:
|
||||||
|
# If true, the controller will only watch custom resources in a single namespace
|
||||||
|
singleNamespace: false
|
||||||
|
# If `scope.singleNamespace=true`, the controller will only watch custom resources in this namespace
|
||||||
|
# The default value is "", which means the namespace of the controller
|
||||||
|
watchNamespace: ""
|
||||||
|
|
||||||
githubWebhookServer:
|
githubWebhookServer:
|
||||||
enabled: false
|
enabled: false
|
||||||
labels: {}
|
|
||||||
replicaCount: 1
|
replicaCount: 1
|
||||||
syncPeriod: 10m
|
syncPeriod: 10m
|
||||||
secret:
|
secret:
|
||||||
enabled: false
|
create: false
|
||||||
|
name: "github-webhook-server"
|
||||||
### GitHub Webhook Configuration
|
### GitHub Webhook Configuration
|
||||||
#github_webhook_secret_token: ""
|
github_webhook_secret_token: ""
|
||||||
image:
|
|
||||||
repository: summerwind/actions-runner-controller
|
|
||||||
# Overrides the manager image tag whose default is the chart appVersion if the tag key is commented out
|
|
||||||
tag: "latest"
|
|
||||||
pullPolicy: IfNotPresent
|
|
||||||
imagePullSecrets: []
|
imagePullSecrets: []
|
||||||
nameOverride: ""
|
nameOverride: ""
|
||||||
fullnameOverride: ""
|
fullnameOverride: ""
|
||||||
@@ -135,6 +135,7 @@ githubWebhookServer:
|
|||||||
# If not set and create is true, a name is generated using the fullname template
|
# If not set and create is true, a name is generated using the fullname template
|
||||||
name: ""
|
name: ""
|
||||||
podAnnotations: {}
|
podAnnotations: {}
|
||||||
|
podLabels: {}
|
||||||
podSecurityContext: {}
|
podSecurityContext: {}
|
||||||
# fsGroup: 2000
|
# fsGroup: 2000
|
||||||
securityContext: {}
|
securityContext: {}
|
||||||
@@ -144,10 +145,24 @@ githubWebhookServer:
|
|||||||
affinity: {}
|
affinity: {}
|
||||||
priorityClassName: ""
|
priorityClassName: ""
|
||||||
service:
|
service:
|
||||||
type: NodePort
|
type: ClusterIP
|
||||||
|
annotations: {}
|
||||||
ports:
|
ports:
|
||||||
- port: 80
|
- port: 80
|
||||||
targetPort: http
|
targetPort: http
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
name: http
|
name: http
|
||||||
#nodePort: someFixedPortForUseWithTerraformCdkCfnEtc
|
#nodePort: someFixedPortForUseWithTerraformCdkCfnEtc
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
annotations:
|
||||||
|
{}
|
||||||
|
# kubernetes.io/ingress.class: nginx
|
||||||
|
# kubernetes.io/tls-acme: "true"
|
||||||
|
hosts:
|
||||||
|
- host: chart-example.local
|
||||||
|
paths: []
|
||||||
|
tls: []
|
||||||
|
# - secretName: chart-example-tls
|
||||||
|
# hosts:
|
||||||
|
# - chart-example.local
|
||||||
|
|||||||
@@ -25,8 +25,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
actionsv1alpha1 "github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
actionsv1alpha1 "github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
"github.com/summerwind/actions-runner-controller/controllers"
|
"github.com/actions-runner-controller/actions-runner-controller/controllers"
|
||||||
|
zaplib "go.uber.org/zap"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||||
_ "k8s.io/client-go/plugin/pkg/client/auth/exec"
|
_ "k8s.io/client-go/plugin/pkg/client/auth/exec"
|
||||||
@@ -42,6 +43,13 @@ var (
|
|||||||
setupLog = ctrl.Log.WithName("setup")
|
setupLog = ctrl.Log.WithName("setup")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
logLevelDebug = "debug"
|
||||||
|
logLevelInfo = "info"
|
||||||
|
logLevelWarn = "warn"
|
||||||
|
logLevelError = "error"
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
_ = clientgoscheme.AddToScheme(scheme)
|
_ = clientgoscheme.AddToScheme(scheme)
|
||||||
|
|
||||||
@@ -63,6 +71,7 @@ func main() {
|
|||||||
|
|
||||||
enableLeaderElection bool
|
enableLeaderElection bool
|
||||||
syncPeriod time.Duration
|
syncPeriod time.Duration
|
||||||
|
logLevel string
|
||||||
)
|
)
|
||||||
|
|
||||||
webhookSecretToken = os.Getenv("GITHUB_WEBHOOK_SECRET_TOKEN")
|
webhookSecretToken = os.Getenv("GITHUB_WEBHOOK_SECRET_TOKEN")
|
||||||
@@ -73,6 +82,7 @@ func main() {
|
|||||||
flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
|
flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
|
||||||
"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
|
"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
|
||||||
flag.DurationVar(&syncPeriod, "sync-period", 10*time.Minute, "Determines the minimum frequency at which K8s resources managed by this controller are reconciled. When you use autoscaling, set to a lower value like 10 minute, because this corresponds to the minimum time to react on demand change")
|
flag.DurationVar(&syncPeriod, "sync-period", 10*time.Minute, "Determines the minimum frequency at which K8s resources managed by this controller are reconciled. When you use autoscaling, set to a lower value like 10 minute, because this corresponds to the minimum time to react on demand change")
|
||||||
|
flag.StringVar(&logLevel, "log-level", logLevelDebug, `The verbosity of the logging. Valid values are "debug", "info", "warn", "error". Defaults to "debug".`)
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if webhookSecretToken == "" {
|
if webhookSecretToken == "" {
|
||||||
@@ -86,7 +96,19 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger := zap.New(func(o *zap.Options) {
|
logger := zap.New(func(o *zap.Options) {
|
||||||
|
switch logLevel {
|
||||||
|
case logLevelDebug:
|
||||||
o.Development = true
|
o.Development = true
|
||||||
|
case logLevelInfo:
|
||||||
|
lvl := zaplib.NewAtomicLevelAt(zaplib.InfoLevel)
|
||||||
|
o.Level = &lvl
|
||||||
|
case logLevelWarn:
|
||||||
|
lvl := zaplib.NewAtomicLevelAt(zaplib.WarnLevel)
|
||||||
|
o.Level = &lvl
|
||||||
|
case logLevelError:
|
||||||
|
lvl := zaplib.NewAtomicLevelAt(zaplib.ErrorLevel)
|
||||||
|
o.Level = &lvl
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ctrl.SetLogger(logger)
|
ctrl.SetLogger(logger)
|
||||||
@@ -110,7 +132,7 @@ func main() {
|
|||||||
Recorder: nil,
|
Recorder: nil,
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
SecretKeyBytes: []byte(webhookSecretToken),
|
SecretKeyBytes: []byte(webhookSecretToken),
|
||||||
WatchNamespace: watchNamespace,
|
Namespace: watchNamespace,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = hraGitHubWebhook.SetupWithManager(mgr); err != nil {
|
if err = hraGitHubWebhook.SetupWithManager(mgr); err != nil {
|
||||||
@@ -128,7 +150,7 @@ func main() {
|
|||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
setupLog.Info("starting webhook server")
|
setupLog.Info("starting webhook server")
|
||||||
if err := mgr.Start(ctx.Done()); err != nil {
|
if err := mgr.Start(ctx); err != nil {
|
||||||
setupLog.Error(err, "problem running manager")
|
setupLog.Error(err, "problem running manager")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
@@ -161,7 +183,7 @@ func main() {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
<-ctrl.SetupSignalHandler()
|
<-ctrl.SetupSignalHandler().Done()
|
||||||
cancel()
|
cancel()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,13 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: apiextensions.k8s.io/v1beta1
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.3.0
|
controller-gen.kubebuilder.io/version: v0.6.0
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: horizontalrunnerautoscalers.actions.summerwind.dev
|
name: horizontalrunnerautoscalers.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
additionalPrinterColumns:
|
|
||||||
- JSONPath: .spec.minReplicas
|
|
||||||
name: Min
|
|
||||||
type: number
|
|
||||||
- JSONPath: .spec.maxReplicas
|
|
||||||
name: Max
|
|
||||||
type: number
|
|
||||||
- JSONPath: .status.desiredReplicas
|
|
||||||
name: Desired
|
|
||||||
type: number
|
|
||||||
group: actions.summerwind.dev
|
group: actions.summerwind.dev
|
||||||
names:
|
names:
|
||||||
kind: HorizontalRunnerAutoscaler
|
kind: HorizontalRunnerAutoscaler
|
||||||
@@ -25,9 +15,22 @@ spec:
|
|||||||
plural: horizontalrunnerautoscalers
|
plural: horizontalrunnerautoscalers
|
||||||
singular: horizontalrunnerautoscaler
|
singular: horizontalrunnerautoscaler
|
||||||
scope: Namespaced
|
scope: Namespaced
|
||||||
subresources:
|
versions:
|
||||||
status: {}
|
- additionalPrinterColumns:
|
||||||
validation:
|
- jsonPath: .spec.minReplicas
|
||||||
|
name: Min
|
||||||
|
type: number
|
||||||
|
- jsonPath: .spec.maxReplicas
|
||||||
|
name: Max
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.desiredReplicas
|
||||||
|
name: Desired
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.scheduledOverridesSummary
|
||||||
|
name: Schedule
|
||||||
|
type: string
|
||||||
|
name: v1alpha1
|
||||||
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler
|
description: HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler
|
||||||
API
|
API
|
||||||
@@ -45,8 +48,8 @@ spec:
|
|||||||
metadata:
|
metadata:
|
||||||
type: object
|
type: object
|
||||||
spec:
|
spec:
|
||||||
description: HorizontalRunnerAutoscalerSpec defines the desired state of
|
description: HorizontalRunnerAutoscalerSpec defines the desired state
|
||||||
HorizontalRunnerAutoscaler
|
of HorizontalRunnerAutoscaler
|
||||||
properties:
|
properties:
|
||||||
capacityReservations:
|
capacityReservations:
|
||||||
items:
|
items:
|
||||||
@@ -72,16 +75,16 @@ spec:
|
|||||||
items:
|
items:
|
||||||
properties:
|
properties:
|
||||||
repositoryNames:
|
repositoryNames:
|
||||||
description: RepositoryNames is the list of repository names to
|
description: RepositoryNames is the list of repository names
|
||||||
be used for calculating the metric. For example, a repository
|
to be used for calculating the metric. For example, a repository
|
||||||
name is the REPO part of `github.com/USER/REPO`.
|
name is the REPO part of `github.com/USER/REPO`.
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
scaleDownAdjustment:
|
scaleDownAdjustment:
|
||||||
description: ScaleDownAdjustment is the number of runners removed
|
description: ScaleDownAdjustment is the number of runners removed
|
||||||
on scale-down. You can only specify either ScaleDownFactor or
|
on scale-down. You can only specify either ScaleDownFactor
|
||||||
ScaleDownAdjustment.
|
or ScaleDownAdjustment.
|
||||||
type: integer
|
type: integer
|
||||||
scaleDownFactor:
|
scaleDownFactor:
|
||||||
description: ScaleDownFactor is the multiplicative factor applied
|
description: ScaleDownFactor is the multiplicative factor applied
|
||||||
@@ -90,11 +93,13 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
scaleDownThreshold:
|
scaleDownThreshold:
|
||||||
description: ScaleDownThreshold is the percentage of busy runners
|
description: ScaleDownThreshold is the percentage of busy runners
|
||||||
less than which will trigger the hpa to scale the runners down.
|
less than which will trigger the hpa to scale the runners
|
||||||
|
down.
|
||||||
type: string
|
type: string
|
||||||
scaleUpAdjustment:
|
scaleUpAdjustment:
|
||||||
description: ScaleUpAdjustment is the number of runners added
|
description: ScaleUpAdjustment is the number of runners added
|
||||||
on scale-up. You can only specify either ScaleUpFactor or ScaleUpAdjustment.
|
on scale-up. You can only specify either ScaleUpFactor or
|
||||||
|
ScaleUpAdjustment.
|
||||||
type: integer
|
type: integer
|
||||||
scaleUpFactor:
|
scaleUpFactor:
|
||||||
description: ScaleUpFactor is the multiplicative factor applied
|
description: ScaleUpFactor is the multiplicative factor applied
|
||||||
@@ -116,27 +121,34 @@ spec:
|
|||||||
is allowed to scale
|
is allowed to scale
|
||||||
type: integer
|
type: integer
|
||||||
scaleDownDelaySecondsAfterScaleOut:
|
scaleDownDelaySecondsAfterScaleOut:
|
||||||
description: ScaleDownDelaySecondsAfterScaleUp is the approximate delay
|
description: ScaleDownDelaySecondsAfterScaleUp is the approximate
|
||||||
for a scale down followed by a scale up Used to prevent flapping (down->up->down->...
|
delay for a scale down followed by a scale up Used to prevent flapping
|
||||||
loop)
|
(down->up->down->... loop)
|
||||||
type: integer
|
type: integer
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
description: ScaleTargetRef sis the reference to scaled resource like
|
description: ScaleTargetRef sis the reference to scaled resource like
|
||||||
RunnerDeployment
|
RunnerDeployment
|
||||||
properties:
|
properties:
|
||||||
|
kind:
|
||||||
|
description: Kind is the type of resource being referenced
|
||||||
|
enum:
|
||||||
|
- RunnerDeployment
|
||||||
|
- RunnerSet
|
||||||
|
type: string
|
||||||
name:
|
name:
|
||||||
|
description: Name is the name of resource being referenced
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
scaleUpTriggers:
|
scaleUpTriggers:
|
||||||
description: "ScaleUpTriggers is an experimental feature to increase
|
description: "ScaleUpTriggers is an experimental feature to increase
|
||||||
the desired replicas by 1 on each webhook requested received by the
|
the desired replicas by 1 on each webhook requested received by
|
||||||
webhookBasedAutoscaler. \n This feature requires you to also enable
|
the webhookBasedAutoscaler. \n This feature requires you to also
|
||||||
and deploy the webhookBasedAutoscaler onto your cluster. \n Note that
|
enable and deploy the webhookBasedAutoscaler onto your cluster.
|
||||||
the added runners remain until the next sync period at least, and
|
\n Note that the added runners remain until the next sync period
|
||||||
they may or may not be used by GitHub Actions depending on the timing.
|
at least, and they may or may not be used by GitHub Actions depending
|
||||||
They are intended to be used to gain \"resource slack\" immediately
|
on the timing. They are intended to be used to gain \"resource slack\"
|
||||||
after you receive a webhook from GitHub, so that you can loosely expect
|
immediately after you receive a webhook from GitHub, so that you
|
||||||
MinReplicas runners to be always available."
|
can loosely expect MinReplicas runners to be always available."
|
||||||
items:
|
items:
|
||||||
properties:
|
properties:
|
||||||
amount:
|
amount:
|
||||||
@@ -148,6 +160,17 @@ spec:
|
|||||||
checkRun:
|
checkRun:
|
||||||
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#check_run
|
description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#check_run
|
||||||
properties:
|
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
|
||||||
status:
|
status:
|
||||||
type: string
|
type: string
|
||||||
types:
|
types:
|
||||||
@@ -174,6 +197,57 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
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 correspoding 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
|
type: object
|
||||||
status:
|
status:
|
||||||
properties:
|
properties:
|
||||||
@@ -191,11 +265,13 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
desiredReplicas:
|
desiredReplicas:
|
||||||
description: DesiredReplicas is the total number of desired, non-terminated
|
description: DesiredReplicas is the total number of desired, non-terminated
|
||||||
and latest pods to be set for the primary RunnerSet This doesn't include
|
and latest pods to be set for the primary RunnerSet This doesn't
|
||||||
outdated pods while upgrading the deployment and replacing the runnerset.
|
include outdated pods while upgrading the deployment and replacing
|
||||||
|
the runnerset.
|
||||||
type: integer
|
type: integer
|
||||||
lastSuccessfulScaleOutTime:
|
lastSuccessfulScaleOutTime:
|
||||||
format: date-time
|
format: date-time
|
||||||
|
nullable: true
|
||||||
type: string
|
type: string
|
||||||
observedGeneration:
|
observedGeneration:
|
||||||
description: ObservedGeneration is the most recent generation observed
|
description: ObservedGeneration is the most recent generation observed
|
||||||
@@ -203,13 +279,17 @@ spec:
|
|||||||
which is updated on mutation by the API Server.
|
which is updated on mutation by the API Server.
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
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
|
||||||
type: object
|
type: object
|
||||||
version: v1alpha1
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
served: true
|
||||||
storage: true
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
status:
|
status:
|
||||||
acceptedNames:
|
acceptedNames:
|
||||||
kind: ""
|
kind: ""
|
||||||
|
|||||||
@@ -1,21 +1,11 @@
|
|||||||
apiVersion: apiextensions.k8s.io/v1beta1
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.3.0
|
controller-gen.kubebuilder.io/version: v0.6.0
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: runnerdeployments.actions.summerwind.dev
|
name: runnerdeployments.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
additionalPrinterColumns:
|
|
||||||
- JSONPath: .spec.replicas
|
|
||||||
name: Desired
|
|
||||||
type: number
|
|
||||||
- JSONPath: .status.availableReplicas
|
|
||||||
name: Current
|
|
||||||
type: number
|
|
||||||
- JSONPath: .status.readyReplicas
|
|
||||||
name: Ready
|
|
||||||
type: number
|
|
||||||
group: actions.summerwind.dev
|
group: actions.summerwind.dev
|
||||||
names:
|
names:
|
||||||
kind: RunnerDeployment
|
kind: RunnerDeployment
|
||||||
@@ -23,9 +13,25 @@ spec:
|
|||||||
plural: runnerdeployments
|
plural: runnerdeployments
|
||||||
singular: runnerdeployment
|
singular: runnerdeployment
|
||||||
scope: Namespaced
|
scope: Namespaced
|
||||||
subresources:
|
versions:
|
||||||
status: {}
|
- additionalPrinterColumns:
|
||||||
validation:
|
- jsonPath: .spec.replicas
|
||||||
|
name: Desired
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.replicas
|
||||||
|
name: Current
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.updatedReplicas
|
||||||
|
name: Up-To-Date
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.availableReplicas
|
||||||
|
name: Available
|
||||||
|
type: number
|
||||||
|
- jsonPath: .metadata.creationTimestamp
|
||||||
|
name: Age
|
||||||
|
type: date
|
||||||
|
name: v1alpha1
|
||||||
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: RunnerDeployment is the Schema for the runnerdeployments API
|
description: RunnerDeployment is the Schema for the runnerdeployments API
|
||||||
properties:
|
properties:
|
||||||
@@ -38,14 +44,62 @@ spec:
|
|||||||
metadata:
|
metadata:
|
||||||
type: object
|
type: object
|
||||||
spec:
|
spec:
|
||||||
description: RunnerReplicaSetSpec defines the desired state of RunnerDeployment
|
description: RunnerDeploymentSpec defines the desired state of RunnerDeployment
|
||||||
properties:
|
properties:
|
||||||
replicas:
|
replicas:
|
||||||
nullable: true
|
nullable: true
|
||||||
type: integer
|
type: integer
|
||||||
|
selector:
|
||||||
|
description: A label selector is a label query over a set of resources. The result of matchLabels and matchExpressions are ANDed. An empty label selector matches all objects. A null label selector matches no objects.
|
||||||
|
nullable: true
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
template:
|
template:
|
||||||
properties:
|
properties:
|
||||||
metadata:
|
metadata:
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
finalizers:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
labels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
spec:
|
spec:
|
||||||
description: RunnerSpec defines the desired state of Runner
|
description: RunnerSpec defines the desired state of Runner
|
||||||
@@ -213,8 +267,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -268,8 +352,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -322,8 +436,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -377,8 +521,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -402,6 +576,38 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
dockerEnabled:
|
dockerEnabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
dockerMTU:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
dockerRegistryMirror:
|
||||||
|
type: string
|
||||||
|
dockerVolumeMounts:
|
||||||
|
items:
|
||||||
|
description: VolumeMount describes a mounting of a Volume within a container.
|
||||||
|
properties:
|
||||||
|
mountPath:
|
||||||
|
description: Path within the container at which the volume should be mounted. Must not contain ':'.
|
||||||
|
type: string
|
||||||
|
mountPropagation:
|
||||||
|
description: mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: This must match the Name of a Volume.
|
||||||
|
type: string
|
||||||
|
readOnly:
|
||||||
|
description: Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.
|
||||||
|
type: boolean
|
||||||
|
subPath:
|
||||||
|
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
||||||
|
type: string
|
||||||
|
subPathExpr:
|
||||||
|
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- mountPath
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
dockerdContainerResources:
|
dockerdContainerResources:
|
||||||
description: ResourceRequirements describes the compute resource requirements.
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
properties:
|
properties:
|
||||||
@@ -412,7 +618,7 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
requests:
|
requests:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@@ -421,11 +627,13 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
dockerdWithinRunnerContainer:
|
dockerdWithinRunnerContainer:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
enableServiceLinks:
|
||||||
|
type: boolean
|
||||||
enterprise:
|
enterprise:
|
||||||
pattern: ^[^/]+$
|
pattern: ^[^/]+$
|
||||||
type: string
|
type: string
|
||||||
@@ -458,7 +666,7 @@ spec:
|
|||||||
- key
|
- key
|
||||||
type: object
|
type: object
|
||||||
fieldRef:
|
fieldRef:
|
||||||
description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP.'
|
description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels[''<KEY>'']`, `metadata.annotations[''<KEY>'']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.'
|
||||||
properties:
|
properties:
|
||||||
apiVersion:
|
apiVersion:
|
||||||
description: Version of the schema the FieldPath is written in terms of, defaults to "v1".
|
description: Version of the schema the FieldPath is written in terms of, defaults to "v1".
|
||||||
@@ -537,6 +745,8 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
ephemeral:
|
||||||
|
type: boolean
|
||||||
ephemeralContainers:
|
ephemeralContainers:
|
||||||
items:
|
items:
|
||||||
description: An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.
|
description: An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.
|
||||||
@@ -546,6 +756,20 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
group:
|
group:
|
||||||
type: string
|
type: string
|
||||||
|
hostAliases:
|
||||||
|
items:
|
||||||
|
description: HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the pod's hosts file.
|
||||||
|
properties:
|
||||||
|
hostnames:
|
||||||
|
description: Hostnames for the above IP address.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
ip:
|
||||||
|
description: IP address of the host file entry.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
image:
|
image:
|
||||||
type: string
|
type: string
|
||||||
imagePullPolicy:
|
imagePullPolicy:
|
||||||
@@ -591,7 +815,7 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
requests:
|
requests:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@@ -600,9 +824,12 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
runtimeClassName:
|
||||||
|
description: 'RuntimeClassName is the container runtime configuration that containers should run under. More info: https://kubernetes.io/docs/concepts/containers/runtime-class'
|
||||||
|
type: string
|
||||||
securityContext:
|
securityContext:
|
||||||
description: PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.
|
description: PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.
|
||||||
properties:
|
properties:
|
||||||
@@ -610,6 +837,9 @@ spec:
|
|||||||
description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: \n 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- \n If unset, the Kubelet will not modify the ownership and permissions of any volume."
|
description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: \n 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- \n If unset, the Kubelet will not modify the ownership and permissions of any volume."
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
type: integer
|
||||||
|
fsGroupChangePolicy:
|
||||||
|
description: 'fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.'
|
||||||
|
type: string
|
||||||
runAsGroup:
|
runAsGroup:
|
||||||
description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.
|
description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.
|
||||||
format: int64
|
format: int64
|
||||||
@@ -637,6 +867,18 @@ spec:
|
|||||||
description: User is a SELinux user label that applies to the container.
|
description: User is a SELinux user label that applies to the container.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
seccompProfile:
|
||||||
|
description: The seccomp options to use by the containers in this pod.
|
||||||
|
properties:
|
||||||
|
localhostProfile:
|
||||||
|
description: localhostProfile indicates a profile defined in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must only be set if type is "Localhost".
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: "type indicates which kind of seccomp profile will be applied. Valid options are: \n Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied."
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
supplementalGroups:
|
supplementalGroups:
|
||||||
description: A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.
|
description: A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.
|
||||||
items:
|
items:
|
||||||
@@ -663,13 +905,13 @@ spec:
|
|||||||
description: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
description: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||||
properties:
|
properties:
|
||||||
gmsaCredentialSpec:
|
gmsaCredentialSpec:
|
||||||
description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.
|
description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field.
|
||||||
type: string
|
type: string
|
||||||
gmsaCredentialSpecName:
|
gmsaCredentialSpecName:
|
||||||
description: GMSACredentialSpecName is the name of the GMSA credential spec to use. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.
|
description: GMSACredentialSpecName is the name of the GMSA credential spec to use.
|
||||||
type: string
|
type: string
|
||||||
runAsUserName:
|
runAsUserName:
|
||||||
description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. This field is alpha-level and it is only honored by servers that enable the WindowsRunAsUserName feature flag.
|
description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
@@ -727,13 +969,19 @@ spec:
|
|||||||
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
||||||
type: string
|
type: string
|
||||||
subPathExpr:
|
subPathExpr:
|
||||||
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive. This field is beta in 1.15.
|
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive.
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- mountPath
|
- mountPath
|
||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
volumeSizeLimit:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
volumes:
|
volumes:
|
||||||
items:
|
items:
|
||||||
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||||
@@ -854,7 +1102,7 @@ spec:
|
|||||||
description: ConfigMap represents a configMap that should populate this volume
|
description: ConfigMap represents a configMap that should populate this volume
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -866,7 +1114,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -885,7 +1133,7 @@ spec:
|
|||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
csi:
|
csi:
|
||||||
description: CSI (Container Storage Interface) represents storage that is handled by an external CSI driver (Alpha feature).
|
description: CSI (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).
|
||||||
properties:
|
properties:
|
||||||
driver:
|
driver:
|
||||||
description: Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.
|
description: Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.
|
||||||
@@ -915,7 +1163,7 @@ spec:
|
|||||||
description: DownwardAPI represents downward API about the pod that should populate this volume
|
description: DownwardAPI represents downward API about the pod that should populate this volume
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits to use on created files by default. Must be a Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -936,7 +1184,7 @@ spec:
|
|||||||
- fieldPath
|
- fieldPath
|
||||||
type: object
|
type: object
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -980,6 +1228,122 @@ spec:
|
|||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
type: object
|
type: object
|
||||||
|
ephemeral:
|
||||||
|
description: "Ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. \n Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity tracking are needed, c) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through a PersistentVolumeClaim (see EphemeralVolumeSource for more information on the connection between this volume type and PersistentVolumeClaim). \n Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. \n Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. \n A pod can use both types of ephemeral volumes and persistent volumes at the same time. \n This is a beta feature and only available when the GenericEphemeralVolume feature gate is enabled."
|
||||||
|
properties:
|
||||||
|
volumeClaimTemplate:
|
||||||
|
description: "Will be used to create a stand-alone PVC to provision the volume. The pod in which this EphemeralVolumeSource is embedded will be the owner of the PVC, i.e. the PVC will be deleted together with the pod. The name of the PVC will be `<pod name>-<volume name>` where `<volume name>` is the name from the `PodSpec.Volumes` array entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). \n An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until the unrelated PVC is removed. If such a pre-created PVC is meant to be used by the pod, the PVC has to updated with an owner reference to the pod once the pod exists. Normally this should not be necessary, but it may be useful when manually reconstructing a broken cluster. \n This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. \n Required, must not be nil."
|
||||||
|
properties:
|
||||||
|
metadata:
|
||||||
|
description: May contain labels and annotations that will be copied into the PVC when creating it. No other fields are allowed and will be rejected during validation.
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
finalizers:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
labels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
description: The specification for the PersistentVolumeClaim. The entire content is copied unchanged into the PVC that gets created from this template. The same fields as in a PersistentVolumeClaim are also valid here.
|
||||||
|
properties:
|
||||||
|
accessModes:
|
||||||
|
description: 'AccessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
dataSource:
|
||||||
|
description: 'This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source.'
|
||||||
|
properties:
|
||||||
|
apiGroup:
|
||||||
|
description: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required.
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: Kind is the type of resource being referenced
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: Name is the name of resource being referenced
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- kind
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
resources:
|
||||||
|
description: 'Resources represents the minimum resources the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
|
||||||
|
properties:
|
||||||
|
limits:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
|
type: object
|
||||||
|
requests:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
selector:
|
||||||
|
description: A label query over volumes to consider for binding.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
storageClassName:
|
||||||
|
description: 'Name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
|
||||||
|
type: string
|
||||||
|
volumeMode:
|
||||||
|
description: volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec.
|
||||||
|
type: string
|
||||||
|
volumeName:
|
||||||
|
description: VolumeName is the binding reference to the PersistentVolume backing this claim.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- spec
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
fc:
|
fc:
|
||||||
description: FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
description: FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
||||||
properties:
|
properties:
|
||||||
@@ -1213,7 +1577,7 @@ spec:
|
|||||||
description: Items for all in one resources secrets, configmaps, and downward API
|
description: Items for all in one resources secrets, configmaps, and downward API
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.
|
description: Mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
sources:
|
sources:
|
||||||
@@ -1233,7 +1597,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1272,7 +1636,7 @@ spec:
|
|||||||
- fieldPath
|
- fieldPath
|
||||||
type: object
|
type: object
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1314,7 +1678,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1350,8 +1714,6 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
required:
|
|
||||||
- sources
|
|
||||||
type: object
|
type: object
|
||||||
quobyte:
|
quobyte:
|
||||||
description: Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
description: Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||||
@@ -1461,7 +1823,7 @@ spec:
|
|||||||
description: 'Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
|
description: 'Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -1473,7 +1835,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1546,22 +1908,26 @@ spec:
|
|||||||
status:
|
status:
|
||||||
properties:
|
properties:
|
||||||
availableReplicas:
|
availableReplicas:
|
||||||
|
description: AvailableReplicas is the total number of available runners which have been successfully registered to GitHub and still running. This corresponds to the sum of status.availableReplicas of all the runner replica sets.
|
||||||
type: integer
|
type: integer
|
||||||
desiredReplicas:
|
desiredReplicas:
|
||||||
description: Replicas 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.
|
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
|
type: integer
|
||||||
readyReplicas:
|
readyReplicas:
|
||||||
|
description: ReadyReplicas is the total number of available runners which have been successfully registered to GitHub and still running. This corresponds to the sum of status.readyReplicas of all the runner replica sets.
|
||||||
|
type: integer
|
||||||
|
replicas:
|
||||||
|
description: Replicas is the total number of replicas
|
||||||
|
type: integer
|
||||||
|
updatedReplicas:
|
||||||
|
description: ReadyReplicas is the total number of available runners which have been successfully registered to GitHub and still running. This corresponds to status.replicas of the runner replica set that has the desired template hash.
|
||||||
type: integer
|
type: integer
|
||||||
required:
|
|
||||||
- availableReplicas
|
|
||||||
- readyReplicas
|
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
version: v1alpha1
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
served: true
|
||||||
storage: true
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
status:
|
status:
|
||||||
acceptedNames:
|
acceptedNames:
|
||||||
kind: ""
|
kind: ""
|
||||||
|
|||||||
@@ -1,21 +1,11 @@
|
|||||||
apiVersion: apiextensions.k8s.io/v1beta1
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.3.0
|
controller-gen.kubebuilder.io/version: v0.6.0
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: runnerreplicasets.actions.summerwind.dev
|
name: runnerreplicasets.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
additionalPrinterColumns:
|
|
||||||
- JSONPath: .spec.replicas
|
|
||||||
name: Desired
|
|
||||||
type: number
|
|
||||||
- JSONPath: .status.availableReplicas
|
|
||||||
name: Current
|
|
||||||
type: number
|
|
||||||
- JSONPath: .status.readyReplicas
|
|
||||||
name: Ready
|
|
||||||
type: number
|
|
||||||
group: actions.summerwind.dev
|
group: actions.summerwind.dev
|
||||||
names:
|
names:
|
||||||
kind: RunnerReplicaSet
|
kind: RunnerReplicaSet
|
||||||
@@ -23,9 +13,22 @@ spec:
|
|||||||
plural: runnerreplicasets
|
plural: runnerreplicasets
|
||||||
singular: runnerreplicaset
|
singular: runnerreplicaset
|
||||||
scope: Namespaced
|
scope: Namespaced
|
||||||
subresources:
|
versions:
|
||||||
status: {}
|
- additionalPrinterColumns:
|
||||||
validation:
|
- jsonPath: .spec.replicas
|
||||||
|
name: Desired
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.replicas
|
||||||
|
name: Current
|
||||||
|
type: number
|
||||||
|
- jsonPath: .status.readyReplicas
|
||||||
|
name: Ready
|
||||||
|
type: number
|
||||||
|
- jsonPath: .metadata.creationTimestamp
|
||||||
|
name: Age
|
||||||
|
type: date
|
||||||
|
name: v1alpha1
|
||||||
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: RunnerReplicaSet is the Schema for the runnerreplicasets API
|
description: RunnerReplicaSet is the Schema for the runnerreplicasets API
|
||||||
properties:
|
properties:
|
||||||
@@ -43,9 +46,57 @@ spec:
|
|||||||
replicas:
|
replicas:
|
||||||
nullable: true
|
nullable: true
|
||||||
type: integer
|
type: integer
|
||||||
|
selector:
|
||||||
|
description: A label selector is a label query over a set of resources. The result of matchLabels and matchExpressions are ANDed. An empty label selector matches all objects. A null label selector matches no objects.
|
||||||
|
nullable: true
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
template:
|
template:
|
||||||
properties:
|
properties:
|
||||||
metadata:
|
metadata:
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
finalizers:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
labels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
spec:
|
spec:
|
||||||
description: RunnerSpec defines the desired state of Runner
|
description: RunnerSpec defines the desired state of Runner
|
||||||
@@ -213,8 +264,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -268,8 +349,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -322,8 +433,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -377,8 +518,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -402,6 +573,38 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
dockerEnabled:
|
dockerEnabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
dockerMTU:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
dockerRegistryMirror:
|
||||||
|
type: string
|
||||||
|
dockerVolumeMounts:
|
||||||
|
items:
|
||||||
|
description: VolumeMount describes a mounting of a Volume within a container.
|
||||||
|
properties:
|
||||||
|
mountPath:
|
||||||
|
description: Path within the container at which the volume should be mounted. Must not contain ':'.
|
||||||
|
type: string
|
||||||
|
mountPropagation:
|
||||||
|
description: mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: This must match the Name of a Volume.
|
||||||
|
type: string
|
||||||
|
readOnly:
|
||||||
|
description: Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.
|
||||||
|
type: boolean
|
||||||
|
subPath:
|
||||||
|
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
||||||
|
type: string
|
||||||
|
subPathExpr:
|
||||||
|
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- mountPath
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
dockerdContainerResources:
|
dockerdContainerResources:
|
||||||
description: ResourceRequirements describes the compute resource requirements.
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
properties:
|
properties:
|
||||||
@@ -412,7 +615,7 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
requests:
|
requests:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@@ -421,11 +624,13 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
dockerdWithinRunnerContainer:
|
dockerdWithinRunnerContainer:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
enableServiceLinks:
|
||||||
|
type: boolean
|
||||||
enterprise:
|
enterprise:
|
||||||
pattern: ^[^/]+$
|
pattern: ^[^/]+$
|
||||||
type: string
|
type: string
|
||||||
@@ -458,7 +663,7 @@ spec:
|
|||||||
- key
|
- key
|
||||||
type: object
|
type: object
|
||||||
fieldRef:
|
fieldRef:
|
||||||
description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP.'
|
description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels[''<KEY>'']`, `metadata.annotations[''<KEY>'']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.'
|
||||||
properties:
|
properties:
|
||||||
apiVersion:
|
apiVersion:
|
||||||
description: Version of the schema the FieldPath is written in terms of, defaults to "v1".
|
description: Version of the schema the FieldPath is written in terms of, defaults to "v1".
|
||||||
@@ -537,6 +742,8 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
ephemeral:
|
||||||
|
type: boolean
|
||||||
ephemeralContainers:
|
ephemeralContainers:
|
||||||
items:
|
items:
|
||||||
description: An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.
|
description: An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.
|
||||||
@@ -546,6 +753,20 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
group:
|
group:
|
||||||
type: string
|
type: string
|
||||||
|
hostAliases:
|
||||||
|
items:
|
||||||
|
description: HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the pod's hosts file.
|
||||||
|
properties:
|
||||||
|
hostnames:
|
||||||
|
description: Hostnames for the above IP address.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
ip:
|
||||||
|
description: IP address of the host file entry.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
image:
|
image:
|
||||||
type: string
|
type: string
|
||||||
imagePullPolicy:
|
imagePullPolicy:
|
||||||
@@ -591,7 +812,7 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
requests:
|
requests:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@@ -600,9 +821,12 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
runtimeClassName:
|
||||||
|
description: 'RuntimeClassName is the container runtime configuration that containers should run under. More info: https://kubernetes.io/docs/concepts/containers/runtime-class'
|
||||||
|
type: string
|
||||||
securityContext:
|
securityContext:
|
||||||
description: PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.
|
description: PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.
|
||||||
properties:
|
properties:
|
||||||
@@ -610,6 +834,9 @@ spec:
|
|||||||
description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: \n 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- \n If unset, the Kubelet will not modify the ownership and permissions of any volume."
|
description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: \n 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- \n If unset, the Kubelet will not modify the ownership and permissions of any volume."
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
type: integer
|
||||||
|
fsGroupChangePolicy:
|
||||||
|
description: 'fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.'
|
||||||
|
type: string
|
||||||
runAsGroup:
|
runAsGroup:
|
||||||
description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.
|
description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.
|
||||||
format: int64
|
format: int64
|
||||||
@@ -637,6 +864,18 @@ spec:
|
|||||||
description: User is a SELinux user label that applies to the container.
|
description: User is a SELinux user label that applies to the container.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
seccompProfile:
|
||||||
|
description: The seccomp options to use by the containers in this pod.
|
||||||
|
properties:
|
||||||
|
localhostProfile:
|
||||||
|
description: localhostProfile indicates a profile defined in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must only be set if type is "Localhost".
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: "type indicates which kind of seccomp profile will be applied. Valid options are: \n Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied."
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
supplementalGroups:
|
supplementalGroups:
|
||||||
description: A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.
|
description: A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.
|
||||||
items:
|
items:
|
||||||
@@ -663,13 +902,13 @@ spec:
|
|||||||
description: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
description: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||||
properties:
|
properties:
|
||||||
gmsaCredentialSpec:
|
gmsaCredentialSpec:
|
||||||
description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.
|
description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field.
|
||||||
type: string
|
type: string
|
||||||
gmsaCredentialSpecName:
|
gmsaCredentialSpecName:
|
||||||
description: GMSACredentialSpecName is the name of the GMSA credential spec to use. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.
|
description: GMSACredentialSpecName is the name of the GMSA credential spec to use.
|
||||||
type: string
|
type: string
|
||||||
runAsUserName:
|
runAsUserName:
|
||||||
description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. This field is alpha-level and it is only honored by servers that enable the WindowsRunAsUserName feature flag.
|
description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
@@ -727,13 +966,19 @@ spec:
|
|||||||
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
||||||
type: string
|
type: string
|
||||||
subPathExpr:
|
subPathExpr:
|
||||||
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive. This field is beta in 1.15.
|
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive.
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- mountPath
|
- mountPath
|
||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
volumeSizeLimit:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
volumes:
|
volumes:
|
||||||
items:
|
items:
|
||||||
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||||
@@ -854,7 +1099,7 @@ spec:
|
|||||||
description: ConfigMap represents a configMap that should populate this volume
|
description: ConfigMap represents a configMap that should populate this volume
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -866,7 +1111,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -885,7 +1130,7 @@ spec:
|
|||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
csi:
|
csi:
|
||||||
description: CSI (Container Storage Interface) represents storage that is handled by an external CSI driver (Alpha feature).
|
description: CSI (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).
|
||||||
properties:
|
properties:
|
||||||
driver:
|
driver:
|
||||||
description: Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.
|
description: Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.
|
||||||
@@ -915,7 +1160,7 @@ spec:
|
|||||||
description: DownwardAPI represents downward API about the pod that should populate this volume
|
description: DownwardAPI represents downward API about the pod that should populate this volume
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits to use on created files by default. Must be a Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -936,7 +1181,7 @@ spec:
|
|||||||
- fieldPath
|
- fieldPath
|
||||||
type: object
|
type: object
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -980,6 +1225,122 @@ spec:
|
|||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
type: object
|
type: object
|
||||||
|
ephemeral:
|
||||||
|
description: "Ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. \n Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity tracking are needed, c) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through a PersistentVolumeClaim (see EphemeralVolumeSource for more information on the connection between this volume type and PersistentVolumeClaim). \n Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. \n Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. \n A pod can use both types of ephemeral volumes and persistent volumes at the same time. \n This is a beta feature and only available when the GenericEphemeralVolume feature gate is enabled."
|
||||||
|
properties:
|
||||||
|
volumeClaimTemplate:
|
||||||
|
description: "Will be used to create a stand-alone PVC to provision the volume. The pod in which this EphemeralVolumeSource is embedded will be the owner of the PVC, i.e. the PVC will be deleted together with the pod. The name of the PVC will be `<pod name>-<volume name>` where `<volume name>` is the name from the `PodSpec.Volumes` array entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). \n An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until the unrelated PVC is removed. If such a pre-created PVC is meant to be used by the pod, the PVC has to updated with an owner reference to the pod once the pod exists. Normally this should not be necessary, but it may be useful when manually reconstructing a broken cluster. \n This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. \n Required, must not be nil."
|
||||||
|
properties:
|
||||||
|
metadata:
|
||||||
|
description: May contain labels and annotations that will be copied into the PVC when creating it. No other fields are allowed and will be rejected during validation.
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
finalizers:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
labels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
description: The specification for the PersistentVolumeClaim. The entire content is copied unchanged into the PVC that gets created from this template. The same fields as in a PersistentVolumeClaim are also valid here.
|
||||||
|
properties:
|
||||||
|
accessModes:
|
||||||
|
description: 'AccessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
dataSource:
|
||||||
|
description: 'This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source.'
|
||||||
|
properties:
|
||||||
|
apiGroup:
|
||||||
|
description: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required.
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: Kind is the type of resource being referenced
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: Name is the name of resource being referenced
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- kind
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
resources:
|
||||||
|
description: 'Resources represents the minimum resources the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
|
||||||
|
properties:
|
||||||
|
limits:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
|
type: object
|
||||||
|
requests:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
selector:
|
||||||
|
description: A label query over volumes to consider for binding.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
storageClassName:
|
||||||
|
description: 'Name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
|
||||||
|
type: string
|
||||||
|
volumeMode:
|
||||||
|
description: volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec.
|
||||||
|
type: string
|
||||||
|
volumeName:
|
||||||
|
description: VolumeName is the binding reference to the PersistentVolume backing this claim.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- spec
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
fc:
|
fc:
|
||||||
description: FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
description: FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
||||||
properties:
|
properties:
|
||||||
@@ -1213,7 +1574,7 @@ spec:
|
|||||||
description: Items for all in one resources secrets, configmaps, and downward API
|
description: Items for all in one resources secrets, configmaps, and downward API
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.
|
description: Mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
sources:
|
sources:
|
||||||
@@ -1233,7 +1594,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1272,7 +1633,7 @@ spec:
|
|||||||
- fieldPath
|
- fieldPath
|
||||||
type: object
|
type: object
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1314,7 +1675,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1350,8 +1711,6 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
required:
|
|
||||||
- sources
|
|
||||||
type: object
|
type: object
|
||||||
quobyte:
|
quobyte:
|
||||||
description: Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
description: Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||||
@@ -1461,7 +1820,7 @@ spec:
|
|||||||
description: 'Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
|
description: 'Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -1473,7 +1832,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1546,19 +1905,23 @@ spec:
|
|||||||
status:
|
status:
|
||||||
properties:
|
properties:
|
||||||
availableReplicas:
|
availableReplicas:
|
||||||
|
description: AvailableReplicas is the number of runners that are created and Runnning. This is currently same as ReadyReplicas but perserved for future use.
|
||||||
type: integer
|
type: integer
|
||||||
readyReplicas:
|
readyReplicas:
|
||||||
|
description: ReadyReplicas is the number of runners that are created and Runnning.
|
||||||
|
type: integer
|
||||||
|
replicas:
|
||||||
|
description: Replicas is the number of runners that are created and still being managed by this runner replica set.
|
||||||
type: integer
|
type: integer
|
||||||
required:
|
required:
|
||||||
- availableReplicas
|
- availableReplicas
|
||||||
- readyReplicas
|
- readyReplicas
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
version: v1alpha1
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
served: true
|
||||||
storage: true
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
status:
|
status:
|
||||||
acceptedNames:
|
acceptedNames:
|
||||||
kind: ""
|
kind: ""
|
||||||
|
|||||||
@@ -1,27 +1,11 @@
|
|||||||
apiVersion: apiextensions.k8s.io/v1beta1
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.3.0
|
controller-gen.kubebuilder.io/version: v0.6.0
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: runners.actions.summerwind.dev
|
name: runners.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
additionalPrinterColumns:
|
|
||||||
- JSONPath: .spec.enterprise
|
|
||||||
name: Enterprise
|
|
||||||
type: string
|
|
||||||
- JSONPath: .spec.organization
|
|
||||||
name: Organization
|
|
||||||
type: string
|
|
||||||
- JSONPath: .spec.repository
|
|
||||||
name: Repository
|
|
||||||
type: string
|
|
||||||
- JSONPath: .spec.labels
|
|
||||||
name: Labels
|
|
||||||
type: string
|
|
||||||
- JSONPath: .status.phase
|
|
||||||
name: Status
|
|
||||||
type: string
|
|
||||||
group: actions.summerwind.dev
|
group: actions.summerwind.dev
|
||||||
names:
|
names:
|
||||||
kind: Runner
|
kind: Runner
|
||||||
@@ -29,9 +13,28 @@ spec:
|
|||||||
plural: runners
|
plural: runners
|
||||||
singular: runner
|
singular: runner
|
||||||
scope: Namespaced
|
scope: Namespaced
|
||||||
subresources:
|
versions:
|
||||||
status: {}
|
- additionalPrinterColumns:
|
||||||
validation:
|
- jsonPath: .spec.enterprise
|
||||||
|
name: Enterprise
|
||||||
|
type: string
|
||||||
|
- jsonPath: .spec.organization
|
||||||
|
name: Organization
|
||||||
|
type: string
|
||||||
|
- jsonPath: .spec.repository
|
||||||
|
name: Repository
|
||||||
|
type: string
|
||||||
|
- jsonPath: .spec.labels
|
||||||
|
name: Labels
|
||||||
|
type: string
|
||||||
|
- jsonPath: .status.phase
|
||||||
|
name: Status
|
||||||
|
type: string
|
||||||
|
- jsonPath: .metadata.creationTimestamp
|
||||||
|
name: Age
|
||||||
|
type: date
|
||||||
|
name: v1alpha1
|
||||||
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: Runner is the Schema for the runners API
|
description: Runner is the Schema for the runners API
|
||||||
properties:
|
properties:
|
||||||
@@ -209,8 +212,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -264,8 +297,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -318,8 +381,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -373,8 +466,38 @@ spec:
|
|||||||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
namespaceSelector:
|
||||||
|
description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
namespaces:
|
namespaces:
|
||||||
description: namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
|
description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace"
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
@@ -398,6 +521,38 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
dockerEnabled:
|
dockerEnabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
dockerMTU:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
dockerRegistryMirror:
|
||||||
|
type: string
|
||||||
|
dockerVolumeMounts:
|
||||||
|
items:
|
||||||
|
description: VolumeMount describes a mounting of a Volume within a container.
|
||||||
|
properties:
|
||||||
|
mountPath:
|
||||||
|
description: Path within the container at which the volume should be mounted. Must not contain ':'.
|
||||||
|
type: string
|
||||||
|
mountPropagation:
|
||||||
|
description: mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: This must match the Name of a Volume.
|
||||||
|
type: string
|
||||||
|
readOnly:
|
||||||
|
description: Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.
|
||||||
|
type: boolean
|
||||||
|
subPath:
|
||||||
|
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
||||||
|
type: string
|
||||||
|
subPathExpr:
|
||||||
|
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- mountPath
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
dockerdContainerResources:
|
dockerdContainerResources:
|
||||||
description: ResourceRequirements describes the compute resource requirements.
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
properties:
|
properties:
|
||||||
@@ -408,7 +563,7 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
requests:
|
requests:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@@ -417,11 +572,13 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
dockerdWithinRunnerContainer:
|
dockerdWithinRunnerContainer:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
enableServiceLinks:
|
||||||
|
type: boolean
|
||||||
enterprise:
|
enterprise:
|
||||||
pattern: ^[^/]+$
|
pattern: ^[^/]+$
|
||||||
type: string
|
type: string
|
||||||
@@ -454,7 +611,7 @@ spec:
|
|||||||
- key
|
- key
|
||||||
type: object
|
type: object
|
||||||
fieldRef:
|
fieldRef:
|
||||||
description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP.'
|
description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels[''<KEY>'']`, `metadata.annotations[''<KEY>'']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.'
|
||||||
properties:
|
properties:
|
||||||
apiVersion:
|
apiVersion:
|
||||||
description: Version of the schema the FieldPath is written in terms of, defaults to "v1".
|
description: Version of the schema the FieldPath is written in terms of, defaults to "v1".
|
||||||
@@ -533,6 +690,8 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
ephemeral:
|
||||||
|
type: boolean
|
||||||
ephemeralContainers:
|
ephemeralContainers:
|
||||||
items:
|
items:
|
||||||
description: An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.
|
description: An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.
|
||||||
@@ -542,6 +701,20 @@ spec:
|
|||||||
type: array
|
type: array
|
||||||
group:
|
group:
|
||||||
type: string
|
type: string
|
||||||
|
hostAliases:
|
||||||
|
items:
|
||||||
|
description: HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the pod's hosts file.
|
||||||
|
properties:
|
||||||
|
hostnames:
|
||||||
|
description: Hostnames for the above IP address.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
ip:
|
||||||
|
description: IP address of the host file entry.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
image:
|
image:
|
||||||
type: string
|
type: string
|
||||||
imagePullPolicy:
|
imagePullPolicy:
|
||||||
@@ -587,7 +760,7 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
requests:
|
requests:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@@ -596,9 +769,12 @@ spec:
|
|||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
runtimeClassName:
|
||||||
|
description: 'RuntimeClassName is the container runtime configuration that containers should run under. More info: https://kubernetes.io/docs/concepts/containers/runtime-class'
|
||||||
|
type: string
|
||||||
securityContext:
|
securityContext:
|
||||||
description: PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.
|
description: PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.
|
||||||
properties:
|
properties:
|
||||||
@@ -606,6 +782,9 @@ spec:
|
|||||||
description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: \n 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- \n If unset, the Kubelet will not modify the ownership and permissions of any volume."
|
description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: \n 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- \n If unset, the Kubelet will not modify the ownership and permissions of any volume."
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
type: integer
|
||||||
|
fsGroupChangePolicy:
|
||||||
|
description: 'fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.'
|
||||||
|
type: string
|
||||||
runAsGroup:
|
runAsGroup:
|
||||||
description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.
|
description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.
|
||||||
format: int64
|
format: int64
|
||||||
@@ -633,6 +812,18 @@ spec:
|
|||||||
description: User is a SELinux user label that applies to the container.
|
description: User is a SELinux user label that applies to the container.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
seccompProfile:
|
||||||
|
description: The seccomp options to use by the containers in this pod.
|
||||||
|
properties:
|
||||||
|
localhostProfile:
|
||||||
|
description: localhostProfile indicates a profile defined in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must only be set if type is "Localhost".
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: "type indicates which kind of seccomp profile will be applied. Valid options are: \n Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied."
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
supplementalGroups:
|
supplementalGroups:
|
||||||
description: A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.
|
description: A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.
|
||||||
items:
|
items:
|
||||||
@@ -659,13 +850,13 @@ spec:
|
|||||||
description: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
description: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||||
properties:
|
properties:
|
||||||
gmsaCredentialSpec:
|
gmsaCredentialSpec:
|
||||||
description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.
|
description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field.
|
||||||
type: string
|
type: string
|
||||||
gmsaCredentialSpecName:
|
gmsaCredentialSpecName:
|
||||||
description: GMSACredentialSpecName is the name of the GMSA credential spec to use. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.
|
description: GMSACredentialSpecName is the name of the GMSA credential spec to use.
|
||||||
type: string
|
type: string
|
||||||
runAsUserName:
|
runAsUserName:
|
||||||
description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. This field is alpha-level and it is only honored by servers that enable the WindowsRunAsUserName feature flag.
|
description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
@@ -723,13 +914,19 @@ spec:
|
|||||||
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root).
|
||||||
type: string
|
type: string
|
||||||
subPathExpr:
|
subPathExpr:
|
||||||
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive. This field is beta in 1.15.
|
description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive.
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- mountPath
|
- mountPath
|
||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
volumeSizeLimit:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
volumes:
|
volumes:
|
||||||
items:
|
items:
|
||||||
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||||
@@ -850,7 +1047,7 @@ spec:
|
|||||||
description: ConfigMap represents a configMap that should populate this volume
|
description: ConfigMap represents a configMap that should populate this volume
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -862,7 +1059,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -881,7 +1078,7 @@ spec:
|
|||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
csi:
|
csi:
|
||||||
description: CSI (Container Storage Interface) represents storage that is handled by an external CSI driver (Alpha feature).
|
description: CSI (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).
|
||||||
properties:
|
properties:
|
||||||
driver:
|
driver:
|
||||||
description: Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.
|
description: Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.
|
||||||
@@ -911,7 +1108,7 @@ spec:
|
|||||||
description: DownwardAPI represents downward API about the pod that should populate this volume
|
description: DownwardAPI represents downward API about the pod that should populate this volume
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits to use on created files by default. Must be a Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -932,7 +1129,7 @@ spec:
|
|||||||
- fieldPath
|
- fieldPath
|
||||||
type: object
|
type: object
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -976,6 +1173,122 @@ spec:
|
|||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
type: object
|
type: object
|
||||||
|
ephemeral:
|
||||||
|
description: "Ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. \n Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity tracking are needed, c) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through a PersistentVolumeClaim (see EphemeralVolumeSource for more information on the connection between this volume type and PersistentVolumeClaim). \n Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. \n Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. \n A pod can use both types of ephemeral volumes and persistent volumes at the same time. \n This is a beta feature and only available when the GenericEphemeralVolume feature gate is enabled."
|
||||||
|
properties:
|
||||||
|
volumeClaimTemplate:
|
||||||
|
description: "Will be used to create a stand-alone PVC to provision the volume. The pod in which this EphemeralVolumeSource is embedded will be the owner of the PVC, i.e. the PVC will be deleted together with the pod. The name of the PVC will be `<pod name>-<volume name>` where `<volume name>` is the name from the `PodSpec.Volumes` array entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). \n An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until the unrelated PVC is removed. If such a pre-created PVC is meant to be used by the pod, the PVC has to updated with an owner reference to the pod once the pod exists. Normally this should not be necessary, but it may be useful when manually reconstructing a broken cluster. \n This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. \n Required, must not be nil."
|
||||||
|
properties:
|
||||||
|
metadata:
|
||||||
|
description: May contain labels and annotations that will be copied into the PVC when creating it. No other fields are allowed and will be rejected during validation.
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
finalizers:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
labels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
description: The specification for the PersistentVolumeClaim. The entire content is copied unchanged into the PVC that gets created from this template. The same fields as in a PersistentVolumeClaim are also valid here.
|
||||||
|
properties:
|
||||||
|
accessModes:
|
||||||
|
description: 'AccessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
dataSource:
|
||||||
|
description: 'This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) * An existing custom resource that implements data population (Alpha) In order to use custom resource types that implement data population, the AnyVolumeDataSource feature gate must be enabled. If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source.'
|
||||||
|
properties:
|
||||||
|
apiGroup:
|
||||||
|
description: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required.
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: Kind is the type of resource being referenced
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: Name is the name of resource being referenced
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- kind
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
resources:
|
||||||
|
description: 'Resources represents the minimum resources the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
|
||||||
|
properties:
|
||||||
|
limits:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
|
type: object
|
||||||
|
requests:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
selector:
|
||||||
|
description: A label query over volumes to consider for binding.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
storageClassName:
|
||||||
|
description: 'Name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
|
||||||
|
type: string
|
||||||
|
volumeMode:
|
||||||
|
description: volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec.
|
||||||
|
type: string
|
||||||
|
volumeName:
|
||||||
|
description: VolumeName is the binding reference to the PersistentVolume backing this claim.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- spec
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
fc:
|
fc:
|
||||||
description: FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
description: FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
||||||
properties:
|
properties:
|
||||||
@@ -1209,7 +1522,7 @@ spec:
|
|||||||
description: Items for all in one resources secrets, configmaps, and downward API
|
description: Items for all in one resources secrets, configmaps, and downward API
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.
|
description: Mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
sources:
|
sources:
|
||||||
@@ -1229,7 +1542,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1268,7 +1581,7 @@ spec:
|
|||||||
- fieldPath
|
- fieldPath
|
||||||
type: object
|
type: object
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1310,7 +1623,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1346,8 +1659,6 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
required:
|
|
||||||
- sources
|
|
||||||
type: object
|
type: object
|
||||||
quobyte:
|
quobyte:
|
||||||
description: Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
description: Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||||
@@ -1457,7 +1768,7 @@ spec:
|
|||||||
description: 'Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
|
description: 'Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
|
||||||
properties:
|
properties:
|
||||||
defaultMode:
|
defaultMode:
|
||||||
description: 'Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
items:
|
items:
|
||||||
@@ -1469,7 +1780,7 @@ spec:
|
|||||||
description: The key to project.
|
description: The key to project.
|
||||||
type: string
|
type: string
|
||||||
mode:
|
mode:
|
||||||
description: 'Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
description: 'Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.'
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
path:
|
path:
|
||||||
@@ -1538,6 +1849,10 @@ spec:
|
|||||||
status:
|
status:
|
||||||
description: RunnerStatus defines the observed state of Runner
|
description: RunnerStatus defines the observed state of Runner
|
||||||
properties:
|
properties:
|
||||||
|
lastRegistrationCheckTime:
|
||||||
|
format: date-time
|
||||||
|
nullable: true
|
||||||
|
type: string
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
phase:
|
phase:
|
||||||
@@ -1566,18 +1881,12 @@ spec:
|
|||||||
- expiresAt
|
- expiresAt
|
||||||
- token
|
- token
|
||||||
type: object
|
type: object
|
||||||
required:
|
|
||||||
- message
|
|
||||||
- phase
|
|
||||||
- reason
|
|
||||||
- registration
|
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
version: v1alpha1
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
served: true
|
||||||
storage: true
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
status:
|
status:
|
||||||
acceptedNames:
|
acceptedNames:
|
||||||
kind: ""
|
kind: ""
|
||||||
|
|||||||
7163
config/crd/bases/actions.summerwind.dev_runnersets.yaml
Normal file
7163
config/crd/bases/actions.summerwind.dev_runnersets.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: kube-rbac-proxy
|
- name: kube-rbac-proxy
|
||||||
image: quay.io/brancz/kube-rbac-proxy:v0.8.0
|
image: quay.io/brancz/kube-rbac-proxy:v0.10.0
|
||||||
args:
|
args:
|
||||||
- "--secure-listen-address=0.0.0.0:8443"
|
- "--secure-listen-address=0.0.0.0:8443"
|
||||||
- "--upstream=http://127.0.0.1:8080/"
|
- "--upstream=http://127.0.0.1:8080/"
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1
|
|||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
images:
|
images:
|
||||||
- name: controller
|
- name: controller
|
||||||
newName: summerwind/actions-runner-controller
|
newName: mumoshu/actions-runner-controller
|
||||||
newTag: latest
|
newTag: controller1
|
||||||
|
|||||||
@@ -134,6 +134,67 @@ rules:
|
|||||||
- get
|
- get
|
||||||
- patch
|
- patch
|
||||||
- update
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- actions.summerwind.dev
|
||||||
|
resources:
|
||||||
|
- runnersets
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- actions.summerwind.dev
|
||||||
|
resources:
|
||||||
|
- runnersets/finalizers
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- actions.summerwind.dev
|
||||||
|
resources:
|
||||||
|
- runnersets/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- apps
|
||||||
|
resources:
|
||||||
|
- statefulsets
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- apps
|
||||||
|
resources:
|
||||||
|
- statefulsets/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- coordination.k8s.io
|
||||||
|
resources:
|
||||||
|
- leases
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- update
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- ""
|
||||||
resources:
|
resources:
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ kind: Runner
|
|||||||
metadata:
|
metadata:
|
||||||
name: summerwind-actions-runner-controller
|
name: summerwind-actions-runner-controller
|
||||||
spec:
|
spec:
|
||||||
repository: summerwind/actions-runner-controller
|
repository: actions-runner-controller/actions-runner-controller
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ spec:
|
|||||||
replicas: 2
|
replicas: 2
|
||||||
template:
|
template:
|
||||||
spec:
|
spec:
|
||||||
repository: summerwind/actions-runner-controller
|
repository: actions-runner-controller/actions-runner-controller
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ spec:
|
|||||||
replicas: 2
|
replicas: 2
|
||||||
template:
|
template:
|
||||||
spec:
|
spec:
|
||||||
repository: summerwind/actions-runner-controller
|
repository: actions-runner-controller/actions-runner-controller
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
resources:
|
resources:
|
||||||
- manifests.yaml
|
- manifests.yaml
|
||||||
|
- manifests.v1beta1.yaml
|
||||||
- service.yaml
|
- service.yaml
|
||||||
|
|
||||||
configurations:
|
configurations:
|
||||||
|
|||||||
130
config/webhook/manifests.v1beta1.yaml
Normal file
130
config/webhook/manifests.v1beta1.yaml
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||||
|
kind: MutatingWebhookConfiguration
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
name: mutating-webhook-configuration
|
||||||
|
webhooks:
|
||||||
|
- admissionReviewVersions: null
|
||||||
|
clientConfig:
|
||||||
|
service:
|
||||||
|
name: webhook-service
|
||||||
|
namespace: system
|
||||||
|
path: /mutate-actions-summerwind-dev-v1alpha1-runner
|
||||||
|
failurePolicy: Fail
|
||||||
|
name: mutate.runner.actions.summerwind.dev
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- actions.summerwind.dev
|
||||||
|
apiVersions:
|
||||||
|
- v1alpha1
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
|
resources:
|
||||||
|
- runners
|
||||||
|
sideEffects: None
|
||||||
|
- admissionReviewVersions: null
|
||||||
|
clientConfig:
|
||||||
|
service:
|
||||||
|
name: webhook-service
|
||||||
|
namespace: system
|
||||||
|
path: /mutate-actions-summerwind-dev-v1alpha1-runnerdeployment
|
||||||
|
failurePolicy: Fail
|
||||||
|
name: mutate.runnerdeployment.actions.summerwind.dev
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- actions.summerwind.dev
|
||||||
|
apiVersions:
|
||||||
|
- v1alpha1
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
|
resources:
|
||||||
|
- runnerdeployments
|
||||||
|
sideEffects: null
|
||||||
|
- admissionReviewVersions: null
|
||||||
|
clientConfig:
|
||||||
|
service:
|
||||||
|
name: webhook-service
|
||||||
|
namespace: system
|
||||||
|
path: /mutate-actions-summerwind-dev-v1alpha1-runnerreplicaset
|
||||||
|
failurePolicy: Fail
|
||||||
|
name: mutate.runnerreplicaset.actions.summerwind.dev
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- actions.summerwind.dev
|
||||||
|
apiVersions:
|
||||||
|
- v1alpha1
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
|
resources:
|
||||||
|
- runnerreplicasets
|
||||||
|
sideEffects: None
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||||
|
kind: ValidatingWebhookConfiguration
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
name: validating-webhook-configuration
|
||||||
|
webhooks:
|
||||||
|
- admissionReviewVersions: null
|
||||||
|
clientConfig:
|
||||||
|
service:
|
||||||
|
name: webhook-service
|
||||||
|
namespace: system
|
||||||
|
path: /validate-actions-summerwind-dev-v1alpha1-runner
|
||||||
|
failurePolicy: Fail
|
||||||
|
name: validate.runner.actions.summerwind.dev
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- actions.summerwind.dev
|
||||||
|
apiVersions:
|
||||||
|
- v1alpha1
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
|
resources:
|
||||||
|
- runners
|
||||||
|
sideEffects: None
|
||||||
|
- admissionReviewVersions: null
|
||||||
|
clientConfig:
|
||||||
|
service:
|
||||||
|
name: webhook-service
|
||||||
|
namespace: system
|
||||||
|
path: /validate-actions-summerwind-dev-v1alpha1-runnerdeployment
|
||||||
|
failurePolicy: Fail
|
||||||
|
name: validate.runnerdeployment.actions.summerwind.dev
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- actions.summerwind.dev
|
||||||
|
apiVersions:
|
||||||
|
- v1alpha1
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
|
resources:
|
||||||
|
- runnerdeployments
|
||||||
|
sideEffects: null
|
||||||
|
- admissionReviewVersions: null
|
||||||
|
clientConfig:
|
||||||
|
service:
|
||||||
|
name: webhook-service
|
||||||
|
namespace: system
|
||||||
|
path: /validate-actions-summerwind-dev-v1alpha1-runnerreplicaset
|
||||||
|
failurePolicy: Fail
|
||||||
|
name: validate.runnerreplicaset.actions.summerwind.dev
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- actions.summerwind.dev
|
||||||
|
apiVersions:
|
||||||
|
- v1alpha1
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
|
resources:
|
||||||
|
- runnerreplicasets
|
||||||
|
sideEffects: None
|
||||||
@@ -1,124 +1,27 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
apiVersion: admissionregistration.k8s.io/v1
|
||||||
kind: MutatingWebhookConfiguration
|
kind: MutatingWebhookConfiguration
|
||||||
metadata:
|
metadata:
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: mutating-webhook-configuration
|
name: mutating-webhook-configuration
|
||||||
webhooks:
|
webhooks:
|
||||||
- clientConfig:
|
- admissionReviewVersions:
|
||||||
caBundle: Cg==
|
- v1beta1
|
||||||
|
clientConfig:
|
||||||
service:
|
service:
|
||||||
name: webhook-service
|
name: webhook-service
|
||||||
namespace: system
|
namespace: system
|
||||||
path: /mutate-actions-summerwind-dev-v1alpha1-runner
|
path: /mutate-runner-set-pod
|
||||||
failurePolicy: Fail
|
failurePolicy: Ignore
|
||||||
name: mutate.runner.actions.summerwind.dev
|
name: mutate-runner-pod.webhook.actions.summerwind.dev
|
||||||
rules:
|
rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- actions.summerwind.dev
|
- ""
|
||||||
apiVersions:
|
apiVersions:
|
||||||
- v1alpha1
|
- v1
|
||||||
operations:
|
operations:
|
||||||
- CREATE
|
- CREATE
|
||||||
- UPDATE
|
|
||||||
resources:
|
resources:
|
||||||
- runners
|
- pods
|
||||||
- clientConfig:
|
sideEffects: None
|
||||||
caBundle: Cg==
|
|
||||||
service:
|
|
||||||
name: webhook-service
|
|
||||||
namespace: system
|
|
||||||
path: /mutate-actions-summerwind-dev-v1alpha1-runnerdeployment
|
|
||||||
failurePolicy: Fail
|
|
||||||
name: mutate.runnerdeployment.actions.summerwind.dev
|
|
||||||
rules:
|
|
||||||
- apiGroups:
|
|
||||||
- actions.summerwind.dev
|
|
||||||
apiVersions:
|
|
||||||
- v1alpha1
|
|
||||||
operations:
|
|
||||||
- CREATE
|
|
||||||
- UPDATE
|
|
||||||
resources:
|
|
||||||
- runnerdeployments
|
|
||||||
- clientConfig:
|
|
||||||
caBundle: Cg==
|
|
||||||
service:
|
|
||||||
name: webhook-service
|
|
||||||
namespace: system
|
|
||||||
path: /mutate-actions-summerwind-dev-v1alpha1-runnerreplicaset
|
|
||||||
failurePolicy: Fail
|
|
||||||
name: mutate.runnerreplicaset.actions.summerwind.dev
|
|
||||||
rules:
|
|
||||||
- apiGroups:
|
|
||||||
- actions.summerwind.dev
|
|
||||||
apiVersions:
|
|
||||||
- v1alpha1
|
|
||||||
operations:
|
|
||||||
- CREATE
|
|
||||||
- UPDATE
|
|
||||||
resources:
|
|
||||||
- runnerreplicasets
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
|
||||||
kind: ValidatingWebhookConfiguration
|
|
||||||
metadata:
|
|
||||||
creationTimestamp: null
|
|
||||||
name: validating-webhook-configuration
|
|
||||||
webhooks:
|
|
||||||
- clientConfig:
|
|
||||||
caBundle: Cg==
|
|
||||||
service:
|
|
||||||
name: webhook-service
|
|
||||||
namespace: system
|
|
||||||
path: /validate-actions-summerwind-dev-v1alpha1-runner
|
|
||||||
failurePolicy: Fail
|
|
||||||
name: validate.runner.actions.summerwind.dev
|
|
||||||
rules:
|
|
||||||
- apiGroups:
|
|
||||||
- actions.summerwind.dev
|
|
||||||
apiVersions:
|
|
||||||
- v1alpha1
|
|
||||||
operations:
|
|
||||||
- CREATE
|
|
||||||
- UPDATE
|
|
||||||
resources:
|
|
||||||
- runners
|
|
||||||
- clientConfig:
|
|
||||||
caBundle: Cg==
|
|
||||||
service:
|
|
||||||
name: webhook-service
|
|
||||||
namespace: system
|
|
||||||
path: /validate-actions-summerwind-dev-v1alpha1-runnerdeployment
|
|
||||||
failurePolicy: Fail
|
|
||||||
name: validate.runnerdeployment.actions.summerwind.dev
|
|
||||||
rules:
|
|
||||||
- apiGroups:
|
|
||||||
- actions.summerwind.dev
|
|
||||||
apiVersions:
|
|
||||||
- v1alpha1
|
|
||||||
operations:
|
|
||||||
- CREATE
|
|
||||||
- UPDATE
|
|
||||||
resources:
|
|
||||||
- runnerdeployments
|
|
||||||
- clientConfig:
|
|
||||||
caBundle: Cg==
|
|
||||||
service:
|
|
||||||
name: webhook-service
|
|
||||||
namespace: system
|
|
||||||
path: /validate-actions-summerwind-dev-v1alpha1-runnerreplicaset
|
|
||||||
failurePolicy: Fail
|
|
||||||
name: validate.runnerreplicaset.actions.summerwind.dev
|
|
||||||
rules:
|
|
||||||
- apiGroups:
|
|
||||||
- actions.summerwind.dev
|
|
||||||
apiVersions:
|
|
||||||
- v1alpha1
|
|
||||||
operations:
|
|
||||||
- CREATE
|
|
||||||
- UPDATE
|
|
||||||
resources:
|
|
||||||
- runnerreplicasets
|
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -32,7 +31,7 @@ func getValueAvailableAt(now time.Time, from, to *time.Time, reservedValue int)
|
|||||||
return &reservedValue
|
return &reservedValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *HorizontalRunnerAutoscalerReconciler) getDesiredReplicasFromCache(hra v1alpha1.HorizontalRunnerAutoscaler) *int {
|
func (r *HorizontalRunnerAutoscalerReconciler) fetchSuggestedReplicasFromCache(hra v1alpha1.HorizontalRunnerAutoscaler) *int {
|
||||||
var entry *v1alpha1.CacheEntry
|
var entry *v1alpha1.CacheEntry
|
||||||
|
|
||||||
for i := range hra.Status.CacheEntries {
|
for i := range hra.Status.CacheEntries {
|
||||||
@@ -61,7 +60,7 @@ func (r *HorizontalRunnerAutoscalerReconciler) getDesiredReplicasFromCache(hra v
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *HorizontalRunnerAutoscalerReconciler) determineDesiredReplicas(rd v1alpha1.RunnerDeployment, hra v1alpha1.HorizontalRunnerAutoscaler) (*int, error) {
|
func (r *HorizontalRunnerAutoscalerReconciler) suggestDesiredReplicas(st scaleTarget, hra v1alpha1.HorizontalRunnerAutoscaler) (*int, error) {
|
||||||
if hra.Spec.MinReplicas == nil {
|
if hra.Spec.MinReplicas == nil {
|
||||||
return nil, fmt.Errorf("horizontalrunnerautoscaler %s/%s is missing minReplicas", hra.Namespace, hra.Name)
|
return nil, fmt.Errorf("horizontalrunnerautoscaler %s/%s is missing minReplicas", hra.Namespace, hra.Name)
|
||||||
} else if hra.Spec.MaxReplicas == nil {
|
} else if hra.Spec.MaxReplicas == nil {
|
||||||
@@ -69,31 +68,87 @@ func (r *HorizontalRunnerAutoscalerReconciler) determineDesiredReplicas(rd v1alp
|
|||||||
}
|
}
|
||||||
|
|
||||||
metrics := hra.Spec.Metrics
|
metrics := hra.Spec.Metrics
|
||||||
if len(metrics) == 0 || metrics[0].Type == v1alpha1.AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns {
|
numMetrics := len(metrics)
|
||||||
return r.calculateReplicasByQueuedAndInProgressWorkflowRuns(rd, hra)
|
if numMetrics == 0 {
|
||||||
} else if metrics[0].Type == v1alpha1.AutoscalingMetricTypePercentageRunnersBusy {
|
if len(hra.Spec.ScaleUpTriggers) == 0 {
|
||||||
return r.calculateReplicasByPercentageRunnersBusy(rd, hra)
|
return r.suggestReplicasByQueuedAndInProgressWorkflowRuns(st, hra, nil)
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("validting autoscaling metrics: unsupported metric type %q", metrics[0].Type)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *HorizontalRunnerAutoscalerReconciler) calculateReplicasByQueuedAndInProgressWorkflowRuns(rd v1alpha1.RunnerDeployment, hra v1alpha1.HorizontalRunnerAutoscaler) (*int, error) {
|
return nil, nil
|
||||||
|
} else if numMetrics > 2 {
|
||||||
|
return nil, fmt.Errorf("Too many autoscaling metrics configured: It must be 0 to 2, but got %d", numMetrics)
|
||||||
|
}
|
||||||
|
|
||||||
|
primaryMetric := metrics[0]
|
||||||
|
primaryMetricType := primaryMetric.Type
|
||||||
|
|
||||||
|
var (
|
||||||
|
suggested *int
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
switch primaryMetricType {
|
||||||
|
case v1alpha1.AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns:
|
||||||
|
suggested, err = r.suggestReplicasByQueuedAndInProgressWorkflowRuns(st, hra, &primaryMetric)
|
||||||
|
case v1alpha1.AutoscalingMetricTypePercentageRunnersBusy:
|
||||||
|
suggested, err = r.suggestReplicasByPercentageRunnersBusy(st, hra, primaryMetric)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("validting autoscaling metrics: unsupported metric type %q", primaryMetric)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if suggested != nil && *suggested > 0 {
|
||||||
|
return suggested, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(metrics) == 1 {
|
||||||
|
// This is never supposed to happen but anyway-
|
||||||
|
// Fall-back to `minReplicas + capacityReservedThroughWebhook`.
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, we are sure that there are exactly 2 Metrics entries.
|
||||||
|
|
||||||
|
fallbackMetric := metrics[1]
|
||||||
|
fallbackMetricType := fallbackMetric.Type
|
||||||
|
|
||||||
|
if primaryMetricType != v1alpha1.AutoscalingMetricTypePercentageRunnersBusy ||
|
||||||
|
fallbackMetricType != v1alpha1.AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns {
|
||||||
|
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"invalid HRA Spec: Metrics[0] of %s cannot be combined with Metrics[1] of %s: The only allowed combination is 0=PercentageRunnersBusy and 1=TotalNumberOfQueuedAndInProgressWorkflowRuns",
|
||||||
|
primaryMetricType, fallbackMetricType,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.suggestReplicasByQueuedAndInProgressWorkflowRuns(st, hra, &fallbackMetric)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HorizontalRunnerAutoscalerReconciler) suggestReplicasByQueuedAndInProgressWorkflowRuns(st scaleTarget, hra v1alpha1.HorizontalRunnerAutoscaler, metrics *v1alpha1.MetricSpec) (*int, error) {
|
||||||
|
|
||||||
var repos [][]string
|
var repos [][]string
|
||||||
metrics := hra.Spec.Metrics
|
repoID := st.repo
|
||||||
repoID := rd.Spec.Template.Spec.Repository
|
|
||||||
if repoID == "" {
|
if repoID == "" {
|
||||||
orgName := rd.Spec.Template.Spec.Organization
|
orgName := st.org
|
||||||
if orgName == "" {
|
if orgName == "" {
|
||||||
return nil, fmt.Errorf("asserting runner deployment spec to detect bug: spec.template.organization should not be empty on this code path")
|
return nil, fmt.Errorf("asserting runner deployment spec to detect bug: spec.template.organization should not be empty on this code path")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(metrics[0].RepositoryNames) == 0 {
|
// In case it's an organizational runners deployment without any scaling metrics defined,
|
||||||
|
// we assume that the desired replicas should always be `minReplicas + capacityReservedThroughWebhook`.
|
||||||
|
// See https://github.com/actions-runner-controller/actions-runner-controller/issues/377#issuecomment-793372693
|
||||||
|
if metrics == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(metrics.RepositoryNames) == 0 {
|
||||||
return nil, errors.New("validating autoscaling metrics: spec.autoscaling.metrics[].repositoryNames is required and must have one more more entries for organizational runner deployment")
|
return nil, errors.New("validating autoscaling metrics: spec.autoscaling.metrics[].repositoryNames is required and must have one more more entries for organizational runner deployment")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, repoName := range metrics[0].RepositoryNames {
|
for _, repoName := range metrics.RepositoryNames {
|
||||||
repos = append(repos, []string{orgName, repoName})
|
repos = append(repos, []string{orgName, repoName})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -163,45 +218,25 @@ func (r *HorizontalRunnerAutoscalerReconciler) calculateReplicasByQueuedAndInPro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
minReplicas := *hra.Spec.MinReplicas
|
|
||||||
maxReplicas := *hra.Spec.MaxReplicas
|
|
||||||
necessaryReplicas := queued + inProgress
|
necessaryReplicas := queued + inProgress
|
||||||
|
|
||||||
var desiredReplicas int
|
|
||||||
|
|
||||||
if necessaryReplicas < minReplicas {
|
|
||||||
desiredReplicas = minReplicas
|
|
||||||
} else if necessaryReplicas > maxReplicas {
|
|
||||||
desiredReplicas = maxReplicas
|
|
||||||
} else {
|
|
||||||
desiredReplicas = necessaryReplicas
|
|
||||||
}
|
|
||||||
|
|
||||||
rd.Status.Replicas = &desiredReplicas
|
|
||||||
replicas := desiredReplicas
|
|
||||||
|
|
||||||
r.Log.V(1).Info(
|
r.Log.V(1).Info(
|
||||||
"Calculated desired replicas",
|
fmt.Sprintf("Suggested desired replicas of %d by TotalNumberOfQueuedAndInProgressWorkflowRuns", necessaryReplicas),
|
||||||
"computed_replicas_desired", desiredReplicas,
|
|
||||||
"spec_replicas_min", minReplicas,
|
|
||||||
"spec_replicas_max", maxReplicas,
|
|
||||||
"workflow_runs_completed", completed,
|
"workflow_runs_completed", completed,
|
||||||
"workflow_runs_in_progress", inProgress,
|
"workflow_runs_in_progress", inProgress,
|
||||||
"workflow_runs_queued", queued,
|
"workflow_runs_queued", queued,
|
||||||
"workflow_runs_unknown", unknown,
|
"workflow_runs_unknown", unknown,
|
||||||
"namespace", hra.Namespace,
|
"namespace", hra.Namespace,
|
||||||
"runner_deployment", rd.Name,
|
"kind", st.kind,
|
||||||
|
"name", st.st,
|
||||||
"horizontal_runner_autoscaler", hra.Name,
|
"horizontal_runner_autoscaler", hra.Name,
|
||||||
)
|
)
|
||||||
|
|
||||||
return &replicas, nil
|
return &necessaryReplicas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *HorizontalRunnerAutoscalerReconciler) calculateReplicasByPercentageRunnersBusy(rd v1alpha1.RunnerDeployment, hra v1alpha1.HorizontalRunnerAutoscaler) (*int, error) {
|
func (r *HorizontalRunnerAutoscalerReconciler) suggestReplicasByPercentageRunnersBusy(st scaleTarget, hra v1alpha1.HorizontalRunnerAutoscaler, metrics v1alpha1.MetricSpec) (*int, error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
minReplicas := *hra.Spec.MinReplicas
|
|
||||||
maxReplicas := *hra.Spec.MaxReplicas
|
|
||||||
metrics := hra.Spec.Metrics[0]
|
|
||||||
scaleUpThreshold := defaultScaleUpThreshold
|
scaleUpThreshold := defaultScaleUpThreshold
|
||||||
scaleDownThreshold := defaultScaleDownThreshold
|
scaleDownThreshold := defaultScaleDownThreshold
|
||||||
scaleUpFactor := defaultScaleUpFactor
|
scaleUpFactor := defaultScaleUpFactor
|
||||||
@@ -257,20 +292,15 @@ func (r *HorizontalRunnerAutoscalerReconciler) calculateReplicasByPercentageRunn
|
|||||||
scaleDownFactor = sdf
|
scaleDownFactor = sdf
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the list of runners in namespace. Horizontal Runner Autoscaler should only be responsible for scaling resources in its own ns.
|
runnerMap, err := st.getRunnerMap()
|
||||||
var runnerList v1alpha1.RunnerList
|
if err != nil {
|
||||||
if err := r.List(ctx, &runnerList, client.InNamespace(rd.Namespace)); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
runnerMap := make(map[string]struct{})
|
|
||||||
for _, items := range runnerList.Items {
|
|
||||||
runnerMap[items.Name] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
enterprise = rd.Spec.Template.Spec.Enterprise
|
enterprise = st.enterprise
|
||||||
organization = rd.Spec.Template.Spec.Organization
|
organization = st.org
|
||||||
repository = rd.Spec.Template.Spec.Repository
|
repository = st.repo
|
||||||
)
|
)
|
||||||
|
|
||||||
// ListRunners will return all runners managed by GitHub - not restricted to ns
|
// ListRunners will return all runners managed by GitHub - not restricted to ns
|
||||||
@@ -282,56 +312,71 @@ func (r *HorizontalRunnerAutoscalerReconciler) calculateReplicasByPercentageRunn
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
numRunners := len(runnerList.Items)
|
|
||||||
numRunnersBusy := 0
|
var desiredReplicasBefore int
|
||||||
|
|
||||||
|
if v := st.replicas; v == nil {
|
||||||
|
desiredReplicasBefore = 1
|
||||||
|
} else {
|
||||||
|
desiredReplicasBefore = *v
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
numRunners int
|
||||||
|
numRunnersRegistered int
|
||||||
|
numRunnersBusy int
|
||||||
|
)
|
||||||
|
|
||||||
|
numRunners = len(runnerMap)
|
||||||
|
|
||||||
for _, runner := range runners {
|
for _, runner := range runners {
|
||||||
if _, ok := runnerMap[*runner.Name]; ok && runner.GetBusy() {
|
if _, ok := runnerMap[*runner.Name]; ok {
|
||||||
|
numRunnersRegistered++
|
||||||
|
|
||||||
|
if runner.GetBusy() {
|
||||||
numRunnersBusy++
|
numRunnersBusy++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var desiredReplicas int
|
var desiredReplicas int
|
||||||
fractionBusy := float64(numRunnersBusy) / float64(numRunners)
|
fractionBusy := float64(numRunnersBusy) / float64(desiredReplicasBefore)
|
||||||
if fractionBusy >= scaleUpThreshold {
|
if fractionBusy >= scaleUpThreshold {
|
||||||
if scaleUpAdjustment > 0 {
|
if scaleUpAdjustment > 0 {
|
||||||
desiredReplicas = numRunners + scaleUpAdjustment
|
desiredReplicas = desiredReplicasBefore + scaleUpAdjustment
|
||||||
} else {
|
} else {
|
||||||
desiredReplicas = int(math.Ceil(float64(numRunners) * scaleUpFactor))
|
desiredReplicas = int(math.Ceil(float64(desiredReplicasBefore) * scaleUpFactor))
|
||||||
}
|
}
|
||||||
} else if fractionBusy < scaleDownThreshold {
|
} else if fractionBusy < scaleDownThreshold {
|
||||||
if scaleDownAdjustment > 0 {
|
if scaleDownAdjustment > 0 {
|
||||||
desiredReplicas = numRunners - scaleDownAdjustment
|
desiredReplicas = desiredReplicasBefore - scaleDownAdjustment
|
||||||
} else {
|
} else {
|
||||||
desiredReplicas = int(float64(numRunners) * scaleDownFactor)
|
desiredReplicas = int(float64(desiredReplicasBefore) * scaleDownFactor)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
desiredReplicas = *rd.Spec.Replicas
|
desiredReplicas = *st.replicas
|
||||||
}
|
}
|
||||||
|
|
||||||
if desiredReplicas < minReplicas {
|
// NOTES for operators:
|
||||||
desiredReplicas = minReplicas
|
//
|
||||||
} else if desiredReplicas > maxReplicas {
|
// - num_runners can be as twice as large as replicas_desired_before while
|
||||||
desiredReplicas = maxReplicas
|
// the runnerdeployment controller is replacing RunnerReplicaSet for runner update.
|
||||||
}
|
|
||||||
|
|
||||||
r.Log.V(1).Info(
|
r.Log.V(1).Info(
|
||||||
"Calculated desired replicas",
|
fmt.Sprintf("Suggested desired replicas of %d by PercentageRunnersBusy", desiredReplicas),
|
||||||
"computed_replicas_desired", desiredReplicas,
|
"replicas_desired_before", desiredReplicasBefore,
|
||||||
"spec_replicas_min", minReplicas,
|
"replicas_desired", desiredReplicas,
|
||||||
"spec_replicas_max", maxReplicas,
|
|
||||||
"current_replicas", rd.Spec.Replicas,
|
|
||||||
"num_runners", numRunners,
|
"num_runners", numRunners,
|
||||||
|
"num_runners_registered", numRunnersRegistered,
|
||||||
"num_runners_busy", numRunnersBusy,
|
"num_runners_busy", numRunnersBusy,
|
||||||
"namespace", hra.Namespace,
|
"namespace", hra.Namespace,
|
||||||
"runner_deployment", rd.Name,
|
"kind", st.kind,
|
||||||
|
"name", st.st,
|
||||||
"horizontal_runner_autoscaler", hra.Name,
|
"horizontal_runner_autoscaler", hra.Name,
|
||||||
"enterprise", enterprise,
|
"enterprise", enterprise,
|
||||||
"organization", organization,
|
"organization", organization,
|
||||||
"repository", repository,
|
"repository", repository,
|
||||||
)
|
)
|
||||||
|
|
||||||
rd.Status.Replicas = &desiredReplicas
|
return &desiredReplicas, nil
|
||||||
replicas := desiredReplicas
|
|
||||||
|
|
||||||
return &replicas, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
"github.com/summerwind/actions-runner-controller/github"
|
"github.com/actions-runner-controller/actions-runner-controller/github"
|
||||||
"github.com/summerwind/actions-runner-controller/github/fake"
|
"github.com/actions-runner-controller/actions-runner-controller/github/fake"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||||
@@ -203,13 +204,15 @@ func TestDetermineDesiredReplicas_RepositoryRunner(t *testing.T) {
|
|||||||
Spec: v1alpha1.RunnerDeploymentSpec{
|
Spec: v1alpha1.RunnerDeploymentSpec{
|
||||||
Template: v1alpha1.RunnerTemplate{
|
Template: v1alpha1.RunnerTemplate{
|
||||||
Spec: v1alpha1.RunnerSpec{
|
Spec: v1alpha1.RunnerSpec{
|
||||||
|
RunnerConfig: v1alpha1.RunnerConfig{
|
||||||
Repository: tc.repo,
|
Repository: tc.repo,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
Replicas: tc.fixed,
|
Replicas: tc.fixed,
|
||||||
},
|
},
|
||||||
Status: v1alpha1.RunnerDeploymentStatus{
|
Status: v1alpha1.RunnerDeploymentStatus{
|
||||||
Replicas: tc.sReplicas,
|
DesiredReplicas: tc.sReplicas,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +227,14 @@ func TestDetermineDesiredReplicas_RepositoryRunner(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
got, err := h.computeReplicas(rd, hra)
|
minReplicas, _, _, err := h.getMinReplicas(log, metav1Now.Time, hra)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
st := h.scaleTargetFromRD(context.Background(), rd)
|
||||||
|
|
||||||
|
got, _, _, err := h.computeReplicasWithCache(log, metav1Now.Time, st, hra, minReplicas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if tc.err == "" {
|
if tc.err == "" {
|
||||||
t.Fatalf("unexpected error: expected none, got %v", err)
|
t.Fatalf("unexpected error: expected none, got %v", err)
|
||||||
@@ -234,12 +244,8 @@ func TestDetermineDesiredReplicas_RepositoryRunner(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if got == nil {
|
if got != tc.want {
|
||||||
t.Fatalf("unexpected value of rs.Spec.Replicas: nil")
|
t.Errorf("%d: incorrect desired replicas: want %d, got %d", i, tc.want, got)
|
||||||
}
|
|
||||||
|
|
||||||
if *got != tc.want {
|
|
||||||
t.Errorf("%d: incorrect desired replicas: want %d, got %d", i, tc.want, *got)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -424,6 +430,8 @@ func TestDetermineDesiredReplicas_OrganizationalRunner(t *testing.T) {
|
|||||||
_ = v1alpha1.AddToScheme(scheme)
|
_ = v1alpha1.AddToScheme(scheme)
|
||||||
|
|
||||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
server := fake.NewServer(
|
server := fake.NewServer(
|
||||||
fake.WithListRepositoryWorkflowRunsResponse(200, tc.workflowRuns, tc.workflowRuns_queued, tc.workflowRuns_in_progress),
|
fake.WithListRepositoryWorkflowRunsResponse(200, tc.workflowRuns, tc.workflowRuns_queued, tc.workflowRuns_in_progress),
|
||||||
fake.WithListWorkflowJobsResponse(200, tc.workflowJobs),
|
fake.WithListWorkflowJobsResponse(200, tc.workflowJobs),
|
||||||
@@ -443,15 +451,27 @@ func TestDetermineDesiredReplicas_OrganizationalRunner(t *testing.T) {
|
|||||||
Name: "testrd",
|
Name: "testrd",
|
||||||
},
|
},
|
||||||
Spec: v1alpha1.RunnerDeploymentSpec{
|
Spec: v1alpha1.RunnerDeploymentSpec{
|
||||||
|
Selector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
Template: v1alpha1.RunnerTemplate{
|
Template: v1alpha1.RunnerTemplate{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
Spec: v1alpha1.RunnerSpec{
|
Spec: v1alpha1.RunnerSpec{
|
||||||
|
RunnerConfig: v1alpha1.RunnerConfig{
|
||||||
Organization: tc.org,
|
Organization: tc.org,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
Replicas: tc.fixed,
|
Replicas: tc.fixed,
|
||||||
},
|
},
|
||||||
Status: v1alpha1.RunnerDeploymentStatus{
|
Status: v1alpha1.RunnerDeploymentStatus{
|
||||||
Replicas: tc.sReplicas,
|
DesiredReplicas: tc.sReplicas,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,7 +495,14 @@ func TestDetermineDesiredReplicas_OrganizationalRunner(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
got, err := h.computeReplicas(rd, hra)
|
minReplicas, _, _, err := h.getMinReplicas(log, metav1Now.Time, hra)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
st := h.scaleTargetFromRD(context.Background(), rd)
|
||||||
|
|
||||||
|
got, _, _, err := h.computeReplicasWithCache(log, metav1Now.Time, st, hra, minReplicas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if tc.err == "" {
|
if tc.err == "" {
|
||||||
t.Fatalf("unexpected error: expected none, got %v", err)
|
t.Fatalf("unexpected error: expected none, got %v", err)
|
||||||
@@ -485,12 +512,8 @@ func TestDetermineDesiredReplicas_OrganizationalRunner(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if got == nil {
|
if got != tc.want {
|
||||||
t.Fatalf("unexpected value of rs.Spec.Replicas: nil, wanted %v", tc.want)
|
t.Errorf("%d: incorrect desired replicas: want %d, got %d", i, tc.want, got)
|
||||||
}
|
|
||||||
|
|
||||||
if *got != tc.want {
|
|
||||||
t.Errorf("%d: incorrect desired replicas: want %d, got %d", i, tc.want, *got)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"net/http"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
gogithub "github.com/google/go-github/v33/github"
|
gogithub "github.com/google/go-github/v33/github"
|
||||||
@@ -33,7 +35,7 @@ import (
|
|||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -52,13 +54,14 @@ type HorizontalRunnerAutoscalerGitHubWebhook struct {
|
|||||||
// the administrator is generated and specified in GitHub Web UI.
|
// the administrator is generated and specified in GitHub Web UI.
|
||||||
SecretKeyBytes []byte
|
SecretKeyBytes []byte
|
||||||
|
|
||||||
// WatchNamespace is the namespace to watch for HorizontalRunnerAutoscaler's to be
|
// Namespace is the namespace to watch for HorizontalRunnerAutoscaler's to be
|
||||||
// scaled on Webhook.
|
// scaled on Webhook.
|
||||||
// Set to empty for letting it watch for all namespaces.
|
// Set to empty for letting it watch for all namespaces.
|
||||||
WatchNamespace string
|
Namespace string
|
||||||
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Reconcile(request reconcile.Request) (reconcile.Result, error) {
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Reconcile(_ context.Context, request reconcile.Request) (reconcile.Result, error) {
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +96,12 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// respond ok to GET / e.g. for health check
|
||||||
|
if r.Method == http.MethodGet {
|
||||||
|
fmt.Fprintln(w, "webhook server is running")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var payload []byte
|
var payload []byte
|
||||||
|
|
||||||
if len(autoscaler.SecretKeyBytes) > 0 {
|
if len(autoscaler.SecretKeyBytes) > 0 {
|
||||||
@@ -126,30 +135,54 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
|
|
||||||
var target *ScaleTarget
|
var target *ScaleTarget
|
||||||
|
|
||||||
autoscaler.Log.Info("processing webhook event", "eventType", webhookType)
|
log := autoscaler.Log.WithValues(
|
||||||
|
"event", webhookType,
|
||||||
|
"hookID", r.Header.Get("X-GitHub-Hook-ID"),
|
||||||
|
"delivery", r.Header.Get("X-GitHub-Delivery"),
|
||||||
|
)
|
||||||
|
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case *gogithub.PushEvent:
|
case *gogithub.PushEvent:
|
||||||
target, err = autoscaler.getScaleUpTarget(
|
target, err = autoscaler.getScaleUpTarget(
|
||||||
context.TODO(),
|
context.TODO(),
|
||||||
*e.Repo.Name,
|
log,
|
||||||
*e.Repo.Organization,
|
e.Repo.GetName(),
|
||||||
|
e.Repo.Owner.GetLogin(),
|
||||||
|
e.Repo.Owner.GetType(),
|
||||||
autoscaler.MatchPushEvent(e),
|
autoscaler.MatchPushEvent(e),
|
||||||
)
|
)
|
||||||
case *gogithub.PullRequestEvent:
|
case *gogithub.PullRequestEvent:
|
||||||
target, err = autoscaler.getScaleUpTarget(
|
target, err = autoscaler.getScaleUpTarget(
|
||||||
context.TODO(),
|
context.TODO(),
|
||||||
*e.Repo.Name,
|
log,
|
||||||
*e.Repo.Organization.Name,
|
e.Repo.GetName(),
|
||||||
|
e.Repo.Owner.GetLogin(),
|
||||||
|
e.Repo.Owner.GetType(),
|
||||||
autoscaler.MatchPullRequestEvent(e),
|
autoscaler.MatchPullRequestEvent(e),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if pullRequest := e.PullRequest; pullRequest != nil {
|
||||||
|
log = log.WithValues(
|
||||||
|
"pullRequest.base.ref", e.PullRequest.Base.GetRef(),
|
||||||
|
"action", e.GetAction(),
|
||||||
|
)
|
||||||
|
}
|
||||||
case *gogithub.CheckRunEvent:
|
case *gogithub.CheckRunEvent:
|
||||||
target, err = autoscaler.getScaleUpTarget(
|
target, err = autoscaler.getScaleUpTarget(
|
||||||
context.TODO(),
|
context.TODO(),
|
||||||
*e.Repo.Name,
|
log,
|
||||||
*e.Org.Name,
|
e.Repo.GetName(),
|
||||||
|
e.Repo.Owner.GetLogin(),
|
||||||
|
e.Repo.Owner.GetType(),
|
||||||
autoscaler.MatchCheckRunEvent(e),
|
autoscaler.MatchCheckRunEvent(e),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if checkRun := e.GetCheckRun(); checkRun != nil {
|
||||||
|
log = log.WithValues(
|
||||||
|
"checkRun.status", checkRun.GetStatus(),
|
||||||
|
"action", e.GetAction(),
|
||||||
|
)
|
||||||
|
}
|
||||||
case *gogithub.PingEvent:
|
case *gogithub.PingEvent:
|
||||||
ok = true
|
ok = true
|
||||||
|
|
||||||
@@ -158,42 +191,44 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
msg := "pong"
|
msg := "pong"
|
||||||
|
|
||||||
if written, err := w.Write([]byte(msg)); err != nil {
|
if written, err := w.Write([]byte(msg)); err != nil {
|
||||||
autoscaler.Log.Error(err, "failed writing http response", "msg", msg, "written", written)
|
log.Error(err, "failed writing http response", "msg", msg, "written", written)
|
||||||
}
|
}
|
||||||
|
|
||||||
autoscaler.Log.Info("received ping event")
|
log.Info("received ping event")
|
||||||
|
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
autoscaler.Log.Info("unknown event type", "eventType", webhookType)
|
log.Info("unknown event type", "eventType", webhookType)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
autoscaler.Log.Error(err, "handling check_run event")
|
log.Error(err, "handling check_run event")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if target == nil {
|
if target == nil {
|
||||||
msg := "no horizontalrunnerautoscaler to scale for this github event"
|
log.Info(
|
||||||
|
"Scale target not found. If this is unexpected, ensure that there is exactly one repository-wide or organizational runner deployment that matches this webhook event",
|
||||||
|
)
|
||||||
|
|
||||||
autoscaler.Log.Info(msg, "eventType", webhookType)
|
msg := "no horizontalrunnerautoscaler to scale for this github event"
|
||||||
|
|
||||||
ok = true
|
ok = true
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
if written, err := w.Write([]byte(msg)); err != nil {
|
if written, err := w.Write([]byte(msg)); err != nil {
|
||||||
autoscaler.Log.Error(err, "failed writing http response", "msg", msg, "written", written)
|
log.Error(err, "failed writing http response", "msg", msg, "written", written)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := autoscaler.tryScaleUp(context.TODO(), target); err != nil {
|
if err := autoscaler.tryScaleUp(context.TODO(), target); err != nil {
|
||||||
autoscaler.Log.Error(err, "could not scale up")
|
log.Error(err, "could not scale up")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -207,12 +242,12 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
autoscaler.Log.Info(msg)
|
autoscaler.Log.Info(msg)
|
||||||
|
|
||||||
if written, err := w.Write([]byte(msg)); err != nil {
|
if written, err := w.Write([]byte(msg)); err != nil {
|
||||||
autoscaler.Log.Error(err, "failed writing http response", "msg", msg, "written", written)
|
log.Error(err, "failed writing http response", "msg", msg, "written", written)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) findHRAsByKey(ctx context.Context, value string) ([]v1alpha1.HorizontalRunnerAutoscaler, error) {
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) findHRAsByKey(ctx context.Context, value string) ([]v1alpha1.HorizontalRunnerAutoscaler, error) {
|
||||||
ns := autoscaler.WatchNamespace
|
ns := autoscaler.Namespace
|
||||||
|
|
||||||
var defaultListOpts []client.ListOption
|
var defaultListOpts []client.ListOption
|
||||||
|
|
||||||
@@ -226,6 +261,10 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) findHRAsByKey(ctx con
|
|||||||
opts := append([]client.ListOption{}, defaultListOpts...)
|
opts := append([]client.ListOption{}, defaultListOpts...)
|
||||||
opts = append(opts, client.MatchingFields{scaleTargetKey: value})
|
opts = append(opts, client.MatchingFields{scaleTargetKey: value})
|
||||||
|
|
||||||
|
if autoscaler.Namespace != "" {
|
||||||
|
opts = append(opts, client.InNamespace(autoscaler.Namespace))
|
||||||
|
}
|
||||||
|
|
||||||
var hraList v1alpha1.HorizontalRunnerAutoscalerList
|
var hraList v1alpha1.HorizontalRunnerAutoscalerList
|
||||||
|
|
||||||
if err := autoscaler.List(ctx, &hraList, opts...); err != nil {
|
if err := autoscaler.List(ctx, &hraList, opts...); err != nil {
|
||||||
@@ -292,28 +331,64 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getScaleTarget(ctx co
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
autoscaler.Log.V(1).Info(fmt.Sprintf("Found %d HRAs by key", len(hras)), "key", name)
|
||||||
|
|
||||||
targets := autoscaler.searchScaleTargets(hras, f)
|
targets := autoscaler.searchScaleTargets(hras, f)
|
||||||
|
|
||||||
if len(targets) != 1 {
|
n := len(targets)
|
||||||
|
|
||||||
|
if n == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if n > 1 {
|
||||||
|
var scaleTargetIDs []string
|
||||||
|
|
||||||
|
for _, t := range targets {
|
||||||
|
scaleTargetIDs = append(scaleTargetIDs, t.HorizontalRunnerAutoscaler.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
autoscaler.Log.Info(
|
||||||
|
"Found too many scale targets: "+
|
||||||
|
"It must be exactly one to avoid ambiguity. "+
|
||||||
|
"Either set Namespace for the webhook-based autoscaler to let it only find HRAs in the namespace, "+
|
||||||
|
"or update Repository or Organization fields in your RunnerDeployment resources to fix the ambiguity.",
|
||||||
|
"scaleTargets", strings.Join(scaleTargetIDs, ","))
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &targets[0], nil
|
return &targets[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getScaleUpTarget(ctx context.Context, repoNameFromWebhook, orgNameFromWebhook string, f func(v1alpha1.ScaleUpTrigger) bool) (*ScaleTarget, error) {
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getScaleUpTarget(ctx context.Context, log logr.Logger, repo, owner, ownerType string, f func(v1alpha1.ScaleUpTrigger) bool) (*ScaleTarget, error) {
|
||||||
if target, err := autoscaler.getScaleTarget(ctx, repoNameFromWebhook, f); err != nil {
|
repositoryRunnerKey := owner + "/" + repo
|
||||||
|
|
||||||
|
if target, err := autoscaler.getScaleTarget(ctx, repositoryRunnerKey, f); err != nil {
|
||||||
|
log.Info("finding repository-wide runner", "repository", repositoryRunnerKey)
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if target != nil {
|
} else if target != nil {
|
||||||
autoscaler.Log.Info("scale up target is repository-wide runners", "repository", repoNameFromWebhook)
|
log.Info("scale up target is repository-wide runners", "repository", repo)
|
||||||
return target, nil
|
return target, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if target, err := autoscaler.getScaleTarget(ctx, orgNameFromWebhook, f); err != nil {
|
if ownerType == "User" {
|
||||||
|
log.V(1).Info("no repository runner found", "organization", owner)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if target, err := autoscaler.getScaleTarget(ctx, owner, f); err != nil {
|
||||||
|
log.Info("finding organizational runner", "organization", owner)
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if target != nil {
|
} else if target != nil {
|
||||||
autoscaler.Log.Info("scale up target is organizational runners", "repository", orgNameFromWebhook)
|
log.Info("scale up target is organizational runners", "organization", owner)
|
||||||
return target, nil
|
return target, nil
|
||||||
|
} else {
|
||||||
|
log.V(1).Info("no repository runner or organizational runner found",
|
||||||
|
"repository", repositoryRunnerKey,
|
||||||
|
"organization", owner,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -324,8 +399,6 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) tryScaleUp(ctx contex
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log := autoscaler.Log.WithValues("horizontalrunnerautoscaler", target.HorizontalRunnerAutoscaler.Name)
|
|
||||||
|
|
||||||
copy := target.HorizontalRunnerAutoscaler.DeepCopy()
|
copy := target.HorizontalRunnerAutoscaler.DeepCopy()
|
||||||
|
|
||||||
amount := 1
|
amount := 1
|
||||||
@@ -334,25 +407,43 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) tryScaleUp(ctx contex
|
|||||||
amount = target.ScaleUpTrigger.Amount
|
amount = target.ScaleUpTrigger.Amount
|
||||||
}
|
}
|
||||||
|
|
||||||
copy.Spec.CapacityReservations = append(copy.Spec.CapacityReservations, v1alpha1.CapacityReservation{
|
capacityReservations := getValidCapacityReservations(copy)
|
||||||
|
|
||||||
|
copy.Spec.CapacityReservations = append(capacityReservations, v1alpha1.CapacityReservation{
|
||||||
ExpirationTime: metav1.Time{Time: time.Now().Add(target.ScaleUpTrigger.Duration.Duration)},
|
ExpirationTime: metav1.Time{Time: time.Now().Add(target.ScaleUpTrigger.Duration.Duration)},
|
||||||
Replicas: amount,
|
Replicas: amount,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := autoscaler.Client.Update(ctx, copy); err != nil {
|
if err := autoscaler.Client.Patch(ctx, copy, client.MergeFrom(&target.HorizontalRunnerAutoscaler)); err != nil {
|
||||||
log.Error(err, "Failed to update horizontalrunnerautoscaler resource")
|
return fmt.Errorf("patching horizontalrunnerautoscaler to add capacity reservation: %w", err)
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getValidCapacityReservations(autoscaler *v1alpha1.HorizontalRunnerAutoscaler) []v1alpha1.CapacityReservation {
|
||||||
|
var capacityReservations []v1alpha1.CapacityReservation
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
for _, reservation := range autoscaler.Spec.CapacityReservations {
|
||||||
|
if reservation.ExpirationTime.Time.After(now) {
|
||||||
|
capacityReservations = append(capacityReservations, reservation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return capacityReservations
|
||||||
|
}
|
||||||
|
|
||||||
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) SetupWithManager(mgr ctrl.Manager) error {
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
name := "webhookbasedautoscaler"
|
name := "webhookbasedautoscaler"
|
||||||
|
if autoscaler.Name != "" {
|
||||||
|
name = autoscaler.Name
|
||||||
|
}
|
||||||
|
|
||||||
autoscaler.Recorder = mgr.GetEventRecorderFor(name)
|
autoscaler.Recorder = mgr.GetEventRecorderFor(name)
|
||||||
|
|
||||||
if err := mgr.GetFieldIndexer().IndexField(&v1alpha1.HorizontalRunnerAutoscaler{}, scaleTargetKey, func(rawObj runtime.Object) []string {
|
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &v1alpha1.HorizontalRunnerAutoscaler{}, scaleTargetKey, func(rawObj client.Object) []string {
|
||||||
hra := rawObj.(*v1alpha1.HorizontalRunnerAutoscaler)
|
hra := rawObj.(*v1alpha1.HorizontalRunnerAutoscaler)
|
||||||
|
|
||||||
if hra.Spec.ScaleTargetRef.Name == "" {
|
if hra.Spec.ScaleTargetRef.Name == "" {
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/pkg/actionsglob"
|
||||||
"github.com/google/go-github/v33/github"
|
"github.com/google/go-github/v33/github"
|
||||||
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) MatchCheckRunEvent(event *github.CheckRunEvent) func(scaleUpTrigger v1alpha1.ScaleUpTrigger) bool {
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) MatchCheckRunEvent(event *github.CheckRunEvent) func(scaleUpTrigger v1alpha1.ScaleUpTrigger) bool {
|
||||||
@@ -27,6 +28,16 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) MatchCheckRunEvent(ev
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if checkRun := event.CheckRun; checkRun != nil && len(cr.Names) > 0 {
|
||||||
|
for _, pat := range cr.Names {
|
||||||
|
if r := actionsglob.Match(pat, checkRun.GetName()); r {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
"github.com/google/go-github/v33/github"
|
"github.com/google/go-github/v33/github"
|
||||||
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) MatchPullRequestEvent(event *github.PullRequestEvent) func(scaleUpTrigger v1alpha1.ScaleUpTrigger) bool {
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) MatchPullRequestEvent(event *github.PullRequestEvent) func(scaleUpTrigger v1alpha1.ScaleUpTrigger) bool {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
"github.com/google/go-github/v33/github"
|
"github.com/google/go-github/v33/github"
|
||||||
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) MatchPushEvent(event *github.PushEvent) func(scaleUpTrigger v1alpha1.ScaleUpTrigger) bool {
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) MatchPushEvent(event *github.PushEvent) func(scaleUpTrigger v1alpha1.ScaleUpTrigger) bool {
|
||||||
|
|||||||
@@ -4,18 +4,22 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-logr/logr"
|
|
||||||
"github.com/google/go-github/v33/github"
|
|
||||||
actionsv1alpha1 "github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
actionsv1alpha1 "github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
|
"github.com/go-logr/logr"
|
||||||
|
"github.com/google/go-github/v33/github"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -27,21 +31,37 @@ func init() {
|
|||||||
_ = actionsv1alpha1.AddToScheme(sc)
|
_ = actionsv1alpha1.AddToScheme(sc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWebhookCheckRun(t *testing.T) {
|
func TestOrgWebhookCheckRun(t *testing.T) {
|
||||||
|
f, err := os.Open("testdata/org_webhook_check_run_payload.json")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not open the fixture: %s", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
var e github.CheckRunEvent
|
||||||
|
if err := json.NewDecoder(f).Decode(&e); err != nil {
|
||||||
|
t.Fatalf("invalid json: %s", err)
|
||||||
|
}
|
||||||
testServer(t,
|
testServer(t,
|
||||||
"check_run",
|
"check_run",
|
||||||
&github.CheckRunEvent{
|
&e,
|
||||||
CheckRun: &github.CheckRun{
|
200,
|
||||||
Status: github.String("queued"),
|
"no horizontalrunnerautoscaler to scale for this github event",
|
||||||
},
|
)
|
||||||
Repo: &github.Repository{
|
}
|
||||||
Name: github.String("myorg/myrepo"),
|
|
||||||
},
|
func TestRepoWebhookCheckRun(t *testing.T) {
|
||||||
Org: &github.Organization{
|
f, err := os.Open("testdata/repo_webhook_check_run_payload.json")
|
||||||
Name: github.String("myorg"),
|
if err != nil {
|
||||||
},
|
t.Fatalf("could not open the fixture: %s", err)
|
||||||
Action: github.String("created"),
|
}
|
||||||
},
|
defer f.Close()
|
||||||
|
var e github.CheckRunEvent
|
||||||
|
if err := json.NewDecoder(f).Decode(&e); err != nil {
|
||||||
|
t.Fatalf("invalid json: %s", err)
|
||||||
|
}
|
||||||
|
testServer(t,
|
||||||
|
"check_run",
|
||||||
|
&e,
|
||||||
200,
|
200,
|
||||||
"no horizontalrunnerautoscaler to scale for this github event",
|
"no horizontalrunnerautoscaler to scale for this github event",
|
||||||
)
|
)
|
||||||
@@ -94,6 +114,56 @@ func TestWebhookPing(t *testing.T) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetRequest(t *testing.T) {
|
||||||
|
hra := HorizontalRunnerAutoscalerGitHubWebhook{}
|
||||||
|
request, _ := http.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
recorder := httptest.ResponseRecorder{}
|
||||||
|
|
||||||
|
hra.Handle(&recorder, request)
|
||||||
|
response := recorder.Result()
|
||||||
|
|
||||||
|
if response.StatusCode != http.StatusOK {
|
||||||
|
t.Errorf("want %d, got %d", http.StatusOK, response.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetValidCapacityReservations(t *testing.T) {
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
hra := &actionsv1alpha1.HorizontalRunnerAutoscaler{
|
||||||
|
Spec: actionsv1alpha1.HorizontalRunnerAutoscalerSpec{
|
||||||
|
CapacityReservations: []actionsv1alpha1.CapacityReservation{
|
||||||
|
{
|
||||||
|
ExpirationTime: metav1.Time{Time: now.Add(-time.Second)},
|
||||||
|
Replicas: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExpirationTime: metav1.Time{Time: now},
|
||||||
|
Replicas: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExpirationTime: metav1.Time{Time: now.Add(time.Second)},
|
||||||
|
Replicas: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
revs := getValidCapacityReservations(hra)
|
||||||
|
|
||||||
|
var count int
|
||||||
|
|
||||||
|
for _, r := range revs {
|
||||||
|
count += r.Replicas
|
||||||
|
}
|
||||||
|
|
||||||
|
want := 3
|
||||||
|
|
||||||
|
if count != want {
|
||||||
|
t.Errorf("want %d, got %d", want, count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func installTestLogger(webhook *HorizontalRunnerAutoscalerGitHubWebhook) *bytes.Buffer {
|
func installTestLogger(webhook *HorizontalRunnerAutoscalerGitHubWebhook) *bytes.Buffer {
|
||||||
logs := &bytes.Buffer{}
|
logs := &bytes.Buffer{}
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,14 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/summerwind/actions-runner-controller/github"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/github"
|
||||||
|
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
@@ -29,10 +34,10 @@ import (
|
|||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/controllers/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -48,16 +53,18 @@ type HorizontalRunnerAutoscalerReconciler struct {
|
|||||||
Scheme *runtime.Scheme
|
Scheme *runtime.Scheme
|
||||||
|
|
||||||
CacheDuration time.Duration
|
CacheDuration time.Duration
|
||||||
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultReplicas = 1
|
||||||
|
|
||||||
// +kubebuilder:rbac:groups=actions.summerwind.dev,resources=runnerdeployments,verbs=get;list;watch;update;patch
|
// +kubebuilder:rbac:groups=actions.summerwind.dev,resources=runnerdeployments,verbs=get;list;watch;update;patch
|
||||||
// +kubebuilder:rbac:groups=actions.summerwind.dev,resources=horizontalrunnerautoscalers,verbs=get;list;watch;create;update;patch;delete
|
// +kubebuilder:rbac:groups=actions.summerwind.dev,resources=horizontalrunnerautoscalers,verbs=get;list;watch;create;update;patch;delete
|
||||||
// +kubebuilder:rbac:groups=actions.summerwind.dev,resources=horizontalrunnerautoscalers/finalizers,verbs=get;list;watch;create;update;patch;delete
|
// +kubebuilder:rbac:groups=actions.summerwind.dev,resources=horizontalrunnerautoscalers/finalizers,verbs=get;list;watch;create;update;patch;delete
|
||||||
// +kubebuilder:rbac:groups=actions.summerwind.dev,resources=horizontalrunnerautoscalers/status,verbs=get;update;patch
|
// +kubebuilder:rbac:groups=actions.summerwind.dev,resources=horizontalrunnerautoscalers/status,verbs=get;update;patch
|
||||||
// +kubebuilder:rbac:groups=core,resources=events,verbs=create;patch
|
// +kubebuilder:rbac:groups=core,resources=events,verbs=create;patch
|
||||||
|
|
||||||
func (r *HorizontalRunnerAutoscalerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
func (r *HorizontalRunnerAutoscalerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
ctx := context.Background()
|
|
||||||
log := r.Log.WithValues("horizontalrunnerautoscaler", req.NamespacedName)
|
log := r.Log.WithValues("horizontalrunnerautoscaler", req.NamespacedName)
|
||||||
|
|
||||||
var hra v1alpha1.HorizontalRunnerAutoscaler
|
var hra v1alpha1.HorizontalRunnerAutoscaler
|
||||||
@@ -69,6 +76,12 @@ func (r *HorizontalRunnerAutoscalerReconciler) Reconcile(req ctrl.Request) (ctrl
|
|||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
metrics.SetHorizontalRunnerAutoscalerSpec(hra.ObjectMeta, hra.Spec)
|
||||||
|
|
||||||
|
kind := hra.Spec.ScaleTargetRef.Kind
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case "", "RunnerDeployment":
|
||||||
var rd v1alpha1.RunnerDeployment
|
var rd v1alpha1.RunnerDeployment
|
||||||
if err := r.Get(ctx, types.NamespacedName{
|
if err := r.Get(ctx, types.NamespacedName{
|
||||||
Namespace: req.Namespace,
|
Namespace: req.Namespace,
|
||||||
@@ -81,16 +94,175 @@ func (r *HorizontalRunnerAutoscalerReconciler) Reconcile(req ctrl.Request) (ctrl
|
|||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
st := r.scaleTargetFromRD(ctx, rd)
|
||||||
|
|
||||||
|
return r.reconcile(ctx, req, log, hra, st, func(newDesiredReplicas int) error {
|
||||||
|
currentDesiredReplicas := getIntOrDefault(rd.Spec.Replicas, defaultReplicas)
|
||||||
|
|
||||||
|
// Please add more conditions that we can in-place update the newest runnerreplicaset without disruption
|
||||||
|
if currentDesiredReplicas != newDesiredReplicas {
|
||||||
|
copy := rd.DeepCopy()
|
||||||
|
copy.Spec.Replicas = &newDesiredReplicas
|
||||||
|
|
||||||
|
if err := r.Client.Patch(ctx, copy, client.MergeFrom(&rd)); err != nil {
|
||||||
|
return fmt.Errorf("patching runnerdeployment to have %d replicas: %w", newDesiredReplicas, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
case "RunnerSet":
|
||||||
|
var rs v1alpha1.RunnerSet
|
||||||
|
if err := r.Get(ctx, types.NamespacedName{
|
||||||
|
Namespace: req.Namespace,
|
||||||
|
Name: hra.Spec.ScaleTargetRef.Name,
|
||||||
|
}, &rs); err != nil {
|
||||||
|
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !rs.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
var replicas *int
|
var replicas *int
|
||||||
|
|
||||||
replicasFromCache := r.getDesiredReplicasFromCache(hra)
|
if rs.Spec.Replicas != nil {
|
||||||
|
v := int(*rs.Spec.Replicas)
|
||||||
|
replicas = &v
|
||||||
|
}
|
||||||
|
|
||||||
if replicasFromCache != nil {
|
st := scaleTarget{
|
||||||
replicas = replicasFromCache
|
st: rs.Name,
|
||||||
} else {
|
kind: "runnerset",
|
||||||
var err error
|
enterprise: rs.Spec.Enterprise,
|
||||||
|
org: rs.Spec.Organization,
|
||||||
|
repo: rs.Spec.Repository,
|
||||||
|
replicas: replicas,
|
||||||
|
getRunnerMap: func() (map[string]struct{}, error) {
|
||||||
|
// return the list of runners in namespace. Horizontal Runner Autoscaler should only be responsible for scaling resources in its own ns.
|
||||||
|
var runnerPodList corev1.PodList
|
||||||
|
|
||||||
replicas, err = r.computeReplicas(rd, hra)
|
var opts []client.ListOption
|
||||||
|
|
||||||
|
opts = append(opts, client.InNamespace(rs.Namespace))
|
||||||
|
|
||||||
|
selector, err := metav1.LabelSelectorAsSelector(rs.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = append(opts, client.MatchingLabelsSelector{Selector: selector})
|
||||||
|
|
||||||
|
r.Log.V(2).Info("Finding runnerset's runner pods with selector", "ns", rs.Namespace)
|
||||||
|
|
||||||
|
if err := r.List(
|
||||||
|
ctx,
|
||||||
|
&runnerPodList,
|
||||||
|
opts...,
|
||||||
|
); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runnerMap := make(map[string]struct{})
|
||||||
|
for _, items := range runnerPodList.Items {
|
||||||
|
runnerMap[items.Name] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return runnerMap, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.reconcile(ctx, req, log, hra, st, func(newDesiredReplicas int) error {
|
||||||
|
var replicas *int
|
||||||
|
if rs.Spec.Replicas != nil {
|
||||||
|
v := int(*rs.Spec.Replicas)
|
||||||
|
replicas = &v
|
||||||
|
}
|
||||||
|
currentDesiredReplicas := getIntOrDefault(replicas, defaultReplicas)
|
||||||
|
|
||||||
|
if currentDesiredReplicas != newDesiredReplicas {
|
||||||
|
copy := rs.DeepCopy()
|
||||||
|
v := int32(newDesiredReplicas)
|
||||||
|
copy.Spec.Replicas = &v
|
||||||
|
|
||||||
|
if err := r.Client.Patch(ctx, copy, client.MergeFrom(&rs)); err != nil {
|
||||||
|
return fmt.Errorf("patching runnerset to have %d replicas: %w", newDesiredReplicas, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info(fmt.Sprintf("Unsupported scale target %s %s: kind %s is not supported. valid kinds are %s and %s", kind, hra.Spec.ScaleTargetRef.Name, kind, "RunnerDeployment", "RunnerSet"))
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HorizontalRunnerAutoscalerReconciler) scaleTargetFromRD(ctx context.Context, rd v1alpha1.RunnerDeployment) scaleTarget {
|
||||||
|
st := scaleTarget{
|
||||||
|
st: rd.Name,
|
||||||
|
kind: "runnerdeployment",
|
||||||
|
enterprise: rd.Spec.Template.Spec.Enterprise,
|
||||||
|
org: rd.Spec.Template.Spec.Organization,
|
||||||
|
repo: rd.Spec.Template.Spec.Repository,
|
||||||
|
replicas: rd.Spec.Replicas,
|
||||||
|
getRunnerMap: func() (map[string]struct{}, error) {
|
||||||
|
// return the list of runners in namespace. Horizontal Runner Autoscaler should only be responsible for scaling resources in its own ns.
|
||||||
|
var runnerList v1alpha1.RunnerList
|
||||||
|
|
||||||
|
var opts []client.ListOption
|
||||||
|
|
||||||
|
opts = append(opts, client.InNamespace(rd.Namespace))
|
||||||
|
|
||||||
|
selector, err := metav1.LabelSelectorAsSelector(getSelector(&rd))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = append(opts, client.MatchingLabelsSelector{Selector: selector})
|
||||||
|
|
||||||
|
r.Log.V(2).Info("Finding runners with selector", "ns", rd.Namespace)
|
||||||
|
|
||||||
|
if err := r.List(
|
||||||
|
ctx,
|
||||||
|
&runnerList,
|
||||||
|
opts...,
|
||||||
|
); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runnerMap := make(map[string]struct{})
|
||||||
|
for _, items := range runnerList.Items {
|
||||||
|
runnerMap[items.Name] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return runnerMap, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return st
|
||||||
|
}
|
||||||
|
|
||||||
|
type scaleTarget struct {
|
||||||
|
st, kind string
|
||||||
|
enterprise, repo, org string
|
||||||
|
replicas *int
|
||||||
|
|
||||||
|
getRunnerMap func() (map[string]struct{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HorizontalRunnerAutoscalerReconciler) reconcile(ctx context.Context, req ctrl.Request, log logr.Logger, hra v1alpha1.HorizontalRunnerAutoscaler, st scaleTarget, updatedDesiredReplicas func(int) error) (ctrl.Result, error) {
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
minReplicas, active, upcoming, err := r.getMinReplicas(log, now, hra)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err, "Could not compute min replicas")
|
||||||
|
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
newDesiredReplicas, computedReplicas, computedReplicasFromCache, err := r.computeReplicasWithCache(log, now, st, hra, minReplicas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Recorder.Event(&hra, corev1.EventTypeNormal, "RunnerAutoscalingFailure", err.Error())
|
r.Recorder.Event(&hra, corev1.EventTypeNormal, "RunnerAutoscalingFailure", err.Error())
|
||||||
|
|
||||||
@@ -98,63 +270,25 @@ func (r *HorizontalRunnerAutoscalerReconciler) Reconcile(req ctrl.Request) (ctrl
|
|||||||
|
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const defaultReplicas = 1
|
|
||||||
|
|
||||||
currentDesiredReplicas := getIntOrDefault(rd.Spec.Replicas, defaultReplicas)
|
|
||||||
newDesiredReplicas := getIntOrDefault(replicas, defaultReplicas)
|
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
|
|
||||||
for _, reservation := range hra.Spec.CapacityReservations {
|
|
||||||
if reservation.ExpirationTime.Time.After(now) {
|
|
||||||
newDesiredReplicas += reservation.Replicas
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if hra.Spec.MaxReplicas != nil && *hra.Spec.MaxReplicas < newDesiredReplicas {
|
|
||||||
newDesiredReplicas = *hra.Spec.MaxReplicas
|
|
||||||
}
|
|
||||||
|
|
||||||
// Please add more conditions that we can in-place update the newest runnerreplicaset without disruption
|
|
||||||
if currentDesiredReplicas != newDesiredReplicas {
|
|
||||||
copy := rd.DeepCopy()
|
|
||||||
copy.Spec.Replicas = &newDesiredReplicas
|
|
||||||
|
|
||||||
if err := r.Client.Update(ctx, copy); err != nil {
|
|
||||||
log.Error(err, "Failed to update runnerderployment resource")
|
|
||||||
|
|
||||||
|
if err := updatedDesiredReplicas(newDesiredReplicas); err != nil {
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var updated *v1alpha1.HorizontalRunnerAutoscaler
|
updated := hra.DeepCopy()
|
||||||
|
|
||||||
if hra.Status.DesiredReplicas == nil || *hra.Status.DesiredReplicas != *replicas {
|
if hra.Status.DesiredReplicas == nil || *hra.Status.DesiredReplicas != newDesiredReplicas {
|
||||||
updated = hra.DeepCopy()
|
if (hra.Status.DesiredReplicas == nil && newDesiredReplicas > 1) ||
|
||||||
|
(hra.Status.DesiredReplicas != nil && newDesiredReplicas > *hra.Status.DesiredReplicas) {
|
||||||
if (hra.Status.DesiredReplicas == nil && *replicas > 1) ||
|
|
||||||
(hra.Status.DesiredReplicas != nil && *replicas > *hra.Status.DesiredReplicas) {
|
|
||||||
|
|
||||||
updated.Status.LastSuccessfulScaleOutTime = &metav1.Time{Time: time.Now()}
|
updated.Status.LastSuccessfulScaleOutTime = &metav1.Time{Time: time.Now()}
|
||||||
}
|
}
|
||||||
|
|
||||||
updated.Status.DesiredReplicas = replicas
|
updated.Status.DesiredReplicas = &newDesiredReplicas
|
||||||
}
|
}
|
||||||
|
|
||||||
if replicasFromCache == nil {
|
if computedReplicasFromCache == nil {
|
||||||
if updated == nil {
|
cacheEntries := getValidCacheEntries(updated, now)
|
||||||
updated = hra.DeepCopy()
|
|
||||||
}
|
|
||||||
|
|
||||||
var cacheEntries []v1alpha1.CacheEntry
|
|
||||||
|
|
||||||
for _, ent := range updated.Status.CacheEntries {
|
|
||||||
if ent.ExpirationTime.Before(&metav1.Time{Time: now}) {
|
|
||||||
cacheEntries = append(cacheEntries, ent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var cacheDuration time.Duration
|
var cacheDuration time.Duration
|
||||||
|
|
||||||
@@ -164,26 +298,65 @@ func (r *HorizontalRunnerAutoscalerReconciler) Reconcile(req ctrl.Request) (ctrl
|
|||||||
cacheDuration = 10 * time.Minute
|
cacheDuration = 10 * time.Minute
|
||||||
}
|
}
|
||||||
|
|
||||||
updated.Status.CacheEntries = append(updated.Status.CacheEntries, v1alpha1.CacheEntry{
|
updated.Status.CacheEntries = append(cacheEntries, v1alpha1.CacheEntry{
|
||||||
Key: v1alpha1.CacheEntryKeyDesiredReplicas,
|
Key: v1alpha1.CacheEntryKeyDesiredReplicas,
|
||||||
Value: *replicas,
|
Value: computedReplicas,
|
||||||
ExpirationTime: metav1.Time{Time: time.Now().Add(cacheDuration)},
|
ExpirationTime: metav1.Time{Time: time.Now().Add(cacheDuration)},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if updated != nil {
|
var overridesSummary string
|
||||||
if err := r.Status().Update(ctx, updated); err != nil {
|
|
||||||
log.Error(err, "Failed to update horizontalrunnerautoscaler status")
|
|
||||||
|
|
||||||
return ctrl.Result{}, err
|
if (active != nil && upcoming == nil) || (active != nil && upcoming != nil && active.Period.EndTime.Before(upcoming.Period.StartTime)) {
|
||||||
|
after := defaultReplicas
|
||||||
|
if hra.Spec.MinReplicas != nil && *hra.Spec.MinReplicas >= 0 {
|
||||||
|
after = *hra.Spec.MinReplicas
|
||||||
|
}
|
||||||
|
|
||||||
|
overridesSummary = fmt.Sprintf("min=%d time=%s", after, active.Period.EndTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
if active == nil && upcoming != nil || (active != nil && upcoming != nil && active.Period.EndTime.After(upcoming.Period.StartTime)) {
|
||||||
|
if upcoming.ScheduledOverride.MinReplicas != nil {
|
||||||
|
overridesSummary = fmt.Sprintf("min=%d time=%s", *upcoming.ScheduledOverride.MinReplicas, upcoming.Period.StartTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if overridesSummary != "" {
|
||||||
|
updated.Status.ScheduledOverridesSummary = &overridesSummary
|
||||||
|
} else {
|
||||||
|
updated.Status.ScheduledOverridesSummary = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(hra.Status, updated.Status) {
|
||||||
|
metrics.SetHorizontalRunnerAutoscalerStatus(updated.ObjectMeta, updated.Status)
|
||||||
|
|
||||||
|
if err := r.Status().Patch(ctx, updated, client.MergeFrom(&hra)); err != nil {
|
||||||
|
return ctrl.Result{}, fmt.Errorf("patching horizontalrunnerautoscaler status: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getValidCacheEntries(hra *v1alpha1.HorizontalRunnerAutoscaler, now time.Time) []v1alpha1.CacheEntry {
|
||||||
|
var cacheEntries []v1alpha1.CacheEntry
|
||||||
|
|
||||||
|
for _, ent := range hra.Status.CacheEntries {
|
||||||
|
if ent.ExpirationTime.After(now) {
|
||||||
|
cacheEntries = append(cacheEntries, ent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cacheEntries
|
||||||
|
}
|
||||||
|
|
||||||
func (r *HorizontalRunnerAutoscalerReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
func (r *HorizontalRunnerAutoscalerReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
name := "horizontalrunnerautoscaler-controller"
|
name := "horizontalrunnerautoscaler-controller"
|
||||||
|
if r.Name != "" {
|
||||||
|
name = r.Name
|
||||||
|
}
|
||||||
|
|
||||||
r.Recorder = mgr.GetEventRecorderFor(name)
|
r.Recorder = mgr.GetEventRecorderFor(name)
|
||||||
|
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
@@ -192,14 +365,132 @@ func (r *HorizontalRunnerAutoscalerReconciler) SetupWithManager(mgr ctrl.Manager
|
|||||||
Complete(r)
|
Complete(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *HorizontalRunnerAutoscalerReconciler) computeReplicas(rd v1alpha1.RunnerDeployment, hra v1alpha1.HorizontalRunnerAutoscaler) (*int, error) {
|
type Override struct {
|
||||||
var computedReplicas *int
|
ScheduledOverride v1alpha1.ScheduledOverride
|
||||||
|
Period Period
|
||||||
replicas, err := r.determineDesiredReplicas(rd, hra)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *HorizontalRunnerAutoscalerReconciler) matchScheduledOverrides(log logr.Logger, now time.Time, hra v1alpha1.HorizontalRunnerAutoscaler) (*int, *Override, *Override, error) {
|
||||||
|
var minReplicas *int
|
||||||
|
var active, upcoming *Override
|
||||||
|
|
||||||
|
for _, o := range hra.Spec.ScheduledOverrides {
|
||||||
|
log.V(1).Info(
|
||||||
|
"Checking scheduled override",
|
||||||
|
"now", now,
|
||||||
|
"startTime", o.StartTime,
|
||||||
|
"endTime", o.EndTime,
|
||||||
|
"frequency", o.RecurrenceRule.Frequency,
|
||||||
|
"untilTime", o.RecurrenceRule.UntilTime,
|
||||||
|
)
|
||||||
|
|
||||||
|
a, u, err := MatchSchedule(
|
||||||
|
now, o.StartTime.Time, o.EndTime.Time,
|
||||||
|
RecurrenceRule{
|
||||||
|
Frequency: o.RecurrenceRule.Frequency,
|
||||||
|
UntilTime: o.RecurrenceRule.UntilTime.Time,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return minReplicas, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the first when there are two or more active scheduled overrides,
|
||||||
|
// as the spec defines that the earlier scheduled override is prioritized higher than later ones.
|
||||||
|
if a != nil && active == nil {
|
||||||
|
active = &Override{Period: *a, ScheduledOverride: o}
|
||||||
|
|
||||||
|
if o.MinReplicas != nil {
|
||||||
|
minReplicas = o.MinReplicas
|
||||||
|
|
||||||
|
log.V(1).Info(
|
||||||
|
"Found active scheduled override",
|
||||||
|
"activeStartTime", a.StartTime,
|
||||||
|
"activeEndTime", a.EndTime,
|
||||||
|
"activeMinReplicas", minReplicas,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if u != nil && (upcoming == nil || u.StartTime.Before(upcoming.Period.StartTime)) {
|
||||||
|
upcoming = &Override{Period: *u, ScheduledOverride: o}
|
||||||
|
|
||||||
|
log.V(1).Info(
|
||||||
|
"Found upcoming scheduled override",
|
||||||
|
"upcomingStartTime", u.StartTime,
|
||||||
|
"upcomingEndTime", u.EndTime,
|
||||||
|
"upcomingMinReplicas", o.MinReplicas,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return minReplicas, active, upcoming, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HorizontalRunnerAutoscalerReconciler) getMinReplicas(log logr.Logger, now time.Time, hra v1alpha1.HorizontalRunnerAutoscaler) (int, *Override, *Override, error) {
|
||||||
|
minReplicas := defaultReplicas
|
||||||
|
if hra.Spec.MinReplicas != nil && *hra.Spec.MinReplicas >= 0 {
|
||||||
|
minReplicas = *hra.Spec.MinReplicas
|
||||||
|
}
|
||||||
|
|
||||||
|
m, active, upcoming, err := r.matchScheduledOverrides(log, now, hra)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, nil, err
|
||||||
|
} else if m != nil {
|
||||||
|
minReplicas = *m
|
||||||
|
}
|
||||||
|
|
||||||
|
return minReplicas, active, upcoming, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HorizontalRunnerAutoscalerReconciler) computeReplicasWithCache(log logr.Logger, now time.Time, st scaleTarget, hra v1alpha1.HorizontalRunnerAutoscaler, minReplicas int) (int, int, *int, error) {
|
||||||
|
var suggestedReplicas int
|
||||||
|
|
||||||
|
suggestedReplicasFromCache := r.fetchSuggestedReplicasFromCache(hra)
|
||||||
|
|
||||||
|
var cached *int
|
||||||
|
|
||||||
|
if suggestedReplicasFromCache != nil {
|
||||||
|
cached = suggestedReplicasFromCache
|
||||||
|
|
||||||
|
if cached == nil {
|
||||||
|
suggestedReplicas = minReplicas
|
||||||
|
} else {
|
||||||
|
suggestedReplicas = *cached
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v, err := r.suggestDesiredReplicas(st, hra)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if v == nil {
|
||||||
|
suggestedReplicas = minReplicas
|
||||||
|
} else {
|
||||||
|
suggestedReplicas = *v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var reserved int
|
||||||
|
|
||||||
|
for _, reservation := range hra.Spec.CapacityReservations {
|
||||||
|
if reservation.ExpirationTime.Time.After(now) {
|
||||||
|
reserved += reservation.Replicas
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newDesiredReplicas := suggestedReplicas + reserved
|
||||||
|
|
||||||
|
if newDesiredReplicas < minReplicas {
|
||||||
|
newDesiredReplicas = minReplicas
|
||||||
|
} else if hra.Spec.MaxReplicas != nil && newDesiredReplicas > *hra.Spec.MaxReplicas {
|
||||||
|
newDesiredReplicas = *hra.Spec.MaxReplicas
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Delay scaling-down for ScaleDownDelaySecondsAfterScaleUp or DefaultScaleDownDelay
|
||||||
|
//
|
||||||
|
|
||||||
var scaleDownDelay time.Duration
|
var scaleDownDelay time.Duration
|
||||||
|
|
||||||
if hra.Spec.ScaleDownDelaySecondsAfterScaleUp != nil {
|
if hra.Spec.ScaleDownDelaySecondsAfterScaleUp != nil {
|
||||||
@@ -208,17 +499,50 @@ func (r *HorizontalRunnerAutoscalerReconciler) computeReplicas(rd v1alpha1.Runne
|
|||||||
scaleDownDelay = DefaultScaleDownDelay
|
scaleDownDelay = DefaultScaleDownDelay
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
var scaleDownDelayUntil *time.Time
|
||||||
|
|
||||||
if hra.Status.DesiredReplicas == nil ||
|
if hra.Status.DesiredReplicas == nil ||
|
||||||
*hra.Status.DesiredReplicas < *replicas ||
|
*hra.Status.DesiredReplicas < newDesiredReplicas ||
|
||||||
hra.Status.LastSuccessfulScaleOutTime == nil ||
|
hra.Status.LastSuccessfulScaleOutTime == nil {
|
||||||
hra.Status.LastSuccessfulScaleOutTime.Add(scaleDownDelay).Before(now) {
|
|
||||||
|
|
||||||
computedReplicas = replicas
|
} else if hra.Status.LastSuccessfulScaleOutTime != nil {
|
||||||
|
t := hra.Status.LastSuccessfulScaleOutTime.Add(scaleDownDelay)
|
||||||
|
|
||||||
|
// ScaleDownDelay is not passed
|
||||||
|
if t.After(now) {
|
||||||
|
scaleDownDelayUntil = &t
|
||||||
|
newDesiredReplicas = *hra.Status.DesiredReplicas
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
computedReplicas = hra.Status.DesiredReplicas
|
newDesiredReplicas = *hra.Status.DesiredReplicas
|
||||||
}
|
}
|
||||||
|
|
||||||
return computedReplicas, nil
|
//
|
||||||
|
// Logs various numbers for monitoring and debugging purpose
|
||||||
|
//
|
||||||
|
|
||||||
|
kvs := []interface{}{
|
||||||
|
"suggested", suggestedReplicas,
|
||||||
|
"reserved", reserved,
|
||||||
|
"min", minReplicas,
|
||||||
|
}
|
||||||
|
|
||||||
|
if cached != nil {
|
||||||
|
kvs = append(kvs, "cached", *cached)
|
||||||
|
}
|
||||||
|
|
||||||
|
if scaleDownDelayUntil != nil {
|
||||||
|
kvs = append(kvs, "last_scale_up_time", *hra.Status.LastSuccessfulScaleOutTime)
|
||||||
|
kvs = append(kvs, "scale_down_delay_until", scaleDownDelayUntil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxReplicas := hra.Spec.MaxReplicas; maxReplicas != nil {
|
||||||
|
kvs = append(kvs, "max", *maxReplicas)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.V(1).Info(fmt.Sprintf("Calculated desired replicas of %d", newDesiredReplicas),
|
||||||
|
kvs...,
|
||||||
|
)
|
||||||
|
|
||||||
|
return newDesiredReplicas, suggestedReplicas, suggestedReplicasFromCache, nil
|
||||||
}
|
}
|
||||||
|
|||||||
50
controllers/horizontalrunnerautoscaler_controller_test.go
Normal file
50
controllers/horizontalrunnerautoscaler_controller_test.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
actionsv1alpha1 "github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetValidCacheEntries(t *testing.T) {
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
hra := &actionsv1alpha1.HorizontalRunnerAutoscaler{
|
||||||
|
Status: actionsv1alpha1.HorizontalRunnerAutoscalerStatus{
|
||||||
|
CacheEntries: []actionsv1alpha1.CacheEntry{
|
||||||
|
{
|
||||||
|
Key: "foo",
|
||||||
|
Value: 1,
|
||||||
|
ExpirationTime: metav1.Time{Time: now.Add(-time.Second)},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "foo",
|
||||||
|
Value: 2,
|
||||||
|
ExpirationTime: metav1.Time{Time: now},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "foo",
|
||||||
|
Value: 3,
|
||||||
|
ExpirationTime: metav1.Time{Time: now.Add(time.Second)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
revs := getValidCacheEntries(hra, now)
|
||||||
|
|
||||||
|
counts := map[string]int{}
|
||||||
|
|
||||||
|
for _, r := range revs {
|
||||||
|
counts[r.Key] += r.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
want := map[string]int{"foo": 3}
|
||||||
|
|
||||||
|
if d := cmp.Diff(want, counts); d != "" {
|
||||||
|
t.Errorf("%s", d)
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
67
controllers/metrics/horizontalrunnerautoscaler.go
Normal file
67
controllers/metrics/horizontalrunnerautoscaler.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
hraName = "horizontalrunnerautoscaler"
|
||||||
|
hraNamespace = "namespace"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
horizontalRunnerAutoscalerMetrics = []prometheus.Collector{
|
||||||
|
horizontalRunnerAutoscalerMinReplicas,
|
||||||
|
horizontalRunnerAutoscalerMaxReplicas,
|
||||||
|
horizontalRunnerAutoscalerDesiredReplicas,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
horizontalRunnerAutoscalerMinReplicas = prometheus.NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "horizontalrunnerautoscaler_spec_min_replicas",
|
||||||
|
Help: "minReplicas of HorizontalRunnerAutoscaler",
|
||||||
|
},
|
||||||
|
[]string{hraName, hraNamespace},
|
||||||
|
)
|
||||||
|
horizontalRunnerAutoscalerMaxReplicas = prometheus.NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "horizontalrunnerautoscaler_spec_max_replicas",
|
||||||
|
Help: "maxReplicas of HorizontalRunnerAutoscaler",
|
||||||
|
},
|
||||||
|
[]string{hraName, hraNamespace},
|
||||||
|
)
|
||||||
|
horizontalRunnerAutoscalerDesiredReplicas = prometheus.NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "horizontalrunnerautoscaler_status_desired_replicas",
|
||||||
|
Help: "desiredReplicas of HorizontalRunnerAutoscaler",
|
||||||
|
},
|
||||||
|
[]string{hraName, hraNamespace},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetHorizontalRunnerAutoscalerSpec(o metav1.ObjectMeta, spec v1alpha1.HorizontalRunnerAutoscalerSpec) {
|
||||||
|
labels := prometheus.Labels{
|
||||||
|
hraName: o.Name,
|
||||||
|
hraNamespace: o.Namespace,
|
||||||
|
}
|
||||||
|
if spec.MaxReplicas != nil {
|
||||||
|
horizontalRunnerAutoscalerMaxReplicas.With(labels).Set(float64(*spec.MaxReplicas))
|
||||||
|
}
|
||||||
|
if spec.MinReplicas != nil {
|
||||||
|
horizontalRunnerAutoscalerMinReplicas.With(labels).Set(float64(*spec.MinReplicas))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetHorizontalRunnerAutoscalerStatus(o metav1.ObjectMeta, status v1alpha1.HorizontalRunnerAutoscalerStatus) {
|
||||||
|
labels := prometheus.Labels{
|
||||||
|
hraName: o.Name,
|
||||||
|
hraNamespace: o.Namespace,
|
||||||
|
}
|
||||||
|
if status.DesiredReplicas != nil {
|
||||||
|
horizontalRunnerAutoscalerDesiredReplicas.With(labels).Set(float64(*status.DesiredReplicas))
|
||||||
|
}
|
||||||
|
}
|
||||||
14
controllers/metrics/metrics.go
Normal file
14
controllers/metrics/metrics.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Package metrics provides the metrics of custom resources such as HRA.
|
||||||
|
//
|
||||||
|
// This depends on the metrics exporter of kubebuilder.
|
||||||
|
// See https://book.kubebuilder.io/reference/metrics.html for details.
|
||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
metrics.Registry.MustRegister(runnerDeploymentMetrics...)
|
||||||
|
metrics.Registry.MustRegister(horizontalRunnerAutoscalerMetrics...)
|
||||||
|
}
|
||||||
37
controllers/metrics/runnerdeployment.go
Normal file
37
controllers/metrics/runnerdeployment.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
rdName = "runnerdeployment"
|
||||||
|
rdNamespace = "namespace"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
runnerDeploymentMetrics = []prometheus.Collector{
|
||||||
|
runnerDeploymentReplicas,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
runnerDeploymentReplicas = prometheus.NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "runnerdeployment_spec_replicas",
|
||||||
|
Help: "replicas of RunnerDeployment",
|
||||||
|
},
|
||||||
|
[]string{rdName, rdNamespace},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetRunnerDeployment(rd v1alpha1.RunnerDeployment) {
|
||||||
|
labels := prometheus.Labels{
|
||||||
|
rdName: rd.Name,
|
||||||
|
rdNamespace: rd.Namespace,
|
||||||
|
}
|
||||||
|
if rd.Spec.Replicas != nil {
|
||||||
|
runnerDeploymentReplicas.With(labels).Set(float64(*rd.Spec.Replicas))
|
||||||
|
}
|
||||||
|
}
|
||||||
37
controllers/metrics/runnerset.go
Normal file
37
controllers/metrics/runnerset.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
rsName = "runnerset"
|
||||||
|
rsNamespace = "namespace"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
runnerSetMetrics = []prometheus.Collector{
|
||||||
|
runnerSetReplicas,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
runnerSetReplicas = prometheus.NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "runnerset_spec_replicas",
|
||||||
|
Help: "replicas of RunnerSet",
|
||||||
|
},
|
||||||
|
[]string{rsName, rsNamespace},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetRunnerSet(rd v1alpha1.RunnerSet) {
|
||||||
|
labels := prometheus.Labels{
|
||||||
|
rsName: rd.Name,
|
||||||
|
rsNamespace: rd.Namespace,
|
||||||
|
}
|
||||||
|
if rd.Spec.Replicas != nil {
|
||||||
|
runnerSetReplicas.With(labels).Set(float64(*rd.Spec.Replicas))
|
||||||
|
}
|
||||||
|
}
|
||||||
132
controllers/pod_runner_token_injector.go
Normal file
132
controllers/pod_runner_token_injector.go
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/github"
|
||||||
|
"github.com/go-logr/logr"
|
||||||
|
"gomodules.xyz/jsonpatch/v2"
|
||||||
|
admissionv1 "k8s.io/api/admission/v1"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/client-go/tools/record"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AnnotationKeyTokenExpirationDate = "actions-runner-controller/token-expires-at"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +kubebuilder:webhook:path=/mutate-runner-set-pod,mutating=true,failurePolicy=ignore,groups="",resources=pods,verbs=create,versions=v1,name=mutate-runner-pod.webhook.actions.summerwind.dev,sideEffects=None,admissionReviewVersions=v1beta1
|
||||||
|
|
||||||
|
type PodRunnerTokenInjector struct {
|
||||||
|
client.Client
|
||||||
|
|
||||||
|
Name string
|
||||||
|
Log logr.Logger
|
||||||
|
Recorder record.EventRecorder
|
||||||
|
GitHubClient *github.Client
|
||||||
|
decoder *admission.Decoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *PodRunnerTokenInjector) Handle(ctx context.Context, req admission.Request) admission.Response {
|
||||||
|
var pod corev1.Pod
|
||||||
|
err := t.decoder.Decode(req, &pod)
|
||||||
|
if err != nil {
|
||||||
|
t.Log.Error(err, "Failed to decode request object")
|
||||||
|
return admission.Errored(http.StatusBadRequest, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pod.Annotations == nil {
|
||||||
|
pod.Annotations = map[string]string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var runnerContainer *corev1.Container
|
||||||
|
|
||||||
|
for i := range pod.Spec.Containers {
|
||||||
|
c := pod.Spec.Containers[i]
|
||||||
|
|
||||||
|
if c.Name == "runner" {
|
||||||
|
runnerContainer = &c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if runnerContainer == nil {
|
||||||
|
return newEmptyResponse()
|
||||||
|
}
|
||||||
|
|
||||||
|
enterprise, okEnterprise := getEnv(runnerContainer, "RUNNER_ENTERPRISE")
|
||||||
|
repo, okRepo := getEnv(runnerContainer, "RUNNER_REPO")
|
||||||
|
org, okOrg := getEnv(runnerContainer, "RUNNER_ORG")
|
||||||
|
if !okRepo || !okOrg || !okEnterprise {
|
||||||
|
return newEmptyResponse()
|
||||||
|
}
|
||||||
|
|
||||||
|
rt, err := t.GitHubClient.GetRegistrationToken(context.Background(), enterprise, org, repo, pod.Name)
|
||||||
|
if err != nil {
|
||||||
|
t.Log.Error(err, "Failed to get new registration token")
|
||||||
|
return admission.Errored(http.StatusInternalServerError, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ts := rt.GetExpiresAt().Format(time.RFC3339)
|
||||||
|
|
||||||
|
updated := mutatePod(&pod, *rt.Token)
|
||||||
|
|
||||||
|
updated.Annotations[AnnotationKeyTokenExpirationDate] = ts
|
||||||
|
|
||||||
|
if pod.Spec.RestartPolicy != corev1.RestartPolicyOnFailure {
|
||||||
|
updated.Spec.RestartPolicy = corev1.RestartPolicyOnFailure
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := json.Marshal(updated)
|
||||||
|
if err != nil {
|
||||||
|
t.Log.Error(err, "Failed to encode new object")
|
||||||
|
return admission.Errored(http.StatusInternalServerError, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := admission.PatchResponseFromRaw(req.Object.Raw, buf)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEnv(container *corev1.Container, key string) (string, bool) {
|
||||||
|
for _, env := range container.Env {
|
||||||
|
if env.Name == key {
|
||||||
|
return env.Value, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *PodRunnerTokenInjector) InjectDecoder(d *admission.Decoder) error {
|
||||||
|
t.decoder = d
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEmptyResponse() admission.Response {
|
||||||
|
pt := admissionv1.PatchTypeJSONPatch
|
||||||
|
return admission.Response{
|
||||||
|
Patches: []jsonpatch.Operation{},
|
||||||
|
AdmissionResponse: admissionv1.AdmissionResponse{
|
||||||
|
Allowed: true,
|
||||||
|
PatchType: &pt,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PodRunnerTokenInjector) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
name := "pod-runner-token-injector"
|
||||||
|
if r.Name != "" {
|
||||||
|
name = r.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Recorder = mgr.GetEventRecorderFor(name)
|
||||||
|
|
||||||
|
mgr.GetWebhookServer().Register("/mutate-runner-set-pod", &admission.Webhook{Handler: r})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
431
controllers/runner_pod_controller.go
Normal file
431
controllers/runner_pod_controller.go
Normal file
@@ -0,0 +1,431 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The actions-runner-controller authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
gogithub "github.com/google/go-github/v33/github"
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
|
||||||
|
"github.com/go-logr/logr"
|
||||||
|
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/client-go/tools/record"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/github"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RunnerPodReconciler reconciles a Runner object
|
||||||
|
type RunnerPodReconciler struct {
|
||||||
|
client.Client
|
||||||
|
Log logr.Logger
|
||||||
|
Recorder record.EventRecorder
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
GitHubClient *github.Client
|
||||||
|
Name string
|
||||||
|
RegistrationRecheckInterval time.Duration
|
||||||
|
RegistrationRecheckJitter time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// This names requires at leaset one slash to work.
|
||||||
|
// See https://github.com/google/knative-gcp/issues/378
|
||||||
|
runnerPodFinalizerName = "actions.summerwind.dev/runner-pod"
|
||||||
|
|
||||||
|
AnnotationKeyLastRegistrationCheckTime = "actions-runner-controller/last-registration-check-time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;update;patch;delete
|
||||||
|
// +kubebuilder:rbac:groups=core,resources=events,verbs=create;patch
|
||||||
|
|
||||||
|
func (r *RunnerPodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
|
log := r.Log.WithValues("runnerpod", req.NamespacedName)
|
||||||
|
|
||||||
|
var runnerPod corev1.Pod
|
||||||
|
if err := r.Get(ctx, req.NamespacedName, &runnerPod); err != nil {
|
||||||
|
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, isRunnerPod := runnerPod.Labels[LabelKeyRunnerSetName]
|
||||||
|
if !isRunnerPod {
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var enterprise, org, repo string
|
||||||
|
|
||||||
|
envvars := runnerPod.Spec.Containers[0].Env
|
||||||
|
for _, e := range envvars {
|
||||||
|
switch e.Name {
|
||||||
|
case EnvVarEnterprise:
|
||||||
|
enterprise = e.Value
|
||||||
|
case EnvVarOrg:
|
||||||
|
org = e.Value
|
||||||
|
case EnvVarRepo:
|
||||||
|
repo = e.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if runnerPod.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||||
|
finalizers, added := addFinalizer(runnerPod.ObjectMeta.Finalizers, runnerPodFinalizerName)
|
||||||
|
|
||||||
|
if added {
|
||||||
|
newRunner := runnerPod.DeepCopy()
|
||||||
|
newRunner.ObjectMeta.Finalizers = finalizers
|
||||||
|
|
||||||
|
if err := r.Patch(ctx, newRunner, client.MergeFrom(&runnerPod)); err != nil {
|
||||||
|
log.Error(err, "Failed to update runner")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
finalizers, removed := removeFinalizer(runnerPod.ObjectMeta.Finalizers, runnerPodFinalizerName)
|
||||||
|
|
||||||
|
if removed {
|
||||||
|
ok, err := r.unregisterRunner(ctx, enterprise, org, repo, runnerPod.Name)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, &gogithub.RateLimitError{}) {
|
||||||
|
// We log the underlying error when we failed calling GitHub API to list or unregisters,
|
||||||
|
// or the runner is still busy.
|
||||||
|
log.Error(
|
||||||
|
err,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"Failed to unregister runner due to GitHub API rate limits. Delaying retry for %s to avoid excessive GitHub API calls",
|
||||||
|
retryDelayOnGitHubAPIRateLimitError,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return ctrl.Result{RequeueAfter: retryDelayOnGitHubAPIRateLimitError}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
log.V(1).Info("Runner no longer exists on GitHub")
|
||||||
|
}
|
||||||
|
|
||||||
|
newRunner := runnerPod.DeepCopy()
|
||||||
|
newRunner.ObjectMeta.Finalizers = finalizers
|
||||||
|
|
||||||
|
if err := r.Patch(ctx, newRunner, client.MergeFrom(&runnerPod)); err != nil {
|
||||||
|
log.Error(err, "Failed to update runner for finalizer removal")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Removed runner from GitHub", "repository", repo, "organization", org)
|
||||||
|
}
|
||||||
|
|
||||||
|
deletionTimeout := 1 * time.Minute
|
||||||
|
currentTime := time.Now()
|
||||||
|
deletionDidTimeout := currentTime.Sub(runnerPod.DeletionTimestamp.Add(deletionTimeout)) > 0
|
||||||
|
|
||||||
|
if deletionDidTimeout {
|
||||||
|
log.Info(
|
||||||
|
fmt.Sprintf("Failed to delete pod within %s. ", deletionTimeout)+
|
||||||
|
"This is typically the case when a Kubernetes node became unreachable "+
|
||||||
|
"and the kube controller started evicting nodes. Forcefully deleting the pod to not get stuck.",
|
||||||
|
"podDeletionTimestamp", runnerPod.DeletionTimestamp,
|
||||||
|
"currentTime", currentTime,
|
||||||
|
"configuredDeletionTimeout", deletionTimeout,
|
||||||
|
)
|
||||||
|
|
||||||
|
var force int64 = 0
|
||||||
|
// forcefully delete runner as we would otherwise get stuck if the node stays unreachable
|
||||||
|
if err := r.Delete(ctx, &runnerPod, &client.DeleteOptions{GracePeriodSeconds: &force}); err != nil {
|
||||||
|
// probably
|
||||||
|
if !kerrors.IsNotFound(err) {
|
||||||
|
log.Error(err, "Failed to forcefully delete pod resource ...")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
// forceful deletion finally succeeded
|
||||||
|
return ctrl.Result{Requeue: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Recorder.Event(&runnerPod, corev1.EventTypeNormal, "PodDeleted", fmt.Sprintf("Forcefully deleted pod '%s'", runnerPod.Name))
|
||||||
|
log.Info("Forcefully deleted runner pod", "repository", repo)
|
||||||
|
// give kube manager a little time to forcefully delete the stuck pod
|
||||||
|
return ctrl.Result{RequeueAfter: 3 * time.Second}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If pod has ended up succeeded we need to restart it
|
||||||
|
// Happens e.g. when dind is in runner and run completes
|
||||||
|
stopped := runnerPod.Status.Phase == corev1.PodSucceeded
|
||||||
|
|
||||||
|
if !stopped {
|
||||||
|
if runnerPod.Status.Phase == corev1.PodRunning {
|
||||||
|
for _, status := range runnerPod.Status.ContainerStatuses {
|
||||||
|
if status.Name != containerName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if status.State.Terminated != nil && status.State.Terminated.ExitCode == 0 {
|
||||||
|
stopped = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
restart := stopped
|
||||||
|
|
||||||
|
var registrationRecheckDelay time.Duration
|
||||||
|
|
||||||
|
// all checks done below only decide whether a restart is needed
|
||||||
|
// if a restart was already decided before, there is no need for the checks
|
||||||
|
// saving API calls and scary log messages
|
||||||
|
if !restart {
|
||||||
|
registrationCheckInterval := time.Minute
|
||||||
|
if r.RegistrationRecheckInterval > 0 {
|
||||||
|
registrationCheckInterval = r.RegistrationRecheckInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
lastCheckTimeStr := runnerPod.Annotations[AnnotationKeyLastRegistrationCheckTime]
|
||||||
|
|
||||||
|
var lastCheckTime *time.Time
|
||||||
|
|
||||||
|
if lastCheckTimeStr != "" {
|
||||||
|
t, err := time.Parse(time.RFC3339, lastCheckTimeStr)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err, "failed to parase last check time %q", lastCheckTimeStr)
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
lastCheckTime = &t
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want to call ListRunners GitHub Actions API only once per runner per minute.
|
||||||
|
// This if block, in conjunction with:
|
||||||
|
// return ctrl.Result{RequeueAfter: registrationRecheckDelay}, nil
|
||||||
|
// achieves that.
|
||||||
|
if lastCheckTime != nil {
|
||||||
|
nextCheckTime := lastCheckTime.Add(registrationCheckInterval)
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
// Requeue scheduled by RequeueAfter can happen a bit earlier (like dozens of milliseconds)
|
||||||
|
// so to avoid excessive, in-effective retry, we heuristically ignore the remaining delay in case it is
|
||||||
|
// shorter than 1s
|
||||||
|
requeueAfter := nextCheckTime.Sub(now) - time.Second
|
||||||
|
if requeueAfter > 0 {
|
||||||
|
log.Info(
|
||||||
|
fmt.Sprintf("Skipped registration check because it's deferred until %s. Retrying in %s at latest", nextCheckTime, requeueAfter),
|
||||||
|
"lastRegistrationCheckTime", lastCheckTime,
|
||||||
|
"registrationCheckInterval", registrationCheckInterval,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Without RequeueAfter, the controller may not retry on scheduled. Instead, it must wait until the
|
||||||
|
// next sync period passes, which can be too much later than nextCheckTime.
|
||||||
|
//
|
||||||
|
// We need to requeue on this reconcilation even though we have already scheduled the initial
|
||||||
|
// requeue previously with `return ctrl.Result{RequeueAfter: registrationRecheckDelay}, nil`.
|
||||||
|
// Apparently, the workqueue used by controller-runtime seems to deduplicate and resets the delay on
|
||||||
|
// other requeues- so the initial scheduled requeue may have been reset due to requeue on
|
||||||
|
// spec/status change.
|
||||||
|
return ctrl.Result{RequeueAfter: requeueAfter}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notFound := false
|
||||||
|
offline := false
|
||||||
|
|
||||||
|
_, err := r.GitHubClient.IsRunnerBusy(ctx, enterprise, org, repo, runnerPod.Name)
|
||||||
|
|
||||||
|
currentTime := time.Now()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
var notFoundException *github.RunnerNotFound
|
||||||
|
var offlineException *github.RunnerOffline
|
||||||
|
if errors.As(err, ¬FoundException) {
|
||||||
|
notFound = true
|
||||||
|
} else if errors.As(err, &offlineException) {
|
||||||
|
offline = true
|
||||||
|
} else {
|
||||||
|
var e *gogithub.RateLimitError
|
||||||
|
if errors.As(err, &e) {
|
||||||
|
// We log the underlying error when we failed calling GitHub API to list or unregisters,
|
||||||
|
// or the runner is still busy.
|
||||||
|
log.Error(
|
||||||
|
err,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"Failed to check if runner is busy due to Github API rate limit. Retrying in %s to avoid excessive GitHub API calls",
|
||||||
|
retryDelayOnGitHubAPIRateLimitError,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return ctrl.Result{RequeueAfter: retryDelayOnGitHubAPIRateLimitError}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registrationTimeout := 10 * time.Minute
|
||||||
|
durationAfterRegistrationTimeout := currentTime.Sub(runnerPod.CreationTimestamp.Add(registrationTimeout))
|
||||||
|
registrationDidTimeout := durationAfterRegistrationTimeout > 0
|
||||||
|
|
||||||
|
if notFound {
|
||||||
|
if registrationDidTimeout {
|
||||||
|
log.Info(
|
||||||
|
"Runner failed to register itself to GitHub in timely manner. "+
|
||||||
|
"Recreating the pod to see if it resolves the issue. "+
|
||||||
|
"CAUTION: If you see this a lot, you should investigate the root cause. "+
|
||||||
|
"See https://github.com/actions-runner-controller/actions-runner-controller/issues/288",
|
||||||
|
"podCreationTimestamp", runnerPod.CreationTimestamp,
|
||||||
|
"currentTime", currentTime,
|
||||||
|
"configuredRegistrationTimeout", registrationTimeout,
|
||||||
|
)
|
||||||
|
|
||||||
|
restart = true
|
||||||
|
} else {
|
||||||
|
log.V(1).Info(
|
||||||
|
"Runner pod exists but we failed to check if runner is busy. Apparently it still needs more time.",
|
||||||
|
"runnerName", runnerPod.Name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if offline {
|
||||||
|
if registrationDidTimeout {
|
||||||
|
log.Info(
|
||||||
|
"Already existing GitHub runner still appears offline . "+
|
||||||
|
"Recreating the pod to see if it resolves the issue. "+
|
||||||
|
"CAUTION: If you see this a lot, you should investigate the root cause. ",
|
||||||
|
"podCreationTimestamp", runnerPod.CreationTimestamp,
|
||||||
|
"currentTime", currentTime,
|
||||||
|
"configuredRegistrationTimeout", registrationTimeout,
|
||||||
|
)
|
||||||
|
|
||||||
|
restart = true
|
||||||
|
} else {
|
||||||
|
log.V(1).Info(
|
||||||
|
"Runner pod exists but the GitHub runner appears to be still offline. Waiting for runner to get online ...",
|
||||||
|
"runnerName", runnerPod.Name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notFound || offline) && !registrationDidTimeout {
|
||||||
|
registrationRecheckJitter := 10 * time.Second
|
||||||
|
if r.RegistrationRecheckJitter > 0 {
|
||||||
|
registrationRecheckJitter = r.RegistrationRecheckJitter
|
||||||
|
}
|
||||||
|
|
||||||
|
registrationRecheckDelay = registrationCheckInterval + wait.Jitter(registrationRecheckJitter, 0.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't do anything if there's no need to restart the runner
|
||||||
|
if !restart {
|
||||||
|
// This guard enables us to update runner.Status.Phase to `Running` only after
|
||||||
|
// the runner is registered to GitHub.
|
||||||
|
if registrationRecheckDelay > 0 {
|
||||||
|
log.V(1).Info(fmt.Sprintf("Rechecking the runner registration in %s", registrationRecheckDelay))
|
||||||
|
|
||||||
|
updated := runnerPod.DeepCopy()
|
||||||
|
t := time.Now().Format(time.RFC3339)
|
||||||
|
updated.Annotations[AnnotationKeyLastRegistrationCheckTime] = t
|
||||||
|
|
||||||
|
if err := r.Patch(ctx, updated, client.MergeFrom(&runnerPod)); err != nil {
|
||||||
|
log.Error(err, "Failed to update runner pod annotation for LastRegistrationCheckTime")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{RequeueAfter: registrationRecheckDelay}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seeing this message, you can expect the runner to become `Running` soon.
|
||||||
|
log.Info(
|
||||||
|
"Runner appears to have registered and running.",
|
||||||
|
"podCreationTimestamp", runnerPod.CreationTimestamp,
|
||||||
|
)
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete current pod if recreation is needed
|
||||||
|
if err := r.Delete(ctx, &runnerPod); err != nil {
|
||||||
|
log.Error(err, "Failed to delete pod resource")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Recorder.Event(&runnerPod, corev1.EventTypeNormal, "PodDeleted", fmt.Sprintf("Deleted pod '%s'", runnerPod.Name))
|
||||||
|
log.Info("Deleted runner pod", "name", runnerPod.Name)
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RunnerPodReconciler) unregisterRunner(ctx context.Context, enterprise, org, repo, name string) (bool, error) {
|
||||||
|
runners, err := r.GitHubClient.ListRunners(ctx, enterprise, org, repo)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var busy bool
|
||||||
|
|
||||||
|
id := int64(0)
|
||||||
|
for _, runner := range runners {
|
||||||
|
if runner.GetName() == name {
|
||||||
|
// Sometimes a runner can stuck "busy" even though it is already "offline".
|
||||||
|
// Thus removing the condition on status can block the runner pod from being terminated forever.
|
||||||
|
busy = runner.GetBusy()
|
||||||
|
if runner.GetStatus() != "offline" && busy {
|
||||||
|
r.Log.Info("This runner will delay the runner pod deletion and the runner deregistration until it becomes either offline or non-busy", "name", runner.GetName(), "status", runner.GetStatus(), "busy", runner.GetBusy())
|
||||||
|
return false, fmt.Errorf("runner is busy")
|
||||||
|
}
|
||||||
|
id = runner.GetID()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if id == int64(0) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sometimes a runner can stuck "busy" even though it is already "offline".
|
||||||
|
// Trying to remove the offline but busy runner can result in errors like the following:
|
||||||
|
// failed to remove runner: DELETE https://api.github.com/repos/actions-runner-controller/mumoshu-actions-test/actions/runners/47: 422 Bad request - Runner \"example-runnerset-0\" is still running a job\" []
|
||||||
|
if !busy {
|
||||||
|
if err := r.GitHubClient.RemoveRunner(ctx, enterprise, org, repo, id); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RunnerPodReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
name := "runnerpod-controller"
|
||||||
|
if r.Name != "" {
|
||||||
|
name = r.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Recorder = mgr.GetEventRecorderFor(name)
|
||||||
|
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
For(&corev1.Pod{}).
|
||||||
|
Named(name).
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -36,11 +37,13 @@ import (
|
|||||||
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"
|
||||||
|
|
||||||
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/controllers/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LabelKeyRunnerTemplateHash = "runner-template-hash"
|
LabelKeyRunnerTemplateHash = "runner-template-hash"
|
||||||
|
LabelKeyRunnerDeploymentName = "runner-deployment-name"
|
||||||
|
|
||||||
runnerSetOwnerKey = ".metadata.controller"
|
runnerSetOwnerKey = ".metadata.controller"
|
||||||
)
|
)
|
||||||
@@ -52,6 +55,7 @@ type RunnerDeploymentReconciler struct {
|
|||||||
Recorder record.EventRecorder
|
Recorder record.EventRecorder
|
||||||
Scheme *runtime.Scheme
|
Scheme *runtime.Scheme
|
||||||
CommonRunnerLabels []string
|
CommonRunnerLabels []string
|
||||||
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:rbac:groups=actions.summerwind.dev,resources=runnerdeployments,verbs=get;list;watch;create;update;patch;delete
|
// +kubebuilder:rbac:groups=actions.summerwind.dev,resources=runnerdeployments,verbs=get;list;watch;create;update;patch;delete
|
||||||
@@ -61,8 +65,7 @@ type RunnerDeploymentReconciler struct {
|
|||||||
// +kubebuilder:rbac:groups=actions.summerwind.dev,resources=runnerreplicasets/status,verbs=get;update;patch
|
// +kubebuilder:rbac:groups=actions.summerwind.dev,resources=runnerreplicasets/status,verbs=get;update;patch
|
||||||
// +kubebuilder:rbac:groups=core,resources=events,verbs=create;patch
|
// +kubebuilder:rbac:groups=core,resources=events,verbs=create;patch
|
||||||
|
|
||||||
func (r *RunnerDeploymentReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
func (r *RunnerDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
ctx := context.Background()
|
|
||||||
log := r.Log.WithValues("runnerdeployment", req.NamespacedName)
|
log := r.Log.WithValues("runnerdeployment", req.NamespacedName)
|
||||||
|
|
||||||
var rd v1alpha1.RunnerDeployment
|
var rd v1alpha1.RunnerDeployment
|
||||||
@@ -74,6 +77,8 @@ func (r *RunnerDeploymentReconciler) Reconcile(req ctrl.Request) (ctrl.Result, e
|
|||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
metrics.SetRunnerDeployment(rd)
|
||||||
|
|
||||||
var myRunnerReplicaSetList v1alpha1.RunnerReplicaSetList
|
var myRunnerReplicaSetList v1alpha1.RunnerReplicaSetList
|
||||||
if err := r.List(ctx, &myRunnerReplicaSetList, client.InNamespace(req.Namespace), client.MatchingFields{runnerSetOwnerKey: req.Name}); err != nil {
|
if err := r.List(ctx, &myRunnerReplicaSetList, client.InNamespace(req.Namespace), client.MatchingFields{runnerSetOwnerKey: req.Name}); err != nil {
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
@@ -142,6 +147,28 @@ func (r *RunnerDeploymentReconciler) Reconcile(req ctrl.Request) (ctrl.Result, e
|
|||||||
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
|
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(newestSet.Spec.Selector, desiredRS.Spec.Selector) {
|
||||||
|
updateSet := newestSet.DeepCopy()
|
||||||
|
updateSet.Spec = *desiredRS.Spec.DeepCopy()
|
||||||
|
|
||||||
|
// A selector update change doesn't trigger replicaset replacement,
|
||||||
|
// but we still need to update the existing replicaset with it.
|
||||||
|
// Otherwise selector-based runner query will never work on replicasets created before the controller v0.17.0
|
||||||
|
// See https://github.com/actions-runner-controller/actions-runner-controller/pull/355#discussion_r585379259
|
||||||
|
if err := r.Client.Update(ctx, updateSet); err != nil {
|
||||||
|
log.Error(err, "Failed to update runnerreplicaset resource")
|
||||||
|
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, we are already sure that there's no need to create a new replicaset
|
||||||
|
// as the runner template hash is not changed.
|
||||||
|
//
|
||||||
|
// But we still need to requeue for the (possibly rare) cases that there are still old replicasets that needs
|
||||||
|
// to be cleaned up.
|
||||||
|
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
|
||||||
|
}
|
||||||
|
|
||||||
const defaultReplicas = 1
|
const defaultReplicas = 1
|
||||||
|
|
||||||
currentDesiredReplicas := getIntOrDefault(newestSet.Spec.Replicas, defaultReplicas)
|
currentDesiredReplicas := getIntOrDefault(newestSet.Spec.Replicas, defaultReplicas)
|
||||||
@@ -160,18 +187,35 @@ func (r *RunnerDeploymentReconciler) Reconcile(req ctrl.Request) (ctrl.Result, e
|
|||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do we old runner replica sets that should eventually deleted?
|
// Do we have old runner replica sets that should eventually deleted?
|
||||||
if len(oldSets) > 0 {
|
if len(oldSets) > 0 {
|
||||||
readyReplicas := newestSet.Status.ReadyReplicas
|
var readyReplicas int
|
||||||
|
if newestSet.Status.ReadyReplicas != nil {
|
||||||
|
readyReplicas = *newestSet.Status.ReadyReplicas
|
||||||
|
}
|
||||||
|
|
||||||
if readyReplicas < currentDesiredReplicas {
|
oldSetsCount := len(oldSets)
|
||||||
log.WithValues("runnerreplicaset", types.NamespacedName{
|
|
||||||
|
logWithDebugInfo := log.WithValues(
|
||||||
|
"newest_runnerreplicaset", types.NamespacedName{
|
||||||
Namespace: newestSet.Namespace,
|
Namespace: newestSet.Namespace,
|
||||||
Name: newestSet.Name,
|
Name: newestSet.Name,
|
||||||
}).
|
},
|
||||||
|
"newest_runnerreplicaset_replicas_ready", readyReplicas,
|
||||||
|
"newest_runnerreplicaset_replicas_desired", currentDesiredReplicas,
|
||||||
|
"old_runnerreplicasets_count", oldSetsCount,
|
||||||
|
)
|
||||||
|
|
||||||
|
if readyReplicas < currentDesiredReplicas {
|
||||||
|
logWithDebugInfo.
|
||||||
Info("Waiting until the newest runnerreplicaset to be 100% available")
|
Info("Waiting until the newest runnerreplicaset to be 100% available")
|
||||||
|
|
||||||
return ctrl.Result{RequeueAfter: 10 * time.Second}, nil
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldSetsCount > 0 {
|
||||||
|
logWithDebugInfo.
|
||||||
|
Info("The newest runnerreplicaset is 100% available. Deleting old runnerreplicasets")
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range oldSets {
|
for i := range oldSets {
|
||||||
@@ -189,14 +233,49 @@ func (r *RunnerDeploymentReconciler) Reconcile(req ctrl.Request) (ctrl.Result, e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rd.Spec.Replicas == nil && desiredRS.Spec.Replicas != nil {
|
var replicaSets []v1alpha1.RunnerReplicaSet
|
||||||
|
|
||||||
|
replicaSets = append(replicaSets, *newestSet)
|
||||||
|
replicaSets = append(replicaSets, oldSets...)
|
||||||
|
|
||||||
|
var totalCurrentReplicas, totalStatusAvailableReplicas, updatedReplicas int
|
||||||
|
|
||||||
|
for _, rs := range replicaSets {
|
||||||
|
var current, available int
|
||||||
|
|
||||||
|
if rs.Status.Replicas != nil {
|
||||||
|
current = *rs.Status.Replicas
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Status.AvailableReplicas != nil {
|
||||||
|
available = *rs.Status.AvailableReplicas
|
||||||
|
}
|
||||||
|
|
||||||
|
totalCurrentReplicas += current
|
||||||
|
totalStatusAvailableReplicas += available
|
||||||
|
}
|
||||||
|
|
||||||
|
if newestSet.Status.Replicas != nil {
|
||||||
|
updatedReplicas = *newestSet.Status.Replicas
|
||||||
|
}
|
||||||
|
|
||||||
|
var status v1alpha1.RunnerDeploymentStatus
|
||||||
|
|
||||||
|
status.AvailableReplicas = &totalStatusAvailableReplicas
|
||||||
|
status.ReadyReplicas = &totalStatusAvailableReplicas
|
||||||
|
status.DesiredReplicas = &newDesiredReplicas
|
||||||
|
status.Replicas = &totalCurrentReplicas
|
||||||
|
status.UpdatedReplicas = &updatedReplicas
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(rd.Status, status) {
|
||||||
updated := rd.DeepCopy()
|
updated := rd.DeepCopy()
|
||||||
updated.Status.Replicas = desiredRS.Spec.Replicas
|
updated.Status = status
|
||||||
|
|
||||||
if err := r.Status().Update(ctx, updated); err != nil {
|
if err := r.Status().Patch(ctx, updated, client.MergeFrom(&rd)); err != nil {
|
||||||
log.Error(err, "Failed to update runnerdeployment status")
|
log.Info("Failed to patch runnerdeployment status. Retrying immediately", "error", err.Error())
|
||||||
|
return ctrl.Result{
|
||||||
return ctrl.Result{}, err
|
Requeue: true,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,32 +336,94 @@ func CloneAndAddLabel(labels map[string]string, labelKey, labelValue string) map
|
|||||||
return newLabels
|
return newLabels
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RunnerDeploymentReconciler) newRunnerReplicaSet(rd v1alpha1.RunnerDeployment) (*v1alpha1.RunnerReplicaSet, error) {
|
// Clones the given selector and returns a new selector with the given key and value added.
|
||||||
newRSTemplate := *rd.Spec.Template.DeepCopy()
|
// Returns the given selector, if labelKey is empty.
|
||||||
templateHash := ComputeHash(&newRSTemplate)
|
//
|
||||||
// Add template hash label to selector.
|
// Proudly copied from k8s.io/kubernetes/pkg/util/labels.CloneSelectorAndAddLabel
|
||||||
labels := CloneAndAddLabel(rd.Spec.Template.Labels, LabelKeyRunnerTemplateHash, templateHash)
|
func CloneSelectorAndAddLabel(selector *metav1.LabelSelector, labelKey, labelValue string) *metav1.LabelSelector {
|
||||||
|
if labelKey == "" {
|
||||||
|
// Don't need to add a label.
|
||||||
|
return selector
|
||||||
|
}
|
||||||
|
|
||||||
for _, l := range r.CommonRunnerLabels {
|
// Clone.
|
||||||
|
newSelector := new(metav1.LabelSelector)
|
||||||
|
|
||||||
|
newSelector.MatchLabels = make(map[string]string)
|
||||||
|
if selector.MatchLabels != nil {
|
||||||
|
for key, val := range selector.MatchLabels {
|
||||||
|
newSelector.MatchLabels[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newSelector.MatchLabels[labelKey] = labelValue
|
||||||
|
|
||||||
|
if selector.MatchExpressions != nil {
|
||||||
|
newMExps := make([]metav1.LabelSelectorRequirement, len(selector.MatchExpressions))
|
||||||
|
for i, me := range selector.MatchExpressions {
|
||||||
|
newMExps[i].Key = me.Key
|
||||||
|
newMExps[i].Operator = me.Operator
|
||||||
|
if me.Values != nil {
|
||||||
|
newMExps[i].Values = make([]string, len(me.Values))
|
||||||
|
copy(newMExps[i].Values, me.Values)
|
||||||
|
} else {
|
||||||
|
newMExps[i].Values = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newSelector.MatchExpressions = newMExps
|
||||||
|
} else {
|
||||||
|
newSelector.MatchExpressions = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return newSelector
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RunnerDeploymentReconciler) newRunnerReplicaSet(rd v1alpha1.RunnerDeployment) (*v1alpha1.RunnerReplicaSet, error) {
|
||||||
|
return newRunnerReplicaSet(&rd, r.CommonRunnerLabels, r.Scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSelector(rd *v1alpha1.RunnerDeployment) *metav1.LabelSelector {
|
||||||
|
selector := rd.Spec.Selector
|
||||||
|
if selector == nil {
|
||||||
|
selector = &metav1.LabelSelector{MatchLabels: map[string]string{LabelKeyRunnerDeploymentName: rd.Name}}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selector
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRunnerReplicaSet(rd *v1alpha1.RunnerDeployment, commonRunnerLabels []string, scheme *runtime.Scheme) (*v1alpha1.RunnerReplicaSet, error) {
|
||||||
|
newRSTemplate := *rd.Spec.Template.DeepCopy()
|
||||||
|
|
||||||
|
for _, l := range commonRunnerLabels {
|
||||||
newRSTemplate.Spec.Labels = append(newRSTemplate.Spec.Labels, l)
|
newRSTemplate.Spec.Labels = append(newRSTemplate.Spec.Labels, l)
|
||||||
}
|
}
|
||||||
|
|
||||||
newRSTemplate.Labels = labels
|
templateHash := ComputeHash(&newRSTemplate)
|
||||||
|
|
||||||
|
// Add template hash label to selector.
|
||||||
|
newRSTemplate.ObjectMeta.Labels = CloneAndAddLabel(newRSTemplate.ObjectMeta.Labels, LabelKeyRunnerTemplateHash, templateHash)
|
||||||
|
|
||||||
|
// This label selector is used by default when rd.Spec.Selector is empty.
|
||||||
|
newRSTemplate.ObjectMeta.Labels = CloneAndAddLabel(newRSTemplate.ObjectMeta.Labels, LabelKeyRunnerDeploymentName, rd.Name)
|
||||||
|
|
||||||
|
selector := getSelector(rd)
|
||||||
|
|
||||||
|
newRSSelector := CloneSelectorAndAddLabel(selector, LabelKeyRunnerTemplateHash, templateHash)
|
||||||
|
|
||||||
rs := v1alpha1.RunnerReplicaSet{
|
rs := v1alpha1.RunnerReplicaSet{
|
||||||
TypeMeta: metav1.TypeMeta{},
|
TypeMeta: metav1.TypeMeta{},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
GenerateName: rd.ObjectMeta.Name + "-",
|
GenerateName: rd.ObjectMeta.Name + "-",
|
||||||
Namespace: rd.ObjectMeta.Namespace,
|
Namespace: rd.ObjectMeta.Namespace,
|
||||||
Labels: labels,
|
Labels: newRSTemplate.ObjectMeta.Labels,
|
||||||
},
|
},
|
||||||
Spec: v1alpha1.RunnerReplicaSetSpec{
|
Spec: v1alpha1.RunnerReplicaSetSpec{
|
||||||
Replicas: rd.Spec.Replicas,
|
Replicas: rd.Spec.Replicas,
|
||||||
|
Selector: newRSSelector,
|
||||||
Template: newRSTemplate,
|
Template: newRSTemplate,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ctrl.SetControllerReference(&rd, &rs, r.Scheme); err != nil {
|
if err := ctrl.SetControllerReference(rd, &rs, scheme); err != nil {
|
||||||
return &rs, err
|
return &rs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,9 +432,13 @@ func (r *RunnerDeploymentReconciler) newRunnerReplicaSet(rd v1alpha1.RunnerDeplo
|
|||||||
|
|
||||||
func (r *RunnerDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
func (r *RunnerDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
name := "runnerdeployment-controller"
|
name := "runnerdeployment-controller"
|
||||||
|
if r.Name != "" {
|
||||||
|
name = r.Name
|
||||||
|
}
|
||||||
|
|
||||||
r.Recorder = mgr.GetEventRecorderFor(name)
|
r.Recorder = mgr.GetEventRecorderFor(name)
|
||||||
|
|
||||||
if err := mgr.GetFieldIndexer().IndexField(&v1alpha1.RunnerReplicaSet{}, runnerSetOwnerKey, func(rawObj runtime.Object) []string {
|
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &v1alpha1.RunnerReplicaSet{}, runnerSetOwnerKey, func(rawObj client.Object) []string {
|
||||||
runnerSet := rawObj.(*v1alpha1.RunnerReplicaSet)
|
runnerSet := rawObj.(*v1alpha1.RunnerReplicaSet)
|
||||||
owner := metav1.GetControllerOf(runnerSet)
|
owner := metav1.GetControllerOf(runnerSet)
|
||||||
if owner == nil {
|
if owner == nil {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user