mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-04-06 16:58:48 +02:00
Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64a7bb8f02 | ||
|
|
bc1908cdea | ||
|
|
4bacb3a381 | ||
|
|
9e06a83c2f | ||
|
|
4a02cf1639 | ||
|
|
7a5cf79984 | ||
|
|
798642dc19 | ||
|
|
aa60207496 | ||
|
|
5611eea361 | ||
|
|
4376093af0 | ||
|
|
435691827a | ||
|
|
3bcdec30f3 | ||
|
|
ccd7f76768 | ||
|
|
c2cb6691dd | ||
|
|
eb06207959 | ||
|
|
23c950728a | ||
|
|
1c0a505140 | ||
|
|
b1986bb6a5 | ||
|
|
36a134fa4a | ||
|
|
b4df63495a | ||
|
|
1a5bcf858a | ||
|
|
c9ca3ff5f6 | ||
|
|
64a09a1fb6 | ||
|
|
bb24b5c38a | ||
|
|
1125042e5b | ||
|
|
471e386ff0 | ||
|
|
ae3f5402ab | ||
|
|
1dfb61ec60 | ||
|
|
4cb8de4501 | ||
|
|
403ec2786b | ||
|
|
9075a56650 | ||
|
|
5ccaafc504 | ||
|
|
58bb6adc79 | ||
|
|
7aa54a5e17 | ||
|
|
6ade5f2bad | ||
|
|
9cd67b16f3 | ||
|
|
33d756e8d9 | ||
|
|
48edd4d998 | ||
|
|
3e96e915dd | ||
|
|
7530d3ff8e | ||
|
|
6c3b07f56d | ||
|
|
8833e41511 | ||
|
|
d3d03868d8 | ||
|
|
7d853494ec | ||
|
|
602f8d07f9 | ||
|
|
2dfcb49b34 | ||
|
|
5eb4e0fee5 | ||
|
|
af9a51603b | ||
|
|
62e23e2e80 | ||
|
|
e5fc4f5a9c | ||
|
|
8ca2b1de52 | ||
|
|
6dd79895e2 | ||
|
|
333f0d72a1 | ||
|
|
5a21561d6e | ||
|
|
ee8016b3d9 | ||
|
|
2a584836b8 | ||
|
|
3d328268f0 | ||
|
|
26f116af70 | ||
|
|
a08a6fc7d9 | ||
|
|
d311fad538 | ||
|
|
a18be650b8 | ||
|
|
72013390bd | ||
|
|
93547ce7ea | ||
|
|
dbf5ea5935 | ||
|
|
fa1fd6965e | ||
|
|
1f7e47f747 | ||
|
|
2d9dc7f75a | ||
|
|
f93dc55a55 | ||
|
|
46ec2d1b46 | ||
|
|
b413afd522 | ||
|
|
702082e4c9 | ||
|
|
e5f1194a6d | ||
|
|
ef4f103ee8 | ||
|
|
1925612f1b | ||
|
|
86f75b05ea | ||
|
|
35546fd856 | ||
|
|
9ce407fec0 |
59
.github/workflows/ci-build.yaml
vendored
59
.github/workflows/ci-build.yaml
vendored
@@ -9,6 +9,7 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'release-*'
|
||||
|
||||
env:
|
||||
# Golang version to use across CI steps
|
||||
@@ -27,9 +28,9 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Download all Go modules
|
||||
@@ -45,13 +46,13 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Restore go build cache
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3
|
||||
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
|
||||
with:
|
||||
path: ~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
|
||||
@@ -69,9 +70,9 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Run golangci-lint
|
||||
@@ -92,11 +93,11 @@ jobs:
|
||||
- name: Create checkout directory
|
||||
run: mkdir -p ~/go/src/github.com/argoproj
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
- name: Create symlink in GOPATH
|
||||
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Install required packages
|
||||
@@ -116,13 +117,17 @@ jobs:
|
||||
run: |
|
||||
echo "/usr/local/bin" >> $GITHUB_PATH
|
||||
- name: Restore go build cache
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3
|
||||
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
|
||||
with:
|
||||
path: ~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
|
||||
- name: Install all tools required for building & testing
|
||||
run: |
|
||||
make install-test-tools-local
|
||||
# We install kustomize in the dist directory
|
||||
- name: Add dist to PATH
|
||||
run: |
|
||||
echo "/home/runner/work/argo-cd/argo-cd/dist" >> $GITHUB_PATH
|
||||
- name: Setup git username and email
|
||||
run: |
|
||||
git config --global user.name "John Doe"
|
||||
@@ -155,11 +160,11 @@ jobs:
|
||||
- name: Create checkout directory
|
||||
run: mkdir -p ~/go/src/github.com/argoproj
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
- name: Create symlink in GOPATH
|
||||
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Install required packages
|
||||
@@ -179,13 +184,17 @@ jobs:
|
||||
run: |
|
||||
echo "/usr/local/bin" >> $GITHUB_PATH
|
||||
- name: Restore go build cache
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3
|
||||
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
|
||||
with:
|
||||
path: ~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
|
||||
- name: Install all tools required for building & testing
|
||||
run: |
|
||||
make install-test-tools-local
|
||||
# We install kustomize in the dist directory
|
||||
- name: Add dist to PATH
|
||||
run: |
|
||||
echo "/home/runner/work/argo-cd/argo-cd/dist" >> $GITHUB_PATH
|
||||
- name: Setup git username and email
|
||||
run: |
|
||||
git config --global user.name "John Doe"
|
||||
@@ -206,9 +215,9 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Create symlink in GOPATH
|
||||
@@ -232,6 +241,10 @@ jobs:
|
||||
make install-codegen-tools-local
|
||||
make install-go-tools-local
|
||||
working-directory: /home/runner/go/src/github.com/argoproj/argo-cd
|
||||
# We install kustomize in the dist directory
|
||||
- name: Add dist to PATH
|
||||
run: |
|
||||
echo "/home/runner/work/argo-cd/argo-cd/dist" >> $GITHUB_PATH
|
||||
- name: Run codegen
|
||||
run: |
|
||||
set -x
|
||||
@@ -250,14 +263,14 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
- name: Setup NodeJS
|
||||
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
|
||||
with:
|
||||
node-version: '12.18.4'
|
||||
- name: Restore node dependency cache
|
||||
id: cache-dependencies
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3
|
||||
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
|
||||
with:
|
||||
path: ui/node_modules
|
||||
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
|
||||
@@ -287,12 +300,12 @@ jobs:
|
||||
sonar_secret: ${{ secrets.SONAR_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Restore node dependency cache
|
||||
id: cache-dependencies
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3
|
||||
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
|
||||
with:
|
||||
path: ui/node_modules
|
||||
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
|
||||
@@ -366,9 +379,9 @@ jobs:
|
||||
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: GH actions workaround - Kill XSP4 process
|
||||
@@ -386,7 +399,7 @@ jobs:
|
||||
sudo chown runner $HOME/.kube/config
|
||||
kubectl version
|
||||
- name: Restore go build cache
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3
|
||||
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
|
||||
with:
|
||||
path: ~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
|
||||
@@ -414,7 +427,7 @@ jobs:
|
||||
run: |
|
||||
docker pull ghcr.io/dexidp/dex:v2.35.3
|
||||
docker pull argoproj/argo-cd-ci-builder:v1.0.0
|
||||
docker pull redis:7.0.7-alpine
|
||||
docker pull redis:7.0.8-alpine
|
||||
- name: Create target directory for binaries in the build-process
|
||||
run: |
|
||||
mkdir -p dist
|
||||
|
||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
10
.github/workflows/image.yaml
vendored
10
.github/workflows/image.yaml
vendored
@@ -28,10 +28,10 @@ jobs:
|
||||
env:
|
||||
GOPATH: /home/runner/work/argo-cd/argo-cd
|
||||
steps:
|
||||
- uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
- uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
with:
|
||||
path: src/github.com/argoproj/argo-cd
|
||||
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
|
||||
# build
|
||||
- uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0
|
||||
- uses: docker/setup-buildx-action@8c0edbc76e98fa90f69d9a2c020dcb50019dc325 # v2.2.1
|
||||
- uses: docker/setup-buildx-action@f03ac48505955848960e80bbb68046aa35c7b9e7 # v2.4.1
|
||||
- run: |
|
||||
IMAGE_PLATFORMS=linux/amd64
|
||||
if [[ "${{ github.event_name }}" == "push" || "${{ contains(github.event.pull_request.labels.*.name, 'test-arm-image') }}" == "true" ]]
|
||||
@@ -68,12 +68,12 @@ jobs:
|
||||
|
||||
# sign container images
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@9becc617647dfa20ae7b1151972e9b3a2c338a2b # v2.8.1
|
||||
uses: sigstore/cosign-installer@c3667d99424e7e6047999fb6246c0da843953c65 # v3.0.1
|
||||
with:
|
||||
cosign-release: 'v1.13.1'
|
||||
|
||||
- name: Install crane to get digest of image
|
||||
uses: imjasonh/setup-crane@e82f1b9a8007d399333baba4d75915558e9fb6a4
|
||||
uses: imjasonh/setup-crane@00c9e93efa4e1138c9a7a5c594acd6c75a2fbf0c
|
||||
|
||||
- name: Get digest of image
|
||||
run: |
|
||||
|
||||
14
.github/workflows/release.yaml
vendored
14
.github/workflows/release.yaml
vendored
@@ -43,7 +43,7 @@ jobs:
|
||||
GIT_EMAIL: argoproj@gmail.com
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -147,7 +147,7 @@ jobs:
|
||||
echo "RELEASE_NOTES=${RELEASE_NOTES}" >> $GITHUB_ENV
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
|
||||
@@ -177,6 +177,10 @@ jobs:
|
||||
run: |
|
||||
set -ue
|
||||
make install-codegen-tools-local
|
||||
|
||||
# We install kustomize in the dist directory
|
||||
echo "/home/runner/work/argo-cd/argo-cd/dist" >> $GITHUB_PATH
|
||||
|
||||
make manifests-local VERSION=${TARGET_VERSION}
|
||||
git diff
|
||||
git commit manifests/ -m "Bump version to ${TARGET_VERSION}"
|
||||
@@ -201,7 +205,7 @@ jobs:
|
||||
if: ${{ env.DRY_RUN != 'true' }}
|
||||
|
||||
- uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0
|
||||
- uses: docker/setup-buildx-action@8c0edbc76e98fa90f69d9a2c020dcb50019dc325 # v2.2.1
|
||||
- uses: docker/setup-buildx-action@f03ac48505955848960e80bbb68046aa35c7b9e7 # v2.4.1
|
||||
- name: Build and push Docker image for release
|
||||
run: |
|
||||
set -ue
|
||||
@@ -215,12 +219,12 @@ jobs:
|
||||
if: ${{ env.DRY_RUN != 'true' }}
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@9becc617647dfa20ae7b1151972e9b3a2c338a2b # v2.8.1
|
||||
uses: sigstore/cosign-installer@c3667d99424e7e6047999fb6246c0da843953c65 # v3.0.1
|
||||
with:
|
||||
cosign-release: 'v1.13.1'
|
||||
|
||||
- name: Install crane to get digest of image
|
||||
uses: imjasonh/setup-crane@e82f1b9a8007d399333baba4d75915558e9fb6a4
|
||||
uses: imjasonh/setup-crane@00c9e93efa4e1138c9a7a5c594acd6c75a2fbf0c
|
||||
|
||||
- name: Get digest of image
|
||||
run: |
|
||||
|
||||
2
.github/workflows/update-snyk.yaml
vendored
2
.github/workflows/update-snyk.yaml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build reports
|
||||
|
||||
3
USERS.md
3
USERS.md
@@ -96,6 +96,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [IITS-Consulting](https://iits-consulting.de)
|
||||
1. [imaware](https://imaware.health)
|
||||
1. [Index Exchange](https://www.indexexchange.com/)
|
||||
1. [Info Support](https://www.infosupport.com/)
|
||||
1. [InsideBoard](https://www.insideboard.com)
|
||||
1. [Intuit](https://www.intuit.com/)
|
||||
1. [Joblift](https://joblift.com/)
|
||||
@@ -155,6 +156,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Packlink](https://www.packlink.com/)
|
||||
1. [Pandosearch](https://www.pandosearch.com/en/home)
|
||||
1. [PagerDuty](https://www.pagerduty.com/)
|
||||
1. [Patreon](https://www.patreon.com/)
|
||||
1. [PayPay](https://paypay.ne.jp/)
|
||||
1. [Peloton Interactive](https://www.onepeloton.com/)
|
||||
1. [Pipefy](https://www.pipefy.com/)
|
||||
@@ -171,6 +173,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [RapidAPI](https://www.rapidapi.com/)
|
||||
1. [Recreation.gov](https://www.recreation.gov/)
|
||||
1. [Red Hat](https://www.redhat.com/)
|
||||
1. [Redpill Linpro](https://www.redpill-linpro.com/)
|
||||
1. [reev.com](https://www.reev.com/)
|
||||
1. [RightRev](https://rightrev.com/)
|
||||
1. [Rise](https://www.risecard.eu/)
|
||||
|
||||
179
applicationset/controllers/requeue_after_test.go
Normal file
179
applicationset/controllers/requeue_after_test.go
Normal file
@@ -0,0 +1,179 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/generators"
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
dynfake "k8s.io/client-go/dynamic/fake"
|
||||
kubefake "k8s.io/client-go/kubernetes/fake"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
)
|
||||
|
||||
func TestRequeueAfter(t *testing.T) {
|
||||
mockServer := argoCDServiceMock{}
|
||||
ctx := context.Background()
|
||||
scheme := runtime.NewScheme()
|
||||
err := argov1alpha1.AddToScheme(scheme)
|
||||
assert.Nil(t, err)
|
||||
gvrToListKind := map[schema.GroupVersionResource]string{{
|
||||
Group: "mallard.io",
|
||||
Version: "v1",
|
||||
Resource: "ducks",
|
||||
}: "DuckList"}
|
||||
appClientset := kubefake.NewSimpleClientset()
|
||||
k8sClient := fake.NewClientBuilder().Build()
|
||||
duckType := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v2quack",
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "mightyduck",
|
||||
"namespace": "namespace",
|
||||
"labels": map[string]interface{}{"duck": "all-species"},
|
||||
},
|
||||
"status": map[string]interface{}{
|
||||
"decisions": []interface{}{
|
||||
map[string]interface{}{
|
||||
"clusterName": "staging-01",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"clusterName": "production-01",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
fakeDynClient := dynfake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), gvrToListKind, duckType)
|
||||
|
||||
terminalGenerators := map[string]generators.Generator{
|
||||
"List": generators.NewListGenerator(),
|
||||
"Clusters": generators.NewClusterGenerator(k8sClient, ctx, appClientset, "argocd"),
|
||||
"Git": generators.NewGitGenerator(mockServer),
|
||||
"SCMProvider": generators.NewSCMProviderGenerator(fake.NewClientBuilder().WithObjects(&corev1.Secret{}).Build(), generators.SCMAuthProviders{}),
|
||||
"ClusterDecisionResource": generators.NewDuckTypeGenerator(ctx, fakeDynClient, appClientset, "argocd"),
|
||||
"PullRequest": generators.NewPullRequestGenerator(k8sClient, generators.SCMAuthProviders{}),
|
||||
}
|
||||
|
||||
nestedGenerators := map[string]generators.Generator{
|
||||
"List": terminalGenerators["List"],
|
||||
"Clusters": terminalGenerators["Clusters"],
|
||||
"Git": terminalGenerators["Git"],
|
||||
"SCMProvider": terminalGenerators["SCMProvider"],
|
||||
"ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"],
|
||||
"PullRequest": terminalGenerators["PullRequest"],
|
||||
"Matrix": generators.NewMatrixGenerator(terminalGenerators),
|
||||
"Merge": generators.NewMergeGenerator(terminalGenerators),
|
||||
}
|
||||
|
||||
topLevelGenerators := map[string]generators.Generator{
|
||||
"List": terminalGenerators["List"],
|
||||
"Clusters": terminalGenerators["Clusters"],
|
||||
"Git": terminalGenerators["Git"],
|
||||
"SCMProvider": terminalGenerators["SCMProvider"],
|
||||
"ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"],
|
||||
"PullRequest": terminalGenerators["PullRequest"],
|
||||
"Matrix": generators.NewMatrixGenerator(nestedGenerators),
|
||||
"Merge": generators.NewMergeGenerator(nestedGenerators),
|
||||
}
|
||||
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).Build()
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
Scheme: scheme,
|
||||
Recorder: record.NewFakeRecorder(0),
|
||||
Generators: topLevelGenerators,
|
||||
}
|
||||
|
||||
type args struct {
|
||||
appset *argov1alpha1.ApplicationSet
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want time.Duration
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{name: "Cluster", args: args{appset: &argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{{Clusters: &argov1alpha1.ClusterGenerator{}}},
|
||||
},
|
||||
}}, want: generators.NoRequeueAfter, wantErr: assert.NoError},
|
||||
{name: "ClusterMergeNested", args: args{&argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{
|
||||
{Clusters: &argov1alpha1.ClusterGenerator{}},
|
||||
{Merge: &argov1alpha1.MergeGenerator{
|
||||
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Clusters: &argov1alpha1.ClusterGenerator{},
|
||||
Git: &argov1alpha1.GitGenerator{},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}, want: generators.DefaultRequeueAfterSeconds, wantErr: assert.NoError},
|
||||
{name: "ClusterMatrixNested", args: args{&argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{
|
||||
{Clusters: &argov1alpha1.ClusterGenerator{}},
|
||||
{Matrix: &argov1alpha1.MatrixGenerator{
|
||||
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Clusters: &argov1alpha1.ClusterGenerator{},
|
||||
Git: &argov1alpha1.GitGenerator{},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}, want: generators.DefaultRequeueAfterSeconds, wantErr: assert.NoError},
|
||||
{name: "ListGenerator", args: args{appset: &argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{{List: &argov1alpha1.ListGenerator{}}},
|
||||
},
|
||||
}}, want: generators.NoRequeueAfter, wantErr: assert.NoError},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equalf(t, tt.want, r.getMinRequeueAfter(tt.args.appset), "getMinRequeueAfter(%v)", tt.args.appset)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type argoCDServiceMock struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (a argoCDServiceMock) GetApps(ctx context.Context, repoURL string, revision string) ([]string, error) {
|
||||
args := a.mock.Called(ctx, repoURL, revision)
|
||||
|
||||
return args.Get(0).([]string), args.Error(1)
|
||||
}
|
||||
|
||||
func (a argoCDServiceMock) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) {
|
||||
args := a.mock.Called(ctx, repoURL, revision, pattern)
|
||||
|
||||
return args.Get(0).(map[string][]byte), args.Error(1)
|
||||
}
|
||||
|
||||
func (a argoCDServiceMock) GetFileContent(ctx context.Context, repoURL string, revision string, path string) ([]byte, error) {
|
||||
args := a.mock.Called(ctx, repoURL, revision, path)
|
||||
|
||||
return args.Get(0).([]byte), args.Error(1)
|
||||
}
|
||||
|
||||
func (a argoCDServiceMock) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) {
|
||||
args := a.mock.Called(ctx, repoURL, revision)
|
||||
return args.Get(0).([]string), args.Error(1)
|
||||
}
|
||||
@@ -51,6 +51,8 @@ func NewClusterGenerator(c client.Client, ctx context.Context, clientset kuberne
|
||||
return g
|
||||
}
|
||||
|
||||
// GetRequeueAfter never requeue the cluster generator because the `clusterSecretEventHandler` will requeue the appsets
|
||||
// when the cluster secrets change
|
||||
func (g *ClusterGenerator) GetRequeueAfter(appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator) time.Duration {
|
||||
return NoRequeueAfter
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package generators
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
@@ -24,7 +23,7 @@ type TransformResult struct {
|
||||
Template argoprojiov1alpha1.ApplicationSetTemplate
|
||||
}
|
||||
|
||||
//Transform a spec generator to list of paramSets and a template
|
||||
// Transform a spec generator to list of paramSets and a template
|
||||
func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, allGenerators map[string]Generator, baseTemplate argoprojiov1alpha1.ApplicationSetTemplate, appSet *argoprojiov1alpha1.ApplicationSet, genParams map[string]interface{}) ([]TransformResult, error) {
|
||||
selector, err := metav1.LabelSelectorAsSelector(requestedGenerator.Selector)
|
||||
if err != nil {
|
||||
@@ -131,27 +130,15 @@ func mergeGeneratorTemplate(g Generator, requestedGenerator *argoprojiov1alpha1.
|
||||
return *dest, err
|
||||
}
|
||||
|
||||
// Currently for Matrix Generator. Allows interpolating the matrix's 2nd child generator with values from the 1st child generator
|
||||
// InterpolateGenerator allows interpolating the matrix's 2nd child generator with values from the 1st child generator
|
||||
// "params" parameter is an array, where each index corresponds to a generator. Each index contains a map w/ that generator's parameters.
|
||||
func InterpolateGenerator(requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, params map[string]interface{}, useGoTemplate bool) (argoprojiov1alpha1.ApplicationSetGenerator, error) {
|
||||
interpolatedGenerator := requestedGenerator.DeepCopy()
|
||||
tmplBytes, err := json.Marshal(interpolatedGenerator)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("requestedGenerator", interpolatedGenerator).Error("error marshalling requested generator for interpolation")
|
||||
return *interpolatedGenerator, err
|
||||
}
|
||||
|
||||
render := utils.Render{}
|
||||
replacedTmplStr, err := render.Replace(string(tmplBytes), params, useGoTemplate)
|
||||
interpolatedGenerator, err := render.RenderGeneratorParams(requestedGenerator, params, useGoTemplate)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("interpolatedGeneratorString", replacedTmplStr).Error("error interpolating generator with other generator's parameter")
|
||||
log.WithError(err).WithField("interpolatedGenerator", interpolatedGenerator).Error("error interpolating generator with other generator's parameter")
|
||||
return *interpolatedGenerator, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(replacedTmplStr), interpolatedGenerator)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("requestedGenerator", interpolatedGenerator).Error("error unmarshalling requested generator for interpolation")
|
||||
return *interpolatedGenerator, err
|
||||
}
|
||||
return *interpolatedGenerator, nil
|
||||
}
|
||||
|
||||
@@ -6,9 +6,11 @@ import (
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
testutils "github.com/argoproj/argo-cd/v2/applicationset/utils/test"
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
@@ -159,8 +161,8 @@ func getMockClusterGenerator() Generator {
|
||||
}
|
||||
|
||||
func getMockGitGenerator() Generator {
|
||||
argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}}
|
||||
argoCDServiceMock.mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return([]string{"app1", "app2", "app_3", "p1/app4"}, nil)
|
||||
argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}}
|
||||
argoCDServiceMock.Mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return([]string{"app1", "app2", "app_3", "p1/app4"}, nil)
|
||||
var gitGenerator = NewGitGenerator(argoCDServiceMock)
|
||||
return gitGenerator
|
||||
}
|
||||
@@ -248,6 +250,60 @@ func TestInterpolateGenerator(t *testing.T) {
|
||||
Path: "{{server}}",
|
||||
}
|
||||
|
||||
requestedGenerator = &argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Git: &argoprojiov1alpha1.GitGenerator{
|
||||
Files: append([]argoprojiov1alpha1.GitFileGeneratorItem{}, fileNamePath, fileServerPath),
|
||||
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
}
|
||||
clusterGeneratorParams := map[string]interface{}{
|
||||
"name": "production_01/west", "server": "https://production-01.example.com",
|
||||
}
|
||||
interpolatedGenerator, err = InterpolateGenerator(requestedGenerator, clusterGeneratorParams, false)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("requestedGenerator", requestedGenerator).Error("error interpolating Generator")
|
||||
return
|
||||
}
|
||||
assert.Equal(t, "production_01/west", interpolatedGenerator.Git.Files[0].Path)
|
||||
assert.Equal(t, "https://production-01.example.com", interpolatedGenerator.Git.Files[1].Path)
|
||||
}
|
||||
|
||||
func TestInterpolateGenerator_go(t *testing.T) {
|
||||
requestedGenerator := &argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Clusters: &argoprojiov1alpha1.ClusterGenerator{
|
||||
Selector: metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"path-basename": "{{base .path.path}}",
|
||||
"path-zero": "{{index .path.segments 0}}",
|
||||
"path-full": "{{.path.path}}",
|
||||
"kubernetes.io/environment": `{{default "foo" .my_label}}`,
|
||||
}},
|
||||
},
|
||||
}
|
||||
gitGeneratorParams := map[string]interface{}{
|
||||
"path": map[string]interface{}{
|
||||
"path": "p1/p2/app3",
|
||||
"segments": []string{"p1", "p2", "app3"},
|
||||
},
|
||||
}
|
||||
interpolatedGenerator, err := InterpolateGenerator(requestedGenerator, gitGeneratorParams, true)
|
||||
require.NoError(t, err)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("requestedGenerator", requestedGenerator).Error("error interpolating Generator")
|
||||
return
|
||||
}
|
||||
assert.Equal(t, "app3", interpolatedGenerator.Clusters.Selector.MatchLabels["path-basename"])
|
||||
assert.Equal(t, "p1", interpolatedGenerator.Clusters.Selector.MatchLabels["path-zero"])
|
||||
assert.Equal(t, "p1/p2/app3", interpolatedGenerator.Clusters.Selector.MatchLabels["path-full"])
|
||||
|
||||
fileNamePath := argoprojiov1alpha1.GitFileGeneratorItem{
|
||||
Path: "{{.name}}",
|
||||
}
|
||||
fileServerPath := argoprojiov1alpha1.GitFileGeneratorItem{
|
||||
Path: "{{.server}}",
|
||||
}
|
||||
|
||||
requestedGenerator = &argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Git: &argoprojiov1alpha1.GitGenerator{
|
||||
Files: append([]argoprojiov1alpha1.GitFileGeneratorItem{}, fileNamePath, fileServerPath),
|
||||
|
||||
@@ -58,9 +58,9 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
|
||||
|
||||
var err error
|
||||
var res []map[string]interface{}
|
||||
if appSetGenerator.Git.Directories != nil {
|
||||
if len(appSetGenerator.Git.Directories) != 0 {
|
||||
res, err = g.generateParamsForGitDirectories(appSetGenerator, appSet.Spec.GoTemplate)
|
||||
} else if appSetGenerator.Git.Files != nil {
|
||||
} else if len(appSetGenerator.Git.Files) != 0 {
|
||||
res, err = g.generateParamsForGitFiles(appSetGenerator, appSet.Spec.GoTemplate)
|
||||
} else {
|
||||
return nil, EmptyAppSetGeneratorError
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package generators
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
@@ -9,6 +8,7 @@ import (
|
||||
"github.com/stretchr/testify/mock"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
testutils "github.com/argoproj/argo-cd/v2/applicationset/utils/test"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
@@ -20,33 +20,6 @@ import (
|
||||
// return io.NewCloser(func() error { return nil }), c.RepoServerServiceClient, nil
|
||||
// }
|
||||
|
||||
type argoCDServiceMock struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (a argoCDServiceMock) GetApps(ctx context.Context, repoURL string, revision string) ([]string, error) {
|
||||
args := a.mock.Called(ctx, repoURL, revision)
|
||||
|
||||
return args.Get(0).([]string), args.Error(1)
|
||||
}
|
||||
|
||||
func (a argoCDServiceMock) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) {
|
||||
args := a.mock.Called(ctx, repoURL, revision, pattern)
|
||||
|
||||
return args.Get(0).(map[string][]byte), args.Error(1)
|
||||
}
|
||||
|
||||
func (a argoCDServiceMock) GetFileContent(ctx context.Context, repoURL string, revision string, path string) ([]byte, error) {
|
||||
args := a.mock.Called(ctx, repoURL, revision, path)
|
||||
|
||||
return args.Get(0).([]byte), args.Error(1)
|
||||
}
|
||||
|
||||
func (a argoCDServiceMock) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) {
|
||||
args := a.mock.Called(ctx, repoURL, revision)
|
||||
return args.Get(0).([]string), args.Error(1)
|
||||
}
|
||||
|
||||
func Test_generateParamsFromGitFile(t *testing.T) {
|
||||
params, err := (*GitGenerator)(nil).generateParamsFromGitFile("path/dir/file_name.yaml", []byte(`
|
||||
foo:
|
||||
@@ -200,9 +173,9 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
|
||||
t.Run(testCaseCopy.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}}
|
||||
argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}}
|
||||
|
||||
argoCDServiceMock.mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
|
||||
argoCDServiceMock.Mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
|
||||
|
||||
var gitGenerator = NewGitGenerator(argoCDServiceMock)
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
@@ -229,7 +202,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
|
||||
assert.Equal(t, testCaseCopy.expected, got)
|
||||
}
|
||||
|
||||
argoCDServiceMock.mock.AssertExpectations(t)
|
||||
argoCDServiceMock.Mock.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -442,9 +415,9 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) {
|
||||
t.Run(testCaseCopy.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}}
|
||||
argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}}
|
||||
|
||||
argoCDServiceMock.mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
|
||||
argoCDServiceMock.Mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
|
||||
|
||||
var gitGenerator = NewGitGenerator(argoCDServiceMock)
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
@@ -472,7 +445,7 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) {
|
||||
assert.Equal(t, testCaseCopy.expected, got)
|
||||
}
|
||||
|
||||
argoCDServiceMock.mock.AssertExpectations(t)
|
||||
argoCDServiceMock.Mock.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -732,8 +705,8 @@ cluster:
|
||||
t.Run(testCaseCopy.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}}
|
||||
argoCDServiceMock.mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||
argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}}
|
||||
argoCDServiceMock.Mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||
Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError)
|
||||
|
||||
var gitGenerator = NewGitGenerator(argoCDServiceMock)
|
||||
@@ -762,7 +735,7 @@ cluster:
|
||||
assert.ElementsMatch(t, testCaseCopy.expected, got)
|
||||
}
|
||||
|
||||
argoCDServiceMock.mock.AssertExpectations(t)
|
||||
argoCDServiceMock.Mock.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1081,8 +1054,8 @@ cluster:
|
||||
t.Run(testCaseCopy.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}}
|
||||
argoCDServiceMock.mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||
argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}}
|
||||
argoCDServiceMock.Mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||
Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError)
|
||||
|
||||
var gitGenerator = NewGitGenerator(argoCDServiceMock)
|
||||
@@ -1112,7 +1085,7 @@ cluster:
|
||||
assert.ElementsMatch(t, testCaseCopy.expected, got)
|
||||
}
|
||||
|
||||
argoCDServiceMock.mock.AssertExpectations(t)
|
||||
argoCDServiceMock.Mock.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,28 +80,13 @@ func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.App
|
||||
}
|
||||
|
||||
func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet, params map[string]interface{}) ([]map[string]interface{}, error) {
|
||||
var matrix *argoprojiov1alpha1.MatrixGenerator
|
||||
if appSetBaseGenerator.Matrix != nil {
|
||||
// Since nested matrix generator is represented as a JSON object in the CRD, we unmarshall it back to a Go struct here.
|
||||
nestedMatrix, err := argoprojiov1alpha1.ToNestedMatrixGenerator(appSetBaseGenerator.Matrix)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshall nested matrix generator: %v", err)
|
||||
}
|
||||
if nestedMatrix != nil {
|
||||
matrix = nestedMatrix.ToMatrixGenerator()
|
||||
}
|
||||
matrixGen, err := getMatrixGenerator(appSetBaseGenerator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var mergeGenerator *argoprojiov1alpha1.MergeGenerator
|
||||
if appSetBaseGenerator.Merge != nil {
|
||||
// Since nested merge generator is represented as a JSON object in the CRD, we unmarshall it back to a Go struct here.
|
||||
nestedMerge, err := argoprojiov1alpha1.ToNestedMergeGenerator(appSetBaseGenerator.Merge)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshall nested merge generator: %v", err)
|
||||
}
|
||||
if nestedMerge != nil {
|
||||
mergeGenerator = nestedMerge.ToMergeGenerator()
|
||||
}
|
||||
mergeGen, err := getMergeGenerator(appSetBaseGenerator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t, err := Transform(
|
||||
@@ -112,8 +97,8 @@ func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Appli
|
||||
SCMProvider: appSetBaseGenerator.SCMProvider,
|
||||
ClusterDecisionResource: appSetBaseGenerator.ClusterDecisionResource,
|
||||
PullRequest: appSetBaseGenerator.PullRequest,
|
||||
Matrix: matrix,
|
||||
Merge: mergeGenerator,
|
||||
Matrix: matrixGen,
|
||||
Merge: mergeGen,
|
||||
Selector: appSetBaseGenerator.Selector,
|
||||
},
|
||||
m.supportedGenerators,
|
||||
@@ -143,11 +128,15 @@ func (m *MatrixGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Ap
|
||||
var found bool
|
||||
|
||||
for _, r := range appSetGenerator.Matrix.Generators {
|
||||
matrixGen, _ := getMatrixGenerator(r)
|
||||
mergeGen, _ := getMergeGenerator(r)
|
||||
base := &argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
List: r.List,
|
||||
Clusters: r.Clusters,
|
||||
Git: r.Git,
|
||||
PullRequest: r.PullRequest,
|
||||
Matrix: matrixGen,
|
||||
Merge: mergeGen,
|
||||
}
|
||||
generators := GetRelevantGenerators(base, m.supportedGenerators)
|
||||
|
||||
@@ -168,6 +157,17 @@ func (m *MatrixGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Ap
|
||||
|
||||
}
|
||||
|
||||
func getMatrixGenerator(r argoprojiov1alpha1.ApplicationSetNestedGenerator) (*argoprojiov1alpha1.MatrixGenerator, error) {
|
||||
if r.Matrix == nil {
|
||||
return nil, nil
|
||||
}
|
||||
matrix, err := argoprojiov1alpha1.ToNestedMatrixGenerator(r.Matrix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return matrix.ToMatrixGenerator(), nil
|
||||
}
|
||||
|
||||
func (m *MatrixGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate {
|
||||
return &appSetGenerator.Matrix.Template
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
"github.com/stretchr/testify/mock"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
|
||||
testutils "github.com/argoproj/argo-cd/v2/applicationset/utils/test"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
@@ -857,3 +859,72 @@ func (g *generatorMock) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Appl
|
||||
return args.Get(0).(time.Duration)
|
||||
|
||||
}
|
||||
|
||||
func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) {
|
||||
// Given a matrix generator over a list generator and a git files generator, the nested git files generator should
|
||||
// be treated as a files generator, and it should produce parameters.
|
||||
|
||||
// This tests for a specific bug where a nested git files generator was being treated as a directory generator. This
|
||||
// happened because, when the matrix generator was being processed, the nested git files generator was being
|
||||
// interpolated by the deeplyReplace function. That function cannot differentiate between a nil slice and an empty
|
||||
// slice. So it was replacing the `Directories` field with an empty slice, which the ApplicationSet controller
|
||||
// interpreted as meaning this was a directory generator, not a files generator.
|
||||
|
||||
// Now instead of checking for nil, we check whether the field is a non-empty slice. This test prevents a regression
|
||||
// of that bug.
|
||||
|
||||
listGeneratorMock := &generatorMock{}
|
||||
listGeneratorMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), mock.AnythingOfType("*v1alpha1.ApplicationSet")).Return([]map[string]interface{}{
|
||||
{"some": "value"},
|
||||
}, nil)
|
||||
listGeneratorMock.On("GetTemplate", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator")).Return(&argoprojiov1alpha1.ApplicationSetTemplate{})
|
||||
|
||||
gitGeneratorSpec := &argoprojiov1alpha1.GitGenerator{
|
||||
RepoURL: "https://git.example.com",
|
||||
Files: []argoprojiov1alpha1.GitFileGeneratorItem{
|
||||
{Path: "some/path.json"},
|
||||
},
|
||||
}
|
||||
|
||||
repoServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}}
|
||||
repoServiceMock.Mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{
|
||||
"some/path.json": []byte("test: content"),
|
||||
}, nil)
|
||||
gitGenerator := NewGitGenerator(repoServiceMock)
|
||||
|
||||
matrixGenerator := NewMatrixGenerator(map[string]Generator{
|
||||
"List": listGeneratorMock,
|
||||
"Git": gitGenerator,
|
||||
})
|
||||
|
||||
matrixGeneratorSpec := &argoprojiov1alpha1.MatrixGenerator{
|
||||
Generators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
List: &argoprojiov1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{
|
||||
{
|
||||
Raw: []byte(`{"some": "value"}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Git: gitGeneratorSpec,
|
||||
},
|
||||
},
|
||||
}
|
||||
params, err := matrixGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Matrix: matrixGeneratorSpec,
|
||||
}, &argoprojiov1alpha1.ApplicationSet{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []map[string]interface{}{{
|
||||
"path": "some",
|
||||
"path.basename": "some",
|
||||
"path.basenameNormalized": "some",
|
||||
"path.filename": "path.json",
|
||||
"path.filenameNormalized": "path.json",
|
||||
"path[0]": "some",
|
||||
"some": "value",
|
||||
"test": "content",
|
||||
}}, params)
|
||||
}
|
||||
|
||||
@@ -137,27 +137,13 @@ func getParamSetsByMergeKey(mergeKeys []string, paramSets []map[string]interface
|
||||
|
||||
// getParams get the parameters generated by this generator.
|
||||
func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) {
|
||||
|
||||
var matrix *argoprojiov1alpha1.MatrixGenerator
|
||||
if appSetBaseGenerator.Matrix != nil {
|
||||
nestedMatrix, err := argoprojiov1alpha1.ToNestedMatrixGenerator(appSetBaseGenerator.Matrix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if nestedMatrix != nil {
|
||||
matrix = nestedMatrix.ToMatrixGenerator()
|
||||
}
|
||||
matrixGen, err := getMatrixGenerator(appSetBaseGenerator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var mergeGenerator *argoprojiov1alpha1.MergeGenerator
|
||||
if appSetBaseGenerator.Merge != nil {
|
||||
nestedMerge, err := argoprojiov1alpha1.ToNestedMergeGenerator(appSetBaseGenerator.Merge)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if nestedMerge != nil {
|
||||
mergeGenerator = nestedMerge.ToMergeGenerator()
|
||||
}
|
||||
mergeGen, err := getMergeGenerator(appSetBaseGenerator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t, err := Transform(
|
||||
@@ -168,8 +154,8 @@ func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Applic
|
||||
SCMProvider: appSetBaseGenerator.SCMProvider,
|
||||
ClusterDecisionResource: appSetBaseGenerator.ClusterDecisionResource,
|
||||
PullRequest: appSetBaseGenerator.PullRequest,
|
||||
Matrix: matrix,
|
||||
Merge: mergeGenerator,
|
||||
Matrix: matrixGen,
|
||||
Merge: mergeGen,
|
||||
Selector: appSetBaseGenerator.Selector,
|
||||
},
|
||||
m.supportedGenerators,
|
||||
@@ -197,10 +183,15 @@ func (m *MergeGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.App
|
||||
var found bool
|
||||
|
||||
for _, r := range appSetGenerator.Merge.Generators {
|
||||
matrixGen, _ := getMatrixGenerator(r)
|
||||
mergeGen, _ := getMergeGenerator(r)
|
||||
base := &argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
List: r.List,
|
||||
Clusters: r.Clusters,
|
||||
Git: r.Git,
|
||||
List: r.List,
|
||||
Clusters: r.Clusters,
|
||||
Git: r.Git,
|
||||
PullRequest: r.PullRequest,
|
||||
Matrix: matrixGen,
|
||||
Merge: mergeGen,
|
||||
}
|
||||
generators := GetRelevantGenerators(base, m.supportedGenerators)
|
||||
|
||||
@@ -221,6 +212,17 @@ func (m *MergeGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.App
|
||||
|
||||
}
|
||||
|
||||
func getMergeGenerator(r argoprojiov1alpha1.ApplicationSetNestedGenerator) (*argoprojiov1alpha1.MergeGenerator, error) {
|
||||
if r.Merge == nil {
|
||||
return nil, nil
|
||||
}
|
||||
merge, err := argoprojiov1alpha1.ToNestedMergeGenerator(r.Merge)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return merge.ToMergeGenerator(), nil
|
||||
}
|
||||
|
||||
// GetTemplate gets the Template field for the MergeGenerator.
|
||||
func (m *MergeGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate {
|
||||
return &appSetGenerator.Merge.Template
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"net/http"
|
||||
pathpkg "path"
|
||||
|
||||
gitlab "github.com/xanzy/go-gitlab"
|
||||
@@ -144,7 +145,11 @@ func (g *GitlabProvider) listBranches(_ context.Context, repo *Repository) ([]gi
|
||||
branches := []gitlab.Branch{}
|
||||
// If we don't specifically want to query for all branches, just use the default branch and call it a day.
|
||||
if !g.allBranches {
|
||||
gitlabBranch, _, err := g.client.Branches.GetBranch(repo.RepositoryId, repo.Branch, nil)
|
||||
gitlabBranch, resp, err := g.client.Branches.GetBranch(repo.RepositoryId, repo.Branch, nil)
|
||||
// 404s are not an error here, just a normal false.
|
||||
if resp != nil && resp.StatusCode == http.StatusNotFound {
|
||||
return []gitlab.Branch{}, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -157,6 +162,10 @@ func (g *GitlabProvider) listBranches(_ context.Context, repo *Repository) ([]gi
|
||||
}
|
||||
for {
|
||||
gitlabBranches, resp, err := g.client.Branches.ListBranches(repo.RepositoryId, opt)
|
||||
// 404s are not an error here, just a normal false.
|
||||
if resp != nil && resp.StatusCode == http.StatusNotFound {
|
||||
return []gitlab.Branch{}, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -274,6 +274,8 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v4/projects/27084533/repository/branches/foo":
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
default:
|
||||
_, err := io.WriteString(w, `[]`)
|
||||
if err != nil {
|
||||
@@ -391,3 +393,29 @@ func TestGitlabHasPath(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitlabGetBranches(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gitlabMockHandler(t)(w, r)
|
||||
}))
|
||||
host, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, false, true)
|
||||
|
||||
repo := &Repository{
|
||||
RepositoryId: 27084533,
|
||||
Branch: "master",
|
||||
}
|
||||
t.Run("branch exists", func(t *testing.T) {
|
||||
repos, err := host.GetBranches(context.Background(), repo)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, repos[0].Branch, "master")
|
||||
})
|
||||
|
||||
repo2 := &Repository{
|
||||
RepositoryId: 27084533,
|
||||
Branch: "foo",
|
||||
}
|
||||
t.Run("unknown branch", func(t *testing.T) {
|
||||
_, err := host.GetBranches(context.Background(), repo2)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
34
applicationset/utils/test/testutils.go
Normal file
34
applicationset/utils/test/testutils.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
type ArgoCDServiceMock struct {
|
||||
Mock *mock.Mock
|
||||
}
|
||||
|
||||
func (a ArgoCDServiceMock) GetApps(ctx context.Context, repoURL string, revision string) ([]string, error) {
|
||||
args := a.Mock.Called(ctx, repoURL, revision)
|
||||
|
||||
return args.Get(0).([]string), args.Error(1)
|
||||
}
|
||||
|
||||
func (a ArgoCDServiceMock) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) {
|
||||
args := a.Mock.Called(ctx, repoURL, revision, pattern)
|
||||
|
||||
return args.Get(0).(map[string][]byte), args.Error(1)
|
||||
}
|
||||
|
||||
func (a ArgoCDServiceMock) GetFileContent(ctx context.Context, repoURL string, revision string, path string) ([]byte, error) {
|
||||
args := a.Mock.Called(ctx, repoURL, revision, path)
|
||||
|
||||
return args.Get(0).([]byte), args.Error(1)
|
||||
}
|
||||
|
||||
func (a ArgoCDServiceMock) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) {
|
||||
args := a.Mock.Called(ctx, repoURL, revision)
|
||||
return args.Get(0).([]string), args.Error(1)
|
||||
}
|
||||
@@ -174,7 +174,7 @@ func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[stri
|
||||
|
||||
func (r *Render) RenderTemplateParams(tmpl *argoappsv1.Application, syncPolicy *argoappsv1.ApplicationSetSyncPolicy, params map[string]interface{}, useGoTemplate bool) (*argoappsv1.Application, error) {
|
||||
if tmpl == nil {
|
||||
return nil, fmt.Errorf("application template is empty ")
|
||||
return nil, fmt.Errorf("application template is empty")
|
||||
}
|
||||
|
||||
if len(params) == 0 {
|
||||
@@ -204,6 +204,27 @@ func (r *Render) RenderTemplateParams(tmpl *argoappsv1.Application, syncPolicy *
|
||||
return replacedTmpl, nil
|
||||
}
|
||||
|
||||
func (r *Render) RenderGeneratorParams(gen *argoappsv1.ApplicationSetGenerator, params map[string]interface{}, useGoTemplate bool) (*argoappsv1.ApplicationSetGenerator, error) {
|
||||
if gen == nil {
|
||||
return nil, fmt.Errorf("generator is empty")
|
||||
}
|
||||
|
||||
if len(params) == 0 {
|
||||
return gen, nil
|
||||
}
|
||||
|
||||
original := reflect.ValueOf(gen)
|
||||
copy := reflect.New(original.Type()).Elem()
|
||||
|
||||
if err := r.deeplyReplace(copy, original, params, useGoTemplate); err != nil {
|
||||
return nil, fmt.Errorf("failed to replace parameters in generator: %w", err)
|
||||
}
|
||||
|
||||
replacedGen := copy.Interface().(*argoappsv1.ApplicationSetGenerator)
|
||||
|
||||
return replacedGen, nil
|
||||
}
|
||||
|
||||
var isTemplatedRegex = regexp.MustCompile(".*{{.*}}.*")
|
||||
|
||||
// Replace executes basic string substitution of a template with replacement values.
|
||||
|
||||
@@ -271,6 +271,16 @@
|
||||
"description": "the application's namespace.",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"collectionFormat": "multi",
|
||||
"description": "the project names to restrict returned list applications (legacy name for backwards-compatibility).",
|
||||
"name": "project",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -585,6 +595,16 @@
|
||||
"description": "the application's namespace.",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"collectionFormat": "multi",
|
||||
"description": "the project names to restrict returned list applications (legacy name for backwards-compatibility).",
|
||||
"name": "project",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -3507,6 +3527,16 @@
|
||||
"description": "the application's namespace.",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"collectionFormat": "multi",
|
||||
"description": "the project names to restrict returned list applications (legacy name for backwards-compatibility).",
|
||||
"name": "project",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
||||
@@ -964,7 +964,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
|
||||
diffOption.serversideRes = res
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "Warning: local diff without --server-side-generate is deprecated and does not work with plugins. Server-side generation will be the default in v2.6.")
|
||||
fmt.Fprintf(os.Stderr, "Warning: local diff without --server-side-generate is deprecated and does not work with plugins. Server-side generation will be the default in v2.7.")
|
||||
conn, clusterIf := clientset.NewClusterClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
cluster, err := clusterIf.Get(ctx, &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server})
|
||||
|
||||
@@ -342,16 +342,19 @@ func printAppSetSummaryTable(appSet *arogappsetv1.ApplicationSet) {
|
||||
fmt.Printf(printOpFmtStr, "Path:", appSet.Spec.Template.Spec.Source.Path)
|
||||
printAppSourceDetails(&appSet.Spec.Template.Spec.Source)
|
||||
|
||||
var syncPolicy string
|
||||
if appSet.Spec.SyncPolicy != nil && appSet.Spec.Template.Spec.SyncPolicy.Automated != nil {
|
||||
syncPolicy = "Automated"
|
||||
if appSet.Spec.Template.Spec.SyncPolicy.Automated.Prune {
|
||||
syncPolicy += " (Prune)"
|
||||
var (
|
||||
syncPolicyStr string
|
||||
syncPolicy = appSet.Spec.Template.Spec.SyncPolicy
|
||||
)
|
||||
if syncPolicy != nil && syncPolicy.Automated != nil {
|
||||
syncPolicyStr = "Automated"
|
||||
if syncPolicy.Automated.Prune {
|
||||
syncPolicyStr += " (Prune)"
|
||||
}
|
||||
} else {
|
||||
syncPolicy = "<none>"
|
||||
syncPolicyStr = "<none>"
|
||||
}
|
||||
fmt.Printf(printOpFmtStr, "SyncPolicy:", syncPolicy)
|
||||
fmt.Printf(printOpFmtStr, "SyncPolicy:", syncPolicyStr)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
@@ -68,3 +70,124 @@ func TestPrintApplicationSetTable(t *testing.T) {
|
||||
expectation := "NAME NAMESPACE PROJECT SYNCPOLICY CONDITIONS\napp-name default nil [{ResourcesUpToDate <nil> True }]\napp-name default nil [{ResourcesUpToDate <nil> True }]\n"
|
||||
assert.Equal(t, expectation, output)
|
||||
}
|
||||
|
||||
func TestPrintAppSetSummaryTable(t *testing.T) {
|
||||
baseAppSet := &arogappsetv1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app-name",
|
||||
},
|
||||
Spec: arogappsetv1.ApplicationSetSpec{
|
||||
Generators: []arogappsetv1.ApplicationSetGenerator{
|
||||
arogappsetv1.ApplicationSetGenerator{
|
||||
Git: &arogappsetv1.GitGenerator{
|
||||
RepoURL: "https://github.com/argoproj/argo-cd.git",
|
||||
Revision: "head",
|
||||
Directories: []arogappsetv1.GitDirectoryGeneratorItem{
|
||||
arogappsetv1.GitDirectoryGeneratorItem{
|
||||
Path: "applicationset/examples/git-generator-directory/cluster-addons/*",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Template: arogappsetv1.ApplicationSetTemplate{
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "default",
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: arogappsetv1.ApplicationSetStatus{
|
||||
Conditions: []arogappsetv1.ApplicationSetCondition{
|
||||
arogappsetv1.ApplicationSetCondition{
|
||||
Status: v1alpha1.ApplicationSetConditionStatusTrue,
|
||||
Type: arogappsetv1.ApplicationSetConditionResourcesUpToDate,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
appsetSpecSyncPolicy := baseAppSet.DeepCopy()
|
||||
appsetSpecSyncPolicy.Spec.SyncPolicy = &arogappsetv1.ApplicationSetSyncPolicy{
|
||||
PreserveResourcesOnDeletion: true,
|
||||
}
|
||||
|
||||
appSetTemplateSpecSyncPolicy := baseAppSet.DeepCopy()
|
||||
appSetTemplateSpecSyncPolicy.Spec.Template.Spec.SyncPolicy = &arogappsetv1.SyncPolicy{
|
||||
Automated: &arogappsetv1.SyncPolicyAutomated{
|
||||
SelfHeal: true,
|
||||
},
|
||||
}
|
||||
|
||||
appSetBothSyncPolicies := baseAppSet.DeepCopy()
|
||||
appSetBothSyncPolicies.Spec.SyncPolicy = &arogappsetv1.ApplicationSetSyncPolicy{
|
||||
PreserveResourcesOnDeletion: true,
|
||||
}
|
||||
appSetBothSyncPolicies.Spec.Template.Spec.SyncPolicy = &arogappsetv1.SyncPolicy{
|
||||
Automated: &arogappsetv1.SyncPolicyAutomated{
|
||||
SelfHeal: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
appSet *arogappsetv1.ApplicationSet
|
||||
expectedOutput string
|
||||
}{
|
||||
{
|
||||
name: "appset with only spec.syncPolicy set",
|
||||
appSet: appsetSpecSyncPolicy,
|
||||
expectedOutput: `Name: app-name
|
||||
Project: default
|
||||
Server:
|
||||
Namespace:
|
||||
Repo:
|
||||
Target:
|
||||
Path:
|
||||
SyncPolicy: <none>
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "appset with only spec.template.spec.syncPolicy set",
|
||||
appSet: appSetTemplateSpecSyncPolicy,
|
||||
expectedOutput: `Name: app-name
|
||||
Project: default
|
||||
Server:
|
||||
Namespace:
|
||||
Repo:
|
||||
Target:
|
||||
Path:
|
||||
SyncPolicy: Automated
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "appset with both spec.SyncPolicy and spec.template.spec.syncPolicy set",
|
||||
appSet: appSetBothSyncPolicies,
|
||||
expectedOutput: `Name: app-name
|
||||
Project: default
|
||||
Server:
|
||||
Namespace:
|
||||
Repo:
|
||||
Target:
|
||||
Path:
|
||||
SyncPolicy: Automated
|
||||
`,
|
||||
},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
oldStdout := os.Stdout
|
||||
defer func() {
|
||||
os.Stdout = oldStdout
|
||||
}()
|
||||
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
printAppSetSummaryTable(tt.appSet)
|
||||
w.Close()
|
||||
|
||||
out, err := ioutil.ReadAll(r)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.expectedOutput, string(out))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,6 @@ func readAppset(yml []byte, appsets *[]*argoprojiov1alpha1.ApplicationSet) error
|
||||
*appsets = append(*appsets, &appset)
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
// we reach here if there is no error found while reading the Application Set
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/argoproj/pkg/rand"
|
||||
|
||||
@@ -73,9 +75,8 @@ func runCommand(ctx context.Context, command Command, path string, env []string)
|
||||
}
|
||||
logCtx := log.WithFields(log.Fields{"execID": execId})
|
||||
|
||||
// log in a way we can copy-and-paste into a terminal
|
||||
args := strings.Join(cmd.Args, " ")
|
||||
logCtx.WithFields(log.Fields{"dir": cmd.Dir}).Info(args)
|
||||
argsToLog := getCommandArgsToLog(cmd)
|
||||
logCtx.WithFields(log.Fields{"dir": cmd.Dir}).Info(argsToLog)
|
||||
|
||||
var stdout bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
@@ -106,7 +107,7 @@ func runCommand(ctx context.Context, command Command, path string, env []string)
|
||||
logCtx.WithFields(log.Fields{"duration": duration}).Debug(output)
|
||||
|
||||
if err != nil {
|
||||
err := newCmdError(args, errors.New(err.Error()), strings.TrimSpace(stderr.String()))
|
||||
err := newCmdError(argsToLog, errors.New(err.Error()), strings.TrimSpace(stderr.String()))
|
||||
logCtx.Error(err.Error())
|
||||
return strings.TrimSuffix(output, "\n"), err
|
||||
}
|
||||
@@ -114,6 +115,28 @@ func runCommand(ctx context.Context, command Command, path string, env []string)
|
||||
return strings.TrimSuffix(output, "\n"), nil
|
||||
}
|
||||
|
||||
// getCommandArgsToLog represents the given command in a way that we can copy-and-paste into a terminal
|
||||
func getCommandArgsToLog(cmd *exec.Cmd) string {
|
||||
var argsToLog []string
|
||||
for _, arg := range cmd.Args {
|
||||
containsSpace := false
|
||||
for _, r := range arg {
|
||||
if unicode.IsSpace(r) {
|
||||
containsSpace = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if containsSpace {
|
||||
// add quotes and escape any internal quotes
|
||||
argsToLog = append(argsToLog, strconv.Quote(arg))
|
||||
} else {
|
||||
argsToLog = append(argsToLog, arg)
|
||||
}
|
||||
}
|
||||
args := strings.Join(argsToLog, " ")
|
||||
return args
|
||||
}
|
||||
|
||||
type CmdError struct {
|
||||
Args string
|
||||
Stderr string
|
||||
|
||||
@@ -2,6 +2,7 @@ package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -266,3 +267,30 @@ func TestRunCommandContextTimeout(t *testing.T) {
|
||||
assert.Error(t, err) // The command should time out, causing an error.
|
||||
assert.Less(t, after.Sub(before), 1*time.Second)
|
||||
}
|
||||
|
||||
func Test_getCommandArgsToLog(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "no spaces",
|
||||
args: []string{"sh", "-c", "cat"},
|
||||
expected: "sh -c cat",
|
||||
},
|
||||
{
|
||||
name: "spaces",
|
||||
args: []string{"sh", "-c", `echo "hello world"`},
|
||||
expected: `sh -c "echo \"hello world\""`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tcc := tc
|
||||
t.Run(tcc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, tcc.expected, getCommandArgsToLog(exec.Command(tcc.args[0], tcc.args[1:]...)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Default service addresses and URLS of Argo CD internal services
|
||||
@@ -322,3 +324,5 @@ const (
|
||||
const TokenVerificationError = "failed to verify the token"
|
||||
|
||||
var TokenVerificationErr = errors.New(TokenVerificationError)
|
||||
|
||||
var PermissionDeniedAPIError = status.Error(codes.PermissionDenied, "permission denied")
|
||||
|
||||
17
controller/cache/cache.go
vendored
17
controller/cache/cache.go
vendored
@@ -25,6 +25,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/controller/metrics"
|
||||
@@ -389,6 +390,20 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
|
||||
return nil, fmt.Errorf("controller is configured to ignore cluster %s", cluster.Server)
|
||||
}
|
||||
|
||||
clusterCacheConfig := cluster.RESTConfig()
|
||||
// Controller dynamically fetches all resource types available on the cluster
|
||||
// using a discovery API that may contain deprecated APIs.
|
||||
// This causes log flooding when managing a large number of clusters.
|
||||
// https://github.com/argoproj/argo-cd/issues/11973
|
||||
// However, we can safely suppress deprecation warnings
|
||||
// because we do not rely on resources with a particular API group or version.
|
||||
// https://kubernetes.io/blog/2020/09/03/warnings/#customize-client-handling
|
||||
//
|
||||
// Completely suppress warning logs only for log levels that are less than Debug.
|
||||
if log.GetLevel() < log.DebugLevel {
|
||||
clusterCacheConfig.WarningHandler = rest.NoWarnings{}
|
||||
}
|
||||
|
||||
clusterCacheOpts := []clustercache.UpdateSettingsFunc{
|
||||
clustercache.SetListSemaphore(semaphore.NewWeighted(clusterCacheListSemaphoreSize)),
|
||||
clustercache.SetListPageSize(clusterCacheListPageSize),
|
||||
@@ -420,7 +435,7 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
|
||||
clustercache.SetRetryOptions(clusterCacheAttemptLimit, clusterCacheRetryUseBackoff, isRetryableError),
|
||||
}
|
||||
|
||||
clusterCache = clustercache.NewClusterCache(cluster.RESTConfig(), clusterCacheOpts...)
|
||||
clusterCache = clustercache.NewClusterCache(clusterCacheConfig, clusterCacheOpts...)
|
||||
|
||||
_ = clusterCache.OnResourceUpdated(func(newRes *clustercache.Resource, oldRes *clustercache.Resource, namespaceResources map[kube.ResourceKey]*clustercache.Resource) {
|
||||
toNotify := make(map[string]bool)
|
||||
|
||||
44
docs/faq.md
44
docs/faq.md
@@ -123,9 +123,9 @@ To terminate the sync, click on the "synchronisation" then "terminate":
|
||||
|
||||
 
|
||||
|
||||
## Why Is My App Out Of Sync Even After Syncing?
|
||||
## Why Is My App `Out Of Sync` Even After Syncing?
|
||||
|
||||
Is some cases, the tool you use may conflict with Argo CD by adding the `app.kubernetes.io/instance` label. E.g. using
|
||||
In some cases, the tool you use may conflict with Argo CD by adding the `app.kubernetes.io/instance` label. E.g. using
|
||||
Kustomize common labels feature.
|
||||
|
||||
Argo CD automatically sets the `app.kubernetes.io/instance` label and uses it to determine which resources form the app.
|
||||
@@ -143,7 +143,7 @@ The default polling interval is 3 minutes (180 seconds).
|
||||
You can change the setting by updating the `timeout.reconciliation` value in the [argocd-cm](https://github.com/argoproj/argo-cd/blob/2d6ce088acd4fb29271ffb6f6023dbb27594d59b/docs/operator-manual/argocd-cm.yaml#L279-L282) config map. If there are any Git changes, ArgoCD will only update applications with the [auto-sync setting](user-guide/auto_sync.md) enabled. If you set it to `0` then Argo CD will stop polling Git repositories automatically and you can only use alternative methods such as [webhooks](operator-manual/webhook.md) and/or manual syncs for deploying applications.
|
||||
|
||||
|
||||
## Why Are My Resource Limits Out Of Sync?
|
||||
## Why Are My Resource Limits `Out Of Sync`?
|
||||
|
||||
Kubernetes has normalized your resource limits when they are applied, and then Argo CD has then compared the version in
|
||||
your generated manifests to the normalized one is Kubernetes - they won't match.
|
||||
@@ -158,7 +158,7 @@ E.g.
|
||||
To fix this use diffing
|
||||
customizations [settings](./user-guide/diffing.md#known-kubernetes-types-in-crds-resource-limits-volume-mounts-etc).
|
||||
|
||||
## How Do I Fix "invalid cookie, longer than max length 4093"?
|
||||
## How Do I Fix `invalid cookie, longer than max length 4093`?
|
||||
|
||||
Argo CD uses a JWT as the auth token. You likely are part of many groups and have gone over the 4KB limit which is set
|
||||
for cookies. You can get the list of groups by opening "developer tools -> network"
|
||||
@@ -225,4 +225,38 @@ resource.customizations.health.bitnami.com_SealedSecret: |
|
||||
hs.status = "Healthy"
|
||||
hs.message = "Controller doesn't report resource status"
|
||||
return hs
|
||||
```
|
||||
```
|
||||
|
||||
## How do I fix `The order in patch list … doesn't match $setElementOrder list: …`?
|
||||
|
||||
An application may trigger a sync error labeled a `ComparisonError` with a message like:
|
||||
|
||||
> The order in patch list: [map[name:**KEY_BC** value:150] map[name:**KEY_BC** value:500] map[name:**KEY_BD** value:250] map[name:**KEY_BD** value:500] map[name:KEY_BI value:something]] doesn't match $setElementOrder list: [map[name:KEY_AA] map[name:KEY_AB] map[name:KEY_AC] map[name:KEY_AD] map[name:KEY_AE] map[name:KEY_AF] map[name:KEY_AG] map[name:KEY_AH] map[name:KEY_AI] map[name:KEY_AJ] map[name:KEY_AK] map[name:KEY_AL] map[name:KEY_AM] map[name:KEY_AN] map[name:KEY_AO] map[name:KEY_AP] map[name:KEY_AQ] map[name:KEY_AR] map[name:KEY_AS] map[name:KEY_AT] map[name:KEY_AU] map[name:KEY_AV] map[name:KEY_AW] map[name:KEY_AX] map[name:KEY_AY] map[name:KEY_AZ] map[name:KEY_BA] map[name:KEY_BB] map[name:**KEY_BC**] map[name:**KEY_BD**] map[name:KEY_BE] map[name:KEY_BF] map[name:KEY_BG] map[name:KEY_BH] map[name:KEY_BI] map[name:**KEY_BC**] map[name:**KEY_BD**]]
|
||||
|
||||
|
||||
There are two parts to the message:
|
||||
|
||||
1. `The order in patch list: [`
|
||||
|
||||
This identifies values for items, especially items that appear multiple times:
|
||||
|
||||
> map[name:**KEY_BC** value:150] map[name:**KEY_BC** value:500] map[name:**KEY_BD** value:250] map[name:**KEY_BD** value:500] map[name:KEY_BI value:something]
|
||||
|
||||
You'll want to identify the keys that are duplicated -- you can focus on the first part, as each duplicated key will appear, once for each of its value with its value in the first list. The second list is really just
|
||||
|
||||
`]`
|
||||
|
||||
2. `doesn't match $setElementOrder list: [`
|
||||
|
||||
This includes all of the keys. It's included for debugging purposes -- you don't need to pay much attention to it. It will give you a hint about the precise location in the list for the duplicated keys:
|
||||
|
||||
> map[name:KEY_AA] map[name:KEY_AB] map[name:KEY_AC] map[name:KEY_AD] map[name:KEY_AE] map[name:KEY_AF] map[name:KEY_AG] map[name:KEY_AH] map[name:KEY_AI] map[name:KEY_AJ] map[name:KEY_AK] map[name:KEY_AL] map[name:KEY_AM] map[name:KEY_AN] map[name:KEY_AO] map[name:KEY_AP] map[name:KEY_AQ] map[name:KEY_AR] map[name:KEY_AS] map[name:KEY_AT] map[name:KEY_AU] map[name:KEY_AV] map[name:KEY_AW] map[name:KEY_AX] map[name:KEY_AY] map[name:KEY_AZ] map[name:KEY_BA] map[name:KEY_BB] map[name:**KEY_BC**] map[name:**KEY_BD**] map[name:KEY_BE] map[name:KEY_BF] map[name:KEY_BG] map[name:KEY_BH] map[name:KEY_BI] map[name:**KEY_BC**] map[name:**KEY_BD**]
|
||||
|
||||
`]`
|
||||
|
||||
In this case, the duplicated keys have been **emphasized** to help you identify the problematic keys. Many editors have the ability to highlight all instances of a string, using such an editor can help with such problems.
|
||||
|
||||
The most common instance of this error is with `env:` fields for `containers`.
|
||||
|
||||
!!! note "Dynamic applications"
|
||||
It's possible that your application is being generated by a tool in which case the duplication might not be evident within the scope of a single file. If you have trouble debugging this problem, consider filing a ticket to the owner of the generator tool asking them to improve its validation and error reporting.
|
||||
|
||||
@@ -125,7 +125,10 @@ spec:
|
||||
|
||||
# Destination cluster and namespace to deploy the application
|
||||
destination:
|
||||
# cluster API URL
|
||||
server: https://kubernetes.default.svc
|
||||
# or cluster name
|
||||
# name: in-cluster
|
||||
# The namespace will only be set for namespace-scoped resources that have not set a value for .metadata.namespace
|
||||
namespace: guestbook
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ spec:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: '{{path.basename}}'
|
||||
```
|
||||
(*The full example can be found [here](https://github.com/argoproj/argo-cd/tree/master/examples/applicationset/git-generator-directory/excludes).*)
|
||||
(*The full example can be found [here](https://github.com/argoproj/argo-cd/tree/master/applicationset/examples/git-generator-directory/excludes).*)
|
||||
|
||||
This example excludes the `exclude-helm-guestbook` directory from the list of directories scanned for this `ApplicationSet` resource.
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# Post Selector all generators
|
||||
|
||||
The Selector allows to post-filter based on generated values using the kubernetes common labelSelector format. In the example, the list generator generates a set of two application which then filter by the key value to only select the `env` with value `staging`:
|
||||
|
||||
## Example: List generator + Post Selector
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: ApplicationSet
|
||||
metadata:
|
||||
name: guestbook
|
||||
spec:
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- cluster: engineering-dev
|
||||
url: https://kubernetes.default.svc
|
||||
env: staging
|
||||
- cluster: engineering-prod
|
||||
url: https://kubernetes.default.svc
|
||||
env: prod
|
||||
selector:
|
||||
matchLabels:
|
||||
env: staging
|
||||
template:
|
||||
metadata:
|
||||
name: '{{cluster}}-guestbook'
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/argoproj-labs/applicationset.git
|
||||
targetRevision: HEAD
|
||||
path: examples/list-generator/guestbook/{{cluster}}
|
||||
destination:
|
||||
server: '{{url}}'
|
||||
namespace: guestbook
|
||||
```
|
||||
|
||||
The List generator + Post Selector generates a single set of parameters:
|
||||
```yaml
|
||||
- cluster: engineering-dev
|
||||
url: https://kubernetes.default.svc
|
||||
env: staging
|
||||
```
|
||||
@@ -15,4 +15,6 @@ As of this writing there are eight generators:
|
||||
- [Pull Request generator](Generators-Pull-Request.md): The Pull Request generator uses the API of an SCMaaS provider (eg GitHub) to automatically discover open pull requests within an repository.
|
||||
- [Cluster Decision Resource generator](Generators-Cluster-Decision-Resource.md): The Cluster Decision Resource generator is used to interface with Kubernetes custom resources that use custom resource-specific logic to decide which set of Argo CD clusters to deploy to.
|
||||
|
||||
All generators can be filtered by using the [Post Selector](Generators-Post-Selector.md)
|
||||
|
||||
If you are new to generators, begin with the **List** and **Cluster** generators. For more advanced use cases, see the documentation for the remaining generators above.
|
||||
|
||||
@@ -77,7 +77,7 @@ spec:
|
||||
```
|
||||
|
||||
!!! warning
|
||||
By default, deleting an application will not perform a cascade delete, which would delete its resources. You must add the finalizer if you want this behaviour - which you may well not want.
|
||||
Without the `resources-finalizer.argocd.argoproj.io` finalizer, deleting an application will not delete the resources it manages. To perform a cascading delete, you must add the finalizer. See [App Deletion](../user-guide/app_deletion.md#about-the-deletion-finalizer).
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
|
||||
@@ -5,7 +5,7 @@ Argo CD provides built-in health assessment for several standard Kubernetes type
|
||||
surfaced to the overall Application health status as a whole. The following checks are made for
|
||||
specific types of kubernetes resources:
|
||||
|
||||
### Deployment, ReplicaSet, StatefulSet DaemonSet
|
||||
### Deployment, ReplicaSet, StatefulSet, DaemonSet
|
||||
* Observed generation is equal to desired generation.
|
||||
* Number of **updated** replicas equals the number of desired replicas.
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
# High Availability
|
||||
|
||||
Argo CD is largely stateless, all data is persisted as Kubernetes objects, which in turn is stored in Kubernetes' etcd. Redis is only used as a throw-away cache and can be lost. When lost, it will be rebuilt without loss of service.
|
||||
Argo CD is largely stateless. All data is persisted as Kubernetes objects, which in turn is stored in Kubernetes' etcd. Redis is only used as a throw-away cache and can be lost. When lost, it will be rebuilt without loss of service.
|
||||
|
||||
A set of HA manifests are provided for users who wish to run Argo CD in a highly available manner. This runs more containers, and runs Redis in HA mode.
|
||||
|
||||
[Manifests ⧉](https://github.com/argoproj/argo-cd/tree/master/manifests)
|
||||
A set of [HA manifests](https://github.com/argoproj/argo-cd/tree/master/manifests/ha) are provided for users who wish to run Argo CD in a highly available manner. This runs more containers, and runs Redis in HA mode.
|
||||
|
||||
> **NOTE:** The HA installation will require at least three different nodes due to pod anti-affinity roles in the
|
||||
> specs. Additionally, IPv6 only clusters are not supported.
|
||||
@@ -17,11 +15,11 @@ A set of HA manifests are provided for users who wish to run Argo CD in a highly
|
||||
|
||||
The `argocd-repo-server` is responsible for cloning Git repository, keeping it up to date and generating manifests using the appropriate tool.
|
||||
|
||||
* `argocd-repo-server` fork/exec config management tool to generate manifests. The fork can fail due to lack of memory and limit on the number of OS threads.
|
||||
The `--parallelismlimit` flag controls how many manifests generations are running concurrently and allows avoiding OOM kills.
|
||||
* `argocd-repo-server` fork/exec config management tool to generate manifests. The fork can fail due to lack of memory or limit on the number of OS threads.
|
||||
The `--parallelismlimit` flag controls how many manifests generations are running concurrently and helps avoid OOM kills.
|
||||
|
||||
* the `argocd-repo-server` ensures that repository is in the clean state during the manifest generation using config management tools such as Kustomize, Helm
|
||||
or custom plugin. As a result Git repositories with multiple applications might be affect repository server performance.
|
||||
or custom plugin. As a result Git repositories with multiple applications might affect repository server performance.
|
||||
Read [Monorepo Scaling Considerations](#monorepo-scaling-considerations) for more information.
|
||||
|
||||
* `argocd-repo-server` clones repository into `/tmp` ( of path specified in `TMPDIR` env variable ). Pod might run out of disk space if have too many repository
|
||||
@@ -30,7 +28,7 @@ or repositories has a lot of files. To avoid this problem mount persistent volum
|
||||
* `argocd-repo-server` `git ls-remote` to resolve ambiguous revision such as `HEAD`, branch or tag name. This operation is happening pretty frequently
|
||||
and might fail. To avoid failed syncs use `ARGOCD_GIT_ATTEMPTS_COUNT` environment variable to retry failed requests.
|
||||
|
||||
* `argocd-repo-server` Every 3m (by default) Argo CD checks for changes to the app manifests. Argo CD assumes by default that manifests only change when the repo changes, so it caches generated manifests (for 24h by default). With Kustomize remote bases, or Helm patch releases, the manifests can change even though the repo has not changed. By reducing the cache time, you can get the changes without waiting for 24h. Use `--repo-cache-expiration duration`, and we'd suggest in low volume environments you try '1h'. Bear in mind this will negate the benefit of caching if set too low.
|
||||
* `argocd-repo-server` Every 3m (by default) Argo CD checks for changes to the app manifests. Argo CD assumes by default that manifests only change when the repo changes, so it caches the generated manifests (for 24h by default). With Kustomize remote bases, or Helm patch releases, the manifests can change even though the repo has not changed. By reducing the cache time, you can get the changes without waiting for 24h. Use `--repo-cache-expiration duration`, and we'd suggest in low volume environments you try '1h'. Bear in mind that this will negate the benefits of caching if set too low.
|
||||
|
||||
* `argocd-repo-server` fork exec config management tools such as `helm` or `kustomize` and enforces 90 seconds timeout. The timeout can be increased using `ARGOCD_EXEC_TIMEOUT` env variable. The value should be in Go time duration string format, for example, `2m30s`.
|
||||
|
||||
@@ -188,4 +186,4 @@ spec:
|
||||
targetRevision: HEAD
|
||||
path: my-application
|
||||
# ...
|
||||
```
|
||||
```
|
||||
|
||||
@@ -74,7 +74,7 @@ kind: Kustomization
|
||||
|
||||
namespace: argocd
|
||||
resources:
|
||||
- https://raw.githubusercontent.com/argoproj/argo-cd/v2.0.4/manifests/ha/install.yaml
|
||||
- github.com/argoproj/argo-cd/manifests/ha?ref=v2.6.2
|
||||
```
|
||||
|
||||
## Helm
|
||||
|
||||
@@ -9,9 +9,8 @@ Operators can add actions to custom resources in form of a Lua script and expand
|
||||
|
||||
Argo CD supports custom resource actions written in [Lua](https://www.lua.org/). This is useful if you:
|
||||
|
||||
* Have a custom resource for which Argo CD does not provide any built-in actions.
|
||||
* Have a commonly performed manual task that might be error prone if executed by users via `kubectl`
|
||||
|
||||
* Have a custom resource for which Argo CD does not provide any built-in actions.
|
||||
* Have a commonly performed manual task that might be error prone if executed by users via `kubectl`
|
||||
|
||||
You can define your own custom resource actions in the `argocd-cm` ConfigMap.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# v1.8 to v2.0
|
||||
# v1.8 to 2.0
|
||||
|
||||
## Redis Upgraded to v6.2.1
|
||||
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# v2.3 to 2.4
|
||||
|
||||
## Known Issues
|
||||
|
||||
### Broken `project` filter before 2.4.27
|
||||
|
||||
Argo CD 2.4.0 introduced a breaking API change, renaming the `project` filter to `projects`.
|
||||
|
||||
#### Impact to API clients
|
||||
|
||||
A similar issue applies to other API clients which communicate with the Argo CD API server via its REST API. If the
|
||||
client uses the `project` field to filter projects, the filter will not be applied. **The failing project filter could
|
||||
have detrimental consequences if, for example, you rely on it to list Applications to be deleted.**
|
||||
|
||||
#### Impact to CLI clients
|
||||
|
||||
CLI clients older that v2.4.0 rely on client-side filtering and are not impacted by this bug.
|
||||
|
||||
#### How to fix the problem
|
||||
|
||||
Upgrade to Argo CD >=2.4.27, >=2.5.15, or >=2.6.6. This version of Argo CD will accept both `project` and `projects` as
|
||||
valid filters.
|
||||
|
||||
## KSonnet support is removed
|
||||
|
||||
Ksonnet was deprecated in [2019](https://github.com/ksonnet/ksonnet/pull/914/files) and is no longer maintained.
|
||||
|
||||
@@ -1,5 +1,57 @@
|
||||
# v2.4 to 2.5
|
||||
|
||||
## Known Issues
|
||||
|
||||
### Broken `project` filter before 2.5.15
|
||||
|
||||
Argo CD 2.4.0 introduced a breaking API change, renaming the `project` filter to `projects`.
|
||||
|
||||
#### Impact to API clients
|
||||
|
||||
A similar issue applies to other API clients which communicate with the Argo CD API server via its REST API. If the
|
||||
client uses the `project` field to filter projects, the filter will not be applied. **The failing project filter could
|
||||
have detrimental consequences if, for example, you rely on it to list Applications to be deleted.**
|
||||
|
||||
#### Impact to CLI clients
|
||||
|
||||
CLI clients older that v2.4.0 rely on client-side filtering and are not impacted by this bug.
|
||||
|
||||
#### How to fix the problem
|
||||
|
||||
Upgrade to Argo CD >=2.4.27, >=2.5.15, or >=2.6.6. This version of Argo CD will accept both `project` and `projects` as
|
||||
valid filters.
|
||||
|
||||
### Broken matrix-nested git files generator in 2.5.14
|
||||
|
||||
Argo CD 2.5.14 introduced a bug in the matrix-nested git files generator. The bug only applies when the git files
|
||||
generator is the second generator nested under a matrix. For example:
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: ApplicationSet
|
||||
metadata:
|
||||
name: guestbook
|
||||
spec:
|
||||
generators:
|
||||
- matrix:
|
||||
generators:
|
||||
- clusters: {}
|
||||
- git:
|
||||
repoURL: https://git.example.com/org/repo.git
|
||||
revision: HEAD
|
||||
files:
|
||||
- path: "defaults/*.yaml"
|
||||
template:
|
||||
# ...
|
||||
```
|
||||
|
||||
The nested git files generator will produce no parameters, causing the matrix generator to also produce no parameters.
|
||||
This will cause the ApplicationSet to produce no Applications. If the ApplicationSet controller is
|
||||
[configured with the ability to delete applications](https://argo-cd.readthedocs.io/en/latest/operator-manual/applicationset/Controlling-Resource-Modification/),
|
||||
it will delete all Applications which were previously created by the ApplicationSet.
|
||||
|
||||
To avoid this issue, upgrade directly to >=2.5.15 or >= 2.6.6.
|
||||
|
||||
## Configure RBAC to account for new `applicationsets` resource
|
||||
|
||||
2.5 introduces a new `applicationsets` [RBAC resource](https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/#rbac-resources-and-actions).
|
||||
@@ -97,7 +149,7 @@ When using `argocd app diff --local`, code from the repo server is run on the us
|
||||
|
||||
In order to support CMPs and reduce local requirements, we have implemented *server-side generation* of local manifests via the `--server-side-generate` argument. For example, `argocd app diff --local repoDir --server-side-generate` will upload the contents of `repoDir` to the repo server and run your manifest generation pipeline against it, the same as it would for a Git repo.
|
||||
|
||||
In v2.6, the `--server-side-generate` argument will become the default and client-side generation will be removed.
|
||||
In v2.7, the `--server-side-generate` argument will become the default and client-side generation will be removed.
|
||||
|
||||
!!! warning
|
||||
The semantics of *where* Argo will start generating manifests within a repo has changed between client-side and server-side generation. With client-side generation, the application's path (`spec.source.path`) was ignored and the value of `--local-repo-root` was effectively used (by default `/` relative to `--local`).
|
||||
|
||||
@@ -302,8 +302,9 @@ data:
|
||||
clientID: aaaabbbbccccddddeee
|
||||
clientSecret: $oidc.okta.clientSecret
|
||||
|
||||
# Optional list of allowed aud claims. If omitted or empty, defaults to the clientID value above. If you specify a
|
||||
# list and want the clientD to be allowed, you must explicitly include it in the list.
|
||||
# Optional list of allowed aud claims. If omitted or empty, defaults to the clientID value above (and the
|
||||
# cliCientID, if that is also specified). If you specify a list and want the clientID to be allowed, you must
|
||||
# explicitly include it in the list.
|
||||
# Token verification will pass if any of the token's audiences matches any of the audiences in this list.
|
||||
allowedAudiences:
|
||||
- aaaabbbbccccddddeee
|
||||
|
||||
@@ -94,6 +94,7 @@ data:
|
||||
```
|
||||
|
||||
Make sure that:
|
||||
|
||||
- __issuer__ ends with the correct realm (in this example _master_)
|
||||
- __issuer__ on Keycloak releases older than version 17 the URL must include /auth (in this expample /auth/realms/master)
|
||||
- __clientID__ is set to the Client ID you configured in Keycloak
|
||||
|
||||
@@ -11,5 +11,6 @@ Before effectively using Argo CD, it is necessary to understand the underlying t
|
||||
* Depending on how you plan to template your applications:
|
||||
* [Kustomize](https://kustomize.io)
|
||||
* [Helm](https://helm.sh)
|
||||
* If you're integrating with Jenkins:
|
||||
* [Jenkins User Guide](https://jenkins.io)
|
||||
* If you're integrating with a CI tool:
|
||||
* [GitHub Actions Documentation](https://docs.github.com/en/actions)
|
||||
* [Jenkins User Guide](https://www.jenkins.io/doc/book/)
|
||||
|
||||
@@ -24,9 +24,10 @@ argocd app delete APPNAME
|
||||
|
||||
# Deletion Using `kubectl`
|
||||
|
||||
To perform a non-cascade delete:
|
||||
To perform a non-cascade delete, make sure the finalizer is unset and then delete the app:
|
||||
|
||||
```bash
|
||||
kubectl patch app APPNAME -p '{"metadata": {"finalizers": null}}' --type merge
|
||||
kubectl delete app APPNAME
|
||||
```
|
||||
|
||||
|
||||
@@ -48,40 +48,4 @@ Within ApplicationSet there exist other more powerful generators in addition to
|
||||
|
||||
To learn more about the ApplicationSet controller, check out [ApplicationSet documentation](../operator-manual/applicationset/index.md) to install the ApplicationSet controller alongside Argo CD.
|
||||
|
||||
**Note:** Starting `v2.3` of Argo CD, we don't need to install ApplicationSet Controller separately. It would be instead as part of Argo CD installation.
|
||||
|
||||
#### Post Selector all generators
|
||||
|
||||
The Selector allows to post-filter based on generated values using the kubernetes common labelSelector format. In the example, the list generator generates a set of two application which then filter by the key value to only select the `env` with value `staging`:
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: ApplicationSet
|
||||
metadata:
|
||||
name: guestbook
|
||||
spec:
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- cluster: engineering-dev
|
||||
url: https://kubernetes.default.svc
|
||||
env: staging
|
||||
- cluster: engineering-prod
|
||||
url: https://kubernetes.default.svc
|
||||
env: prod
|
||||
selector:
|
||||
matchLabels:
|
||||
env: staging
|
||||
template:
|
||||
metadata:
|
||||
name: '{{cluster}}-guestbook'
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/argoproj-labs/applicationset.git
|
||||
targetRevision: HEAD
|
||||
path: examples/list-generator/guestbook/{{cluster}}
|
||||
destination:
|
||||
server: '{{url}}'
|
||||
namespace: guestbook
|
||||
```
|
||||
**Note:** Starting `v2.3` of Argo CD, we don't need to install ApplicationSet Controller separately. It would be instead as part of Argo CD installation.
|
||||
@@ -43,6 +43,9 @@ spec:
|
||||
recurse: true
|
||||
```
|
||||
|
||||
!!! warning
|
||||
Directory-type applications only work for plain manifest files. If Argo CD encounters Kustomize, Helm, or Jsonnet files when directory: is set, it will fail to render the manifests.
|
||||
|
||||
## Including/Excluding Files
|
||||
|
||||
### Including Only Certain Files
|
||||
|
||||
@@ -272,7 +272,7 @@ Helm, [starting with v3.6.1](https://github.com/helm/helm/releases/tag/v3.6.1),
|
||||
prevents sending repository credentials to download charts that are being served
|
||||
from a different domain than the repository.
|
||||
|
||||
If needed, it is possible to specifically set the Helm version to template with by setting the `helm-pass-credentials` flag on the cli:
|
||||
If needed, it is possible to opt into passing credentials for all domains by setting the `helm-pass-credentials` flag on the cli:
|
||||
|
||||
```bash
|
||||
argocd app set helm-guestbook --helm-pass-credentials
|
||||
|
||||
19
go.mod
19
go.mod
@@ -74,10 +74,10 @@ require (
|
||||
github.com/xanzy/go-gitlab v0.60.0
|
||||
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
|
||||
golang.org/x/net v0.0.0-20220621193019-9d032be2e588 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
|
||||
golang.org/x/term v0.5.0
|
||||
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368
|
||||
google.golang.org/grpc v1.45.0
|
||||
google.golang.org/protobuf v1.28.0
|
||||
@@ -225,11 +225,11 @@ require (
|
||||
go.opentelemetry.io/proto/otlp v0.15.0 // indirect
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
|
||||
golang.org/x/exp v0.0.0-20210901193431-a062eea981d2 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||
golang.org/x/tools v0.1.10 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||
@@ -252,6 +252,8 @@ require (
|
||||
)
|
||||
|
||||
replace (
|
||||
// Address CVE-2021-4238
|
||||
github.com/Masterminds/goutils => github.com/Masterminds/goutils v1.1.1
|
||||
// https://github.com/golang/go/issues/33546#issuecomment-519656923
|
||||
github.com/go-check/check => github.com/go-check/check v0.0.0-20180628173108-788fd7840127
|
||||
|
||||
@@ -260,6 +262,9 @@ replace (
|
||||
github.com/grpc-ecosystem/grpc-gateway => github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
||||
github.com/improbable-eng/grpc-web => github.com/improbable-eng/grpc-web v0.0.0-20181111100011-16092bd1d58a
|
||||
|
||||
// Avoid CVE-2022-3064
|
||||
gopkg.in/yaml.v2 => gopkg.in/yaml.v2 v2.2.4
|
||||
|
||||
// Avoid CVE-2022-28948
|
||||
gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
|
||||
|
||||
|
||||
38
go.sum
38
go.sum
@@ -85,8 +85,8 @@ github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU=
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
|
||||
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
|
||||
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||
@@ -1297,8 +1297,9 @@ 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/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.5.1-0.20210830214625-1b1db11ec8f4/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/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=
|
||||
@@ -1361,8 +1362,8 @@ golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220621193019-9d032be2e588 h1:9ubFuySsnAJYGyJrZ3koiEv8FyqofCBdz3G9Mbf2YFc=
|
||||
golang.org/x/net v0.0.0-20220621193019-9d032be2e588/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/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=
|
||||
@@ -1395,8 +1396,9 @@ 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-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-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/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=
|
||||
@@ -1508,11 +1510,12 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/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-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1521,8 +1524,9 @@ 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.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
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/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/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=
|
||||
@@ -1606,8 +1610,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1822,16 +1826,8 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
|
||||
gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
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.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
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.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
|
||||
@@ -5,7 +5,7 @@ kind: Kustomization
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.5.8
|
||||
newTag: v2.5.15
|
||||
resources:
|
||||
- ./application-controller
|
||||
- ./dex
|
||||
|
||||
@@ -23,7 +23,7 @@ spec:
|
||||
serviceAccountName: argocd-redis
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: Always
|
||||
args:
|
||||
- "--save"
|
||||
|
||||
@@ -9635,7 +9635,7 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -9717,7 +9717,7 @@ spec:
|
||||
- ""
|
||||
- --appendonly
|
||||
- "no"
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -9893,7 +9893,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -9944,7 +9944,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -10151,7 +10151,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -12,4 +12,4 @@ resources:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.5.8
|
||||
newTag: v2.5.15
|
||||
|
||||
@@ -11,7 +11,7 @@ patchesStrategicMerge:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.5.8
|
||||
newTag: v2.5.15
|
||||
resources:
|
||||
- ../../base/application-controller
|
||||
- ../../base/applicationset-controller
|
||||
|
||||
@@ -1071,7 +1071,7 @@ spec:
|
||||
topologyKey: kubernetes.io/hostname
|
||||
initContainers:
|
||||
- name: config-init
|
||||
image: haproxy:2.6.2-alpine
|
||||
image: haproxy:2.6.9-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
{}
|
||||
@@ -1089,7 +1089,7 @@ spec:
|
||||
mountPath: /data
|
||||
containers:
|
||||
- name: haproxy
|
||||
image: haproxy:2.6.2-alpine
|
||||
image: haproxy:2.6.9-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
securityContext:
|
||||
null
|
||||
@@ -1179,7 +1179,7 @@ spec:
|
||||
automountServiceAccountToken: false
|
||||
initContainers:
|
||||
- name: config-init
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
{}
|
||||
@@ -1206,7 +1206,7 @@ spec:
|
||||
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- redis-server
|
||||
@@ -1256,7 +1256,7 @@ spec:
|
||||
- /bin/sh
|
||||
- /readonly-config/trigger-failover-if-master.sh
|
||||
- name: sentinel
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- redis-sentinel
|
||||
@@ -1300,7 +1300,7 @@ spec:
|
||||
{}
|
||||
|
||||
- name: split-brain-fix
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- sh
|
||||
|
||||
@@ -11,14 +11,14 @@ redis-ha:
|
||||
IPv6:
|
||||
enabled: false
|
||||
image:
|
||||
tag: 2.6.2-alpine
|
||||
tag: 2.6.9-alpine
|
||||
containerSecurityContext: null
|
||||
timeout:
|
||||
server: 6m
|
||||
client: 6m
|
||||
checkInterval: 3s
|
||||
image:
|
||||
tag: 7.0.7-alpine
|
||||
tag: 7.0.8-alpine
|
||||
containerSecurityContext: null
|
||||
sentinel:
|
||||
bind: "0.0.0.0"
|
||||
|
||||
@@ -10836,7 +10836,7 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -10946,7 +10946,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -10999,7 +10999,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -11070,7 +11070,7 @@ spec:
|
||||
app.kubernetes.io/name: argocd-redis-ha-haproxy
|
||||
topologyKey: kubernetes.io/hostname
|
||||
containers:
|
||||
- image: haproxy:2.6.2-alpine
|
||||
- image: haproxy:2.6.9-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -11106,7 +11106,7 @@ spec:
|
||||
- /readonly/haproxy_init.sh
|
||||
command:
|
||||
- sh
|
||||
image: haproxy:2.6.2-alpine
|
||||
image: haproxy:2.6.9-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
@@ -11296,7 +11296,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -11347,7 +11347,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -11620,7 +11620,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -11855,7 +11855,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
@@ -11932,7 +11932,7 @@ spec:
|
||||
- /data/conf/redis.conf
|
||||
command:
|
||||
- redis-server
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
preStop:
|
||||
@@ -11985,7 +11985,7 @@ spec:
|
||||
- /data/conf/sentinel.conf
|
||||
command:
|
||||
- redis-sentinel
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -12037,7 +12037,7 @@ spec:
|
||||
value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4
|
||||
- name: SENTINEL_ID_2
|
||||
value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: split-brain-fix
|
||||
resources: {}
|
||||
@@ -12066,7 +12066,7 @@ spec:
|
||||
value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4
|
||||
- name: SENTINEL_ID_2
|
||||
value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
|
||||
@@ -1502,7 +1502,7 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -1612,7 +1612,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -1665,7 +1665,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -1736,7 +1736,7 @@ spec:
|
||||
app.kubernetes.io/name: argocd-redis-ha-haproxy
|
||||
topologyKey: kubernetes.io/hostname
|
||||
containers:
|
||||
- image: haproxy:2.6.2-alpine
|
||||
- image: haproxy:2.6.9-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -1772,7 +1772,7 @@ spec:
|
||||
- /readonly/haproxy_init.sh
|
||||
command:
|
||||
- sh
|
||||
image: haproxy:2.6.2-alpine
|
||||
image: haproxy:2.6.9-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
@@ -1962,7 +1962,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -2013,7 +2013,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -2286,7 +2286,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2521,7 +2521,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
@@ -2598,7 +2598,7 @@ spec:
|
||||
- /data/conf/redis.conf
|
||||
command:
|
||||
- redis-server
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
preStop:
|
||||
@@ -2651,7 +2651,7 @@ spec:
|
||||
- /data/conf/sentinel.conf
|
||||
command:
|
||||
- redis-sentinel
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -2703,7 +2703,7 @@ spec:
|
||||
value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4
|
||||
- name: SENTINEL_ID_2
|
||||
value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: split-brain-fix
|
||||
resources: {}
|
||||
@@ -2732,7 +2732,7 @@ spec:
|
||||
value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4
|
||||
- name: SENTINEL_ID_2
|
||||
value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
|
||||
@@ -9955,7 +9955,7 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -10065,7 +10065,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -10118,7 +10118,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -10195,7 +10195,7 @@ spec:
|
||||
- ""
|
||||
- --appendonly
|
||||
- "no"
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -10371,7 +10371,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -10422,7 +10422,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -10691,7 +10691,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -10924,7 +10924,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -621,7 +621,7 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -731,7 +731,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -784,7 +784,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -861,7 +861,7 @@ spec:
|
||||
- ""
|
||||
- --appendonly
|
||||
- "no"
|
||||
image: redis:7.0.7-alpine
|
||||
image: redis:7.0.8-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -1037,7 +1037,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1088,7 +1088,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -1357,7 +1357,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -1590,7 +1590,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.5.8
|
||||
image: quay.io/argoproj/argocd:v2.5.15
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -94,6 +94,7 @@ nav:
|
||||
- operator-manual/applicationset/Generators-SCM-Provider.md
|
||||
- operator-manual/applicationset/Generators-Cluster-Decision-Resource.md
|
||||
- operator-manual/applicationset/Generators-Pull-Request.md
|
||||
- operator-manual/applicationset/Generators-Post-Selector.md
|
||||
- Template fields:
|
||||
- operator-manual/applicationset/Template.md
|
||||
- operator-manual/applicationset/GoTemplate.md
|
||||
|
||||
@@ -51,7 +51,9 @@ type ApplicationQuery struct {
|
||||
// the repoURL to restrict returned list applications
|
||||
Repo *string `protobuf:"bytes,6,opt,name=repo" json:"repo,omitempty"`
|
||||
// the application's namespace
|
||||
AppNamespace *string `protobuf:"bytes,7,opt,name=appNamespace" json:"appNamespace,omitempty"`
|
||||
AppNamespace *string `protobuf:"bytes,7,opt,name=appNamespace" json:"appNamespace,omitempty"`
|
||||
// the project names to restrict returned list applications (legacy name for backwards-compatibility)
|
||||
Project []string `protobuf:"bytes,8,rep,name=project" json:"project,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -139,6 +141,13 @@ func (m *ApplicationQuery) GetAppNamespace() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *ApplicationQuery) GetProject() []string {
|
||||
if m != nil {
|
||||
return m.Project
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NodeQuery struct {
|
||||
// the application's name
|
||||
Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
|
||||
@@ -2451,160 +2460,161 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_df6e82b174b5eaec = []byte{
|
||||
// 2444 bytes of a gzipped FileDescriptorProto
|
||||
// 2453 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0xcd, 0x8f, 0x1c, 0x47,
|
||||
0x15, 0xa7, 0x66, 0xbf, 0x66, 0xde, 0xac, 0xbf, 0x2a, 0xf1, 0xd2, 0x19, 0xaf, 0xcd, 0xa6, 0xfd,
|
||||
0xb5, 0x5e, 0x7b, 0x67, 0xec, 0xc1, 0x20, 0x67, 0x03, 0x02, 0xdb, 0xf1, 0x17, 0xac, 0x1d, 0xd3,
|
||||
0x6b, 0xb3, 0x28, 0x1c, 0xa0, 0xd2, 0x5d, 0x3b, 0xdb, 0xec, 0x4c, 0x57, 0xbb, 0xbb, 0x67, 0xac,
|
||||
0x91, 0xf1, 0x25, 0x08, 0x4e, 0x28, 0x48, 0x49, 0x0e, 0x28, 0x8a, 0x10, 0x4a, 0x94, 0x0b, 0x17,
|
||||
0x6e, 0x08, 0x89, 0x0b, 0x5c, 0x10, 0x48, 0x1c, 0x10, 0x1f, 0x97, 0x9c, 0x90, 0xc5, 0x8d, 0x0b,
|
||||
0x7f, 0x02, 0xaa, 0xea, 0xaa, 0xee, 0xea, 0x99, 0x9e, 0x9e, 0x59, 0x76, 0xa3, 0xf8, 0x56, 0xaf,
|
||||
0xba, 0xea, 0xbd, 0x5f, 0xbd, 0x7a, 0xef, 0x55, 0xd5, 0x6f, 0x06, 0x4e, 0x85, 0x34, 0xe8, 0xd1,
|
||||
0xa0, 0x41, 0x7c, 0xbf, 0xed, 0xda, 0x24, 0x72, 0x99, 0xa7, 0xb7, 0xeb, 0x7e, 0xc0, 0x22, 0x86,
|
||||
0xab, 0x5a, 0x57, 0x6d, 0xb1, 0xc5, 0x58, 0xab, 0x4d, 0x1b, 0xc4, 0x77, 0x1b, 0xc4, 0xf3, 0x58,
|
||||
0x24, 0xba, 0xc3, 0x78, 0x68, 0xcd, 0xdc, 0xb9, 0x12, 0xd6, 0x5d, 0x26, 0xbe, 0xda, 0x2c, 0xa0,
|
||||
0x8d, 0xde, 0xa5, 0x46, 0x8b, 0x7a, 0x34, 0x20, 0x11, 0x75, 0xe4, 0x98, 0xcb, 0xe9, 0x98, 0x0e,
|
||||
0xb1, 0xb7, 0x5d, 0x8f, 0x06, 0xfd, 0x86, 0xbf, 0xd3, 0xe2, 0x1d, 0x61, 0xa3, 0x43, 0x23, 0x92,
|
||||
0x37, 0x6b, 0xbd, 0xe5, 0x46, 0xdb, 0xdd, 0x37, 0xeb, 0x36, 0xeb, 0x34, 0x48, 0xd0, 0x62, 0x7e,
|
||||
0xc0, 0x7e, 0x20, 0x1a, 0xab, 0xb6, 0xd3, 0xe8, 0x35, 0x53, 0x05, 0xfa, 0x5a, 0x7a, 0x97, 0x48,
|
||||
0xdb, 0xdf, 0x26, 0xc3, 0xda, 0x6e, 0x8c, 0xd1, 0x16, 0x50, 0x9f, 0x49, 0xdf, 0x88, 0xa6, 0x1b,
|
||||
0xb1, 0xa0, 0xaf, 0x35, 0x63, 0x35, 0xe6, 0x27, 0x08, 0x0e, 0x5f, 0x4d, 0xed, 0x7d, 0xab, 0x4b,
|
||||
0x83, 0x3e, 0xc6, 0x30, 0xed, 0x91, 0x0e, 0x35, 0xd0, 0x12, 0x5a, 0xae, 0x58, 0xa2, 0x8d, 0x0d,
|
||||
0x98, 0x0b, 0xe8, 0x56, 0x40, 0xc3, 0x6d, 0xa3, 0x24, 0xba, 0x95, 0x88, 0x6b, 0x50, 0xe6, 0xc6,
|
||||
0xa9, 0x1d, 0x85, 0xc6, 0xd4, 0xd2, 0xd4, 0x72, 0xc5, 0x4a, 0x64, 0xbc, 0x0c, 0x87, 0x02, 0x1a,
|
||||
0xb2, 0x6e, 0x60, 0xd3, 0x6f, 0xd3, 0x20, 0x74, 0x99, 0x67, 0x4c, 0x8b, 0xd9, 0x83, 0xdd, 0x5c,
|
||||
0x4b, 0x48, 0xdb, 0xd4, 0x8e, 0x58, 0x60, 0xcc, 0x88, 0x21, 0x89, 0xcc, 0xf1, 0x70, 0xe0, 0xc6,
|
||||
0x6c, 0x8c, 0x87, 0xb7, 0xb1, 0x09, 0xf3, 0xc4, 0xf7, 0xef, 0x91, 0x0e, 0x0d, 0x7d, 0x62, 0x53,
|
||||
0x63, 0x4e, 0x7c, 0xcb, 0xf4, 0x99, 0xd7, 0xa1, 0x72, 0x8f, 0x39, 0x74, 0xf4, 0xa2, 0x06, 0x95,
|
||||
0x94, 0x72, 0x94, 0xec, 0xc0, 0x51, 0x8b, 0xf6, 0x5c, 0x0e, 0xf2, 0x2e, 0x8d, 0x88, 0x43, 0x22,
|
||||
0x32, 0xa8, 0xb0, 0x94, 0x28, 0xac, 0x41, 0x39, 0x90, 0x83, 0x8d, 0x92, 0xe8, 0x4f, 0xe4, 0x21,
|
||||
0x63, 0x53, 0x39, 0xc6, 0xfe, 0x82, 0xe0, 0x84, 0xb6, 0x1d, 0x96, 0x74, 0xd2, 0x8d, 0x1e, 0xf5,
|
||||
0xa2, 0x70, 0xb4, 0xd9, 0x0b, 0x70, 0x44, 0xf9, 0x73, 0x70, 0x31, 0xc3, 0x1f, 0x38, 0x10, 0xbd,
|
||||
0x53, 0x01, 0xd1, 0xfb, 0xf0, 0x12, 0x54, 0x95, 0xfc, 0xf0, 0xce, 0x6b, 0x72, 0xd3, 0xf4, 0xae,
|
||||
0xa1, 0xe5, 0xcc, 0xe4, 0x2c, 0xc7, 0x03, 0x43, 0x5b, 0xcd, 0x5d, 0xe2, 0xb9, 0x5b, 0x34, 0x8c,
|
||||
0x26, 0x75, 0x1f, 0xda, 0xb5, 0xfb, 0x5e, 0x86, 0xca, 0x4d, 0xb7, 0x4d, 0xaf, 0x6f, 0x77, 0xbd,
|
||||
0x1d, 0xfc, 0x22, 0xcc, 0xd8, 0xbc, 0x21, 0x2c, 0xcc, 0x5b, 0xb1, 0x60, 0x3e, 0x86, 0x97, 0x47,
|
||||
0x41, 0xda, 0x74, 0xa3, 0x6d, 0x3e, 0x3d, 0x1c, 0x85, 0xcd, 0xde, 0xa6, 0xf6, 0x4e, 0xd8, 0xed,
|
||||
0xa8, 0xad, 0x55, 0xf2, 0x44, 0xd8, 0x7e, 0x85, 0x60, 0x79, 0xac, 0xe5, 0xcd, 0x80, 0xf8, 0x3e,
|
||||
0x0d, 0xf0, 0x4d, 0x98, 0x79, 0xc4, 0x3f, 0x88, 0x68, 0xad, 0x36, 0xeb, 0x75, 0xbd, 0xa6, 0x8d,
|
||||
0xd5, 0x72, 0xfb, 0x73, 0x56, 0x3c, 0x1d, 0xd7, 0x95, 0x0f, 0x4a, 0x42, 0xcf, 0x42, 0x46, 0x4f,
|
||||
0xe2, 0x2a, 0x3e, 0x5e, 0x0c, 0xbb, 0x36, 0x0b, 0xd3, 0x3e, 0x09, 0x22, 0xf3, 0x28, 0xbc, 0x90,
|
||||
0x0d, 0x43, 0x9f, 0x79, 0x21, 0x35, 0x7f, 0x87, 0x32, 0x1b, 0x7a, 0x3d, 0xa0, 0x24, 0xa2, 0x16,
|
||||
0x7d, 0xd4, 0xa5, 0x61, 0x84, 0x77, 0x40, 0x2f, 0xb3, 0xc2, 0x77, 0xd5, 0xe6, 0x9d, 0x7a, 0x5a,
|
||||
0xa7, 0xea, 0xaa, 0x4e, 0x89, 0xc6, 0xf7, 0x6c, 0xa7, 0xde, 0x6b, 0xd6, 0xfd, 0x9d, 0x56, 0x9d,
|
||||
0x57, 0xbd, 0x0c, 0x32, 0x55, 0xf5, 0xf4, 0xa5, 0x5a, 0xba, 0x76, 0xbc, 0x00, 0xb3, 0x5d, 0x3f,
|
||||
0xa4, 0x41, 0x24, 0x56, 0x56, 0xb6, 0xa4, 0xc4, 0x77, 0xa9, 0x47, 0xda, 0xae, 0x43, 0xa2, 0x78,
|
||||
0x17, 0xca, 0x56, 0x22, 0x9b, 0x1f, 0x65, 0xd1, 0x3f, 0xf4, 0x9d, 0xcf, 0x0a, 0xbd, 0x8e, 0xb2,
|
||||
0x34, 0x80, 0xf2, 0xfd, 0x2c, 0xca, 0xd7, 0x68, 0x9b, 0xa6, 0x28, 0xf3, 0x02, 0xd3, 0x80, 0x39,
|
||||
0x9b, 0x84, 0x36, 0x71, 0x94, 0x2e, 0x25, 0xf2, 0xb2, 0xe0, 0x07, 0xcc, 0x27, 0x2d, 0xa1, 0xe9,
|
||||
0x3e, 0x6b, 0xbb, 0x76, 0x5f, 0xc6, 0xe6, 0xf0, 0x87, 0xa1, 0x20, 0x9e, 0xce, 0x09, 0xe2, 0x93,
|
||||
0x50, 0xdd, 0xe8, 0x7b, 0xf6, 0xeb, 0xbe, 0x38, 0x32, 0x79, 0x8a, 0xb9, 0x11, 0xed, 0x84, 0x06,
|
||||
0x12, 0x75, 0x3f, 0x16, 0xcc, 0x0f, 0x66, 0x60, 0x41, 0x5b, 0x01, 0x9f, 0x50, 0x84, 0xbf, 0x28,
|
||||
0xe9, 0x17, 0x60, 0xd6, 0x09, 0xfa, 0x56, 0xd7, 0x93, 0x9b, 0x29, 0x25, 0x6e, 0xd8, 0x0f, 0xba,
|
||||
0x5e, 0x0c, 0xb2, 0x6c, 0xc5, 0x02, 0xde, 0x82, 0x72, 0x18, 0xf1, 0x43, 0xb2, 0xd5, 0x17, 0xe5,
|
||||
0xa8, 0xda, 0xfc, 0xc6, 0xde, 0x36, 0x90, 0x43, 0xdf, 0x90, 0x1a, 0xad, 0x44, 0x37, 0x7e, 0x04,
|
||||
0x15, 0x55, 0x09, 0x43, 0x63, 0x6e, 0x69, 0x6a, 0xb9, 0xda, 0xdc, 0xd8, 0xbb, 0xa1, 0xd7, 0x7d,
|
||||
0x7e, 0xc0, 0x6b, 0x55, 0xdf, 0x4a, 0xad, 0xe0, 0x45, 0xa8, 0x74, 0x64, 0xae, 0x87, 0x46, 0x59,
|
||||
0x78, 0x3b, 0xed, 0xc0, 0xdf, 0x81, 0x19, 0xd7, 0xdb, 0x62, 0xa1, 0x51, 0x11, 0x60, 0xae, 0xed,
|
||||
0x0d, 0xcc, 0x1d, 0x6f, 0x8b, 0x59, 0xb1, 0x42, 0xfc, 0x08, 0x0e, 0x04, 0x34, 0x0a, 0xfa, 0xca,
|
||||
0x0b, 0x06, 0x08, 0xbf, 0x7e, 0x73, 0x6f, 0x16, 0x2c, 0x5d, 0xa5, 0x95, 0xb5, 0x80, 0xd7, 0xa0,
|
||||
0x1a, 0xa6, 0x31, 0x66, 0x54, 0x85, 0x41, 0x23, 0xa3, 0x48, 0x8b, 0x41, 0x4b, 0x1f, 0x3c, 0x14,
|
||||
0xc3, 0xf3, 0x39, 0x31, 0xfc, 0x4f, 0x04, 0x8b, 0x43, 0x65, 0x60, 0xc3, 0xa7, 0x85, 0x41, 0x4a,
|
||||
0x60, 0x3a, 0xf4, 0xa9, 0x2d, 0x2a, 0x7f, 0xb5, 0x79, 0x77, 0xdf, 0xea, 0x82, 0xb0, 0x2b, 0x54,
|
||||
0x17, 0x95, 0xae, 0x89, 0x72, 0xf3, 0xc7, 0x08, 0x3e, 0xaf, 0x69, 0xbe, 0x4f, 0x22, 0x7b, 0xbb,
|
||||
0x68, 0x49, 0x3c, 0x87, 0xf8, 0x18, 0x79, 0x9a, 0xc5, 0x02, 0x0f, 0x34, 0xd1, 0x78, 0xd0, 0xf7,
|
||||
0x39, 0x0c, 0xfe, 0x25, 0xed, 0x98, 0xe8, 0xd0, 0x7f, 0x07, 0x41, 0x4d, 0xaf, 0x7c, 0xac, 0xdd,
|
||||
0x7e, 0x93, 0xd8, 0x3b, 0x45, 0x50, 0x0e, 0x42, 0xc9, 0x75, 0x04, 0x8e, 0x29, 0xab, 0xe4, 0x3a,
|
||||
0xbb, 0x4c, 0xfb, 0x41, 0x50, 0xb3, 0x39, 0xa0, 0x3e, 0x19, 0x00, 0xa5, 0x52, 0xac, 0x00, 0xd4,
|
||||
0x22, 0x54, 0xbc, 0x81, 0xcb, 0x54, 0xda, 0x91, 0x73, 0x89, 0x2a, 0x0d, 0x5d, 0xa2, 0x0c, 0x98,
|
||||
0xeb, 0x25, 0xb7, 0x5e, 0xfe, 0x59, 0x89, 0x7c, 0x21, 0xad, 0x80, 0x75, 0x7d, 0xe9, 0xc0, 0x58,
|
||||
0xe0, 0x28, 0x76, 0x5c, 0xcf, 0x31, 0x66, 0x63, 0x14, 0xbc, 0x3d, 0xd1, 0x3d, 0xf7, 0xdd, 0x12,
|
||||
0x7c, 0x21, 0x67, 0x71, 0x63, 0x23, 0xe0, 0xf9, 0x58, 0x61, 0x12, 0x87, 0x73, 0x23, 0xe3, 0xb0,
|
||||
0x3c, 0x2e, 0x0e, 0x2b, 0x39, 0x5e, 0x79, 0xbb, 0x04, 0x4b, 0x39, 0x5e, 0x19, 0x7f, 0xa0, 0x3e,
|
||||
0x37, 0x6e, 0xd9, 0x62, 0x81, 0xdc, 0xf1, 0xb2, 0x15, 0x0b, 0x3c, 0x33, 0x58, 0xe0, 0x6f, 0x13,
|
||||
0xcf, 0x28, 0xc7, 0x99, 0x11, 0x4b, 0x13, 0x39, 0xe4, 0xbf, 0x08, 0x0c, 0xe5, 0x85, 0xab, 0xb6,
|
||||
0xf0, 0x49, 0xd7, 0x7b, 0xfe, 0x1d, 0xb1, 0x00, 0xb3, 0x44, 0xa0, 0x95, 0x01, 0x22, 0xa5, 0xa1,
|
||||
0x25, 0x97, 0xf3, 0x6b, 0xe2, 0xb1, 0xec, 0x92, 0xc3, 0x75, 0x37, 0x8c, 0xd4, 0x85, 0x16, 0x6f,
|
||||
0xc1, 0x5c, 0xac, 0x2d, 0xbe, 0xc2, 0x54, 0x9b, 0xeb, 0x7b, 0x3d, 0xd8, 0x32, 0xee, 0x55, 0xca,
|
||||
0xcd, 0x57, 0xe0, 0x58, 0x6e, 0xf5, 0x91, 0x30, 0x6a, 0x50, 0x56, 0x87, 0xb9, 0xdc, 0x80, 0x44,
|
||||
0x36, 0xff, 0x33, 0x95, 0x2d, 0xeb, 0xcc, 0x59, 0x67, 0xad, 0x82, 0xb7, 0x60, 0xf1, 0xa6, 0x19,
|
||||
0x30, 0xe7, 0x33, 0x47, 0x7b, 0xf6, 0x29, 0x91, 0xcf, 0xb3, 0x99, 0x17, 0x11, 0xd7, 0xa3, 0x81,
|
||||
0x3c, 0x5f, 0xd2, 0x0e, 0xee, 0xec, 0xd0, 0xf5, 0x6c, 0xba, 0x41, 0x6d, 0xe6, 0x39, 0xa1, 0xd8,
|
||||
0xb5, 0x29, 0x2b, 0xd3, 0x87, 0x6f, 0x43, 0x45, 0xc8, 0x0f, 0xdc, 0x4e, 0x5c, 0x84, 0xab, 0xcd,
|
||||
0x95, 0x7a, 0x4c, 0x95, 0xd4, 0x75, 0xaa, 0x24, 0xf5, 0x61, 0x87, 0x46, 0xa4, 0xde, 0xbb, 0x54,
|
||||
0xe7, 0x33, 0xac, 0x74, 0x32, 0xc7, 0x12, 0x11, 0xb7, 0xbd, 0xee, 0x7a, 0xe2, 0x82, 0xc5, 0x4d,
|
||||
0xa5, 0x1d, 0x3c, 0x20, 0xb6, 0x58, 0xbb, 0xcd, 0x1e, 0xab, 0x1c, 0x88, 0x25, 0x3e, 0xab, 0xeb,
|
||||
0x45, 0x6e, 0x5b, 0xd8, 0x8f, 0x13, 0x20, 0xed, 0x10, 0xb3, 0xdc, 0x76, 0x44, 0x03, 0x71, 0x85,
|
||||
0xa9, 0x58, 0x52, 0x4a, 0x42, 0xae, 0x1a, 0xf3, 0x02, 0x2a, 0xf7, 0xe2, 0xe0, 0x9c, 0xd7, 0x83,
|
||||
0x73, 0x30, 0xe0, 0x0f, 0xe4, 0xbc, 0x9b, 0x05, 0x19, 0x42, 0x7b, 0x2e, 0xeb, 0x86, 0xc6, 0xc1,
|
||||
0xf8, 0x10, 0x57, 0xf2, 0x50, 0xc0, 0x1e, 0xca, 0x09, 0xd8, 0xdf, 0x23, 0x28, 0xaf, 0xb3, 0xd6,
|
||||
0x0d, 0x2f, 0x0a, 0xfa, 0xe2, 0x66, 0xcf, 0xbc, 0x88, 0x7a, 0x2a, 0x2a, 0x94, 0xc8, 0x5d, 0x1d,
|
||||
0xb9, 0x1d, 0xba, 0x11, 0x91, 0x8e, 0x2f, 0xef, 0x24, 0xbb, 0x72, 0x75, 0x32, 0x99, 0x2f, 0xbf,
|
||||
0x4d, 0xc2, 0x48, 0x64, 0x6f, 0xd9, 0x12, 0x6d, 0x0e, 0x34, 0x19, 0xb0, 0x11, 0x05, 0x32, 0x75,
|
||||
0x33, 0x7d, 0x7a, 0x20, 0xcd, 0xc4, 0xd8, 0xa4, 0x68, 0x6e, 0xc0, 0x4b, 0xc9, 0x55, 0xf6, 0x01,
|
||||
0x0d, 0x3a, 0xae, 0x47, 0x8a, 0xeb, 0xed, 0x24, 0x2c, 0xcc, 0xc3, 0x4c, 0x02, 0xf1, 0xfb, 0xdf,
|
||||
0xa6, 0xeb, 0x39, 0xec, 0x71, 0x41, 0x22, 0x4c, 0xa2, 0xf6, 0x6f, 0x59, 0xbe, 0x45, 0xd3, 0x9b,
|
||||
0xe4, 0xe6, 0x6d, 0x38, 0xc0, 0xb3, 0xb8, 0x47, 0xe5, 0x07, 0x59, 0x28, 0xcc, 0x51, 0x4f, 0xf2,
|
||||
0x54, 0x87, 0x95, 0x9d, 0x88, 0xd7, 0xe1, 0x10, 0x09, 0x43, 0xb7, 0xe5, 0x51, 0x47, 0xe9, 0x2a,
|
||||
0x4d, 0xac, 0x6b, 0x70, 0x6a, 0xfc, 0xec, 0x13, 0x23, 0xe4, 0xde, 0x29, 0xd1, 0xfc, 0x11, 0x82,
|
||||
0xa3, 0xb9, 0x4a, 0x92, 0x58, 0x47, 0x5a, 0x79, 0xad, 0x41, 0x39, 0xb4, 0xb7, 0xa9, 0xd3, 0x6d,
|
||||
0x53, 0xc5, 0x6b, 0x28, 0x99, 0x7f, 0x73, 0xba, 0xf1, 0x4e, 0xca, 0xf2, 0x9e, 0xc8, 0xf8, 0x04,
|
||||
0x40, 0x87, 0x78, 0x5d, 0xd2, 0x16, 0x10, 0xa6, 0x05, 0x04, 0xad, 0xc7, 0x5c, 0x84, 0x5a, 0x5e,
|
||||
0x18, 0x48, 0x26, 0xe1, 0x1f, 0x08, 0x0e, 0xaa, 0x32, 0x28, 0xf7, 0x70, 0x19, 0x0e, 0x69, 0x6e,
|
||||
0xb8, 0x97, 0x6e, 0xe7, 0x60, 0xf7, 0x98, 0x12, 0xa7, 0x62, 0x61, 0x2a, 0xcb, 0x5e, 0xf6, 0x32,
|
||||
0xfc, 0xe3, 0xc4, 0xe7, 0x10, 0xda, 0xd5, 0x4d, 0xec, 0x87, 0x60, 0xdc, 0x25, 0x1e, 0x69, 0x51,
|
||||
0x27, 0x59, 0x5c, 0x12, 0x48, 0xdf, 0xd7, 0x1f, 0xcb, 0x7b, 0x7e, 0x9a, 0x26, 0xd7, 0x19, 0x77,
|
||||
0x6b, 0x4b, 0x3e, 0xbc, 0x9b, 0x3f, 0x59, 0x02, 0xac, 0x6f, 0x3c, 0x0d, 0x7a, 0xae, 0x4d, 0xf1,
|
||||
0x3b, 0x08, 0xa6, 0xf9, 0xa9, 0x87, 0x8f, 0x8f, 0x8a, 0x33, 0xb1, 0x01, 0xb5, 0xfd, 0x7b, 0xd5,
|
||||
0x70, 0x6b, 0xe6, 0xe2, 0x5b, 0x7f, 0xff, 0xf7, 0xbb, 0xa5, 0x05, 0xfc, 0xa2, 0xe0, 0xd2, 0x7b,
|
||||
0x97, 0x74, 0x5e, 0x3b, 0xc4, 0x3f, 0x45, 0x80, 0xe5, 0x51, 0xac, 0x51, 0x9c, 0xf8, 0xfc, 0x28,
|
||||
0x88, 0x39, 0x54, 0x68, 0xed, 0xb8, 0x56, 0xf2, 0xea, 0x36, 0x0b, 0x28, 0x2f, 0x70, 0x62, 0x80,
|
||||
0x00, 0xb0, 0x22, 0x00, 0x9c, 0xc2, 0x66, 0x1e, 0x80, 0xc6, 0x13, 0x1e, 0x18, 0x4f, 0x1b, 0x34,
|
||||
0xb6, 0xfb, 0x21, 0x82, 0x99, 0x4d, 0x71, 0xf1, 0x1c, 0xe3, 0xa4, 0x8d, 0x7d, 0x73, 0x92, 0x30,
|
||||
0x27, 0xd0, 0x9a, 0x27, 0x05, 0xd2, 0xe3, 0xf8, 0x98, 0x42, 0x1a, 0x46, 0x01, 0x25, 0x9d, 0x0c,
|
||||
0xe0, 0x8b, 0x08, 0x7f, 0x8c, 0x60, 0x36, 0xe6, 0xdc, 0xf0, 0xe9, 0x51, 0x28, 0x33, 0x9c, 0x5c,
|
||||
0x6d, 0xff, 0x08, 0x2c, 0xf3, 0x9c, 0xc0, 0x78, 0xd2, 0xcc, 0xdd, 0xce, 0xb5, 0x0c, 0xbd, 0xf5,
|
||||
0x1e, 0x82, 0xa9, 0x5b, 0x74, 0x6c, 0xbc, 0xed, 0x23, 0xb8, 0x21, 0x07, 0xe6, 0x6c, 0x35, 0xfe,
|
||||
0x08, 0xc1, 0x4b, 0xb7, 0x68, 0x94, 0x5f, 0xef, 0xf1, 0xf2, 0xf8, 0x22, 0x2c, 0xc3, 0xee, 0xfc,
|
||||
0x04, 0x23, 0x93, 0x42, 0xd7, 0x10, 0xc8, 0xce, 0xe1, 0xb3, 0x45, 0x41, 0x18, 0xf6, 0x3d, 0xfb,
|
||||
0xb1, 0xc4, 0xf1, 0x67, 0x04, 0x87, 0x07, 0x7f, 0x70, 0xc0, 0xd9, 0x13, 0x22, 0xf7, 0xf7, 0x88,
|
||||
0xda, 0xbd, 0xbd, 0x16, 0x94, 0xac, 0x52, 0xf3, 0xaa, 0x40, 0xfe, 0x2a, 0x7e, 0xa5, 0x08, 0xb9,
|
||||
0x62, 0xea, 0xc2, 0xc6, 0x13, 0xd5, 0x7c, 0x2a, 0x7e, 0x01, 0x13, 0xb0, 0xdf, 0x42, 0x30, 0x7f,
|
||||
0x8b, 0x46, 0x77, 0x13, 0xa2, 0xea, 0xf4, 0x44, 0x44, 0x76, 0x6d, 0xb1, 0xae, 0xfd, 0x50, 0xa5,
|
||||
0x3e, 0x25, 0x2e, 0x5d, 0x15, 0xc0, 0xce, 0xe2, 0xd3, 0x45, 0xc0, 0x52, 0x72, 0xec, 0x43, 0x04,
|
||||
0x47, 0x75, 0x10, 0x29, 0xcd, 0xff, 0xa5, 0xdd, 0xd1, 0xea, 0x92, 0x9c, 0x1f, 0x83, 0xae, 0x29,
|
||||
0xd0, 0x5d, 0x30, 0xf3, 0x37, 0xbc, 0x33, 0x84, 0x62, 0x0d, 0xad, 0x2c, 0x23, 0xfc, 0x07, 0x04,
|
||||
0xb3, 0x31, 0x13, 0x35, 0xda, 0x47, 0x19, 0xc2, 0x7a, 0x3f, 0xb3, 0xe7, 0x86, 0x80, 0xfc, 0xb5,
|
||||
0xda, 0xc5, 0x7c, 0x87, 0xea, 0xf3, 0xd5, 0xd6, 0xd6, 0x85, 0x97, 0xb3, 0x69, 0xff, 0x1b, 0x04,
|
||||
0x90, 0xb2, 0x69, 0xf8, 0x5c, 0xf1, 0x3a, 0x34, 0xc6, 0xad, 0xb6, 0xbf, 0x7c, 0x9a, 0x59, 0x17,
|
||||
0xeb, 0x59, 0xae, 0x2d, 0x15, 0xe6, 0x9c, 0x4f, 0xed, 0xb5, 0x98, 0x79, 0xfb, 0x25, 0x82, 0x19,
|
||||
0x41, 0x96, 0xe0, 0x53, 0xa3, 0x30, 0xeb, 0x5c, 0xca, 0x7e, 0xba, 0xfe, 0x8c, 0x80, 0xba, 0xd4,
|
||||
0x2c, 0x2a, 0x5c, 0x6b, 0x68, 0x05, 0xf7, 0x60, 0x36, 0x26, 0x2e, 0x46, 0x87, 0x47, 0x86, 0xd8,
|
||||
0xa8, 0x2d, 0x15, 0x1c, 0xa4, 0x71, 0xa0, 0xca, 0x9a, 0xb9, 0x32, 0xae, 0x66, 0x4e, 0xf3, 0xb2,
|
||||
0x86, 0x4f, 0x16, 0x15, 0xbd, 0x4f, 0xc1, 0x31, 0xe7, 0x05, 0xba, 0xd3, 0xe6, 0xd2, 0xb8, 0xba,
|
||||
0xc9, 0xbd, 0xf3, 0x73, 0x04, 0x87, 0x07, 0xef, 0x5d, 0xf8, 0xd8, 0x40, 0xcd, 0xd4, 0x2f, 0x9b,
|
||||
0xb5, 0xac, 0x17, 0x47, 0xdd, 0xd9, 0xcc, 0xaf, 0x0b, 0x14, 0x6b, 0xf8, 0xca, 0xd8, 0xcc, 0xb8,
|
||||
0xa7, 0xaa, 0x0e, 0x57, 0xb4, 0x9a, 0x12, 0xf7, 0xbf, 0x45, 0x30, 0xaf, 0xf4, 0x3e, 0x08, 0x28,
|
||||
0x2d, 0x86, 0xb5, 0x7f, 0x89, 0xc0, 0x6d, 0x99, 0x5f, 0x11, 0xf0, 0xbf, 0x8c, 0x2f, 0x4f, 0x08,
|
||||
0x5f, 0xc1, 0x5e, 0x8d, 0x38, 0xd2, 0x3f, 0x22, 0x38, 0xb2, 0x19, 0xc7, 0xfd, 0x67, 0x84, 0xff,
|
||||
0xba, 0xc0, 0xff, 0x55, 0xfc, 0x6a, 0xc1, 0xbd, 0x68, 0xdc, 0x32, 0x2e, 0x22, 0xfc, 0x6b, 0x04,
|
||||
0x65, 0x45, 0x43, 0xe3, 0xb3, 0x23, 0x13, 0x23, 0x4b, 0x54, 0xef, 0x67, 0x30, 0xcb, 0x4b, 0x80,
|
||||
0x79, 0xaa, 0xf0, 0x28, 0x95, 0xf6, 0x79, 0x40, 0xbf, 0x87, 0x00, 0x27, 0x8f, 0xa6, 0xe4, 0x19,
|
||||
0x85, 0xcf, 0x64, 0x4c, 0x8d, 0x7c, 0x65, 0xd7, 0xce, 0x8e, 0x1d, 0x97, 0x3d, 0x4a, 0x57, 0x0a,
|
||||
0x8f, 0x52, 0x96, 0xd8, 0x7f, 0x1b, 0x41, 0xf5, 0x16, 0x4d, 0xee, 0xec, 0x05, 0xbe, 0xcc, 0xf2,
|
||||
0xeb, 0xb5, 0xe5, 0xf1, 0x03, 0x25, 0xa2, 0x0b, 0x02, 0xd1, 0x19, 0x5c, 0xec, 0x2a, 0x05, 0xe0,
|
||||
0x03, 0x04, 0x07, 0xee, 0xeb, 0x21, 0x8a, 0x2f, 0x8c, 0xb3, 0x94, 0xa9, 0xe4, 0x93, 0xe3, 0xfa,
|
||||
0xa2, 0xc0, 0xb5, 0x6a, 0x4e, 0x84, 0x6b, 0x4d, 0x92, 0xd8, 0xbf, 0x40, 0xf0, 0x82, 0xfe, 0xc8,
|
||||
0x91, 0x14, 0xe4, 0xff, 0xeb, 0xb7, 0x02, 0x26, 0xd3, 0xbc, 0x2c, 0xf0, 0xd5, 0xf1, 0x85, 0x49,
|
||||
0xf0, 0x35, 0x24, 0x2f, 0x89, 0xdf, 0x47, 0x70, 0x44, 0x90, 0xc0, 0xba, 0xe2, 0x81, 0x23, 0x66,
|
||||
0x14, 0x65, 0x3c, 0xc1, 0x11, 0x23, 0xeb, 0x8f, 0xb9, 0x2b, 0x50, 0x6b, 0x8a, 0xe0, 0xfd, 0x19,
|
||||
0x82, 0x83, 0xea, 0x50, 0x93, 0xbb, 0xbb, 0x3a, 0xce, 0x71, 0xbb, 0x3d, 0x04, 0x65, 0xb8, 0xad,
|
||||
0x4c, 0x16, 0x6e, 0x1f, 0x23, 0x98, 0x93, 0x04, 0x6c, 0xc1, 0x55, 0x41, 0x63, 0x68, 0x6b, 0x47,
|
||||
0x33, 0xa3, 0x14, 0xb3, 0x67, 0x7e, 0x57, 0x98, 0x7d, 0x88, 0x1b, 0x45, 0x66, 0x7d, 0xe6, 0x84,
|
||||
0x8d, 0x27, 0x92, 0x56, 0x7b, 0xda, 0x68, 0xb3, 0x56, 0xf8, 0x86, 0x89, 0x0b, 0x0f, 0x44, 0x3e,
|
||||
0xe6, 0x22, 0xba, 0x76, 0xf3, 0x4f, 0xcf, 0x4e, 0xa0, 0xbf, 0x3e, 0x3b, 0x81, 0xfe, 0xf5, 0xec,
|
||||
0x04, 0x7a, 0xe3, 0xca, 0x64, 0x7f, 0x3c, 0xb3, 0xdb, 0x2e, 0xf5, 0x22, 0x5d, 0xed, 0xff, 0x02,
|
||||
0x00, 0x00, 0xff, 0xff, 0xa8, 0x3a, 0x7a, 0xdf, 0x5e, 0x27, 0x00, 0x00,
|
||||
0x6e, 0x08, 0x89, 0x0b, 0x5c, 0x10, 0x48, 0x1c, 0x10, 0x1f, 0x17, 0x4e, 0xc8, 0xe2, 0xc6, 0x85,
|
||||
0x03, 0x7f, 0x00, 0xaa, 0xea, 0xaa, 0xee, 0xea, 0x99, 0x9e, 0x9e, 0x59, 0x76, 0xa3, 0xf8, 0x56,
|
||||
0xaf, 0xba, 0xea, 0xbd, 0x5f, 0xbd, 0x7a, 0xf5, 0x5e, 0xd5, 0x6f, 0x06, 0x4e, 0x85, 0x34, 0xe8,
|
||||
0xd1, 0xa0, 0x41, 0x7c, 0xbf, 0xed, 0xda, 0x24, 0x72, 0x99, 0xa7, 0xb7, 0xeb, 0x7e, 0xc0, 0x22,
|
||||
0x86, 0xab, 0x5a, 0x57, 0x6d, 0xb1, 0xc5, 0x58, 0xab, 0x4d, 0x1b, 0xc4, 0x77, 0x1b, 0xc4, 0xf3,
|
||||
0x58, 0x24, 0xba, 0xc3, 0x78, 0x68, 0xcd, 0xdc, 0xb9, 0x12, 0xd6, 0x5d, 0x26, 0xbe, 0xda, 0x2c,
|
||||
0xa0, 0x8d, 0xde, 0xa5, 0x46, 0x8b, 0x7a, 0x34, 0x20, 0x11, 0x75, 0xe4, 0x98, 0xcb, 0xe9, 0x98,
|
||||
0x0e, 0xb1, 0xb7, 0x5d, 0x8f, 0x06, 0xfd, 0x86, 0xbf, 0xd3, 0xe2, 0x1d, 0x61, 0xa3, 0x43, 0x23,
|
||||
0x92, 0x37, 0x6b, 0xbd, 0xe5, 0x46, 0xdb, 0xdd, 0x37, 0xeb, 0x36, 0xeb, 0x34, 0x48, 0xd0, 0x62,
|
||||
0x7e, 0xc0, 0xbe, 0x27, 0x1a, 0xab, 0xb6, 0xd3, 0xe8, 0x35, 0x53, 0x05, 0xfa, 0x5a, 0x7a, 0x97,
|
||||
0x48, 0xdb, 0xdf, 0x26, 0xc3, 0xda, 0x6e, 0x8c, 0xd1, 0x16, 0x50, 0x9f, 0x49, 0xdf, 0x88, 0xa6,
|
||||
0x1b, 0xb1, 0xa0, 0xaf, 0x35, 0x63, 0x35, 0xe6, 0x7f, 0x11, 0x1c, 0xbe, 0x9a, 0xda, 0xfb, 0x46,
|
||||
0x97, 0x06, 0x7d, 0x8c, 0x61, 0xda, 0x23, 0x1d, 0x6a, 0xa0, 0x25, 0xb4, 0x5c, 0xb1, 0x44, 0x1b,
|
||||
0x1b, 0x30, 0x17, 0xd0, 0xad, 0x80, 0x86, 0xdb, 0x46, 0x49, 0x74, 0x2b, 0x11, 0xd7, 0xa0, 0xcc,
|
||||
0x8d, 0x53, 0x3b, 0x0a, 0x8d, 0xa9, 0xa5, 0xa9, 0xe5, 0x8a, 0x95, 0xc8, 0x78, 0x19, 0x0e, 0x05,
|
||||
0x34, 0x64, 0xdd, 0xc0, 0xa6, 0xdf, 0xa4, 0x41, 0xe8, 0x32, 0xcf, 0x98, 0x16, 0xb3, 0x07, 0xbb,
|
||||
0xb9, 0x96, 0x90, 0xb6, 0xa9, 0x1d, 0xb1, 0xc0, 0x98, 0x11, 0x43, 0x12, 0x99, 0xe3, 0xe1, 0xc0,
|
||||
0x8d, 0xd9, 0x18, 0x0f, 0x6f, 0x63, 0x13, 0xe6, 0x89, 0xef, 0xdf, 0x23, 0x1d, 0x1a, 0xfa, 0xc4,
|
||||
0xa6, 0xc6, 0x9c, 0xf8, 0x96, 0xe9, 0xe3, 0x98, 0x25, 0x12, 0xa3, 0x2c, 0x80, 0x29, 0xd1, 0xbc,
|
||||
0x0e, 0x95, 0x7b, 0xcc, 0xa1, 0xa3, 0x97, 0x3b, 0xa8, 0xbe, 0x34, 0xac, 0xde, 0xdc, 0x81, 0xa3,
|
||||
0x16, 0xed, 0xb9, 0x1c, 0xfe, 0x5d, 0x1a, 0x11, 0x87, 0x44, 0x64, 0x50, 0x61, 0x29, 0x51, 0x58,
|
||||
0x83, 0x72, 0x20, 0x07, 0x1b, 0x25, 0xd1, 0x9f, 0xc8, 0x43, 0xc6, 0xa6, 0x72, 0x8c, 0xfd, 0x09,
|
||||
0xc1, 0x09, 0x6d, 0xa3, 0x2c, 0xe9, 0xbe, 0x1b, 0x3d, 0xea, 0x45, 0xe1, 0x68, 0xb3, 0x17, 0xe0,
|
||||
0x88, 0xf2, 0xf4, 0xe0, 0x62, 0x86, 0x3f, 0x70, 0x20, 0x7a, 0xa7, 0x02, 0xa2, 0xf7, 0xe1, 0x25,
|
||||
0xa8, 0x2a, 0xf9, 0xe1, 0x9d, 0xd7, 0xe4, 0x76, 0xea, 0x5d, 0x43, 0xcb, 0x99, 0xc9, 0x59, 0x8e,
|
||||
0x07, 0x86, 0xb6, 0x9a, 0xbb, 0xc4, 0x73, 0xb7, 0x68, 0x18, 0x4d, 0xea, 0x3e, 0xb4, 0x6b, 0xf7,
|
||||
0xbd, 0x0c, 0x95, 0x9b, 0x6e, 0x9b, 0x5e, 0xdf, 0xee, 0x7a, 0x3b, 0xf8, 0x45, 0x98, 0xb1, 0x79,
|
||||
0x43, 0x58, 0x98, 0xb7, 0x62, 0xc1, 0x7c, 0x0c, 0x2f, 0x8f, 0x82, 0xb4, 0xe9, 0x46, 0xdb, 0x7c,
|
||||
0x7a, 0x38, 0x0a, 0x9b, 0xbd, 0x4d, 0xed, 0x9d, 0xb0, 0xdb, 0x51, 0x5b, 0xab, 0xe4, 0x89, 0xb0,
|
||||
0xfd, 0x02, 0xc1, 0xf2, 0x58, 0xcb, 0x9b, 0x01, 0xf1, 0x7d, 0x1a, 0xe0, 0x9b, 0x30, 0xf3, 0x88,
|
||||
0x7f, 0x10, 0xd1, 0x5a, 0x6d, 0xd6, 0xeb, 0x7a, 0xb6, 0x1b, 0xab, 0xe5, 0xf6, 0x67, 0xac, 0x78,
|
||||
0x3a, 0xae, 0x2b, 0x1f, 0x94, 0x84, 0x9e, 0x85, 0x8c, 0x9e, 0xc4, 0x55, 0x7c, 0xbc, 0x18, 0x76,
|
||||
0x6d, 0x16, 0xa6, 0x7d, 0x12, 0x44, 0xe6, 0x51, 0x78, 0x21, 0x1b, 0x86, 0x3e, 0xf3, 0x42, 0x6a,
|
||||
0xfe, 0x06, 0x65, 0x36, 0xf4, 0x7a, 0x40, 0x49, 0x44, 0x2d, 0xfa, 0xa8, 0x4b, 0xc3, 0x08, 0xef,
|
||||
0x80, 0x9e, 0x80, 0x85, 0xef, 0xaa, 0xcd, 0x3b, 0xf5, 0x34, 0x83, 0xd5, 0x55, 0x06, 0x13, 0x8d,
|
||||
0xef, 0xd8, 0x4e, 0xbd, 0xd7, 0xac, 0xfb, 0x3b, 0xad, 0x3a, 0xcf, 0x87, 0x19, 0x64, 0x2a, 0x1f,
|
||||
0xea, 0x4b, 0xb5, 0x74, 0xed, 0x78, 0x01, 0x66, 0xbb, 0x7e, 0x48, 0x83, 0x48, 0xac, 0xac, 0x6c,
|
||||
0x49, 0x89, 0xef, 0x52, 0x8f, 0xb4, 0x5d, 0x87, 0x44, 0xf1, 0x2e, 0x94, 0xad, 0x44, 0x36, 0x3f,
|
||||
0xca, 0xa2, 0x7f, 0xe8, 0x3b, 0x9f, 0x16, 0x7a, 0x1d, 0x65, 0x69, 0x00, 0xe5, 0xfb, 0x59, 0x94,
|
||||
0xaf, 0xd1, 0x36, 0x4d, 0x51, 0xe6, 0x05, 0xa6, 0x01, 0x73, 0x36, 0x09, 0x6d, 0xe2, 0x28, 0x5d,
|
||||
0x4a, 0xe4, 0x69, 0xc1, 0x0f, 0x98, 0x4f, 0x5a, 0x42, 0xd3, 0x7d, 0xd6, 0x76, 0xed, 0xbe, 0x8c,
|
||||
0xcd, 0xe1, 0x0f, 0x43, 0x41, 0x3c, 0x9d, 0x13, 0xc4, 0x27, 0xa1, 0xba, 0xd1, 0xf7, 0xec, 0xd7,
|
||||
0x7d, 0x51, 0x4c, 0xf9, 0x11, 0x73, 0x23, 0xda, 0x09, 0x0d, 0x24, 0x12, 0x6f, 0x2c, 0x98, 0x1f,
|
||||
0xcc, 0xc0, 0x82, 0xb6, 0x02, 0x3e, 0xa1, 0x08, 0x7f, 0xd1, 0xa1, 0x5f, 0x80, 0x59, 0x27, 0xe8,
|
||||
0x5b, 0x5d, 0x4f, 0x6e, 0xa6, 0x94, 0xb8, 0x61, 0x3f, 0xe8, 0x7a, 0x31, 0xc8, 0xb2, 0x15, 0x0b,
|
||||
0x78, 0x0b, 0xca, 0x61, 0xc4, 0xcb, 0x67, 0xab, 0x2f, 0xd2, 0x51, 0xb5, 0xf9, 0xb5, 0xbd, 0x6d,
|
||||
0x20, 0x87, 0xbe, 0x21, 0x35, 0x5a, 0x89, 0x6e, 0xfc, 0x08, 0x2a, 0x2a, 0x13, 0x86, 0xc6, 0xdc,
|
||||
0xd2, 0xd4, 0x72, 0xb5, 0xb9, 0xb1, 0x77, 0x43, 0xaf, 0xfb, 0xbc, 0xf4, 0x6b, 0x59, 0xdf, 0x4a,
|
||||
0xad, 0xe0, 0x45, 0xa8, 0x74, 0xe4, 0x59, 0x0f, 0x65, 0x99, 0x4b, 0x3b, 0xf0, 0xb7, 0x60, 0xc6,
|
||||
0xf5, 0xb6, 0x58, 0x68, 0x54, 0x04, 0x98, 0x6b, 0x7b, 0x03, 0x73, 0xc7, 0xdb, 0x62, 0x56, 0xac,
|
||||
0x10, 0x3f, 0x82, 0x03, 0x01, 0x8d, 0x82, 0xbe, 0xf2, 0x82, 0x01, 0xc2, 0xaf, 0x5f, 0xdf, 0x9b,
|
||||
0x05, 0x4b, 0x57, 0x69, 0x65, 0x2d, 0xe0, 0x35, 0xa8, 0x86, 0x69, 0x8c, 0x19, 0x55, 0x61, 0xd0,
|
||||
0xc8, 0x28, 0xd2, 0x62, 0xd0, 0xd2, 0x07, 0x0f, 0xc5, 0xf0, 0x7c, 0x4e, 0x0c, 0xff, 0x1d, 0xc1,
|
||||
0xe2, 0x50, 0x1a, 0xd8, 0xf0, 0x69, 0x61, 0x90, 0x12, 0x98, 0x0e, 0x7d, 0x6a, 0x8b, 0xcc, 0x5f,
|
||||
0x6d, 0xde, 0xdd, 0xb7, 0xbc, 0x20, 0xec, 0x0a, 0xd5, 0x45, 0xa9, 0x6b, 0xa2, 0xb3, 0xf9, 0x43,
|
||||
0x04, 0x9f, 0xd5, 0x34, 0xdf, 0x27, 0x91, 0xbd, 0x5d, 0xb4, 0x24, 0x7e, 0x86, 0xf8, 0x18, 0x59,
|
||||
0xcd, 0x62, 0x81, 0x07, 0x9a, 0x68, 0x3c, 0xe8, 0xfb, 0x1c, 0x06, 0xff, 0x92, 0x76, 0x4c, 0x54,
|
||||
0xf4, 0xdf, 0x41, 0x50, 0xd3, 0x33, 0x1f, 0x6b, 0xb7, 0xdf, 0x24, 0xf6, 0x4e, 0x11, 0x94, 0x83,
|
||||
0x50, 0x72, 0x1d, 0x81, 0x63, 0xca, 0x2a, 0xb9, 0xce, 0x2e, 0x8f, 0xfd, 0x20, 0xa8, 0xd9, 0x1c,
|
||||
0x50, 0xff, 0x18, 0x00, 0xa5, 0x8e, 0x58, 0x01, 0xa8, 0x45, 0xa8, 0x78, 0x03, 0x97, 0xa9, 0xb4,
|
||||
0x23, 0xe7, 0x12, 0x55, 0x1a, 0xba, 0x44, 0x19, 0x30, 0xd7, 0x4b, 0xee, 0xc3, 0xfc, 0xb3, 0x12,
|
||||
0xf9, 0x42, 0x5a, 0x01, 0xeb, 0xfa, 0xd2, 0x81, 0xb1, 0xc0, 0x51, 0xec, 0xb8, 0x9e, 0x63, 0xcc,
|
||||
0xc6, 0x28, 0x78, 0x7b, 0x92, 0x1b, 0xb0, 0xf9, 0x6e, 0x09, 0x3e, 0x97, 0xb3, 0xb8, 0xb1, 0x11,
|
||||
0xf0, 0x7c, 0xac, 0x30, 0x89, 0xc3, 0xb9, 0x91, 0x71, 0x58, 0x1e, 0x17, 0x87, 0x95, 0x1c, 0xaf,
|
||||
0xbc, 0x5d, 0x82, 0xa5, 0x1c, 0xaf, 0x8c, 0x2f, 0xa8, 0xcf, 0x8d, 0x5b, 0xb6, 0x58, 0x20, 0x77,
|
||||
0xbc, 0x6c, 0xc5, 0x02, 0x3f, 0x19, 0x2c, 0xf0, 0xb7, 0x89, 0x67, 0x94, 0xe3, 0x93, 0x11, 0x4b,
|
||||
0x13, 0x39, 0xe4, 0x3f, 0x08, 0x0c, 0xe5, 0x85, 0xab, 0xb6, 0xf0, 0x49, 0xd7, 0x7b, 0xfe, 0x1d,
|
||||
0xb1, 0x00, 0xb3, 0x44, 0xa0, 0x95, 0x01, 0x22, 0xa5, 0xa1, 0x25, 0x97, 0xf3, 0x73, 0xe2, 0xb1,
|
||||
0xec, 0x92, 0xc3, 0x75, 0x37, 0x8c, 0xd4, 0x85, 0x16, 0x6f, 0xc1, 0x5c, 0xac, 0x2d, 0xbe, 0xc2,
|
||||
0x54, 0x9b, 0xeb, 0x7b, 0x2d, 0x6c, 0x19, 0xf7, 0x2a, 0xe5, 0xe6, 0x2b, 0x70, 0x2c, 0x37, 0xfb,
|
||||
0x48, 0x18, 0x35, 0x28, 0xab, 0x62, 0x2e, 0x37, 0x20, 0x91, 0xcd, 0x7f, 0x4f, 0x65, 0xd3, 0x3a,
|
||||
0x73, 0xd6, 0x59, 0xab, 0xe0, 0x2d, 0x58, 0xbc, 0x69, 0xfc, 0xb1, 0xcc, 0x1c, 0xed, 0xd9, 0xa7,
|
||||
0x44, 0x3e, 0xcf, 0x66, 0x5e, 0x44, 0x5c, 0x8f, 0x06, 0xb2, 0xbe, 0xa4, 0x1d, 0xdc, 0xd9, 0xa1,
|
||||
0xeb, 0xd9, 0x74, 0x83, 0xda, 0xcc, 0x73, 0x42, 0xb1, 0x6b, 0x53, 0x56, 0xa6, 0x0f, 0xdf, 0x86,
|
||||
0x8a, 0x90, 0x1f, 0xb8, 0x9d, 0x38, 0x09, 0x57, 0x9b, 0x2b, 0xf5, 0x98, 0x44, 0xa9, 0xeb, 0x24,
|
||||
0x4a, 0xea, 0xc3, 0x0e, 0x8d, 0x48, 0xbd, 0x77, 0xa9, 0xce, 0x67, 0x58, 0xe9, 0x64, 0x8e, 0x25,
|
||||
0x22, 0x6e, 0x7b, 0xdd, 0xf5, 0xc4, 0x05, 0x8b, 0x9b, 0x4a, 0x3b, 0x78, 0x40, 0x6c, 0xb1, 0x76,
|
||||
0x9b, 0x3d, 0x56, 0x67, 0x20, 0x96, 0xf8, 0xac, 0xae, 0x17, 0xb9, 0x6d, 0x61, 0x3f, 0x3e, 0x00,
|
||||
0x69, 0x87, 0x98, 0xe5, 0xb6, 0x23, 0x1a, 0x88, 0x2b, 0x4c, 0xc5, 0x92, 0x52, 0x12, 0x72, 0xd5,
|
||||
0x98, 0x17, 0x50, 0x67, 0x2f, 0x0e, 0xce, 0x79, 0x3d, 0x38, 0x07, 0x03, 0xfe, 0x40, 0xce, 0xbb,
|
||||
0x59, 0xd0, 0x24, 0xb4, 0xe7, 0xb2, 0x6e, 0x68, 0x1c, 0x8c, 0x8b, 0xb8, 0x92, 0x87, 0x02, 0xf6,
|
||||
0x50, 0x4e, 0xc0, 0xfe, 0x16, 0x41, 0x79, 0x9d, 0xb5, 0x6e, 0x78, 0x51, 0xd0, 0x17, 0x37, 0x7b,
|
||||
0xe6, 0x45, 0xd4, 0x53, 0x51, 0xa1, 0x44, 0xee, 0xea, 0xc8, 0xed, 0xd0, 0x8d, 0x88, 0x74, 0x7c,
|
||||
0x79, 0x27, 0xd9, 0x95, 0xab, 0x93, 0xc9, 0x7c, 0xf9, 0x6d, 0x12, 0x46, 0xe2, 0xf4, 0x96, 0x2d,
|
||||
0xd1, 0xe6, 0x40, 0x93, 0x01, 0x1b, 0x51, 0x20, 0x8f, 0x6e, 0xa6, 0x4f, 0x0f, 0xa4, 0x99, 0x18,
|
||||
0x9b, 0x14, 0xcd, 0x0d, 0x78, 0x29, 0xb9, 0xca, 0x3e, 0xa0, 0x41, 0xc7, 0xf5, 0x48, 0x71, 0xbe,
|
||||
0x9d, 0x84, 0x85, 0x79, 0x98, 0x39, 0x40, 0xfc, 0xfe, 0xb7, 0xe9, 0x7a, 0x0e, 0x7b, 0x5c, 0x70,
|
||||
0x10, 0x26, 0x51, 0xfb, 0x97, 0x2c, 0xdf, 0xa2, 0xe9, 0x4d, 0xce, 0xe6, 0x6d, 0x38, 0xc0, 0x4f,
|
||||
0x71, 0x8f, 0xca, 0x0f, 0x32, 0x51, 0x98, 0xa3, 0x9e, 0xe4, 0xa9, 0x0e, 0x2b, 0x3b, 0x11, 0xaf,
|
||||
0xc3, 0x21, 0x12, 0x86, 0x6e, 0xcb, 0xa3, 0x8e, 0xd2, 0x55, 0x9a, 0x58, 0xd7, 0xe0, 0xd4, 0xf8,
|
||||
0xd9, 0x27, 0x46, 0xc8, 0xbd, 0x53, 0xa2, 0xf9, 0x03, 0x04, 0x47, 0x73, 0x95, 0x24, 0xb1, 0x8e,
|
||||
0xb4, 0xf4, 0x5a, 0x83, 0x72, 0x68, 0x6f, 0x53, 0xa7, 0xdb, 0xa6, 0x8a, 0xd7, 0x50, 0x32, 0xff,
|
||||
0xe6, 0x74, 0xe3, 0x9d, 0x94, 0xe9, 0x3d, 0x91, 0xf1, 0x09, 0x80, 0x0e, 0xf1, 0xba, 0xa4, 0x2d,
|
||||
0x20, 0x4c, 0x0b, 0x08, 0x5a, 0x8f, 0xb9, 0x08, 0xb5, 0xbc, 0x30, 0x90, 0x4c, 0xc2, 0xdf, 0x10,
|
||||
0x1c, 0x54, 0x69, 0x50, 0xee, 0xe1, 0x32, 0x1c, 0xd2, 0xdc, 0x70, 0x2f, 0xdd, 0xce, 0xc1, 0xee,
|
||||
0x31, 0x29, 0x4e, 0xc5, 0xc2, 0x54, 0x96, 0xd7, 0xec, 0x65, 0x98, 0xc9, 0x89, 0xeb, 0x10, 0xda,
|
||||
0xd5, 0x4d, 0xec, 0xfb, 0x60, 0xdc, 0x25, 0x1e, 0x69, 0x51, 0x27, 0x59, 0x5c, 0x12, 0x48, 0xdf,
|
||||
0xd5, 0x1f, 0xcb, 0x7b, 0x7e, 0x9a, 0x26, 0xd7, 0x19, 0x77, 0x6b, 0x4b, 0x3e, 0xbc, 0x9b, 0x3f,
|
||||
0x5a, 0x02, 0xac, 0x6f, 0x3c, 0x0d, 0x7a, 0xae, 0x4d, 0xf1, 0x3b, 0x08, 0xa6, 0x79, 0xd5, 0xc3,
|
||||
0xc7, 0x47, 0xc5, 0x99, 0xd8, 0x80, 0xda, 0xfe, 0xbd, 0x6a, 0xb8, 0x35, 0x73, 0xf1, 0xad, 0xbf,
|
||||
0xfe, 0xeb, 0xdd, 0xd2, 0x02, 0x7e, 0x51, 0xb0, 0xec, 0xbd, 0x4b, 0x3a, 0xe3, 0x1d, 0xe2, 0x1f,
|
||||
0x23, 0xc0, 0xb2, 0x14, 0x6b, 0x14, 0x27, 0x3e, 0x3f, 0x0a, 0x62, 0x0e, 0x15, 0x5a, 0x3b, 0xae,
|
||||
0xa5, 0xbc, 0xba, 0xcd, 0x02, 0xca, 0x13, 0x9c, 0x18, 0x20, 0x00, 0xac, 0x08, 0x00, 0xa7, 0xb0,
|
||||
0x99, 0x07, 0xa0, 0xf1, 0x84, 0x07, 0xc6, 0xd3, 0x06, 0x8d, 0xed, 0x7e, 0x88, 0x60, 0x66, 0x53,
|
||||
0x5c, 0x3c, 0xc7, 0x38, 0x69, 0x63, 0xdf, 0x9c, 0x24, 0xcc, 0x09, 0xb4, 0xe6, 0x49, 0x81, 0xf4,
|
||||
0x38, 0x3e, 0xa6, 0x90, 0x86, 0x51, 0x40, 0x49, 0x27, 0x03, 0xf8, 0x22, 0xc2, 0x1f, 0x23, 0x98,
|
||||
0x8d, 0x39, 0x37, 0x7c, 0x7a, 0x14, 0xca, 0x0c, 0x27, 0x57, 0xdb, 0x3f, 0x02, 0xcb, 0x3c, 0x27,
|
||||
0x30, 0x9e, 0x34, 0x73, 0xb7, 0x73, 0x2d, 0x43, 0x6f, 0xbd, 0x87, 0x60, 0xea, 0x16, 0x1d, 0x1b,
|
||||
0x6f, 0xfb, 0x08, 0x6e, 0xc8, 0x81, 0x39, 0x5b, 0x8d, 0x3f, 0x42, 0xf0, 0xd2, 0x2d, 0x1a, 0xe5,
|
||||
0xe7, 0x7b, 0xbc, 0x3c, 0x3e, 0x09, 0xcb, 0xb0, 0x3b, 0x3f, 0xc1, 0xc8, 0x24, 0xd1, 0x35, 0x04,
|
||||
0xb2, 0x73, 0xf8, 0x6c, 0x51, 0x10, 0x86, 0x7d, 0xcf, 0x7e, 0x2c, 0x71, 0xfc, 0x11, 0xc1, 0xe1,
|
||||
0xc1, 0x1f, 0x1c, 0x70, 0xb6, 0x42, 0xe4, 0xfe, 0x1e, 0x51, 0xbb, 0xb7, 0xd7, 0x84, 0x92, 0x55,
|
||||
0x6a, 0x5e, 0x15, 0xc8, 0x5f, 0xc5, 0xaf, 0x14, 0x21, 0x57, 0x4c, 0x5d, 0xd8, 0x78, 0xa2, 0x9a,
|
||||
0x4f, 0xc5, 0x6f, 0x63, 0x02, 0xf6, 0x5b, 0x08, 0xe6, 0x6f, 0xd1, 0xe8, 0x6e, 0x42, 0x54, 0x9d,
|
||||
0x9e, 0x88, 0xc8, 0xae, 0x2d, 0xd6, 0xb5, 0x9f, 0xb0, 0xd4, 0xa7, 0xc4, 0xa5, 0xab, 0x02, 0xd8,
|
||||
0x59, 0x7c, 0xba, 0x08, 0x58, 0x4a, 0x8e, 0x7d, 0x88, 0xe0, 0xa8, 0x0e, 0x22, 0xa5, 0xf9, 0xbf,
|
||||
0xb0, 0x3b, 0x5a, 0x5d, 0x92, 0xf3, 0x63, 0xd0, 0x35, 0x05, 0xba, 0x0b, 0x66, 0xfe, 0x86, 0x77,
|
||||
0x86, 0x50, 0xac, 0xa1, 0x95, 0x65, 0x84, 0x7f, 0x87, 0x60, 0x36, 0x66, 0xa2, 0x46, 0xfb, 0x28,
|
||||
0x43, 0x58, 0xef, 0xe7, 0xe9, 0xb9, 0x21, 0x20, 0x7f, 0xa5, 0x76, 0x31, 0xdf, 0xa1, 0xfa, 0x7c,
|
||||
0xb5, 0xb5, 0x75, 0xe1, 0xe5, 0xec, 0xb1, 0xff, 0x15, 0x02, 0x48, 0xd9, 0x34, 0x7c, 0xae, 0x78,
|
||||
0x1d, 0x1a, 0xe3, 0x56, 0xdb, 0x5f, 0x3e, 0xcd, 0xac, 0x8b, 0xf5, 0x2c, 0xd7, 0x96, 0x0a, 0xcf,
|
||||
0x9c, 0x4f, 0xed, 0xb5, 0x98, 0x79, 0xfb, 0x39, 0x82, 0x19, 0x41, 0x96, 0xe0, 0x53, 0xa3, 0x30,
|
||||
0xeb, 0x5c, 0xca, 0x7e, 0xba, 0xfe, 0x8c, 0x80, 0xba, 0xd4, 0x2c, 0x4a, 0x5c, 0x6b, 0x68, 0x05,
|
||||
0xf7, 0x60, 0x36, 0x26, 0x2e, 0x46, 0x87, 0x47, 0x86, 0xd8, 0xa8, 0x2d, 0x15, 0x14, 0xd2, 0x38,
|
||||
0x50, 0x65, 0xce, 0x5c, 0x19, 0x97, 0x33, 0xa7, 0x79, 0x5a, 0xc3, 0x27, 0x8b, 0x92, 0xde, 0x27,
|
||||
0xe0, 0x98, 0xf3, 0x02, 0xdd, 0x69, 0x73, 0x69, 0x5c, 0xde, 0xe4, 0xde, 0xf9, 0x29, 0x82, 0xc3,
|
||||
0x83, 0xf7, 0x2e, 0x7c, 0x6c, 0x20, 0x67, 0xea, 0x97, 0xcd, 0x5a, 0xd6, 0x8b, 0xa3, 0xee, 0x6c,
|
||||
0xe6, 0x57, 0x05, 0x8a, 0x35, 0x7c, 0x65, 0xec, 0xc9, 0xb8, 0xa7, 0xb2, 0x0e, 0x57, 0xb4, 0x9a,
|
||||
0x12, 0xf7, 0xbf, 0x46, 0x30, 0xaf, 0xf4, 0x3e, 0x08, 0x28, 0x2d, 0x86, 0xb5, 0x7f, 0x07, 0x81,
|
||||
0xdb, 0x32, 0xbf, 0x24, 0xe0, 0x7f, 0x11, 0x5f, 0x9e, 0x10, 0xbe, 0x82, 0xbd, 0x1a, 0x71, 0xa4,
|
||||
0xbf, 0x47, 0x70, 0x64, 0x33, 0x8e, 0xfb, 0x4f, 0x09, 0xff, 0x75, 0x81, 0xff, 0xcb, 0xf8, 0xd5,
|
||||
0x82, 0x7b, 0xd1, 0xb8, 0x65, 0x5c, 0x44, 0xf8, 0x97, 0x08, 0xca, 0x8a, 0x86, 0xc6, 0x67, 0x47,
|
||||
0x1e, 0x8c, 0x2c, 0x51, 0xbd, 0x9f, 0xc1, 0x2c, 0x2f, 0x01, 0xe6, 0xa9, 0xc2, 0x52, 0x2a, 0xed,
|
||||
0xf3, 0x80, 0x7e, 0x0f, 0x01, 0x4e, 0x1e, 0x4d, 0xc9, 0x33, 0x0a, 0x9f, 0xc9, 0x98, 0x1a, 0xf9,
|
||||
0xca, 0xae, 0x9d, 0x1d, 0x3b, 0x2e, 0x5b, 0x4a, 0x57, 0x0a, 0x4b, 0x29, 0x4b, 0xec, 0xbf, 0x8d,
|
||||
0xa0, 0x7a, 0x8b, 0x26, 0x77, 0xf6, 0x02, 0x5f, 0x66, 0xf9, 0xf5, 0xda, 0xf2, 0xf8, 0x81, 0x12,
|
||||
0xd1, 0x05, 0x81, 0xe8, 0x0c, 0x2e, 0x76, 0x95, 0x02, 0xf0, 0x01, 0x82, 0x03, 0xf7, 0xf5, 0x10,
|
||||
0xc5, 0x17, 0xc6, 0x59, 0xca, 0x64, 0xf2, 0xc9, 0x71, 0x7d, 0x5e, 0xe0, 0x5a, 0x35, 0x27, 0xc2,
|
||||
0xb5, 0x26, 0x49, 0xec, 0x9f, 0x21, 0x78, 0x41, 0x7f, 0xe4, 0x48, 0x0a, 0xf2, 0xff, 0xf5, 0x5b,
|
||||
0x01, 0x93, 0x69, 0x5e, 0x16, 0xf8, 0xea, 0xf8, 0xc2, 0x24, 0xf8, 0x1a, 0x92, 0x97, 0xc4, 0xef,
|
||||
0x23, 0x38, 0x22, 0x48, 0x60, 0x5d, 0xf1, 0x40, 0x89, 0x19, 0x45, 0x19, 0x4f, 0x50, 0x62, 0x64,
|
||||
0xfe, 0x31, 0x77, 0x05, 0x6a, 0x4d, 0x11, 0xbc, 0x3f, 0x41, 0x70, 0x50, 0x15, 0x35, 0xb9, 0xbb,
|
||||
0xab, 0xe3, 0x1c, 0xb7, 0xdb, 0x22, 0x28, 0xc3, 0x6d, 0x65, 0xb2, 0x70, 0xfb, 0x18, 0xc1, 0x9c,
|
||||
0x24, 0x60, 0x0b, 0xae, 0x0a, 0x1a, 0x43, 0x5b, 0x3b, 0x9a, 0x19, 0xa5, 0x98, 0x3d, 0xf3, 0xdb,
|
||||
0xc2, 0xec, 0x43, 0xdc, 0x28, 0x32, 0xeb, 0x33, 0x27, 0x6c, 0x3c, 0x91, 0xb4, 0xda, 0xd3, 0x46,
|
||||
0x9b, 0xb5, 0xc2, 0x37, 0x4c, 0x5c, 0x58, 0x10, 0xf9, 0x98, 0x8b, 0xe8, 0xda, 0xcd, 0x3f, 0x3c,
|
||||
0x3b, 0x81, 0xfe, 0xfc, 0xec, 0x04, 0xfa, 0xe7, 0xb3, 0x13, 0xe8, 0x8d, 0x2b, 0x93, 0xfd, 0x25,
|
||||
0xcd, 0x6e, 0xbb, 0xd4, 0x8b, 0x74, 0xb5, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xbd, 0x18, 0xcd,
|
||||
0x5d, 0x78, 0x27, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -3741,6 +3751,15 @@ func (m *ApplicationQuery) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.Project) > 0 {
|
||||
for iNdEx := len(m.Project) - 1; iNdEx >= 0; iNdEx-- {
|
||||
i -= len(m.Project[iNdEx])
|
||||
copy(dAtA[i:], m.Project[iNdEx])
|
||||
i = encodeVarintApplication(dAtA, i, uint64(len(m.Project[iNdEx])))
|
||||
i--
|
||||
dAtA[i] = 0x42
|
||||
}
|
||||
}
|
||||
if m.AppNamespace != nil {
|
||||
i -= len(*m.AppNamespace)
|
||||
copy(dAtA[i:], *m.AppNamespace)
|
||||
@@ -5837,6 +5856,12 @@ func (m *ApplicationQuery) Size() (n int) {
|
||||
l = len(*m.AppNamespace)
|
||||
n += 1 + l + sovApplication(uint64(l))
|
||||
}
|
||||
if len(m.Project) > 0 {
|
||||
for _, s := range m.Project {
|
||||
l = len(s)
|
||||
n += 1 + l + sovApplication(uint64(l))
|
||||
}
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
@@ -7004,6 +7029,38 @@ func (m *ApplicationQuery) Unmarshal(dAtA []byte) error {
|
||||
s := string(dAtA[iNdEx:postIndex])
|
||||
m.AppNamespace = &s
|
||||
iNdEx = postIndex
|
||||
case 8:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowApplication
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthApplication
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthApplication
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Project = append(m.Project, string(dAtA[iNdEx:postIndex]))
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipApplication(dAtA[iNdEx:])
|
||||
|
||||
@@ -19,7 +19,7 @@ const (
|
||||
AppProjectFullName string = AppProjectPlural + "." + Group
|
||||
|
||||
// ApplicationSet constants
|
||||
ApplicationSetKind string = "Applicationset"
|
||||
ApplicationSetKind string = "ApplicationSet"
|
||||
ApplicationSetSingular string = "applicationset"
|
||||
ApplicationSetShortName string = "appset"
|
||||
ApplicationSetPlural string = "applicationsets"
|
||||
|
||||
@@ -541,7 +541,7 @@ const (
|
||||
// prefix "Info" means informational condition
|
||||
type ApplicationSetConditionType string
|
||||
|
||||
//ErrorOccurred / ParametersGenerated / TemplateRendered / ResourcesUpToDate
|
||||
// ErrorOccurred / ParametersGenerated / TemplateRendered / ResourcesUpToDate
|
||||
const (
|
||||
ApplicationSetConditionErrorOccurred ApplicationSetConditionType = "ErrorOccurred"
|
||||
ApplicationSetConditionParametersGenerated ApplicationSetConditionType = "ParametersGenerated"
|
||||
|
||||
@@ -1246,7 +1246,7 @@ func TestGetAppDetailsKustomize(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "Kustomize", res.Type)
|
||||
assert.NotNil(t, res.Kustomize)
|
||||
assert.EqualValues(t, []string{"nginx:1.15.4", "k8s.gcr.io/nginx-slim:0.8"}, res.Kustomize.Images)
|
||||
assert.EqualValues(t, []string{"nginx:1.15.4", "registry.k8s.io/nginx-slim:0.8"}, res.Kustomize.Images)
|
||||
}
|
||||
|
||||
func TestGetHelmCharts(t *testing.T) {
|
||||
|
||||
@@ -25,7 +25,7 @@ spec:
|
||||
name: daemonset
|
||||
spec:
|
||||
containers:
|
||||
- image: k8s.gcr.io/nginx-slim:0.8
|
||||
- image: registry.k8s.io/nginx-slim:0.8
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: nginx
|
||||
resources: {}
|
||||
|
||||
@@ -23,7 +23,7 @@ spec:
|
||||
name: daemonset
|
||||
spec:
|
||||
containers:
|
||||
- image: k8s.gcr.io/nginx-slim:0.8
|
||||
- image: registry.k8s.io/nginx-slim:0.8
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: nginx
|
||||
resources: {}
|
||||
|
||||
@@ -26,7 +26,7 @@ spec:
|
||||
kubectl.kubernetes.io/restartedAt: "0001-01-01T00:00:00Z"
|
||||
spec:
|
||||
containers:
|
||||
- image: k8s.gcr.io/nginx-slim:0.8
|
||||
- image: registry.k8s.io/nginx-slim:0.8
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: nginx
|
||||
resources: {}
|
||||
|
||||
@@ -24,7 +24,7 @@ spec:
|
||||
app: statefulset
|
||||
spec:
|
||||
containers:
|
||||
- image: k8s.gcr.io/nginx-slim:0.8
|
||||
- image: registry.k8s.io/nginx-slim:0.8
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: nginx
|
||||
resources: {}
|
||||
|
||||
@@ -1,4 +1,55 @@
|
||||
health_status = {}
|
||||
-- Can't use standard lib, math.huge equivalent
|
||||
infinity = 2^1024-1
|
||||
|
||||
local function executor_range_api()
|
||||
min_executor_instances = 0
|
||||
max_executor_instances = infinity
|
||||
if obj.spec.dynamicAllocation.maxExecutors then
|
||||
max_executor_instances = obj.spec.dynamicAllocation.maxExecutors
|
||||
end
|
||||
if obj.spec.dynamicAllocation.minExecutors then
|
||||
min_executor_instances = obj.spec.dynamicAllocation.minExecutors
|
||||
end
|
||||
return min_executor_instances, max_executor_instances
|
||||
end
|
||||
|
||||
local function maybe_executor_range_spark_conf()
|
||||
min_executor_instances = 0
|
||||
max_executor_instances = infinity
|
||||
if obj.spec.sparkConf["spark.streaming.dynamicAllocation.enabled"] ~= nil and
|
||||
obj.spec.sparkConf["spark.streaming.dynamicAllocation.enabled"] == "true" then
|
||||
if(obj.spec.sparkConf["spark.streaming.dynamicAllocation.maxExecutors"] ~= nil) then
|
||||
max_executor_instances = tonumber(obj.spec.sparkConf["spark.streaming.dynamicAllocation.maxExecutors"])
|
||||
end
|
||||
if(obj.spec.sparkConf["spark.streaming.dynamicAllocation.minExecutors"] ~= nil) then
|
||||
min_executor_instances = tonumber(obj.spec.sparkConf["spark.streaming.dynamicAllocation.minExecutors"])
|
||||
end
|
||||
return min_executor_instances, max_executor_instances
|
||||
elseif obj.spec.sparkConf["spark.dynamicAllocation.enabled"] ~= nil and
|
||||
obj.spec.sparkConf["spark.dynamicAllocation.enabled"] == "true" then
|
||||
if(obj.spec.sparkConf["spark.dynamicAllocation.maxExecutors"] ~= nil) then
|
||||
max_executor_instances = tonumber(obj.spec.sparkConf["spark.dynamicAllocation.maxExecutors"])
|
||||
end
|
||||
if(obj.spec.sparkConf["spark.dynamicAllocation.minExecutors"] ~= nil) then
|
||||
min_executor_instances = tonumber(obj.spec.sparkConf["spark.dynamicAllocation.minExecutors"])
|
||||
end
|
||||
return min_executor_instances, max_executor_instances
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local function maybe_executor_range()
|
||||
if obj.spec["dynamicAllocation"] and obj.spec.dynamicAllocation.enabled then
|
||||
return executor_range_api()
|
||||
elseif obj.spec["sparkConf"] ~= nil then
|
||||
return maybe_executor_range_spark_conf()
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
if obj.status ~= nil then
|
||||
if obj.status.applicationState.state ~= nil then
|
||||
if obj.status.applicationState.state == "" then
|
||||
@@ -19,6 +70,13 @@ if obj.status ~= nil then
|
||||
health_status.status = "Healthy"
|
||||
health_status.message = "SparkApplication is Running"
|
||||
return health_status
|
||||
elseif maybe_executor_range() then
|
||||
min_executor_instances, max_executor_instances = maybe_executor_range()
|
||||
if count >= min_executor_instances and count <= max_executor_instances then
|
||||
health_status.status = "Healthy"
|
||||
health_status.message = "SparkApplication is Running"
|
||||
return health_status
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -72,4 +130,4 @@ if obj.status ~= nil then
|
||||
end
|
||||
health_status.status = "Progressing"
|
||||
health_status.message = "Waiting for Executor pods"
|
||||
return health_status
|
||||
return health_status
|
||||
|
||||
@@ -11,3 +11,15 @@ tests:
|
||||
status: Healthy
|
||||
message: "SparkApplication is Running"
|
||||
inputPath: testdata/healthy.yaml
|
||||
- healthStatus:
|
||||
status: Healthy
|
||||
message: "SparkApplication is Running"
|
||||
inputPath: testdata/healthy_dynamic_alloc.yaml
|
||||
- healthStatus:
|
||||
status: Healthy
|
||||
message: "SparkApplication is Running"
|
||||
inputPath: testdata/healthy_dynamic_alloc_dstream.yaml
|
||||
- healthStatus:
|
||||
status: Healthy
|
||||
message: "SparkApplication is Running"
|
||||
inputPath: testdata/healthy_dynamic_alloc_operator_api.yaml
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
apiVersion: sparkoperator.k8s.io/v1beta2
|
||||
kind: SparkApplication
|
||||
metadata:
|
||||
generation: 4
|
||||
labels:
|
||||
argocd.argoproj.io/instance: spark-job
|
||||
name: spark-job-app
|
||||
namespace: spark-cluster
|
||||
resourceVersion: "31812990"
|
||||
uid: bfee52b0-74ca-4465-8005-f6643097ed64
|
||||
spec:
|
||||
executor:
|
||||
instances: 4
|
||||
sparkConf:
|
||||
spark.dynamicAllocation.enabled: 'true'
|
||||
spark.dynamicAllocation.maxExecutors: '10'
|
||||
spark.dynamicAllocation.minExecutors: '2'
|
||||
status:
|
||||
applicationState:
|
||||
state: RUNNING
|
||||
driverInfo:
|
||||
podName: ingestion-datalake-news-app-driver
|
||||
webUIAddress: 172.20.207.161:4040
|
||||
webUIPort: 4040
|
||||
webUIServiceName: ingestion-datalake-news-app-ui-svc
|
||||
executionAttempts: 13
|
||||
executorState:
|
||||
ingestion-datalake-news-app-1591613851251-exec-1: RUNNING
|
||||
ingestion-datalake-news-app-1591613851251-exec-2: RUNNING
|
||||
ingestion-datalake-news-app-1591613851251-exec-4: RUNNING
|
||||
ingestion-datalake-news-app-1591613851251-exec-5: RUNNING
|
||||
ingestion-datalake-news-app-1591613851251-exec-6: RUNNING
|
||||
lastSubmissionAttemptTime: "2020-06-08T10:57:32Z"
|
||||
sparkApplicationId: spark-a5920b2a5aa04d22a737c60759b5bf82
|
||||
submissionAttempts: 1
|
||||
submissionID: 3e713ec8-9f6c-4e78-ac28-749797c846f0
|
||||
terminationTime: null
|
||||
@@ -0,0 +1,35 @@
|
||||
apiVersion: sparkoperator.k8s.io/v1beta2
|
||||
kind: SparkApplication
|
||||
metadata:
|
||||
generation: 4
|
||||
labels:
|
||||
argocd.argoproj.io/instance: spark-job
|
||||
name: spark-job-app
|
||||
namespace: spark-cluster
|
||||
resourceVersion: "31812990"
|
||||
uid: bfee52b0-74ca-4465-8005-f6643097ed64
|
||||
spec:
|
||||
executor:
|
||||
instances: 4
|
||||
sparkConf:
|
||||
spark.streaming.dynamicAllocation.enabled: 'true'
|
||||
spark.streaming.dynamicAllocation.maxExecutors: '10'
|
||||
spark.streaming.dynamicAllocation.minExecutors: '2'
|
||||
status:
|
||||
applicationState:
|
||||
state: RUNNING
|
||||
driverInfo:
|
||||
podName: ingestion-datalake-news-app-driver
|
||||
webUIAddress: 172.20.207.161:4040
|
||||
webUIPort: 4040
|
||||
webUIServiceName: ingestion-datalake-news-app-ui-svc
|
||||
executionAttempts: 13
|
||||
executorState:
|
||||
ingestion-datalake-news-app-1591613851251-exec-1: RUNNING
|
||||
ingestion-datalake-news-app-1591613851251-exec-4: RUNNING
|
||||
ingestion-datalake-news-app-1591613851251-exec-6: RUNNING
|
||||
lastSubmissionAttemptTime: "2020-06-08T10:57:32Z"
|
||||
sparkApplicationId: spark-a5920b2a5aa04d22a737c60759b5bf82
|
||||
submissionAttempts: 1
|
||||
submissionID: 3e713ec8-9f6c-4e78-ac28-749797c846f0
|
||||
terminationTime: null
|
||||
@@ -0,0 +1,38 @@
|
||||
apiVersion: sparkoperator.k8s.io/v1beta2
|
||||
kind: SparkApplication
|
||||
metadata:
|
||||
generation: 4
|
||||
labels:
|
||||
argocd.argoproj.io/instance: spark-job
|
||||
name: spark-job-app
|
||||
namespace: spark-cluster
|
||||
resourceVersion: "31812990"
|
||||
uid: bfee52b0-74ca-4465-8005-f6643097ed64
|
||||
spec:
|
||||
executor:
|
||||
instances: 4
|
||||
dynamicAllocation:
|
||||
enabled: true
|
||||
initialExecutors: 2
|
||||
minExecutors: 2
|
||||
maxExecutors: 10
|
||||
status:
|
||||
applicationState:
|
||||
state: RUNNING
|
||||
driverInfo:
|
||||
podName: ingestion-datalake-news-app-driver
|
||||
webUIAddress: 172.20.207.161:4040
|
||||
webUIPort: 4040
|
||||
webUIServiceName: ingestion-datalake-news-app-ui-svc
|
||||
executionAttempts: 13
|
||||
executorState:
|
||||
ingestion-datalake-news-app-1591613851251-exec-1: RUNNING
|
||||
ingestion-datalake-news-app-1591613851251-exec-2: RUNNING
|
||||
ingestion-datalake-news-app-1591613851251-exec-4: RUNNING
|
||||
ingestion-datalake-news-app-1591613851251-exec-5: RUNNING
|
||||
ingestion-datalake-news-app-1591613851251-exec-6: RUNNING
|
||||
lastSubmissionAttemptTime: "2020-06-08T10:57:32Z"
|
||||
sparkApplicationId: spark-a5920b2a5aa04d22a737c60759b5bf82
|
||||
submissionAttempts: 1
|
||||
submissionID: 3e713ec8-9f6c-4e78-ac28-749797c846f0
|
||||
terminationTime: null
|
||||
@@ -148,7 +148,7 @@ func (s *Server) List(ctx context.Context, q *application.ApplicationQuery) (*ap
|
||||
}
|
||||
newItems := make([]appv1.Application, 0)
|
||||
for _, a := range apps {
|
||||
// Skip any application that is neither in the conrol plane's namespace
|
||||
// Skip any application that is neither in the control plane's namespace
|
||||
// nor in the list of enabled namespaces.
|
||||
if a.Namespace != s.ns && !glob.MatchStringInList(s.enabledNamespaces, a.Namespace, false) {
|
||||
continue
|
||||
@@ -165,8 +165,8 @@ func (s *Server) List(ctx context.Context, q *application.ApplicationQuery) (*ap
|
||||
}
|
||||
}
|
||||
|
||||
// Filter applications by name
|
||||
newItems = argoutil.FilterByProjects(newItems, q.Projects)
|
||||
// Filter applications by projects
|
||||
newItems = argoutil.FilterByProjects(newItems, getProjectsFromApplicationQuery(*q))
|
||||
|
||||
// Filter applications by source repo URL
|
||||
newItems = argoutil.FilterByRepo(newItems, q.GetRepo())
|
||||
@@ -1008,8 +1008,8 @@ func (s *Server) Watch(q *application.ApplicationQuery, ws application.Applicati
|
||||
logCtx = logCtx.WithField("application", *q.Name)
|
||||
}
|
||||
projects := map[string]bool{}
|
||||
for i := range q.Projects {
|
||||
projects[q.Projects[i]] = true
|
||||
for _, project := range getProjectsFromApplicationQuery(*q) {
|
||||
projects[project] = true
|
||||
}
|
||||
claims := ws.Context().Value("claims")
|
||||
selector, err := labels.Parse(q.GetSelector())
|
||||
@@ -2292,3 +2292,12 @@ func (s *Server) appNamespaceOrDefault(appNs string) string {
|
||||
func (s *Server) isNamespaceEnabled(namespace string) bool {
|
||||
return security.IsNamespaceEnabled(namespace, s.ns, s.enabledNamespaces)
|
||||
}
|
||||
|
||||
// getProjectFromApplicationQuery gets the project names from a query. If the legacy "project" field was specified, use
|
||||
// that. Otherwise, use the newer "projects" field.
|
||||
func getProjectsFromApplicationQuery(q application.ApplicationQuery) []string {
|
||||
if q.Project != nil {
|
||||
return q.Project
|
||||
}
|
||||
return q.Projects
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ message ApplicationQuery {
|
||||
optional string repo = 6;
|
||||
// the application's namespace
|
||||
optional string appNamespace = 7;
|
||||
// the project names to restrict returned list applications (legacy name for backwards-compatibility)
|
||||
repeated string project = 8;
|
||||
}
|
||||
|
||||
message NodeQuery {
|
||||
|
||||
@@ -401,6 +401,57 @@ func testListAppsWithLabels(t *testing.T, appQuery application.ApplicationQuery,
|
||||
}
|
||||
}
|
||||
|
||||
func TestListAppWithProjects(t *testing.T) {
|
||||
appServer := newTestAppServer(newTestApp(func(app *appsv1.Application) {
|
||||
app.Name = "App1"
|
||||
app.Spec.Project = "test-project1"
|
||||
}), newTestApp(func(app *appsv1.Application) {
|
||||
app.Name = "App2"
|
||||
app.Spec.Project = "test-project2"
|
||||
}), newTestApp(func(app *appsv1.Application) {
|
||||
app.Name = "App3"
|
||||
app.Spec.Project = "test-project3"
|
||||
}))
|
||||
|
||||
t.Run("List all apps", func(t *testing.T) {
|
||||
appQuery := application.ApplicationQuery{}
|
||||
appList, err := appServer.List(context.Background(), &appQuery)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, appList.Items, 3)
|
||||
})
|
||||
|
||||
t.Run("List apps with projects filter set", func(t *testing.T) {
|
||||
appQuery := application.ApplicationQuery{Projects: []string{"test-project1"}}
|
||||
appList, err := appServer.List(context.Background(), &appQuery)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, appList.Items, 1)
|
||||
for _, app := range appList.Items {
|
||||
assert.Equal(t, "test-project1", app.Spec.Project)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("List apps with project filter set (legacy field)", func(t *testing.T) {
|
||||
appQuery := application.ApplicationQuery{Project: []string{"test-project1"}}
|
||||
appList, err := appServer.List(context.Background(), &appQuery)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, appList.Items, 1)
|
||||
for _, app := range appList.Items {
|
||||
assert.Equal(t, "test-project1", app.Spec.Project)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("List apps with both projects and project filter set", func(t *testing.T) {
|
||||
// If the older field is present, we should use it instead of the newer field.
|
||||
appQuery := application.ApplicationQuery{Project: []string{"test-project1"}, Projects: []string{"test-project2"}}
|
||||
appList, err := appServer.List(context.Background(), &appQuery)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, appList.Items, 1)
|
||||
for _, app := range appList.Items {
|
||||
assert.Equal(t, "test-project1", app.Spec.Project)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestListApps(t *testing.T) {
|
||||
appServer := newTestAppServer(newTestApp(func(app *appsv1.Application) {
|
||||
app.Name = "bcd"
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/util/rbac"
|
||||
"github.com/argoproj/argo-cd/v2/util/security"
|
||||
sessionmgr "github.com/argoproj/argo-cd/v2/util/session"
|
||||
"github.com/argoproj/argo-cd/v2/util/settings"
|
||||
)
|
||||
|
||||
type terminalHandler struct {
|
||||
@@ -95,6 +96,26 @@ func isValidContainerName(name string) bool {
|
||||
return len(validationErrors) == 0
|
||||
}
|
||||
|
||||
type GetSettingsFunc func() (*settings.ArgoCDSettings, error)
|
||||
|
||||
// WithFeatureFlagMiddleware is an HTTP middleware to verify if the terminal
|
||||
// feature is enabled before invoking the main handler
|
||||
func (s *terminalHandler) WithFeatureFlagMiddleware(getSettings GetSettingsFunc) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
argocdSettings, err := getSettings()
|
||||
if err != nil {
|
||||
log.Errorf("error executing WithFeatureFlagMiddleware: error getting settings: %s", err)
|
||||
http.Error(w, "Failed to get settings", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if !argocdSettings.ExecEnabled {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
s.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *terminalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
q := r.URL.Query()
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"context"
|
||||
|
||||
"github.com/argoproj/gitops-engine/pkg/utils/kube"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
@@ -14,6 +13,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster"
|
||||
appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
servercache "github.com/argoproj/argo-cd/v2/server/cache"
|
||||
@@ -135,7 +135,7 @@ func (s *Server) Get(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Clust
|
||||
func (s *Server) getClusterWith403IfNotExist(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Cluster, error) {
|
||||
repo, err := s.getCluster(ctx, q)
|
||||
if err != nil || repo == nil {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
return nil, common.PermissionDeniedAPIError
|
||||
}
|
||||
return repo, nil
|
||||
}
|
||||
@@ -221,14 +221,14 @@ func (s *Server) Update(ctx context.Context, q *cluster.ClusterUpdateRequest) (*
|
||||
}
|
||||
|
||||
// verify that user can do update inside project where cluster is located
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, createRBACObject(c.Project, q.Cluster.Server)); err != nil {
|
||||
return nil, err
|
||||
if !s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, createRBACObject(c.Project, c.Server)) {
|
||||
return nil, common.PermissionDeniedAPIError
|
||||
}
|
||||
|
||||
if len(q.UpdatedFields) == 0 || sets.NewString(q.UpdatedFields...).Has("project") {
|
||||
// verify that user can do update inside project where cluster will be located
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, createRBACObject(q.Cluster.Project, q.Cluster.Server)); err != nil {
|
||||
return nil, err
|
||||
if !s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, createRBACObject(q.Cluster.Project, c.Server)) {
|
||||
return nil, common.PermissionDeniedAPIError
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package cluster
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -49,6 +50,117 @@ func newNoopEnforcer() *rbac.Enforcer {
|
||||
return enf
|
||||
}
|
||||
|
||||
func TestUpdateCluster_RejectInvalidParams(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
request clusterapi.ClusterUpdateRequest
|
||||
}{
|
||||
{
|
||||
name: "allowed cluster URL in body, disallowed cluster URL in query",
|
||||
request: clusterapi.ClusterUpdateRequest{Cluster: &v1alpha1.Cluster{Name: "", Server: "https://127.0.0.1", Project: "", ClusterResources: true}, Id: &clusterapi.ClusterID{Type: "", Value: "https://127.0.0.2"}, UpdatedFields: []string{"clusterResources", "project"}},
|
||||
},
|
||||
{
|
||||
name: "allowed cluster URL in body, disallowed cluster name in query",
|
||||
request: clusterapi.ClusterUpdateRequest{Cluster: &v1alpha1.Cluster{Name: "", Server: "https://127.0.0.1", Project: "", ClusterResources: true}, Id: &clusterapi.ClusterID{Type: "name", Value: "disallowed-unscoped"}, UpdatedFields: []string{"clusterResources", "project"}},
|
||||
},
|
||||
{
|
||||
name: "allowed cluster URL in body, disallowed cluster name in query, changing unscoped to scoped",
|
||||
request: clusterapi.ClusterUpdateRequest{Cluster: &v1alpha1.Cluster{Name: "", Server: "https://127.0.0.1", Project: "allowed-project", ClusterResources: true}, Id: &clusterapi.ClusterID{Type: "", Value: "https://127.0.0.2"}, UpdatedFields: []string{"clusterResources", "project"}},
|
||||
},
|
||||
{
|
||||
name: "allowed cluster URL in body, disallowed cluster URL in query, changing unscoped to scoped",
|
||||
request: clusterapi.ClusterUpdateRequest{Cluster: &v1alpha1.Cluster{Name: "", Server: "https://127.0.0.1", Project: "allowed-project", ClusterResources: true}, Id: &clusterapi.ClusterID{Type: "name", Value: "disallowed-unscoped"}, UpdatedFields: []string{"clusterResources", "project"}},
|
||||
},
|
||||
}
|
||||
|
||||
db := &dbmocks.ArgoDB{}
|
||||
|
||||
clusters := []v1alpha1.Cluster{
|
||||
{
|
||||
Name: "allowed-unscoped",
|
||||
Server: "https://127.0.0.1",
|
||||
},
|
||||
{
|
||||
Name: "disallowed-unscoped",
|
||||
Server: "https://127.0.0.2",
|
||||
},
|
||||
{
|
||||
Name: "allowed-scoped",
|
||||
Server: "https://127.0.0.3",
|
||||
Project: "allowed-project",
|
||||
},
|
||||
{
|
||||
Name: "disallowed-scoped",
|
||||
Server: "https://127.0.0.4",
|
||||
Project: "disallowed-project",
|
||||
},
|
||||
}
|
||||
|
||||
db.On("ListClusters", mock.Anything).Return(
|
||||
func(ctx context.Context) *v1alpha1.ClusterList {
|
||||
return &v1alpha1.ClusterList{
|
||||
ListMeta: v1.ListMeta{},
|
||||
Items: clusters,
|
||||
}
|
||||
},
|
||||
func(ctx context.Context) error {
|
||||
return nil
|
||||
},
|
||||
)
|
||||
db.On("UpdateCluster", mock.Anything, mock.Anything).Return(
|
||||
func(ctx context.Context, c *v1alpha1.Cluster) *v1alpha1.Cluster {
|
||||
for _, cluster := range clusters {
|
||||
if c.Server == cluster.Server {
|
||||
return c
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func(ctx context.Context, c *v1alpha1.Cluster) error {
|
||||
for _, cluster := range clusters {
|
||||
if c.Server == cluster.Server {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("cluster '%s' not found", c.Server)
|
||||
},
|
||||
)
|
||||
db.On("GetCluster", mock.Anything, mock.Anything).Return(
|
||||
func(ctx context.Context, server string) *v1alpha1.Cluster {
|
||||
for _, cluster := range clusters {
|
||||
if server == cluster.Server {
|
||||
return &cluster
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func(ctx context.Context, server string) error {
|
||||
for _, cluster := range clusters {
|
||||
if server == cluster.Server {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("cluster '%s' not found", server)
|
||||
},
|
||||
)
|
||||
|
||||
enf := rbac.NewEnforcer(fake.NewSimpleClientset(test.NewFakeConfigMap()), test.FakeArgoCDNamespace, common.ArgoCDConfigMapName, nil)
|
||||
_ = enf.SetBuiltinPolicy(`p, role:test, clusters, *, https://127.0.0.1, allow
|
||||
p, role:test, clusters, *, allowed-project/*, allow`)
|
||||
enf.SetDefaultRole("role:test")
|
||||
server := NewServer(db, enf, newServerInMemoryCache(), &kubetest.MockKubectlCmd{})
|
||||
|
||||
for _, c := range testCases {
|
||||
cc := c
|
||||
t.Run(cc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
out, err := server.Update(context.Background(), &cc.request)
|
||||
require.Nil(t, out)
|
||||
assert.ErrorIs(t, err, common.PermissionDeniedAPIError)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCluster_UrlEncodedName(t *testing.T) {
|
||||
db := &dbmocks.ArgoDB{}
|
||||
|
||||
|
||||
@@ -463,8 +463,9 @@ func (a *ArgoCDServer) Run(ctx context.Context, listeners *Listeners) {
|
||||
|
||||
// If not matched, we assume that its TLS.
|
||||
tlsl := tcpm.Match(cmux.Any())
|
||||
tlsConfig := tls.Config{
|
||||
Certificates: []tls.Certificate{*a.settings.Certificate},
|
||||
tlsConfig := tls.Config{}
|
||||
tlsConfig.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
return a.settings.Certificate, nil
|
||||
}
|
||||
if a.TLSConfigCustomizer != nil {
|
||||
a.TLSConfigCustomizer(&tlsConfig)
|
||||
@@ -607,8 +608,8 @@ func (a *ArgoCDServer) watchSettings() {
|
||||
newCert, newCertKey = tlsutil.EncodeX509KeyPairString(*a.settings.Certificate)
|
||||
}
|
||||
if newCert != prevCert || newCertKey != prevCertKey {
|
||||
log.Infof("tls certificate modified. restarting")
|
||||
break
|
||||
log.Infof("tls certificate modified. reloading certificate")
|
||||
// No need to break out of this loop since TlsConfig.GetCertificate will automagically reload the cert.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -674,6 +675,8 @@ func (a *ArgoCDServer) newGRPCServer() (*grpc.Server, application.AppResourceTre
|
||||
"/repocreds.RepoCredsService/CreateRepositoryCredentials": true,
|
||||
"/repocreds.RepoCredsService/UpdateRepositoryCredentials": true,
|
||||
"/application.ApplicationService/PatchResource": true,
|
||||
// Remove from logs both because the contents are sensitive and because they may be very large.
|
||||
"/application.ApplicationService/GetManifestsWithFiles": true,
|
||||
}
|
||||
// NOTE: notice we do not configure the gRPC server here with TLS (e.g. grpc.Creds(creds))
|
||||
// This is because TLS handshaking occurs in cmux handling
|
||||
@@ -861,40 +864,10 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
|
||||
}
|
||||
mux.Handle("/api/", handler)
|
||||
|
||||
terminalHandler := application.NewHandler(a.appLister, a.Namespace, a.ApplicationNamespaces, a.db, a.enf, a.Cache, appResourceTreeFn, a.settings.ExecShells)
|
||||
mux.HandleFunc("/terminal", func(writer http.ResponseWriter, request *http.Request) {
|
||||
argocdSettings, err := a.settingsMgr.GetSettings()
|
||||
if err != nil {
|
||||
http.Error(writer, fmt.Sprintf("Failed to get settings: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if !argocdSettings.ExecEnabled {
|
||||
writer.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if !a.DisableAuth {
|
||||
ctx := request.Context()
|
||||
cookies := request.Cookies()
|
||||
tokenString, err := httputil.JoinCookies(common.AuthCookieName, cookies)
|
||||
if err == nil && jwtutil.IsValid(tokenString) {
|
||||
claims, _, err := a.sessionMgr.VerifyToken(tokenString)
|
||||
if err != nil {
|
||||
// nolint:staticcheck
|
||||
ctx = context.WithValue(ctx, util_session.AuthErrorCtxKey, err)
|
||||
} else if claims != nil {
|
||||
// Add claims to the context to inspect for RBAC
|
||||
// nolint:staticcheck
|
||||
ctx = context.WithValue(ctx, "claims", claims)
|
||||
}
|
||||
request = request.WithContext(ctx)
|
||||
} else {
|
||||
writer.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
}
|
||||
terminalHandler.ServeHTTP(writer, request)
|
||||
})
|
||||
terminal := application.NewHandler(a.appLister, a.Namespace, a.ApplicationNamespaces, a.db, a.enf, a.Cache, appResourceTreeFn, a.settings.ExecShells).
|
||||
WithFeatureFlagMiddleware(a.settingsMgr.GetSettings)
|
||||
th := util_session.WithAuthMiddleware(a.DisableAuth, a.sessionMgr, terminal)
|
||||
mux.Handle("/terminal", th)
|
||||
|
||||
mustRegisterGWHandler(versionpkg.RegisterVersionServiceHandler, ctx, gwmux, conn)
|
||||
mustRegisterGWHandler(clusterpkg.RegisterClusterServiceHandler, ctx, gwmux, conn)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM docker.io/library/redis:7.0.5 as redis
|
||||
FROM docker.io/library/redis:7.0.8-alpine as redis
|
||||
|
||||
# There are libraries we will want to copy from here in the final stage of the
|
||||
# build, but the COPY directive does not have a way to determine system
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
controller: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''}"
|
||||
api-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''} "
|
||||
dex: sh -c "test $ARGOCD_IN_CI = true && exit 0; ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:v2.30.0 serve /dex.yaml"
|
||||
dex: sh -c "test $ARGOCD_IN_CI = true && exit 0; ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:v2.35.3 serve /dex.yaml"
|
||||
redis: sh -c "/usr/local/bin/redis-server --save "" --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}"
|
||||
repo-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} ARGOCD_BINARY_NAME=argocd-repo-server $COMMAND --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}"
|
||||
ui: sh -c "test $ARGOCD_IN_CI = true && exit 0; cd ui && ARGOCD_E2E_YARN_HOST=0.0.0.0 ${ARGOCD_E2E_YARN_CMD:-yarn} start"
|
||||
|
||||
@@ -811,6 +811,8 @@ func RestartRepoServer() {
|
||||
}
|
||||
FailOnErr(Run("", "kubectl", "rollout", "restart", "deployment", workload))
|
||||
FailOnErr(Run("", "kubectl", "rollout", "status", "deployment", workload))
|
||||
// wait longer to avoid error on s390x
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ export const ApplicationResourceList = ({
|
||||
<Consumer>
|
||||
{ctx => (
|
||||
<span className='application-details__external_link'>
|
||||
<a href={ctx.baseHref + 'applications/' + res.name} title='Open application'>
|
||||
<a href={ctx.baseHref + 'applications/' + res.namespace + '/' + res.name} title='Open application'>
|
||||
<i className='fa fa-external-link-alt' />
|
||||
</a>
|
||||
</span>
|
||||
|
||||
@@ -190,31 +190,21 @@ export const ApplicationParameters = (props: {
|
||||
/>
|
||||
)
|
||||
});
|
||||
if (app?.spec?.source?.helm?.values) {
|
||||
attributes.push({
|
||||
title: 'VALUES',
|
||||
view: app.spec.source.helm && (
|
||||
<Expandable>
|
||||
<pre>{app.spec.source.helm.values}</pre>
|
||||
</Expandable>
|
||||
),
|
||||
edit: (formApi: FormApi) => (
|
||||
<div>
|
||||
<pre>
|
||||
<FormField formApi={formApi} field='spec.source.helm.values' component={TextArea} />
|
||||
</pre>
|
||||
{props.details.helm.values && (
|
||||
<div>
|
||||
<label>values.yaml</label>
|
||||
<Expandable>
|
||||
<pre>{props.details.helm.values}</pre>
|
||||
</Expandable>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
});
|
||||
}
|
||||
attributes.push({
|
||||
title: 'VALUES',
|
||||
view: app.spec.source.helm && (
|
||||
<Expandable>
|
||||
<pre>{app.spec.source.helm.values}</pre>
|
||||
</Expandable>
|
||||
),
|
||||
edit: (formApi: FormApi) => (
|
||||
<div>
|
||||
<pre>
|
||||
<FormField formApi={formApi} field='spec.source.helm.values' component={TextArea} />
|
||||
</pre>
|
||||
</div>
|
||||
)
|
||||
});
|
||||
const paramsByName = new Map<string, models.HelmParameter>();
|
||||
(props.details.helm.parameters || []).forEach(param => paramsByName.set(param.name, param));
|
||||
const overridesByName = new Map<string, number>();
|
||||
|
||||
@@ -433,7 +433,7 @@ function renderPodGroup(props: ApplicationResourceTreeProps, id: string, node: R
|
||||
{appNode && !rootNode && (
|
||||
<Consumer>
|
||||
{ctx => (
|
||||
<a href={ctx.baseHref + 'applications/' + node.name} title='Open application'>
|
||||
<a href={ctx.baseHref + 'applications/' + node.namespace + '/' + node.name} title='Open application'>
|
||||
<i className='fa fa-external-link-alt' />
|
||||
</a>
|
||||
)}
|
||||
@@ -652,7 +652,7 @@ function renderResourceNode(props: ApplicationResourceTreeProps, id: string, nod
|
||||
{appNode && !rootNode && (
|
||||
<Consumer>
|
||||
{ctx => (
|
||||
<a href={ctx.baseHref + 'applications/' + node.name} title='Open application'>
|
||||
<a href={ctx.baseHref + 'applications/' + node.namespace + '/' + node.name} title='Open application'>
|
||||
<i className='fa fa-external-link-alt' />
|
||||
</a>
|
||||
)}
|
||||
|
||||
@@ -48,7 +48,9 @@ export const EventsList = (props: {events: models.Event[]}) => {
|
||||
<div className={`argo-table-list__row events-list__event events-list__event--${event.type}`} key={event.metadata.uid}>
|
||||
<div className='row'>
|
||||
<div className='columns small-2 xxlarge-2'>{event.reason}</div>
|
||||
<div className='columns small-4 xxlarge-5'>{event.message}</div>
|
||||
<div className='columns small-4 xxlarge-5' style={{whiteSpace: 'normal'}}>
|
||||
{event.message}
|
||||
</div>
|
||||
<div className='columns small-2 xxlarge-1'>{event.count}</div>
|
||||
<div className='columns small-2 xxlarge-2'>{event.firstTimestamp ? getTimeElements(event.firstTimestamp) : getTimeElements(event.eventTime)}</div>
|
||||
<div className='columns small-2 xxlarge-2'>{event.lastTimestamp ? getTimeElements(event.lastTimestamp) : getTimeElements(event.eventTime)}</div>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import {Tooltip} from 'argo-ui';
|
||||
import * as React from 'react';
|
||||
import {combineLatest} from 'rxjs';
|
||||
import {map} from 'rxjs/operators';
|
||||
import {ExternalLink} from '../applications/components/application-urls';
|
||||
|
||||
import {DataLoader} from '../shared/components';
|
||||
import {services, ViewPreferences} from '../shared/services';
|
||||
@@ -67,6 +69,14 @@ export const Banner = (props: React.Props<any>) => {
|
||||
chatBottomPosition = 85;
|
||||
}
|
||||
}
|
||||
if (chatUrl) {
|
||||
try {
|
||||
const externalLink = new ExternalLink(chatUrl);
|
||||
chatUrl = externalLink.ref;
|
||||
} catch (InvalidExternalLinkError) {
|
||||
chatUrl = 'invalid-url';
|
||||
}
|
||||
}
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className={combinedBannerClassName} style={{visibility: show ? 'visible' : 'hidden', height: heightOfBanner, left: leftOffset}}>
|
||||
@@ -97,9 +107,17 @@ export const Banner = (props: React.Props<any>) => {
|
||||
{show ? <div className={wrapperClassname}>{props.children}</div> : props.children}
|
||||
{chatUrl && (
|
||||
<div style={{position: 'fixed', right: 10, bottom: chatBottomPosition}}>
|
||||
<a href={chatUrl} className='argo-button argo-button--special'>
|
||||
<i className='fas fa-comment-alt' /> {chatText}
|
||||
</a>
|
||||
{chatUrl === 'invalid-url' ? (
|
||||
<Tooltip content='Invalid URL provided'>
|
||||
<a className='argo-button disabled argo-button--special'>
|
||||
<i className='fas fa-comment-alt' /> {chatText}
|
||||
</a>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<a href={chatUrl} className='argo-button argo-button--special'>
|
||||
<i className='fas fa-comment-alt' /> {chatText}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
|
||||
@@ -16,7 +16,7 @@ spec:
|
||||
terminationGracePeriodSeconds: 10
|
||||
containers:
|
||||
- name: nginx
|
||||
image: k8s.gcr.io/nginx-slim:0.8
|
||||
image: registry.k8s.io/nginx-slim:0.8
|
||||
ports:
|
||||
- containerPort: 80
|
||||
name: web
|
||||
|
||||
@@ -109,6 +109,12 @@ func (p *providerImpl) Verify(tokenString string, argoSettings *settings.ArgoCDS
|
||||
// Token must be verified for at least one allowed audience
|
||||
for _, aud := range allowedAudiences {
|
||||
idToken, err = p.verify(aud, tokenString, false)
|
||||
if err != nil && strings.HasPrefix(err.Error(), "oidc: token is expired") {
|
||||
// If the token is expired, we won't bother checking other audiences. It's important to return a
|
||||
// ErrTokenExpired instead of an error related to an incorrect audience, because the caller may
|
||||
// have specific behavior to handle expired tokens.
|
||||
break
|
||||
}
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -462,6 +462,47 @@ func (mgr *SessionManager) VerifyUsernamePassword(username string, password stri
|
||||
return nil
|
||||
}
|
||||
|
||||
// AuthMiddlewareFunc returns a function that can be used as an
|
||||
// authentication middleware for HTTP requests.
|
||||
func (mgr *SessionManager) AuthMiddlewareFunc(disabled bool) func(http.Handler) http.Handler {
|
||||
return func(h http.Handler) http.Handler {
|
||||
return WithAuthMiddleware(disabled, mgr, h)
|
||||
}
|
||||
}
|
||||
|
||||
// TokenVerifier defines the contract to invoke token
|
||||
// verification logic
|
||||
type TokenVerifier interface {
|
||||
VerifyToken(token string) (jwt.Claims, string, error)
|
||||
}
|
||||
|
||||
// WithAuthMiddleware is an HTTP middleware used to ensure incoming
|
||||
// requests are authenticated before invoking the target handler. If
|
||||
// disabled is true, it will just invoke the next handler in the chain.
|
||||
func WithAuthMiddleware(disabled bool, authn TokenVerifier, next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !disabled {
|
||||
cookies := r.Cookies()
|
||||
tokenString, err := httputil.JoinCookies(common.AuthCookieName, cookies)
|
||||
if err != nil {
|
||||
http.Error(w, "Auth cookie not found", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
claims, _, err := authn.VerifyToken(tokenString)
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid token", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
ctx := r.Context()
|
||||
// Add claims to the context to inspect for RBAC
|
||||
// nolint:staticcheck
|
||||
ctx = context.WithValue(ctx, "claims", claims)
|
||||
r = r.WithContext(ctx)
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// VerifyToken verifies if a token is correct. Tokens can be issued either from us or by an IDP.
|
||||
// We choose how to verify based on the issuer.
|
||||
func (mgr *SessionManager) VerifyToken(tokenString string) (jwt.Claims, string, error) {
|
||||
|
||||
@@ -3,8 +3,12 @@ package session
|
||||
import (
|
||||
"context"
|
||||
"encoding/pem"
|
||||
stderrors "errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -221,6 +225,136 @@ func TestSessionManager_ProjectToken(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
type claimsMock struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (cm *claimsMock) Valid() error {
|
||||
return cm.err
|
||||
}
|
||||
|
||||
type tokenVerifierMock struct {
|
||||
claims *claimsMock
|
||||
err error
|
||||
}
|
||||
|
||||
func (tm *tokenVerifierMock) VerifyToken(token string) (jwt.Claims, string, error) {
|
||||
if tm.claims == nil {
|
||||
return nil, "", tm.err
|
||||
}
|
||||
return tm.claims, "", tm.err
|
||||
}
|
||||
|
||||
func strPointer(str string) *string {
|
||||
return &str
|
||||
}
|
||||
|
||||
func TestSessionManager_WithAuthMiddleware(t *testing.T) {
|
||||
handlerFunc := func() func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Helper()
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Content-Type", "application/text")
|
||||
_, err := w.Write([]byte("Ok"))
|
||||
if err != nil {
|
||||
t.Fatalf("error writing response: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
type testCase struct {
|
||||
name string
|
||||
authDisabled bool
|
||||
cookieHeader bool
|
||||
verifiedClaims *claimsMock
|
||||
verifyTokenErr error
|
||||
expectedStatusCode int
|
||||
expectedResponseBody *string
|
||||
}
|
||||
|
||||
cases := []testCase{
|
||||
{
|
||||
name: "will authenticate successfully",
|
||||
authDisabled: false,
|
||||
cookieHeader: true,
|
||||
verifiedClaims: &claimsMock{},
|
||||
verifyTokenErr: nil,
|
||||
expectedStatusCode: 200,
|
||||
expectedResponseBody: strPointer("Ok"),
|
||||
},
|
||||
{
|
||||
name: "will be noop if auth is disabled",
|
||||
authDisabled: true,
|
||||
cookieHeader: false,
|
||||
verifiedClaims: nil,
|
||||
verifyTokenErr: nil,
|
||||
expectedStatusCode: 200,
|
||||
expectedResponseBody: strPointer("Ok"),
|
||||
},
|
||||
{
|
||||
name: "will return 400 if no cookie header",
|
||||
authDisabled: false,
|
||||
cookieHeader: false,
|
||||
verifiedClaims: &claimsMock{},
|
||||
verifyTokenErr: nil,
|
||||
expectedStatusCode: 400,
|
||||
expectedResponseBody: nil,
|
||||
},
|
||||
{
|
||||
name: "will return 401 verify token fails",
|
||||
authDisabled: false,
|
||||
cookieHeader: true,
|
||||
verifiedClaims: &claimsMock{},
|
||||
verifyTokenErr: stderrors.New("token error"),
|
||||
expectedStatusCode: 401,
|
||||
expectedResponseBody: nil,
|
||||
},
|
||||
{
|
||||
name: "will return 200 if claims are nil",
|
||||
authDisabled: false,
|
||||
cookieHeader: true,
|
||||
verifiedClaims: nil,
|
||||
verifyTokenErr: nil,
|
||||
expectedStatusCode: 200,
|
||||
expectedResponseBody: strPointer("Ok"),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// given
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", handlerFunc())
|
||||
tm := &tokenVerifierMock{
|
||||
claims: tc.verifiedClaims,
|
||||
err: tc.verifyTokenErr,
|
||||
}
|
||||
ts := httptest.NewServer(WithAuthMiddleware(tc.authDisabled, tm, mux))
|
||||
defer ts.Close()
|
||||
req, err := http.NewRequest(http.MethodGet, ts.URL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating request: %s", err)
|
||||
}
|
||||
if tc.cookieHeader {
|
||||
req.Header.Add("Cookie", "argocd.token=123456")
|
||||
}
|
||||
|
||||
// when
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, resp)
|
||||
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
||||
if tc.expectedResponseBody != nil {
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
actual := strings.TrimSuffix(string(body), "\n")
|
||||
assert.Contains(t, actual, *tc.expectedResponseBody)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var loggedOutContext = context.Background()
|
||||
|
||||
// nolint:staticcheck
|
||||
|
||||
@@ -1697,12 +1697,16 @@ func (a *ArgoCDSettings) OAuth2ClientID() string {
|
||||
func (a *ArgoCDSettings) OAuth2AllowedAudiences() []string {
|
||||
if config := a.oidcConfig(); config != nil {
|
||||
if len(config.AllowedAudiences) == 0 {
|
||||
return []string{config.ClientID}
|
||||
allowedAudiences := []string{config.ClientID}
|
||||
if config.CLIClientID != "" {
|
||||
allowedAudiences = append(allowedAudiences, config.CLIClientID)
|
||||
}
|
||||
return allowedAudiences
|
||||
}
|
||||
return config.AllowedAudiences
|
||||
}
|
||||
if a.DexConfig != "" {
|
||||
return []string{common.ArgoCDClientAppID}
|
||||
return []string{common.ArgoCDClientAppID, common.ArgoCDCLIClientAppID}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1343,3 +1343,68 @@ rootCA: "invalid"`},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_OAuth2AllowedAudiences(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
settings *ArgoCDSettings
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "Empty",
|
||||
settings: &ArgoCDSettings{},
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "OIDC configured, no audiences specified, clientID used",
|
||||
settings: &ArgoCDSettings{OIDCConfigRAW: `name: Test
|
||||
issuer: aaa
|
||||
clientID: xxx
|
||||
clientSecret: yyy
|
||||
requestedScopes: ["oidc"]`},
|
||||
expected: []string{"xxx"},
|
||||
},
|
||||
{
|
||||
name: "OIDC configured, no audiences specified, clientID and cliClientID used",
|
||||
settings: &ArgoCDSettings{OIDCConfigRAW: `name: Test
|
||||
issuer: aaa
|
||||
clientID: xxx
|
||||
cliClientID: cli-xxx
|
||||
clientSecret: yyy
|
||||
requestedScopes: ["oidc"]`},
|
||||
expected: []string{"xxx", "cli-xxx"},
|
||||
},
|
||||
{
|
||||
name: "OIDC configured, audiences specified",
|
||||
settings: &ArgoCDSettings{OIDCConfigRAW: `name: Test
|
||||
issuer: aaa
|
||||
clientID: xxx
|
||||
clientSecret: yyy
|
||||
requestedScopes: ["oidc"]
|
||||
allowedAudiences: ["aud1", "aud2"]`},
|
||||
expected: []string{"aud1", "aud2"},
|
||||
},
|
||||
{
|
||||
name: "Dex configured",
|
||||
settings: &ArgoCDSettings{DexConfig: `connectors:
|
||||
- type: github
|
||||
id: github
|
||||
name: GitHub
|
||||
config:
|
||||
clientID: aabbccddeeff00112233
|
||||
clientSecret: $dex.github.clientSecret
|
||||
orgs:
|
||||
- name: your-github-org
|
||||
`},
|
||||
expected: []string{common.ArgoCDClientAppID, common.ArgoCDCLIClientAppID},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tcc := tc
|
||||
t.Run(tcc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.ElementsMatch(t, tcc.expected, tcc.settings.OAuth2AllowedAudiences())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,10 @@ type settingsSource interface {
|
||||
GetTrackingMethod() (string, error)
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc3986#section-3.2.1
|
||||
// https://github.com/shadow-maint/shadow/blob/master/libmisc/chkname.c#L36
|
||||
const usernameRegex = `[a-zA-Z0-9_\.][a-zA-Z0-9_\.-]{0,30}[a-zA-Z0-9_\.\$-]?`
|
||||
|
||||
var _ settingsSource = &settings.SettingsManager{}
|
||||
|
||||
type ArgoCDWebhookHandler struct {
|
||||
@@ -262,7 +266,8 @@ func getWebUrlRegex(webURL string) (*regexp.Regexp, error) {
|
||||
|
||||
regexEscapedHostname := regexp.QuoteMeta(urlObj.Hostname())
|
||||
regexEscapedPath := regexp.QuoteMeta(urlObj.Path[1:])
|
||||
regexpStr := fmt.Sprintf(`(?i)^(http://|https://|\w+@|ssh://(\w+@)?)%s(:[0-9]+|)[:/]%s(\.git)?$`, regexEscapedHostname, regexEscapedPath)
|
||||
regexpStr := fmt.Sprintf(`(?i)^(http://|https://|%s@|ssh://(%s@)?)%s(:[0-9]+|)[:/]%s(\.git)?$`,
|
||||
usernameRegex, usernameRegex, regexEscapedHostname, regexEscapedPath)
|
||||
repoRegexp, err := regexp.Compile(regexpStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to compile regexp for repoURL '%s'", webURL)
|
||||
|
||||
@@ -444,6 +444,8 @@ func Test_getWebUrlRegex(t *testing.T) {
|
||||
{true, "https://example.com/org/repo", "ssh://git@example.com/org/repo", "git with protocol should match"},
|
||||
{true, "https://example.com/org/repo", "ssh://git@example.com:22/org/repo", "git with port number should should match"},
|
||||
{true, "https://example.com:443/org/repo", "ssh://git@example.com:22/org/repo", "https and ssh w/ different port numbers should match"},
|
||||
{true, "https://example.com/org/repo", "ssh://user-name@example.com/org/repo", "valid usernames with hyphens in repo should match"},
|
||||
{false, "https://example.com/org/repo", "ssh://-user-name@example.com/org/repo", "invalid usernames with hyphens in repo should not match"},
|
||||
{true, "https://example.com:443/org/repo", "GIT@EXAMPLE.COM:22:ORG/REPO", "matches aren't case-sensitive"},
|
||||
}
|
||||
for _, testCase := range tests {
|
||||
|
||||
Reference in New Issue
Block a user