mirror of
https://github.com/actions/actions-runner-controller.git
synced 2025-12-10 19:50:30 +00:00
Compare commits
104 Commits
actions-ru
...
actions-ru
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb0a4a9603 | ||
|
|
b6151ebb8d | ||
|
|
ba4bd7c0db | ||
|
|
5b92c412a4 | ||
|
|
e22d981d58 | ||
|
|
a7b39cc247 | ||
|
|
1e452358b4 | ||
|
|
92e133e007 | ||
|
|
d0d316252e | ||
|
|
b509eb4388 | ||
|
|
59437ef79f | ||
|
|
a51fb90cd2 | ||
|
|
eb53d238d1 | ||
|
|
7fdf9a6c67 | ||
|
|
6f591ee774 | ||
|
|
cc25dd7926 | ||
|
|
1b911749a6 | ||
|
|
b652a8f9ae | ||
|
|
069bf6a042 | ||
|
|
f09a974ac2 | ||
|
|
1f7e440030 | ||
|
|
9d5a562407 | ||
|
|
715e6a40f1 | ||
|
|
81b2c5ada9 | ||
|
|
9ae83dfff5 | ||
|
|
5e86881c30 | ||
|
|
1c75b20767 | ||
|
|
8a73560dbc | ||
|
|
01301d3ce8 | ||
|
|
02679ac1d8 | ||
|
|
1a6e5719c3 | ||
|
|
f72d871c5b | ||
|
|
ad48851dc9 | ||
|
|
c5950d75fa | ||
|
|
de1f48111a | ||
|
|
8a7720da77 | ||
|
|
608c56936e | ||
|
|
4ebec38208 | ||
|
|
0c34196d87 | ||
|
|
83c8a9809e | ||
|
|
c64000e11c | ||
|
|
9bb21aef1f | ||
|
|
7261d927fb | ||
|
|
91102c8088 | ||
|
|
6f51f560ba | ||
|
|
961f01baed | ||
|
|
d0642eeff1 | ||
|
|
473fe7f736 | ||
|
|
84b0c64d29 | ||
|
|
f0fccc020b | ||
|
|
2bd6d6342e | ||
|
|
ea2dbc2807 | ||
|
|
c718eaae4f | ||
|
|
67e39d719e | ||
|
|
bbd328a7cc | ||
|
|
8eb6c0f3f0 | ||
|
|
231c1f80e7 | ||
|
|
3c073c5e17 | ||
|
|
a1cfe3be36 | ||
|
|
898ad3c355 | ||
|
|
164a91b18f | ||
|
|
acb004f291 | ||
|
|
3de4e7e9c6 | ||
|
|
4a55fe563c | ||
|
|
23841642df | ||
|
|
7c4ac2ef44 | ||
|
|
550717020d | ||
|
|
9a5ae93cb7 | ||
|
|
f5175256c6 | ||
|
|
031b1848e0 | ||
|
|
47a17754fd | ||
|
|
85ddd0d137 | ||
|
|
eefb48ba3f | ||
|
|
62995fec5b | ||
|
|
7ee1d6bcdb | ||
|
|
b87e6e3966 | ||
|
|
88b8871830 | ||
|
|
2191617eb5 | ||
|
|
b305e38b17 | ||
|
|
b6c33cee32 | ||
|
|
46da4a6b6e | ||
|
|
f7e14e06e8 | ||
|
|
09e6b1839b | ||
|
|
0416a9272f | ||
|
|
c33578a041 | ||
|
|
49566aaebd | ||
|
|
f66e6a00fa | ||
|
|
431c1ed04a | ||
|
|
0d3de9ee2a | ||
|
|
79d63acded | ||
|
|
271a4dcd9d | ||
|
|
0401b2d786 | ||
|
|
43141cb751 | ||
|
|
b805cfada7 | ||
|
|
c4e97d600d | ||
|
|
fce7d6d2a7 | ||
|
|
5805e39e1f | ||
|
|
d36d47fe66 | ||
|
|
8657a34f32 | ||
|
|
b01e193aab | ||
|
|
0a3d2b686e | ||
|
|
2bc050a62d | ||
|
|
0725e72ae0 | ||
|
|
5f9fcaf016 |
52
.github/actions/setup-docker-environment/action.yaml
vendored
Normal file
52
.github/actions/setup-docker-environment/action.yaml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
name: "Setup Docker"
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
username:
|
||||||
|
description: "Username"
|
||||||
|
required: true
|
||||||
|
password:
|
||||||
|
description: "Password"
|
||||||
|
required: true
|
||||||
|
ghcr_username:
|
||||||
|
description: "GHCR username. Usually set from the github.actor variable"
|
||||||
|
required: true
|
||||||
|
ghcr_password:
|
||||||
|
description: "GHCR password. Usually set from the secrets.GITHUB_TOKEN variable"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
sha_short:
|
||||||
|
description: "The short SHA used for image builds"
|
||||||
|
value: ${{ steps.vars.outputs.sha_short }}
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Get Short SHA
|
||||||
|
id: vars
|
||||||
|
run: |
|
||||||
|
echo ::set-output name=sha_short::${GITHUB_SHA::7}
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- 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
|
||||||
|
if: ${{ github.ref == 'master' && github.event.pull_request.merged == true }}
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ inputs.username }}
|
||||||
|
password: ${{ inputs.password }}
|
||||||
|
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
if: ${{ github.ref == 'master' && github.event.pull_request.merged == true }}
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ inputs.ghcr_username }}
|
||||||
|
password: ${{ inputs.ghcr_password }}
|
||||||
5
.github/renovate.json5
vendored
5
.github/renovate.json5
vendored
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extends": ["config:base"],
|
"extends": ["config:base"],
|
||||||
|
"labels": ["dependencies"],
|
||||||
"packageRules": [
|
"packageRules": [
|
||||||
{
|
{
|
||||||
// automatically merge an update of runner
|
// automatically merge an update of runner
|
||||||
@@ -11,7 +12,9 @@
|
|||||||
"regexManagers": [
|
"regexManagers": [
|
||||||
{
|
{
|
||||||
// use https://github.com/actions/runner/releases
|
// use https://github.com/actions/runner/releases
|
||||||
"fileMatch": [".github/workflows/build-and-release-runners.yml"],
|
"fileMatch": [
|
||||||
|
".github/workflows/runners.yml"
|
||||||
|
],
|
||||||
"matchStrings": ["RUNNER_VERSION: +(?<currentValue>.*?)\\n"],
|
"matchStrings": ["RUNNER_VERSION: +(?<currentValue>.*?)\\n"],
|
||||||
"depNameTemplate": "actions/runner",
|
"depNameTemplate": "actions/runner",
|
||||||
"datasourceTemplate": "github-releases"
|
"datasourceTemplate": "github-releases"
|
||||||
|
|||||||
3
.github/stale.yml
vendored
3
.github/stale.yml
vendored
@@ -18,8 +18,9 @@ exemptLabels:
|
|||||||
- refactor
|
- refactor
|
||||||
- documentation
|
- documentation
|
||||||
- chore
|
- chore
|
||||||
- needs-investigation
|
|
||||||
- bug
|
- bug
|
||||||
|
- dependencies
|
||||||
|
- needs-investigation
|
||||||
|
|
||||||
# Set to true to ignore issues in a project (defaults to false)
|
# Set to true to ignore issues in a project (defaults to false)
|
||||||
exemptProjects: false
|
exemptProjects: false
|
||||||
|
|||||||
121
.github/workflows/build-and-release-runners.yml
vendored
121
.github/workflows/build-and-release-runners.yml
vendored
@@ -1,121 +0,0 @@
|
|||||||
name: Build and Release Runners
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
paths:
|
|
||||||
- 'runner/**'
|
|
||||||
- .github/workflows/build-and-release-runners.yml
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
paths:
|
|
||||||
- runner/patched/*
|
|
||||||
- runner/Dockerfile
|
|
||||||
- runner/Dockerfile.ubuntu.1804
|
|
||||||
- runner/Dockerfile.dindrunner
|
|
||||||
- runner/entrypoint.sh
|
|
||||||
- .github/workflows/build-and-release-runners.yml
|
|
||||||
|
|
||||||
env:
|
|
||||||
RUNNER_VERSION: 2.283.2
|
|
||||||
DOCKER_VERSION: 20.10.8
|
|
||||||
DOCKERHUB_USERNAME: summerwind
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Build ${{ matrix.name }}-ubuntu-${{ matrix.os-version }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- name: actions-runner
|
|
||||||
os-version: 20.04
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
- name: actions-runner
|
|
||||||
os-version: 18.04
|
|
||||||
dockerfile: Dockerfile.ubuntu.1804
|
|
||||||
- name: actions-runner-dind
|
|
||||||
os-version: 20.04
|
|
||||||
dockerfile: Dockerfile.dindrunner
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Set outputs
|
|
||||||
id: vars
|
|
||||||
run: echo ::set-output name=sha_short::${GITHUB_SHA::7}
|
|
||||||
|
|
||||||
- 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
|
|
||||||
if: ${{ github.event_name == 'push' || github.event_name == 'release' }}
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_USER }}
|
|
||||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and Push Versioned Tags
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: ./runner
|
|
||||||
file: ./runner/${{ matrix.dockerfile }}
|
|
||||||
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
|
|
||||||
|
|
||||||
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: |
|
|
||||||
RUNNER_VERSION=${{ env.RUNNER_VERSION }}
|
|
||||||
DOCKER_VERSION=${{ env.DOCKER_VERSION }}
|
|
||||||
tags: |
|
|
||||||
${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:latest
|
|
||||||
7
.github/workflows/on-push-lint-charts.yml
vendored
7
.github/workflows/on-push-lint-charts.yml
vendored
@@ -10,11 +10,12 @@ on:
|
|||||||
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.8.0
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint-test:
|
lint-test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
name: Lint Chart
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -22,7 +23,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Helm
|
- name: Set up Helm
|
||||||
uses: azure/setup-helm@v1
|
uses: azure/setup-helm@v2.0
|
||||||
with:
|
with:
|
||||||
version: ${{ env.HELM_VERSION }}
|
version: ${{ env.HELM_VERSION }}
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ jobs:
|
|||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
|
|
||||||
- name: Set up chart-testing
|
- name: Set up chart-testing
|
||||||
uses: helm/chart-testing-action@v2.1.0
|
uses: helm/chart-testing-action@v2.2.0
|
||||||
|
|
||||||
- name: Run chart-testing (list-changed)
|
- name: Run chart-testing (list-changed)
|
||||||
id: list-changed
|
id: list-changed
|
||||||
|
|||||||
@@ -13,11 +13,14 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
KUBE_SCORE_VERSION: 1.10.0
|
KUBE_SCORE_VERSION: 1.10.0
|
||||||
HELM_VERSION: v3.4.1
|
HELM_VERSION: v3.8.0
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint-chart:
|
lint-chart:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
name: Lint Chart
|
||||||
|
outputs:
|
||||||
|
publish-chart: ${{ steps.publish-chart-step.outputs.publish }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -25,7 +28,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Helm
|
- name: Set up Helm
|
||||||
uses: azure/setup-helm@v1
|
uses: azure/setup-helm@v2.0
|
||||||
with:
|
with:
|
||||||
version: ${{ env.HELM_VERSION }}
|
version: ${{ env.HELM_VERSION }}
|
||||||
|
|
||||||
@@ -51,7 +54,7 @@ jobs:
|
|||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
|
|
||||||
- name: Set up chart-testing
|
- name: Set up chart-testing
|
||||||
uses: helm/chart-testing-action@v2.1.0
|
uses: helm/chart-testing-action@v2.2.0
|
||||||
|
|
||||||
- name: Run chart-testing (list-changed)
|
- name: Run chart-testing (list-changed)
|
||||||
id: list-changed
|
id: list-changed
|
||||||
@@ -79,10 +82,25 @@ jobs:
|
|||||||
run: ct install --config charts/.ci/ct-config.yaml
|
run: ct install --config charts/.ci/ct-config.yaml
|
||||||
if: steps.list-changed.outputs.changed == 'true'
|
if: steps.list-changed.outputs.changed == 'true'
|
||||||
|
|
||||||
publish-chart:
|
# WARNING: This relies on the latest release being inat the top of the JSON from GitHub and a clean chart.yaml
|
||||||
|
- name: Check if Chart Publish is Needed
|
||||||
|
id: publish-chart-step
|
||||||
|
run: |
|
||||||
|
CHART_TEXT=$(curl -fs https://raw.githubusercontent.com/actions-runner-controller/actions-runner-controller/master/charts/actions-runner-controller/Chart.yaml)
|
||||||
|
NEW_CHART_VERSION=$(echo "$CHART_TEXT" | grep version: | cut -d ' ' -f 2)
|
||||||
|
RELEASE_LIST=$(curl -fs https://api.github.com/repos/actions-runner-controller/actions-runner-controller/releases | jq .[].tag_name | grep actions-runner-controller | cut -d '"' -f 2 | cut -d '-' -f 4)
|
||||||
|
LATEST_RELEASED_CHART_VERSION=$(echo $RELEASE_LIST | cut -d ' ' -f 1)
|
||||||
|
echo "Chart version in master : $NEW_CHART_VERSION"
|
||||||
|
echo "Latest release chart version : $LATEST_RELEASED_CHART_VERSION"
|
||||||
|
if [[ $NEW_CHART_VERSION != $LATEST_RELEASED_CHART_VERSION ]]; then
|
||||||
|
echo "::set-output name=publish::true"
|
||||||
|
fi
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
publish-chart:
|
||||||
|
if: needs.lint-chart.outputs.publish-chart == 'true'
|
||||||
needs: lint-chart
|
needs: lint-chart
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Publish Chart
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@@ -96,7 +114,7 @@ jobs:
|
|||||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||||
|
|
||||||
- name: Run chart-releaser
|
- name: Run chart-releaser
|
||||||
uses: helm/chart-releaser-action@v1.2.1
|
uses: helm/chart-releaser-action@v1.3.0
|
||||||
env:
|
env:
|
||||||
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
|
||||||
|
|||||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -1,3 +1,5 @@
|
|||||||
|
name: Publish Controller Image
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [published]
|
types: [published]
|
||||||
@@ -16,6 +18,10 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: '^1.17.7'
|
||||||
|
|
||||||
- name: Install tools
|
- name: Install tools
|
||||||
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.2.0/kubebuilder_2.2.0_linux_amd64.tar.gz
|
||||||
|
|||||||
73
.github/workflows/runners.yml
vendored
Normal file
73
.github/workflows/runners.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
name: Runners
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- synchronize
|
||||||
|
- reopened
|
||||||
|
- closed
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
paths:
|
||||||
|
- 'runner/**'
|
||||||
|
- .github/workflows/runners.yml
|
||||||
|
- '!**.md'
|
||||||
|
|
||||||
|
env:
|
||||||
|
RUNNER_VERSION: 2.287.1
|
||||||
|
DOCKER_VERSION: 20.10.12
|
||||||
|
DOCKERHUB_USERNAME: summerwind
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: read
|
||||||
|
name: Build ${{ matrix.name }}-${{ matrix.os-name }}-${{ matrix.os-version }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- name: actions-runner
|
||||||
|
os-name: ubuntu
|
||||||
|
os-version: 20.04
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
- name: actions-runner-dind
|
||||||
|
os-name: ubuntu
|
||||||
|
os-version: 20.04
|
||||||
|
dockerfile: Dockerfile.dindrunner
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Setup Docker Environment
|
||||||
|
id: vars
|
||||||
|
uses: ./.github/actions/setup-docker-environment
|
||||||
|
with:
|
||||||
|
username: ${{ env.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
ghcr_username: ${{ github.actor }}
|
||||||
|
ghcr_password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and Push Versioned Tags
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: ./runner
|
||||||
|
file: ./runner/${{ matrix.dockerfile }}
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: ${{ github.ref == 'master' && github.event.pull_request.merged == true }}
|
||||||
|
build-args: |
|
||||||
|
RUNNER_VERSION=${{ env.RUNNER_VERSION }}
|
||||||
|
DOCKER_VERSION=${{ env.DOCKER_VERSION }}
|
||||||
|
tags: |
|
||||||
|
${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:v${{ env.RUNNER_VERSION }}-${{ matrix.os-name }}-${{ matrix.os-version }}
|
||||||
|
${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:v${{ env.RUNNER_VERSION }}-${{ matrix.os-name }}-${{ matrix.os-version }}-${{ steps.vars.outputs.sha_short }}
|
||||||
|
${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:latest
|
||||||
|
ghcr.io/${{ github.repository }}/${{ matrix.name }}:latest
|
||||||
|
ghcr.io/${{ github.repository }}/${{ matrix.name }}:v${{ env.RUNNER_VERSION }}-${{ matrix.os-name }}-${{ matrix.os-version }}
|
||||||
|
ghcr.io/${{ github.repository }}/${{ matrix.name }}:v${{ env.RUNNER_VERSION }}-${{ matrix.os-name }}-${{ matrix.os-version }}-${{ steps.vars.outputs.sha_short }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
1
.github/workflows/test-entrypoint.yaml
vendored
1
.github/workflows/test-entrypoint.yaml
vendored
@@ -7,6 +7,7 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- 'runner/**'
|
- 'runner/**'
|
||||||
- 'test/entrypoint/**'
|
- 'test/entrypoint/**'
|
||||||
|
- '!**.md'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
|
|||||||
11
.github/workflows/test.yaml
vendored
11
.github/workflows/test.yaml
vendored
@@ -5,9 +5,14 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
|
- .github/workflows/runners.yml
|
||||||
|
- .github/workflows/on-push-lint-charts.yml
|
||||||
|
- .github/workflows/on-push-master-publish-chart.yml
|
||||||
|
- .github/workflows/release.yml
|
||||||
|
- .github/workflows/test-entrypoint.yml
|
||||||
|
- .github/workflows/wip.yml
|
||||||
- 'runner/**'
|
- 'runner/**'
|
||||||
- .github/workflows/build-and-release-runners.yml
|
- '**.md'
|
||||||
- '*.md'
|
|
||||||
- '.gitignore'
|
- '.gitignore'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -19,7 +24,7 @@ jobs:
|
|||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: '^1.16.5'
|
go-version: '^1.17.7'
|
||||||
- run: go version
|
- run: go version
|
||||||
- name: Install kubebuilder
|
- name: Install kubebuilder
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
9
.github/workflows/wip.yml
vendored
9
.github/workflows/wip.yml
vendored
@@ -1,8 +1,15 @@
|
|||||||
|
name: Publish Canary Image
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
|
- .github/workflows/runners.yml
|
||||||
|
- .github/workflows/on-push-lint-charts.yml
|
||||||
|
- .github/workflows/on-push-master-publish-chart.yml
|
||||||
|
- .github/workflows/release.yml
|
||||||
|
- .github/workflows/test-entrypoint.yml
|
||||||
- "runner/**"
|
- "runner/**"
|
||||||
- "**.md"
|
- "**.md"
|
||||||
- ".gitignore"
|
- ".gitignore"
|
||||||
@@ -10,7 +17,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: release-latest
|
name: Build and Publish Canary Image
|
||||||
env:
|
env:
|
||||||
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USER }}
|
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USER }}
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -1,5 +1,20 @@
|
|||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
### Testing Controller Built from a Pull Request
|
||||||
|
|
||||||
|
We always appreciate your help in testing open pull requests by deploying custom builds of actions-runner-controller onto your own environment, so that we are extra sure we didn't break anything.
|
||||||
|
|
||||||
|
It is especially true when the pull request is about GitHub Enterprise, both GHEC and GHES, as [maintainers don't have GitHub Enterprise environments for testing](/README.md#github-enterprise-support).
|
||||||
|
|
||||||
|
The process would look like the below:
|
||||||
|
|
||||||
|
- Clone this repository locally
|
||||||
|
- Checkout the branch. If you use the `gh` command, run `gh pr checkout $PR_NUMBER`
|
||||||
|
- Run `NAME=$DOCKER_USER/actions-runner-controller VERSION=canary make docker-build docker-push` for a custom container image build
|
||||||
|
- Update your actions-runner-controller's controller-manager deployment to use the new image, `$DOCKER_USER/actions-runner-controller:canary`
|
||||||
|
|
||||||
|
Please also note that you need to replace `$DOCKER_USER` with your own DockerHub account name.
|
||||||
|
|
||||||
### How to Contribute a Patch
|
### 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.
|
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.
|
||||||
@@ -80,6 +95,7 @@ To make your development cycle faster, use the below command to update deploy an
|
|||||||
# you either need to bump VERSION and RUNNER_TAG on each run,
|
# 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.
|
# or manually run `kubectl delete pod $POD` on respective pods for changes to actually take effect.
|
||||||
|
|
||||||
|
# Makefile
|
||||||
VERSION=controller1 \
|
VERSION=controller1 \
|
||||||
RUNNER_TAG=runner1 \
|
RUNNER_TAG=runner1 \
|
||||||
make acceptance/pull acceptance/kind docker-build acceptance/load acceptance/deploy
|
make acceptance/pull acceptance/kind docker-build acceptance/load acceptance/deploy
|
||||||
@@ -88,14 +104,16 @@ VERSION=controller1 \
|
|||||||
If you've already deployed actions-runner-controller and only want to recreate pods to use the newer image, you can run:
|
If you've already deployed actions-runner-controller and only want to recreate pods to use the newer image, you can run:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
# Makefile
|
||||||
NAME=$DOCKER_USER/actions-runner-controller \
|
NAME=$DOCKER_USER/actions-runner-controller \
|
||||||
make docker-build acceptance/load && \
|
make docker-build acceptance/load && \
|
||||||
kubectl -n actions-runner-system delete po $(kubectl -n actions-runner-system get po -ojsonpath={.items[*].metadata.name})
|
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,
|
Similarly, if you'd like to recreate runner pods with the newer runner image you can use the runner specific [Makefile](runner/Makefile) to build and / or push new runner images
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
# runner/Makefile
|
||||||
NAME=$DOCKER_USER/actions-runner make \
|
NAME=$DOCKER_USER/actions-runner make \
|
||||||
-C runner docker-{build,push}-ubuntu && \
|
-C runner docker-{build,push}-ubuntu && \
|
||||||
(kubectl get po -ojsonpath={.items[*].metadata.name} | xargs -n1 kubectl delete po)
|
(kubectl get po -ojsonpath={.items[*].metadata.name} | xargs -n1 kubectl delete po)
|
||||||
@@ -136,7 +154,4 @@ GINKGO_FOCUS='[It] should create a new Runner resource from the specified templa
|
|||||||
|
|
||||||
#### Helm Version Bumps
|
#### Helm Version Bumps
|
||||||
|
|
||||||
**Chart Version :** When bumping the chart version follow semantic versioning https://semver.org/<br />
|
In general we ask you not to bump the version in your PR, the maintainers in general manage the publishing of a new chart.
|
||||||
**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.
|
|
||||||
|
|||||||
12
Makefile
12
Makefile
@@ -5,6 +5,7 @@ else
|
|||||||
endif
|
endif
|
||||||
DOCKER_USER ?= $(shell echo ${NAME} | cut -d / -f1)
|
DOCKER_USER ?= $(shell echo ${NAME} | cut -d / -f1)
|
||||||
VERSION ?= latest
|
VERSION ?= latest
|
||||||
|
TARGETPLATFORM ?= $(shell arch)
|
||||||
RUNNER_NAME ?= ${DOCKER_USER}/actions-runner
|
RUNNER_NAME ?= ${DOCKER_USER}/actions-runner
|
||||||
RUNNER_TAG ?= ${VERSION}
|
RUNNER_TAG ?= ${VERSION}
|
||||||
TEST_REPO ?= ${DOCKER_USER}/actions-runner-controller
|
TEST_REPO ?= ${DOCKER_USER}/actions-runner-controller
|
||||||
@@ -17,9 +18,10 @@ RUNNER_FEATURE_FLAG_EPHEMERAL ?=
|
|||||||
KUBECONTEXT ?= kind-acceptance
|
KUBECONTEXT ?= kind-acceptance
|
||||||
CLUSTER ?= acceptance
|
CLUSTER ?= acceptance
|
||||||
CERT_MANAGER_VERSION ?= v1.1.1
|
CERT_MANAGER_VERSION ?= v1.1.1
|
||||||
|
KUBE_RBAC_PROXY_VERSION ?= v0.11.0
|
||||||
|
|
||||||
# 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,generateEmbeddedObjectMeta=true"
|
CRD_OPTIONS ?= "crd: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))
|
||||||
@@ -110,7 +112,7 @@ generate: controller-gen
|
|||||||
# Build the docker image
|
# Build the docker image
|
||||||
docker-build:
|
docker-build:
|
||||||
docker build -t ${NAME}:${VERSION} .
|
docker build -t ${NAME}:${VERSION} .
|
||||||
docker build -t ${RUNNER_NAME}:${RUNNER_TAG} --build-arg TARGETPLATFORM=$(shell arch) runner
|
docker build -t ${RUNNER_NAME}:${RUNNER_TAG} --build-arg TARGETPLATFORM=${TARGETPLATFORM} runner
|
||||||
|
|
||||||
docker-buildx:
|
docker-buildx:
|
||||||
export DOCKER_CLI_EXPERIMENTAL=enabled
|
export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
@@ -156,7 +158,7 @@ acceptance/kind:
|
|||||||
# See https://kind.sigs.k8s.io/docs/user/known-issues/#docker-installed-with-snap
|
# See https://kind.sigs.k8s.io/docs/user/known-issues/#docker-installed-with-snap
|
||||||
acceptance/load:
|
acceptance/load:
|
||||||
kind load docker-image ${NAME}:${VERSION} --name ${CLUSTER}
|
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 quay.io/brancz/kube-rbac-proxy:$(KUBE_RBAC_PROXY_VERSION) --name ${CLUSTER}
|
||||||
kind load docker-image ${RUNNER_NAME}:${RUNNER_TAG} --name ${CLUSTER}
|
kind load docker-image ${RUNNER_NAME}:${RUNNER_TAG} --name ${CLUSTER}
|
||||||
kind load docker-image docker:dind --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-controller:$(CERT_MANAGER_VERSION) --name ${CLUSTER}
|
||||||
@@ -166,7 +168,7 @@ acceptance/load:
|
|||||||
|
|
||||||
# Pull the docker images for acceptance
|
# Pull the docker images for acceptance
|
||||||
acceptance/pull:
|
acceptance/pull:
|
||||||
docker pull quay.io/brancz/kube-rbac-proxy:v0.10.0
|
docker pull quay.io/brancz/kube-rbac-proxy:$(KUBE_RBAC_PROXY_VERSION)
|
||||||
docker pull docker:dind
|
docker pull docker:dind
|
||||||
docker pull quay.io/jetstack/cert-manager-controller:$(CERT_MANAGER_VERSION)
|
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-cainjector:$(CERT_MANAGER_VERSION)
|
||||||
@@ -221,7 +223,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.6.0 ;\
|
go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.7.0 ;\
|
||||||
rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
|
rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
|
||||||
}
|
}
|
||||||
endif
|
endif
|
||||||
|
|||||||
555
README.md
555
README.md
@@ -17,9 +17,10 @@ ToC:
|
|||||||
- [Repository Runners](#repository-runners)
|
- [Repository Runners](#repository-runners)
|
||||||
- [Organization Runners](#organization-runners)
|
- [Organization Runners](#organization-runners)
|
||||||
- [Enterprise Runners](#enterprise-runners)
|
- [Enterprise Runners](#enterprise-runners)
|
||||||
- [Runner Deployments](#runnerdeployments)
|
- [RunnerDeployments](#runnerdeployments)
|
||||||
- [Note on scaling to/from 0](#note-on-scaling-tofrom-0)
|
|
||||||
- [Autoscaling](#autoscaling)
|
- [Autoscaling](#autoscaling)
|
||||||
|
- [Anti-Flapping Configuration](#anti-flapping-configuration)
|
||||||
|
- [Pull Driven Scaling](#pull-driven-scaling)
|
||||||
- [Webhook Driven Scaling](#webhook-driven-scaling)
|
- [Webhook Driven Scaling](#webhook-driven-scaling)
|
||||||
- [Autoscaling to/from 0](#autoscaling-tofrom-0)
|
- [Autoscaling to/from 0](#autoscaling-tofrom-0)
|
||||||
- [Scheduled Overrides](#scheduled-overrides)
|
- [Scheduled Overrides](#scheduled-overrides)
|
||||||
@@ -27,11 +28,14 @@ ToC:
|
|||||||
- [Additional Tweaks](#additional-tweaks)
|
- [Additional Tweaks](#additional-tweaks)
|
||||||
- [Runner Labels](#runner-labels)
|
- [Runner Labels](#runner-labels)
|
||||||
- [Runner Groups](#runner-groups)
|
- [Runner Groups](#runner-groups)
|
||||||
|
- [Runner Entrypoint Features](#runner-entrypoint-features)
|
||||||
- [Using IRSA (IAM Roles for Service Accounts) in EKS](#using-irsa-iam-roles-for-service-accounts-in-eks)
|
- [Using IRSA (IAM Roles for Service Accounts) in EKS](#using-irsa-iam-roles-for-service-accounts-in-eks)
|
||||||
- [Stateful Runners](#stateful-runners)
|
- [Stateful Runners](#stateful-runners)
|
||||||
- [Ephemeral Runners](#ephemeral-runners)
|
- [Ephemeral Runners](#ephemeral-runners)
|
||||||
- [Software Installed in the Runner Image](#software-installed-in-the-runner-image)
|
- [Software Installed in the Runner Image](#software-installed-in-the-runner-image)
|
||||||
|
- [Using without cert-manager](#using-without-cert-manager)
|
||||||
- [Common Errors](#common-errors)
|
- [Common Errors](#common-errors)
|
||||||
|
- [Troubleshooting](#troubleshooting)
|
||||||
- [Contributing](#contributing)
|
- [Contributing](#contributing)
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
@@ -42,7 +46,7 @@ ToC:
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
actions-runner-controller uses [cert-manager](https://cert-manager.io/docs/installation/kubernetes/) for certificate management of Admission Webhook. Make sure you have already installed cert-manager before you install. The installation instructions for cert-manager can be found below.
|
By default, actions-runner-controller uses [cert-manager](https://cert-manager.io/docs/installation/kubernetes/) for certificate management of Admission Webhook. Make sure you have already installed cert-manager before you install. The installation instructions for cert-manager can be found below.
|
||||||
|
|
||||||
- [Installing cert-manager on Kubernetes](https://cert-manager.io/docs/installation/kubernetes/)
|
- [Installing cert-manager on Kubernetes](https://cert-manager.io/docs/installation/kubernetes/)
|
||||||
|
|
||||||
@@ -51,8 +55,8 @@ Subsequent to this, install the custom resource definitions and actions-runner-c
|
|||||||
**Kubectl Deployment:**
|
**Kubectl Deployment:**
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# REPLACE "v0.20.1" with the version you wish to deploy
|
# REPLACE "v0.20.2" with the version you wish to deploy
|
||||||
kubectl apply -f https://github.com/actions-runner-controller/actions-runner-controller/releases/download/v0.20.1/actions-runner-controller.yaml
|
kubectl apply -f https://github.com/actions-runner-controller/actions-runner-controller/releases/download/v0.20.2/actions-runner-controller.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
**Helm Deployment:**
|
**Helm Deployment:**
|
||||||
@@ -67,11 +71,11 @@ helm upgrade --install --namespace actions-runner-system --create-namespace \
|
|||||||
|
|
||||||
### GitHub Enterprise Support
|
### GitHub Enterprise Support
|
||||||
|
|
||||||
The solution supports both GitHub Enterprise Cloud and Server editions as well as regular GitHub. Both PAT (personal access token) and GitHub App authentication works for installations that will be deploying either repository level and / or organization level runners. If you need to deploy enterprise level runners then you are restricted to PAT based authentication as GitHub doesn't support GitHub App based authentication for enterprise runners currently.
|
The solution supports both GHEC (GitHub Enterprise Cloud) and GHES (GitHub Enterprise Server) editions as well as regular GitHub. Both PAT (personal access token) and GitHub App authentication works for installations that will be deploying either repository level and / or organization level runners. If you need to deploy enterprise level runners then you are restricted to PAT based authentication as GitHub doesn't support GitHub App based authentication for enterprise runners currently.
|
||||||
|
|
||||||
If you are deploying this solution into a GitHub Enterprise Server environment then you will need version >= [3.0.0](https://docs.github.com/en/enterprise-server@3.0/admin/release-notes#3.0.0).
|
If you are deploying this solution into a GHES environment then you will need to be running version >= [3.3.0](https://docs.github.com/en/enterprise-server@3.3/admin/release-notes).
|
||||||
|
|
||||||
When deploying the solution for a GitHub Enterprise Server environment you need to provide an additional environment variable as part of the controller deployment:
|
When deploying the solution for a GHES environment you need to provide an additional environment variable as part of the controller deployment:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl set env deploy controller-manager -c manager GITHUB_ENTERPRISE_URL=<GHEC/S URL> --namespace actions-runner-system
|
kubectl set env deploy controller-manager -c manager GITHUB_ENTERPRISE_URL=<GHEC/S URL> --namespace actions-runner-system
|
||||||
@@ -88,7 +92,7 @@ There are two ways for actions-runner-controller to authenticate with the GitHub
|
|||||||
|
|
||||||
Functionality wise, there isn't much of a difference between the 2 authentication methods. The primarily benefit of authenticating via a GitHub App is an [increased API quota](https://docs.github.com/en/developers/apps/rate-limits-for-github-apps).
|
Functionality wise, there isn't much of a difference between the 2 authentication methods. The primarily benefit of authenticating via a GitHub App is an [increased API quota](https://docs.github.com/en/developers/apps/rate-limits-for-github-apps).
|
||||||
|
|
||||||
If you are deploying the solution for a GitHub Enterprise Server environment you are able to [configure your rate limit settings](https://docs.github.com/en/enterprise-server@3.0/admin/configuration/configuring-rate-limits) making the main benefit irrelevant. If you're deploying the solution for a GitHub Enterprise Cloud or regular GitHub environment and you run into rate limit issues, consider deploying the solution using the GitHub App authentication method instead.
|
If you are deploying the solution for a GHES environment you are able to [configure your rate limit settings](https://docs.github.com/en/enterprise-server@3.0/admin/configuration/configuring-rate-limits) making the main benefit irrelevant. If you're deploying the solution for a GHEC or regular GitHub environment and you run into rate limit issues, consider deploying the solution using the GitHub App authentication method instead.
|
||||||
|
|
||||||
### Deploying Using GitHub App Authentication
|
### Deploying Using GitHub App Authentication
|
||||||
|
|
||||||
@@ -113,11 +117,15 @@ _Note: Links are provided further down to create an app for your logged in user
|
|||||||
**Organization Permissions**
|
**Organization Permissions**
|
||||||
* Self-hosted runners (read / write)
|
* Self-hosted runners (read / write)
|
||||||
|
|
||||||
**Subscribe to events**
|
|
||||||
* Check run (if you are going to use [Webhook Driven Scaling](#webhook-driven-scaling))
|
|
||||||
|
|
||||||
_Note: All API routes mapped to their permissions can be found [here](https://docs.github.com/en/rest/reference/permissions-required-for-github-apps) if you wish to review_
|
_Note: All API routes mapped to their permissions can be found [here](https://docs.github.com/en/rest/reference/permissions-required-for-github-apps) if you wish to review_
|
||||||
|
|
||||||
|
**Subscribe to events**
|
||||||
|
|
||||||
|
At this point you have a choice of configuring a webhook, a webhook is needed if you are going to use [webhook driven scaling](#webhook-driven-scaling). The webhook can be configured centrally in the GitHub app itself or separately. In either case the event details are:
|
||||||
|
|
||||||
|
* Check run (required for all webhook driven scaling events)
|
||||||
|
* Workflow job (optionally) (required for [webhook driven scaling with workflow_job events](https://github.com/actions-runner-controller/actions-runner-controller#example-1-scale-on-each-workflow_job-event)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Setup Steps**
|
**Setup Steps**
|
||||||
@@ -186,10 +194,12 @@ Log-in to a GitHub account that has `admin` privileges for the repository, and [
|
|||||||
|
|
||||||
**Required Scopes for Enterprise Runners**
|
**Required Scopes for Enterprise Runners**
|
||||||
|
|
||||||
* admin:enterprise (Full control)
|
* admin:enterprise (manage_runners:enterprise)
|
||||||
|
|
||||||
_Note: When you deploy enterprise runners they will get access to organizations, however, access to the repositories themselves is **NOT** allowed by default. Each GitHub organization must allow enterprise runner groups to be used in repositories as an initial one time configuration step, this only needs to be done once after which it is permanent for that runner group._
|
_Note: When you deploy enterprise runners they will get access to organizations, however, access to the repositories themselves is **NOT** allowed by default. Each GitHub organization must allow enterprise runner groups to be used in repositories as an initial one time configuration step, this only needs to be done once after which it is permanent for that runner group._
|
||||||
|
|
||||||
|
_Note: GitHub do not document exactly what permissions you get with each PAT scope beyond a vague description. The best documentation they provide on the topic can be found [here](https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps) if you wish to review. The docs target OAuth apps and so are incomplete and amy not be 100% accurate._
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Once you have created the appropriate token, deploy it as a secret to your Kubernetes cluster that you are going to deploy the solution on:
|
Once you have created the appropriate token, deploy it as a secret to your Kubernetes cluster that you are going to deploy the solution on:
|
||||||
@@ -248,7 +258,7 @@ kind: Runner
|
|||||||
metadata:
|
metadata:
|
||||||
name: example-runner
|
name: example-runner
|
||||||
spec:
|
spec:
|
||||||
repository: actions-runner-controller/actions-runner-controller
|
repository: example/myrepo
|
||||||
env: []
|
env: []
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -315,9 +325,11 @@ Now you can see the runner on the enterprise level (if you have enterprise acces
|
|||||||
|
|
||||||
### RunnerDeployments
|
### RunnerDeployments
|
||||||
|
|
||||||
There are `RunnerReplicaSet` and `RunnerDeployment` that corresponds to `ReplicaSet` and `Deployment` but for `Runner`.
|
You can manage sets of runners instead of individually through the `RunnerDeployment` kind and its `replicas:` attribute. This kind is required for many of the advanced features.
|
||||||
|
|
||||||
You usually need only `RunnerDeployment` rather than `RunnerReplicaSet` as the former is for managing the latter.
|
There are `RunnerReplicaSet` and `RunnerDeployment` kinds that corresponds to the `ReplicaSet` and `Deployment` kinds but for the `Runner` kind.
|
||||||
|
|
||||||
|
You typically only need `RunnerDeployment` rather than `RunnerReplicaSet` as the former is for managing the latter.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# runnerdeployment.yaml
|
# runnerdeployment.yaml
|
||||||
@@ -349,61 +361,21 @@ example-runnerdeploy2475h595fr mumoshu/actions-runner-controller-ci Running
|
|||||||
example-runnerdeploy2475ht2qbr mumoshu/actions-runner-controller-ci Running
|
example-runnerdeploy2475ht2qbr mumoshu/actions-runner-controller-ci Running
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Note on scaling to/from 0
|
|
||||||
|
|
||||||
> This feature requires controller version => [v0.19.0](https://github.com/actions-runner-controller/actions-runner-controller/releases/tag/v0.19.0)
|
|
||||||
|
|
||||||
You can either delete the runner deployment, or update it to have `replicas: 0`, so that there will be 0 runner pods in the cluster. This, in combination with e.g. `cluster-autoscaler`, enables you to save your infrastructure cost when there's no need to run Actions jobs.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# runnerdeployment.yaml
|
|
||||||
apiVersion: actions.summerwind.dev/v1alpha1
|
|
||||||
kind: RunnerDeployment
|
|
||||||
metadata:
|
|
||||||
name: example-runnerdeploy
|
|
||||||
spec:
|
|
||||||
replicas: 0
|
|
||||||
```
|
|
||||||
|
|
||||||
The implication of setting `replicas: 0` instead of deleting the runner deployment is that you can let GitHub Actions queue jobs until there will be one or more runners. See [#465](https://github.com/actions-runner-controller/actions-runner-controller/pull/465) for more information.
|
|
||||||
|
|
||||||
Also note that the controller creates a "registration-only" runner per RunnerReplicaSet on it's being scaled to zero,
|
|
||||||
and retains it until there are one or more runners available.
|
|
||||||
|
|
||||||
This, in combination with a correctly configured HorizontalRunnerAutoscaler, allows you to automatically [scale to/from 0](#autoscaling-tofrom-0)
|
|
||||||
|
|
||||||
### Autoscaling
|
### Autoscaling
|
||||||
|
|
||||||
A `RunnerDeployment` can scale the number of runners between `minReplicas` and `maxReplicas` fields on either a pull based scaling metric as defined in the `metrics` attribute or a webhook event. Since GitHub's release of the [`workflow_job` webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#workflow_job), webhook-based autoscaling is the preferred way of autoscaling, it offers more accurate quicker scaling compared to the pull based metrics and is easy to setup.
|
> Since the release of GitHub's [`workflow_job` webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#workflow_job), webhook driven scaling is the preferred way of autoscaling as it enables targeted scaling of your `RunnerDeployment` / `RunnerSet` as it includes the `runs-on` information needed to scale the appropriate runners for that workflow run. More broadly, webhook driven scaling is the preferred scaling option as it is far quicker compared to the pull driven scaling and is easy to setup.
|
||||||
|
|
||||||
The below section covers the pull based metrics which you may want to consider if your scaling demands are minor. To configure your webhook based scaling see the [Webhook Driven Scaling](#webhook-driven-scaling) section.
|
A `RunnerDeployment` or `RunnerSet` (see [stateful runners](#stateful-runners) for more details on this kind) can scale the number of runners between `minReplicas` and `maxReplicas` fields driven by either pull based scaling metrics or via a webhook event (see limitations section of [stateful runners](#stateful-runners) for cavaets of this kind). Whether the autoscaling is driven from a webhook event or pull based metrics it is implemented by backing a `RunnerDeployment` or `RunnerSet` kind with a `HorizontalRunnerAutoscaler` kind.
|
||||||
|
|
||||||
**Pull Driven Scaling Metrics**
|
**_Important!!! If you opt to configure autoscaling, ensure you remove the `replicas:` attribute in the `RunnerDeployment` / `RunnerSet` kinds that are configured for autoscaling [#206](https://github.com/actions-runner-controller/actions-runner-controller/issues/206#issuecomment-748601907)_**
|
||||||
|
|
||||||
**TotalNumberOfQueuedAndInProgressWorkflowRuns**
|
#### Anti-Flapping Configuration
|
||||||
|
|
||||||
In the below example, `actions-runner` will poll GitHub for all pending workflows with the poll period defined by the sync period configuration. It will then scale to e.g. 3 if there're 3 pending jobs at sync time.
|
For both pull driven or webhook driven scaling an anti-flapping implementation is included, by default a runner won't be scaled down within 10 minutes of it having been scaled up. This delay is configurable by including the attribute `scaleDownDelaySecondsAfterScaleOut:` in a `HorizontalRunnerAutoscaler` kind's `spec:`.
|
||||||
With this scaling metric we are required to define a list of repositories within our metric.
|
|
||||||
|
|
||||||
The scale out performance is controlled via the manager containers startup `--sync-period` argument. The default value is set to 10 minutes to prevent default deployments rate limiting themselves from the GitHub API.
|
This configuration has the final say on if a runner can be scaled down or not regardless of the chosen scaling method. Depending on your requirements, you may want to consider adjusting this by setting the `scaleDownDelaySecondsAfterScaleOut:` attribute.
|
||||||
|
|
||||||
**Kustomize Config :** The period can be customised in the `config/default/manager_auth_proxy_patch.yaml` patch<br />
|
Below is a complete basic example with one of the pull driven scaling metrics.
|
||||||
|
|
||||||
**Benefits of this metric**
|
|
||||||
1. Supports named repositories allowing you to restrict the runner to a specified set of repositories server side.
|
|
||||||
2. Scales the runner count based on the actual queue depth of the jobs meaning a more 1:1 scaling of runners to queued jobs (caveat, see drawback #4)
|
|
||||||
3. Like all scaling metrics, you can manage workflow allocation to the RunnerDeployment through the use of [GitHub labels](#runner-labels).
|
|
||||||
|
|
||||||
**Drawbacks of this metric**
|
|
||||||
1. Repositories must be named within the scaling metric, maintaining a list of repositories may not be viable in larger environments or self-serve environments.
|
|
||||||
2. May not scale quick enough for some users needs. This metric is pull based and so the queue depth is polled as configured by the sync period, as a result scaling performance is bound by this sync period meaning there is a lag to scaling activity.
|
|
||||||
3. Relatively large amounts of API requests required to maintain this metric, you may run in API rate limit issues depending on the size of your environment and how aggressive your sync period configuration is
|
|
||||||
4. The GitHub API doesn't provide a way to filter workflow jobs to just those targeting self-hosted runners. If your environment's workflows target both self-hosted and GitHub hosted runners then the queue depth this metric scales against isn't a true 1:1 mapping of queue depth to required runner count. As a result of this, this metric may scale too aggressively for your actual self-hosted runner count needs.
|
|
||||||
|
|
||||||
|
|
||||||
Example `RunnerDeployment` backed by a `HorizontalRunnerAutoscaler`:
|
|
||||||
|
|
||||||
**_Important!!! We no longer include the attribute `replicas` in our `RunnerDeployment` if we are configuring autoscaling!_**
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: actions.summerwind.dev/v1alpha1
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
@@ -413,7 +385,81 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
template:
|
template:
|
||||||
spec:
|
spec:
|
||||||
repository: actions-runner-controller/actions-runner-controller
|
repository: example/myrepo
|
||||||
|
---
|
||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: HorizontalRunnerAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: example-runner-deployment-autoscaler
|
||||||
|
spec:
|
||||||
|
# Runners in the targeted RunnerDeployment won't be scaled down
|
||||||
|
# for 5 minutes instead of the default 10 minutes now
|
||||||
|
scaleDownDelaySecondsAfterScaleOut: 300
|
||||||
|
scaleTargetRef:
|
||||||
|
name: example-runner-deployment
|
||||||
|
# Uncomment the below in case the target is not RunnerDeployment but RunnerSet
|
||||||
|
#kind: RunnerSet
|
||||||
|
minReplicas: 1
|
||||||
|
maxReplicas: 5
|
||||||
|
metrics:
|
||||||
|
- type: PercentageRunnersBusy
|
||||||
|
scaleUpThreshold: '0.75'
|
||||||
|
scaleDownThreshold: '0.25'
|
||||||
|
scaleUpFactor: '2'
|
||||||
|
scaleDownFactor: '0.5'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Pull Driven Scaling
|
||||||
|
|
||||||
|
> To configure webhook driven scaling see the [Webhook Driven Scaling](#webhook-driven-scaling) section
|
||||||
|
|
||||||
|
The pull based metrics are configured in the `metrics` attribute of a HRA (see snippet below). The period between polls is defined by the controller's `--sync-period` flag. If this flag isn't provided then the controller defaults to a sync period of 10 minutes. The default value is set to 10 minutes to prevent default deployments rate limiting themselves from the GitHub API, you will most likely want to adjust this.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: HorizontalRunnerAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: example-runner-deployment-autoscaler
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
# Your RunnerDeployment Here
|
||||||
|
name: example-runner-deployment
|
||||||
|
# Uncomment the below in case the target is not RunnerDeployment but RunnerSet
|
||||||
|
#kind: RunnerSet
|
||||||
|
minReplicas: 1
|
||||||
|
maxReplicas: 5
|
||||||
|
# Your chosen scaling metrics here
|
||||||
|
metrics: []
|
||||||
|
```
|
||||||
|
|
||||||
|
**Metric Options:**
|
||||||
|
|
||||||
|
**TotalNumberOfQueuedAndInProgressWorkflowRuns**
|
||||||
|
|
||||||
|
The `TotalNumberOfQueuedAndInProgressWorkflowRuns` metric polls GitHub for all pending workflow runs against a given set of repositories. The metric will scale the runner count up to the total number of pending jobs at the sync time up to the `maxReplicas` configuration.
|
||||||
|
|
||||||
|
**Benefits of this metric**
|
||||||
|
1. Supports named repositories allowing you to restrict the runner to a specified set of repositories server-side.
|
||||||
|
2. Scales the runner count based on the depth of the job queue meaning a more 1:1 scaling of runners to queued jobs (caveat, see drawback #4)
|
||||||
|
3. Like all scaling metrics, you can manage workflow allocation to the RunnerDeployment through the use of [GitHub labels](#runner-labels).
|
||||||
|
|
||||||
|
**Drawbacks of this metric**
|
||||||
|
1. A list of repositories must be included within the scaling metric. Maintaining a list of repositories may not be viable in larger environments or self-serve environments.
|
||||||
|
2. May not scale quick enough for some users needs. This metric is pull based and so the queue depth is polled as configured by the sync period, as a result scaling performance is bound by this sync period meaning there is a lag to scaling activity.
|
||||||
|
3. Relatively large amounts of API requests required to maintain this metric, you may run in API rate limit issues depending on the size of your environment and how aggressive your sync period configuration is.
|
||||||
|
4. The GitHub API doesn't provide a way to filter workflow jobs to just those targeting self-hosted runners. If your environment's workflows target both self-hosted and GitHub hosted runners then the queue depth this metric scales against isn't a true 1:1 mapping of queue depth to required runner count. As a result of this, this metric may scale too aggressively for your actual self-hosted runner count needs.
|
||||||
|
|
||||||
|
Example `RunnerDeployment` backed by a `HorizontalRunnerAutoscaler`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: RunnerDeployment
|
||||||
|
metadata:
|
||||||
|
name: example-runner-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
repository: example/myrepo
|
||||||
---
|
---
|
||||||
apiVersion: actions.summerwind.dev/v1alpha1
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
kind: HorizontalRunnerAutoscaler
|
kind: HorizontalRunnerAutoscaler
|
||||||
@@ -422,30 +468,22 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
name: example-runner-deployment
|
name: example-runner-deployment
|
||||||
|
# Uncomment the below in case the target is not RunnerDeployment but RunnerSet
|
||||||
|
#kind: RunnerSet
|
||||||
minReplicas: 1
|
minReplicas: 1
|
||||||
maxReplicas: 3
|
maxReplicas: 5
|
||||||
metrics:
|
metrics:
|
||||||
- type: TotalNumberOfQueuedAndInProgressWorkflowRuns
|
- type: TotalNumberOfQueuedAndInProgressWorkflowRuns
|
||||||
repositoryNames:
|
repositoryNames:
|
||||||
- actions-runner-controller/actions-runner-controller
|
- example/myrepo
|
||||||
```
|
|
||||||
|
|
||||||
Additionally, the `HorizontalRunnerAutoscaler` also has an anti-flapping option that prevents periodic loop of scaling up and down.
|
|
||||||
By default, it doesn't scale down until the grace period of 10 minutes passes after a scale up. The grace period can be configured however by adding the setting `scaleDownDelaySecondsAfterScaleOut` in the `HorizontalRunnerAutoscaler` `spec`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
spec:
|
|
||||||
scaleDownDelaySecondsAfterScaleOut: 60
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**PercentageRunnersBusy**
|
**PercentageRunnersBusy**
|
||||||
|
|
||||||
The `HorizontalRunnerAutoscaler` will poll GitHub based on the configuration sync period for the number of busy runners which live in the RunnerDeployment's namespace and scale based on the settings
|
The `HorizontalRunnerAutoscaler` will poll GitHub for the number of runners in the `busy` state which live in the RunnerDeployment's namespace, it will then scale depending on how you have configured the scale factors.
|
||||||
|
|
||||||
**Kustomize Config :** The period can be customised in the `config/default/manager_auth_proxy_patch.yaml` patch<br />
|
|
||||||
|
|
||||||
**Benefits of this metric**
|
**Benefits of this metric**
|
||||||
1. Supports named repositories server side the same as the `TotalNumberOfQueuedAndInProgressWorkflowRuns` metric [#313](https://github.com/actions-runner-controller/actions-runner-controller/pull/313)
|
1. Supports named repositories server-side the same as the `TotalNumberOfQueuedAndInProgressWorkflowRuns` metric [#313](https://github.com/actions-runner-controller/actions-runner-controller/pull/313)
|
||||||
2. Supports GitHub organization wide scaling without maintaining an explicit list of repositories, this is especially useful for those that are working at a larger scale. [#223](https://github.com/actions-runner-controller/actions-runner-controller/pull/223)
|
2. Supports GitHub organization wide scaling without maintaining an explicit list of repositories, this is especially useful for those that are working at a larger scale. [#223](https://github.com/actions-runner-controller/actions-runner-controller/pull/223)
|
||||||
3. Like all scaling metrics, you can manage workflow allocation to the RunnerDeployment through the use of [GitHub labels](#runner-labels)
|
3. Like all scaling metrics, you can manage workflow allocation to the RunnerDeployment through the use of [GitHub labels](#runner-labels)
|
||||||
4. Supports scaling desired runner count on both a percentage increase / decrease basis as well as on a fixed increase / decrease count basis [#223](https://github.com/actions-runner-controller/actions-runner-controller/pull/223) [#315](https://github.com/actions-runner-controller/actions-runner-controller/pull/315)
|
4. Supports scaling desired runner count on both a percentage increase / decrease basis as well as on a fixed increase / decrease count basis [#223](https://github.com/actions-runner-controller/actions-runner-controller/pull/223) [#315](https://github.com/actions-runner-controller/actions-runner-controller/pull/315)
|
||||||
@@ -454,12 +492,8 @@ The `HorizontalRunnerAutoscaler` will poll GitHub based on the configuration syn
|
|||||||
1. May not scale quick enough for some users needs. This metric is pull based and so the number of busy runners are polled as configured by the sync period, as a result scaling performance is bound by this sync period meaning there is a lag to scaling activity.
|
1. May not scale quick enough for some users needs. This metric is pull based and so the number of busy runners are polled as configured by the sync period, as a result scaling performance is bound by this sync period meaning there is a lag to scaling activity.
|
||||||
2. We are scaling up and down based on indicative information rather than a count of the actual number of queued jobs and so the desired runner count is likely to under provision new runners or overprovision them relative to actual job queue depth, this may or may not be a problem for you.
|
2. We are scaling up and down based on indicative information rather than a count of the actual number of queued jobs and so the desired runner count is likely to under provision new runners or overprovision them relative to actual job queue depth, this may or may not be a problem for you.
|
||||||
|
|
||||||
|
|
||||||
Examples of each scaling type implemented with a `RunnerDeployment` backed by a `HorizontalRunnerAutoscaler`:
|
Examples of each scaling type implemented with a `RunnerDeployment` backed by a `HorizontalRunnerAutoscaler`:
|
||||||
|
|
||||||
|
|
||||||
**_Important!!! We no longer include the attribute `replicas` in our `RunnerDeployment` if we are configuring autoscaling!_**
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
---
|
---
|
||||||
apiVersion: actions.summerwind.dev/v1alpha1
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
@@ -469,8 +503,10 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
name: example-runner-deployment
|
name: example-runner-deployment
|
||||||
|
# Uncomment the below in case the target is not RunnerDeployment but RunnerSet
|
||||||
|
#kind: RunnerSet
|
||||||
minReplicas: 1
|
minReplicas: 1
|
||||||
maxReplicas: 3
|
maxReplicas: 5
|
||||||
metrics:
|
metrics:
|
||||||
- type: PercentageRunnersBusy
|
- type: PercentageRunnersBusy
|
||||||
scaleUpThreshold: '0.75' # The percentage of busy runners at which the number of desired runners are re-evaluated to scale up
|
scaleUpThreshold: '0.75' # The percentage of busy runners at which the number of desired runners are re-evaluated to scale up
|
||||||
@@ -488,8 +524,10 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
name: example-runner-deployment
|
name: example-runner-deployment
|
||||||
|
# Uncomment the below in case the target is not RunnerDeployment but RunnerSet
|
||||||
|
#kind: RunnerSet
|
||||||
minReplicas: 1
|
minReplicas: 1
|
||||||
maxReplicas: 3
|
maxReplicas: 5
|
||||||
metrics:
|
metrics:
|
||||||
- type: PercentageRunnersBusy
|
- type: PercentageRunnersBusy
|
||||||
scaleUpThreshold: '0.75' # The percentage of busy runners at which the number of desired runners are re-evaluated to scale up
|
scaleUpThreshold: '0.75' # The percentage of busy runners at which the number of desired runners are re-evaluated to scale up
|
||||||
@@ -498,30 +536,25 @@ spec:
|
|||||||
scaleDownAdjustment: 1 # The scale down runner count subtracted from the desired count
|
scaleDownAdjustment: 1 # The scale down runner count subtracted from the desired count
|
||||||
```
|
```
|
||||||
|
|
||||||
Like the previous metric, the scale down factor respects the anti-flapping configuration is applied to the `HorizontalRunnerAutoscaler` as mentioned previously:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
spec:
|
|
||||||
scaleDownDelaySecondsAfterScaleOut: 60
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Webhook Driven Scaling
|
#### Webhook Driven Scaling
|
||||||
|
|
||||||
`actions-runner-controller` has an optional Webhook server that receives GitHub Webhook events and scale
|
> To configure pull driven scaling see the [Pull Driven Scaling](#pull-driven-scaling) section
|
||||||
|
|
||||||
|
Webhooks are processed by a seperate webhook server. The webhook server receives GitHub Webhook events and scales
|
||||||
[`RunnerDeployments`](#runnerdeployments) by updating corresponding [`HorizontalRunnerAutoscalers`](#autoscaling).
|
[`RunnerDeployments`](#runnerdeployments) by updating corresponding [`HorizontalRunnerAutoscalers`](#autoscaling).
|
||||||
|
|
||||||
Today, the Webhook server can be configured to respond GitHub `check_run`, `workflow_job`, `pull_request` and `push` events
|
Today, the Webhook server can be configured to respond GitHub `check_run`, `workflow_job`, `pull_request` and `push` events
|
||||||
by scaling up the matching `HorizontalRunnerAutoscaler` by N replica(s), where `N` is configurable within
|
by scaling up the matching `HorizontalRunnerAutoscaler` by N replica(s), where `N` is configurable within `HorizontalRunnerAutoscaler`'s `spec:`.
|
||||||
`HorizontalRunnerAutoscaler's` `Spec`.
|
|
||||||
|
|
||||||
More concretely, you can configure the targeted GitHub event types and the `N` in
|
More concretely, you can configure the targeted GitHub event types and the `N` in `scaleUpTriggers`:
|
||||||
`scaleUpTriggers`:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
kind: HorizontalRunnerAutoscaler
|
kind: HorizontalRunnerAutoscaler
|
||||||
spec:
|
spec:
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
name: myrunners
|
name: example-runners
|
||||||
|
# Uncomment the below in case the target is not RunnerDeployment but RunnerSet
|
||||||
|
#kind: RunnerSet
|
||||||
scaleUpTriggers:
|
scaleUpTriggers:
|
||||||
- githubEvent:
|
- githubEvent:
|
||||||
checkRun:
|
checkRun:
|
||||||
@@ -531,21 +564,19 @@ spec:
|
|||||||
duration: "5m"
|
duration: "5m"
|
||||||
```
|
```
|
||||||
|
|
||||||
With the above example, the webhook server scales `myrunners` by `1` replica for 5 minutes on each `check_run` event
|
With the above example, the webhook server scales `example-runners` by `1` replica for 5 minutes on each `check_run` event with the type of `created` and the status of `queued` received.
|
||||||
with the type of `created` and the status of `queued` received.
|
|
||||||
|
|
||||||
The primary benefit of autoscaling on Webhook compared to the standard autoscaling is that it is far quicker as it allows you to
|
Of note is the `HRA.spec.scaleUpTriggers[].duration` attribute. This attribute is used to calculate if the replica number added via the trigger is expired or not. On each reconcilation loop, the controller sums up all the non-expiring replica numbers from previous scale up triggers. It then compares the summed desired replica number against the current replica number. If the summed desired replica number > the current number then it means the replica count needs to scale up.
|
||||||
immediately add "resource slack" for future GitHub Actions job runs.
|
|
||||||
|
|
||||||
In contrast, the standard autoscaling requires you to wait next sync period to add
|
As mentioned previously, the `scaleDownDelaySecondsAfterScaleOut` property has the final say still. If the latest scale-up time + the anti-flapping duration is later than the current time, it doesn’t immediately scale up and instead retries the calculation again later to see if it needs to scale yet.
|
||||||
insufficient runners. You can definitely shorten the sync period to make the standard autoscaling more responsive.
|
|
||||||
But doing so eventually results in the controller not being functional due to it being rated limited by the GitHub API.
|
---
|
||||||
|
|
||||||
|
The primary benefit of autoscaling on Webhook compared to the pull driven scaling is that it is far quicker as it allows you to immediately add runners resource rather than waiting for the next sync period.
|
||||||
|
|
||||||
> You can learn the implementation details in [#282](https://github.com/actions-runner-controller/actions-runner-controller/pull/282)
|
> You can learn the implementation details in [#282](https://github.com/actions-runner-controller/actions-runner-controller/pull/282)
|
||||||
|
|
||||||
To enable this feature, you firstly need to install the webhook server.
|
To enable this feature, you firstly need to install the webhook server, currently, only our Helm chart has the ability install it:
|
||||||
|
|
||||||
Currently, only our Helm chart has the ability install it:
|
|
||||||
_[see the values documentation for all configuration options](https://github.com/actions-runner-controller/actions-runner-controller/blob/master/charts/actions-runner-controller/README.md)_
|
_[see the values documentation for all configuration options](https://github.com/actions-runner-controller/actions-runner-controller/blob/master/charts/actions-runner-controller/README.md)_
|
||||||
|
|
||||||
```console
|
```console
|
||||||
@@ -565,39 +596,45 @@ by learning the following configuration examples.
|
|||||||
- [Example 1: Scale on each `workflow_job` event](#example-1-scale-on-each-workflow_job-event)
|
- [Example 1: Scale on each `workflow_job` event](#example-1-scale-on-each-workflow_job-event)
|
||||||
- [Example 2: Scale up on each `check_run` event](#example-2-scale-up-on-each-check_run-event)
|
- [Example 2: Scale up on each `check_run` event](#example-2-scale-up-on-each-check_run-event)
|
||||||
- [Example 3: Scale on each `pull_request` event against a given set of branches](#example-3-scale-on-each-pull_request-event-against-a-given-set-of-branches)
|
- [Example 3: Scale on each `pull_request` event against a given set of branches](#example-3-scale-on-each-pull_request-event-against-a-given-set-of-branches)
|
||||||
|
- [Example 4: Scale on each `push` event](#example-4-scale-on-each-push-event)
|
||||||
|
|
||||||
|
**Note:** All these examples should have **minReplicas** & **maxReplicas** as mandatory parameter even for webhook driven scaling.
|
||||||
|
|
||||||
##### Example 1: Scale on each `workflow_job` event
|
##### Example 1: Scale on each `workflow_job` event
|
||||||
|
|
||||||
> This feature requires controller version => [v0.20.0](https://github.com/actions-runner-controller/actions-runner-controller/releases/tag/v0.20.0)
|
> This feature requires controller version => [v0.20.0](https://github.com/actions-runner-controller/actions-runner-controller/releases/tag/v0.20.0)
|
||||||
|
|
||||||
|
_Note: GitHub does not include the runner group information of a repository in the payload of `workflow_job` event in the initial `queued` event. The runner group information is only include for `workflow_job` events when the job has already been allocated to a runner (events with a status of `in_progress` or `completed`). Please do raise feature requests against [GitHub](https://support.github.com/tickets/personal/0) for this information to be included in the initial `queued` event if this would improve autoscaling runners for you._
|
||||||
|
|
||||||
The most flexible webhook GitHub offers is the `workflow_job` webhook, it includes the `runs-on` information in the payload allowing scaling based on runner labels.
|
The most flexible webhook GitHub offers is the `workflow_job` webhook, it includes the `runs-on` information in the payload allowing scaling based on runner labels.
|
||||||
|
|
||||||
This webhook should cover most people's needs, please experiment with this webhook before considering the others.
|
This webhook should cover most people's needs, please experiment with this webhook first before considering the others.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
kind: RunnerDeployment
|
kind: RunnerDeployment
|
||||||
metadata:
|
metadata:
|
||||||
name: myrunners
|
name: example-runners
|
||||||
spec:
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
repository: example/myrepo
|
repository: example/myrepo
|
||||||
---
|
---
|
||||||
kind: HorizontalRunnerAutoscaler
|
kind: HorizontalRunnerAutoscaler
|
||||||
spec:
|
spec:
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
name: myrunners
|
name: example-runners
|
||||||
|
# Uncomment the below in case the target is not RunnerDeployment but RunnerSet
|
||||||
|
#kind: RunnerSet
|
||||||
scaleUpTriggers:
|
scaleUpTriggers:
|
||||||
- githubEvent: {}
|
- githubEvent: {}
|
||||||
duration: "30m"
|
duration: "30m"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This webhook requires you to explicitly set the labels in the RunnerDeployment / RunnerSet if you are using them in your workflow to match the agents (field `runs-on`). Only `self-hosted` will be considered as included by default.
|
||||||
|
|
||||||
You can configure your GitHub webhook settings to only include `Workflows Job` events, so that it sends us three kinds of `workflow_job` events per a job run.
|
You can configure your GitHub webhook settings to only include `Workflows Job` events, so that it sends us three kinds of `workflow_job` events per a job run.
|
||||||
|
|
||||||
Each kind has a `status` of `queued`, `in_progress` and `completed`.
|
Each kind has a `status` of `queued`, `in_progress` and `completed`. With the above configuration, `actions-runner-controller` adds one runner for a `workflow_job` event whose `status` is `queued`. Similarly, it removes one runner for a `workflow_job` event whose `status` is `completed`. The cavaet to this to remember is that this the scale down is within the bounds of your `scaleDownDelaySecondsAfterScaleOut` configuration, if this time hasn't past the scale down will be defered.
|
||||||
With the above configuration, `actions-runner-controller` adds one runner for a `workflow_job` event whose `status` is `queued`. Similarly, it removes one runner for a `workflow_job` event whose `status` is `completed`.
|
|
||||||
|
|
||||||
Beware that a scale-down after a scale-up is deferred until `scaleDownDelaySecondsAfterScaleOut` elapses. Let's say you had configured `scaleDownDelaySecondsAfterScaleOut` of 60 seconds, 2 consequtive workflow jobs will result in immediately adding 2 runners. The 2 runners are removed only after 60 seconds. This basically gives you 60 seconds of a "grace period" that makes it possible for self-hosted runners to immediately run additional workflow jobs enqueued in that 60 seconds.
|
|
||||||
|
|
||||||
You must not include `spec.metrics` like `PercentageRunnersBusy` when using this feature, as it is unnecessary. That is, if you've configured the webhook for `workflow_job`, it should be enough for all your scale-out needs.
|
|
||||||
|
|
||||||
##### Example 2: Scale up on each `check_run` event
|
##### Example 2: Scale up on each `check_run` event
|
||||||
|
|
||||||
@@ -608,14 +645,18 @@ To scale up replicas of the runners for `example/myrepo` by 1 for 5 minutes on e
|
|||||||
```yaml
|
```yaml
|
||||||
kind: RunnerDeployment
|
kind: RunnerDeployment
|
||||||
metadata:
|
metadata:
|
||||||
name: myrunners
|
name: example-runners
|
||||||
spec:
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
repository: example/myrepo
|
repository: example/myrepo
|
||||||
---
|
---
|
||||||
kind: HorizontalRunnerAutoscaler
|
kind: HorizontalRunnerAutoscaler
|
||||||
spec:
|
spec:
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
name: myrunners
|
name: example-runners
|
||||||
|
# Uncomment the below in case the target is not RunnerDeployment but RunnerSet
|
||||||
|
#kind: RunnerSet
|
||||||
scaleUpTriggers:
|
scaleUpTriggers:
|
||||||
- githubEvent:
|
- githubEvent:
|
||||||
checkRun:
|
checkRun:
|
||||||
@@ -630,14 +671,18 @@ To scale up replicas of the runners for `myorg` organization by 1 for 5 minutes
|
|||||||
```yaml
|
```yaml
|
||||||
kind: RunnerDeployment
|
kind: RunnerDeployment
|
||||||
metadata:
|
metadata:
|
||||||
name: myrunners
|
name: example-runners
|
||||||
spec:
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
organization: myorg
|
organization: myorg
|
||||||
---
|
---
|
||||||
kind: HorizontalRunnerAutoscaler
|
kind: HorizontalRunnerAutoscaler
|
||||||
spec:
|
spec:
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
name: myrunners
|
name: example-runners
|
||||||
|
# Uncomment the below in case the target is not RunnerDeployment but RunnerSet
|
||||||
|
#kind: RunnerSet
|
||||||
scaleUpTriggers:
|
scaleUpTriggers:
|
||||||
- githubEvent:
|
- githubEvent:
|
||||||
checkRun:
|
checkRun:
|
||||||
@@ -656,14 +701,18 @@ To scale up replicas of the runners for `example/myrepo` by 1 for 5 minutes on e
|
|||||||
```yaml
|
```yaml
|
||||||
kind: RunnerDeployment
|
kind: RunnerDeployment
|
||||||
metadata:
|
metadata:
|
||||||
name: myrunners
|
name: example-runners
|
||||||
spec:
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
repository: example/myrepo
|
repository: example/myrepo
|
||||||
---
|
---
|
||||||
kind: HorizontalRunnerAutoscaler
|
kind: HorizontalRunnerAutoscaler
|
||||||
spec:
|
spec:
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
name: myrunners
|
name: example-runners
|
||||||
|
# Uncomment the below in case the target is not RunnerDeployment but RunnerSet
|
||||||
|
#kind: RunnerSet
|
||||||
scaleUpTriggers:
|
scaleUpTriggers:
|
||||||
- githubEvent:
|
- githubEvent:
|
||||||
pullRequest:
|
pullRequest:
|
||||||
@@ -675,59 +724,59 @@ spec:
|
|||||||
|
|
||||||
See ["activity types"](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request) for the list of valid values for `scaleUpTriggers[].githubEvent.pullRequest.types`.
|
See ["activity types"](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request) for the list of valid values for `scaleUpTriggers[].githubEvent.pullRequest.types`.
|
||||||
|
|
||||||
|
###### Example 4: Scale on each push event
|
||||||
|
|
||||||
|
To scale up replicas of the runners for `example/myrepo` by 1 for 5 minutes on each `push` write manifests like the below:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
kind: RunnerDeployment
|
||||||
|
metadata:
|
||||||
|
name: example-runners
|
||||||
|
spec:
|
||||||
|
repository: example/myrepo
|
||||||
|
---
|
||||||
|
kind: HorizontalRunnerAutoscaler
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
name: example-runners
|
||||||
|
# Uncomment the below in case the target is not RunnerDeployment but RunnerSet
|
||||||
|
#kind: RunnerSet
|
||||||
|
scaleUpTriggers:
|
||||||
|
- githubEvent:
|
||||||
|
push:
|
||||||
|
amount: 1
|
||||||
|
duration: "5m"
|
||||||
|
```
|
||||||
|
|
||||||
#### Autoscaling to/from 0
|
#### Autoscaling to/from 0
|
||||||
|
|
||||||
> This feature requires controller version => [v0.19.0](https://github.com/actions-runner-controller/actions-runner-controller/releases/tag/v0.19.0)
|
> This feature requires controller version => [v0.19.0](https://github.com/actions-runner-controller/actions-runner-controller/releases/tag/v0.19.0)
|
||||||
|
|
||||||
Previously, we've discussed about [how to scale a RunnerDeployment to/from 0](#note-on-scaling-tofrom-0)
|
The regular `RunnerDeployment` `replicas:` attribute as well as the `HorizontalRunnerAutoscaler` `minReplicas:` attribute supports being set to 0.
|
||||||
|
|
||||||
To scale from 0 whilst still being able to provision runners as jobs are queued we must use the `HorizontalRunnerAutoscaler` with only certain metric configurations, only the below configurations support scaling from 0 whilst also being able to provision runners as jobs are queued:
|
The main use case for scaling from 0 is with the `HorizontalRunnerAutoscaler` kind. To scale from 0 whilst still being able to provision runners as jobs are queued we must use the `HorizontalRunnerAutoscaler` with only certain scaling configurations, only the below configurations support scaling from 0 whilst also being able to provision runners as jobs are queued:
|
||||||
|
|
||||||
- `TotalNumberOfQueuedAndInProgressWorkflowRuns`
|
- `TotalNumberOfQueuedAndInProgressWorkflowRuns`
|
||||||
- `PercentageRunnersBusy` + `TotalNumberOfQueuedAndInProgressWorkflowRuns`
|
- `PercentageRunnersBusy` + `TotalNumberOfQueuedAndInProgressWorkflowRuns`
|
||||||
- `PercentageRunnersBusy` + Webhook-based autoscaling
|
- `PercentageRunnersBusy` + Webhook-based autoscaling
|
||||||
- Webhook-based autoscaling only
|
- Webhook-based autoscaling only
|
||||||
|
|
||||||
This is due to that `PercentageRunnersBusy`, by its definition, needs one or more GitHub runners that can become `busy` to be able to scale. If there isn't a runner to pick up a job and enter a `busy` state then the controller will never know to provision a runner to begin with as this metric is no knowledge of the jobs queued and is relying using the number of busy runners as a means for calculating the desired replica count.
|
`PercentageRunnersBusy` can't be used alone as, by its definition, it needs one or more GitHub runners to become `busy` to be able to scale. If there isn't a runner to pick up a job and enter a `busy` state then the controller will never know to provision a runner to begin with as this metric has no knowledge of the job queue and is relying using the number of busy runners as a means for calculating the desired replica count.
|
||||||
|
|
||||||
If a HorizontalRunnerAutoscaler is configured with a secondary metric of `TotalNumberOfQueuedAndInProgressWorkflowRuns` then be aware that the controller will check the primary metric of `PercentageRunnersBusy` first and will only use the secondary metric to calculate the desired replica count if the primary metric returns 0 desired replicas.
|
If a HorizontalRunnerAutoscaler is configured with a secondary metric of `TotalNumberOfQueuedAndInProgressWorkflowRuns` then be aware that the controller will check the primary metric of `PercentageRunnersBusy` first and will only use the secondary metric to calculate the desired replica count if the primary metric returns 0 desired replicas.
|
||||||
|
|
||||||
A correctly configured `TotalNumberOfQueuedAndInProgressWorkflowRuns` can return non-zero desired replicas even when there are no runners other than [registration-only runners](#note-on-scaling-tofrom-0), hence the `PercentageRunnersBusy` + `TotalNumberOfQueuedAndInProgressWorkflowRuns` configuration makes scaling from zero possible.
|
Webhook-based autoscaling is the best option as it is relatively easy to configure and also it can scale scale quickly.
|
||||||
|
|
||||||
Similarly, Webhook-based autoscaling works regardless of there are active runners, hence `PercentageRunnersBusy` + Webhook-based autoscaling configuration makes scaling from zero, too.
|
|
||||||
|
|
||||||
#### Scheduled Overrides
|
#### Scheduled Overrides
|
||||||
|
|
||||||
> This feature requires controller version => [v0.19.0](https://github.com/actions-runner-controller/actions-runner-controller/releases/tag/v0.19.0)
|
> This feature requires controller version => [v0.19.0](https://github.com/actions-runner-controller/actions-runner-controller/releases/tag/v0.19.0)
|
||||||
|
|
||||||
`Scheduled Overrides` allows you to configure HorizontalRunnerAutoscaler so that its Spec gets updated only during a certain period of time. This feature is usually used for following scenarios:
|
`Scheduled Overrides` allows you to configure `HorizontalRunnerAutoscaler` so that its `spec:` gets updated only during a certain period of time. This feature is usually used for following scenarios:
|
||||||
|
|
||||||
- You want to reduce your infrastructure costs by scaling your Kubernetes nodes down outside of business hours
|
- You want to reduce your infrastructure costs by scaling your Kubernetes nodes down outside a given period
|
||||||
- You want to scale for scheduled spikes in workloads
|
- You want to scale for scheduled spikes in workloads
|
||||||
|
|
||||||
For the first scenario, you might consider configuration like the below:
|
The most basic usage of this feature is to set a non-repeating override:
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: actions.summerwind.dev/v1alpha1
|
|
||||||
kind: HorizontalRunnerAutoscaler
|
|
||||||
metadata:
|
|
||||||
name: example-runner-deployment-autoscaler
|
|
||||||
spec:
|
|
||||||
scaleTargetRef:
|
|
||||||
name: example-runner-deployment
|
|
||||||
scheduledOverrides:
|
|
||||||
# Override minReplicas to 0 only between 0am sat to 0am mon
|
|
||||||
- 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: 1
|
|
||||||
```
|
|
||||||
|
|
||||||
For the second scenario, you might consider something like the below:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: actions.summerwind.dev/v1alpha1
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
@@ -737,6 +786,8 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
name: example-runner-deployment
|
name: example-runner-deployment
|
||||||
|
# Uncomment the below in case the target is not RunnerDeployment but RunnerSet
|
||||||
|
#kind: RunnerSet
|
||||||
scheduledOverrides:
|
scheduledOverrides:
|
||||||
# Override minReplicas to 100 only between 2021-06-01T00:00:00+09:00 and 2021-06-03T00:00:00+09:00
|
# Override minReplicas to 100 only between 2021-06-01T00:00:00+09:00 and 2021-06-03T00:00:00+09:00
|
||||||
- startTime: "2021-06-01T00:00:00+09:00"
|
- startTime: "2021-06-01T00:00:00+09:00"
|
||||||
@@ -745,10 +796,33 @@ spec:
|
|||||||
minReplicas: 1
|
minReplicas: 1
|
||||||
```
|
```
|
||||||
|
|
||||||
The most basic usage of this feature is actually the second scenario mentioned above.
|
|
||||||
A scheduled override without `recurrenceRule` is considered a one-off override, that is active between `startTime` and `endTime`. In the second scenario, it overrides `minReplicas` to `100` only between `2021-06-01T00:00:00+09:00` and `2021-06-03T00:00:00+09:00`.
|
A scheduled override without `recurrenceRule` is considered a one-off override, that is active between `startTime` and `endTime`. In the second scenario, it overrides `minReplicas` to `100` only between `2021-06-01T00:00:00+09:00` and `2021-06-03T00:00:00+09:00`.
|
||||||
|
|
||||||
A scheduled override with `recurrenceRule` is considered a recurring override. A recurring override is initially active between `startTime` and `endTime`, and then it repeatedly get activated after a certain period of time denoted by `frequency`.
|
A more advanced configuration is to include a `recurrenceRule` in the override:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: HorizontalRunnerAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: example-runner-deployment-autoscaler
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
name: example-runner-deployment
|
||||||
|
# Uncomment the below in case the target is not RunnerDeployment but RunnerSet
|
||||||
|
#kind: RunnerSet
|
||||||
|
scheduledOverrides:
|
||||||
|
# Override minReplicas to 0 only between 0am sat to 0am mon
|
||||||
|
- startTime: "2021-05-01T00:00:00+09:00"
|
||||||
|
endTime: "2021-05-03T00:00:00+09:00"
|
||||||
|
recurrenceRule:
|
||||||
|
frequency: Weekly
|
||||||
|
# Optional sunset datetime attribute
|
||||||
|
# untilTime: "2022-05-01T00:00:00+09:00"
|
||||||
|
minReplicas: 0
|
||||||
|
minReplicas: 1
|
||||||
|
```
|
||||||
|
|
||||||
|
A recurring override is initially active between `startTime` and `endTime`, and then it repeatedly get activated after a certain period of time denoted by `frequency`.
|
||||||
|
|
||||||
`frequecy` can take one of the following values:
|
`frequecy` can take one of the following values:
|
||||||
|
|
||||||
@@ -759,7 +833,7 @@ A scheduled override with `recurrenceRule` is considered a recurring override. A
|
|||||||
|
|
||||||
By default, a scheduled override repeats forever. If you want it to repeat until a specific point in time, define `untilTime`. The controller create the last recurrence of the override until the recurrence's `startTime` is equal or earlier than `untilTime`.
|
By default, a scheduled override repeats forever. If you want it to repeat until a specific point in time, define `untilTime`. The controller create the last recurrence of the override until the recurrence's `startTime` is equal or earlier than `untilTime`.
|
||||||
|
|
||||||
Do note that you have enough slack for `untilTime`, so that a delayed or offline `actions-runner-controller` is much less likely to miss the last recurrence. For example, you might want to set `untilTime` to `M` minutes after the last recurrence's `startTime`, so that `actions-runner-controller` being offline up to `M` minutes doesn't miss the last recurrence.
|
Do ensure that you have enough slack for `untilTime` so that a delayed or offline `actions-runner-controller` is much less likely to miss the last recurrence. For example, you might want to set `untilTime` to `M` minutes after the last recurrence's `startTime`, so that `actions-runner-controller` being offline up to `M` minutes doesn't miss the last recurrence.
|
||||||
|
|
||||||
**Combining Multiple Scheduled Overrides**:
|
**Combining Multiple Scheduled Overrides**:
|
||||||
|
|
||||||
@@ -767,6 +841,8 @@ In case you have a more complex scenarios, try writing two or more entries under
|
|||||||
|
|
||||||
The earlier entry is prioritized higher than later entries. So you usually define one-time overrides in the top of your list, then yearly, monthly, weekly, and lastly daily overrides.
|
The earlier entry is prioritized higher than later entries. So you usually define one-time overrides in the top of your list, then yearly, monthly, weekly, and lastly daily overrides.
|
||||||
|
|
||||||
|
A common use case for this may be to have 1 override to scale to 0 during the week outside of core business hours and another override to scale to 0 during all hours of the weekend.
|
||||||
|
|
||||||
### Runner with DinD
|
### Runner with DinD
|
||||||
|
|
||||||
When using default runner, runner pod starts up 2 containers: runner and DinD (Docker-in-Docker). This might create issues if there's `LimitRange` set to namespace.
|
When using default runner, runner pod starts up 2 containers: runner and DinD (Docker-in-Docker). This might create issues if there's `LimitRange` set to namespace.
|
||||||
@@ -823,6 +899,14 @@ spec:
|
|||||||
key: node-role.kubernetes.io/test
|
key: node-role.kubernetes.io/test
|
||||||
operator: Exists
|
operator: Exists
|
||||||
|
|
||||||
|
topologySpreadConstraints:
|
||||||
|
- maxSkew: 1
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
whenUnsatisfiable: ScheduleAnyway
|
||||||
|
labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
runner-deployment-name: actions-runner
|
||||||
|
|
||||||
repository: mumoshu/actions-runner-controller-ci
|
repository: mumoshu/actions-runner-controller-ci
|
||||||
# The default "summerwind/actions-runner" images are available at DockerHub:
|
# The default "summerwind/actions-runner" images are available at DockerHub:
|
||||||
# https://hub.docker.com/r/summerwind/actions-runner
|
# https://hub.docker.com/r/summerwind/actions-runner
|
||||||
@@ -866,6 +950,11 @@ spec:
|
|||||||
# false (default) = Docker support is provided by a sidecar container deployed in the runner pod.
|
# false (default) = Docker support is provided by a sidecar container deployed in the runner pod.
|
||||||
# true = No docker sidecar container is deployed in the runner pod but docker can be used within the runner container instead. The image summerwind/actions-runner-dind is used by default.
|
# true = No docker sidecar container is deployed in the runner pod but docker can be used within the runner container instead. The image summerwind/actions-runner-dind is used by default.
|
||||||
dockerdWithinRunnerContainer: true
|
dockerdWithinRunnerContainer: true
|
||||||
|
#Optional environement variables for docker container
|
||||||
|
# Valid only when dockerdWithinRunnerContainer=false
|
||||||
|
dockerEnv:
|
||||||
|
- name: HTTP_PROXY
|
||||||
|
value: http://example.com
|
||||||
# Docker sidecar container image tweaks examples below, only applicable if dockerdWithinRunnerContainer = false
|
# Docker sidecar container image tweaks examples below, only applicable if dockerdWithinRunnerContainer = false
|
||||||
dockerdContainerResources:
|
dockerdContainerResources:
|
||||||
limits:
|
limits:
|
||||||
@@ -982,6 +1071,46 @@ spec:
|
|||||||
group: NewGroup
|
group: NewGroup
|
||||||
```
|
```
|
||||||
|
|
||||||
|
GitHub supports custom visilibity in a Runner Group to make it available to a specific set of repositories only. By default if no GitHub
|
||||||
|
authentication is included in the GitHub webhook server it will be assumed that all runner groups to be usable in all repositories.
|
||||||
|
Supporting custom visibility requires to do a few GitHub API calls to find out what are the potential runner groups that are visible to
|
||||||
|
the webhook's repository, this may incur in increased API rate limiting when using github.com
|
||||||
|
|
||||||
|
This option will be enabled when proper GitHub authentication options (token, app or basic auth is provided) in the GitHub webhook server and `useRunnerGroupsVisibility` is set to true, e.g.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
githubWebhookServer:
|
||||||
|
enabled: false
|
||||||
|
replicaCount: 1
|
||||||
|
useRunnerGroupsVisibility: true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Runner Entrypoint Features
|
||||||
|
|
||||||
|
> Environment variable values must all be strings
|
||||||
|
|
||||||
|
The entrypoint script is aware of a few environment variables for configuring features:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: RunnerDeployment
|
||||||
|
metadata:
|
||||||
|
name: example-runnerdeployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
env:
|
||||||
|
# Issues a sleep command at the start of the entrypoint
|
||||||
|
- name: STARTUP_DELAY_IN_SECONDS
|
||||||
|
value: "2"
|
||||||
|
# Disables the wait for the docker daemon to be available check
|
||||||
|
- name: DISABLE_WAIT_FOR_DOCKER
|
||||||
|
value: "true"
|
||||||
|
# Disables automatic runner updates
|
||||||
|
- name: DISABLE_RUNNER_UPDATE
|
||||||
|
value: "true"
|
||||||
|
```
|
||||||
|
|
||||||
### Using IRSA (IAM Roles for Service Accounts) in EKS
|
### Using IRSA (IAM Roles for Service Accounts) in EKS
|
||||||
|
|
||||||
> This feature requires controller version => [v0.15.0](https://github.com/actions-runner-controller/actions-runner-controller/releases/tag/v0.15.0)
|
> This feature requires controller version => [v0.15.0](https://github.com/actions-runner-controller/actions-runner-controller/releases/tag/v0.15.0)
|
||||||
@@ -1007,17 +1136,6 @@ spec:
|
|||||||
fsGroup: 1000
|
fsGroup: 1000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Use with Istio
|
|
||||||
|
|
||||||
Istio 1.7.0 or greater has `holdApplicationUntilProxyStarts` added in https://github.com/istio/istio/pull/24737, which enables you to delay the `runner` container startup until the injected `istio-proxy` container finish starting. Try using it if you need to use Istio. Otherwise the runner is unlikely to work, because it fails to call any GitHub API to register itself due to `istio-proxy` being not up and running yet.
|
|
||||||
|
|
||||||
Note that there's no official Istio integration in actions-runner-controller. It should work, but it isn't covered by our acceptance test (a contribution to resolve this is welcomed). In addition to that, none of the actions-runner-controller maintainers use Istio daily. If you need more information, or have any issues using it, refer to the following links:
|
|
||||||
|
|
||||||
- https://github.com/actions-runner-controller/actions-runner-controller/issues/591
|
|
||||||
- https://github.com/actions-runner-controller/actions-runner-controller/pull/592
|
|
||||||
- https://github.com/istio/istio/issues/11130
|
|
||||||
|
|
||||||
### Stateful Runners
|
### Stateful Runners
|
||||||
|
|
||||||
> This feature requires controller version => [v0.20.0](https://github.com/actions-runner-controller/actions-runner-controller/releases/tag/v0.20.0)
|
> This feature requires controller version => [v0.20.0](https://github.com/actions-runner-controller/actions-runner-controller/releases/tag/v0.20.0)
|
||||||
@@ -1064,7 +1182,6 @@ kind: RunnerSet
|
|||||||
metadata:
|
metadata:
|
||||||
name: example
|
name: example
|
||||||
spec:
|
spec:
|
||||||
# NOTE: RunnerSet supports non-ephemeral runners only today
|
|
||||||
ephemeral: false
|
ephemeral: false
|
||||||
replicas: 2
|
replicas: 2
|
||||||
repository: mumoshu/actions-runner-controller-ci
|
repository: mumoshu/actions-runner-controller-ci
|
||||||
@@ -1109,10 +1226,9 @@ We envision that `RunnerSet` will eventually replace `RunnerDeployment`, as `Run
|
|||||||
|
|
||||||
**Limitations**
|
**Limitations**
|
||||||
|
|
||||||
A known down-side of `RunnerSet` compared to `RunnerDeployment` is that it is uanble to create [a registration-only pod on scaling-down to zero](https://github.com/actions-runner-controller/actions-runner-controller#note-on-scaling-tofrom-0). To workaround that, you need to create a `RunnerDeployment` with `spec.repliacs` set to `0` with `spec.repository`, `spec.organization`, or `spec.enterprise`, and `spec.labels` and `spec.groups` as same values as your `RunnerSet`, so that you can keep the registration-only runner regardless of the number of `RunnerSet`-managed runners.
|
* For autoscaling the `RunnerSet` kind only supports pull driven scaling or the `workflow_job` event for webhook driven scaling.
|
||||||
|
* For autoscaling the `RunnerSet` kind doesn't support the [registration-only runner](#autoscaling-tofrom-0), these are deprecated however and to be [removed](https://github.com/actions-runner-controller/actions-runner-controller/issues/859)
|
||||||
A known down-side of relying on `StatefulSet` is that it misses a support for `maxUnavailable`.
|
* A known down-side of relying on `StatefulSet` is that it misses a support for `maxUnavailable`. A `StatefulSet` basically works like `maxUnavailable: 1` in `Deployment`, which means that it can take down only one pod concurrently while doing a rolling-update of pods. Kubernetes 1.22 doesn't support customizing it yet so probably it takes more releases to arrive. See https://github.com/kubernetes/kubernetes/issues/68397 for more information.
|
||||||
A `StatefulSet` basically works like `maxUnavailable: 1` in `Deployment`, which means that it can take down only one pod concurrently while doing a rolling-update of pods. Kubernetes 1.22 doesn't support customizing it yet so probably it takes more releases to arrive. See https://github.com/kubernetes/kubernetes/issues/68397 for more information.
|
|
||||||
|
|
||||||
### Ephemeral Runners
|
### Ephemeral Runners
|
||||||
|
|
||||||
@@ -1120,19 +1236,9 @@ Both `RunnerDeployment` and `RunnerSet` has ability to configure `ephemeral: tru
|
|||||||
|
|
||||||
When it is configured, it passes a `--once` flag to every runner.
|
When it is configured, it passes a `--once` flag to every runner.
|
||||||
|
|
||||||
`--once` is an experimental `actions/runner` feature that instructs the runner to stop after the first job run. But it is a known race issue that may fetch a job even when it's being terminated. If a runner fetched a job while terminating, the job is very likely to fail because the terminating runner doesn't wait for the job to complete. This is tracked in #466.
|
`--once` is an experimental `actions/runner` feature that instructs the runner to stop after the first job run. It has a known race condition issue that means the runner may fetch a job even when it's being terminated. If a runner fetched a job while terminating, the job is very likely to fail because the terminating runner doesn't wait for the job to complete. This is tracked in issue [#466](https://github.com/actions-runner-controller/actions-runner-controller/issues/466).
|
||||||
|
|
||||||
> The below feature depends on an unreleased GitHub feature
|
Since the implementation of the `--once` flag GitHub have implemented the `--ephemeral` flag which has no known race conditions and is much more supported by GitHub, this is the prefered flag for ephemeral runners. To have your `RunnerDeployment` and `RunnerSet` kinds use this new flag instead of the `--once` flag set `RUNNER_FEATURE_FLAG_EPHEMERAL` to `"true"`. For example, a `RunnerSet` configured to use the new flag looks like:
|
||||||
|
|
||||||
GitHub seems to be adding an another flag called `--ephemeral` that is race-free. The pull request to add it to `actions/runner` can be found at https://github.com/actions/runner/pull/660.
|
|
||||||
|
|
||||||
`actions-runner-controller` has a feature flag backend by an environment variable to enable using `--ephemeral` instead of `--once`. The environment variable is `RUNNER_FEATURE_FLAG_EPHEMERAL`. You can se it to `true` on runner containers in your runner pods to enable the feature.
|
|
||||||
|
|
||||||
> At the time of writing this, you need to wait until GitHub rolls out the server-side feature for `--ephemeral`, AND you need to include your own `actions/runner` binary built from https://github.com/actions/runner/pull/660 into the runner container image to test this feature.
|
|
||||||
>
|
|
||||||
> Please see comments in [`runner/Dockerfile`](/runner/Dockerfile) for more information about how to build a custom image using your own `actions/runner` binary.
|
|
||||||
|
|
||||||
For example, a `RunnerSet` config with the flag enabled looks like:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
kind: RunnerSet
|
kind: RunnerSet
|
||||||
@@ -1153,9 +1259,9 @@ spec:
|
|||||||
value: "true"
|
value: "true"
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that once https://github.com/actions/runner/pull/660 becomes generally available on GitHub, you no longer need to build a custom runner image to use this feature. Just set `RUNNER_FEATURE_FLAG_EPHEMERAL` and it should use `--ephemeral`.
|
You should configure all your ephemeral runners to use the new flag unless you have a reason for needing to use the old flag.
|
||||||
|
|
||||||
In the future, `--once` might get removed in `actions/runner`. `actions-runner-controller` will make `--ephemeral` the default option for `ephemeral: true` runners until the legacy flag is removed.
|
Once able, `actions-runner-controller` will make `--ephemeral` the default option for `ephemeral: true` runners and potentially remove `--once` entirely. It is likely that in the future the `--once` flag will be officially deprecated by GitHub and subsquently removed in `actions/runner`.
|
||||||
|
|
||||||
### Software Installed in the Runner Image
|
### Software Installed in the Runner Image
|
||||||
|
|
||||||
@@ -1165,7 +1271,7 @@ The project supports being deployed on the various cloud Kubernetes platforms (e
|
|||||||
**Bundled Software**<br />
|
**Bundled Software**<br />
|
||||||
The GitHub hosted runners include a large amount of pre-installed software packages. GitHub maintain a list in README files at <https://github.com/actions/virtual-environments/tree/main/images/linux>
|
The GitHub hosted runners include a large amount of pre-installed software packages. GitHub maintain a list in README files at <https://github.com/actions/virtual-environments/tree/main/images/linux>
|
||||||
|
|
||||||
This solution maintains a few runner images with `latest` aligning with GitHub's Ubuntu version. Older images are maintained whilst GitHub also provides them as an option. These images do not contain all of the software installed on the GitHub runners. It contains the following subset of packages from the GitHub runners:
|
This solution maintains a few runner images with `latest` aligning with GitHub's Ubuntu version, these images do not contain all of the software installed on the GitHub runners. The images contain the following subset of packages from the GitHub runners:
|
||||||
|
|
||||||
- Basic CLI packages
|
- Basic CLI packages
|
||||||
- git
|
- git
|
||||||
@@ -1196,67 +1302,38 @@ spec:
|
|||||||
image: YOUR_CUSTOM_DOCKER_IMAGE
|
image: YOUR_CUSTOM_DOCKER_IMAGE
|
||||||
```
|
```
|
||||||
|
|
||||||
### Common Errors
|
### Using without cert-manager
|
||||||
|
|
||||||
#### invalid header field value
|
Assuming you are installing in the default namespace, ensure your certificate has SANs:
|
||||||
|
|
||||||
```json
|
* `webhook-service.actions-runner-system.svc`
|
||||||
2020-11-12T22:17:30.693Z ERROR controller-runtime.controller Reconciler error
|
* `webhook-service.actions-runner-system.svc.cluster.local`
|
||||||
{
|
|
||||||
"controller": "runner",
|
It is possible to use a self-signed certificate by following a guide like
|
||||||
"request": "actions-runner-system/runner-deployment-dk7q8-dk5c9",
|
[this one](https://mariadb.com/docs/security/encryption/in-transit/create-self-signed-certificates-keys-openssl/)
|
||||||
"error": "failed to create registration token: Post \"https://api.github.com/orgs/$YOUR_ORG_HERE/actions/runners/registration-token\": net/http: invalid header field value \"Bearer $YOUR_TOKEN_HERE\\n\" for key Authorization"
|
using `openssl`.
|
||||||
}
|
|
||||||
|
Install your certificate as a TLS secret:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ kubectl create secret tls webhook-server-cert \
|
||||||
|
-n actions-runner-system \
|
||||||
|
--cert=path/to/cert/file \
|
||||||
|
--key=path/to/key/file
|
||||||
```
|
```
|
||||||
|
|
||||||
**Solution**
|
Set the Helm chart values as follows:
|
||||||
|
|
||||||
Your base64'ed PAT token has a new line at the end, it needs to be created without a `\n` added, either:
|
```shell
|
||||||
* `echo -n $TOKEN | base64`
|
$ CA_BUNDLE=$(cat path/to/ca.pem | base64)
|
||||||
* Create the secret as described in the docs using the shell and documented flags
|
$ helm --upgrade install actions-runner-controller/actions-runner-controller \
|
||||||
|
certManagerEnabled=false \
|
||||||
#### Runner coming up before network available
|
admissionWebHooks.caBundle=${CA_BUNDLE}
|
||||||
|
|
||||||
If you're running your action runners on a service mesh like Istio, you might
|
|
||||||
have problems with runner configuration accompanied by logs like:
|
|
||||||
|
|
||||||
```
|
|
||||||
....
|
|
||||||
runner Starting Runner listener with startup type: service
|
|
||||||
runner Started listener process
|
|
||||||
runner An error occurred: Not configured
|
|
||||||
runner Runner listener exited with error code 2
|
|
||||||
runner Runner listener exit with retryable error, re-launch runner in 5 seconds.
|
|
||||||
....
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This is because the `istio-proxy` has not completed configuring itself when the
|
# Troubleshooting
|
||||||
configuration script tries to communicate with the network.
|
|
||||||
|
|
||||||
**Solution**<br />
|
See [troubleshooting guide](TROUBLESHOOTING.md) for solutions to various problems people have ran into consistently.
|
||||||
|
|
||||||
> Added originally to help users with older istio instances.
|
|
||||||
> Newer Istio instances can use Istio's `holdApplicationUntilProxyStarts` attribute ([istio/istio#11130](https://github.com/istio/istio/issues/11130)) to avoid having to delay starting up the runner.
|
|
||||||
> Please read the discussion in [#592](https://github.com/actions-runner-controller/actions-runner-controller/pull/592) for more information.
|
|
||||||
|
|
||||||
_Note: Prior to the runner version v2.279.0, the environment variable referenced below was called `STARTUP_DELAY`._
|
|
||||||
|
|
||||||
You can add a delay to the runner's entrypoint script by setting the `STARTUP_DELAY_IN_SECONDS` environment
|
|
||||||
variable for the runner pod. This will cause the script to sleep X seconds, this works with any runner kind.
|
|
||||||
|
|
||||||
*Example `RunnerDeployment` with a 2 second startup delay:*
|
|
||||||
```yaml
|
|
||||||
apiVersion: actions.summerwind.dev/v1alpha1
|
|
||||||
kind: RunnerDeployment
|
|
||||||
metadata:
|
|
||||||
name: example-runnerdeployment-with-sleep
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
env:
|
|
||||||
- name: STARTUP_DELAY_IN_SECONDS
|
|
||||||
value: "2" # Remember! env var values must be strings.
|
|
||||||
```
|
|
||||||
|
|
||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
|
|||||||
100
TROUBLESHOOTING.md
Normal file
100
TROUBLESHOOTING.md
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
* [Invalid header field value](#invalid-header-field-value)
|
||||||
|
* [Runner coming up before network available](#runner-coming-up-before-network-available)
|
||||||
|
* [Deployment fails on GKE due to webhooks](#deployment-fails-on-gke-due-to-webhooks)
|
||||||
|
|
||||||
|
## Invalid header field value
|
||||||
|
|
||||||
|
**Problem**
|
||||||
|
|
||||||
|
```json
|
||||||
|
2020-11-12T22:17:30.693Z ERROR controller-runtime.controller Reconciler error
|
||||||
|
{
|
||||||
|
"controller": "runner",
|
||||||
|
"request": "actions-runner-system/runner-deployment-dk7q8-dk5c9",
|
||||||
|
"error": "failed to create registration token: Post \"https://api.github.com/orgs/$YOUR_ORG_HERE/actions/runners/registration-token\": net/http: invalid header field value \"Bearer $YOUR_TOKEN_HERE\\n\" for key Authorization"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution**
|
||||||
|
|
||||||
|
Your base64'ed PAT token has a new line at the end, it needs to be created without a `\n` added, either:
|
||||||
|
* `echo -n $TOKEN | base64`
|
||||||
|
* Create the secret as described in the docs using the shell and documented flags
|
||||||
|
|
||||||
|
## Runner coming up before network available
|
||||||
|
|
||||||
|
**Problem**
|
||||||
|
|
||||||
|
If you're running your action runners on a service mesh like Istio, you might
|
||||||
|
have problems with runner configuration accompanied by logs like:
|
||||||
|
|
||||||
|
```
|
||||||
|
....
|
||||||
|
runner Starting Runner listener with startup type: service
|
||||||
|
runner Started listener process
|
||||||
|
runner An error occurred: Not configured
|
||||||
|
runner Runner listener exited with error code 2
|
||||||
|
runner Runner listener exit with retryable error, re-launch runner in 5 seconds.
|
||||||
|
....
|
||||||
|
```
|
||||||
|
|
||||||
|
This is because the `istio-proxy` has not completed configuring itself when the
|
||||||
|
configuration script tries to communicate with the network.
|
||||||
|
|
||||||
|
More broadly, there are many other circumstances where the runner pod coming up first can cause issues.
|
||||||
|
|
||||||
|
**Solution**<br />
|
||||||
|
|
||||||
|
> Added originally to help users with older istio instances.
|
||||||
|
> Newer Istio instances can use Istio's `holdApplicationUntilProxyStarts` attribute ([istio/istio#11130](https://github.com/istio/istio/issues/11130)) to avoid having to delay starting up the runner.
|
||||||
|
> Please read the discussion in [#592](https://github.com/actions-runner-controller/actions-runner-controller/pull/592) for more information.
|
||||||
|
|
||||||
|
You can add a delay to the runner's entrypoint script by setting the `STARTUP_DELAY_IN_SECONDS` environment variable for the runner pod. This will cause the script to sleep X seconds, this works with any runner kind.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: RunnerDeployment
|
||||||
|
metadata:
|
||||||
|
name: example-runnerdeployment-with-sleep
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
env:
|
||||||
|
# This runner's entrypoint script will have a 5 seconds delay
|
||||||
|
# as a first action within the entrypoint script
|
||||||
|
- name: STARTUP_DELAY_IN_SECONDS
|
||||||
|
value: "5"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment fails on GKE due to webhooks
|
||||||
|
|
||||||
|
**Problem**
|
||||||
|
|
||||||
|
Due to GKEs firewall settings you may run into the following errors when trying to deploy runners on a private GKE cluster:
|
||||||
|
|
||||||
|
```
|
||||||
|
Internal error occurred: failed calling webhook "mutate.runner.actions.summerwind.dev":
|
||||||
|
Post https://webhook-service.actions-runner-system.svc:443/mutate-actions-summerwind-dev-v1alpha1-runner?timeout=10s:
|
||||||
|
context deadline exceeded
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution**<br />
|
||||||
|
|
||||||
|
To fix this, you need to set up a firewall rule to allow the master node to connect to the webhook port.
|
||||||
|
The exact way to do this may wary, but the following script should point you in the right direction:
|
||||||
|
|
||||||
|
```
|
||||||
|
# 1) Retrieve the network tag automatically given to the worker nodes
|
||||||
|
# NOTE: this only works if you have only one cluster in your GCP project. You will have to manually inspect the result of this command to find the tag for the cluster you want to target
|
||||||
|
WORKER_NODES_TAG=$(gcloud compute instances list --format='text(tags.items[0])' --filter='metadata.kubelet-config:*' | grep tags | awk '{print $2}' | sort | uniq)
|
||||||
|
|
||||||
|
# 2) Take note of the VPC network in which you deployed your cluster
|
||||||
|
# NOTE this only works if you have only one network in which you deploy your clusters
|
||||||
|
NETWORK=$(gcloud compute instances list --format='text(networkInterfaces[0].network)' --filter='metadata.kubelet-config:*' | grep networks | awk -F'/' '{print $NF}' | sort | uniq)
|
||||||
|
|
||||||
|
# 3) Get the master source ip block
|
||||||
|
SOURCE=$(gcloud container clusters describe <cluster-name> --region <region> | grep masterIpv4CidrBlock| cut -d ':' -f 2 | tr -d ' ')
|
||||||
|
gcloud compute firewall-rules create k8s-cert-manager --source-ranges $SOURCE --target-tags $WORKER_NODES_TAG --allow TCP:9443 --network $NETWORK
|
||||||
|
```
|
||||||
@@ -6,6 +6,8 @@ tpe=${ACCEPTANCE_TEST_SECRET_TYPE}
|
|||||||
|
|
||||||
VALUES_FILE=${VALUES_FILE:-$(dirname $0)/values.yaml}
|
VALUES_FILE=${VALUES_FILE:-$(dirname $0)/values.yaml}
|
||||||
|
|
||||||
|
kubectl delete secret controller-manager || :
|
||||||
|
|
||||||
if [ "${tpe}" == "token" ]; then
|
if [ "${tpe}" == "token" ]; then
|
||||||
if ! kubectl get secret controller-manager -n actions-runner-system >/dev/null; 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 \
|
||||||
@@ -23,6 +25,16 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "${WEBHOOK_GITHUB_TOKEN}" ]; then
|
||||||
|
kubectl -n actions-runner-system delete secret \
|
||||||
|
github-webhook-server || :
|
||||||
|
kubectl -n actions-runner-system create secret generic \
|
||||||
|
github-webhook-server \
|
||||||
|
--from-literal=github_token=${WEBHOOK_GITHUB_TOKEN:?WEBHOOK_GITHUB_TOKEN must not be empty}
|
||||||
|
else
|
||||||
|
echo 'Skipped deploying secret "github-webhook-server". Set WEBHOOK_GITHUB_TOKEN to deploy.' 1>&2
|
||||||
|
fi
|
||||||
|
|
||||||
tool=${ACCEPTANCE_TEST_DEPLOYMENT_TOOL}
|
tool=${ACCEPTANCE_TEST_DEPLOYMENT_TOOL}
|
||||||
|
|
||||||
if [ "${tool}" == "helm" ]; then
|
if [ "${tool}" == "helm" ]; then
|
||||||
@@ -35,7 +47,9 @@ if [ "${tool}" == "helm" ]; then
|
|||||||
--set image.repository=${NAME} \
|
--set image.repository=${NAME} \
|
||||||
--set image.tag=${VERSION} \
|
--set image.tag=${VERSION} \
|
||||||
-f ${VALUES_FILE}
|
-f ${VALUES_FILE}
|
||||||
kubectl apply -f charts/actions-runner-controller/crds
|
# To prevent `CustomResourceDefinition.apiextensions.k8s.io "runners.actions.summerwind.dev" is invalid: metadata.annotations: Too long: must have at most 262144 bytes`
|
||||||
|
# errors
|
||||||
|
kubectl create -f charts/actions-runner-controller/crds || kubectl replace -f charts/actions-runner-controller/crds
|
||||||
kubectl -n actions-runner-system wait deploy/actions-runner-controller --for condition=available --timeout 60s
|
kubectl -n actions-runner-system wait deploy/actions-runner-controller --for condition=available --timeout 60s
|
||||||
else
|
else
|
||||||
kubectl apply \
|
kubectl apply \
|
||||||
@@ -50,7 +64,7 @@ sleep 20
|
|||||||
RUNNER_LABEL=${RUNNER_LABEL:-self-hosted}
|
RUNNER_LABEL=${RUNNER_LABEL:-self-hosted}
|
||||||
|
|
||||||
if [ -n "${TEST_REPO}" ]; then
|
if [ -n "${TEST_REPO}" ]; then
|
||||||
if [ -n "USE_RUNNERSET" ]; then
|
if [ "${USE_RUNNERSET}" -ne "false" ]; then
|
||||||
cat acceptance/testdata/repo.runnerset.yaml | envsubst | kubectl apply -f -
|
cat acceptance/testdata/repo.runnerset.yaml | envsubst | kubectl apply -f -
|
||||||
cat acceptance/testdata/repo.runnerset.hra.yaml | envsubst | kubectl apply -f -
|
cat acceptance/testdata/repo.runnerset.hra.yaml | envsubst | kubectl apply -f -
|
||||||
else
|
else
|
||||||
@@ -63,13 +77,25 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "${TEST_ORG}" ]; then
|
if [ -n "${TEST_ORG}" ]; then
|
||||||
cat acceptance/testdata/org.runnerdeploy.yaml | envsubst | kubectl apply -f -
|
cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ENTERPRISE= TEST_REPO= NAME=org-runnerdeploy envsubst | kubectl apply -f -
|
||||||
|
|
||||||
if [ -n "${TEST_ORG_REPO}" ]; then
|
if [ -n "${TEST_ORG_GROUP}" ]; then
|
||||||
cat acceptance/testdata/org.hra.yaml | envsubst | kubectl apply -f -
|
cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ENTERPRISE= TEST_REPO= TEST_GROUP=${TEST_ORG_GROUP} NAME=orggroup-runnerdeploy envsubst | kubectl apply -f -
|
||||||
else
|
else
|
||||||
echo 'Skipped deploying organizational hra. Set TEST_ORG_REPO to "yourorg/yourrepo" to deploy.'
|
echo 'Skipped deploying enterprise runnerdeployment. Set TEST_ORG_GROUP to deploy.'
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo 'Skipped deploying organizational runnerdeployment. Set TEST_ORG to deploy.'
|
echo 'Skipped deploying organizational runnerdeployment. Set TEST_ORG to deploy.'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "${TEST_ENTERPRISE}" ]; then
|
||||||
|
cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ORG= TEST_REPO= NAME=enterprise-runnerdeploy envsubst | kubectl apply -f -
|
||||||
|
|
||||||
|
if [ -n "${TEST_ENTERPRISE_GROUP}" ]; then
|
||||||
|
cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ORG= TEST_REPO= TEST_GROUP=${TEST_ENTERPRISE_GROUP} NAME=enterprisegroup-runnerdeploy envsubst | kubectl apply -f -
|
||||||
|
else
|
||||||
|
echo 'Skipped deploying enterprise runnerdeployment. Set TEST_ENTERPRISE_GROUP to deploy.'
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo 'Skipped deploying enterprise runnerdeployment. Set TEST_ENTERPRISE to deploy.'
|
||||||
|
fi
|
||||||
|
|||||||
7
acceptance/testdata/org.runnerdeploy.yaml
vendored
7
acceptance/testdata/org.runnerdeploy.yaml
vendored
@@ -14,6 +14,11 @@ spec:
|
|||||||
image: ${RUNNER_NAME}:${RUNNER_TAG}
|
image: ${RUNNER_NAME}:${RUNNER_TAG}
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
# Whether to pass --ephemeral (true) or --once (false, deprecated)
|
||||||
|
env:
|
||||||
|
- name: RUNNER_FEATURE_FLAG_EPHEMERAL
|
||||||
|
value: "${RUNNER_FEATURE_FLAG_EPHEMERAL}"
|
||||||
|
|
||||||
#
|
#
|
||||||
# dockerd within runner container
|
# dockerd within runner container
|
||||||
#
|
#
|
||||||
@@ -30,6 +35,8 @@ spec:
|
|||||||
# labels:
|
# labels:
|
||||||
# - "mylabel 1"
|
# - "mylabel 1"
|
||||||
# - "mylabel 2"
|
# - "mylabel 2"
|
||||||
|
labels:
|
||||||
|
- "${RUNNER_LABEL}"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Non-standard working directory
|
# Non-standard working directory
|
||||||
|
|||||||
7
acceptance/testdata/repo.runnerdeploy.yaml
vendored
7
acceptance/testdata/repo.runnerdeploy.yaml
vendored
@@ -14,6 +14,11 @@ spec:
|
|||||||
image: ${RUNNER_NAME}:${RUNNER_TAG}
|
image: ${RUNNER_NAME}:${RUNNER_TAG}
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
# Whether to pass --ephemeral (true) or --once (false, deprecated)
|
||||||
|
env:
|
||||||
|
- name: RUNNER_FEATURE_FLAG_EPHEMERAL
|
||||||
|
value: "${RUNNER_FEATURE_FLAG_EPHEMERAL}"
|
||||||
|
|
||||||
#
|
#
|
||||||
# dockerd within runner container
|
# dockerd within runner container
|
||||||
#
|
#
|
||||||
@@ -30,6 +35,8 @@ spec:
|
|||||||
# labels:
|
# labels:
|
||||||
# - "mylabel 1"
|
# - "mylabel 1"
|
||||||
# - "mylabel 2"
|
# - "mylabel 2"
|
||||||
|
labels:
|
||||||
|
- "${RUNNER_LABEL}"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Non-standard working directory
|
# Non-standard working directory
|
||||||
|
|||||||
61
acceptance/testdata/runnerdeploy.envsubst.yaml
vendored
Normal file
61
acceptance/testdata/runnerdeploy.envsubst.yaml
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: RunnerDeployment
|
||||||
|
metadata:
|
||||||
|
name: ${NAME}
|
||||||
|
spec:
|
||||||
|
# replicas: 1
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
enterprise: ${TEST_ENTERPRISE}
|
||||||
|
group: ${TEST_GROUP}
|
||||||
|
organization: ${TEST_ORG}
|
||||||
|
repository: ${TEST_REPO}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Custom runner image
|
||||||
|
#
|
||||||
|
image: ${RUNNER_NAME}:${RUNNER_TAG}
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
# Whether to pass --ephemeral (true) or --once (false, deprecated)
|
||||||
|
env:
|
||||||
|
- name: RUNNER_FEATURE_FLAG_EPHEMERAL
|
||||||
|
value: "${RUNNER_FEATURE_FLAG_EPHEMERAL}"
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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"
|
||||||
|
labels:
|
||||||
|
- "${RUNNER_LABEL}"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Non-standard working directory
|
||||||
|
#
|
||||||
|
# workDir: "/"
|
||||||
|
---
|
||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: HorizontalRunnerAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: ${NAME}
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
name: ${NAME}
|
||||||
|
scaleUpTriggers:
|
||||||
|
- githubEvent: {}
|
||||||
|
amount: 1
|
||||||
|
duration: "1m"
|
||||||
|
minReplicas: 0
|
||||||
|
maxReplicas: 10
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
# Set actions-runner-controller settings for testing
|
# Set actions-runner-controller settings for testing
|
||||||
githubAPICacheDuration: 10s
|
githubAPICacheDuration: 10s
|
||||||
githubWebhookServer:
|
githubWebhookServer:
|
||||||
|
logLevel: debug
|
||||||
enabled: true
|
enabled: true
|
||||||
labels: {}
|
labels: {}
|
||||||
replicaCount: 1
|
replicaCount: 1
|
||||||
syncPeriod: 10m
|
syncPeriod: 10m
|
||||||
|
useRunnerGroupsVisibility: true
|
||||||
secret:
|
secret:
|
||||||
create: true
|
enabled: true
|
||||||
|
# create: true
|
||||||
name: "github-webhook-server"
|
name: "github-webhook-server"
|
||||||
### GitHub Webhook Configuration
|
### GitHub Webhook Configuration
|
||||||
#github_webhook_secret_token: ""
|
#github_webhook_secret_token: ""
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ type HorizontalRunnerAutoscalerSpec struct {
|
|||||||
// +optional
|
// +optional
|
||||||
MinReplicas *int `json:"minReplicas,omitempty"`
|
MinReplicas *int `json:"minReplicas,omitempty"`
|
||||||
|
|
||||||
// MinReplicas is the maximum number of replicas the deployment is allowed to scale
|
// MaxReplicas is the maximum number of replicas the deployment is allowed to scale
|
||||||
// +optional
|
// +optional
|
||||||
MaxReplicas *int `json:"maxReplicas,omitempty"`
|
MaxReplicas *int `json:"maxReplicas,omitempty"`
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ type RunnerPodSpec struct {
|
|||||||
// +optional
|
// +optional
|
||||||
DockerVolumeMounts []corev1.VolumeMount `json:"dockerVolumeMounts,omitempty"`
|
DockerVolumeMounts []corev1.VolumeMount `json:"dockerVolumeMounts,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
DockerEnv []corev1.EnvVar `json:"dockerEnv,omitempty"`
|
||||||
|
|
||||||
// +optional
|
// +optional
|
||||||
Containers []corev1.Container `json:"containers,omitempty"`
|
Containers []corev1.Container `json:"containers,omitempty"`
|
||||||
|
|
||||||
@@ -141,6 +144,9 @@ type RunnerPodSpec struct {
|
|||||||
// +optional
|
// +optional
|
||||||
HostAliases []corev1.HostAlias `json:"hostAliases,omitempty"`
|
HostAliases []corev1.HostAlias `json:"hostAliases,omitempty"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraint,omitempty"`
|
||||||
|
|
||||||
// RuntimeClassName is the container runtime configuration that containers should run under.
|
// RuntimeClassName is the container runtime configuration that containers should run under.
|
||||||
// More info: https://kubernetes.io/docs/concepts/containers/runtime-class
|
// More info: https://kubernetes.io/docs/concepts/containers/runtime-class
|
||||||
// +optional
|
// +optional
|
||||||
|
|||||||
@@ -599,6 +599,13 @@ func (in *RunnerPodSpec) DeepCopyInto(out *RunnerPodSpec) {
|
|||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if in.DockerEnv != nil {
|
||||||
|
in, out := &in.DockerEnv, &out.DockerEnv
|
||||||
|
*out = make([]v1.EnvVar, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
if in.Containers != nil {
|
if in.Containers != nil {
|
||||||
in, out := &in.Containers, &out.Containers
|
in, out := &in.Containers, &out.Containers
|
||||||
*out = make([]v1.Container, len(*in))
|
*out = make([]v1.Container, len(*in))
|
||||||
@@ -707,6 +714,13 @@ func (in *RunnerPodSpec) DeepCopyInto(out *RunnerPodSpec) {
|
|||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if in.TopologySpreadConstraints != nil {
|
||||||
|
in, out := &in.TopologySpreadConstraints, &out.TopologySpreadConstraints
|
||||||
|
*out = make([]v1.TopologySpreadConstraint, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
if in.RuntimeClassName != nil {
|
if in.RuntimeClassName != nil {
|
||||||
in, out := &in.RuntimeClassName, &out.RuntimeClassName
|
in, out := &in.RuntimeClassName, &out.RuntimeClassName
|
||||||
*out = new(string)
|
*out = new(string)
|
||||||
|
|||||||
@@ -2,3 +2,4 @@
|
|||||||
lint-conf: charts/.ci/lint-config.yaml
|
lint-conf: charts/.ci/lint-config.yaml
|
||||||
chart-repos:
|
chart-repos:
|
||||||
- jetstack=https://charts.jetstack.io
|
- jetstack=https://charts.jetstack.io
|
||||||
|
check-version-increment: false # Disable checking that the chart version has been bumped
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ type: application
|
|||||||
# This is the chart version. This version number should be incremented each time you make changes
|
# This is the chart version. This version number should be incremented each time you make changes
|
||||||
# to the chart and its templates, including the app version.
|
# to the chart and its templates, including the app version.
|
||||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||||
version: 0.13.2
|
version: 0.16.0
|
||||||
|
|
||||||
# Used as the default manager tag value when no tag property is provided in the values.yaml
|
# Used as the default manager tag value when no tag property is provided in the values.yaml
|
||||||
appVersion: 0.20.2
|
appVersion: 0.21.0
|
||||||
|
|
||||||
home: https://github.com/actions-runner-controller/actions-runner-controller
|
home: https://github.com/actions-runner-controller/actions-runner-controller
|
||||||
|
|
||||||
|
|||||||
@@ -17,27 +17,37 @@ All additional docs are kept in the `docs/` folder, this README is solely for do
|
|||||||
| `leaderElectionId` | Set the election ID for the controller group | |
|
| `leaderElectionId` | Set the election ID for the controller group | |
|
||||||
| `githubAPICacheDuration` | Set the cache period for API calls | |
|
| `githubAPICacheDuration` | Set the cache period for API calls | |
|
||||||
| `githubEnterpriseServerURL` | Set the URL for a self-hosted GitHub Enterprise Server | |
|
| `githubEnterpriseServerURL` | Set the URL for a self-hosted GitHub Enterprise Server | |
|
||||||
|
| `githubURL` | Override GitHub URL to be used for GitHub API calls | |
|
||||||
|
| `githubUploadURL` | Override GitHub Upload URL to be used for GitHub API calls | |
|
||||||
|
| `runnerGithubURL` | Override GitHub URL to be used by runners during registration | |
|
||||||
| `logLevel` | Set the log level of the controller container | |
|
| `logLevel` | Set the log level of the controller container | |
|
||||||
|
| `additionalVolumes` | Set additional volumes to add to the manager container | |
|
||||||
|
| `additionalVolumeMounts` | Set additional volume mounts to add to the manager container | |
|
||||||
| `authSecret.create` | Deploy the controller auth secret | false |
|
| `authSecret.create` | Deploy the controller auth secret | false |
|
||||||
| `authSecret.name` | Set the name of the auth secret | controller-manager |
|
| `authSecret.name` | Set the name of the auth secret | controller-manager |
|
||||||
|
| `authSecret.annotations` | Set annotations for the auth Secret | |
|
||||||
| `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_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_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_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_*`** | |
|
| `authSecret.github_token` | Your chosen GitHub PAT token. **This can't be set at the same time as the `authSecret.github_app_*`** | |
|
||||||
|
| `authSecret.github_basicauth_username` | Username for GitHub basic auth to use instead of PAT or GitHub APP in case it's running behind a proxy API | |
|
||||||
|
| `authSecret.github_basicauth_password` | Password for GitHub basic auth to use instead of PAT or GitHub APP in case it's running behind a proxy API | |
|
||||||
| `dockerRegistryMirror` | The default Docker Registry Mirror used by runners. | |
|
| `dockerRegistryMirror` | The default Docker Registry Mirror used by runners. | |
|
||||||
| `image.repository` | The "repository/image" of the controller container | summerwind/actions-runner-controller |
|
| `image.repository` | The "repository/image" of the controller container | summerwind/actions-runner-controller |
|
||||||
| `image.tag` | The tag of the controller container | |
|
| `image.tag` | The tag of the controller container | |
|
||||||
| `image.actionsRunnerRepositoryAndTag` | The "repository/image" of the actions runner container | summerwind/actions-runner:latest |
|
| `image.actionsRunnerRepositoryAndTag` | The "repository/image" of the actions runner container | summerwind/actions-runner:latest |
|
||||||
|
| `image.actionsRunnerImagePullSecrets` | Optional image pull secrets to be included in the runner pod's ImagePullSecrets | |
|
||||||
| `image.dindSidecarRepositoryAndTag` | The "repository/image" of the dind sidecar container | docker:dind |
|
| `image.dindSidecarRepositoryAndTag` | The "repository/image" of the dind sidecar container | docker:dind |
|
||||||
| `image.pullPolicy` | The pull policy of the controller image | IfNotPresent |
|
| `image.pullPolicy` | The pull policy of the controller image | IfNotPresent |
|
||||||
| `metrics.serviceMonitor` | Deploy serviceMonitor kind for for use with prometheus-operator CRDs | false |
|
| `metrics.serviceMonitor` | Deploy serviceMonitor kind for for use with prometheus-operator CRDs | false |
|
||||||
|
| `metrics.serviceAnnotations` | Set annotations for the provisioned metrics service resource | |
|
||||||
| `metrics.port` | Set port of metrics service | 8443 |
|
| `metrics.port` | Set port of metrics service | 8443 |
|
||||||
| `metrics.proxy.enabled` | Deploy kube-rbac-proxy container in controller pod | true |
|
| `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.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 |
|
| `metrics.proxy.image.tag` | The tag of the kube-proxy image to use when pulling the container | v0.10.0 |
|
||||||
| `metrics.serviceMonitorLabels` | Set labels to apply to ServiceMonitor resources | |
|
| `metrics.serviceMonitorLabels` | Set labels to apply to ServiceMonitor resources | |
|
||||||
| `imagePullSecrets` | Specifies the secret to be used when pulling the controller pod containers | |
|
| `imagePullSecrets` | Specifies the secret to be used when pulling the controller pod containers | |
|
||||||
| `fullNameOverride` | Override the full resource names | |
|
| `fullnameOverride` | Override the full resource names | |
|
||||||
| `nameOverride` | Override the resource name prefix | |
|
| `nameOverride` | Override the resource name prefix | |
|
||||||
| `serviceAccont.annotations` | Set annotations to the service account | |
|
| `serviceAccont.annotations` | Set annotations to the service account | |
|
||||||
| `serviceAccount.create` | Deploy the controller pod under a service account | true |
|
| `serviceAccount.create` | Deploy the controller pod under a service account | true |
|
||||||
@@ -46,27 +56,35 @@ All additional docs are kept in the `docs/` folder, this README is solely for do
|
|||||||
| `serviceAccount.name` | Set the name of the service account | |
|
| `serviceAccount.name` | Set the name of the service account | |
|
||||||
| `securityContext` | Set the security context for each container in the controller pod | |
|
| `securityContext` | Set the security context for each container in the controller pod | |
|
||||||
| `podSecurityContext` | Set the security context to controller pod | |
|
| `podSecurityContext` | Set the security context to controller pod | |
|
||||||
| `service.port` | Set controller service type | |
|
| `service.annotations` | Set annotations for the provisioned webhook service resource | |
|
||||||
| `service.type` | Set controller service ports | |
|
| `service.port` | Set controller service ports | |
|
||||||
|
| `service.type` | Set controller service type | |
|
||||||
| `topologySpreadConstraints` | Set the controller pod topologySpreadConstraints | |
|
| `topologySpreadConstraints` | Set the controller pod topologySpreadConstraints | |
|
||||||
| `nodeSelector` | Set the controller pod nodeSelector | |
|
| `nodeSelector` | Set the controller pod nodeSelector | |
|
||||||
| `resources` | Set the controller pod resources | |
|
| `resources` | Set the controller pod resources | |
|
||||||
| `affinity` | Set the controller pod affinity rules | |
|
| `affinity` | Set the controller pod affinity rules | |
|
||||||
|
| `podDisruptionBudget.enabled` | Enables a PDB to ensure HA of controller pods | false |
|
||||||
|
| `podDisruptionBudget.minAvailable` | Minimum number of pods that must be available after eviction | |
|
||||||
|
| `podDisruptionBudget.maxUnavailable` | Maximum number of pods that can be unavailable after eviction. Kubernetes 1.7+ required. | |
|
||||||
| `tolerations` | Set the controller pod tolerations | |
|
| `tolerations` | Set the controller pod tolerations | |
|
||||||
| `env` | Set environment variables for the controller container | |
|
| `env` | Set environment variables for the controller container | |
|
||||||
| `priorityClassName` | Set the controller pod priorityClassName | |
|
| `priorityClassName` | Set the controller pod priorityClassName | |
|
||||||
| `scope.watchNamespace` | Tells the controller which namespace to watch if `scope.singleNamespace` is true | |
|
| `scope.watchNamespace` | Tells the controller and the github webhook server which namespace to watch if `scope.singleNamespace` is true | `Release.Namespace` (the default namespace of the helm chart). |
|
||||||
| `scope.singleNamespace` | Limit the controller to watch a single namespace | false |
|
| `scope.singleNamespace` | Limit the controller to watch a single namespace | false |
|
||||||
|
| `certManagerEnabled` | Enable cert-manager. If disabled you must set admissionWebHooks.caBundle and create TLS secrets manually | true |
|
||||||
|
| `admissionWebHooks.caBundle` | Base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate | |
|
||||||
| `githubWebhookServer.logLevel` | Set the log level of the githubWebhookServer container | |
|
| `githubWebhookServer.logLevel` | Set the log level of the githubWebhookServer container | |
|
||||||
| `githubWebhookServer.replicaCount` | Set the number of webhook server pods | 1 |
|
| `githubWebhookServer.replicaCount` | Set the number of webhook server pods | 1 |
|
||||||
|
| `githubWebhookServer.useRunnerGroupsVisibility` | Enable supporting runner groups with custom visibility. This will incur in extra API calls and may blow up your budget. Currently, you also need to set `githubWebhookServer.secret.enabled` to enable this feature. | false |
|
||||||
| `githubWebhookServer.syncPeriod` | Set the period in which the controller reconciles the resources | 10m |
|
| `githubWebhookServer.syncPeriod` | Set the period in which the controller reconciles the resources | 10m |
|
||||||
| `githubWebhookServer.enabled` | Deploy the webhook server pod | false |
|
| `githubWebhookServer.enabled` | Deploy the webhook server pod | false |
|
||||||
|
| `githubWebhookServer.secret.enabled` | Passes the webhook hook secret to the github-webhook-server | false |
|
||||||
| `githubWebhookServer.secret.create` | Deploy the webhook hook secret | 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.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.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.imagePullSecrets` | Specifies the secret to be used when pulling the githubWebhookServer pod containers | |
|
||||||
| `githubWebhookServer.nameOveride` | Override the resource name prefix | |
|
| `githubWebhookServer.nameOverride` | Override the resource name prefix | |
|
||||||
| `githubWebhookServer.fullNameOveride` | Override the full resource names | |
|
| `githubWebhookServer.fullnameOverride` | Override the full resource names | |
|
||||||
| `githubWebhookServer.serviceAccount.create` | Deploy the githubWebhookServer under a service account | true |
|
| `githubWebhookServer.serviceAccount.create` | Deploy the githubWebhookServer under a service account | true |
|
||||||
| `githubWebhookServer.serviceAccount.annotations` | Set annotations for the service account | |
|
| `githubWebhookServer.serviceAccount.annotations` | Set annotations for the service account | |
|
||||||
| `githubWebhookServer.serviceAccount.name` | Set the service account name | |
|
| `githubWebhookServer.serviceAccount.name` | Set the service account name | |
|
||||||
@@ -86,3 +104,7 @@ All additional docs are kept in the `docs/` folder, this README is solely for do
|
|||||||
| `githubWebhookServer.ingress.annotations` | Set annotations for the ingress kind | |
|
| `githubWebhookServer.ingress.annotations` | Set annotations for the ingress kind | |
|
||||||
| `githubWebhookServer.ingress.hosts` | Set hosts configuration for ingress | `[{"host": "chart-example.local", "paths": []}]` |
|
| `githubWebhookServer.ingress.hosts` | Set hosts configuration for ingress | `[{"host": "chart-example.local", "paths": []}]` |
|
||||||
| `githubWebhookServer.ingress.tls` | Set tls configuration for ingress | |
|
| `githubWebhookServer.ingress.tls` | Set tls configuration for ingress | |
|
||||||
|
| `githubWebhookServer.ingress.ingressClassName` | Set ingress class name | |
|
||||||
|
| `githubWebhookServer.podDisruptionBudget.enabled` | Enables a PDB to ensure HA of githubwebhook pods | false |
|
||||||
|
| `githubWebhookServer.podDisruptionBudget.minAvailable` | Minimum number of pods that must be available after eviction | |
|
||||||
|
| `githubWebhookServer.podDisruptionBudget.maxUnavailable` | Maximum number of pods that can be unavailable after eviction. Kubernetes 1.7+ required. | |
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.6.0
|
controller-gen.kubebuilder.io/version: v0.7.0
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: horizontalrunnerautoscalers.actions.summerwind.dev
|
name: horizontalrunnerautoscalers.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
@@ -59,7 +59,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
maxReplicas:
|
maxReplicas:
|
||||||
description: MinReplicas is the maximum number of replicas the deployment is allowed to scale
|
description: MaxReplicas is the maximum number of replicas the deployment is allowed to scale
|
||||||
type: integer
|
type: integer
|
||||||
metrics:
|
metrics:
|
||||||
description: Metrics is the collection of various metric targets to calculate desired number of runners
|
description: Metrics is the collection of various metric targets to calculate desired number of runners
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,7 @@ Due to the above you can't just do a `helm upgrade` to release the latest versio
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
# REMEMBER TO UPDATE THE CHART_VERSION TO RELEVANT CHART VERISON!!!!
|
# REMEMBER TO UPDATE THE CHART_VERSION TO RELEVANT CHART VERISON!!!!
|
||||||
CHART_VERSION=0.11.0
|
CHART_VERSION=0.14.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
|
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
|
||||||
|
|
||||||
@@ -32,9 +32,10 @@ kubectl apply -f crds/
|
|||||||
2. Upgrade the Helm release
|
2. Upgrade the Helm release
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
helm upgrade --install \
|
# helm upgrade [RELEASE] [CHART] [flags]
|
||||||
--namespace actions-runner-system \
|
helm upgrade actions-runner-controller \
|
||||||
--version ${CHART_VERSION} \
|
|
||||||
actions-runner-controller/actions-runner-controller \
|
actions-runner-controller/actions-runner-controller \
|
||||||
actions-runner-controller
|
--install \
|
||||||
|
--namespace actions-runner-system \
|
||||||
|
--version ${CHART_VERSION}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -58,3 +58,7 @@ Create the name of the service account to use
|
|||||||
{{- define "actions-runner-controller-github-webhook-server.serviceMonitorName" -}}
|
{{- define "actions-runner-controller-github-webhook-server.serviceMonitorName" -}}
|
||||||
{{- include "actions-runner-controller-github-webhook-server.fullname" . | trunc 47 }}-service-monitor
|
{{- include "actions-runner-controller-github-webhook-server.fullname" . | trunc 47 }}-service-monitor
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "actions-runner-controller-github-webhook-server.pdbName" -}}
|
||||||
|
{{- include "actions-runner-controller-github-webhook-server.fullname" . | trunc 59 }}-pdb
|
||||||
|
{{- end }}
|
||||||
@@ -68,6 +68,10 @@ Create the name of the service account to use
|
|||||||
{{- default (include "actions-runner-controller.fullname" .) .Values.authSecret.name -}}
|
{{- default (include "actions-runner-controller.fullname" .) .Values.authSecret.name -}}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "actions-runner-controller.githubWebhookServerSecretName" -}}
|
||||||
|
{{- default (include "actions-runner-controller.fullname" .) .Values.githubWebhookServer.secret.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 }}
|
||||||
@@ -107,3 +111,7 @@ Create the name of the service account to use
|
|||||||
{{- define "actions-runner-controller.servingCertName" -}}
|
{{- define "actions-runner-controller.servingCertName" -}}
|
||||||
{{- include "actions-runner-controller.fullname" . }}-serving-cert
|
{{- include "actions-runner-controller.fullname" . }}-serving-cert
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "actions-runner-controller.pdbName" -}}
|
||||||
|
{{- include "actions-runner-controller.fullname" . | trunc 59 }}-pdb
|
||||||
|
{{- end }}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{{- if .Values.certManagerEnabled }}
|
||||||
# The following manifests contain a self-signed issuer CR and a certificate CR.
|
# The following manifests contain a self-signed issuer CR and a certificate CR.
|
||||||
# More document can be found at https://docs.cert-manager.io
|
# More document can be found at https://docs.cert-manager.io
|
||||||
# WARNING: Targets CertManager 0.11 check https://docs.cert-manager.io/en/latest/tasks/upgrading/index.html for breaking changes
|
# WARNING: Targets CertManager 0.11 check https://docs.cert-manager.io/en/latest/tasks/upgrading/index.html for breaking changes
|
||||||
@@ -22,3 +23,4 @@ spec:
|
|||||||
kind: Issuer
|
kind: Issuer
|
||||||
name: {{ include "actions-runner-controller.selfsignedIssuerName" . }}
|
name: {{ include "actions-runner-controller.selfsignedIssuerName" . }}
|
||||||
secretName: {{ include "actions-runner-controller.servingCertName" . }}
|
secretName: {{ include "actions-runner-controller.servingCertName" . }}
|
||||||
|
{{- end }}
|
||||||
|
|||||||
@@ -7,4 +7,8 @@ data:
|
|||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: controller-manager
|
name: controller-manager
|
||||||
|
{{- if .Values.authSecret.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{ toYaml .Values.authSecret.annotations | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -5,6 +5,10 @@ metadata:
|
|||||||
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
name: {{ include "actions-runner-controller.metricsServiceName" . }}
|
name: {{ include "actions-runner-controller.metricsServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
|
{{- with .Values.metrics.serviceAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
spec:
|
spec:
|
||||||
ports:
|
ports:
|
||||||
- name: metrics-port
|
- name: metrics-port
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{{- if .Values.podDisruptionBudget.enabled }}
|
||||||
|
apiVersion: policy/v1beta1
|
||||||
|
kind: PodDisruptionBudget
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
|
name: {{ include "actions-runner-controller.pdbName" . }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.podDisruptionBudget.minAvailable }}
|
||||||
|
minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.podDisruptionBudget.maxUnavailable }}
|
||||||
|
maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "actions-runner-controller.selectorLabels" . | nindent 6 }}
|
||||||
|
{{- end -}}
|
||||||
@@ -46,6 +46,9 @@ spec:
|
|||||||
- "--sync-period={{ .Values.syncPeriod }}"
|
- "--sync-period={{ .Values.syncPeriod }}"
|
||||||
- "--docker-image={{ .Values.image.dindSidecarRepositoryAndTag }}"
|
- "--docker-image={{ .Values.image.dindSidecarRepositoryAndTag }}"
|
||||||
- "--runner-image={{ .Values.image.actionsRunnerRepositoryAndTag }}"
|
- "--runner-image={{ .Values.image.actionsRunnerRepositoryAndTag }}"
|
||||||
|
{{- range .Values.image.actionsRunnerImagePullSecrets }}
|
||||||
|
- "--runner-image-pull-secret={{ . }}"
|
||||||
|
{{- end }}
|
||||||
{{- if .Values.dockerRegistryMirror }}
|
{{- if .Values.dockerRegistryMirror }}
|
||||||
- "--docker-registry-mirror={{ .Values.dockerRegistryMirror }}"
|
- "--docker-registry-mirror={{ .Values.dockerRegistryMirror }}"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -58,6 +61,9 @@ spec:
|
|||||||
{{- if .Values.logLevel }}
|
{{- if .Values.logLevel }}
|
||||||
- "--log-level={{ .Values.logLevel }}"
|
- "--log-level={{ .Values.logLevel }}"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.runnerGithubURL }}
|
||||||
|
- "--runner-github-url={{ .Values.runnerGithubURL }}"
|
||||||
|
{{- end }}
|
||||||
command:
|
command:
|
||||||
- "/manager"
|
- "/manager"
|
||||||
env:
|
env:
|
||||||
@@ -65,6 +71,15 @@ spec:
|
|||||||
- name: GITHUB_ENTERPRISE_URL
|
- name: GITHUB_ENTERPRISE_URL
|
||||||
value: {{ .Values.githubEnterpriseServerURL }}
|
value: {{ .Values.githubEnterpriseServerURL }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.githubURL }}
|
||||||
|
- name: GITHUB_URL
|
||||||
|
value: {{ .Values.githubURL }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.githubUploadURL }}
|
||||||
|
- name: GITHUB_UPLOAD_URL
|
||||||
|
value: {{ .Values.githubUploadURL }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.authSecret.enabled }}
|
||||||
- name: GITHUB_TOKEN
|
- name: GITHUB_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
@@ -84,7 +99,23 @@ spec:
|
|||||||
name: {{ include "actions-runner-controller.secretName" . }}
|
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
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: github_app_private_key
|
||||||
|
name: {{ include "actions-runner-controller.secretName" . }}
|
||||||
|
optional: true
|
||||||
|
{{- if .Values.authSecret.github_basicauth_username }}
|
||||||
|
- name: GITHUB_BASICAUTH_USERNAME
|
||||||
|
value: {{ .Values.authSecret.github_basicauth_username }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.authSecret.github_basicauth_password }}
|
||||||
|
- name: GITHUB_BASICAUTH_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: github_basicauth_password
|
||||||
|
name: {{ include "actions-runner-controller.secretName" . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
{{- range $key, $val := .Values.env }}
|
{{- range $key, $val := .Values.env }}
|
||||||
- name: {{ $key }}
|
- name: {{ $key }}
|
||||||
value: {{ $val | quote }}
|
value: {{ $val | quote }}
|
||||||
@@ -106,14 +137,19 @@ spec:
|
|||||||
securityContext:
|
securityContext:
|
||||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
|
{{- if .Values.authSecret.enabled }}
|
||||||
- mountPath: "/etc/actions-runner-controller"
|
- mountPath: "/etc/actions-runner-controller"
|
||||||
name: secret
|
name: secret
|
||||||
readOnly: true
|
readOnly: true
|
||||||
|
{{- end }}
|
||||||
- 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.additionalVolumeMounts }}
|
||||||
|
{{- toYaml .Values.additionalVolumeMounts | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
{{- if .Values.metrics.proxy.enabled }}
|
{{- if .Values.metrics.proxy.enabled }}
|
||||||
- args:
|
- args:
|
||||||
- "--secure-listen-address=0.0.0.0:{{ .Values.metrics.port }}"
|
- "--secure-listen-address=0.0.0.0:{{ .Values.metrics.port }}"
|
||||||
@@ -133,15 +169,20 @@ spec:
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
terminationGracePeriodSeconds: 10
|
terminationGracePeriodSeconds: 10
|
||||||
volumes:
|
volumes:
|
||||||
|
{{- if .Values.authSecret.enabled }}
|
||||||
- name: secret
|
- name: secret
|
||||||
secret:
|
secret:
|
||||||
secretName: {{ include "actions-runner-controller.secretName" . }}
|
secretName: {{ include "actions-runner-controller.secretName" . }}
|
||||||
|
{{- end }}
|
||||||
- name: cert
|
- name: cert
|
||||||
secret:
|
secret:
|
||||||
defaultMode: 420
|
defaultMode: 420
|
||||||
secretName: {{ include "actions-runner-controller.servingCertName" . }}
|
secretName: {{ include "actions-runner-controller.servingCertName" . }}
|
||||||
- name: tmp
|
- name: tmp
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
|
{{- if .Values.additionalVolumes }}
|
||||||
|
{{- toYaml .Values.additionalVolumes | nindent 6}}
|
||||||
|
{{- end }}
|
||||||
{{- with .Values.nodeSelector }}
|
{{- with .Values.nodeSelector }}
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
|
|||||||
@@ -42,6 +42,12 @@ spec:
|
|||||||
{{- if .Values.githubWebhookServer.logLevel }}
|
{{- if .Values.githubWebhookServer.logLevel }}
|
||||||
- "--log-level={{ .Values.githubWebhookServer.logLevel }}"
|
- "--log-level={{ .Values.githubWebhookServer.logLevel }}"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.scope.singleNamespace }}
|
||||||
|
- "--watch-namespace={{ default .Release.Namespace .Values.scope.watchNamespace }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.runnerGithubURL }}
|
||||||
|
- "--runner-github-url={{ .Values.runnerGithubURL }}"
|
||||||
|
{{- end }}
|
||||||
command:
|
command:
|
||||||
- "/github-webhook-server"
|
- "/github-webhook-server"
|
||||||
env:
|
env:
|
||||||
@@ -51,6 +57,55 @@ spec:
|
|||||||
key: github_webhook_secret_token
|
key: github_webhook_secret_token
|
||||||
name: {{ include "actions-runner-controller-github-webhook-server.secretName" . }}
|
name: {{ include "actions-runner-controller-github-webhook-server.secretName" . }}
|
||||||
optional: true
|
optional: true
|
||||||
|
{{- if .Values.githubEnterpriseServerURL }}
|
||||||
|
- name: GITHUB_ENTERPRISE_URL
|
||||||
|
value: {{ .Values.githubEnterpriseServerURL }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.githubURL }}
|
||||||
|
- name: GITHUB_URL
|
||||||
|
value: {{ .Values.githubURL }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.githubUploadURL }}
|
||||||
|
- name: GITHUB_UPLOAD_URL
|
||||||
|
value: {{ .Values.githubUploadURL }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and .Values.githubWebhookServer.useRunnerGroupsVisibility .Values.githubWebhookServer.secret.enabled }}
|
||||||
|
- name: GITHUB_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: github_token
|
||||||
|
name: {{ include "actions-runner-controller.githubWebhookServerSecretName" . }}
|
||||||
|
optional: true
|
||||||
|
- name: GITHUB_APP_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: github_app_id
|
||||||
|
name: {{ include "actions-runner-controller.githubWebhookServerSecretName" . }}
|
||||||
|
optional: true
|
||||||
|
- name: GITHUB_APP_INSTALLATION_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: github_app_installation_id
|
||||||
|
name: {{ include "actions-runner-controller.githubWebhookServerSecretName" . }}
|
||||||
|
optional: true
|
||||||
|
- name: GITHUB_APP_PRIVATE_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: github_app_private_key
|
||||||
|
name: {{ include "actions-runner-controller.githubWebhookServerSecretName" . }}
|
||||||
|
optional: true
|
||||||
|
{{- if .Values.authSecret.github_basicauth_username }}
|
||||||
|
- name: GITHUB_BASICAUTH_USERNAME
|
||||||
|
value: {{ .Values.authSecret.github_basicauth_username }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.authSecret.github_basicauth_password }}
|
||||||
|
- name: GITHUB_BASICAUTH_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: github_basicauth_password
|
||||||
|
name: {{ include "actions-runner-controller.secretName" . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
{{- range $key, $val := .Values.githubWebhookServer.env }}
|
{{- range $key, $val := .Values.githubWebhookServer.env }}
|
||||||
- name: {{ $key }}
|
- name: {{ $key }}
|
||||||
value: {{ $val | quote }}
|
value: {{ $val | quote }}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
{{- if .Values.githubWebhookServer.ingress.enabled -}}
|
{{- if .Values.githubWebhookServer.ingress.enabled -}}
|
||||||
{{- $fullName := include "actions-runner-controller-github-webhook-server.fullname" . -}}
|
{{- $fullName := include "actions-runner-controller-github-webhook-server.fullname" . -}}
|
||||||
{{- $svcPort := (index .Values.githubWebhookServer.service.ports 0).port -}}
|
{{- $svcPort := (index .Values.githubWebhookServer.service.ports 0).port -}}
|
||||||
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
{{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
{{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" }}
|
||||||
apiVersion: networking.k8s.io/v1beta1
|
apiVersion: networking.k8s.io/v1beta1
|
||||||
{{- else -}}
|
{{- else if .Capabilities.APIVersions.Has "extensions/v1beta1" }}
|
||||||
apiVersion: extensions/v1beta1
|
apiVersion: extensions/v1beta1
|
||||||
{{- end }}
|
{{- end }}
|
||||||
kind: Ingress
|
kind: Ingress
|
||||||
@@ -26,6 +28,9 @@ spec:
|
|||||||
secretName: {{ .secretName }}
|
secretName: {{ .secretName }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- with .Values.githubWebhookServer.ingress.ingressClassName }}
|
||||||
|
ingressClassName: {{ . }}
|
||||||
|
{{- end }}
|
||||||
rules:
|
rules:
|
||||||
{{- range .Values.githubWebhookServer.ingress.hosts }}
|
{{- range .Values.githubWebhookServer.ingress.hosts }}
|
||||||
- host: {{ .host | quote }}
|
- host: {{ .host | quote }}
|
||||||
@@ -33,9 +38,19 @@ spec:
|
|||||||
paths:
|
paths:
|
||||||
{{- range .paths }}
|
{{- range .paths }}
|
||||||
- path: {{ .path }}
|
- path: {{ .path }}
|
||||||
|
{{- if $.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
|
||||||
|
pathType: {{ .pathType }}
|
||||||
|
{{- end }}
|
||||||
backend:
|
backend:
|
||||||
|
{{- if $.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
|
||||||
|
service:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
port:
|
||||||
|
number: {{ $svcPort }}
|
||||||
|
{{- else }}
|
||||||
serviceName: {{ $fullName }}
|
serviceName: {{ $fullName }}
|
||||||
servicePort: {{ $svcPort }}
|
servicePort: {{ $svcPort }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{{- if .Values.githubWebhookServer.podDisruptionBudget.enabled }}
|
||||||
|
apiVersion: policy/v1beta1
|
||||||
|
kind: PodDisruptionBudget
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
|
name: {{ include "actions-runner-controller-github-webhook-server.pdbName" . }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.githubWebhookServer.podDisruptionBudget.minAvailable }}
|
||||||
|
minAvailable: {{ .Values.githubWebhookServer.podDisruptionBudget.minAvailable }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.githubWebhookServer.podDisruptionBudget.maxUnavailable }}
|
||||||
|
maxUnavailable: {{ .Values.githubWebhookServer.podDisruptionBudget.maxUnavailable }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "actions-runner-controller-github-webhook-server.selectorLabels" . | nindent 6 }}
|
||||||
|
{{- end -}}
|
||||||
@@ -4,14 +4,20 @@ kind: Secret
|
|||||||
metadata:
|
metadata:
|
||||||
name: {{ include "actions-runner-controller.secretName" . }}
|
name: {{ include "actions-runner-controller.secretName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
|
{{- if .Values.authSecret.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{ toYaml .Values.authSecret.annotations | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
labels:
|
labels:
|
||||||
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
data:
|
||||||
{{- if .Values.authSecret.github_app_id }}
|
{{- if .Values.authSecret.github_app_id }}
|
||||||
|
# Keep this as a string as strings integrate better with things like AWS Parameter Store, see PR #882 for an example
|
||||||
github_app_id: {{ .Values.authSecret.github_app_id | toString | b64enc }}
|
github_app_id: {{ .Values.authSecret.github_app_id | toString | b64enc }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if .Values.authSecret.github_app_installation_id }}
|
{{- if .Values.authSecret.github_app_installation_id }}
|
||||||
|
# Keep this as a string as strings integrate better with things like AWS Parameter Store, see PR #882 for an example
|
||||||
github_app_installation_id: {{ .Values.authSecret.github_app_installation_id | toString | b64enc }}
|
github_app_installation_id: {{ .Values.authSecret.github_app_installation_id | toString | b64enc }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if .Values.authSecret.github_app_private_key }}
|
{{- if .Values.authSecret.github_app_private_key }}
|
||||||
@@ -20,4 +26,7 @@ data:
|
|||||||
{{- if .Values.authSecret.github_token }}
|
{{- if .Values.authSecret.github_token }}
|
||||||
github_token: {{ .Values.authSecret.github_token | toString | b64enc }}
|
github_token: {{ .Values.authSecret.github_token | toString | b64enc }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.authSecret.github_basicauth_password }}
|
||||||
|
github_basicauth_password: {{ .Values.authSecret.github_basicauth_password | toString | b64enc }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -5,12 +5,17 @@ kind: MutatingWebhookConfiguration
|
|||||||
metadata:
|
metadata:
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: {{ include "actions-runner-controller.fullname" . }}-mutating-webhook-configuration
|
name: {{ include "actions-runner-controller.fullname" . }}-mutating-webhook-configuration
|
||||||
|
{{- if .Values.certManagerEnabled }}
|
||||||
annotations:
|
annotations:
|
||||||
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" . }}
|
||||||
|
{{- end }}
|
||||||
webhooks:
|
webhooks:
|
||||||
- admissionReviewVersions:
|
- admissionReviewVersions:
|
||||||
- v1beta1
|
- v1beta1
|
||||||
clientConfig:
|
clientConfig:
|
||||||
|
{{- if .Values.admissionWebHooks.caBundle }}
|
||||||
|
caBundle: {{ quote .Values.admissionWebHooks.caBundle }}
|
||||||
|
{{- end }}
|
||||||
service:
|
service:
|
||||||
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -31,6 +36,9 @@ webhooks:
|
|||||||
- admissionReviewVersions:
|
- admissionReviewVersions:
|
||||||
- v1beta1
|
- v1beta1
|
||||||
clientConfig:
|
clientConfig:
|
||||||
|
{{- if .Values.admissionWebHooks.caBundle }}
|
||||||
|
caBundle: {{ .Values.admissionWebHooks.caBundle }}
|
||||||
|
{{- end }}
|
||||||
service:
|
service:
|
||||||
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -51,6 +59,9 @@ webhooks:
|
|||||||
- admissionReviewVersions:
|
- admissionReviewVersions:
|
||||||
- v1beta1
|
- v1beta1
|
||||||
clientConfig:
|
clientConfig:
|
||||||
|
{{- if .Values.admissionWebHooks.caBundle }}
|
||||||
|
caBundle: {{ .Values.admissionWebHooks.caBundle }}
|
||||||
|
{{- end }}
|
||||||
service:
|
service:
|
||||||
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -71,6 +82,9 @@ webhooks:
|
|||||||
- admissionReviewVersions:
|
- admissionReviewVersions:
|
||||||
- v1beta1
|
- v1beta1
|
||||||
clientConfig:
|
clientConfig:
|
||||||
|
{{- if .Values.admissionWebHooks.caBundle }}
|
||||||
|
caBundle: {{ .Values.admissionWebHooks.caBundle }}
|
||||||
|
{{- end }}
|
||||||
service:
|
service:
|
||||||
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -96,12 +110,17 @@ kind: ValidatingWebhookConfiguration
|
|||||||
metadata:
|
metadata:
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: {{ include "actions-runner-controller.fullname" . }}-validating-webhook-configuration
|
name: {{ include "actions-runner-controller.fullname" . }}-validating-webhook-configuration
|
||||||
|
{{- if .Values.certManagerEnabled }}
|
||||||
annotations:
|
annotations:
|
||||||
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" . }}
|
||||||
|
{{- end }}
|
||||||
webhooks:
|
webhooks:
|
||||||
- admissionReviewVersions:
|
- admissionReviewVersions:
|
||||||
- v1beta1
|
- v1beta1
|
||||||
clientConfig:
|
clientConfig:
|
||||||
|
{{- if .Values.admissionWebHooks.caBundle }}
|
||||||
|
caBundle: {{ .Values.admissionWebHooks.caBundle }}
|
||||||
|
{{- end }}
|
||||||
service:
|
service:
|
||||||
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -122,6 +141,9 @@ webhooks:
|
|||||||
- admissionReviewVersions:
|
- admissionReviewVersions:
|
||||||
- v1beta1
|
- v1beta1
|
||||||
clientConfig:
|
clientConfig:
|
||||||
|
{{- if .Values.admissionWebHooks.caBundle }}
|
||||||
|
caBundle: {{ .Values.admissionWebHooks.caBundle }}
|
||||||
|
{{- end }}
|
||||||
service:
|
service:
|
||||||
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -142,6 +164,9 @@ webhooks:
|
|||||||
- admissionReviewVersions:
|
- admissionReviewVersions:
|
||||||
- v1beta1
|
- v1beta1
|
||||||
clientConfig:
|
clientConfig:
|
||||||
|
{{- if .Values.admissionWebHooks.caBundle }}
|
||||||
|
caBundle: {{ .Values.admissionWebHooks.caBundle }}
|
||||||
|
{{- end }}
|
||||||
service:
|
service:
|
||||||
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
name: {{ include "actions-runner-controller.webhookServiceName" . }}
|
||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ metadata:
|
|||||||
namespace: {{ .Release.Namespace }}
|
namespace: {{ .Release.Namespace }}
|
||||||
labels:
|
labels:
|
||||||
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.service.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
spec:
|
spec:
|
||||||
type: {{ .Values.service.type }}
|
type: {{ .Values.service.type }}
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -21,17 +21,34 @@ enableLeaderElection: true
|
|||||||
# The URL of your GitHub Enterprise server, if you're using one.
|
# The URL of your GitHub Enterprise server, if you're using one.
|
||||||
#githubEnterpriseServerURL: https://github.example.com
|
#githubEnterpriseServerURL: https://github.example.com
|
||||||
|
|
||||||
|
# Override GitHub URLs in case of using proxy APIs
|
||||||
|
#githubURL: ""
|
||||||
|
#githubUploadURL: ""
|
||||||
|
#runnerGithubURL: ""
|
||||||
|
|
||||||
# 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
|
||||||
|
#
|
||||||
|
# If authSecret.enabled=true these values are inherited to actions-runner-controller's controller-manager container's env.
|
||||||
|
#
|
||||||
|
# Do set authSecret.enabled=false and set env if you want full control over
|
||||||
|
# the GitHub authn related envvars of the container.
|
||||||
|
# See https://github.com/actions-runner-controller/actions-runner-controller/pull/937 for more details.
|
||||||
authSecret:
|
authSecret:
|
||||||
|
enabled: true
|
||||||
create: false
|
create: false
|
||||||
name: "controller-manager"
|
name: "controller-manager"
|
||||||
|
annotations: {}
|
||||||
### GitHub Apps Configuration
|
### GitHub Apps Configuration
|
||||||
|
## NOTE: IDs MUST be strings, use quotes
|
||||||
#github_app_id: ""
|
#github_app_id: ""
|
||||||
#github_app_installation_id: ""
|
#github_app_installation_id: ""
|
||||||
#github_app_private_key: |
|
#github_app_private_key: |
|
||||||
### GitHub PAT Configuration
|
### GitHub PAT Configuration
|
||||||
#github_token: ""
|
#github_token: ""
|
||||||
|
### Basic auth for github API proxy
|
||||||
|
#github_basicauth_username: ""
|
||||||
|
#github_basicauth_password: ""
|
||||||
|
|
||||||
dockerRegistryMirror: ""
|
dockerRegistryMirror: ""
|
||||||
image:
|
image:
|
||||||
@@ -39,6 +56,9 @@ image:
|
|||||||
actionsRunnerRepositoryAndTag: "summerwind/actions-runner:latest"
|
actionsRunnerRepositoryAndTag: "summerwind/actions-runner:latest"
|
||||||
dindSidecarRepositoryAndTag: "docker:dind"
|
dindSidecarRepositoryAndTag: "docker:dind"
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
# The default image-pull secrets name for self-hosted runner container.
|
||||||
|
# It's added to spec.ImagePullSecrets of self-hosted runner pods.
|
||||||
|
actionsRunnerImagePullSecrets: []
|
||||||
|
|
||||||
imagePullSecrets: []
|
imagePullSecrets: []
|
||||||
nameOverride: ""
|
nameOverride: ""
|
||||||
@@ -70,11 +90,15 @@ securityContext:
|
|||||||
# runAsNonRoot: true
|
# runAsNonRoot: true
|
||||||
# runAsUser: 1000
|
# runAsUser: 1000
|
||||||
|
|
||||||
|
# Webhook service resource
|
||||||
service:
|
service:
|
||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
port: 443
|
port: 443
|
||||||
|
annotations: {}
|
||||||
|
|
||||||
|
# Metrics service resource
|
||||||
metrics:
|
metrics:
|
||||||
|
serviceAnnotations: {}
|
||||||
serviceMonitor: false
|
serviceMonitor: false
|
||||||
serviceMonitorLabels: {}
|
serviceMonitorLabels: {}
|
||||||
port: 8443
|
port: 8443
|
||||||
@@ -82,7 +106,7 @@ metrics:
|
|||||||
enabled: true
|
enabled: true
|
||||||
image:
|
image:
|
||||||
repository: quay.io/brancz/kube-rbac-proxy
|
repository: quay.io/brancz/kube-rbac-proxy
|
||||||
tag: v0.10.0
|
tag: v0.11.0
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
{}
|
{}
|
||||||
@@ -103,6 +127,12 @@ tolerations: []
|
|||||||
|
|
||||||
affinity: {}
|
affinity: {}
|
||||||
|
|
||||||
|
# Only one of minAvailable or maxUnavailable can be set
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: false
|
||||||
|
# minAvailable: 1
|
||||||
|
# maxUnavailable: 3
|
||||||
|
|
||||||
# Leverage a PriorityClass to ensure your pods survive resource shortages
|
# Leverage a PriorityClass to ensure your pods survive resource shortages
|
||||||
# ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/
|
# ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/
|
||||||
# PriorityClass: system-cluster-critical
|
# PriorityClass: system-cluster-critical
|
||||||
@@ -114,6 +144,14 @@ env:
|
|||||||
# https_proxy: "proxy.com:8080"
|
# https_proxy: "proxy.com:8080"
|
||||||
# no_proxy: ""
|
# no_proxy: ""
|
||||||
|
|
||||||
|
## specify additional volumes to mount in the manager container, this can be used
|
||||||
|
## to specify additional storage of material or to inject files from ConfigMaps
|
||||||
|
## into the running container
|
||||||
|
additionalVolumes: []
|
||||||
|
|
||||||
|
## specify where the additional volumes are mounted in the manager container
|
||||||
|
additionalVolumeMounts: []
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
# If true, the controller will only watch custom resources in a single namespace
|
# If true, the controller will only watch custom resources in a single namespace
|
||||||
singleNamespace: false
|
singleNamespace: false
|
||||||
@@ -121,11 +159,19 @@ scope:
|
|||||||
# The default value is "", which means the namespace of the controller
|
# The default value is "", which means the namespace of the controller
|
||||||
watchNamespace: ""
|
watchNamespace: ""
|
||||||
|
|
||||||
|
certManagerEnabled: true
|
||||||
|
|
||||||
|
admissionWebHooks:
|
||||||
|
{}
|
||||||
|
#caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate>...tLS0K"
|
||||||
|
|
||||||
githubWebhookServer:
|
githubWebhookServer:
|
||||||
enabled: false
|
enabled: false
|
||||||
replicaCount: 1
|
replicaCount: 1
|
||||||
syncPeriod: 10m
|
syncPeriod: 10m
|
||||||
|
useRunnerGroupsVisibility: false
|
||||||
secret:
|
secret:
|
||||||
|
enabled: false
|
||||||
create: false
|
create: false
|
||||||
name: "github-webhook-server"
|
name: "github-webhook-server"
|
||||||
### GitHub Webhook Configuration
|
### GitHub Webhook Configuration
|
||||||
@@ -162,14 +208,22 @@ githubWebhookServer:
|
|||||||
#nodePort: someFixedPortForUseWithTerraformCdkCfnEtc
|
#nodePort: someFixedPortForUseWithTerraformCdkCfnEtc
|
||||||
ingress:
|
ingress:
|
||||||
enabled: false
|
enabled: false
|
||||||
annotations:
|
ingressClassName: ""
|
||||||
{}
|
annotations: {}
|
||||||
# kubernetes.io/ingress.class: nginx
|
# kubernetes.io/ingress.class: nginx
|
||||||
# kubernetes.io/tls-acme: "true"
|
# kubernetes.io/tls-acme: "true"
|
||||||
hosts:
|
hosts:
|
||||||
- host: chart-example.local
|
- host: chart-example.local
|
||||||
paths: []
|
paths: []
|
||||||
|
# - path: /*
|
||||||
|
# pathType: ImplementationSpecific
|
||||||
tls: []
|
tls: []
|
||||||
# - secretName: chart-example-tls
|
# - secretName: chart-example-tls
|
||||||
# hosts:
|
# hosts:
|
||||||
# - chart-example.local
|
# - chart-example.local
|
||||||
|
|
||||||
|
# Only one of minAvailable or maxUnavailable can be set
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: false
|
||||||
|
# minAvailable: 1
|
||||||
|
# maxUnavailable: 3
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -27,6 +28,8 @@ import (
|
|||||||
|
|
||||||
actionsv1alpha1 "github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
actionsv1alpha1 "github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/controllers"
|
"github.com/actions-runner-controller/actions-runner-controller/controllers"
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/github"
|
||||||
|
"github.com/kelseyhightower/envconfig"
|
||||||
zaplib "go.uber.org/zap"
|
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"
|
||||||
@@ -48,6 +51,8 @@ const (
|
|||||||
logLevelInfo = "info"
|
logLevelInfo = "info"
|
||||||
logLevelWarn = "warn"
|
logLevelWarn = "warn"
|
||||||
logLevelError = "error"
|
logLevelError = "error"
|
||||||
|
|
||||||
|
webhookSecretTokenEnvName = "GITHUB_WEBHOOK_SECRET_TOKEN"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -66,15 +71,25 @@ func main() {
|
|||||||
|
|
||||||
// The secret token of the GitHub Webhook. See https://docs.github.com/en/developers/webhooks-and-events/securing-your-webhooks
|
// The secret token of the GitHub Webhook. See https://docs.github.com/en/developers/webhooks-and-events/securing-your-webhooks
|
||||||
webhookSecretToken string
|
webhookSecretToken string
|
||||||
|
webhookSecretTokenEnv string
|
||||||
|
|
||||||
watchNamespace string
|
watchNamespace string
|
||||||
|
|
||||||
enableLeaderElection bool
|
enableLeaderElection bool
|
||||||
syncPeriod time.Duration
|
syncPeriod time.Duration
|
||||||
logLevel string
|
logLevel string
|
||||||
|
|
||||||
|
ghClient *github.Client
|
||||||
)
|
)
|
||||||
|
|
||||||
webhookSecretToken = os.Getenv("GITHUB_WEBHOOK_SECRET_TOKEN")
|
var c github.Config
|
||||||
|
err = envconfig.Process("github", &c)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: processing environment variables: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
webhookSecretTokenEnv = os.Getenv(webhookSecretTokenEnvName)
|
||||||
|
|
||||||
flag.StringVar(&webhookAddr, "webhook-addr", ":8000", "The address the metric endpoint binds to.")
|
flag.StringVar(&webhookAddr, "webhook-addr", ":8000", "The address the metric endpoint binds to.")
|
||||||
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
|
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
|
||||||
@@ -83,10 +98,26 @@ func main() {
|
|||||||
"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.StringVar(&logLevel, "log-level", logLevelDebug, `The verbosity of the logging. Valid values are "debug", "info", "warn", "error". Defaults to "debug".`)
|
||||||
|
flag.StringVar(&webhookSecretToken, "github-webhook-secret-token", "", "The personal access token of GitHub.")
|
||||||
|
flag.StringVar(&c.Token, "github-token", c.Token, "The personal access token of GitHub.")
|
||||||
|
flag.Int64Var(&c.AppID, "github-app-id", c.AppID, "The application ID of GitHub App.")
|
||||||
|
flag.Int64Var(&c.AppInstallationID, "github-app-installation-id", c.AppInstallationID, "The installation ID of GitHub App.")
|
||||||
|
flag.StringVar(&c.AppPrivateKey, "github-app-private-key", c.AppPrivateKey, "The path of a private key file to authenticate as a GitHub App")
|
||||||
|
flag.StringVar(&c.URL, "github-url", c.URL, "GitHub URL to be used for GitHub API calls")
|
||||||
|
flag.StringVar(&c.UploadURL, "github-upload-url", c.UploadURL, "GitHub Upload URL to be used for GitHub API calls")
|
||||||
|
flag.StringVar(&c.BasicauthUsername, "github-basicauth-username", c.BasicauthUsername, "Username for GitHub basic auth to use instead of PAT or GitHub APP in case it's running behind a proxy API")
|
||||||
|
flag.StringVar(&c.BasicauthPassword, "github-basicauth-password", c.BasicauthPassword, "Password for GitHub basic auth to use instead of PAT or GitHub APP in case it's running behind a proxy API")
|
||||||
|
flag.StringVar(&c.RunnerGitHubURL, "runner-github-url", c.RunnerGitHubURL, "GitHub URL to be used by runners during registration")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
if webhookSecretToken == "" && webhookSecretTokenEnv != "" {
|
||||||
|
setupLog.Info(fmt.Sprintf("Using the value from %s for -github-webhook-secret-token", webhookSecretTokenEnvName))
|
||||||
|
webhookSecretToken = webhookSecretTokenEnv
|
||||||
|
}
|
||||||
|
|
||||||
if webhookSecretToken == "" {
|
if webhookSecretToken == "" {
|
||||||
setupLog.Info("-webhook-secret-token is missing or empty. Create one following https://docs.github.com/en/developers/webhooks-and-events/securing-your-webhooks")
|
setupLog.Info(fmt.Sprintf("-github-webhook-secret-token and %s are missing or empty. Create one following https://docs.github.com/en/developers/webhooks-and-events/securing-your-webhooks and specify it via the flag or the envvar", webhookSecretTokenEnvName))
|
||||||
}
|
}
|
||||||
|
|
||||||
if watchNamespace == "" {
|
if watchNamespace == "" {
|
||||||
@@ -99,6 +130,8 @@ func main() {
|
|||||||
switch logLevel {
|
switch logLevel {
|
||||||
case logLevelDebug:
|
case logLevelDebug:
|
||||||
o.Development = true
|
o.Development = true
|
||||||
|
lvl := zaplib.NewAtomicLevelAt(-2) // maps to logr's V(2)
|
||||||
|
o.Level = &lvl
|
||||||
case logLevelInfo:
|
case logLevelInfo:
|
||||||
lvl := zaplib.NewAtomicLevelAt(zaplib.InfoLevel)
|
lvl := zaplib.NewAtomicLevelAt(zaplib.InfoLevel)
|
||||||
o.Level = &lvl
|
o.Level = &lvl
|
||||||
@@ -111,6 +144,22 @@ func main() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// In order to support runner groups with custom visibility (selected repositories), we need to perform some GitHub API calls.
|
||||||
|
// Let the user define if they want to opt-in supporting this option by providing the proper GitHub authentication parameters
|
||||||
|
// Without an opt-in, runner groups with custom visibility won't be supported to save API calls
|
||||||
|
// That is, all runner groups managed by ARC are assumed to be visible to any repositories,
|
||||||
|
// which is wrong when you have one or more non-default runner groups in your organization or enterprise.
|
||||||
|
if len(c.Token) > 0 || (c.AppID > 0 && c.AppInstallationID > 0 && c.AppPrivateKey != "") || (len(c.BasicauthUsername) > 0 && len(c.BasicauthPassword) > 0) {
|
||||||
|
ghClient, err = c.NewClient()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "Error: Client creation failed.", err)
|
||||||
|
setupLog.Error(err, "unable to create controller", "controller", "Runner")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setupLog.Info("GitHub client is not initialized. Runner groups with custom visibility are not supported. If needed, please provide GitHub authentication. This will incur in extra GitHub API calls")
|
||||||
|
}
|
||||||
|
|
||||||
ctrl.SetLogger(logger)
|
ctrl.SetLogger(logger)
|
||||||
|
|
||||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
||||||
@@ -127,16 +176,18 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hraGitHubWebhook := &controllers.HorizontalRunnerAutoscalerGitHubWebhook{
|
hraGitHubWebhook := &controllers.HorizontalRunnerAutoscalerGitHubWebhook{
|
||||||
|
Name: "webhookbasedautoscaler",
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Log: ctrl.Log.WithName("controllers").WithName("Runner"),
|
Log: ctrl.Log.WithName("controllers").WithName("webhookbasedautoscaler"),
|
||||||
Recorder: nil,
|
Recorder: nil,
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
SecretKeyBytes: []byte(webhookSecretToken),
|
SecretKeyBytes: []byte(webhookSecretToken),
|
||||||
Namespace: watchNamespace,
|
Namespace: watchNamespace,
|
||||||
|
GitHubClient: ghClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = hraGitHubWebhook.SetupWithManager(mgr); err != nil {
|
if err = hraGitHubWebhook.SetupWithManager(mgr); err != nil {
|
||||||
setupLog.Error(err, "unable to create controller", "controller", "Runner")
|
setupLog.Error(err, "unable to create controller", "controller", "webhookbasedautoscaler")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.6.0
|
controller-gen.kubebuilder.io/version: v0.7.0
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: horizontalrunnerautoscalers.actions.summerwind.dev
|
name: horizontalrunnerautoscalers.actions.summerwind.dev
|
||||||
spec:
|
spec:
|
||||||
@@ -59,7 +59,7 @@ spec:
|
|||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
maxReplicas:
|
maxReplicas:
|
||||||
description: MinReplicas is the maximum number of replicas the deployment is allowed to scale
|
description: MaxReplicas is the maximum number of replicas the deployment is allowed to scale
|
||||||
type: integer
|
type: integer
|
||||||
metrics:
|
metrics:
|
||||||
description: Metrics is the collection of various metric targets to calculate desired number of runners
|
description: Metrics is the collection of various metric targets to calculate desired number of runners
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
|
"github.com/google/go-github/v39/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -164,14 +165,24 @@ func (r *HorizontalRunnerAutoscalerReconciler) suggestReplicasByQueuedAndInProgr
|
|||||||
fallback_cb()
|
fallback_cb()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
jobs, _, err := r.GitHubClient.Actions.ListWorkflowJobs(context.TODO(), user, repoName, runID, nil)
|
opt := github.ListWorkflowJobsOptions{ListOptions: github.ListOptions{PerPage: 50}}
|
||||||
|
var allJobs []*github.WorkflowJob
|
||||||
|
for {
|
||||||
|
jobs, resp, err := r.GitHubClient.Actions.ListWorkflowJobs(context.TODO(), user, repoName, runID, &opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Log.Error(err, "Error listing workflow jobs")
|
r.Log.Error(err, "Error listing workflow jobs")
|
||||||
fallback_cb()
|
return //err
|
||||||
} else if len(jobs.Jobs) == 0 {
|
}
|
||||||
|
allJobs = append(allJobs, jobs.Jobs...)
|
||||||
|
if resp.NextPage == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
opt.Page = resp.NextPage
|
||||||
|
}
|
||||||
|
if len(allJobs) == 0 {
|
||||||
fallback_cb()
|
fallback_cb()
|
||||||
} else {
|
} else {
|
||||||
for _, job := range jobs.Jobs {
|
for _, job := range allJobs {
|
||||||
switch job.GetStatus() {
|
switch job.GetStatus() {
|
||||||
case "completed":
|
case "completed":
|
||||||
// We add a case for `completed` so it is not counted in `unknown`.
|
// We add a case for `completed` so it is not counted in `unknown`.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -29,17 +30,22 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
gogithub "github.com/google/go-github/v37/github"
|
gogithub "github.com/google/go-github/v39/github"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
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/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/github"
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/simulator"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
scaleTargetKey = "scaleTarget"
|
scaleTargetKey = "scaleTarget"
|
||||||
|
|
||||||
|
keyPrefixEnterprise = "enterprises/"
|
||||||
|
keyRunnerGroup = "/group/"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HorizontalRunnerAutoscalerGitHubWebhook autoscales a HorizontalRunnerAutoscaler and the RunnerDeployment on each
|
// HorizontalRunnerAutoscalerGitHubWebhook autoscales a HorizontalRunnerAutoscaler and the RunnerDeployment on each
|
||||||
@@ -54,6 +60,9 @@ 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
|
||||||
|
|
||||||
|
// GitHub Client to discover runner groups assigned to a repository
|
||||||
|
GitHubClient *github.Client
|
||||||
|
|
||||||
// Namespace 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.
|
||||||
@@ -84,7 +93,7 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
msg := err.Error()
|
msg := err.Error()
|
||||||
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 error response", "msg", msg, "written", written)
|
autoscaler.Log.V(1).Error(err, "failed writing http error response", "msg", msg, "written", written)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,6 +107,7 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
|
|
||||||
// respond ok to GET / e.g. for health check
|
// respond ok to GET / e.g. for health check
|
||||||
if r.Method == http.MethodGet {
|
if r.Method == http.MethodGet {
|
||||||
|
ok = true
|
||||||
fmt.Fprintln(w, "webhook server is running")
|
fmt.Fprintln(w, "webhook server is running")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -141,6 +151,20 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
"delivery", r.Header.Get("X-GitHub-Delivery"),
|
"delivery", r.Header.Get("X-GitHub-Delivery"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var enterpriseEvent struct {
|
||||||
|
Enterprise struct {
|
||||||
|
Slug string `json:"slug,omitempty"`
|
||||||
|
} `json:"enterprise,omitempty"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(payload, &enterpriseEvent); err != nil {
|
||||||
|
var s string
|
||||||
|
if payload != nil {
|
||||||
|
s = string(payload)
|
||||||
|
}
|
||||||
|
autoscaler.Log.Error(err, "could not parse webhook payload for extracting enterprise slug", "webhookType", webhookType, "payload", s)
|
||||||
|
}
|
||||||
|
enterpriseSlug := enterpriseEvent.Enterprise.Slug
|
||||||
|
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case *gogithub.PushEvent:
|
case *gogithub.PushEvent:
|
||||||
target, err = autoscaler.getScaleUpTarget(
|
target, err = autoscaler.getScaleUpTarget(
|
||||||
@@ -149,6 +173,9 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
e.Repo.GetName(),
|
e.Repo.GetName(),
|
||||||
e.Repo.Owner.GetLogin(),
|
e.Repo.Owner.GetLogin(),
|
||||||
e.Repo.Owner.GetType(),
|
e.Repo.Owner.GetType(),
|
||||||
|
// Most go-github Event types don't seem to contain Enteprirse(.Slug) fields
|
||||||
|
// we need, so we parse it by ourselves.
|
||||||
|
enterpriseSlug,
|
||||||
autoscaler.MatchPushEvent(e),
|
autoscaler.MatchPushEvent(e),
|
||||||
)
|
)
|
||||||
case *gogithub.PullRequestEvent:
|
case *gogithub.PullRequestEvent:
|
||||||
@@ -158,6 +185,9 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
e.Repo.GetName(),
|
e.Repo.GetName(),
|
||||||
e.Repo.Owner.GetLogin(),
|
e.Repo.Owner.GetLogin(),
|
||||||
e.Repo.Owner.GetType(),
|
e.Repo.Owner.GetType(),
|
||||||
|
// Most go-github Event types don't seem to contain Enteprirse(.Slug) fields
|
||||||
|
// we need, so we parse it by ourselves.
|
||||||
|
enterpriseSlug,
|
||||||
autoscaler.MatchPullRequestEvent(e),
|
autoscaler.MatchPullRequestEvent(e),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -174,6 +204,9 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
e.Repo.GetName(),
|
e.Repo.GetName(),
|
||||||
e.Repo.Owner.GetLogin(),
|
e.Repo.Owner.GetLogin(),
|
||||||
e.Repo.Owner.GetType(),
|
e.Repo.Owner.GetType(),
|
||||||
|
// Most go-github Event types don't seem to contain Enteprirse(.Slug) fields
|
||||||
|
// we need, so we parse it by ourselves.
|
||||||
|
enterpriseSlug,
|
||||||
autoscaler.MatchCheckRunEvent(e),
|
autoscaler.MatchCheckRunEvent(e),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -191,13 +224,14 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
"repository.name", e.Repo.GetName(),
|
"repository.name", e.Repo.GetName(),
|
||||||
"repository.owner.login", e.Repo.Owner.GetLogin(),
|
"repository.owner.login", e.Repo.Owner.GetLogin(),
|
||||||
"repository.owner.type", e.Repo.Owner.GetType(),
|
"repository.owner.type", e.Repo.Owner.GetType(),
|
||||||
|
"enterprise.slug", enterpriseSlug,
|
||||||
"action", e.GetAction(),
|
"action", e.GetAction(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
labels := e.WorkflowJob.Labels
|
labels := e.WorkflowJob.Labels
|
||||||
|
|
||||||
switch e.GetAction() {
|
switch action := e.GetAction(); action {
|
||||||
case "queued", "completed":
|
case "queued", "completed":
|
||||||
target, err = autoscaler.getJobScaleUpTargetForRepoOrOrg(
|
target, err = autoscaler.getJobScaleUpTargetForRepoOrOrg(
|
||||||
context.TODO(),
|
context.TODO(),
|
||||||
@@ -205,6 +239,7 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
e.Repo.GetName(),
|
e.Repo.GetName(),
|
||||||
e.Repo.Owner.GetLogin(),
|
e.Repo.Owner.GetLogin(),
|
||||||
e.Repo.Owner.GetType(),
|
e.Repo.Owner.GetType(),
|
||||||
|
enterpriseSlug,
|
||||||
labels,
|
labels,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -220,7 +255,13 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
ok = true
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
log.V(2).Info("Received and ignored a workflow_job event as it triggers neither scale-up nor scale-down", "action", action)
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
case *gogithub.PingEvent:
|
case *gogithub.PingEvent:
|
||||||
ok = true
|
ok = true
|
||||||
@@ -249,7 +290,7 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) Handle(w http.Respons
|
|||||||
}
|
}
|
||||||
|
|
||||||
if target == nil {
|
if target == nil {
|
||||||
log.Info(
|
log.V(1).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",
|
"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",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -391,7 +432,7 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getScaleTarget(ctx co
|
|||||||
"Found too many scale targets: "+
|
"Found too many scale targets: "+
|
||||||
"It must be exactly one to avoid ambiguity. "+
|
"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, "+
|
"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.",
|
"or update Repository, Organization, or Enterprise fields in your RunnerDeployment resources to fix the ambiguity.",
|
||||||
"scaleTargets", strings.Join(scaleTargetIDs, ","))
|
"scaleTargets", strings.Join(scaleTargetIDs, ","))
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -400,44 +441,31 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getScaleTarget(ctx co
|
|||||||
return &targets[0], nil
|
return &targets[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getScaleUpTarget(ctx context.Context, log logr.Logger, repo, owner, ownerType string, f func(v1alpha1.ScaleUpTrigger) bool) (*ScaleTarget, error) {
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getScaleUpTarget(ctx context.Context, log logr.Logger, repo, owner, ownerType, enterprise string, f func(v1alpha1.ScaleUpTrigger) bool) (*ScaleTarget, error) {
|
||||||
repositoryRunnerKey := owner + "/" + repo
|
scaleTarget := func(value string) (*ScaleTarget, error) {
|
||||||
|
return autoscaler.getScaleTarget(ctx, value, f)
|
||||||
if target, err := autoscaler.getScaleTarget(ctx, repositoryRunnerKey, f); err != nil {
|
|
||||||
log.Info("finding repository-wide runner", "repository", repositoryRunnerKey)
|
|
||||||
return nil, err
|
|
||||||
} else if target != nil {
|
|
||||||
log.Info("scale up target is repository-wide runners", "repository", repo)
|
|
||||||
return target, nil
|
|
||||||
}
|
}
|
||||||
|
return autoscaler.getScaleUpTargetWithFunction(ctx, log, repo, owner, ownerType, enterprise, scaleTarget)
|
||||||
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
|
|
||||||
} else if target != nil {
|
|
||||||
log.Info("scale up target is organizational runners", "organization", owner)
|
|
||||||
return target, nil
|
|
||||||
} else {
|
|
||||||
log.V(1).Info("no repository runner or organizational runner found",
|
|
||||||
"repository", repositoryRunnerKey,
|
|
||||||
"organization", owner,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getJobScaleUpTargetForRepoOrOrg(ctx context.Context, log logr.Logger, repo, owner, ownerType string, labels []string) (*ScaleTarget, error) {
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getJobScaleUpTargetForRepoOrOrg(
|
||||||
|
ctx context.Context, log logr.Logger, repo, owner, ownerType, enterprise string, labels []string,
|
||||||
|
) (*ScaleTarget, error) {
|
||||||
|
|
||||||
|
scaleTarget := func(value string) (*ScaleTarget, error) {
|
||||||
|
return autoscaler.getJobScaleTarget(ctx, value, labels)
|
||||||
|
}
|
||||||
|
return autoscaler.getScaleUpTargetWithFunction(ctx, log, repo, owner, ownerType, enterprise, scaleTarget)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getScaleUpTargetWithFunction(
|
||||||
|
ctx context.Context, log logr.Logger, repo, owner, ownerType, enterprise string, scaleTarget func(value string) (*ScaleTarget, error)) (*ScaleTarget, error) {
|
||||||
|
|
||||||
repositoryRunnerKey := owner + "/" + repo
|
repositoryRunnerKey := owner + "/" + repo
|
||||||
|
|
||||||
if target, err := autoscaler.getJobScaleTarget(ctx, repositoryRunnerKey, labels); err != nil {
|
// Search for repository HRAs
|
||||||
log.Info("finding repository-wide runner", "repository", repositoryRunnerKey)
|
if target, err := scaleTarget(repositoryRunnerKey); err != nil {
|
||||||
|
log.Error(err, "finding repository-wide runner", "repository", repositoryRunnerKey)
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if target != nil {
|
} else if target != nil {
|
||||||
log.Info("job scale up target is repository-wide runners", "repository", repo)
|
log.Info("job scale up target is repository-wide runners", "repository", repo)
|
||||||
@@ -445,25 +473,174 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getJobScaleUpTargetFo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ownerType == "User" {
|
if ownerType == "User" {
|
||||||
log.V(1).Info("no repository runner found", "organization", owner)
|
log.V(1).Info("user repositories not supported", "owner", owner)
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if target, err := autoscaler.getJobScaleTarget(ctx, owner, labels); err != nil {
|
// Find the potential runner groups first to avoid spending API queries needless. Once/if GitHub improves an
|
||||||
log.Info("finding organizational runner", "organization", owner)
|
// API to find related/linked runner groups from a specific repository this logic could be removed
|
||||||
|
managedRunnerGroups, err := autoscaler.getManagedRunnerGroupsFromHRAs(ctx, enterprise, owner)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err, "finding potential organization/enterprise runner groups from HRAs", "organization", owner)
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if target != nil {
|
}
|
||||||
log.Info("job scale up target is organizational runners", "organization", owner)
|
if managedRunnerGroups.IsEmpty() {
|
||||||
return target, nil
|
log.V(1).Info("no repository/organizational/enterprise runner found",
|
||||||
} else {
|
|
||||||
log.V(1).Info("no repository runner or organizational runner found",
|
|
||||||
"repository", repositoryRunnerKey,
|
"repository", repositoryRunnerKey,
|
||||||
"organization", owner,
|
"organization", owner,
|
||||||
|
"enterprises", enterprise,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
log.V(1).Info("Found some runner groups are managed by ARC", "groups", managedRunnerGroups)
|
||||||
|
}
|
||||||
|
|
||||||
|
var visibleGroups *simulator.VisibleRunnerGroups
|
||||||
|
if autoscaler.GitHubClient != nil {
|
||||||
|
simu := &simulator.Simulator{
|
||||||
|
Client: autoscaler.GitHubClient,
|
||||||
|
}
|
||||||
|
// Get available organization runner groups and enterprise runner groups for a repository
|
||||||
|
// These are the sum of runner groups with repository access = All repositories and runner groups
|
||||||
|
// where owner/repo has access to as well. The list will include default runner group also if it has access to
|
||||||
|
visibleGroups, err = simu.GetRunnerGroupsVisibleToRepository(ctx, owner, repositoryRunnerKey, managedRunnerGroups)
|
||||||
|
log.V(1).Info("Searching in runner groups", "groups", visibleGroups)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err, "Unable to find runner groups from repository", "organization", owner, "repository", repo)
|
||||||
|
return nil, fmt.Errorf("error while finding visible runner groups: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For backwards compatibility if GitHub authentication is not configured, we assume all runner groups have
|
||||||
|
// visibility=all to honor the previous implementation, therefore any available enterprise/organization runner
|
||||||
|
// is a potential target for scaling. This will also avoid doing extra API calls caused by
|
||||||
|
// GitHubClient.GetRunnerGroupsVisibleToRepository in case users are not using custom visibility on their runner
|
||||||
|
// groups or they are using only default runner groups
|
||||||
|
visibleGroups = managedRunnerGroups
|
||||||
|
}
|
||||||
|
|
||||||
|
scaleTargetKey := func(rg simulator.RunnerGroup) string {
|
||||||
|
switch rg.Kind {
|
||||||
|
case simulator.Default:
|
||||||
|
switch rg.Scope {
|
||||||
|
case simulator.Organization:
|
||||||
|
return owner
|
||||||
|
case simulator.Enterprise:
|
||||||
|
return enterpriseKey(enterprise)
|
||||||
|
}
|
||||||
|
case simulator.Custom:
|
||||||
|
switch rg.Scope {
|
||||||
|
case simulator.Organization:
|
||||||
|
return organizationalRunnerGroupKey(owner, rg.Name)
|
||||||
|
case simulator.Enterprise:
|
||||||
|
return enterpriseRunnerGroupKey(enterprise, rg.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
log.V(1).Info("groups", "groups", visibleGroups)
|
||||||
|
|
||||||
|
var t *ScaleTarget
|
||||||
|
|
||||||
|
traverseErr := visibleGroups.Traverse(func(rg simulator.RunnerGroup) (bool, error) {
|
||||||
|
key := scaleTargetKey(rg)
|
||||||
|
|
||||||
|
target, err := scaleTarget(key)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err, "finding runner group", "enterprise", enterprise, "organization", owner, "repository", repo, "key", key)
|
||||||
|
return false, err
|
||||||
|
} else if target == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t = target
|
||||||
|
log.V(1).Info("job scale up target found", "enterprise", enterprise, "organization", owner, "repository", repo, "key", key)
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if traverseErr != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if t == nil {
|
||||||
|
log.V(1).Info("no repository/organizational/enterprise runner found",
|
||||||
|
"repository", repositoryRunnerKey,
|
||||||
|
"organization", owner,
|
||||||
|
"enterprise", enterprise,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getManagedRunnerGroupsFromHRAs(ctx context.Context, enterprise, org string) (*simulator.VisibleRunnerGroups, error) {
|
||||||
|
groups := simulator.NewVisibleRunnerGroups()
|
||||||
|
ns := autoscaler.Namespace
|
||||||
|
|
||||||
|
var defaultListOpts []client.ListOption
|
||||||
|
if ns != "" {
|
||||||
|
defaultListOpts = append(defaultListOpts, client.InNamespace(ns))
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := append([]client.ListOption{}, defaultListOpts...)
|
||||||
|
if autoscaler.Namespace != "" {
|
||||||
|
opts = append(opts, client.InNamespace(autoscaler.Namespace))
|
||||||
|
}
|
||||||
|
|
||||||
|
var hraList v1alpha1.HorizontalRunnerAutoscalerList
|
||||||
|
if err := autoscaler.List(ctx, &hraList, opts...); err != nil {
|
||||||
|
return groups, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, hra := range hraList.Items {
|
||||||
|
var o, e, g string
|
||||||
|
|
||||||
|
kind := hra.Spec.ScaleTargetRef.Kind
|
||||||
|
switch kind {
|
||||||
|
case "RunnerSet":
|
||||||
|
var rs v1alpha1.RunnerSet
|
||||||
|
if err := autoscaler.Client.Get(context.Background(), types.NamespacedName{Namespace: hra.Namespace, Name: hra.Spec.ScaleTargetRef.Name}, &rs); err != nil {
|
||||||
|
return groups, err
|
||||||
|
}
|
||||||
|
o, e, g = rs.Spec.Organization, rs.Spec.Enterprise, rs.Spec.Group
|
||||||
|
case "RunnerDeployment", "":
|
||||||
|
var rd v1alpha1.RunnerDeployment
|
||||||
|
if err := autoscaler.Client.Get(context.Background(), types.NamespacedName{Namespace: hra.Namespace, Name: hra.Spec.ScaleTargetRef.Name}, &rd); err != nil {
|
||||||
|
return groups, err
|
||||||
|
}
|
||||||
|
o, e, g = rd.Spec.Template.Spec.Organization, rd.Spec.Template.Spec.Enterprise, rd.Spec.Template.Spec.Group
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported scale target kind: %v", kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
if g == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if e == "" && o == "" {
|
||||||
|
autoscaler.Log.V(1).Info(
|
||||||
|
"invalid runner group config in scale target: spec.group must be set along with either spec.enterprise or spec.organization",
|
||||||
|
"scaleTargetKind", kind,
|
||||||
|
"group", g,
|
||||||
|
"enterprise", e,
|
||||||
|
"organization", o,
|
||||||
|
)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if e != enterprise && o != org {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
rg := simulator.NewRunnerGroupFromProperties(e, o, g)
|
||||||
|
|
||||||
|
if err := groups.Add(rg); err != nil {
|
||||||
|
return groups, fmt.Errorf("failed adding visible group from HRA %s/%s: %w", hra.Namespace, hra.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return groups, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getJobScaleTarget(ctx context.Context, name string, labels []string) (*ScaleTarget, error) {
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) getJobScaleTarget(ctx context.Context, name string, labels []string) (*ScaleTarget, error) {
|
||||||
@@ -508,13 +685,17 @@ HRA:
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(labels) == 1 && labels[0] == "self-hosted" {
|
|
||||||
return &ScaleTarget{HorizontalRunnerAutoscaler: hra, ScaleUpTrigger: v1alpha1.ScaleUpTrigger{Duration: duration}}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that the RunnerSet-managed runners have all the labels requested by the workflow_job.
|
// Ensure that the RunnerSet-managed runners have all the labels requested by the workflow_job.
|
||||||
for _, l := range labels {
|
for _, l := range labels {
|
||||||
var matched bool
|
var matched bool
|
||||||
|
|
||||||
|
// ignore "self-hosted" label as all instance here are self-hosted
|
||||||
|
if l == "self-hosted" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO labels related to OS and architecture needs to be explicitly declared or the current implementation will not be able to find them.
|
||||||
|
|
||||||
for _, l2 := range rs.Spec.Labels {
|
for _, l2 := range rs.Spec.Labels {
|
||||||
if l == l2 {
|
if l == l2 {
|
||||||
matched = true
|
matched = true
|
||||||
@@ -535,13 +716,17 @@ HRA:
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(labels) == 1 && labels[0] == "self-hosted" {
|
|
||||||
return &ScaleTarget{HorizontalRunnerAutoscaler: hra, ScaleUpTrigger: v1alpha1.ScaleUpTrigger{Duration: duration}}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that the RunnerDeployment-managed runners have all the labels requested by the workflow_job.
|
// Ensure that the RunnerDeployment-managed runners have all the labels requested by the workflow_job.
|
||||||
for _, l := range labels {
|
for _, l := range labels {
|
||||||
var matched bool
|
var matched bool
|
||||||
|
|
||||||
|
// ignore "self-hosted" label as all instance here are self-hosted
|
||||||
|
if l == "self-hosted" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO labels related to OS and architecture needs to be explicitly declared or the current implementation will not be able to find them.
|
||||||
|
|
||||||
for _, l2 := range rd.Spec.Template.Spec.Labels {
|
for _, l2 := range rd.Spec.Template.Spec.Labels {
|
||||||
if l == l2 {
|
if l == l2 {
|
||||||
matched = true
|
matched = true
|
||||||
@@ -644,20 +829,56 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) SetupWithManager(mgr
|
|||||||
switch hra.Spec.ScaleTargetRef.Kind {
|
switch hra.Spec.ScaleTargetRef.Kind {
|
||||||
case "", "RunnerDeployment":
|
case "", "RunnerDeployment":
|
||||||
var rd v1alpha1.RunnerDeployment
|
var rd v1alpha1.RunnerDeployment
|
||||||
|
|
||||||
if err := autoscaler.Client.Get(context.Background(), types.NamespacedName{Namespace: hra.Namespace, Name: hra.Spec.ScaleTargetRef.Name}, &rd); err != nil {
|
if err := autoscaler.Client.Get(context.Background(), types.NamespacedName{Namespace: hra.Namespace, Name: hra.Spec.ScaleTargetRef.Name}, &rd); err != nil {
|
||||||
|
autoscaler.Log.V(1).Info(fmt.Sprintf("RunnerDeployment not found with scale target ref name %s for hra %s", hra.Spec.ScaleTargetRef.Name, hra.Name))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return []string{rd.Spec.Template.Spec.Repository, rd.Spec.Template.Spec.Organization}
|
keys := []string{}
|
||||||
|
if rd.Spec.Template.Spec.Repository != "" {
|
||||||
|
keys = append(keys, rd.Spec.Template.Spec.Repository) // Repository runners
|
||||||
|
}
|
||||||
|
if rd.Spec.Template.Spec.Organization != "" {
|
||||||
|
if group := rd.Spec.Template.Spec.Group; group != "" {
|
||||||
|
keys = append(keys, organizationalRunnerGroupKey(rd.Spec.Template.Spec.Organization, rd.Spec.Template.Spec.Group)) // Organization runner groups
|
||||||
|
} else {
|
||||||
|
keys = append(keys, rd.Spec.Template.Spec.Organization) // Organization runners
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if enterprise := rd.Spec.Template.Spec.Enterprise; enterprise != "" {
|
||||||
|
if group := rd.Spec.Template.Spec.Group; group != "" {
|
||||||
|
keys = append(keys, enterpriseRunnerGroupKey(enterprise, rd.Spec.Template.Spec.Group)) // Enterprise runner groups
|
||||||
|
} else {
|
||||||
|
keys = append(keys, enterpriseKey(enterprise)) // Enterprise runners
|
||||||
|
}
|
||||||
|
}
|
||||||
|
autoscaler.Log.V(2).Info(fmt.Sprintf("HRA keys indexed for HRA %s: %v", hra.Name, keys))
|
||||||
|
return keys
|
||||||
case "RunnerSet":
|
case "RunnerSet":
|
||||||
var rs v1alpha1.RunnerSet
|
var rs v1alpha1.RunnerSet
|
||||||
|
|
||||||
if err := autoscaler.Client.Get(context.Background(), types.NamespacedName{Namespace: hra.Namespace, Name: hra.Spec.ScaleTargetRef.Name}, &rs); err != nil {
|
if err := autoscaler.Client.Get(context.Background(), types.NamespacedName{Namespace: hra.Namespace, Name: hra.Spec.ScaleTargetRef.Name}, &rs); err != nil {
|
||||||
|
autoscaler.Log.V(1).Info(fmt.Sprintf("RunnerSet not found with scale target ref name %s for hra %s", hra.Spec.ScaleTargetRef.Name, hra.Name))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return []string{rs.Spec.Repository, rs.Spec.Organization}
|
keys := []string{}
|
||||||
|
if rs.Spec.Repository != "" {
|
||||||
|
keys = append(keys, rs.Spec.Repository) // Repository runners
|
||||||
|
}
|
||||||
|
if rs.Spec.Organization != "" {
|
||||||
|
keys = append(keys, rs.Spec.Organization) // Organization runners
|
||||||
|
if group := rs.Spec.Group; group != "" {
|
||||||
|
keys = append(keys, organizationalRunnerGroupKey(rs.Spec.Organization, rs.Spec.Group)) // Organization runner groups
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if enterprise := rs.Spec.Enterprise; enterprise != "" {
|
||||||
|
keys = append(keys, enterpriseKey(enterprise)) // Enterprise runners
|
||||||
|
if group := rs.Spec.Group; group != "" {
|
||||||
|
keys = append(keys, enterpriseRunnerGroupKey(enterprise, rs.Spec.Group)) // Enterprise runner groups
|
||||||
|
}
|
||||||
|
}
|
||||||
|
autoscaler.Log.V(2).Info(fmt.Sprintf("HRA keys indexed for HRA %s: %v", hra.Name, keys))
|
||||||
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -670,3 +891,15 @@ func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) SetupWithManager(mgr
|
|||||||
Named(name).
|
Named(name).
|
||||||
Complete(autoscaler)
|
Complete(autoscaler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func enterpriseKey(name string) string {
|
||||||
|
return keyPrefixEnterprise + name
|
||||||
|
}
|
||||||
|
|
||||||
|
func organizationalRunnerGroupKey(owner, group string) string {
|
||||||
|
return owner + keyRunnerGroup + group
|
||||||
|
}
|
||||||
|
|
||||||
|
func enterpriseRunnerGroupKey(enterprise, group string) string {
|
||||||
|
return keyPrefixEnterprise + enterprise + keyRunnerGroup + group
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/pkg/actionsglob"
|
"github.com/actions-runner-controller/actions-runner-controller/pkg/actionsglob"
|
||||||
"github.com/google/go-github/v37/github"
|
"github.com/google/go-github/v39/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) MatchCheckRunEvent(event *github.CheckRunEvent) func(scaleUpTrigger v1alpha1.ScaleUpTrigger) bool {
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) MatchCheckRunEvent(event *github.CheckRunEvent) func(scaleUpTrigger v1alpha1.ScaleUpTrigger) bool {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
"github.com/google/go-github/v37/github"
|
"github.com/google/go-github/v39/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) MatchPullRequestEvent(event *github.PullRequestEvent) func(scaleUpTrigger v1alpha1.ScaleUpTrigger) bool {
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) MatchPullRequestEvent(event *github.PullRequestEvent) func(scaleUpTrigger v1alpha1.ScaleUpTrigger) bool {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
"github.com/google/go-github/v37/github"
|
"github.com/google/go-github/v39/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) MatchPushEvent(event *github.PushEvent) func(scaleUpTrigger v1alpha1.ScaleUpTrigger) bool {
|
func (autoscaler *HorizontalRunnerAutoscalerGitHubWebhook) MatchPushEvent(event *github.PushEvent) func(scaleUpTrigger v1alpha1.ScaleUpTrigger) bool {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
|
|
||||||
actionsv1alpha1 "github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
actionsv1alpha1 "github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
"github.com/google/go-github/v37/github"
|
"github.com/google/go-github/v39/github"
|
||||||
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"
|
||||||
@@ -253,6 +253,145 @@ func TestWebhookWorkflowJob(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWebhookWorkflowJobWithSelfHostedLabel(t *testing.T) {
|
||||||
|
setupTest := func() github.WorkflowJobEvent {
|
||||||
|
f, err := os.Open("testdata/org_webhook_workflow_job_with_self_hosted_label_payload.json")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not open the fixture: %s", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
var e github.WorkflowJobEvent
|
||||||
|
if err := json.NewDecoder(f).Decode(&e); err != nil {
|
||||||
|
t.Fatalf("invalid json: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
t.Run("Successful", func(t *testing.T) {
|
||||||
|
e := setupTest()
|
||||||
|
hra := &actionsv1alpha1.HorizontalRunnerAutoscaler{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-name",
|
||||||
|
},
|
||||||
|
Spec: actionsv1alpha1.HorizontalRunnerAutoscalerSpec{
|
||||||
|
ScaleTargetRef: actionsv1alpha1.ScaleTargetRef{
|
||||||
|
Name: "test-name",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rd := &actionsv1alpha1.RunnerDeployment{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-name",
|
||||||
|
},
|
||||||
|
Spec: actionsv1alpha1.RunnerDeploymentSpec{
|
||||||
|
Template: actionsv1alpha1.RunnerTemplate{
|
||||||
|
Spec: actionsv1alpha1.RunnerSpec{
|
||||||
|
RunnerConfig: actionsv1alpha1.RunnerConfig{
|
||||||
|
Organization: "MYORG",
|
||||||
|
Labels: []string{"label1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
initObjs := []runtime.Object{hra, rd}
|
||||||
|
|
||||||
|
testServerWithInitObjs(t,
|
||||||
|
"workflow_job",
|
||||||
|
&e,
|
||||||
|
200,
|
||||||
|
"scaled test-name by 1",
|
||||||
|
initObjs,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
t.Run("WrongLabels", func(t *testing.T) {
|
||||||
|
e := setupTest()
|
||||||
|
hra := &actionsv1alpha1.HorizontalRunnerAutoscaler{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-name",
|
||||||
|
},
|
||||||
|
Spec: actionsv1alpha1.HorizontalRunnerAutoscalerSpec{
|
||||||
|
ScaleTargetRef: actionsv1alpha1.ScaleTargetRef{
|
||||||
|
Name: "test-name",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rd := &actionsv1alpha1.RunnerDeployment{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-name",
|
||||||
|
},
|
||||||
|
Spec: actionsv1alpha1.RunnerDeploymentSpec{
|
||||||
|
Template: actionsv1alpha1.RunnerTemplate{
|
||||||
|
Spec: actionsv1alpha1.RunnerSpec{
|
||||||
|
RunnerConfig: actionsv1alpha1.RunnerConfig{
|
||||||
|
Organization: "MYORG",
|
||||||
|
Labels: []string{"bad-label"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
initObjs := []runtime.Object{hra, rd}
|
||||||
|
|
||||||
|
testServerWithInitObjs(t,
|
||||||
|
"workflow_job",
|
||||||
|
&e,
|
||||||
|
200,
|
||||||
|
"no horizontalrunnerautoscaler to scale for this github event",
|
||||||
|
initObjs,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
// This test verifies that the old way of matching labels doesn't work anymore
|
||||||
|
t.Run("OldLabels", func(t *testing.T) {
|
||||||
|
e := setupTest()
|
||||||
|
hra := &actionsv1alpha1.HorizontalRunnerAutoscaler{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-name",
|
||||||
|
},
|
||||||
|
Spec: actionsv1alpha1.HorizontalRunnerAutoscalerSpec{
|
||||||
|
ScaleTargetRef: actionsv1alpha1.ScaleTargetRef{
|
||||||
|
Name: "test-name",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rd := &actionsv1alpha1.RunnerDeployment{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-name",
|
||||||
|
},
|
||||||
|
Spec: actionsv1alpha1.RunnerDeploymentSpec{
|
||||||
|
Template: actionsv1alpha1.RunnerTemplate{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"label1": "label1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: actionsv1alpha1.RunnerSpec{
|
||||||
|
RunnerConfig: actionsv1alpha1.RunnerConfig{
|
||||||
|
Organization: "MYORG",
|
||||||
|
Labels: []string{"bad-label"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
initObjs := []runtime.Object{hra, rd}
|
||||||
|
|
||||||
|
testServerWithInitObjs(t,
|
||||||
|
"workflow_job",
|
||||||
|
&e,
|
||||||
|
200,
|
||||||
|
"no horizontalrunnerautoscaler to scale for this github event",
|
||||||
|
initObjs,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetRequest(t *testing.T) {
|
func TestGetRequest(t *testing.T) {
|
||||||
hra := HorizontalRunnerAutoscalerGitHubWebhook{}
|
hra := HorizontalRunnerAutoscalerGitHubWebhook{}
|
||||||
request, _ := http.NewRequest(http.MethodGet, "/", nil)
|
request, _ := http.NewRequest(http.MethodGet, "/", nil)
|
||||||
@@ -306,12 +445,14 @@ func TestGetValidCapacityReservations(t *testing.T) {
|
|||||||
func installTestLogger(webhook *HorizontalRunnerAutoscalerGitHubWebhook) *bytes.Buffer {
|
func installTestLogger(webhook *HorizontalRunnerAutoscalerGitHubWebhook) *bytes.Buffer {
|
||||||
logs := &bytes.Buffer{}
|
logs := &bytes.Buffer{}
|
||||||
|
|
||||||
log := testLogger{
|
sink := &testLogSink{
|
||||||
name: "testlog",
|
name: "testlog",
|
||||||
writer: logs,
|
writer: logs,
|
||||||
}
|
}
|
||||||
|
|
||||||
webhook.Log = &log
|
log := logr.New(sink)
|
||||||
|
|
||||||
|
webhook.Log = log
|
||||||
|
|
||||||
return logs
|
return logs
|
||||||
}
|
}
|
||||||
@@ -398,18 +539,22 @@ func sendWebhook(server *httptest.Server, eventType string, event interface{}) (
|
|||||||
return http.DefaultClient.Do(req)
|
return http.DefaultClient.Do(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// testLogger is a sample logr.Logger that logs in-memory.
|
// testLogSink is a sample logr.Logger that logs in-memory.
|
||||||
// It's only for testing log outputs.
|
// It's only for testing log outputs.
|
||||||
type testLogger struct {
|
type testLogSink struct {
|
||||||
name string
|
name string
|
||||||
keyValues map[string]interface{}
|
keyValues map[string]interface{}
|
||||||
|
|
||||||
writer io.Writer
|
writer io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ logr.Logger = &testLogger{}
|
var _ logr.LogSink = &testLogSink{}
|
||||||
|
|
||||||
func (l *testLogger) Info(msg string, kvs ...interface{}) {
|
func (l *testLogSink) Init(_ logr.RuntimeInfo) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *testLogSink) Info(_ int, msg string, kvs ...interface{}) {
|
||||||
fmt.Fprintf(l.writer, "%s] %s\t", l.name, msg)
|
fmt.Fprintf(l.writer, "%s] %s\t", l.name, msg)
|
||||||
for k, v := range l.keyValues {
|
for k, v := range l.keyValues {
|
||||||
fmt.Fprintf(l.writer, "%s=%+v ", k, v)
|
fmt.Fprintf(l.writer, "%s=%+v ", k, v)
|
||||||
@@ -420,28 +565,24 @@ func (l *testLogger) Info(msg string, kvs ...interface{}) {
|
|||||||
fmt.Fprintf(l.writer, "\n")
|
fmt.Fprintf(l.writer, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ *testLogger) Enabled() bool {
|
func (_ *testLogSink) Enabled(level int) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *testLogger) Error(err error, msg string, kvs ...interface{}) {
|
func (l *testLogSink) Error(err error, msg string, kvs ...interface{}) {
|
||||||
kvs = append(kvs, "error", err)
|
kvs = append(kvs, "error", err)
|
||||||
l.Info(msg, kvs...)
|
l.Info(0, msg, kvs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *testLogger) V(_ int) logr.InfoLogger {
|
func (l *testLogSink) WithName(name string) logr.LogSink {
|
||||||
return l
|
return &testLogSink{
|
||||||
}
|
|
||||||
|
|
||||||
func (l *testLogger) WithName(name string) logr.Logger {
|
|
||||||
return &testLogger{
|
|
||||||
name: l.name + "." + name,
|
name: l.name + "." + name,
|
||||||
keyValues: l.keyValues,
|
keyValues: l.keyValues,
|
||||||
writer: l.writer,
|
writer: l.writer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *testLogger) WithValues(kvs ...interface{}) logr.Logger {
|
func (l *testLogSink) WithValues(kvs ...interface{}) logr.LogSink {
|
||||||
newMap := make(map[string]interface{}, len(l.keyValues)+len(kvs)/2)
|
newMap := make(map[string]interface{}, len(l.keyValues)+len(kvs)/2)
|
||||||
for k, v := range l.keyValues {
|
for k, v := range l.keyValues {
|
||||||
newMap[k] = v
|
newMap[k] = v
|
||||||
@@ -449,7 +590,7 @@ func (l *testLogger) WithValues(kvs ...interface{}) logr.Logger {
|
|||||||
for i := 0; i < len(kvs); i += 2 {
|
for i := 0; i < len(kvs); i += 2 {
|
||||||
newMap[kvs[i].(string)] = kvs[i+1]
|
newMap[kvs[i].(string)] = kvs[i+1]
|
||||||
}
|
}
|
||||||
return &testLogger{
|
return &testLogSink{
|
||||||
name: l.name,
|
name: l.name,
|
||||||
keyValues: newMap,
|
keyValues: newMap,
|
||||||
writer: l.writer,
|
writer: l.writer,
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ import (
|
|||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/github"
|
"github.com/actions-runner-controller/actions-runner-controller/github"
|
||||||
|
"github.com/go-logr/logr"
|
||||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
github2 "github.com/actions-runner-controller/actions-runner-controller/github"
|
github2 "github.com/actions-runner-controller/actions-runner-controller/github"
|
||||||
"github.com/google/go-github/v37/github"
|
"github.com/google/go-github/v39/github"
|
||||||
|
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/github/fake"
|
"github.com/actions-runner-controller/actions-runner-controller/github/fake"
|
||||||
|
|
||||||
@@ -1077,6 +1077,169 @@ var _ = Context("INTEGRATION: Inside of a new namespace", func() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("should be able to scale visible organization runner group with default labels", func() {
|
||||||
|
name := "example-runnerdeploy"
|
||||||
|
|
||||||
|
{
|
||||||
|
rd := &actionsv1alpha1.RunnerDeployment{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Namespace: ns.Name,
|
||||||
|
},
|
||||||
|
Spec: actionsv1alpha1.RunnerDeploymentSpec{
|
||||||
|
Replicas: intPtr(1),
|
||||||
|
Selector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Template: actionsv1alpha1.RunnerTemplate{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: actionsv1alpha1.RunnerSpec{
|
||||||
|
RunnerConfig: actionsv1alpha1.RunnerConfig{
|
||||||
|
Repository: "test/valid",
|
||||||
|
Image: "bar",
|
||||||
|
Group: "baz",
|
||||||
|
},
|
||||||
|
RunnerPodSpec: actionsv1alpha1.RunnerPodSpec{
|
||||||
|
Env: []corev1.EnvVar{
|
||||||
|
{Name: "FOO", Value: "FOOVALUE"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpectCreate(ctx, rd, "test RunnerDeployment")
|
||||||
|
|
||||||
|
hra := &actionsv1alpha1.HorizontalRunnerAutoscaler{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Namespace: ns.Name,
|
||||||
|
},
|
||||||
|
Spec: actionsv1alpha1.HorizontalRunnerAutoscalerSpec{
|
||||||
|
ScaleTargetRef: actionsv1alpha1.ScaleTargetRef{
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
MinReplicas: intPtr(1),
|
||||||
|
MaxReplicas: intPtr(5),
|
||||||
|
ScaleDownDelaySecondsAfterScaleUp: intPtr(1),
|
||||||
|
ScaleUpTriggers: []actionsv1alpha1.ScaleUpTrigger{
|
||||||
|
{
|
||||||
|
GitHubEvent: &actionsv1alpha1.GitHubEventScaleUpTriggerSpec{},
|
||||||
|
Amount: 1,
|
||||||
|
Duration: metav1.Duration{Duration: time.Minute},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpectCreate(ctx, hra, "test HorizontalRunnerAutoscaler")
|
||||||
|
|
||||||
|
ExpectRunnerSetsCountEventuallyEquals(ctx, ns.Name, 1)
|
||||||
|
ExpectRunnerSetsManagedReplicasCountEventuallyEquals(ctx, ns.Name, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
env.ExpectRegisteredNumberCountEventuallyEquals(1, "count of fake list runners")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale-up to 2 replicas on first workflow_job webhook event
|
||||||
|
{
|
||||||
|
env.SendWorkflowJobEvent("test", "valid", "pending", "created", []string{"self-hosted"})
|
||||||
|
ExpectRunnerSetsCountEventuallyEquals(ctx, ns.Name, 1, "runner sets after webhook")
|
||||||
|
ExpectRunnerSetsManagedReplicasCountEventuallyEquals(ctx, ns.Name, 2, "runners after first webhook event")
|
||||||
|
env.ExpectRegisteredNumberCountEventuallyEquals(2, "count of fake list runners")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should be able to scale visible organization runner group with custom labels", func() {
|
||||||
|
name := "example-runnerdeploy"
|
||||||
|
|
||||||
|
{
|
||||||
|
rd := &actionsv1alpha1.RunnerDeployment{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Namespace: ns.Name,
|
||||||
|
},
|
||||||
|
Spec: actionsv1alpha1.RunnerDeploymentSpec{
|
||||||
|
Replicas: intPtr(1),
|
||||||
|
Selector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Template: actionsv1alpha1.RunnerTemplate{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: actionsv1alpha1.RunnerSpec{
|
||||||
|
RunnerConfig: actionsv1alpha1.RunnerConfig{
|
||||||
|
Repository: "test/valid",
|
||||||
|
Image: "bar",
|
||||||
|
Group: "baz",
|
||||||
|
Labels: []string{"custom-label"},
|
||||||
|
},
|
||||||
|
RunnerPodSpec: actionsv1alpha1.RunnerPodSpec{
|
||||||
|
Env: []corev1.EnvVar{
|
||||||
|
{Name: "FOO", Value: "FOOVALUE"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpectCreate(ctx, rd, "test RunnerDeployment")
|
||||||
|
|
||||||
|
hra := &actionsv1alpha1.HorizontalRunnerAutoscaler{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Namespace: ns.Name,
|
||||||
|
},
|
||||||
|
Spec: actionsv1alpha1.HorizontalRunnerAutoscalerSpec{
|
||||||
|
ScaleTargetRef: actionsv1alpha1.ScaleTargetRef{
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
MinReplicas: intPtr(1),
|
||||||
|
MaxReplicas: intPtr(5),
|
||||||
|
ScaleDownDelaySecondsAfterScaleUp: intPtr(1),
|
||||||
|
ScaleUpTriggers: []actionsv1alpha1.ScaleUpTrigger{
|
||||||
|
{
|
||||||
|
GitHubEvent: &actionsv1alpha1.GitHubEventScaleUpTriggerSpec{},
|
||||||
|
Amount: 1,
|
||||||
|
Duration: metav1.Duration{Duration: time.Minute},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpectCreate(ctx, hra, "test HorizontalRunnerAutoscaler")
|
||||||
|
|
||||||
|
ExpectRunnerSetsCountEventuallyEquals(ctx, ns.Name, 1)
|
||||||
|
ExpectRunnerSetsManagedReplicasCountEventuallyEquals(ctx, ns.Name, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
env.ExpectRegisteredNumberCountEventuallyEquals(1, "count of fake list runners")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale-up to 2 replicas on first workflow_job webhook event
|
||||||
|
{
|
||||||
|
env.SendWorkflowJobEvent("test", "valid", "pending", "created", []string{"custom-label"})
|
||||||
|
ExpectRunnerSetsCountEventuallyEquals(ctx, ns.Name, 1, "runner sets after webhook")
|
||||||
|
ExpectRunnerSetsManagedReplicasCountEventuallyEquals(ctx, ns.Name, 2, "runners after first webhook event")
|
||||||
|
env.ExpectRegisteredNumberCountEventuallyEquals(2, "count of fake list runners")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1208,6 +1371,28 @@ func (env *testEnvironment) SendUserCheckRunEvent(owner, repo, status, action st
|
|||||||
ExpectWithOffset(1, resp.StatusCode).To(Equal(200))
|
ExpectWithOffset(1, resp.StatusCode).To(Equal(200))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (env *testEnvironment) SendWorkflowJobEvent(owner, repo, status, action string, labels []string) {
|
||||||
|
resp, err := sendWebhook(env.webhookServer, "workflow_job", &github.WorkflowJobEvent{
|
||||||
|
Org: &github.Organization{
|
||||||
|
Name: github.String(owner),
|
||||||
|
},
|
||||||
|
WorkflowJob: &github.WorkflowJob{
|
||||||
|
Labels: labels,
|
||||||
|
},
|
||||||
|
Action: github.String("queued"),
|
||||||
|
Repo: &github.Repository{
|
||||||
|
Name: github.String(repo),
|
||||||
|
Owner: &github.User{
|
||||||
|
Login: github.String(owner),
|
||||||
|
Type: github.String("Organization"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
ExpectWithOffset(1, err).NotTo(HaveOccurred(), "failed to send check_run event")
|
||||||
|
|
||||||
|
ExpectWithOffset(1, resp.StatusCode).To(Equal(200))
|
||||||
|
}
|
||||||
func (env *testEnvironment) SyncRunnerRegistrations() {
|
func (env *testEnvironment) SyncRunnerRegistrations() {
|
||||||
var runnerList actionsv1alpha1.RunnerList
|
var runnerList actionsv1alpha1.RunnerList
|
||||||
|
|
||||||
|
|||||||
@@ -24,15 +24,16 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/hash"
|
"github.com/actions-runner-controller/actions-runner-controller/hash"
|
||||||
gogithub "github.com/google/go-github/v37/github"
|
"github.com/go-logr/logr"
|
||||||
|
gogithub "github.com/google/go-github/v39/github"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
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"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
|
|
||||||
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"
|
||||||
@@ -65,6 +66,7 @@ type RunnerReconciler struct {
|
|||||||
Scheme *runtime.Scheme
|
Scheme *runtime.Scheme
|
||||||
GitHubClient *github.Client
|
GitHubClient *github.Client
|
||||||
RunnerImage string
|
RunnerImage string
|
||||||
|
RunnerImagePullSecrets []string
|
||||||
DockerImage string
|
DockerImage string
|
||||||
DockerRegistryMirror string
|
DockerRegistryMirror string
|
||||||
Name string
|
Name string
|
||||||
@@ -108,48 +110,8 @@ func (r *RunnerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
|
|||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
finalizers, removed := removeFinalizer(runner.ObjectMeta.Finalizers, finalizerName)
|
// Request to remove a runner. DeletionTimestamp was set in the runner - we need to unregister runner
|
||||||
|
return r.processRunnerDeletion(runner, ctx, log)
|
||||||
if removed {
|
|
||||||
if len(runner.Status.Registration.Token) > 0 {
|
|
||||||
ok, err := r.unregisterRunner(ctx, runner.Spec.Enterprise, runner.Spec.Organization, runner.Spec.Repository, runner.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")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.V(1).Info("Runner was never registered on GitHub")
|
|
||||||
}
|
|
||||||
|
|
||||||
newRunner := runner.DeepCopy()
|
|
||||||
newRunner.ObjectMeta.Finalizers = finalizers
|
|
||||||
|
|
||||||
if err := r.Patch(ctx, newRunner, client.MergeFrom(&runner)); err != nil {
|
|
||||||
log.Error(err, "Failed to update runner for finalizer removal")
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Removed runner from GitHub", "repository", runner.Spec.Repository, "organization", runner.Spec.Organization)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registrationOnly := metav1.HasAnnotation(runner.ObjectMeta, annotationKeyRegistrationOnly)
|
registrationOnly := metav1.HasAnnotation(runner.ObjectMeta, annotationKeyRegistrationOnly)
|
||||||
@@ -173,7 +135,7 @@ func (r *RunnerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Successfully deleted egistration-only runner pod to free node and cluster resource")
|
log.Info("Successfully deleted registration-only runner pod to free node and cluster resource")
|
||||||
|
|
||||||
// Return here to not recreate the deleted pod, because recreating it is the waste of cluster and node resource,
|
// Return here to not recreate the deleted pod, because recreating it is the waste of cluster and node resource,
|
||||||
// and also defeats the original purpose of scale-from/to-zero we're trying to implement by using the registration-only runner.
|
// and also defeats the original purpose of scale-from/to-zero we're trying to implement by using the registration-only runner.
|
||||||
@@ -183,75 +145,16 @@ func (r *RunnerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
|
|||||||
var pod corev1.Pod
|
var pod corev1.Pod
|
||||||
if err := r.Get(ctx, req.NamespacedName, &pod); err != nil {
|
if err := r.Get(ctx, req.NamespacedName, &pod); err != nil {
|
||||||
if !kerrors.IsNotFound(err) {
|
if !kerrors.IsNotFound(err) {
|
||||||
|
// An error ocurred
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
|
return r.processRunnerCreation(ctx, runner, log)
|
||||||
if updated, err := r.updateRegistrationToken(ctx, runner); err != nil {
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
} else if updated {
|
|
||||||
return ctrl.Result{Requeue: true}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newPod, err := r.newPod(runner)
|
// Pod already exists
|
||||||
if err != nil {
|
|
||||||
log.Error(err, "Could not create pod")
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := r.Create(ctx, &newPod); err != nil {
|
|
||||||
if kerrors.IsAlreadyExists(err) {
|
|
||||||
// Gracefully handle pod-already-exists errors due to informer cache delay.
|
|
||||||
// Without this we got a few errors like the below on new runner pod:
|
|
||||||
// 2021-03-16T00:23:10.116Z ERROR controller-runtime.controller Reconciler error {"controller": "runner-controller", "request": "default/example-runnerdeploy-b2g2g-j4mcp", "error": "pods \"example-runnerdeploy-b2g2g-j4mcp\" already exists"}
|
|
||||||
log.Info(
|
|
||||||
"Failed to create pod due to AlreadyExists error. Probably this pod has been already created in previous reconcilation but is still not in the informer cache. Will retry on pod created. If it doesn't repeat, there's no problem",
|
|
||||||
)
|
|
||||||
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Error(err, "Failed to create pod resource")
|
|
||||||
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
r.Recorder.Event(&runner, corev1.EventTypeNormal, "PodCreated", fmt.Sprintf("Created pod '%s'", newPod.Name))
|
|
||||||
log.Info("Created runner pod", "repository", runner.Spec.Repository)
|
|
||||||
} else {
|
|
||||||
if !pod.ObjectMeta.DeletionTimestamp.IsZero() {
|
if !pod.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||||
deletionTimeout := 1 * time.Minute
|
return r.processRunnerPodDeletion(ctx, runner, log, pod)
|
||||||
currentTime := time.Now()
|
|
||||||
deletionDidTimeout := currentTime.Sub(pod.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", pod.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, &pod, &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(&runner, corev1.EventTypeNormal, "PodDeleted", fmt.Sprintf("Forcefully deleted pod '%s'", pod.Name))
|
|
||||||
log.Info("Forcefully deleted runner pod", "repository", runner.Spec.Repository)
|
|
||||||
// give kube manager a little time to forcefully delete the stuck pod
|
|
||||||
return ctrl.Result{RequeueAfter: 3 * time.Second}, err
|
|
||||||
} else {
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If pod has ended up succeeded we need to restart it
|
// If pod has ended up succeeded we need to restart it
|
||||||
@@ -422,6 +325,15 @@ func (r *RunnerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
|
|||||||
"configuredRegistrationTimeout", registrationTimeout,
|
"configuredRegistrationTimeout", registrationTimeout,
|
||||||
)
|
)
|
||||||
} else if registrationDidTimeout {
|
} else if registrationDidTimeout {
|
||||||
|
if runnerBusy {
|
||||||
|
log.Info(
|
||||||
|
"Timeout out while waiting for the runner to be online, but observed that it's busy at the same time."+
|
||||||
|
"This is a known (unintuitive) behaviour of a runner that is already running a job. Please see https://github.com/actions-runner-controller/actions-runner-controller/issues/911",
|
||||||
|
"podCreationTimestamp", pod.CreationTimestamp,
|
||||||
|
"currentTime", currentTime,
|
||||||
|
"configuredRegistrationTimeout", registrationTimeout,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
log.Info(
|
log.Info(
|
||||||
"Already existing GitHub runner still appears offline . "+
|
"Already existing GitHub runner still appears offline . "+
|
||||||
"Recreating the pod to see if it resolves the issue. "+
|
"Recreating the pod to see if it resolves the issue. "+
|
||||||
@@ -432,6 +344,7 @@ func (r *RunnerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
|
|||||||
)
|
)
|
||||||
|
|
||||||
restart = true
|
restart = true
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.V(1).Info(
|
log.V(1).Info(
|
||||||
"Runner pod exists but the GitHub runner appears to be still offline. Waiting for runner to get online ...",
|
"Runner pod exists but the GitHub runner appears to be still offline. Waiting for runner to get online ...",
|
||||||
@@ -499,8 +412,122 @@ func (r *RunnerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
|
|||||||
|
|
||||||
r.Recorder.Event(&runner, corev1.EventTypeNormal, "PodDeleted", fmt.Sprintf("Deleted pod '%s'", newPod.Name))
|
r.Recorder.Event(&runner, corev1.EventTypeNormal, "PodDeleted", fmt.Sprintf("Deleted pod '%s'", newPod.Name))
|
||||||
log.Info("Deleted runner pod", "repository", runner.Spec.Repository)
|
log.Info("Deleted runner pod", "repository", runner.Spec.Repository)
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RunnerReconciler) processRunnerDeletion(runner v1alpha1.Runner, ctx context.Context, log logr.Logger) (reconcile.Result, error) {
|
||||||
|
finalizers, removed := removeFinalizer(runner.ObjectMeta.Finalizers, finalizerName)
|
||||||
|
|
||||||
|
if removed {
|
||||||
|
if len(runner.Status.Registration.Token) > 0 {
|
||||||
|
ok, err := r.unregisterRunner(ctx, runner.Spec.Enterprise, runner.Spec.Organization, runner.Spec.Repository, runner.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")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.V(1).Info("Runner was never registered on GitHub")
|
||||||
|
}
|
||||||
|
|
||||||
|
newRunner := runner.DeepCopy()
|
||||||
|
newRunner.ObjectMeta.Finalizers = finalizers
|
||||||
|
|
||||||
|
if err := r.Patch(ctx, newRunner, client.MergeFrom(&runner)); err != nil {
|
||||||
|
log.Error(err, "Failed to update runner for finalizer removal")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Removed runner from GitHub", "repository", runner.Spec.Repository, "organization", runner.Spec.Organization)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RunnerReconciler) processRunnerPodDeletion(ctx context.Context, runner v1alpha1.Runner, log logr.Logger, pod corev1.Pod) (reconcile.Result, error) {
|
||||||
|
deletionTimeout := 1 * time.Minute
|
||||||
|
currentTime := time.Now()
|
||||||
|
deletionDidTimeout := currentTime.Sub(pod.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", pod.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, &pod, &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(&runner, corev1.EventTypeNormal, "PodDeleted", fmt.Sprintf("Forcefully deleted pod '%s'", pod.Name))
|
||||||
|
log.Info("Forcefully deleted runner pod", "repository", runner.Spec.Repository)
|
||||||
|
// give kube manager a little time to forcefully delete the stuck pod
|
||||||
|
return ctrl.Result{RequeueAfter: 3 * time.Second}, nil
|
||||||
|
} else {
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RunnerReconciler) processRunnerCreation(ctx context.Context, runner v1alpha1.Runner, log logr.Logger) (reconcile.Result, error) {
|
||||||
|
if updated, err := r.updateRegistrationToken(ctx, runner); err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
} else if updated {
|
||||||
|
return ctrl.Result{Requeue: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newPod, err := r.newPod(runner)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err, "Could not create pod")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.Create(ctx, &newPod); err != nil {
|
||||||
|
if kerrors.IsAlreadyExists(err) {
|
||||||
|
// Gracefully handle pod-already-exists errors due to informer cache delay.
|
||||||
|
// Without this we got a few errors like the below on new runner pod:
|
||||||
|
// 2021-03-16T00:23:10.116Z ERROR controller-runtime.controller Reconciler error {"controller": "runner-controller", "request": "default/example-runnerdeploy-b2g2g-j4mcp", "error": "pods \"example-runnerdeploy-b2g2g-j4mcp\" already exists"}
|
||||||
|
log.Info(
|
||||||
|
"Failed to create pod due to AlreadyExists error. Probably this pod has been already created in previous reconcilation but is still not in the informer cache. Will retry on pod created. If it doesn't repeat, there's no problem",
|
||||||
|
)
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Error(err, "Failed to create pod resource")
|
||||||
|
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Recorder.Event(&runner, corev1.EventTypeNormal, "PodCreated", fmt.Sprintf("Created pod '%s'", newPod.Name))
|
||||||
|
log.Info("Created runner pod", "repository", runner.Spec.Repository)
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,6 +651,7 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
|||||||
Name: "docker",
|
Name: "docker",
|
||||||
VolumeMounts: runner.Spec.DockerVolumeMounts,
|
VolumeMounts: runner.Spec.DockerVolumeMounts,
|
||||||
Resources: runner.Spec.DockerdContainerResources,
|
Resources: runner.Spec.DockerdContainerResources,
|
||||||
|
Env: runner.Spec.DockerEnv,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -635,7 +663,7 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
|||||||
|
|
||||||
registrationOnly := metav1.HasAnnotation(runner.ObjectMeta, annotationKeyRegistrationOnly)
|
registrationOnly := metav1.HasAnnotation(runner.ObjectMeta, annotationKeyRegistrationOnly)
|
||||||
|
|
||||||
pod, err := newRunnerPod(template, runner.Spec.RunnerConfig, r.RunnerImage, r.DockerImage, r.DockerRegistryMirror, r.GitHubClient.GithubBaseURL, registrationOnly)
|
pod, err := newRunnerPod(template, runner.Spec.RunnerConfig, r.RunnerImage, r.RunnerImagePullSecrets, r.DockerImage, r.DockerRegistryMirror, r.GitHubClient.GithubBaseURL, registrationOnly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return pod, err
|
return pod, err
|
||||||
}
|
}
|
||||||
@@ -644,10 +672,29 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
|||||||
runnerSpec := runner.Spec
|
runnerSpec := runner.Spec
|
||||||
|
|
||||||
if len(runnerSpec.VolumeMounts) != 0 {
|
if len(runnerSpec.VolumeMounts) != 0 {
|
||||||
|
// if operater provides a work volume mount, use that
|
||||||
|
isPresent, _ := workVolumeMountPresent(runnerSpec.VolumeMounts)
|
||||||
|
if isPresent {
|
||||||
|
// remove work volume since it will be provided from runnerSpec.Volumes
|
||||||
|
// if we don't remove it here we would get a duplicate key error, i.e. two volumes named work
|
||||||
|
_, index := workVolumeMountPresent(pod.Spec.Containers[0].VolumeMounts)
|
||||||
|
pod.Spec.Containers[0].VolumeMounts = append(pod.Spec.Containers[0].VolumeMounts[:index], pod.Spec.Containers[0].VolumeMounts[index+1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
pod.Spec.Containers[0].VolumeMounts = append(pod.Spec.Containers[0].VolumeMounts, runnerSpec.VolumeMounts...)
|
pod.Spec.Containers[0].VolumeMounts = append(pod.Spec.Containers[0].VolumeMounts, runnerSpec.VolumeMounts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(runnerSpec.Volumes) != 0 {
|
if len(runnerSpec.Volumes) != 0 {
|
||||||
|
// if operator provides a work volume. use that
|
||||||
|
isPresent, _ := workVolumePresent(runnerSpec.Volumes)
|
||||||
|
if isPresent {
|
||||||
|
_, index := workVolumePresent(pod.Spec.Volumes)
|
||||||
|
|
||||||
|
// remove work volume since it will be provided from runnerSpec.Volumes
|
||||||
|
// if we don't remove it here we would get a duplicate key error, i.e. two volumes named work
|
||||||
|
pod.Spec.Volumes = append(pod.Spec.Volumes[:index], pod.Spec.Volumes[index+1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
pod.Spec.Volumes = append(pod.Spec.Volumes, runnerSpec.Volumes...)
|
pod.Spec.Volumes = append(pod.Spec.Volumes, runnerSpec.Volumes...)
|
||||||
}
|
}
|
||||||
if len(runnerSpec.InitContainers) != 0 {
|
if len(runnerSpec.InitContainers) != 0 {
|
||||||
@@ -680,6 +727,10 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
|||||||
pod.Spec.Tolerations = runnerSpec.Tolerations
|
pod.Spec.Tolerations = runnerSpec.Tolerations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(runnerSpec.TopologySpreadConstraints) != 0 {
|
||||||
|
pod.Spec.TopologySpreadConstraints = runnerSpec.TopologySpreadConstraints
|
||||||
|
}
|
||||||
|
|
||||||
if len(runnerSpec.EphemeralContainers) != 0 {
|
if len(runnerSpec.EphemeralContainers) != 0 {
|
||||||
pod.Spec.EphemeralContainers = runnerSpec.EphemeralContainers
|
pod.Spec.EphemeralContainers = runnerSpec.EphemeralContainers
|
||||||
}
|
}
|
||||||
@@ -729,7 +780,7 @@ func mutatePod(pod *corev1.Pod, token string) *corev1.Pod {
|
|||||||
return updated
|
return updated
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRunnerPod(template corev1.Pod, runnerSpec v1alpha1.RunnerConfig, defaultRunnerImage, defaultDockerImage, defaultDockerRegistryMirror string, githubBaseURL string, registrationOnly bool) (corev1.Pod, error) {
|
func newRunnerPod(template corev1.Pod, runnerSpec v1alpha1.RunnerConfig, defaultRunnerImage string, defaultRunnerImagePullSecrets []string, defaultDockerImage, defaultDockerRegistryMirror string, githubBaseURL string, registrationOnly bool) (corev1.Pod, error) {
|
||||||
var (
|
var (
|
||||||
privileged bool = true
|
privileged bool = true
|
||||||
dockerdInRunner bool = runnerSpec.DockerdWithinRunnerContainer != nil && *runnerSpec.DockerdWithinRunnerContainer
|
dockerdInRunner bool = runnerSpec.DockerdWithinRunnerContainer != nil && *runnerSpec.DockerdWithinRunnerContainer
|
||||||
@@ -750,6 +801,8 @@ func newRunnerPod(template corev1.Pod, runnerSpec v1alpha1.RunnerConfig, default
|
|||||||
dockerRegistryMirror = *runnerSpec.DockerRegistryMirror
|
dockerRegistryMirror = *runnerSpec.DockerRegistryMirror
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Be aware some of the environment variables are used
|
||||||
|
// in the runner entrypoint script
|
||||||
env := []corev1.EnvVar{
|
env := []corev1.EnvVar{
|
||||||
{
|
{
|
||||||
Name: EnvVarOrg,
|
Name: EnvVarOrg,
|
||||||
@@ -771,6 +824,10 @@ func newRunnerPod(template corev1.Pod, runnerSpec v1alpha1.RunnerConfig, default
|
|||||||
Name: "RUNNER_GROUP",
|
Name: "RUNNER_GROUP",
|
||||||
Value: runnerSpec.Group,
|
Value: runnerSpec.Group,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "DOCKER_ENABLED",
|
||||||
|
Value: fmt.Sprintf("%v", dockerEnabled || dockerdInRunner),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "DOCKERD_IN_RUNNER",
|
Name: "DOCKERD_IN_RUNNER",
|
||||||
Value: fmt.Sprintf("%v", dockerdInRunner),
|
Value: fmt.Sprintf("%v", dockerdInRunner),
|
||||||
@@ -872,6 +929,15 @@ func newRunnerPod(template corev1.Pod, runnerSpec v1alpha1.RunnerConfig, default
|
|||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(pod.Spec.ImagePullSecrets) == 0 && len(defaultRunnerImagePullSecrets) > 0 {
|
||||||
|
// runner spec didn't provide custom values and default image pull secrets are provided
|
||||||
|
for _, imagePullSecret := range defaultRunnerImagePullSecrets {
|
||||||
|
pod.Spec.ImagePullSecrets = append(pod.Spec.ImagePullSecrets, corev1.LocalObjectReference{
|
||||||
|
Name: imagePullSecret,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if dockerRegistryMirror != "" && dockerdInRunner {
|
if dockerRegistryMirror != "" && dockerdInRunner {
|
||||||
runnerContainer.Env = append(runnerContainer.Env, []corev1.EnvVar{
|
runnerContainer.Env = append(runnerContainer.Env, []corev1.EnvVar{
|
||||||
{
|
{
|
||||||
@@ -944,6 +1010,7 @@ func newRunnerPod(template corev1.Pod, runnerSpec v1alpha1.RunnerConfig, default
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
runnerContainer.VolumeMounts = append(runnerContainer.VolumeMounts,
|
runnerContainer.VolumeMounts = append(runnerContainer.VolumeMounts,
|
||||||
corev1.VolumeMount{
|
corev1.VolumeMount{
|
||||||
Name: "work",
|
Name: "work",
|
||||||
@@ -955,6 +1022,7 @@ func newRunnerPod(template corev1.Pod, runnerSpec v1alpha1.RunnerConfig, default
|
|||||||
ReadOnly: true,
|
ReadOnly: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
runnerContainer.Env = append(runnerContainer.Env, []corev1.EnvVar{
|
runnerContainer.Env = append(runnerContainer.Env, []corev1.EnvVar{
|
||||||
{
|
{
|
||||||
Name: "DOCKER_HOST",
|
Name: "DOCKER_HOST",
|
||||||
@@ -973,10 +1041,6 @@ func newRunnerPod(template corev1.Pod, runnerSpec v1alpha1.RunnerConfig, default
|
|||||||
// Determine the volume mounts assigned to the docker sidecar. In case extra mounts are included in the RunnerSpec, append them to the standard
|
// Determine the volume mounts assigned to the docker sidecar. In case extra mounts are included in the RunnerSpec, append them to the standard
|
||||||
// set of mounts. See https://github.com/actions-runner-controller/actions-runner-controller/issues/435 for context.
|
// set of mounts. See https://github.com/actions-runner-controller/actions-runner-controller/issues/435 for context.
|
||||||
dockerVolumeMounts := []corev1.VolumeMount{
|
dockerVolumeMounts := []corev1.VolumeMount{
|
||||||
{
|
|
||||||
Name: "work",
|
|
||||||
MountPath: workDir,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: runnerVolumeName,
|
Name: runnerVolumeName,
|
||||||
MountPath: runnerVolumeMountPath,
|
MountPath: runnerVolumeMountPath,
|
||||||
@@ -987,6 +1051,14 @@ func newRunnerPod(template corev1.Pod, runnerSpec v1alpha1.RunnerConfig, default
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mountPresent, _ := workVolumeMountPresent(dockerdContainer.VolumeMounts)
|
||||||
|
if !mountPresent {
|
||||||
|
dockerVolumeMounts = append(dockerVolumeMounts, corev1.VolumeMount{
|
||||||
|
Name: "work",
|
||||||
|
MountPath: workDir,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if dockerdContainer.Image == "" {
|
if dockerdContainer.Image == "" {
|
||||||
dockerdContainer.Image = defaultDockerImage
|
dockerdContainer.Image = defaultDockerImage
|
||||||
}
|
}
|
||||||
@@ -1092,3 +1164,21 @@ func removeFinalizer(finalizers []string, finalizerName string) ([]string, bool)
|
|||||||
|
|
||||||
return result, removed
|
return result, removed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func workVolumePresent(items []corev1.Volume) (bool, int) {
|
||||||
|
for index, item := range items {
|
||||||
|
if item.Name == "work" {
|
||||||
|
return true, index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func workVolumeMountPresent(items []corev1.VolumeMount) (bool, int) {
|
||||||
|
for index, item := range items {
|
||||||
|
if item.Name == "work" {
|
||||||
|
return true, index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, 0
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
gogithub "github.com/google/go-github/v37/github"
|
"github.com/go-logr/logr"
|
||||||
|
gogithub "github.com/google/go-github/v39/github"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
gogithub "github.com/google/go-github/v37/github"
|
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
|
gogithub "github.com/google/go-github/v39/github"
|
||||||
|
|
||||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
@@ -117,6 +117,17 @@ func (r *RunnerReplicaSetReconciler) Reconcile(ctx context.Context, req ctrl.Req
|
|||||||
desired = 1
|
desired = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove this registration runner cleanup later (v0.23.0 or v0.24.0)
|
||||||
|
//
|
||||||
|
// We had to have a registration-only runner to support scale-from-zero before.
|
||||||
|
// But since Sep 2021 Actions update on GitHub Cloud and GHES 3.3, it is unneceesary.
|
||||||
|
// See the below issues for more contexts:
|
||||||
|
// https://github.com/actions-runner-controller/actions-runner-controller/issues/516
|
||||||
|
// https://github.com/actions-runner-controller/actions-runner-controller/issues/859
|
||||||
|
//
|
||||||
|
// In the below block, we have a logic to remove existing registration-only runners as unnecessary.
|
||||||
|
// This logic is introduced since actions-runner-controller 0.21.0 and probably last one or two minor releases
|
||||||
|
// so that actions-runner-controller instance in everyone's cluster won't leave dangling registration-only runners.
|
||||||
registrationOnlyRunnerNsName := req.NamespacedName
|
registrationOnlyRunnerNsName := req.NamespacedName
|
||||||
registrationOnlyRunnerNsName.Name = registrationOnlyRunnerNameFor(rs.Name)
|
registrationOnlyRunnerNsName.Name = registrationOnlyRunnerNameFor(rs.Name)
|
||||||
registrationOnlyRunner := v1alpha1.Runner{}
|
registrationOnlyRunner := v1alpha1.Runner{}
|
||||||
@@ -133,46 +144,6 @@ func (r *RunnerReplicaSetReconciler) Reconcile(ctx context.Context, req ctrl.Req
|
|||||||
registrationOnlyRunnerExists = true
|
registrationOnlyRunnerExists = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// On scale to zero, we must have fully registered registration-only runner before we start deleting other runners, hence `desired == 0`
|
|
||||||
// On scale from zero, we must retain the registratoin-only runner until one or more other runners get registered, hence `registrationOnlyRunnerExists && available == 0`.
|
|
||||||
// On RunnerReplicaSet creation, it have always 0 replics and no registration-only runner.
|
|
||||||
// In this case We don't need to bother creating a registration-only runner which gets deleted soon after we have 1 or more available repolicas,
|
|
||||||
// hence it's not `available == 0`, but `registrationOnlyRunnerExists && available == 0`.
|
|
||||||
// See https://github.com/actions-runner-controller/actions-runner-controller/issues/516
|
|
||||||
registrationOnlyRunnerNeeded := desired == 0 || (registrationOnlyRunnerExists && current == 0)
|
|
||||||
|
|
||||||
if registrationOnlyRunnerNeeded {
|
|
||||||
if registrationOnlyRunnerExists {
|
|
||||||
if registrationOnlyRunner.Status.Phase == "" {
|
|
||||||
log.Info("Still waiting for the registration-only runner to be registered")
|
|
||||||
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// A registration-only runner does not exist and is needed, hence create it.
|
|
||||||
|
|
||||||
runnerForScaleFromToZero, err := r.newRunner(rs)
|
|
||||||
if err != nil {
|
|
||||||
return ctrl.Result{}, fmt.Errorf("failed to create runner for scale from/to zero: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
runnerForScaleFromToZero.ObjectMeta.Name = registrationOnlyRunnerNsName.Name
|
|
||||||
runnerForScaleFromToZero.ObjectMeta.GenerateName = ""
|
|
||||||
runnerForScaleFromToZero.ObjectMeta.Labels = nil
|
|
||||||
metav1.SetMetaDataAnnotation(&runnerForScaleFromToZero.ObjectMeta, annotationKeyRegistrationOnly, "true")
|
|
||||||
|
|
||||||
if err := r.Client.Create(ctx, &runnerForScaleFromToZero); err != nil {
|
|
||||||
log.Error(err, "Failed to create runner for scale from/to zero")
|
|
||||||
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can continue to deleting runner pods only after the
|
|
||||||
// registration-only runner gets registered.
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// A registration-only runner exists and is not needed, hence delete it.
|
|
||||||
if registrationOnlyRunnerExists {
|
if registrationOnlyRunnerExists {
|
||||||
if err := r.Client.Delete(ctx, ®istrationOnlyRunner); err != nil {
|
if err := r.Client.Delete(ctx, ®istrationOnlyRunner); err != nil {
|
||||||
log.Error(err, "Retrying soon because we failed to delete registration-only runner")
|
log.Error(err, "Retrying soon because we failed to delete registration-only runner")
|
||||||
@@ -180,7 +151,6 @@ func (r *RunnerReplicaSetReconciler) Reconcile(ctx context.Context, req ctrl.Req
|
|||||||
return ctrl.Result{Requeue: true}, nil
|
return ctrl.Result{Requeue: true}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if current > desired {
|
if current > desired {
|
||||||
n := current - desired
|
n := current - desired
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"time"
|
"time"
|
||||||
@@ -257,22 +256,6 @@ var _ = Context("Inside of a new namespace", func() {
|
|||||||
})
|
})
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
var regOnly actionsv1alpha1.Runner
|
|
||||||
if err := k8sClient.Get(ctx, types.NamespacedName{Namespace: ns.Name, Name: registrationOnlyRunnerNameFor(name)}, ®Only); err != nil {
|
|
||||||
logf.Log.Info(fmt.Sprintf("Failed getting registration-only runner in test: %v", err))
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
updated := regOnly.DeepCopy()
|
|
||||||
updated.Status.Phase = "Completed"
|
|
||||||
|
|
||||||
if err := k8sClient.Status().Patch(ctx, updated, client.MergeFrom(®Only)); err != nil {
|
|
||||||
logf.Log.Info(fmt.Sprintf("Failed updating registration-only runner in test: %v", err))
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
runnersList.AddOffline([]actionsv1alpha1.Runner{*updated})
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := k8sClient.List(ctx, &runners, client.InNamespace(ns.Name), client.MatchingLabelsSelector{Selector: selector}); err != nil {
|
if err := k8sClient.List(ctx, &runners, client.InNamespace(ns.Name), client.MatchingLabelsSelector{Selector: selector}); err != nil {
|
||||||
logf.Log.Error(err, "list runners")
|
logf.Log.Error(err, "list runners")
|
||||||
return -1
|
return -1
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
@@ -36,6 +35,7 @@ import (
|
|||||||
|
|
||||||
"github.com/actions-runner-controller/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"
|
"github.com/actions-runner-controller/actions-runner-controller/controllers/metrics"
|
||||||
|
"github.com/go-logr/logr"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -54,6 +54,7 @@ type RunnerSetReconciler struct {
|
|||||||
CommonRunnerLabels []string
|
CommonRunnerLabels []string
|
||||||
GitHubBaseURL string
|
GitHubBaseURL string
|
||||||
RunnerImage string
|
RunnerImage string
|
||||||
|
RunnerImagePullSecrets []string
|
||||||
DockerImage string
|
DockerImage string
|
||||||
DockerRegistryMirror string
|
DockerRegistryMirror string
|
||||||
}
|
}
|
||||||
@@ -137,8 +138,7 @@ func (r *RunnerSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
|
|||||||
log.Error(err, "Failed to patch statefulset", "reason", errors.ReasonForError(err))
|
log.Error(err, "Failed to patch statefulset", "reason", errors.ReasonForError(err))
|
||||||
|
|
||||||
if errors.IsInvalid(err) {
|
if errors.IsInvalid(err) {
|
||||||
// NOTE: This might not be ideal but deal the forbidden error by recreating the statefulset
|
// NOTE: This might not be ideal but is currently required to deal with the forbidden error by recreating the statefulset
|
||||||
// Probably we'd better create a registration-only runner to prevent queued jobs from immediately failing.
|
|
||||||
//
|
//
|
||||||
// 2021-06-13T07:19:52.760Z ERROR actions-runner-controller.runnerset Failed to patch statefulset
|
// 2021-06-13T07:19:52.760Z ERROR actions-runner-controller.runnerset Failed to patch statefulset
|
||||||
// {"runnerset": "default/example-runnerset", "error": "StatefulSet.apps \"example-runnerset\" is invalid: s
|
// {"runnerset": "default/example-runnerset", "error": "StatefulSet.apps \"example-runnerset\" is invalid: s
|
||||||
@@ -259,7 +259,7 @@ func (r *RunnerSetReconciler) newStatefulSet(runnerSet *v1alpha1.RunnerSet) (*ap
|
|||||||
Spec: runnerSetWithOverrides.StatefulSetSpec.Template.Spec,
|
Spec: runnerSetWithOverrides.StatefulSetSpec.Template.Spec,
|
||||||
}
|
}
|
||||||
|
|
||||||
pod, err := newRunnerPod(template, runnerSet.Spec.RunnerConfig, r.RunnerImage, r.DockerImage, r.DockerRegistryMirror, r.GitHubBaseURL, false)
|
pod, err := newRunnerPod(template, runnerSet.Spec.RunnerConfig, r.RunnerImage, r.RunnerImagePullSecrets, r.DockerImage, r.DockerRegistryMirror, r.GitHubBaseURL, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
152
controllers/testdata/org_webhook_workflow_job_with_self_hosted_label_payload.json
vendored
Normal file
152
controllers/testdata/org_webhook_workflow_job_with_self_hosted_label_payload.json
vendored
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
{
|
||||||
|
"action": "queued",
|
||||||
|
"workflow_job": {
|
||||||
|
"id": 1234567890,
|
||||||
|
"run_id": 1234567890,
|
||||||
|
"run_url": "https://api.github.com/repos/MYORG/MYREPO/actions/runs/1234567890",
|
||||||
|
"node_id": "CR_kwDOGCados7e1x2g",
|
||||||
|
"head_sha": "1234567890123456789012345678901234567890",
|
||||||
|
"url": "https://api.github.com/repos/MYORG/MYREPO/actions/jobs/1234567890",
|
||||||
|
"html_url": "https://github.com/MYORG/MYREPO/runs/1234567890",
|
||||||
|
"status": "queued",
|
||||||
|
"conclusion": null,
|
||||||
|
"started_at": "2021-09-28T23:45:29Z",
|
||||||
|
"completed_at": null,
|
||||||
|
"name": "build",
|
||||||
|
"steps": [],
|
||||||
|
"check_run_url": "https://api.github.com/repos/MYORG/MYREPO/check-runs/1234567890",
|
||||||
|
"labels": [
|
||||||
|
"self-hosted",
|
||||||
|
"label1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"id": 1234567890,
|
||||||
|
"node_id": "ABCDEFGHIJKLMNOPQRSTUVWXYZ=",
|
||||||
|
"name": "MYREPO",
|
||||||
|
"full_name": "MYORG/MYREPO",
|
||||||
|
"private": true,
|
||||||
|
"owner": {
|
||||||
|
"login": "MYORG",
|
||||||
|
"id": 1234567890,
|
||||||
|
"node_id": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/1234567890?v=4",
|
||||||
|
"gravatar_id": "",
|
||||||
|
"url": "https://api.github.com/users/MYORG",
|
||||||
|
"html_url": "https://github.com/MYORG",
|
||||||
|
"followers_url": "https://api.github.com/users/MYORG/followers",
|
||||||
|
"following_url": "https://api.github.com/users/MYORG/following{/other_user}",
|
||||||
|
"gists_url": "https://api.github.com/users/MYORG/gists{/gist_id}",
|
||||||
|
"starred_url": "https://api.github.com/users/MYORG/starred{/owner}{/repo}",
|
||||||
|
"subscriptions_url": "https://api.github.com/users/MYORG/subscriptions",
|
||||||
|
"organizations_url": "https://api.github.com/users/MYORG/orgs",
|
||||||
|
"repos_url": "https://api.github.com/users/MYORG/repos",
|
||||||
|
"events_url": "https://api.github.com/users/MYORG/events{/privacy}",
|
||||||
|
"received_events_url": "https://api.github.com/users/MYORG/received_events",
|
||||||
|
"type": "Organization",
|
||||||
|
"site_admin": false
|
||||||
|
},
|
||||||
|
"html_url": "https://github.com/MYORG/MYREPO",
|
||||||
|
"description": "MYREPO",
|
||||||
|
"fork": false,
|
||||||
|
"url": "https://api.github.com/repos/MYORG/MYREPO",
|
||||||
|
"forks_url": "https://api.github.com/repos/MYORG/MYREPO/forks",
|
||||||
|
"keys_url": "https://api.github.com/repos/MYORG/MYREPO/keys{/key_id}",
|
||||||
|
"collaborators_url": "https://api.github.com/repos/MYORG/MYREPO/collaborators{/collaborator}",
|
||||||
|
"teams_url": "https://api.github.com/repos/MYORG/MYREPO/teams",
|
||||||
|
"hooks_url": "https://api.github.com/repos/MYORG/MYREPO/hooks",
|
||||||
|
"issue_events_url": "https://api.github.com/repos/MYORG/MYREPO/issues/events{/number}",
|
||||||
|
"events_url": "https://api.github.com/repos/MYORG/MYREPO/events",
|
||||||
|
"assignees_url": "https://api.github.com/repos/MYORG/MYREPO/assignees{/user}",
|
||||||
|
"branches_url": "https://api.github.com/repos/MYORG/MYREPO/branches{/branch}",
|
||||||
|
"tags_url": "https://api.github.com/repos/MYORG/MYREPO/tags",
|
||||||
|
"blobs_url": "https://api.github.com/repos/MYORG/MYREPO/git/blobs{/sha}",
|
||||||
|
"git_tags_url": "https://api.github.com/repos/MYORG/MYREPO/git/tags{/sha}",
|
||||||
|
"git_refs_url": "https://api.github.com/repos/MYORG/MYREPO/git/refs{/sha}",
|
||||||
|
"trees_url": "https://api.github.com/repos/MYORG/MYREPO/git/trees{/sha}",
|
||||||
|
"statuses_url": "https://api.github.com/repos/MYORG/MYREPO/statuses/{sha}",
|
||||||
|
"languages_url": "https://api.github.com/repos/MYORG/MYREPO/languages",
|
||||||
|
"stargazers_url": "https://api.github.com/repos/MYORG/MYREPO/stargazers",
|
||||||
|
"contributors_url": "https://api.github.com/repos/MYORG/MYREPO/contributors",
|
||||||
|
"subscribers_url": "https://api.github.com/repos/MYORG/MYREPO/subscribers",
|
||||||
|
"subscription_url": "https://api.github.com/repos/MYORG/MYREPO/subscription",
|
||||||
|
"commits_url": "https://api.github.com/repos/MYORG/MYREPO/commits{/sha}",
|
||||||
|
"git_commits_url": "https://api.github.com/repos/MYORG/MYREPO/git/commits{/sha}",
|
||||||
|
"comments_url": "https://api.github.com/repos/MYORG/MYREPO/comments{/number}",
|
||||||
|
"issue_comment_url": "https://api.github.com/repos/MYORG/MYREPO/issues/comments{/number}",
|
||||||
|
"contents_url": "https://api.github.com/repos/MYORG/MYREPO/contents/{+path}",
|
||||||
|
"compare_url": "https://api.github.com/repos/MYORG/MYREPO/compare/{base}...{head}",
|
||||||
|
"merges_url": "https://api.github.com/repos/MYORG/MYREPO/merges",
|
||||||
|
"archive_url": "https://api.github.com/repos/MYORG/MYREPO/{archive_format}{/ref}",
|
||||||
|
"downloads_url": "https://api.github.com/repos/MYORG/MYREPO/downloads",
|
||||||
|
"issues_url": "https://api.github.com/repos/MYORG/MYREPO/issues{/number}",
|
||||||
|
"pulls_url": "https://api.github.com/repos/MYORG/MYREPO/pulls{/number}",
|
||||||
|
"milestones_url": "https://api.github.com/repos/MYORG/MYREPO/milestones{/number}",
|
||||||
|
"notifications_url": "https://api.github.com/repos/MYORG/MYREPO/notifications{?since,all,participating}",
|
||||||
|
"labels_url": "https://api.github.com/repos/MYORG/MYREPO/labels{/name}",
|
||||||
|
"releases_url": "https://api.github.com/repos/MYORG/MYREPO/releases{/id}",
|
||||||
|
"deployments_url": "https://api.github.com/repos/MYORG/MYREPO/deployments",
|
||||||
|
"created_at": "2021-09-10T18:55:38Z",
|
||||||
|
"updated_at": "2021-09-10T18:55:41Z",
|
||||||
|
"pushed_at": "2021-09-28T23:25:26Z",
|
||||||
|
"git_url": "git://github.com/MYORG/MYREPO.git",
|
||||||
|
"ssh_url": "git@github.com:MYORG/MYREPO.git",
|
||||||
|
"clone_url": "https://github.com/MYORG/MYREPO.git",
|
||||||
|
"svn_url": "https://github.com/MYORG/MYREPO",
|
||||||
|
"homepage": null,
|
||||||
|
"size": 121,
|
||||||
|
"stargazers_count": 0,
|
||||||
|
"watchers_count": 0,
|
||||||
|
"language": null,
|
||||||
|
"has_issues": true,
|
||||||
|
"has_projects": true,
|
||||||
|
"has_downloads": true,
|
||||||
|
"has_wiki": true,
|
||||||
|
"has_pages": false,
|
||||||
|
"forks_count": 0,
|
||||||
|
"mirror_url": null,
|
||||||
|
"archived": false,
|
||||||
|
"disabled": false,
|
||||||
|
"open_issues_count": 1,
|
||||||
|
"license": null,
|
||||||
|
"allow_forking": false,
|
||||||
|
"forks": 0,
|
||||||
|
"open_issues": 1,
|
||||||
|
"watchers": 0,
|
||||||
|
"default_branch": "master"
|
||||||
|
},
|
||||||
|
"organization": {
|
||||||
|
"login": "MYORG",
|
||||||
|
"id": 1234567890,
|
||||||
|
"node_id": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||||
|
"url": "https://api.github.com/orgs/MYORG",
|
||||||
|
"repos_url": "https://api.github.com/orgs/MYORG/repos",
|
||||||
|
"events_url": "https://api.github.com/orgs/MYORG/events",
|
||||||
|
"hooks_url": "https://api.github.com/orgs/MYORG/hooks",
|
||||||
|
"issues_url": "https://api.github.com/orgs/MYORG/issues",
|
||||||
|
"members_url": "https://api.github.com/orgs/MYORG/members{/member}",
|
||||||
|
"public_members_url": "https://api.github.com/orgs/MYORG/public_members{/member}",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/1234567890?v=4",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"sender": {
|
||||||
|
"login": "MYNAME",
|
||||||
|
"id": 1234567890,
|
||||||
|
"node_id": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/1234567890?v=4",
|
||||||
|
"gravatar_id": "",
|
||||||
|
"url": "https://api.github.com/users/MYNAME",
|
||||||
|
"html_url": "https://github.com/MYNAME",
|
||||||
|
"followers_url": "https://api.github.com/users/MYNAME/followers",
|
||||||
|
"following_url": "https://api.github.com/users/MYNAME/following{/other_user}",
|
||||||
|
"gists_url": "https://api.github.com/users/MYNAME/gists{/gist_id}",
|
||||||
|
"starred_url": "https://api.github.com/users/MYNAME/starred{/owner}{/repo}",
|
||||||
|
"subscriptions_url": "https://api.github.com/users/MYNAME/subscriptions",
|
||||||
|
"organizations_url": "https://api.github.com/users/MYNAME/orgs",
|
||||||
|
"repos_url": "https://api.github.com/users/MYNAME/repos",
|
||||||
|
"events_url": "https://api.github.com/users/MYNAME/events{/privacy}",
|
||||||
|
"received_events_url": "https://api.github.com/users/MYNAME/received_events",
|
||||||
|
"type": "User",
|
||||||
|
"site_admin": false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
"github.com/actions-runner-controller/actions-runner-controller/api/v1alpha1"
|
||||||
|
|
||||||
"github.com/google/go-github/v37/github"
|
"github.com/google/go-github/v39/github"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
107
github/github.go
107
github/github.go
@@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/github/metrics"
|
"github.com/actions-runner-controller/actions-runner-controller/github/metrics"
|
||||||
"github.com/bradleyfalzon/ghinstallation"
|
"github.com/bradleyfalzon/ghinstallation"
|
||||||
"github.com/google/go-github/v37/github"
|
"github.com/google/go-github/v39/github"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,6 +23,11 @@ type Config struct {
|
|||||||
AppInstallationID int64 `split_words:"true"`
|
AppInstallationID int64 `split_words:"true"`
|
||||||
AppPrivateKey string `split_words:"true"`
|
AppPrivateKey string `split_words:"true"`
|
||||||
Token string
|
Token string
|
||||||
|
URL string `split_words:"true"`
|
||||||
|
UploadURL string `split_words:"true"`
|
||||||
|
BasicauthUsername string `split_words:"true"`
|
||||||
|
BasicauthPassword string `split_words:"true"`
|
||||||
|
RunnerGitHubURL string `split_words:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client wraps GitHub client with some additional
|
// Client wraps GitHub client with some additional
|
||||||
@@ -34,10 +39,23 @@ type Client struct {
|
|||||||
GithubBaseURL string
|
GithubBaseURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BasicAuthTransport struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
req.SetBasicAuth(p.Username, p.Password)
|
||||||
|
req.Header.Set("User-Agent", "actions-runner-controller")
|
||||||
|
return http.DefaultTransport.RoundTrip(req)
|
||||||
|
}
|
||||||
|
|
||||||
// NewClient creates a Github Client
|
// NewClient creates a Github Client
|
||||||
func (c *Config) NewClient() (*Client, error) {
|
func (c *Config) NewClient() (*Client, error) {
|
||||||
var transport http.RoundTripper
|
var transport http.RoundTripper
|
||||||
if len(c.Token) > 0 {
|
if len(c.BasicauthUsername) > 0 && len(c.BasicauthPassword) > 0 {
|
||||||
|
transport = BasicAuthTransport{Username: c.BasicauthUsername, Password: c.BasicauthPassword}
|
||||||
|
} else if len(c.Token) > 0 {
|
||||||
transport = oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(&oauth2.Token{AccessToken: c.Token})).Transport
|
transport = oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(&oauth2.Token{AccessToken: c.Token})).Transport
|
||||||
} else {
|
} else {
|
||||||
var tr *ghinstallation.Transport
|
var tr *ghinstallation.Transport
|
||||||
@@ -63,6 +81,7 @@ func (c *Config) NewClient() (*Client, error) {
|
|||||||
}
|
}
|
||||||
transport = tr
|
transport = tr
|
||||||
}
|
}
|
||||||
|
|
||||||
transport = metrics.Transport{Transport: transport}
|
transport = metrics.Transport{Transport: transport}
|
||||||
httpClient := &http.Client{Transport: transport}
|
httpClient := &http.Client{Transport: transport}
|
||||||
|
|
||||||
@@ -78,6 +97,35 @@ func (c *Config) NewClient() (*Client, error) {
|
|||||||
} else {
|
} else {
|
||||||
client = github.NewClient(httpClient)
|
client = github.NewClient(httpClient)
|
||||||
githubBaseURL = "https://github.com/"
|
githubBaseURL = "https://github.com/"
|
||||||
|
|
||||||
|
if len(c.URL) > 0 {
|
||||||
|
baseUrl, err := url.Parse(c.URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("github client creation failed: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(baseUrl.Path, "/") {
|
||||||
|
baseUrl.Path += "/"
|
||||||
|
}
|
||||||
|
client.BaseURL = baseUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.UploadURL) > 0 {
|
||||||
|
uploadUrl, err := url.Parse(c.UploadURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("github client creation failed: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(uploadUrl.Path, "/") {
|
||||||
|
uploadUrl.Path += "/"
|
||||||
|
}
|
||||||
|
client.UploadURL = uploadUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.RunnerGitHubURL) > 0 {
|
||||||
|
githubBaseURL = c.RunnerGitHubURL
|
||||||
|
if !strings.HasSuffix(githubBaseURL, "/") {
|
||||||
|
githubBaseURL += "/"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Client{
|
return &Client{
|
||||||
@@ -103,7 +151,7 @@ func (c *Client) GetRegistrationToken(ctx context.Context, enterprise, org, repo
|
|||||||
return rt, nil
|
return rt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
enterprise, owner, repo, err := getEnterpriseOrganisationAndRepo(enterprise, org, repo)
|
enterprise, owner, repo, err := getEnterpriseOrganizationAndRepo(enterprise, org, repo)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rt, err
|
return rt, err
|
||||||
@@ -129,7 +177,7 @@ func (c *Client) GetRegistrationToken(ctx context.Context, enterprise, org, repo
|
|||||||
|
|
||||||
// RemoveRunner removes a runner with specified runner ID from repository.
|
// RemoveRunner removes a runner with specified runner ID from repository.
|
||||||
func (c *Client) RemoveRunner(ctx context.Context, enterprise, org, repo string, runnerID int64) error {
|
func (c *Client) RemoveRunner(ctx context.Context, enterprise, org, repo string, runnerID int64) error {
|
||||||
enterprise, owner, repo, err := getEnterpriseOrganisationAndRepo(enterprise, org, repo)
|
enterprise, owner, repo, err := getEnterpriseOrganizationAndRepo(enterprise, org, repo)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -150,7 +198,7 @@ func (c *Client) RemoveRunner(ctx context.Context, enterprise, org, repo string,
|
|||||||
|
|
||||||
// ListRunners returns a list of runners of specified owner/repository name.
|
// ListRunners returns a list of runners of specified owner/repository name.
|
||||||
func (c *Client) ListRunners(ctx context.Context, enterprise, org, repo string) ([]*github.Runner, error) {
|
func (c *Client) ListRunners(ctx context.Context, enterprise, org, repo string) ([]*github.Runner, error) {
|
||||||
enterprise, owner, repo, err := getEnterpriseOrganisationAndRepo(enterprise, org, repo)
|
enterprise, owner, repo, err := getEnterpriseOrganizationAndRepo(enterprise, org, repo)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -176,6 +224,49 @@ func (c *Client) ListRunners(ctx context.Context, enterprise, org, repo string)
|
|||||||
return runners, nil
|
return runners, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListOrganizationRunnerGroups returns all the runner groups defined in the organization and
|
||||||
|
// inherited to the organization from an enterprise.
|
||||||
|
func (c *Client) ListOrganizationRunnerGroups(ctx context.Context, org string) ([]*github.RunnerGroup, error) {
|
||||||
|
var runnerGroups []*github.RunnerGroup
|
||||||
|
|
||||||
|
opts := github.ListOptions{PerPage: 100}
|
||||||
|
for {
|
||||||
|
list, res, err := c.Client.Actions.ListOrganizationRunnerGroups(ctx, org, &opts)
|
||||||
|
if err != nil {
|
||||||
|
return runnerGroups, fmt.Errorf("failed to list organization runner groups: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
runnerGroups = append(runnerGroups, list.RunnerGroups...)
|
||||||
|
if res.NextPage == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
opts.Page = res.NextPage
|
||||||
|
}
|
||||||
|
|
||||||
|
return runnerGroups, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListRunnerGroupRepositoryAccesses(ctx context.Context, org string, runnerGroupId int64) ([]*github.Repository, error) {
|
||||||
|
var repos []*github.Repository
|
||||||
|
|
||||||
|
opts := github.ListOptions{PerPage: 100}
|
||||||
|
for {
|
||||||
|
list, res, err := c.Client.Actions.ListRepositoryAccessRunnerGroup(ctx, org, runnerGroupId, &opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to list repository access for runner group: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
repos = append(repos, list.Repositories...)
|
||||||
|
if res.NextPage == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.Page = res.NextPage
|
||||||
|
}
|
||||||
|
|
||||||
|
return repos, nil
|
||||||
|
}
|
||||||
|
|
||||||
// cleanup removes expired registration tokens.
|
// cleanup removes expired registration tokens.
|
||||||
func (c *Client) cleanup() {
|
func (c *Client) cleanup() {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
@@ -267,8 +358,8 @@ func (c *Client) listRepositoryWorkflowRuns(ctx context.Context, user string, re
|
|||||||
return workflowRuns, nil
|
return workflowRuns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validates enterprise, organisation and repo arguments. Both are optional, but at least one should be specified
|
// Validates enterprise, organization and repo arguments. Both are optional, but at least one should be specified
|
||||||
func getEnterpriseOrganisationAndRepo(enterprise, org, repo string) (string, string, string, error) {
|
func getEnterpriseOrganizationAndRepo(enterprise, org, repo string) (string, string, string, error) {
|
||||||
if len(repo) > 0 {
|
if len(repo) > 0 {
|
||||||
owner, repository, err := splitOwnerAndRepo(repo)
|
owner, repository, err := splitOwnerAndRepo(repo)
|
||||||
return "", owner, repository, err
|
return "", owner, repository, err
|
||||||
@@ -337,7 +428,7 @@ func (r *Client) IsRunnerBusy(ctx context.Context, enterprise, org, repo, name s
|
|||||||
for _, runner := range runners {
|
for _, runner := range runners {
|
||||||
if runner.GetName() == name {
|
if runner.GetName() == name {
|
||||||
if runner.GetStatus() == "offline" {
|
if runner.GetStatus() == "offline" {
|
||||||
return false, &RunnerOffline{runnerName: name}
|
return runner.GetBusy(), &RunnerOffline{runnerName: name}
|
||||||
}
|
}
|
||||||
return runner.GetBusy(), nil
|
return runner.GetBusy(), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/github/fake"
|
"github.com/actions-runner-controller/actions-runner-controller/github/fake"
|
||||||
"github.com/google/go-github/v37/github"
|
"github.com/google/go-github/v39/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
var server *httptest.Server
|
var server *httptest.Server
|
||||||
|
|||||||
80
go.mod
80
go.mod
@@ -1,27 +1,77 @@
|
|||||||
module github.com/actions-runner-controller/actions-runner-controller
|
module github.com/actions-runner-controller/actions-runner-controller
|
||||||
|
|
||||||
go 1.15
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bradleyfalzon/ghinstallation v1.1.1
|
github.com/bradleyfalzon/ghinstallation v1.1.1
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/go-logr/logr v0.4.0
|
github.com/go-logr/logr v1.2.0
|
||||||
github.com/google/go-cmp v0.5.6
|
github.com/google/go-cmp v0.5.7
|
||||||
github.com/google/go-github/v37 v37.0.0
|
github.com/google/go-github/v39 v39.2.0
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/kelseyhightower/envconfig v1.4.0
|
github.com/kelseyhightower/envconfig v1.4.0
|
||||||
github.com/onsi/ginkgo v1.16.4
|
github.com/onsi/ginkgo v1.16.5
|
||||||
github.com/onsi/gomega v1.13.0
|
github.com/onsi/gomega v1.17.0
|
||||||
github.com/prometheus/client_golang v1.11.0
|
github.com/prometheus/client_golang v1.11.0
|
||||||
github.com/teambition/rrule-go v1.6.2
|
github.com/stretchr/testify v1.7.0
|
||||||
go.uber.org/zap v1.19.0
|
github.com/teambition/rrule-go v1.7.2
|
||||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
|
go.uber.org/zap v1.20.0
|
||||||
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
|
||||||
gomodules.xyz/jsonpatch/v2 v2.2.0
|
gomodules.xyz/jsonpatch/v2 v2.2.0
|
||||||
k8s.io/api v0.21.1
|
k8s.io/api v0.23.0
|
||||||
k8s.io/apimachinery v0.21.1
|
k8s.io/apimachinery v0.23.0
|
||||||
k8s.io/client-go v0.21.1
|
k8s.io/client-go v0.23.0
|
||||||
sigs.k8s.io/controller-runtime v0.9.0
|
sigs.k8s.io/controller-runtime v0.11.0
|
||||||
sigs.k8s.io/yaml v1.2.0
|
sigs.k8s.io/yaml v1.3.0
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/google/go-github/v37 => github.com/mumoshu/go-github/v37 v37.0.100
|
require (
|
||||||
|
cloud.google.com/go v0.81.0 // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
|
||||||
|
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||||
|
github.com/go-logr/zapr v1.2.0 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/google/go-github/v29 v29.0.2 // indirect
|
||||||
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
|
github.com/google/gofuzz v1.1.0 // indirect
|
||||||
|
github.com/google/uuid v1.1.2 // indirect
|
||||||
|
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||||
|
github.com/imdario/mergo v0.3.12 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/nxadm/tail v1.4.8 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/prometheus/client_model v0.2.0 // indirect
|
||||||
|
github.com/prometheus/common v0.28.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.6.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20210825183410-e898025ed96a // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 // indirect
|
||||||
|
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||||
|
golang.org/x/text v0.3.7 // indirect
|
||||||
|
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||||
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
|
k8s.io/apiextensions-apiserver v0.23.0 // indirect
|
||||||
|
k8s.io/component-base v0.23.0 // indirect
|
||||||
|
k8s.io/klog/v2 v2.30.0 // indirect
|
||||||
|
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
|
||||||
|
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect
|
||||||
|
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.0 // indirect
|
||||||
|
)
|
||||||
|
|||||||
394
go.sum
394
go.sum
@@ -8,13 +8,17 @@ cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg
|
|||||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||||
cloud.google.com/go v0.54.0 h1:3ithwDMr7/3vpAMXiH+ZQnYbuIsh+OPhUPMFC9enmn0=
|
|
||||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||||
cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
|
|
||||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||||
|
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||||
|
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||||
|
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||||
|
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||||
|
cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8=
|
||||||
|
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||||
@@ -34,13 +38,14 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
|||||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||||
github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
|
github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
|
github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
|
||||||
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
||||||
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
|
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
|
||||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
@@ -54,10 +59,14 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
|
|||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
|
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
|
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
|
||||||
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
@@ -65,10 +74,13 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
|||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||||
|
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||||
github.com/bradleyfalzon/ghinstallation v1.1.1 h1:pmBXkxgM1WeF8QYvDLT5kuQiHMcmf+X015GI0KM/E3I=
|
github.com/bradleyfalzon/ghinstallation v1.1.1 h1:pmBXkxgM1WeF8QYvDLT5kuQiHMcmf+X015GI0KM/E3I=
|
||||||
github.com/bradleyfalzon/ghinstallation v1.1.1/go.mod h1:vyCmHTciHx/uuyN82Zc3rXN3X2KTK8nUTCrTMwAhcug=
|
github.com/bradleyfalzon/ghinstallation v1.1.1/go.mod h1:vyCmHTciHx/uuyN82Zc3rXN3X2KTK8nUTCrTMwAhcug=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
||||||
|
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
||||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||||
@@ -78,18 +90,20 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
|
|||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
||||||
|
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
|
||||||
|
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -99,7 +113,6 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC
|
|||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||||
@@ -107,16 +120,24 @@ github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
||||||
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
|
||||||
github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs=
|
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||||
|
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||||
|
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||||
|
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
||||||
|
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
@@ -129,31 +150,32 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
|
|||||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||||
github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
|
github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE=
|
||||||
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM=
|
github.com/go-logr/zapr v1.2.0 h1:n4JnPI1T3Qq1SFEi/F8rwLrZERp2bso19PJZDB9dayk=
|
||||||
github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
|
github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro=
|
||||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||||
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||||
github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
|
|
||||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
|
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
|
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
@@ -161,6 +183,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
|||||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
|
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
@@ -176,10 +199,14 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
|||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||||
|
github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w=
|
||||||
|
github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
@@ -188,21 +215,26 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
||||||
|
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||||
github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts=
|
github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts=
|
||||||
github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E=
|
github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E=
|
||||||
github.com/google/go-github/v37 v37.0.1-0.20210713230028-465df60a8ec3 h1:YVfdOQRQ95EjQz0qpGdw9LIzJUflL4FV0EEX3fZ7fH8=
|
github.com/google/go-github/v39 v39.2.0 h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvto3aSnQ=
|
||||||
github.com/google/go-github/v37 v37.0.1-0.20210713230028-465df60a8ec3/go.mod h1:LM7in3NmXDrX58GbEHy7FtNLbI2JijX93RnMKvWG3m4=
|
github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE=
|
||||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
|
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
|
||||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
|
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
@@ -210,27 +242,28 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
|||||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
|
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
|
||||||
github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
|
github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
|
||||||
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
|
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
@@ -246,8 +279,6 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
|
|||||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||||
@@ -255,18 +286,21 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
|
|||||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||||
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
|
|
||||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
@@ -275,26 +309,26 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
|
|||||||
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
||||||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
|
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
|
||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
@@ -307,16 +341,16 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
|
|||||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||||
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
|
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mumoshu/go-github/v37 v37.0.100 h1:a0S2oEJ8naEW5M4y6S+wu3ufSe9PmKxu77C72VJ6LLw=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/mumoshu/go-github/v37 v37.0.100/go.mod h1:LM7in3NmXDrX58GbEHy7FtNLbI2JijX93RnMKvWG3m4=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
@@ -328,27 +362,28 @@ github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI
|
|||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
|
||||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
|
||||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||||
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
|
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
|
||||||
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
@@ -368,17 +403,18 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q
|
|||||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||||
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
|
||||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||||
|
github.com/prometheus/common v0.28.0 h1:vGVfV9KrDTvWt5boZO0I19g2E3CsWfpPPKZM9dt3mEw=
|
||||||
|
github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
|
||||||
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
@@ -388,26 +424,29 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
|||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
|
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
|
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
|
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||||
|
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||||
|
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
@@ -416,50 +455,73 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/teambition/rrule-go v1.6.2 h1:keZiiijltBxYUuhQaySAEGyIFR0UOkAd7i+u6FM5/+I=
|
github.com/teambition/rrule-go v1.7.2 h1:goEajFWYydfCgavn2m/3w5U+1b3PGqPUHx/fFSVfTy0=
|
||||||
github.com/teambition/rrule-go v1.6.2/go.mod h1:mBJ1Ht5uboJ6jexKdNUJg2NcwP8uUMNvStWXlJD3MvU=
|
github.com/teambition/rrule-go v1.7.2/go.mod h1:mBJ1Ht5uboJ6jexKdNUJg2NcwP8uUMNvStWXlJD3MvU=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
|
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||||
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
|
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||||
|
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||||
|
go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
|
||||||
|
go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE=
|
||||||
|
go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc=
|
||||||
|
go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||||
|
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||||
|
go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
|
||||||
|
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
|
||||||
|
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
|
||||||
|
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
|
||||||
|
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
|
||||||
|
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
|
||||||
|
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
|
||||||
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
|
||||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||||
|
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
|
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
|
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||||
|
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
|
|
||||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||||
go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE=
|
|
||||||
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||||
|
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||||
|
go.uber.org/zap v1.20.0 h1:N4oPlghZwYG55MlU6LXk/Zp00FVNE9X9wrYO8CEs4lc=
|
||||||
|
go.uber.org/zap v1.20.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@@ -481,8 +543,9 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
|
|||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
|
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
@@ -491,8 +554,9 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449 h1:xUIPaMhvROX9dhPvRCenIJtU78+lbEenGbgqB5hfHCQ=
|
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -511,7 +575,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
@@ -529,17 +592,35 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
|
|||||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||||
|
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw=
|
||||||
|
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw=
|
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -550,6 +631,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -564,10 +646,8 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -587,40 +667,60 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 h1:JWgyZ1qgdTaF3N3oxC+MdTV7qvEEgHo3otj+HB5CM7Q=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 h1:M69LAlWZCshgp0QSzyDcSsSIejIEeuaCVpmwcKwyLMk=
|
||||||
|
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
|
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
|
||||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
|
||||||
|
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
@@ -631,7 +731,6 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn
|
|||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
@@ -667,10 +766,17 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
|
|||||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||||
|
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
|
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
|
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -694,6 +800,12 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
|
|||||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||||
|
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||||
|
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||||
|
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||||
|
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||||
|
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||||
|
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
@@ -723,16 +835,30 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG
|
|||||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||||
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||||
|
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
@@ -745,6 +871,16 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
|
|||||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||||
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
|
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||||
|
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
|
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
|
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
|
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
|
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@@ -756,20 +892,21 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
|||||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||||
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
@@ -778,6 +915,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
|
|||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
@@ -797,38 +935,40 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
k8s.io/api v0.21.1 h1:94bbZ5NTjdINJEdzOkpS4vdPhkb1VFpTYC9zh43f75c=
|
k8s.io/api v0.23.0 h1:WrL1gb73VSC8obi8cuYETJGXEoFNEh3LU0Pt+Sokgro=
|
||||||
k8s.io/api v0.21.1/go.mod h1:FstGROTmsSHBarKc8bylzXih8BLNYTiS3TZcsoEDg2s=
|
k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg=
|
||||||
k8s.io/apiextensions-apiserver v0.21.1 h1:AA+cnsb6w7SZ1vD32Z+zdgfXdXY8X9uGX5bN6EoPEIo=
|
k8s.io/apiextensions-apiserver v0.23.0 h1:uii8BYmHYiT2ZTAJxmvc3X8UhNYMxl2A0z0Xq3Pm+WY=
|
||||||
k8s.io/apiextensions-apiserver v0.21.1/go.mod h1:KESQFCGjqVcVsZ9g0xX5bacMjyX5emuWcS2arzdEouA=
|
k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4=
|
||||||
k8s.io/apimachinery v0.21.1 h1:Q6XuHGlj2xc+hlMCvqyYfbv3H7SRGn2c8NycxJquDVs=
|
k8s.io/apimachinery v0.23.0 h1:mIfWRMjBuMdolAWJ3Fd+aPTMv3X9z+waiARMpvvb0HQ=
|
||||||
k8s.io/apimachinery v0.21.1/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY=
|
k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc=
|
||||||
k8s.io/apiserver v0.21.1/go.mod h1:nLLYZvMWn35glJ4/FZRhzLG/3MPxAaZTgV4FJZdr+tY=
|
k8s.io/apiserver v0.23.0/go.mod h1:Cec35u/9zAepDPPFyT+UMrgqOCjgJ5qtfVJDxjZYmt4=
|
||||||
k8s.io/client-go v0.21.1 h1:bhblWYLZKUu+pm50plvQF8WpY6TXdRRtcS/K9WauOj4=
|
k8s.io/client-go v0.23.0 h1:vcsOqyPq7XV3QmQRCBH/t9BICJM9Q1M18qahjv+rebY=
|
||||||
k8s.io/client-go v0.21.1/go.mod h1:/kEw4RgW+3xnBGzvp9IWxKSNA+lXn3A7AuH3gdOAzLs=
|
k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA=
|
||||||
k8s.io/code-generator v0.21.1/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q=
|
k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE=
|
||||||
k8s.io/component-base v0.21.1 h1:iLpj2btXbR326s/xNQWmPNGu0gaYSjzn7IN/5i28nQw=
|
k8s.io/component-base v0.23.0 h1:UAnyzjvVZ2ZR1lF35YwtNY6VMN94WtOnArcXBu34es8=
|
||||||
k8s.io/component-base v0.21.1/go.mod h1:NgzFZ2qu4m1juby4TnrmpR8adRk6ka62YdH5DkIIyKA=
|
k8s.io/component-base v0.23.0/go.mod h1:DHH5uiFvLC1edCpvcTDV++NKULdYYU6pR9Tt3HIKMKI=
|
||||||
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||||
k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
|
||||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||||
k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts=
|
k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw=
|
||||||
k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
|
k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||||
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0=
|
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4=
|
||||||
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE=
|
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
||||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
k8s.io/utils v0.0.0-20210527160623-6fdb442a123b h1:MSqsVQ3pZvPGTqCjptfimO2WjG7A9un2zcpiHkA6M/s=
|
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs=
|
||||||
k8s.io/utils v0.0.0-20210527160623-6fdb442a123b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25/go.mod h1:Mlj9PNLmG9bZ6BHFwFKDo5afkpWyUISkb9Me0GnK66I=
|
||||||
sigs.k8s.io/controller-runtime v0.9.0 h1:ZIZ/dtpboPSbZYY7uUz2OzrkaBTOThx2yekLtpGB+zY=
|
sigs.k8s.io/controller-runtime v0.11.0 h1:DqO+c8mywcZLFJWILq4iktoECTyn30Bkj0CwgqMpZWQ=
|
||||||
sigs.k8s.io/controller-runtime v0.9.0/go.mod h1:TgkfvrhhEw3PlI0BRL/5xM+89y3/yc0ZDfdbTl84si8=
|
sigs.k8s.io/controller-runtime v0.11.0/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
|
||||||
|
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
|
||||||
|
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8=
|
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.0 h1:kDvPBbnPk+qYmkHmSo8vKGp438IASWofnbbUKDE/bv0=
|
||||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.0/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
|
||||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||||
|
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||||
|
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||||
|
|||||||
30
main.go
30
main.go
@@ -58,6 +58,17 @@ func init() {
|
|||||||
// +kubebuilder:scaffold:scheme
|
// +kubebuilder:scaffold:scheme
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type stringSlice []string
|
||||||
|
|
||||||
|
func (i *stringSlice) String() string {
|
||||||
|
return fmt.Sprintf("%v", *i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *stringSlice) Set(value string) error {
|
||||||
|
*i = append(*i, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
@@ -71,6 +82,8 @@ func main() {
|
|||||||
gitHubAPICacheDuration time.Duration
|
gitHubAPICacheDuration time.Duration
|
||||||
|
|
||||||
runnerImage string
|
runnerImage string
|
||||||
|
runnerImagePullSecrets stringSlice
|
||||||
|
|
||||||
dockerImage string
|
dockerImage string
|
||||||
dockerRegistryMirror string
|
dockerRegistryMirror string
|
||||||
namespace string
|
namespace string
|
||||||
@@ -82,7 +95,8 @@ func main() {
|
|||||||
var c github.Config
|
var c github.Config
|
||||||
err = envconfig.Process("github", &c)
|
err = envconfig.Process("github", &c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "Error: Environment variable read failed.")
|
fmt.Fprintf(os.Stderr, "Error: processing environment variables: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
|
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
|
||||||
@@ -91,11 +105,17 @@ func main() {
|
|||||||
flag.StringVar(&leaderElectionId, "leader-election-id", "actions-runner-controller", "Controller id for leader election.")
|
flag.StringVar(&leaderElectionId, "leader-election-id", "actions-runner-controller", "Controller id for leader election.")
|
||||||
flag.StringVar(&runnerImage, "runner-image", defaultRunnerImage, "The image name of self-hosted runner container.")
|
flag.StringVar(&runnerImage, "runner-image", defaultRunnerImage, "The image name of self-hosted runner container.")
|
||||||
flag.StringVar(&dockerImage, "docker-image", defaultDockerImage, "The image name of docker sidecar container.")
|
flag.StringVar(&dockerImage, "docker-image", defaultDockerImage, "The image name of docker sidecar container.")
|
||||||
|
flag.Var(&runnerImagePullSecrets, "runner-image-pull-secret", "The default image-pull secret name for self-hosted runner container.")
|
||||||
flag.StringVar(&dockerRegistryMirror, "docker-registry-mirror", "", "The default Docker Registry Mirror used by runners.")
|
flag.StringVar(&dockerRegistryMirror, "docker-registry-mirror", "", "The default Docker Registry Mirror used by runners.")
|
||||||
flag.StringVar(&c.Token, "github-token", c.Token, "The personal access token of GitHub.")
|
flag.StringVar(&c.Token, "github-token", c.Token, "The personal access token of GitHub.")
|
||||||
flag.Int64Var(&c.AppID, "github-app-id", c.AppID, "The application ID of GitHub App.")
|
flag.Int64Var(&c.AppID, "github-app-id", c.AppID, "The application ID of GitHub App.")
|
||||||
flag.Int64Var(&c.AppInstallationID, "github-app-installation-id", c.AppInstallationID, "The installation ID of GitHub App.")
|
flag.Int64Var(&c.AppInstallationID, "github-app-installation-id", c.AppInstallationID, "The installation ID of GitHub App.")
|
||||||
flag.StringVar(&c.AppPrivateKey, "github-app-private-key", c.AppPrivateKey, "The path of a private key file to authenticate as a GitHub App")
|
flag.StringVar(&c.AppPrivateKey, "github-app-private-key", c.AppPrivateKey, "The path of a private key file to authenticate as a GitHub App")
|
||||||
|
flag.StringVar(&c.URL, "github-url", c.URL, "GitHub URL to be used for GitHub API calls")
|
||||||
|
flag.StringVar(&c.UploadURL, "github-upload-url", c.UploadURL, "GitHub Upload URL to be used for GitHub API calls")
|
||||||
|
flag.StringVar(&c.BasicauthUsername, "github-basicauth-username", c.BasicauthUsername, "Username for GitHub basic auth to use instead of PAT or GitHub APP in case it's running behind a proxy API")
|
||||||
|
flag.StringVar(&c.BasicauthPassword, "github-basicauth-password", c.BasicauthPassword, "Password for GitHub basic auth to use instead of PAT or GitHub APP in case it's running behind a proxy API")
|
||||||
|
flag.StringVar(&c.RunnerGitHubURL, "runner-github-url", c.RunnerGitHubURL, "GitHub URL to be used by runners during registration")
|
||||||
flag.DurationVar(&gitHubAPICacheDuration, "github-api-cache-duration", 0, "The duration until the GitHub API cache expires. Setting this to e.g. 10m results in the controller tries its best not to make the same API call within 10m to reduce the chance of being rate-limited. Defaults to mostly the same value as sync-period. If you're tweaking this in order to make autoscaling more responsive, you'll probably want to tweak sync-period, too")
|
flag.DurationVar(&gitHubAPICacheDuration, "github-api-cache-duration", 0, "The duration until the GitHub API cache expires. Setting this to e.g. 10m results in the controller tries its best not to make the same API call within 10m to reduce the chance of being rate-limited. Defaults to mostly the same value as sync-period. If you're tweaking this in order to make autoscaling more responsive, you'll probably want to tweak sync-period, too")
|
||||||
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. . If you're tweaking this in order to make autoscaling more responsive, you'll probably want to tweak github-api-cache-duration, too")
|
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. . If you're tweaking this in order to make autoscaling more responsive, you'll probably want to tweak github-api-cache-duration, too")
|
||||||
flag.Var(&commonRunnerLabels, "common-runner-labels", "Runner labels in the K1=V1,K2=V2,... format that are inherited all the runners created by the controller. See https://github.com/actions-runner-controller/actions-runner-controller/issues/321 for more information")
|
flag.Var(&commonRunnerLabels, "common-runner-labels", "Runner labels in the K1=V1,K2=V2,... format that are inherited all the runners created by the controller. See https://github.com/actions-runner-controller/actions-runner-controller/issues/321 for more information")
|
||||||
@@ -146,9 +166,11 @@ func main() {
|
|||||||
Log: log.WithName("runner"),
|
Log: log.WithName("runner"),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
GitHubClient: ghClient,
|
GitHubClient: ghClient,
|
||||||
RunnerImage: runnerImage,
|
|
||||||
DockerImage: dockerImage,
|
DockerImage: dockerImage,
|
||||||
DockerRegistryMirror: dockerRegistryMirror,
|
DockerRegistryMirror: dockerRegistryMirror,
|
||||||
|
// Defaults for self-hosted runner containers
|
||||||
|
RunnerImage: runnerImage,
|
||||||
|
RunnerImagePullSecrets: runnerImagePullSecrets,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = runnerReconciler.SetupWithManager(mgr); err != nil {
|
if err = runnerReconciler.SetupWithManager(mgr); err != nil {
|
||||||
@@ -185,10 +207,12 @@ func main() {
|
|||||||
Log: log.WithName("runnerset"),
|
Log: log.WithName("runnerset"),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
CommonRunnerLabels: commonRunnerLabels,
|
CommonRunnerLabels: commonRunnerLabels,
|
||||||
RunnerImage: runnerImage,
|
|
||||||
DockerImage: dockerImage,
|
DockerImage: dockerImage,
|
||||||
DockerRegistryMirror: dockerRegistryMirror,
|
DockerRegistryMirror: dockerRegistryMirror,
|
||||||
GitHubBaseURL: ghClient.GithubBaseURL,
|
GitHubBaseURL: ghClient.GithubBaseURL,
|
||||||
|
// Defaults for self-hosted runner containers
|
||||||
|
RunnerImage: runnerImage,
|
||||||
|
RunnerImagePullSecrets: runnerImagePullSecrets,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = runnerSetReconciler.SetupWithManager(mgr); err != nil {
|
if err = runnerSetReconciler.SetupWithManager(mgr); err != nil {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/github"
|
"github.com/actions-runner-controller/actions-runner-controller/github"
|
||||||
gogithub "github.com/google/go-github/v37/github"
|
gogithub "github.com/google/go-github/v39/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
type server struct {
|
type server struct {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/github"
|
"github.com/actions-runner-controller/actions-runner-controller/github"
|
||||||
gogithub "github.com/google/go-github/v37/github"
|
gogithub "github.com/google/go-github/v39/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Forwarder struct {
|
type Forwarder struct {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package hookdeliveryforwarder
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
gogithub "github.com/google/go-github/v37/github"
|
gogithub "github.com/google/go-github/v39/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
type hooksAPI struct {
|
type hooksAPI struct {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package hookdeliveryforwarder
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
gogithub "github.com/google/go-github/v37/github"
|
gogithub "github.com/google/go-github/v39/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
type hookDeliveriesAPI struct {
|
type hookDeliveriesAPI struct {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/github"
|
"github.com/actions-runner-controller/actions-runner-controller/github"
|
||||||
gogithub "github.com/google/go-github/v37/github"
|
gogithub "github.com/google/go-github/v39/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MultiForwarder struct {
|
type MultiForwarder struct {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
FROM ubuntu:20.04
|
FROM ubuntu:20.04
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
ARG RUNNER_VERSION=2.280.3
|
ARG RUNNER_VERSION=2.287.1
|
||||||
ARG DOCKER_CHANNEL=stable
|
ARG DOCKER_CHANNEL=stable
|
||||||
ARG DOCKER_VERSION=20.10.8
|
ARG DOCKER_VERSION=20.10.12
|
||||||
ARG DUMB_INIT_VERSION=1.2.5
|
ARG DUMB_INIT_VERSION=1.2.5
|
||||||
|
|
||||||
RUN test -n "$TARGETPLATFORM" || (echo "TARGETPLATFORM must be set" && false)
|
RUN test -n "$TARGETPLATFORM" || (echo "TARGETPLATFORM must be set" && false)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
FROM ubuntu:20.04
|
FROM ubuntu:20.04
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
ARG RUNNER_VERSION=2.280.3
|
ARG RUNNER_VERSION=2.287.1
|
||||||
ARG DOCKER_CHANNEL=stable
|
ARG DOCKER_CHANNEL=stable
|
||||||
ARG DOCKER_VERSION=19.03.13
|
ARG DOCKER_VERSION=20.10.12
|
||||||
ARG DUMB_INIT_VERSION=1.2.5
|
ARG DUMB_INIT_VERSION=1.2.5
|
||||||
|
|
||||||
RUN test -n "$TARGETPLATFORM" || (echo "TARGETPLATFORM must be set" && false)
|
RUN test -n "$TARGETPLATFORM" || (echo "TARGETPLATFORM must be set" && false)
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
FROM ubuntu:18.04
|
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
|
||||||
ARG RUNNER_VERSION=2.280.3
|
|
||||||
ARG DOCKER_CHANNEL=stable
|
|
||||||
ARG DOCKER_VERSION=20.10.8
|
|
||||||
ARG DUMB_INIT_VERSION=1.2.5
|
|
||||||
|
|
||||||
RUN test -n "$TARGETPLATFORM" || (echo "TARGETPLATFORM must be set" && false)
|
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
RUN apt update -y \
|
|
||||||
&& apt install -y software-properties-common \
|
|
||||||
&& add-apt-repository -y ppa:git-core/ppa \
|
|
||||||
&& apt update -y \
|
|
||||||
&& apt install -y --no-install-recommends \
|
|
||||||
build-essential \
|
|
||||||
curl \
|
|
||||||
ca-certificates \
|
|
||||||
dnsutils \
|
|
||||||
ftp \
|
|
||||||
git \
|
|
||||||
iproute2 \
|
|
||||||
iputils-ping \
|
|
||||||
jq \
|
|
||||||
libunwind8 \
|
|
||||||
locales \
|
|
||||||
netcat \
|
|
||||||
openssh-client \
|
|
||||||
parallel \
|
|
||||||
python3-pip \
|
|
||||||
rsync \
|
|
||||||
shellcheck \
|
|
||||||
sudo \
|
|
||||||
telnet \
|
|
||||||
time \
|
|
||||||
tzdata \
|
|
||||||
unzip \
|
|
||||||
upx \
|
|
||||||
wget \
|
|
||||||
zip \
|
|
||||||
zstd \
|
|
||||||
&& ln -sf /usr/bin/python3 /usr/bin/python \
|
|
||||||
&& ln -sf /usr/bin/pip3 /usr/bin/pip \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# arch command on OS X reports "i386" for Intel CPUs regardless of bitness
|
|
||||||
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
|
||||||
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
|
|
||||||
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x86_64 ; fi \
|
|
||||||
&& curl -f -L -o /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_${ARCH} \
|
|
||||||
&& chmod +x /usr/local/bin/dumb-init
|
|
||||||
|
|
||||||
# Docker download supports arm64 as aarch64 & amd64 / i386 as x86_64
|
|
||||||
RUN set -vx; \
|
|
||||||
export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
|
||||||
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
|
|
||||||
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x86_64 ; fi \
|
|
||||||
&& curl -f -L -o docker.tgz https://download.docker.com/linux/static/${DOCKER_CHANNEL}/${ARCH}/docker-${DOCKER_VERSION}.tgz \
|
|
||||||
&& tar zxvf docker.tgz \
|
|
||||||
&& install -o root -g root -m 755 docker/docker /usr/local/bin/docker \
|
|
||||||
&& rm -rf docker docker.tgz \
|
|
||||||
&& adduser --disabled-password --gecos "" --uid 1000 runner \
|
|
||||||
&& groupadd docker \
|
|
||||||
&& usermod -aG sudo runner \
|
|
||||||
&& usermod -aG docker runner \
|
|
||||||
&& echo "%sudo ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers
|
|
||||||
|
|
||||||
ENV RUNNER_ASSETS_DIR=/runnertmp
|
|
||||||
ENV HOME=/home/runner
|
|
||||||
|
|
||||||
# Runner download supports amd64 as x64. Externalstmp is needed for making mount points work inside DinD.
|
|
||||||
#
|
|
||||||
# libyaml-dev is required for ruby/setup-ruby action.
|
|
||||||
# It is installed after installdependencies.sh and before removing /var/lib/apt/lists
|
|
||||||
# to avoid rerunning apt-update on its own.
|
|
||||||
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
|
||||||
&& if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x64 ; fi \
|
|
||||||
&& mkdir -p "$RUNNER_ASSETS_DIR" \
|
|
||||||
&& cd "$RUNNER_ASSETS_DIR" \
|
|
||||||
&& curl -f -L -o runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${ARCH}-${RUNNER_VERSION}.tar.gz \
|
|
||||||
&& tar xzf ./runner.tar.gz \
|
|
||||||
&& rm runner.tar.gz \
|
|
||||||
&& ./bin/installdependencies.sh \
|
|
||||||
&& mv ./externals ./externalstmp \
|
|
||||||
&& apt-get install -y libyaml-dev \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
ENV RUNNER_TOOL_CACHE=/opt/hostedtoolcache
|
|
||||||
RUN mkdir /opt/hostedtoolcache \
|
|
||||||
&& chgrp docker /opt/hostedtoolcache \
|
|
||||||
&& chmod g+rwx /opt/hostedtoolcache
|
|
||||||
|
|
||||||
COPY entrypoint.sh /
|
|
||||||
COPY --chown=runner:docker patched $RUNNER_ASSETS_DIR/patched
|
|
||||||
|
|
||||||
# Add the Python "User Script Directory" to the PATH
|
|
||||||
ENV PATH="${PATH}:${HOME}/.local/bin"
|
|
||||||
ENV ImageOS=ubuntu20
|
|
||||||
|
|
||||||
USER runner
|
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/local/bin/dumb-init", "--"]
|
|
||||||
CMD ["/entrypoint.sh"]
|
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
NAME ?= summerwind/actions-runner
|
DOCKER_USER ?= summerwind
|
||||||
DIND_RUNNER_NAME ?= ${NAME}-dind
|
NAME ?= ${DOCKER_USER}/actions-runner
|
||||||
|
DIND_RUNNER_NAME ?= ${DOCKER_USER}/actions-runner-dind
|
||||||
TAG ?= latest
|
TAG ?= latest
|
||||||
TARGET_PLATFORM ?= $(shell arch)
|
TARGETPLATFORM ?= $(shell arch)
|
||||||
|
|
||||||
RUNNER_VERSION ?= 2.280.3
|
RUNNER_VERSION ?= 2.287.1
|
||||||
DOCKER_VERSION ?= 20.10.8
|
DOCKER_VERSION ?= 20.10.12
|
||||||
|
|
||||||
# default list of platforms for which multiarch image is built
|
# default list of platforms for which multiarch image is built
|
||||||
ifeq (${PLATFORMS}, )
|
ifeq (${PLATFORMS}, )
|
||||||
@@ -24,8 +25,8 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
docker-build-ubuntu:
|
docker-build-ubuntu:
|
||||||
docker build --build-arg TARGETPLATFORM=${TARGET_PLATFORM} --build-arg RUNNER_VERSION=${RUNNER_VERSION} --build-arg DOCKER_VERSION=${DOCKER_VERSION} -t ${NAME}:${TAG} .
|
docker build --build-arg TARGETPLATFORM=${TARGETPLATFORM} --build-arg RUNNER_VERSION=${RUNNER_VERSION} --build-arg DOCKER_VERSION=${DOCKER_VERSION} -t ${NAME}:${TAG} .
|
||||||
docker build --build-arg TARGETPLATFORM=${TARGET_PLATFORM} --build-arg RUNNER_VERSION=${RUNNER_VERSION} --build-arg DOCKER_VERSION=${DOCKER_VERSION} -t ${DIND_RUNNER_NAME}:${TAG} -f Dockerfile.dindrunner .
|
docker build --build-arg TARGETPLATFORM=${TARGETPLATFORM} --build-arg RUNNER_VERSION=${RUNNER_VERSION} --build-arg DOCKER_VERSION=${DOCKER_VERSION} -t ${DIND_RUNNER_NAME}:${TAG} -f Dockerfile.dindrunner .
|
||||||
|
|
||||||
docker-push-ubuntu:
|
docker-push-ubuntu:
|
||||||
docker push ${NAME}:${TAG}
|
docker push ${NAME}:${TAG}
|
||||||
@@ -39,12 +40,12 @@ docker-buildx-ubuntu:
|
|||||||
docker buildx build --platform ${PLATFORMS} \
|
docker buildx build --platform ${PLATFORMS} \
|
||||||
--build-arg RUNNER_VERSION=${RUNNER_VERSION} \
|
--build-arg RUNNER_VERSION=${RUNNER_VERSION} \
|
||||||
--build-arg DOCKER_VERSION=${DOCKER_VERSION} \
|
--build-arg DOCKER_VERSION=${DOCKER_VERSION} \
|
||||||
-t "${NAME}:latest" \
|
-t "${NAME}:${TAG}" \
|
||||||
-f Dockerfile \
|
-f Dockerfile \
|
||||||
. ${PUSH_ARG}
|
. ${PUSH_ARG}
|
||||||
docker buildx build --platform ${PLATFORMS} \
|
docker buildx build --platform ${PLATFORMS} \
|
||||||
--build-arg RUNNER_VERSION=${RUNNER_VERSION} \
|
--build-arg RUNNER_VERSION=${RUNNER_VERSION} \
|
||||||
--build-arg DOCKER_VERSION=${DOCKER_VERSION} \
|
--build-arg DOCKER_VERSION=${DOCKER_VERSION} \
|
||||||
-t "${DIND_RUNNER_NAME}:latest" \
|
-t "${DIND_RUNNER_NAME}:${TAG}" \
|
||||||
-f Dockerfile.dindrunner \
|
-f Dockerfile.dindrunner \
|
||||||
. ${PUSH_ARG}
|
. ${PUSH_ARG}
|
||||||
|
|||||||
@@ -24,6 +24,13 @@ if [ ! -z "${STARTUP_DELAY_IN_SECONDS}" ]; then
|
|||||||
sleep ${STARTUP_DELAY_IN_SECONDS}
|
sleep ${STARTUP_DELAY_IN_SECONDS}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "${DISABLE_WAIT_FOR_DOCKER}" != "true" ]] && [[ "${DOCKER_ENABLED}" == "true" ]]; then
|
||||||
|
log "Docker enabled runner detected and Docker daemon wait is enabled"
|
||||||
|
log "Waiting until Docker is avaliable or the timeout is reached"
|
||||||
|
timeout 120s bash -c 'until docker ps ;do sleep 1; done'
|
||||||
|
else
|
||||||
|
log "Docker wait check skipped. Either Docker is disabled or the wait is disabled, continuing with entrypoint"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -z "${GITHUB_URL}" ]; then
|
if [ -z "${GITHUB_URL}" ]; then
|
||||||
log "Working with public GitHub"
|
log "Working with public GitHub"
|
||||||
@@ -72,7 +79,8 @@ fi
|
|||||||
# if this is not a testing environment
|
# if this is not a testing environment
|
||||||
if [ -z "${UNITTEST:-}" ]; then
|
if [ -z "${UNITTEST:-}" ]; then
|
||||||
sudo chown -R runner:docker ${RUNNER_HOME}
|
sudo chown -R runner:docker ${RUNNER_HOME}
|
||||||
mv /runnertmp/* ${RUNNER_HOME}/
|
# use cp over mv to avoid issues when /runnertmp and {RUNNER_HOME} are on different devices
|
||||||
|
cp -r /runnertmp/* ${RUNNER_HOME}/
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd ${RUNNER_HOME}
|
cd ${RUNNER_HOME}
|
||||||
@@ -83,6 +91,10 @@ if [ "${RUNNER_FEATURE_FLAG_EPHEMERAL:-}" == "true" -a "${RUNNER_EPHEMERAL}" !=
|
|||||||
config_args+=(--ephemeral)
|
config_args+=(--ephemeral)
|
||||||
echo "Passing --ephemeral to config.sh to enable the ephemeral runner."
|
echo "Passing --ephemeral to config.sh to enable the ephemeral runner."
|
||||||
fi
|
fi
|
||||||
|
if [ "${DISABLE_RUNNER_UPDATE:-}" == "true" ]; then
|
||||||
|
config_args+=(--disableupdate)
|
||||||
|
echo "Passing --disableupdate to config.sh to disable automatic runner updates."
|
||||||
|
fi
|
||||||
|
|
||||||
retries_left=10
|
retries_left=10
|
||||||
while [[ ${retries_left} -gt 0 ]]; do
|
while [[ ${retries_left} -gt 0 ]]; do
|
||||||
|
|||||||
63
simulator/runnergroup_visibility.go
Normal file
63
simulator/runnergroup_visibility.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package simulator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/actions-runner-controller/actions-runner-controller/github"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Simulator struct {
|
||||||
|
Client *github.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Simulator) GetRunnerGroupsVisibleToRepository(ctx context.Context, org, repo string, managed *VisibleRunnerGroups) (*VisibleRunnerGroups, error) {
|
||||||
|
visible := NewVisibleRunnerGroups()
|
||||||
|
|
||||||
|
if org == "" {
|
||||||
|
panic(fmt.Sprintf("BUG: owner should not be empty in this context. repo=%v", repo))
|
||||||
|
}
|
||||||
|
|
||||||
|
runnerGroups, err := c.Client.ListOrganizationRunnerGroups(ctx, org)
|
||||||
|
if err != nil {
|
||||||
|
return visible, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, runnerGroup := range runnerGroups {
|
||||||
|
ref := NewRunnerGroupFromGitHub(runnerGroup)
|
||||||
|
|
||||||
|
if !managed.Includes(ref) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if runnerGroup.GetVisibility() != "all" {
|
||||||
|
hasAccess, err := c.hasRepoAccessToOrganizationRunnerGroup(ctx, org, runnerGroup.GetID(), repo)
|
||||||
|
if err != nil {
|
||||||
|
return visible, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasAccess {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
visible.Add(ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
return visible, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Simulator) hasRepoAccessToOrganizationRunnerGroup(ctx context.Context, org string, runnerGroupId int64, repo string) (bool, error) {
|
||||||
|
repos, err := c.Client.ListRunnerGroupRepositoryAccesses(ctx, org, runnerGroupId)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, githubRepo := range repos {
|
||||||
|
if githubRepo.GetFullName() == repo {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
180
simulator/runnergroups.go
Normal file
180
simulator/runnergroups.go
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
package simulator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v39/github"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RunnerGroupScope int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Organization RunnerGroupScope = iota
|
||||||
|
Enterprise
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s RunnerGroupScope) String() string {
|
||||||
|
switch s {
|
||||||
|
case Organization:
|
||||||
|
return "Organization"
|
||||||
|
case Enterprise:
|
||||||
|
return "Enterprise"
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unimplemented RunnerGroupScope: %v", int(s)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RunnerGroupKind int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Default RunnerGroupKind = iota
|
||||||
|
Custom
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s RunnerGroupKind) String() string {
|
||||||
|
switch s {
|
||||||
|
case Default:
|
||||||
|
return "Default"
|
||||||
|
case Custom:
|
||||||
|
return "Custom"
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unimplemented RunnerGroupKind: %v", int(s)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRunnerGroupFromGitHub(g *github.RunnerGroup) RunnerGroup {
|
||||||
|
var name string
|
||||||
|
if !g.GetDefault() {
|
||||||
|
name = g.GetName()
|
||||||
|
}
|
||||||
|
|
||||||
|
var scope RunnerGroupScope
|
||||||
|
|
||||||
|
if g.GetInherited() {
|
||||||
|
scope = Enterprise
|
||||||
|
} else {
|
||||||
|
scope = Organization
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRunnerGroup(scope, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRunnerGroupFromProperties(enterprise, organization, group string) RunnerGroup {
|
||||||
|
var scope RunnerGroupScope
|
||||||
|
|
||||||
|
if enterprise != "" {
|
||||||
|
scope = Enterprise
|
||||||
|
} else {
|
||||||
|
scope = Organization
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRunnerGroup(scope, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newRunnerGroup creates a new RunnerGroup instance from the provided arguments.
|
||||||
|
// There's a convention that an empty name implies a default runner group.
|
||||||
|
func newRunnerGroup(scope RunnerGroupScope, name string) RunnerGroup {
|
||||||
|
if name == "" {
|
||||||
|
return RunnerGroup{
|
||||||
|
Scope: scope,
|
||||||
|
Kind: Default,
|
||||||
|
Name: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RunnerGroup{
|
||||||
|
Scope: scope,
|
||||||
|
Kind: Custom,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RunnerGroup struct {
|
||||||
|
Scope RunnerGroupScope
|
||||||
|
Kind RunnerGroupKind
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// VisibleRunnerGroups is a set of enterprise and organization runner groups
|
||||||
|
// that are visible to a GitHub repository.
|
||||||
|
// GitHub Actions chooses one of such visible group on which the workflow job is scheduled.
|
||||||
|
// ARC chooses the same group as Actions as the scale target.
|
||||||
|
type VisibleRunnerGroups struct {
|
||||||
|
// sortedGroups is a pointer to a mutable list of RunnerGroups that contains all the runner sortedGroups
|
||||||
|
// that are visible to the repository, including organization sortedGroups defined at the organization level,
|
||||||
|
// and enterprise sortedGroups that are inherited down to the organization.
|
||||||
|
sortedGroups []RunnerGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVisibleRunnerGroups() *VisibleRunnerGroups {
|
||||||
|
return &VisibleRunnerGroups{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *VisibleRunnerGroups) IsEmpty() bool {
|
||||||
|
return len(g.sortedGroups) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *VisibleRunnerGroups) Includes(ref RunnerGroup) bool {
|
||||||
|
for _, r := range r.sortedGroups {
|
||||||
|
if r.Scope == ref.Scope && r.Kind == ref.Kind && r.Name == ref.Name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds a runner group into VisibleRunnerGroups
|
||||||
|
// at a certain position in the list so that
|
||||||
|
// Traverse can return runner groups in order of higher precedence to lower precedence.
|
||||||
|
func (g *VisibleRunnerGroups) Add(rg RunnerGroup) error {
|
||||||
|
n := len(g.sortedGroups)
|
||||||
|
i := sort.Search(n, func(i int) bool {
|
||||||
|
data := g.sortedGroups[i]
|
||||||
|
|
||||||
|
if rg.Kind > data.Kind {
|
||||||
|
return false
|
||||||
|
} else if rg.Kind < data.Kind {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if rg.Scope > data.Scope {
|
||||||
|
return false
|
||||||
|
} else if rg.Scope < data.Scope {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
g.insert(rg, i)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *VisibleRunnerGroups) insert(rg RunnerGroup, i int) {
|
||||||
|
var result []RunnerGroup
|
||||||
|
|
||||||
|
result = append(result, g.sortedGroups[:i]...)
|
||||||
|
result = append(result, rg)
|
||||||
|
result = append(result, g.sortedGroups[i:]...)
|
||||||
|
|
||||||
|
g.sortedGroups = result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traverse traverses all the runner groups visible to a repository
|
||||||
|
// in order of higher precedence to lower precedence.
|
||||||
|
func (g *VisibleRunnerGroups) Traverse(f func(RunnerGroup) (bool, error)) error {
|
||||||
|
for _, rg := range g.sortedGroups {
|
||||||
|
ok, err := f(rg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
94
simulator/runnergroups_test.go
Normal file
94
simulator/runnergroups_test.go
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
package simulator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVisibleRunnerGroupsInsert(t *testing.T) {
|
||||||
|
g := NewVisibleRunnerGroups()
|
||||||
|
|
||||||
|
orgDefault := NewRunnerGroupFromProperties("", "myorg1", "")
|
||||||
|
orgCustom := NewRunnerGroupFromProperties("", "myorg1", "myorg1group1")
|
||||||
|
enterpriseDefault := NewRunnerGroupFromProperties("myenterprise1", "", "")
|
||||||
|
|
||||||
|
g.insert(orgCustom, 0)
|
||||||
|
g.insert(orgDefault, 0)
|
||||||
|
g.insert(enterpriseDefault, 1)
|
||||||
|
|
||||||
|
var got []RunnerGroup
|
||||||
|
|
||||||
|
err := g.Traverse(func(rg RunnerGroup) (bool, error) {
|
||||||
|
got = append(got, rg)
|
||||||
|
return false, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, []RunnerGroup{orgDefault, enterpriseDefault, orgCustom}, got, "Unexpected result")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVisibleRunnerGroups(t *testing.T) {
|
||||||
|
v := NewVisibleRunnerGroups()
|
||||||
|
|
||||||
|
requireGroups := func(t *testing.T, included, notIncluded []RunnerGroup) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
for _, rg := range included {
|
||||||
|
if !v.Includes(rg) {
|
||||||
|
t.Errorf("%v must be included", rg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rg := range notIncluded {
|
||||||
|
if v.Includes(rg) {
|
||||||
|
t.Errorf("%v must not be included", rg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var got []RunnerGroup
|
||||||
|
|
||||||
|
err := v.Traverse(func(rg RunnerGroup) (bool, error) {
|
||||||
|
got = append(got, rg)
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, included, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
orgDefault := NewRunnerGroupFromProperties("", "myorg1", "")
|
||||||
|
orgCustom := NewRunnerGroupFromProperties("", "myorg1", "myorg1group1")
|
||||||
|
enterpriseDefault := NewRunnerGroupFromProperties("myenterprise1", "", "")
|
||||||
|
enterpriseCustom := NewRunnerGroupFromProperties("myenterprise1", "", "myenterprise1group1")
|
||||||
|
|
||||||
|
requireGroups(t, nil, []RunnerGroup{orgDefault, enterpriseDefault, orgCustom, enterpriseCustom})
|
||||||
|
|
||||||
|
v.Add(orgCustom)
|
||||||
|
|
||||||
|
requireGroups(t, []RunnerGroup{orgCustom}, []RunnerGroup{orgDefault, enterpriseDefault, enterpriseCustom})
|
||||||
|
|
||||||
|
v.Add(orgDefault)
|
||||||
|
|
||||||
|
requireGroups(t, []RunnerGroup{orgDefault, orgCustom}, []RunnerGroup{enterpriseDefault, enterpriseCustom})
|
||||||
|
|
||||||
|
v.Add(enterpriseCustom)
|
||||||
|
|
||||||
|
requireGroups(t, []RunnerGroup{orgDefault, orgCustom, enterpriseCustom}, []RunnerGroup{enterpriseDefault})
|
||||||
|
|
||||||
|
v.Add(enterpriseDefault)
|
||||||
|
|
||||||
|
requireGroups(t, []RunnerGroup{orgDefault, enterpriseDefault, orgCustom, enterpriseCustom}, nil)
|
||||||
|
|
||||||
|
var first []RunnerGroup
|
||||||
|
|
||||||
|
err := v.Traverse(func(rg RunnerGroup) (bool, error) {
|
||||||
|
first = append(first, rg)
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, []RunnerGroup{orgDefault}, first)
|
||||||
|
}
|
||||||
63
test/e2e/cmd/main.go
Normal file
63
test/e2e/cmd/main.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := run(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() error {
|
||||||
|
var configMapNames []string
|
||||||
|
|
||||||
|
output, err := output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Command failed with output: %s", string(output))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s := bufio.NewScanner(bytes.NewBuffer(output))
|
||||||
|
|
||||||
|
for s.Scan() {
|
||||||
|
if t := s.Text(); strings.Contains(t, "test-info") || strings.Contains(t, "test-result-") {
|
||||||
|
configMapNames = append(configMapNames, s.Text())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, n := range configMapNames {
|
||||||
|
println(n)
|
||||||
|
|
||||||
|
if output, err := delete(n); err != nil {
|
||||||
|
log.Printf("Command failed with output: %s", string(output))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func output() ([]byte, error) {
|
||||||
|
cmd := exec.Command("kubectl", "get", "cm", "-o", `jsonpath={range .items[*]}{.metadata.name}{"\n"}{end}`)
|
||||||
|
data, err := cmd.CombinedOutput()
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func delete(cmName string) ([]byte, error) {
|
||||||
|
cmd := exec.Command("kubectl", "delete", "cm", cmName)
|
||||||
|
return cmd.CombinedOutput()
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteControllerManagerSecret() ([]byte, error) {
|
||||||
|
cmd := exec.Command("kubectl", "-n", "actions-runner-system", "delete", "secret", "controller-manager")
|
||||||
|
return cmd.CombinedOutput()
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/actions-runner-controller/actions-runner-controller/testing"
|
"github.com/actions-runner-controller/actions-runner-controller/testing"
|
||||||
@@ -66,7 +67,7 @@ var (
|
|||||||
// This tests ues testing.Logf extensively for debugging purpose.
|
// This tests ues testing.Logf extensively for debugging purpose.
|
||||||
// But messages logged via Logf shows up only when the test failed by default.
|
// But messages logged via Logf shows up only when the test failed by default.
|
||||||
// To always enable logging, do not forget to pass `-test.v` to `go test`.
|
// To always enable logging, do not forget to pass `-test.v` to `go test`.
|
||||||
// If you're using VS Code, open `Workspace Settings` and search for `go test flags`, edit the `settings.json` and put the below:
|
// If you're using VS Code, open `Workspace Settings` and search for `go test flags`, edit the `.vscode/settings.json` and put the below:
|
||||||
// "go.testFlags": ["-v"]
|
// "go.testFlags": ["-v"]
|
||||||
//
|
//
|
||||||
// This function requires a few environment variables to be set to provide some test data.
|
// This function requires a few environment variables to be set to provide some test data.
|
||||||
@@ -166,7 +167,11 @@ type env struct {
|
|||||||
useRunnerSet bool
|
useRunnerSet bool
|
||||||
|
|
||||||
testID string
|
testID string
|
||||||
|
repoToCommit string
|
||||||
runnerLabel, githubToken, testRepo, testOrg, testOrgRepo string
|
runnerLabel, githubToken, testRepo, testOrg, testOrgRepo string
|
||||||
|
githubTokenWebhook string
|
||||||
|
testEnterprise string
|
||||||
|
featureFlagEphemeral bool
|
||||||
testJobs []job
|
testJobs []job
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,10 +191,15 @@ func initTestEnv(t *testing.T) *env {
|
|||||||
e.testID = testID
|
e.testID = testID
|
||||||
e.runnerLabel = "test-" + id
|
e.runnerLabel = "test-" + id
|
||||||
e.githubToken = testing.Getenv(t, "GITHUB_TOKEN")
|
e.githubToken = testing.Getenv(t, "GITHUB_TOKEN")
|
||||||
e.testRepo = testing.Getenv(t, "TEST_REPO")
|
e.githubTokenWebhook = testing.Getenv(t, "WEBHOOK_GITHUB_TOKEN")
|
||||||
e.testOrg = testing.Getenv(t, "TEST_ORG")
|
e.repoToCommit = testing.Getenv(t, "TEST_COMMIT_REPO")
|
||||||
e.testOrgRepo = testing.Getenv(t, "TEST_ORG_REPO")
|
e.testRepo = testing.Getenv(t, "TEST_REPO", "")
|
||||||
e.testJobs = createTestJobs(id, testResultCMNamePrefix, 2)
|
e.testOrg = testing.Getenv(t, "TEST_ORG", "")
|
||||||
|
e.testOrgRepo = testing.Getenv(t, "TEST_ORG_REPO", "")
|
||||||
|
e.testEnterprise = testing.Getenv(t, "TEST_ENTERPRISE")
|
||||||
|
e.testJobs = createTestJobs(id, testResultCMNamePrefix, 10)
|
||||||
|
ephemeral, _ := strconv.ParseBool(testing.Getenv(t, "TEST_FEATURE_FLAG_EPHEMERAL"))
|
||||||
|
e.featureFlagEphemeral = ephemeral
|
||||||
|
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
@@ -237,11 +247,14 @@ func (e *env) installActionsRunnerController(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
varEnv := []string{
|
varEnv := []string{
|
||||||
|
"TEST_ENTERPRISE=" + e.testEnterprise,
|
||||||
"TEST_REPO=" + e.testRepo,
|
"TEST_REPO=" + e.testRepo,
|
||||||
"TEST_ORG=" + e.testOrg,
|
"TEST_ORG=" + e.testOrg,
|
||||||
"TEST_ORG_REPO=" + e.testOrgRepo,
|
"TEST_ORG_REPO=" + e.testOrgRepo,
|
||||||
"GITHUB_TOKEN=" + e.githubToken,
|
"GITHUB_TOKEN=" + e.githubToken,
|
||||||
|
"WEBHOOK_GITHUB_TOKEN=" + e.githubTokenWebhook,
|
||||||
"RUNNER_LABEL=" + e.runnerLabel,
|
"RUNNER_LABEL=" + e.runnerLabel,
|
||||||
|
fmt.Sprintf("RUNNER_FEATURE_FLAG_EPHEMERAL=%v", e.featureFlagEphemeral),
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptEnv = append(scriptEnv, varEnv...)
|
scriptEnv = append(scriptEnv, varEnv...)
|
||||||
@@ -260,7 +273,7 @@ func (e *env) createControllerNamespaceAndServiceAccount(t *testing.T) {
|
|||||||
func (e *env) installActionsWorkflow(t *testing.T) {
|
func (e *env) installActionsWorkflow(t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
installActionsWorkflow(t, e.testID, e.runnerLabel, testResultCMNamePrefix, e.testRepo, e.testJobs)
|
installActionsWorkflow(t, e.testID, e.runnerLabel, testResultCMNamePrefix, e.repoToCommit, e.testJobs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *env) verifyActionsWorkflowRun(t *testing.T) {
|
func (e *env) verifyActionsWorkflowRun(t *testing.T) {
|
||||||
@@ -287,6 +300,8 @@ func createTestJobs(id, testResultCMNamePrefix string, numJobs int) []job {
|
|||||||
return testJobs
|
return testJobs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Branch = "main"
|
||||||
|
|
||||||
func installActionsWorkflow(t *testing.T, testID, runnerLabel, testResultCMNamePrefix, testRepo string, testJobs []job) {
|
func installActionsWorkflow(t *testing.T, testID, runnerLabel, testResultCMNamePrefix, testRepo string, testJobs []job) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@@ -298,7 +313,7 @@ func installActionsWorkflow(t *testing.T, testID, runnerLabel, testResultCMNameP
|
|||||||
Name: wfName,
|
Name: wfName,
|
||||||
On: testing.On{
|
On: testing.On{
|
||||||
Push: &testing.Push{
|
Push: &testing.Push{
|
||||||
Branches: []string{"master"},
|
Branches: []string{Branch},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Jobs: map[string]testing.Job{},
|
Jobs: map[string]testing.Job{},
|
||||||
@@ -346,6 +361,7 @@ kubectl create cm %s$id --from-literal=status=ok
|
|||||||
".github/workflows/workflow.yaml": wfContent,
|
".github/workflows/workflow.yaml": wfContent,
|
||||||
"test.sh": script,
|
"test.sh": script,
|
||||||
},
|
},
|
||||||
|
Branch: Branch,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := g.Sync(ctx); err != nil {
|
if err := g.Sync(ctx); err != nil {
|
||||||
|
|||||||
29
test/entrypoint/should_work_disable_update/config.sh
Executable file
29
test/entrypoint/should_work_disable_update/config.sh
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export LIGHTGREEN='\e[0;32m'
|
||||||
|
export LIGHTRED='\e[0;31m'
|
||||||
|
export WHITE='\e[0;97m'
|
||||||
|
export RESET='\e[0m'
|
||||||
|
|
||||||
|
log(){
|
||||||
|
printf "\t${WHITE}$@${RESET}\n" 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
success(){
|
||||||
|
printf "\t${LIGHTGREEN}$@${RESET}\n" 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
error(){
|
||||||
|
printf "\t${LIGHTRED}$@${RESET}\n" 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
success "I'm configured normally"
|
||||||
|
touch .runner
|
||||||
|
echo "$*" > runner_config
|
||||||
|
success "created a dummy config file"
|
||||||
|
success
|
||||||
|
# Adding a counter to see how many times we've gone through the configuration step
|
||||||
|
count=`cat counter 2>/dev/null|| echo "0"`
|
||||||
|
count=$((count + 1))
|
||||||
|
echo ${count} > counter
|
||||||
|
|
||||||
31
test/entrypoint/should_work_disable_update/runsvc.sh
Executable file
31
test/entrypoint/should_work_disable_update/runsvc.sh
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
export LIGHTGREEN='\e[0;32m'
|
||||||
|
export LIGHTRED='\e[0;31m'
|
||||||
|
export WHITE='\e[0;97m'
|
||||||
|
export RESET='\e[0m'
|
||||||
|
|
||||||
|
log(){
|
||||||
|
printf "\t${WHITE}$@${RESET}\n" 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
success(){
|
||||||
|
printf "\t${LIGHTGREEN}$@${RESET}\n" 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
error(){
|
||||||
|
printf "\t${LIGHTRED}$@${RESET}\n" 2>&1
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
success ""
|
||||||
|
success "Running the service..."
|
||||||
|
# test if --once is present as a parameter
|
||||||
|
echo "$*" | grep -q 'once' || error "Should include --once in the parameters"j
|
||||||
|
success "...successful"
|
||||||
|
touch runsvc_ran
|
||||||
|
success ""
|
||||||
|
|
||||||
|
|
||||||
78
test/entrypoint/should_work_disable_update/test.sh
Executable file
78
test/entrypoint/should_work_disable_update/test.sh
Executable file
@@ -0,0 +1,78 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# UNITTEST: should work disable update
|
||||||
|
# Will simulate a scneario where disableupdate=true. expects:
|
||||||
|
# - the configuration step to be run exactly once
|
||||||
|
# - the entrypoint script to exit with no error
|
||||||
|
# - the config.sh script to run with the --disableupdate flag set to 'true'.
|
||||||
|
|
||||||
|
source ../logging.sh
|
||||||
|
|
||||||
|
entrypoint_log() {
|
||||||
|
while read I; do
|
||||||
|
printf "\tentrypoint.sh: $I\n"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
log "Setting up the test"
|
||||||
|
export UNITTEST=true
|
||||||
|
export RUNNER_HOME=localhome
|
||||||
|
export RUNNER_NAME="example_runner_name"
|
||||||
|
export RUNNER_REPO="myorg/myrepo"
|
||||||
|
export RUNNER_TOKEN="xxxxxxxxxxxxx"
|
||||||
|
export DISABLE_RUNNER_UPDATE="true"
|
||||||
|
|
||||||
|
mkdir -p ${RUNNER_HOME}/bin
|
||||||
|
# add up the config.sh and runsvc.sh
|
||||||
|
ln -s ../config.sh ${RUNNER_HOME}/config.sh
|
||||||
|
ln -s ../../runsvc.sh ${RUNNER_HOME}/bin/runsvc.sh
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -rf ${RUNNER_HOME}
|
||||||
|
unset UNITTEST
|
||||||
|
unset RUNNERHOME
|
||||||
|
unset RUNNER_NAME
|
||||||
|
unset RUNNER_REPO
|
||||||
|
unset RUNNER_TOKEN
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup SIGINT SIGTERM SIGQUIT EXIT
|
||||||
|
|
||||||
|
log "Running the entrypoint"
|
||||||
|
log ""
|
||||||
|
|
||||||
|
../../../runner/entrypoint.sh 2> >(entrypoint_log)
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
error "=========================="
|
||||||
|
error "Test completed with errors"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Testing if the configuration step was run only once"
|
||||||
|
count=`cat ${RUNNER_HOME}/counter || echo "not_found"`
|
||||||
|
if [ ${count} != "1" ]; then
|
||||||
|
error "==============================================="
|
||||||
|
error "The configuration step was not run exactly once"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
success "The configuration ran ${count} time(s)"
|
||||||
|
|
||||||
|
log "Testing if the configuration included the --disableupdate flag"
|
||||||
|
if ! grep -q -- '--disableupdate' ${RUNNER_HOME}/runner_config; then
|
||||||
|
error "==============================================="
|
||||||
|
error "The configuration should not include the --disableupdate flag"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Testing if runsvc ran"
|
||||||
|
if [ ! -f "${RUNNER_HOME}/runsvc_ran" ]; then
|
||||||
|
error "=============================="
|
||||||
|
error "The runner service has not run"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
success "The service ran"
|
||||||
|
success ""
|
||||||
|
success "==========================="
|
||||||
|
success "Test completed successfully"
|
||||||
@@ -5,12 +5,15 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Getenv(t *testing.T, name string) string {
|
func Getenv(t *testing.T, name string, opts ...string) string {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
v := os.Getenv(name)
|
v := os.Getenv(name)
|
||||||
if v == "" {
|
if v == "" {
|
||||||
|
if len(opts) == 0 {
|
||||||
t.Fatal(name + " must be set")
|
t.Fatal(name + " must be set")
|
||||||
}
|
}
|
||||||
|
v = opts[0]
|
||||||
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ type GitRepo struct {
|
|||||||
Name string
|
Name string
|
||||||
CommitMessage string
|
CommitMessage string
|
||||||
Contents map[string][]byte
|
Contents map[string][]byte
|
||||||
|
Branch string
|
||||||
|
|
||||||
runtime.Cmdr
|
runtime.Cmdr
|
||||||
}
|
}
|
||||||
@@ -43,6 +44,11 @@ func (g *GitRepo) Sync(ctx context.Context) error {
|
|||||||
|
|
||||||
for path, content := range g.Contents {
|
for path, content := range g.Contents {
|
||||||
absPath := filepath.Join(dir, path)
|
absPath := filepath.Join(dir, path)
|
||||||
|
d := filepath.Dir(absPath)
|
||||||
|
|
||||||
|
if err := os.MkdirAll(d, 0755); err != nil {
|
||||||
|
return fmt.Errorf("error creating dir %s: %v", d, err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(absPath, content, 0755); err != nil {
|
if err := os.WriteFile(absPath, content, 0755); err != nil {
|
||||||
return fmt.Errorf("error writing %s: %w", path, err)
|
return fmt.Errorf("error writing %s: %w", path, err)
|
||||||
@@ -89,7 +95,7 @@ func (g *GitRepo) gitCommitCmd(ctx context.Context, dir, msg string) *exec.Cmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GitRepo) gitPushCmd(ctx context.Context, dir string) *exec.Cmd {
|
func (g *GitRepo) gitPushCmd(ctx context.Context, dir string) *exec.Cmd {
|
||||||
cmd := exec.CommandContext(ctx, "git", "push", "origin", "master")
|
cmd := exec.CommandContext(ctx, "git", "push", "origin", g.Branch)
|
||||||
cmd.Dir = dir
|
cmd.Dir = dir
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -323,6 +323,11 @@ func (k *Kind) Start(ctx context.Context) error {
|
|||||||
kindConfig := []byte(fmt.Sprintf(`kind: Cluster
|
kindConfig := []byte(fmt.Sprintf(`kind: Cluster
|
||||||
apiVersion: kind.x-k8s.io/v1alpha4
|
apiVersion: kind.x-k8s.io/v1alpha4
|
||||||
name: %s
|
name: %s
|
||||||
|
networking:
|
||||||
|
apiServerAddress: 0.0.0.0
|
||||||
|
nodes:
|
||||||
|
- role: control-plane
|
||||||
|
- role: worker
|
||||||
`, k.Name))
|
`, k.Name))
|
||||||
|
|
||||||
if err := os.WriteFile(f.Name(), kindConfig, 0644); err != nil {
|
if err := os.WriteFile(f.Name(), kindConfig, 0644); err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user