mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-02-20 09:38:49 +01:00
Compare commits
63 Commits
master
...
v2.6.0-rc6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6df2fcfca | ||
|
|
719b0aae82 | ||
|
|
9a27a20c5d | ||
|
|
01ef2e0c32 | ||
|
|
063dce443f | ||
|
|
5094ee988f | ||
|
|
671f3f493d | ||
|
|
10caed890c | ||
|
|
bc88f98f6d | ||
|
|
e790028e5c | ||
|
|
6ba9975245 | ||
|
|
79baabc837 | ||
|
|
9b6815f06f | ||
|
|
16f2de0b29 | ||
|
|
d744465cdf | ||
|
|
240ffc30ef | ||
|
|
22662559fe | ||
|
|
590ea32083 | ||
|
|
f8483d2be4 | ||
|
|
25d1d7aca2 | ||
|
|
678d773a6a | ||
|
|
e51d0b3224 | ||
|
|
0f5f41ebb0 | ||
|
|
ee4b3cacc9 | ||
|
|
62a521ccf6 | ||
|
|
eb6474c524 | ||
|
|
826507897d | ||
|
|
5fcebcc799 | ||
|
|
7f00420b3d | ||
|
|
6ebca0bd01 | ||
|
|
93fa2a46a5 | ||
|
|
72f92b6f2a | ||
|
|
7d54482d42 | ||
|
|
fe8049fc50 | ||
|
|
8065748cca | ||
|
|
57560b32f6 | ||
|
|
d5eb10c24d | ||
|
|
cab9b5769f | ||
|
|
bb8ef6dfa3 | ||
|
|
6a9f37ca7d | ||
|
|
b357fd61c0 | ||
|
|
f8d275c50d | ||
|
|
053cfaf378 | ||
|
|
f869cc4feb | ||
|
|
fab4a3cb92 | ||
|
|
7dab9b23bf | ||
|
|
c8d010ceb0 | ||
|
|
3fa9a9197b | ||
|
|
af00900049 | ||
|
|
e67f4b151e | ||
|
|
3a8802f083 | ||
|
|
cdaf2b2c73 | ||
|
|
222cdf4711 | ||
|
|
c58d3843d5 | ||
|
|
383a65fe71 | ||
|
|
acfdc3d3be | ||
|
|
80f4ab9d7b | ||
|
|
44d13a73c9 | ||
|
|
a6469140b9 | ||
|
|
9a4179b1b6 | ||
|
|
0cd4854ffa | ||
|
|
81e40d53fe | ||
|
|
8532cfec4a |
68
.github/workflows/ci-build.yaml
vendored
68
.github/workflows/ci-build.yaml
vendored
@@ -27,9 +27,9 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@d0a58c1c4d2b25278816e339b944508c875f3613 # v3.4.0
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Download all Go modules
|
||||
@@ -45,13 +45,13 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@d0a58c1c4d2b25278816e339b944508c875f3613 # v3.4.0
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Restore go build cache
|
||||
uses: actions/cache@9b0c1fce7a93df8e3bb8926b0d6e9d89e92f20a7 # v3.0.11
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3
|
||||
with:
|
||||
path: ~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
|
||||
@@ -69,9 +69,9 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@d0a58c1c4d2b25278816e339b944508c875f3613 # v3.4.0
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Run golangci-lint
|
||||
@@ -92,11 +92,11 @@ jobs:
|
||||
- name: Create checkout directory
|
||||
run: mkdir -p ~/go/src/github.com/argoproj
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: Create symlink in GOPATH
|
||||
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@d0a58c1c4d2b25278816e339b944508c875f3613 # v3.4.0
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Install required packages
|
||||
@@ -116,7 +116,7 @@ jobs:
|
||||
run: |
|
||||
echo "/usr/local/bin" >> $GITHUB_PATH
|
||||
- name: Restore go build cache
|
||||
uses: actions/cache@9b0c1fce7a93df8e3bb8926b0d6e9d89e92f20a7 # v3.0.11
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3
|
||||
with:
|
||||
path: ~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
|
||||
@@ -133,12 +133,12 @@ jobs:
|
||||
- name: Run all unit tests
|
||||
run: make test-local
|
||||
- name: Generate code coverage artifacts
|
||||
uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3.1.1
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: code-coverage
|
||||
path: coverage.out
|
||||
- name: Generate test results artifacts
|
||||
uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3.1.1
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: test-results
|
||||
path: test-results/
|
||||
@@ -155,11 +155,11 @@ jobs:
|
||||
- name: Create checkout directory
|
||||
run: mkdir -p ~/go/src/github.com/argoproj
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: Create symlink in GOPATH
|
||||
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@d0a58c1c4d2b25278816e339b944508c875f3613 # v3.4.0
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Install required packages
|
||||
@@ -179,7 +179,7 @@ jobs:
|
||||
run: |
|
||||
echo "/usr/local/bin" >> $GITHUB_PATH
|
||||
- name: Restore go build cache
|
||||
uses: actions/cache@9b0c1fce7a93df8e3bb8926b0d6e9d89e92f20a7 # v3.0.11
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3
|
||||
with:
|
||||
path: ~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
|
||||
@@ -196,7 +196,7 @@ jobs:
|
||||
- name: Run all unit tests
|
||||
run: make test-race-local
|
||||
- name: Generate test results artifacts
|
||||
uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3.1.1
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: race-results
|
||||
path: test-results/
|
||||
@@ -206,9 +206,9 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@d0a58c1c4d2b25278816e339b944508c875f3613 # v3.4.0
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Create symlink in GOPATH
|
||||
@@ -250,14 +250,14 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: Setup NodeJS
|
||||
uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1
|
||||
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@9b0c1fce7a93df8e3bb8926b0d6e9d89e92f20a7 # v3.0.11
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3
|
||||
with:
|
||||
path: ui/node_modules
|
||||
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
|
||||
@@ -287,12 +287,12 @@ jobs:
|
||||
sonar_secret: ${{ secrets.SONAR_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Restore node dependency cache
|
||||
id: cache-dependencies
|
||||
uses: actions/cache@9b0c1fce7a93df8e3bb8926b0d6e9d89e92f20a7 # v3.0.11
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3
|
||||
with:
|
||||
path: ui/node_modules
|
||||
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
|
||||
@@ -303,11 +303,11 @@ jobs:
|
||||
run: |
|
||||
mkdir -p test-results
|
||||
- name: Get code coverage artifiact
|
||||
uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 # v3.0.1
|
||||
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
|
||||
with:
|
||||
name: code-coverage
|
||||
- name: Get test result artifact
|
||||
uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 # v3.0.1
|
||||
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
|
||||
with:
|
||||
name: test-results
|
||||
path: test-results
|
||||
@@ -366,22 +366,14 @@ jobs:
|
||||
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@d0a58c1c4d2b25278816e339b944508c875f3613 # v3.4.0
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: GH actions workaround - Kill XSP4 process
|
||||
run: |
|
||||
sudo pkill mono || true
|
||||
# ubuntu-22.04 comes with kubectl, but the version is not pinned. The version as of 2022-12-05 is 1.26.0 which
|
||||
# breaks the `TestNamespacedResourceDiffing` e2e test. So we'll pin to 1.25 and then fix the underlying issue.
|
||||
- name: Install kubectl
|
||||
run: |
|
||||
rm /usr/local/bin/kubectl
|
||||
curl -LO https://dl.k8s.io/release/v1.25.4/bin/linux/amd64/kubectl
|
||||
mv kubectl /usr/local/bin/kubectl
|
||||
chmod +x /usr/local/bin/kubectl
|
||||
- name: Install K3S
|
||||
env:
|
||||
INSTALL_K3S_VERSION: ${{ matrix.k3s-version }}+k3s1
|
||||
@@ -394,7 +386,7 @@ jobs:
|
||||
sudo chown runner $HOME/.kube/config
|
||||
kubectl version
|
||||
- name: Restore go build cache
|
||||
uses: actions/cache@9b0c1fce7a93df8e3bb8926b0d6e9d89e92f20a7 # v3.0.11
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3
|
||||
with:
|
||||
path: ~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
|
||||
@@ -422,7 +414,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.5-alpine
|
||||
docker pull redis:7.0.7-alpine
|
||||
- name: Create target directory for binaries in the build-process
|
||||
run: |
|
||||
mkdir -p dist
|
||||
@@ -450,7 +442,7 @@ jobs:
|
||||
set -x
|
||||
make test-e2e-local
|
||||
- name: Upload e2e-server logs
|
||||
uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3.1.1
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: e2e-server-k8s${{ matrix.k3s-version }}.log
|
||||
path: /tmp/e2e-server.log
|
||||
|
||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
17
.github/workflows/image.yaml
vendored
17
.github/workflows/image.yaml
vendored
@@ -29,10 +29,10 @@ jobs:
|
||||
env:
|
||||
GOPATH: /home/runner/work/argo-cd/argo-cd
|
||||
steps:
|
||||
- uses: actions/setup-go@d0a58c1c4d2b25278816e339b944508c875f3613 # v3.4.0
|
||||
- uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
with:
|
||||
path: src/github.com/argoproj/argo-cd
|
||||
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
IMAGE_PLATFORMS=linux/amd64,linux/arm64,linux/s390x,linux/ppc64le
|
||||
fi
|
||||
echo "Building image for platforms: $IMAGE_PLATFORMS"
|
||||
docker buildx build --platform $IMAGE_PLATFORMS --push="${{ github.event_name == 'push' }}" \
|
||||
docker buildx build --platform $IMAGE_PLATFORMS --sbom=false --provenance=false --push="${{ github.event_name == 'push' }}" \
|
||||
-t ghcr.io/argoproj/argo-cd/argocd:${{ steps.image.outputs.tag }} \
|
||||
-t quay.io/argoproj/argocd:latest .
|
||||
working-directory: ./src/github.com/argoproj/argo-cd
|
||||
@@ -71,11 +71,18 @@ jobs:
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@9becc617647dfa20ae7b1151972e9b3a2c338a2b # v2.8.1
|
||||
with:
|
||||
cosign-release: 'v1.13.0'
|
||||
cosign-release: 'v1.13.1'
|
||||
|
||||
- name: Install crane to get digest of image
|
||||
uses: imjasonh/setup-crane@e82f1b9a8007d399333baba4d75915558e9fb6a4
|
||||
|
||||
- name: Get digest of image
|
||||
run: |
|
||||
echo "IMAGE_DIGEST=$(crane digest quay.io/argoproj/argocd:latest)" >> $GITHUB_ENV
|
||||
|
||||
- name: Sign Argo CD latest image
|
||||
run: |
|
||||
cosign sign --key env://COSIGN_PRIVATE_KEY quay.io/argoproj/argocd:latest
|
||||
cosign sign --key env://COSIGN_PRIVATE_KEY quay.io/argoproj/argocd@${{ env.IMAGE_DIGEST }}
|
||||
# Displays the public key to share.
|
||||
cosign public-key --key env://COSIGN_PRIVATE_KEY
|
||||
env:
|
||||
|
||||
21
.github/workflows/release.yaml
vendored
21
.github/workflows/release.yaml
vendored
@@ -12,7 +12,7 @@ on:
|
||||
- "!release-v0*"
|
||||
|
||||
env:
|
||||
GOLANG_VERSION: '1.18'
|
||||
GOLANG_VERSION: '1.18'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
GIT_EMAIL: argoproj@gmail.com
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.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@d0a58c1c4d2b25278816e339b944508c875f3613 # v3.4.0
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
|
||||
@@ -207,7 +207,7 @@ jobs:
|
||||
set -ue
|
||||
git clean -fd
|
||||
mkdir -p dist/
|
||||
docker buildx build --platform linux/amd64,linux/arm64,linux/s390x,linux/ppc64le --push -t ${IMAGE_NAMESPACE}/argocd:v${TARGET_VERSION} -t argoproj/argocd:v${TARGET_VERSION} .
|
||||
docker buildx build --platform linux/amd64,linux/arm64,linux/s390x,linux/ppc64le --sbom=false --provenance=false --push -t ${IMAGE_NAMESPACE}/argocd:v${TARGET_VERSION} -t argoproj/argocd:v${TARGET_VERSION} .
|
||||
make release-cli
|
||||
make checksums
|
||||
chmod +x ./dist/argocd-linux-amd64
|
||||
@@ -217,11 +217,18 @@ jobs:
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@9becc617647dfa20ae7b1151972e9b3a2c338a2b # v2.8.1
|
||||
with:
|
||||
cosign-release: 'v1.13.0'
|
||||
cosign-release: 'v1.13.1'
|
||||
|
||||
- name: Install crane to get digest of image
|
||||
uses: imjasonh/setup-crane@e82f1b9a8007d399333baba4d75915558e9fb6a4
|
||||
|
||||
- name: Get digest of image
|
||||
run: |
|
||||
echo "IMAGE_DIGEST=$(crane digest quay.io/argoproj/argocd:v${TARGET_VERSION})" >> $GITHUB_ENV
|
||||
|
||||
- name: Sign Argo CD container images and assets
|
||||
run: |
|
||||
cosign sign --key env://COSIGN_PRIVATE_KEY ${IMAGE_NAMESPACE}/argocd:v${TARGET_VERSION}
|
||||
cosign sign --key env://COSIGN_PRIVATE_KEY ${IMAGE_NAMESPACE}/argocd@${{ env.IMAGE_DIGEST }}
|
||||
cosign sign-blob --key env://COSIGN_PRIVATE_KEY ./dist/argocd-${TARGET_VERSION}-checksums.txt > ./dist/argocd-${TARGET_VERSION}-checksums.sig
|
||||
# Retrieves the public key to release as an asset
|
||||
cosign public-key --key env://COSIGN_PRIVATE_KEY > ./dist/argocd-cosign.pub
|
||||
@@ -264,7 +271,7 @@ jobs:
|
||||
SIGS_BOM_VERSION: v0.2.1
|
||||
# comma delimited list of project relative folders to inspect for package
|
||||
# managers (gomod, yarn, npm).
|
||||
PROJECT_FOLDERS: ".,./ui"
|
||||
PROJECT_FOLDERS: ".,./ui"
|
||||
# full qualified name of the docker image to be inspected
|
||||
DOCKER_IMAGE: ${{env.IMAGE_NAMESPACE}}/argocd:v${{env.TARGET_VERSION}}
|
||||
run: |
|
||||
|
||||
2
.github/workflows/update-snyk.yaml
vendored
2
.github/workflows/update-snyk.yaml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build reports
|
||||
|
||||
1
USERS.md
1
USERS.md
@@ -169,6 +169,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. [Pigment](https://www.gopigment.com/)
|
||||
|
||||
@@ -144,9 +144,10 @@ func (m *MatrixGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Ap
|
||||
|
||||
for _, r := range appSetGenerator.Matrix.Generators {
|
||||
base := &argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
List: r.List,
|
||||
Clusters: r.Clusters,
|
||||
Git: r.Git,
|
||||
List: r.List,
|
||||
Clusters: r.Clusters,
|
||||
Git: r.Git,
|
||||
PullRequest: r.PullRequest,
|
||||
}
|
||||
generators := GetRelevantGenerators(base, m.supportedGenerators)
|
||||
|
||||
|
||||
@@ -399,6 +399,8 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
|
||||
Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "Cluster","url": "Url"}`)}},
|
||||
}
|
||||
|
||||
pullRequestGenerator := &argoprojiov1alpha1.PullRequestGenerator{}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
|
||||
@@ -431,6 +433,31 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
|
||||
gitGetRequeueAfter: time.Duration(1),
|
||||
expected: time.Duration(1),
|
||||
},
|
||||
{
|
||||
name: "returns the minimal time for pull request",
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
},
|
||||
{
|
||||
PullRequest: pullRequestGenerator,
|
||||
},
|
||||
},
|
||||
gitGetRequeueAfter: time.Duration(15 * time.Second),
|
||||
expected: time.Duration(15 * time.Second),
|
||||
},
|
||||
{
|
||||
name: "returns the default time if no requeueAfterSeconds is provided",
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
},
|
||||
{
|
||||
PullRequest: pullRequestGenerator,
|
||||
},
|
||||
},
|
||||
expected: time.Duration(30 * time.Minute),
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
@@ -441,16 +468,18 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
|
||||
|
||||
for _, g := range testCaseCopy.baseGenerators {
|
||||
gitGeneratorSpec := argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Git: g.Git,
|
||||
List: g.List,
|
||||
Git: g.Git,
|
||||
List: g.List,
|
||||
PullRequest: g.PullRequest,
|
||||
}
|
||||
mock.On("GetRequeueAfter", &gitGeneratorSpec).Return(testCaseCopy.gitGetRequeueAfter, nil)
|
||||
}
|
||||
|
||||
var matrixGenerator = NewMatrixGenerator(
|
||||
map[string]Generator{
|
||||
"Git": mock,
|
||||
"List": &ListGenerator{},
|
||||
"Git": mock,
|
||||
"List": &ListGenerator{},
|
||||
"PullRequest": &PullRequestGenerator{},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -3588,6 +3588,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/settings/plugins": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"SettingsService"
|
||||
],
|
||||
"summary": "Get returns Argo CD plugins",
|
||||
"operationId": "SettingsService_GetPlugins",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/clusterSettingsPluginsResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/runtimeError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/stream/applications": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -4342,6 +4365,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"clusterSettingsPluginsResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"plugins": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/clusterPlugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gpgkeyGnuPGPublicKeyCreateResponse": {
|
||||
"type": "object",
|
||||
"title": "Response to a public key creation request",
|
||||
|
||||
@@ -207,7 +207,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
|
||||
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
|
||||
command.Flags().BoolVar(&dryRun, "dry-run", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_DRY_RUN", false), "Enable dry run mode")
|
||||
command.Flags().BoolVar(&enableProgressiveRollouts, "enable-progressive-rollouts", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_ENABLE_PROGRESSIVE_ROLLOUTS", false), "Enable use of the experimental progressive rollouts feature.")
|
||||
command.Flags().BoolVar(&enableProgressiveRollouts, "enable-progressive-rollouts", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS", false), "Enable use of the experimental progressive rollouts feature.")
|
||||
return &command
|
||||
}
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ var validatorsByGroup = map[string]settingValidator{
|
||||
}
|
||||
ssoProvider = "Dex"
|
||||
} else if general.OIDCConfigRAW != "" {
|
||||
if _, err := settings.UnmarshalOIDCConfig(general.OIDCConfigRAW); err != nil {
|
||||
if err := settings.ValidateOIDCConfig(general.OIDCConfigRAW); err != nil {
|
||||
return "", fmt.Errorf("invalid oidc.config: %v", err)
|
||||
}
|
||||
ssoProvider = "OIDC"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@@ -316,3 +317,8 @@ const (
|
||||
SecurityMedium = 2 // Could indicate malicious events, but has a high likelihood of being user/system error (i.e. access denied)
|
||||
SecurityLow = 1 // Unexceptional entries (i.e. successful access logs)
|
||||
)
|
||||
|
||||
// Common error messages
|
||||
const TokenVerificationError = "failed to verify the token"
|
||||
|
||||
var TokenVerificationErr = errors.New(TokenVerificationError)
|
||||
|
||||
@@ -335,7 +335,7 @@ func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]b
|
||||
}
|
||||
|
||||
if !ctrl.canProcessApp(obj) {
|
||||
// Don't force refresh app if app belongs to a different controller shard
|
||||
// Don't force refresh app if app belongs to a different controller shard or is outside the allowed namespaces.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1773,6 +1773,13 @@ func (ctrl *ApplicationController) canProcessApp(obj interface{}) bool {
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// Only process given app if it exists in a watched namespace, or in the
|
||||
// control plane's namespace.
|
||||
if app.Namespace != ctrl.namespace && !glob.MatchStringInList(ctrl.applicationNamespaces, app.Namespace, false) {
|
||||
return false
|
||||
}
|
||||
|
||||
if ctrl.clusterFilter != nil {
|
||||
cluster, err := ctrl.db.GetCluster(context.Background(), app.Spec.Destination.Server)
|
||||
if err != nil {
|
||||
@@ -1781,12 +1788,6 @@ func (ctrl *ApplicationController) canProcessApp(obj interface{}) bool {
|
||||
return ctrl.clusterFilter(cluster)
|
||||
}
|
||||
|
||||
// Only process given app if it exists in a watched namespace, or in the
|
||||
// control plane's namespace.
|
||||
if app.Namespace != ctrl.namespace && !glob.MatchStringInList(ctrl.applicationNamespaces, app.Namespace, false) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -1373,3 +1373,31 @@ func TestToAppKey(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_canProcessApp(t *testing.T) {
|
||||
app := newFakeApp()
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}})
|
||||
ctrl.applicationNamespaces = []string{"good"}
|
||||
t.Run("without cluster filter, good namespace", func(t *testing.T) {
|
||||
app.Namespace = "good"
|
||||
canProcess := ctrl.canProcessApp(app)
|
||||
assert.True(t, canProcess)
|
||||
})
|
||||
t.Run("without cluster filter, bad namespace", func(t *testing.T) {
|
||||
app.Namespace = "bad"
|
||||
canProcess := ctrl.canProcessApp(app)
|
||||
assert.False(t, canProcess)
|
||||
})
|
||||
t.Run("with cluster filter, good namespace", func(t *testing.T) {
|
||||
app.Namespace = "good"
|
||||
ctrl.clusterFilter = func(_ *argoappv1.Cluster) bool { return true }
|
||||
canProcess := ctrl.canProcessApp(app)
|
||||
assert.True(t, canProcess)
|
||||
})
|
||||
t.Run("with cluster filter, bad namespace", func(t *testing.T) {
|
||||
app.Namespace = "bad"
|
||||
ctrl.clusterFilter = func(_ *argoappv1.Cluster) bool { return true }
|
||||
canProcess := ctrl.canProcessApp(app)
|
||||
assert.False(t, canProcess)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ spec:
|
||||
* `repo`: Required name of the GitHub repository.
|
||||
* `api`: If using GitHub Enterprise, the URL to access it. (Optional)
|
||||
* `tokenRef`: A `Secret` name and key containing the GitHub access token to use for requests. If not specified, will make anonymous requests which have a lower rate limit and can only see public repositories. (Optional)
|
||||
* `labels`: Labels is used to filter the PRs that you want to target. (Optional)
|
||||
* `labels`: Filter the PRs to those containing **all** of the labels listed. (Optional)
|
||||
* `appSecretName`: A `Secret` name containing a GitHub App secret in [repo-creds format][repo-creds].
|
||||
|
||||
[repo-creds]: ../declarative-setup.md#repository-credentials
|
||||
|
||||
@@ -12,8 +12,9 @@ The Progressive Rollouts feature set is intended to be light and flexible. The f
|
||||
|
||||
## Enabling Progressive Rollouts
|
||||
As an experimental feature, progressive rollouts must be explicitly enabled, in one of these ways.
|
||||
|
||||
1. Pass `--enable-progressive-rollouts` to the ApplicationSet controller args.
|
||||
1. Set `ARGOCD_APPLICATIONSET_ENABLE_PROGRESSIVE_ROLLOUTS=true` in the ApplicationSet controller environment variables.
|
||||
1. Set `ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS=true` in the ApplicationSet controller environment variables.
|
||||
1. Set `applicationsetcontroller.enable.progressive.rollouts: true` in the ArgoCD ConfigMap.
|
||||
|
||||
## Strategies
|
||||
@@ -46,6 +47,7 @@ When the ApplicationSet changes, the changes will be applied to each group of Ap
|
||||
The following example illustrates how to stage a progressive rollout over Applications with explicitly configured environment labels.
|
||||
|
||||
Once a change is pushed, the following will happen in order.
|
||||
|
||||
* All `env-dev` Applications will be updated simultaneously.
|
||||
* The rollout will wait for all `env-qa` Applications to be manually synced via the `argocd` CLI or by clicking the Sync button in the UI.
|
||||
* 10% of all `env-prod` Applications will be updated at a time until all `env-prod` Applications have been updated.
|
||||
|
||||
@@ -47,7 +47,7 @@ data:
|
||||
help.download.windows-amd64: "path-or-url-to-download"
|
||||
|
||||
# A dex connector configuration (optional). See SSO configuration documentation:
|
||||
# https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/sso
|
||||
# https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/user-management/index.md#sso
|
||||
# https://dexidp.io/docs/connectors/
|
||||
dex.config: |
|
||||
connectors:
|
||||
@@ -330,4 +330,4 @@ data:
|
||||
resource.links: |
|
||||
- url: https://mycompany.splunk.com?search={{.metadata.namespace}}
|
||||
title: Splunk
|
||||
if: kind == "Pod" || kind == "Deployment"
|
||||
if: kind == "Pod" || kind == "Deployment"
|
||||
|
||||
@@ -26,14 +26,14 @@ There are two ways to install a Config Management Plugin:
|
||||
2. Add the plugin as a sidecar to the repo-server Pod.
|
||||
This is a good option for a more complex plugin that would clutter the Argo CD ConfigMap. A copy of the repository is
|
||||
sent to the sidecar container as a tarball and processed individually per application, which makes it a good option
|
||||
for [concurrent processing of monorepos](../operator-manual/high_availability.md#enable-concurrent-processing).
|
||||
for [concurrent processing of monorepos](high_availability.md#enable-concurrent-processing).
|
||||
|
||||
### Option 1: Configure plugins via Argo CD configmap (deprecated)
|
||||
|
||||
The following changes are required to configure a new plugin:
|
||||
|
||||
1. Make sure required binaries are available in `argocd-repo-server` pod. The binaries can be added via volume mounts or
|
||||
using a custom image (see [custom_tools](../operator-manual/custom_tools.md) for examples of both).
|
||||
using a custom image (see [custom_tools](custom_tools.md) for examples of both).
|
||||
2. Register a new plugin in `argocd-cm` ConfigMap:
|
||||
|
||||
:::yaml
|
||||
@@ -246,7 +246,7 @@ volumes:
|
||||
Plugin commands have access to
|
||||
|
||||
1. The system environment variables (of the repo-server container for argocd-cm plugins or of the sidecar for sidecar plugins)
|
||||
2. [Standard build environment variables](build-environment.md)
|
||||
2. [Standard build environment variables](../user-guide/build-environment.md)
|
||||
3. Variables in the Application spec (References to system and build variables will get interpolated in the variables' values):
|
||||
|
||||
```yaml
|
||||
@@ -7,7 +7,7 @@ other than what Argo CD bundles. Some reasons to do this might be:
|
||||
* To upgrade/downgrade to a specific version of a tool due to bugs or bug fixes.
|
||||
* To install additional dependencies to be used by kustomize's configmap/secret generators.
|
||||
(e.g. curl, vault, gpg, AWS CLI)
|
||||
* To install a [config management plugin](../user-guide/config-management-plugins.md).
|
||||
* To install a [config management plugin](config-management-plugins.md).
|
||||
|
||||
As the Argo CD repo-server is the single service responsible for generating Kubernetes manifests, it
|
||||
can be customized to use alternative toolchain required by your environment.
|
||||
@@ -51,7 +51,7 @@ following example builds an entirely customized repo-server from a Dockerfile, i
|
||||
dependencies that may be needed for generating manifests.
|
||||
|
||||
```Dockerfile
|
||||
FROM argoproj/argocd:latest
|
||||
FROM argoproj/argocd:v2.5.4 # Replace tag with the appropriate argo version
|
||||
|
||||
# Switch to root for the ability to perform install
|
||||
USER root
|
||||
|
||||
63
docs/operator-manual/deep_links.md
Normal file
63
docs/operator-manual/deep_links.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Deep Links
|
||||
|
||||
Deep links allow users to quickly redirect to third-party systems, such as Splunk, Datadog, etc. from the Argo CD
|
||||
user interface.
|
||||
|
||||
Argo CD administrator will be able to configure links to third-party systems by providing
|
||||
deep link templates configured in `argocd-cm`. The templates can be conditionally rendered and are able
|
||||
to reference different types of resources relating to where the links show up, this includes projects, applications,
|
||||
or individual resources (pods, services, etc.).
|
||||
|
||||
## Configuring Deep Links
|
||||
|
||||
The configuration for Deep Links is present in `argocd-cm` as `<location>.links` fields where
|
||||
`<location>` determines where it will be displayed. The possible values for `<location>` are :
|
||||
- `project` : all links under this field will show up in the project tab in the Argo CD UI
|
||||
- `application` : all links under this field will show up in the application summary tab
|
||||
- `resource` : all links under this field will show up in the resource (deployments, pods, services, etc.) summary tab
|
||||
|
||||
Each link in the list has five subfields :
|
||||
1. `title` : title/tag that will be displayed in the UI corresponding to that link
|
||||
2. `url` : the actual URL where the deep link will redirect to, this field can be templated to use data from the
|
||||
corresponing application, project or resource objects (depending on where it is located). This uses [text/template](pkg.go.dev/text/template) pkg for templating
|
||||
3. `description` (optional) : a description for what the deep link is about
|
||||
4. `icon.class` (optional) : a font-awesome icon class to be used when displaying the links in dropdown menus
|
||||
5. `if` (optional) : a conditional statement that results in either `true` or `false`, it also has access to the same
|
||||
data as the `url` field. If the condition resolves to `true` the deep link will be displayed - else it will be hidden. If
|
||||
the field is omitted, by default the deep links will be displayed. This uses [antonmedv/expr](https://github.com/antonmedv/expr/tree/master/docs) for evaluating conditions
|
||||
|
||||
!!!note
|
||||
For resources of kind Secret the data fields are redacted but other fields are accessible for templating the deep links.
|
||||
|
||||
!!!warning
|
||||
Make sure to validate the url templates and inputs to prevent data leaks or possible generation of any malicious links.
|
||||
|
||||
|
||||
An example `argocd-cm.yaml` file with deep links and their variations :
|
||||
|
||||
```yaml
|
||||
# sample project level links
|
||||
project.links: |
|
||||
- url: https://myaudit-system.com?project={{.metadata.name}}
|
||||
title: Audit
|
||||
description: system audit logs
|
||||
icon.class: "fa-book"
|
||||
# sample application level links
|
||||
application.links: |
|
||||
# pkg.go.dev/text/template is used for evaluating url templates
|
||||
- url: https://mycompany.splunk.com?search={{.spec.destination.namespace}}
|
||||
title: Splunk
|
||||
# conditionally show link e.g. for specific project
|
||||
# github.com/antonmedv/expr is used for evaluation of conditions
|
||||
- url: https://mycompany.splunk.com?search={{.spec.destination.namespace}}
|
||||
title: Splunk
|
||||
if: spec.project == "default"
|
||||
- url: https://{{.metadata.annotations.splunkhost}}?search={{.spec.destination.namespace}}
|
||||
title: Splunk
|
||||
if: metadata.annotations.splunkhost
|
||||
# sample resource level links
|
||||
resource.links: |
|
||||
- url: https://mycompany.splunk.com?search={{.metadata.namespace}}
|
||||
title: Splunk
|
||||
if: kind == "Pod" || kind == "Deployment"
|
||||
```
|
||||
@@ -16,6 +16,8 @@ with at least one value for `hostname` or `IP`.
|
||||
### Ingress
|
||||
* The `status.loadBalancer.ingress` list is non-empty, with at least one value for `hostname` or `IP`.
|
||||
|
||||
### Job
|
||||
* If job `.spec.suspended` is set to 'true', then the job and app health will be marked as suspended.
|
||||
### PersistentVolumeClaim
|
||||
* The `status.phase` is `Bound`
|
||||
|
||||
@@ -38,7 +40,7 @@ metadata:
|
||||
data:
|
||||
resource.customizations: |
|
||||
argoproj.io/Application:
|
||||
health.lua: |
|
||||
health.lua: |
|
||||
hs = {}
|
||||
hs.status = "Progressing"
|
||||
hs.message = ""
|
||||
@@ -64,11 +66,11 @@ There are two ways to configure a custom health check. The next two sections des
|
||||
|
||||
### Way 1. Define a Custom Health Check in `argocd-cm` ConfigMap
|
||||
|
||||
Custom health checks can be defined in
|
||||
Custom health checks can be defined in
|
||||
```yaml
|
||||
resource.customizations: |
|
||||
<group/kind>:
|
||||
health.lua: |
|
||||
health.lua: |
|
||||
```
|
||||
field of `argocd-cm`. If you are using argocd-operator, this is overridden by [the argocd-operator resourceCustomizations](https://argocd-operator.readthedocs.io/en/latest/reference/argocd/#resource-customizations).
|
||||
|
||||
@@ -101,15 +103,24 @@ data:
|
||||
hs.message = "Waiting for certificate"
|
||||
return hs
|
||||
```
|
||||
In order to prevent duplication of the same custom health check for potentially multiple resources, it is also possible to specify a wildcard in the resource kind, like this:
|
||||
In order to prevent duplication of the custom health check for potentially multiple resources, it is also possible to specify a wildcard in the resource kind, and anywhere in the resource group, like this:
|
||||
|
||||
```yaml
|
||||
resource.customizations: |
|
||||
ec2.aws.crossplane.io/*:
|
||||
health.lua: |
|
||||
...
|
||||
```
|
||||
|
||||
```yaml
|
||||
resource.customizations: |
|
||||
*.aws.crossplane.io/*:
|
||||
health.lua: |
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
|
||||
The `obj` is a global variable which contains the resource. The script must return an object with status and optional message field.
|
||||
The custom health check might return one of the following health statuses:
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ A set of HA manifests are provided for users who wish to run Argo CD in a highly
|
||||
|
||||
[Manifests ⧉](https://github.com/argoproj/argo-cd/tree/master/manifests)
|
||||
|
||||
!!! note
|
||||
The HA installation will require at least three different nodes due to pod anti-affinity roles in the specs.
|
||||
> **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.
|
||||
|
||||
## Scaling Up
|
||||
|
||||
@@ -188,4 +188,4 @@ spec:
|
||||
targetRevision: HEAD
|
||||
path: my-application
|
||||
# ...
|
||||
```
|
||||
```
|
||||
@@ -15,9 +15,11 @@ spec:
|
||||
- '*'
|
||||
|
||||
# Only permit applications to deploy to the guestbook namespace in the same cluster
|
||||
# Destination clusters can be identified by 'server', 'name', or both.
|
||||
destinations:
|
||||
- namespace: guestbook
|
||||
server: https://kubernetes.default.svc
|
||||
name: in-cluster
|
||||
|
||||
# Deny all cluster-scoped resources from being created, except for Namespace
|
||||
clusterResourceWhitelist:
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
# Secret Management
|
||||
|
||||
Argo CD is un-opinionated about how secrets are managed. There's many ways to do it and there's no one-size-fits-all solution. Here's some ways people are doing GitOps secrets:
|
||||
Argo CD is un-opinionated about how secrets are managed. There are many ways to do it, and there's no one-size-fits-all solution.
|
||||
|
||||
Many solutions use plugins to inject secrets into the application manifests. See [Mitigating Risks of Secret-Injection Plugins](#mitigating-risks-of-secret-injection-plugins)
|
||||
below to make sure you use those plugins securely.
|
||||
|
||||
Here are some ways people are doing GitOps secrets:
|
||||
|
||||
* [Bitnami Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets)
|
||||
* [External Secrets Operator](https://github.com/external-secrets/external-secrets)
|
||||
@@ -15,3 +20,17 @@ Argo CD is un-opinionated about how secrets are managed. There's many ways to do
|
||||
* [Kubernetes Secrets Store CSI Driver](https://github.com/kubernetes-sigs/secrets-store-csi-driver)
|
||||
|
||||
For discussion, see [#1364](https://github.com/argoproj/argo-cd/issues/1364)
|
||||
|
||||
## Mitigating Risks of Secret-Injection Plugins
|
||||
|
||||
Argo CD caches the manifests generated by plugins, along with the injected secrets, in its Redis instance. Those
|
||||
manifests are also available via the repo-server API (a gRPC service). This means that the secrets are available to
|
||||
anyone who has access to the Redis instance or to the repo-server.
|
||||
|
||||
Consider these steps to mitigate the risks of secret-injection plugins:
|
||||
|
||||
1. Set up network policies to prevent direct access to Argo CD components (Redis and the repo-server). Make sure your
|
||||
cluster supports those network policies and can actually enforce them.
|
||||
2. Consider running Argo CD on its own cluster, with no other applications running on it.
|
||||
3. [Enable password authentication on the Redis instance](https://github.com/argoproj/argo-cd/issues/3130) (currently
|
||||
only supported for non-HA Argo CD installations).
|
||||
|
||||
@@ -36,7 +36,7 @@ data:
|
||||
|
||||
## Removed Python from the base image
|
||||
|
||||
If you are using a [Config Management Plugin](../../user-guide/config-management-plugins.md) that relies on Python, you
|
||||
If you are using a [Config Management Plugin](../config-management-plugins.md) that relies on Python, you
|
||||
will need to build a custom image on the Argo CD base to install Python.
|
||||
|
||||
## Upgraded Kustomize Version
|
||||
|
||||
@@ -176,7 +176,7 @@ that uses the Service Account for auth), be sure to test before deploying the 2.
|
||||
|
||||
### Remove the shared volume from any sidecar plugins
|
||||
|
||||
As a security enhancement, [sidecar plugins](../../user-guide/config-management-plugins.md#option-2-configure-plugin-via-sidecar)
|
||||
As a security enhancement, [sidecar plugins](../config-management-plugins.md#option-2-configure-plugin-via-sidecar)
|
||||
no longer share the /tmp directory with the repo-server.
|
||||
|
||||
If you have one or more sidecar plugins enabled, replace the /tmp volume mount for each sidecar to use a volume specific
|
||||
|
||||
@@ -6,3 +6,18 @@ Argo CD 2.5 introduced [Go templating in ApplicationSets](https://argo-cd.readth
|
||||
Argo CD 2.6 upgrades Sprig to v3. That upgrade includes an upgrade of [Masterminds/semver](https://github.com/Masterminds/semver/releases) to v3.
|
||||
|
||||
Masterminds/semver v3 changed the behavior of the `^` prefix in semantic version constraints. If you are using Go-templated ApplicationSets which include references to [Sprig's semver functions](https://masterminds.github.io/sprig/semver.html) and use the `^` prefix, read the [Masterminds/semver changelog](https://github.com/Masterminds/semver/releases/tag/v3.0.0) to understand how your ApplicationSets' behavior may change.
|
||||
|
||||
## Applications with suspended jobs now marked "Suspended" instead of "Progressing"
|
||||
Prior to Argo CD v2.6, an Application managing a suspended Job would be marked as "Progressing". This was confusing/unexpected behavior for many. Starting with v2.6, Argo CD will mark such Applications as "Suspended".
|
||||
|
||||
If you have processes which rely on the previous behavior (for example, a CI job with an argocd app wait call), update those before upgrading to v2.6.
|
||||
|
||||
## The API Server now requires tokens to include the `aud` claim by default
|
||||
|
||||
Argo CD v2.6 now requires that the `aud` claim be present in the token used to authenticate to the API Server. This is a
|
||||
security improvement, as it prevents tokens from being used against the API Server which were not intended for it.
|
||||
|
||||
If you rely on an OIDC provider which does not provide a `aud` claim, you can disable this requirement by setting the
|
||||
`skipAudienceCheckWhenTokenHasNoAudience` flag to `true` in your Argo CD OIDC configuration. (See the
|
||||
[OIDC configuration documentation](https://argo-cd.readthedocs.io/en/stable/operator-manual/user-management/#existing-oidc-provider)
|
||||
for an example.)
|
||||
|
||||
@@ -301,6 +301,19 @@ data:
|
||||
issuer: https://dev-123456.oktapreview.com
|
||||
clientID: aaaabbbbccccddddeee
|
||||
clientSecret: $oidc.okta.clientSecret
|
||||
|
||||
# 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
|
||||
- qqqqwwwweeeerrrrttt
|
||||
|
||||
# Optional. If false, tokens without an audience will always fail validation. If true, tokens without an audience
|
||||
# will always pass validation.
|
||||
# Defaults to true for Argo CD < 2.6.0. Defaults to false for Argo CD >= 2.6.0.
|
||||
skipAudienceCheckWhenTokenHasNoAudience: true
|
||||
|
||||
# Optional set of OIDC scopes to request. If omitted, defaults to: ["openid", "profile", "email", "groups"]
|
||||
requestedScopes: ["openid", "profile", "email", "groups"]
|
||||
|
||||
@@ -7,7 +7,7 @@ Argo CD supports several different ways in which Kubernetes manifests can be def
|
||||
* [Kustomize](kustomize.md) applications
|
||||
* [Helm](helm.md) charts
|
||||
* A directory of YAML/JSON/Jsonnet manifests, including [Jsonnet](jsonnet.md).
|
||||
* Any [custom config management tool](config-management-plugins.md) configured as a config management plugin
|
||||
* Any [custom config management tool](../operator-manual/config-management-plugins.md) configured as a config management plugin
|
||||
|
||||
## Development
|
||||
Argo CD also supports uploading local manifests directly. Since this is an anti-pattern of the
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Build Environment
|
||||
|
||||
[Custom tools](config-management-plugins.md), [Helm](helm.md), [Jsonnet](jsonnet.md), and [Kustomize](kustomize.md) support the following build env vars:
|
||||
[Custom tools](../operator-manual/config-management-plugins.md), [Helm](helm.md), [Jsonnet](jsonnet.md), and [Kustomize](kustomize.md) support the following build env vars:
|
||||
|
||||
| Variable | Description |
|
||||
| ----------------------------------- | ----------------------------------------------------------------------- |
|
||||
|
||||
@@ -69,7 +69,7 @@ spec:
|
||||
source:
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps.git
|
||||
targetRevision: HEAD
|
||||
path: guestbook-kustomize
|
||||
path: kustomize-guestbook
|
||||
|
||||
kustomize:
|
||||
version: v3.5.4
|
||||
@@ -84,7 +84,7 @@ argocd app set <appName> --kustomize-version v3.5.4
|
||||
|
||||
## Build Environment
|
||||
|
||||
Kustomize apps have access to the [standard build environment](build-environment.md) which can be used in combination with a [config managment plugin](config-management-plugins.md) to alter the rendered manifests.
|
||||
Kustomize apps have access to the [standard build environment](build-environment.md) which can be used in combination with a [config managment plugin](../operator-manual/config-management-plugins.md) to alter the rendered manifests.
|
||||
|
||||
## Kustomizing Helm charts
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ spec:
|
||||
sources:
|
||||
- chart: elasticsearch
|
||||
repoURL: https://helm.elastic.co
|
||||
targetRevision: 7.6.0
|
||||
targetRevision: 8.5.1
|
||||
- repoURL: https://github.com/argoproj/argocd-example-apps.git
|
||||
path: guestbook
|
||||
targetRevision: HEAD
|
||||
|
||||
@@ -33,9 +33,11 @@ Otherwise it is assumed to be a plain **directory** application.
|
||||
|
||||
## Disable built-in tools
|
||||
|
||||
Optionally built-in config management tools might be disabled. In order to disable the tool add one of the following
|
||||
keys to the `argocd-cm` ConfigMap: `kustomize.enable`, `helm.enable` or `jsonnet.enable`. Once the
|
||||
tool is disabled Argo CD will assume the application target directory contains plain Kubernetes YAML manifests.
|
||||
Built-in config management tools can be optionally disabled by setting one of the following
|
||||
keys, in the `argocd-cm` ConfigMap, to `false`: `kustomize.enable`, `helm.enable` or `jsonnet.enable`. Once the
|
||||
tool is disabled, Argo CD will assume the application target directory contains plain Kubernetes YAML manifests.
|
||||
|
||||
Disabling unused config management tools can be a helpful security enhancement. Vulnerabilities are sometimes limited to certain config management tools. Even if there is no vulnerability, an attacker may use a certain tool to take advantage of a misconfiguration in an Argo CD instance. Disabling unused config management tools limits the tools available to malicious actors.
|
||||
|
||||
## References
|
||||
|
||||
|
||||
12
go.mod
12
go.mod
@@ -8,7 +8,7 @@ require (
|
||||
github.com/Masterminds/semver/v3 v3.2.0
|
||||
github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d
|
||||
github.com/alicebob/miniredis/v2 v2.23.1
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20221108210551-e284fd71cb96
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20221208230615-917f5a0f16d5
|
||||
github.com/argoproj/notifications-engine v0.3.1-0.20221203221941-490d98afd1d6
|
||||
github.com/argoproj/pkg v0.13.7-0.20221115212233-27bd8ce31415
|
||||
github.com/aws/aws-sdk-go v1.44.156
|
||||
@@ -74,10 +74,10 @@ require (
|
||||
github.com/xanzy/go-gitlab v0.60.0
|
||||
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
|
||||
golang.org/x/net v0.1.0 // indirect
|
||||
golang.org/x/net v0.4.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
|
||||
golang.org/x/term v0.1.0
|
||||
golang.org/x/term v0.3.0
|
||||
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368
|
||||
google.golang.org/grpc v1.51.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
@@ -101,7 +101,7 @@ require (
|
||||
require (
|
||||
github.com/gfleury/go-bitbucket-v1 v0.0.0-20220301131131-8e7ed04b843e
|
||||
github.com/stretchr/objx v0.5.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0
|
||||
k8s.io/apiserver v0.24.2
|
||||
)
|
||||
|
||||
@@ -232,8 +232,8 @@ require (
|
||||
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.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/sys v0.3.0 // indirect
|
||||
golang.org/x/text v0.5.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45 // indirect
|
||||
|
||||
16
go.sum
16
go.sum
@@ -137,8 +137,8 @@ github.com/antonmedv/expr v1.9.0/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmH
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/appscode/go v0.0.0-20191119085241-0887d8ec2ecc/go.mod h1:OawnOmAL4ZX3YaPdN+8HTNwBveT1jMsqP74moa9XUbE=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20221108210551-e284fd71cb96 h1:4CQn3gY9aAsQwHWGnADGyfGfBjE+yEw4zoy5SN7uuZc=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20221108210551-e284fd71cb96/go.mod h1:WpA/B7tgwfz+sdNE3LqrTrb7ArEY1FOPI2pAGI0hfPc=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20221208230615-917f5a0f16d5 h1:iRpHi7X3q9G55KTaMjxKicgNnS2blFHaEfOOgsmP8lE=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20221208230615-917f5a0f16d5/go.mod h1:WpA/B7tgwfz+sdNE3LqrTrb7ArEY1FOPI2pAGI0hfPc=
|
||||
github.com/argoproj/notifications-engine v0.3.1-0.20221203221941-490d98afd1d6 h1:b92Xft7MQv/SP56FW08zt5CMTE1rySH8UPDKOAgSzOM=
|
||||
github.com/argoproj/notifications-engine v0.3.1-0.20221203221941-490d98afd1d6/go.mod h1:pgPU59KCsBOMhyw9amRWPoSuBmUWvx3Xsc5r0mUriLg=
|
||||
github.com/argoproj/pkg v0.13.7-0.20221115212233-27bd8ce31415 h1:/5UtDHntvwPxbe/j2+xmQgvG83PQueGHko+9sf8+FA0=
|
||||
@@ -1340,8 +1340,9 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
|
||||
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
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=
|
||||
@@ -1486,12 +1487,14 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.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/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
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=
|
||||
@@ -1501,8 +1504,9 @@ 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/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.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=
|
||||
|
||||
@@ -86,6 +86,12 @@ spec:
|
||||
key: applicationsetcontroller.enable.git.submodule
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.enable.progressive.rollouts
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
volumeMounts:
|
||||
- mountPath: /app/config/ssh
|
||||
name: ssh-known-hosts
|
||||
|
||||
@@ -5,7 +5,7 @@ kind: Kustomization
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: latest
|
||||
newTag: v2.6.0-rc6
|
||||
resources:
|
||||
- ./application-controller
|
||||
- ./dex
|
||||
|
||||
@@ -23,7 +23,7 @@ spec:
|
||||
serviceAccountName: argocd-redis
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: Always
|
||||
args:
|
||||
- "--save"
|
||||
|
||||
@@ -5476,7 +5476,6 @@ spec:
|
||||
- spec
|
||||
type: object
|
||||
required:
|
||||
- pathParamPrefix
|
||||
- repoURL
|
||||
- revision
|
||||
type: object
|
||||
@@ -7367,7 +7366,6 @@ spec:
|
||||
- spec
|
||||
type: object
|
||||
required:
|
||||
- pathParamPrefix
|
||||
- repoURL
|
||||
- revision
|
||||
type: object
|
||||
@@ -10916,7 +10914,6 @@ spec:
|
||||
- spec
|
||||
type: object
|
||||
required:
|
||||
- pathParamPrefix
|
||||
- repoURL
|
||||
- revision
|
||||
type: object
|
||||
@@ -15551,7 +15548,13 @@ spec:
|
||||
key: applicationsetcontroller.enable.git.submodule
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.enable.progressive.rollouts
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -15633,7 +15636,7 @@ spec:
|
||||
- ""
|
||||
- --appendonly
|
||||
- "no"
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -15815,7 +15818,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -15867,7 +15870,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -16074,7 +16077,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -12,4 +12,4 @@ resources:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: latest
|
||||
newTag: v2.6.0-rc6
|
||||
|
||||
@@ -1462,7 +1462,6 @@ spec:
|
||||
- spec
|
||||
type: object
|
||||
required:
|
||||
- pathParamPrefix
|
||||
- repoURL
|
||||
- revision
|
||||
type: object
|
||||
@@ -3353,7 +3352,6 @@ spec:
|
||||
- spec
|
||||
type: object
|
||||
required:
|
||||
- pathParamPrefix
|
||||
- repoURL
|
||||
- revision
|
||||
type: object
|
||||
@@ -6902,7 +6900,6 @@ spec:
|
||||
- spec
|
||||
type: object
|
||||
required:
|
||||
- pathParamPrefix
|
||||
- repoURL
|
||||
- revision
|
||||
type: object
|
||||
|
||||
@@ -11,7 +11,7 @@ patchesStrategicMerge:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: latest
|
||||
newTag: v2.6.0-rc6
|
||||
resources:
|
||||
- ../../base/application-controller
|
||||
- ../../base/applicationset-controller
|
||||
|
||||
@@ -41,6 +41,7 @@ data:
|
||||
port 6379
|
||||
rename-command FLUSHDB ""
|
||||
rename-command FLUSHALL ""
|
||||
bind 0.0.0.0
|
||||
maxmemory 0
|
||||
maxmemory-policy volatile-lru
|
||||
min-replicas-max-lag 5
|
||||
@@ -53,6 +54,7 @@ data:
|
||||
sentinel.conf: |
|
||||
dir "/data"
|
||||
port 26379
|
||||
bind 0.0.0.0
|
||||
sentinel down-after-milliseconds argocd 10000
|
||||
sentinel failover-timeout argocd 180000
|
||||
maxclients 10000
|
||||
@@ -618,7 +620,7 @@ data:
|
||||
timeout check 2s
|
||||
|
||||
listen health_check_http_url
|
||||
bind [::]:8888 v4v6
|
||||
bind :8888
|
||||
mode http
|
||||
monitor-uri /healthz
|
||||
option dontlognull
|
||||
@@ -665,7 +667,7 @@ data:
|
||||
# decide redis backend to use
|
||||
#master
|
||||
frontend ft_redis_master
|
||||
bind [::]:6379 v4v6
|
||||
bind :6379
|
||||
use_backend bk_redis_master
|
||||
# Check all redis servers to see if they think they are master
|
||||
backend bk_redis_master
|
||||
@@ -1045,7 +1047,7 @@ spec:
|
||||
release: argocd
|
||||
revision: "1"
|
||||
annotations:
|
||||
checksum/config: 1f7a9ffcacb3871ceb9b0741c0714e3f7fa656d426a398c1f727fffb01073f35
|
||||
checksum/config: 718bbb277da8610063a7c0fd810984577c2e8ab215815a71211dfa6e20f67321
|
||||
spec:
|
||||
# Needed when using unmodified rbac-setup.yml
|
||||
|
||||
@@ -1153,7 +1155,7 @@ spec:
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/init-config: 84ccf6a9b8a7fa3ae5b62a8f17d6c65a5197e9605da9b2761179bf942828eefe
|
||||
checksum/init-config: 69130412bda04eacad3530cb7bcf26cf121401e725e15d0959dd71a7380afe75
|
||||
labels:
|
||||
release: argocd
|
||||
app: redis-ha
|
||||
@@ -1177,7 +1179,7 @@ spec:
|
||||
automountServiceAccountToken: false
|
||||
initContainers:
|
||||
- name: config-init
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
{}
|
||||
@@ -1204,7 +1206,7 @@ spec:
|
||||
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- redis-server
|
||||
@@ -1254,7 +1256,7 @@ spec:
|
||||
- /bin/sh
|
||||
- /readonly-config/trigger-failover-if-master.sh
|
||||
- name: sentinel
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- redis-sentinel
|
||||
@@ -1298,7 +1300,7 @@ spec:
|
||||
{}
|
||||
|
||||
- name: split-brain-fix
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- sh
|
||||
|
||||
@@ -5,8 +5,11 @@ redis-ha:
|
||||
masterGroupName: argocd
|
||||
config:
|
||||
save: "\"\""
|
||||
bind: "0.0.0.0"
|
||||
haproxy:
|
||||
enabled: true
|
||||
IPv6:
|
||||
enabled: false
|
||||
image:
|
||||
tag: 2.6.2-alpine
|
||||
containerSecurityContext: null
|
||||
@@ -15,5 +18,7 @@ redis-ha:
|
||||
client: 6m
|
||||
checkInterval: 3s
|
||||
image:
|
||||
tag: 7.0.5-alpine
|
||||
tag: 7.0.7-alpine
|
||||
containerSecurityContext: null
|
||||
sentinel:
|
||||
bind: "0.0.0.0"
|
||||
|
||||
@@ -5476,7 +5476,6 @@ spec:
|
||||
- spec
|
||||
type: object
|
||||
required:
|
||||
- pathParamPrefix
|
||||
- repoURL
|
||||
- revision
|
||||
type: object
|
||||
@@ -7367,7 +7366,6 @@ spec:
|
||||
- spec
|
||||
type: object
|
||||
required:
|
||||
- pathParamPrefix
|
||||
- repoURL
|
||||
- revision
|
||||
type: object
|
||||
@@ -10916,7 +10914,6 @@ spec:
|
||||
- spec
|
||||
type: object
|
||||
required:
|
||||
- pathParamPrefix
|
||||
- repoURL
|
||||
- revision
|
||||
type: object
|
||||
@@ -15943,81 +15940,38 @@ data:
|
||||
fi
|
||||
fi
|
||||
done
|
||||
haproxy.cfg: |
|
||||
defaults REDIS
|
||||
mode tcp
|
||||
timeout connect 4s
|
||||
timeout server 6m
|
||||
timeout client 6m
|
||||
timeout check 2s
|
||||
|
||||
listen health_check_http_url
|
||||
bind [::]:8888 v4v6
|
||||
mode http
|
||||
monitor-uri /healthz
|
||||
option dontlognull
|
||||
# Check Sentinel and whether they are nominated master
|
||||
backend check_if_redis_is_master_0
|
||||
mode tcp
|
||||
option tcp-check
|
||||
tcp-check connect
|
||||
tcp-check send PING\r\n
|
||||
tcp-check expect string +PONG
|
||||
tcp-check send SENTINEL\ get-master-addr-by-name\ argocd\r\n
|
||||
tcp-check expect string REPLACE_ANNOUNCE0
|
||||
tcp-check send QUIT\r\n
|
||||
server R0 argocd-redis-ha-announce-0:26379 check inter 3s
|
||||
server R1 argocd-redis-ha-announce-1:26379 check inter 3s
|
||||
server R2 argocd-redis-ha-announce-2:26379 check inter 3s
|
||||
# Check Sentinel and whether they are nominated master
|
||||
backend check_if_redis_is_master_1
|
||||
mode tcp
|
||||
option tcp-check
|
||||
tcp-check connect
|
||||
tcp-check send PING\r\n
|
||||
tcp-check expect string +PONG
|
||||
tcp-check send SENTINEL\ get-master-addr-by-name\ argocd\r\n
|
||||
tcp-check expect string REPLACE_ANNOUNCE1
|
||||
tcp-check send QUIT\r\n
|
||||
server R0 argocd-redis-ha-announce-0:26379 check inter 3s
|
||||
server R1 argocd-redis-ha-announce-1:26379 check inter 3s
|
||||
server R2 argocd-redis-ha-announce-2:26379 check inter 3s
|
||||
# Check Sentinel and whether they are nominated master
|
||||
backend check_if_redis_is_master_2
|
||||
mode tcp
|
||||
option tcp-check
|
||||
tcp-check connect
|
||||
tcp-check send PING\r\n
|
||||
tcp-check expect string +PONG
|
||||
tcp-check send SENTINEL\ get-master-addr-by-name\ argocd\r\n
|
||||
tcp-check expect string REPLACE_ANNOUNCE2
|
||||
tcp-check send QUIT\r\n
|
||||
server R0 argocd-redis-ha-announce-0:26379 check inter 3s
|
||||
server R1 argocd-redis-ha-announce-1:26379 check inter 3s
|
||||
server R2 argocd-redis-ha-announce-2:26379 check inter 3s
|
||||
|
||||
# decide redis backend to use
|
||||
#master
|
||||
frontend ft_redis_master
|
||||
bind [::]:6379 v4v6
|
||||
use_backend bk_redis_master
|
||||
# Check all redis servers to see if they think they are master
|
||||
backend bk_redis_master
|
||||
mode tcp
|
||||
option tcp-check
|
||||
tcp-check connect
|
||||
tcp-check send PING\r\n
|
||||
tcp-check expect string +PONG
|
||||
tcp-check send info\ replication\r\n
|
||||
tcp-check expect string role:master
|
||||
tcp-check send QUIT\r\n
|
||||
tcp-check expect string +OK
|
||||
use-server R0 if { srv_is_up(R0) } { nbsrv(check_if_redis_is_master_0) ge 2 }
|
||||
server R0 argocd-redis-ha-announce-0:6379 check inter 3s fall 1 rise 1
|
||||
use-server R1 if { srv_is_up(R1) } { nbsrv(check_if_redis_is_master_1) ge 2 }
|
||||
server R1 argocd-redis-ha-announce-1:6379 check inter 3s fall 1 rise 1
|
||||
use-server R2 if { srv_is_up(R2) } { nbsrv(check_if_redis_is_master_2) ge 2 }
|
||||
server R2 argocd-redis-ha-announce-2:6379 check inter 3s fall 1 rise 1
|
||||
haproxy.cfg: "defaults REDIS\n mode tcp\n timeout connect 4s\n timeout server
|
||||
6m\n timeout client 6m\n timeout check 2s\n\nlisten health_check_http_url\n
|
||||
\ bind :8888 \n mode http\n monitor-uri /healthz\n option dontlognull\n#
|
||||
Check Sentinel and whether they are nominated master\nbackend check_if_redis_is_master_0\n
|
||||
\ mode tcp\n option tcp-check\n tcp-check connect\n tcp-check send PING\\r\\n\n
|
||||
\ tcp-check expect string +PONG\n tcp-check send SENTINEL\\ get-master-addr-by-name\\
|
||||
argocd\\r\\n\n tcp-check expect string REPLACE_ANNOUNCE0\n tcp-check send QUIT\\r\\n\n
|
||||
\ server R0 argocd-redis-ha-announce-0:26379 check inter 3s\n server R1 argocd-redis-ha-announce-1:26379
|
||||
check inter 3s\n server R2 argocd-redis-ha-announce-2:26379 check inter 3s\n#
|
||||
Check Sentinel and whether they are nominated master\nbackend check_if_redis_is_master_1\n
|
||||
\ mode tcp\n option tcp-check\n tcp-check connect\n tcp-check send PING\\r\\n\n
|
||||
\ tcp-check expect string +PONG\n tcp-check send SENTINEL\\ get-master-addr-by-name\\
|
||||
argocd\\r\\n\n tcp-check expect string REPLACE_ANNOUNCE1\n tcp-check send QUIT\\r\\n\n
|
||||
\ server R0 argocd-redis-ha-announce-0:26379 check inter 3s\n server R1 argocd-redis-ha-announce-1:26379
|
||||
check inter 3s\n server R2 argocd-redis-ha-announce-2:26379 check inter 3s\n#
|
||||
Check Sentinel and whether they are nominated master\nbackend check_if_redis_is_master_2\n
|
||||
\ mode tcp\n option tcp-check\n tcp-check connect\n tcp-check send PING\\r\\n\n
|
||||
\ tcp-check expect string +PONG\n tcp-check send SENTINEL\\ get-master-addr-by-name\\
|
||||
argocd\\r\\n\n tcp-check expect string REPLACE_ANNOUNCE2\n tcp-check send QUIT\\r\\n\n
|
||||
\ server R0 argocd-redis-ha-announce-0:26379 check inter 3s\n server R1 argocd-redis-ha-announce-1:26379
|
||||
check inter 3s\n server R2 argocd-redis-ha-announce-2:26379 check inter 3s\n\n#
|
||||
decide redis backend to use\n#master\nfrontend ft_redis_master\n bind :6379 \n
|
||||
\ use_backend bk_redis_master\n# Check all redis servers to see if they think
|
||||
they are master\nbackend bk_redis_master\n mode tcp\n option tcp-check\n tcp-check
|
||||
connect\n tcp-check send PING\\r\\n\n tcp-check expect string +PONG\n tcp-check
|
||||
send info\\ replication\\r\\n\n tcp-check expect string role:master\n tcp-check
|
||||
send QUIT\\r\\n\n tcp-check expect string +OK\n use-server R0 if { srv_is_up(R0)
|
||||
} { nbsrv(check_if_redis_is_master_0) ge 2 }\n server R0 argocd-redis-ha-announce-0:6379
|
||||
check inter 3s fall 1 rise 1\n use-server R1 if { srv_is_up(R1) } { nbsrv(check_if_redis_is_master_1)
|
||||
ge 2 }\n server R1 argocd-redis-ha-announce-1:6379 check inter 3s fall 1 rise
|
||||
1\n use-server R2 if { srv_is_up(R2) } { nbsrv(check_if_redis_is_master_2) ge
|
||||
2 }\n server R2 argocd-redis-ha-announce-2:6379 check inter 3s fall 1 rise 1\n"
|
||||
haproxy_init.sh: |
|
||||
HAPROXY_CONF=/data/haproxy.cfg
|
||||
cp /readonly/haproxy.cfg "$HAPROXY_CONF"
|
||||
@@ -16316,6 +16270,7 @@ data:
|
||||
port 6379
|
||||
rename-command FLUSHDB ""
|
||||
rename-command FLUSHALL ""
|
||||
bind 0.0.0.0
|
||||
maxmemory 0
|
||||
maxmemory-policy volatile-lru
|
||||
min-replicas-max-lag 5
|
||||
@@ -16327,6 +16282,7 @@ data:
|
||||
sentinel.conf: |
|
||||
dir "/data"
|
||||
port 26379
|
||||
bind 0.0.0.0
|
||||
sentinel down-after-milliseconds argocd 10000
|
||||
sentinel failover-timeout argocd 180000
|
||||
maxclients 10000
|
||||
@@ -16793,7 +16749,13 @@ spec:
|
||||
key: applicationsetcontroller.enable.git.submodule
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.enable.progressive.rollouts
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -16903,7 +16865,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -16956,7 +16918,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -17014,7 +16976,7 @@ spec:
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/config: 1f7a9ffcacb3871ceb9b0741c0714e3f7fa656d426a398c1f727fffb01073f35
|
||||
checksum/config: 718bbb277da8610063a7c0fd810984577c2e8ab215815a71211dfa6e20f67321
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-redis-ha-haproxy
|
||||
name: argocd-redis-ha-haproxy
|
||||
@@ -17259,7 +17221,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -17311,7 +17273,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -17590,7 +17552,7 @@ spec:
|
||||
key: server.enable.proxy.extension
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -17826,7 +17788,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
@@ -17886,7 +17848,7 @@ spec:
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/init-config: 84ccf6a9b8a7fa3ae5b62a8f17d6c65a5197e9605da9b2761179bf942828eefe
|
||||
checksum/init-config: 69130412bda04eacad3530cb7bcf26cf121401e725e15d0959dd71a7380afe75
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-redis-ha
|
||||
spec:
|
||||
@@ -17903,7 +17865,7 @@ spec:
|
||||
- /data/conf/redis.conf
|
||||
command:
|
||||
- redis-server
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
preStop:
|
||||
@@ -17956,7 +17918,7 @@ spec:
|
||||
- /data/conf/sentinel.conf
|
||||
command:
|
||||
- redis-sentinel
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -18008,7 +17970,7 @@ spec:
|
||||
value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4
|
||||
- name: SENTINEL_ID_2
|
||||
value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: split-brain-fix
|
||||
resources: {}
|
||||
@@ -18037,7 +17999,7 @@ spec:
|
||||
value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4
|
||||
- name: SENTINEL_ID_2
|
||||
value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
|
||||
@@ -747,81 +747,38 @@ data:
|
||||
fi
|
||||
fi
|
||||
done
|
||||
haproxy.cfg: |
|
||||
defaults REDIS
|
||||
mode tcp
|
||||
timeout connect 4s
|
||||
timeout server 6m
|
||||
timeout client 6m
|
||||
timeout check 2s
|
||||
|
||||
listen health_check_http_url
|
||||
bind [::]:8888 v4v6
|
||||
mode http
|
||||
monitor-uri /healthz
|
||||
option dontlognull
|
||||
# Check Sentinel and whether they are nominated master
|
||||
backend check_if_redis_is_master_0
|
||||
mode tcp
|
||||
option tcp-check
|
||||
tcp-check connect
|
||||
tcp-check send PING\r\n
|
||||
tcp-check expect string +PONG
|
||||
tcp-check send SENTINEL\ get-master-addr-by-name\ argocd\r\n
|
||||
tcp-check expect string REPLACE_ANNOUNCE0
|
||||
tcp-check send QUIT\r\n
|
||||
server R0 argocd-redis-ha-announce-0:26379 check inter 3s
|
||||
server R1 argocd-redis-ha-announce-1:26379 check inter 3s
|
||||
server R2 argocd-redis-ha-announce-2:26379 check inter 3s
|
||||
# Check Sentinel and whether they are nominated master
|
||||
backend check_if_redis_is_master_1
|
||||
mode tcp
|
||||
option tcp-check
|
||||
tcp-check connect
|
||||
tcp-check send PING\r\n
|
||||
tcp-check expect string +PONG
|
||||
tcp-check send SENTINEL\ get-master-addr-by-name\ argocd\r\n
|
||||
tcp-check expect string REPLACE_ANNOUNCE1
|
||||
tcp-check send QUIT\r\n
|
||||
server R0 argocd-redis-ha-announce-0:26379 check inter 3s
|
||||
server R1 argocd-redis-ha-announce-1:26379 check inter 3s
|
||||
server R2 argocd-redis-ha-announce-2:26379 check inter 3s
|
||||
# Check Sentinel and whether they are nominated master
|
||||
backend check_if_redis_is_master_2
|
||||
mode tcp
|
||||
option tcp-check
|
||||
tcp-check connect
|
||||
tcp-check send PING\r\n
|
||||
tcp-check expect string +PONG
|
||||
tcp-check send SENTINEL\ get-master-addr-by-name\ argocd\r\n
|
||||
tcp-check expect string REPLACE_ANNOUNCE2
|
||||
tcp-check send QUIT\r\n
|
||||
server R0 argocd-redis-ha-announce-0:26379 check inter 3s
|
||||
server R1 argocd-redis-ha-announce-1:26379 check inter 3s
|
||||
server R2 argocd-redis-ha-announce-2:26379 check inter 3s
|
||||
|
||||
# decide redis backend to use
|
||||
#master
|
||||
frontend ft_redis_master
|
||||
bind [::]:6379 v4v6
|
||||
use_backend bk_redis_master
|
||||
# Check all redis servers to see if they think they are master
|
||||
backend bk_redis_master
|
||||
mode tcp
|
||||
option tcp-check
|
||||
tcp-check connect
|
||||
tcp-check send PING\r\n
|
||||
tcp-check expect string +PONG
|
||||
tcp-check send info\ replication\r\n
|
||||
tcp-check expect string role:master
|
||||
tcp-check send QUIT\r\n
|
||||
tcp-check expect string +OK
|
||||
use-server R0 if { srv_is_up(R0) } { nbsrv(check_if_redis_is_master_0) ge 2 }
|
||||
server R0 argocd-redis-ha-announce-0:6379 check inter 3s fall 1 rise 1
|
||||
use-server R1 if { srv_is_up(R1) } { nbsrv(check_if_redis_is_master_1) ge 2 }
|
||||
server R1 argocd-redis-ha-announce-1:6379 check inter 3s fall 1 rise 1
|
||||
use-server R2 if { srv_is_up(R2) } { nbsrv(check_if_redis_is_master_2) ge 2 }
|
||||
server R2 argocd-redis-ha-announce-2:6379 check inter 3s fall 1 rise 1
|
||||
haproxy.cfg: "defaults REDIS\n mode tcp\n timeout connect 4s\n timeout server
|
||||
6m\n timeout client 6m\n timeout check 2s\n\nlisten health_check_http_url\n
|
||||
\ bind :8888 \n mode http\n monitor-uri /healthz\n option dontlognull\n#
|
||||
Check Sentinel and whether they are nominated master\nbackend check_if_redis_is_master_0\n
|
||||
\ mode tcp\n option tcp-check\n tcp-check connect\n tcp-check send PING\\r\\n\n
|
||||
\ tcp-check expect string +PONG\n tcp-check send SENTINEL\\ get-master-addr-by-name\\
|
||||
argocd\\r\\n\n tcp-check expect string REPLACE_ANNOUNCE0\n tcp-check send QUIT\\r\\n\n
|
||||
\ server R0 argocd-redis-ha-announce-0:26379 check inter 3s\n server R1 argocd-redis-ha-announce-1:26379
|
||||
check inter 3s\n server R2 argocd-redis-ha-announce-2:26379 check inter 3s\n#
|
||||
Check Sentinel and whether they are nominated master\nbackend check_if_redis_is_master_1\n
|
||||
\ mode tcp\n option tcp-check\n tcp-check connect\n tcp-check send PING\\r\\n\n
|
||||
\ tcp-check expect string +PONG\n tcp-check send SENTINEL\\ get-master-addr-by-name\\
|
||||
argocd\\r\\n\n tcp-check expect string REPLACE_ANNOUNCE1\n tcp-check send QUIT\\r\\n\n
|
||||
\ server R0 argocd-redis-ha-announce-0:26379 check inter 3s\n server R1 argocd-redis-ha-announce-1:26379
|
||||
check inter 3s\n server R2 argocd-redis-ha-announce-2:26379 check inter 3s\n#
|
||||
Check Sentinel and whether they are nominated master\nbackend check_if_redis_is_master_2\n
|
||||
\ mode tcp\n option tcp-check\n tcp-check connect\n tcp-check send PING\\r\\n\n
|
||||
\ tcp-check expect string +PONG\n tcp-check send SENTINEL\\ get-master-addr-by-name\\
|
||||
argocd\\r\\n\n tcp-check expect string REPLACE_ANNOUNCE2\n tcp-check send QUIT\\r\\n\n
|
||||
\ server R0 argocd-redis-ha-announce-0:26379 check inter 3s\n server R1 argocd-redis-ha-announce-1:26379
|
||||
check inter 3s\n server R2 argocd-redis-ha-announce-2:26379 check inter 3s\n\n#
|
||||
decide redis backend to use\n#master\nfrontend ft_redis_master\n bind :6379 \n
|
||||
\ use_backend bk_redis_master\n# Check all redis servers to see if they think
|
||||
they are master\nbackend bk_redis_master\n mode tcp\n option tcp-check\n tcp-check
|
||||
connect\n tcp-check send PING\\r\\n\n tcp-check expect string +PONG\n tcp-check
|
||||
send info\\ replication\\r\\n\n tcp-check expect string role:master\n tcp-check
|
||||
send QUIT\\r\\n\n tcp-check expect string +OK\n use-server R0 if { srv_is_up(R0)
|
||||
} { nbsrv(check_if_redis_is_master_0) ge 2 }\n server R0 argocd-redis-ha-announce-0:6379
|
||||
check inter 3s fall 1 rise 1\n use-server R1 if { srv_is_up(R1) } { nbsrv(check_if_redis_is_master_1)
|
||||
ge 2 }\n server R1 argocd-redis-ha-announce-1:6379 check inter 3s fall 1 rise
|
||||
1\n use-server R2 if { srv_is_up(R2) } { nbsrv(check_if_redis_is_master_2) ge
|
||||
2 }\n server R2 argocd-redis-ha-announce-2:6379 check inter 3s fall 1 rise 1\n"
|
||||
haproxy_init.sh: |
|
||||
HAPROXY_CONF=/data/haproxy.cfg
|
||||
cp /readonly/haproxy.cfg "$HAPROXY_CONF"
|
||||
@@ -1120,6 +1077,7 @@ data:
|
||||
port 6379
|
||||
rename-command FLUSHDB ""
|
||||
rename-command FLUSHALL ""
|
||||
bind 0.0.0.0
|
||||
maxmemory 0
|
||||
maxmemory-policy volatile-lru
|
||||
min-replicas-max-lag 5
|
||||
@@ -1131,6 +1089,7 @@ data:
|
||||
sentinel.conf: |
|
||||
dir "/data"
|
||||
port 26379
|
||||
bind 0.0.0.0
|
||||
sentinel down-after-milliseconds argocd 10000
|
||||
sentinel failover-timeout argocd 180000
|
||||
maxclients 10000
|
||||
@@ -1597,7 +1556,13 @@ spec:
|
||||
key: applicationsetcontroller.enable.git.submodule
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.enable.progressive.rollouts
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -1707,7 +1672,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -1760,7 +1725,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -1818,7 +1783,7 @@ spec:
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/config: 1f7a9ffcacb3871ceb9b0741c0714e3f7fa656d426a398c1f727fffb01073f35
|
||||
checksum/config: 718bbb277da8610063a7c0fd810984577c2e8ab215815a71211dfa6e20f67321
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-redis-ha-haproxy
|
||||
name: argocd-redis-ha-haproxy
|
||||
@@ -2063,7 +2028,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -2115,7 +2080,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -2394,7 +2359,7 @@ spec:
|
||||
key: server.enable.proxy.extension
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2630,7 +2595,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
@@ -2690,7 +2655,7 @@ spec:
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/init-config: 84ccf6a9b8a7fa3ae5b62a8f17d6c65a5197e9605da9b2761179bf942828eefe
|
||||
checksum/init-config: 69130412bda04eacad3530cb7bcf26cf121401e725e15d0959dd71a7380afe75
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-redis-ha
|
||||
spec:
|
||||
@@ -2707,7 +2672,7 @@ spec:
|
||||
- /data/conf/redis.conf
|
||||
command:
|
||||
- redis-server
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
preStop:
|
||||
@@ -2760,7 +2725,7 @@ spec:
|
||||
- /data/conf/sentinel.conf
|
||||
command:
|
||||
- redis-sentinel
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -2812,7 +2777,7 @@ spec:
|
||||
value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4
|
||||
- name: SENTINEL_ID_2
|
||||
value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: split-brain-fix
|
||||
resources: {}
|
||||
@@ -2841,7 +2806,7 @@ spec:
|
||||
value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4
|
||||
- name: SENTINEL_ID_2
|
||||
value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
|
||||
@@ -5476,7 +5476,6 @@ spec:
|
||||
- spec
|
||||
type: object
|
||||
required:
|
||||
- pathParamPrefix
|
||||
- repoURL
|
||||
- revision
|
||||
type: object
|
||||
@@ -7367,7 +7366,6 @@ spec:
|
||||
- spec
|
||||
type: object
|
||||
required:
|
||||
- pathParamPrefix
|
||||
- repoURL
|
||||
- revision
|
||||
type: object
|
||||
@@ -10916,7 +10914,6 @@ spec:
|
||||
- spec
|
||||
type: object
|
||||
required:
|
||||
- pathParamPrefix
|
||||
- repoURL
|
||||
- revision
|
||||
type: object
|
||||
@@ -15871,7 +15868,13 @@ spec:
|
||||
key: applicationsetcontroller.enable.git.submodule
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.enable.progressive.rollouts
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -15981,7 +15984,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -16034,7 +16037,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -16111,7 +16114,7 @@ spec:
|
||||
- ""
|
||||
- --appendonly
|
||||
- "no"
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -16293,7 +16296,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -16345,7 +16348,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -16620,7 +16623,7 @@ spec:
|
||||
key: server.enable.proxy.extension
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -16854,7 +16857,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -675,7 +675,13 @@ spec:
|
||||
key: applicationsetcontroller.enable.git.submodule
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.enable.progressive.rollouts
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -785,7 +791,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -838,7 +844,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -915,7 +921,7 @@ spec:
|
||||
- ""
|
||||
- --appendonly
|
||||
- "no"
|
||||
image: redis:7.0.5-alpine
|
||||
image: redis:7.0.7-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -1097,7 +1103,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1149,7 +1155,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -1424,7 +1430,7 @@ spec:
|
||||
key: server.enable.proxy.extension
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -1658,7 +1664,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.6.0-rc6
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -50,6 +50,8 @@ nav:
|
||||
- operator-manual/custom-styles.md
|
||||
- operator-manual/metrics.md
|
||||
- operator-manual/web_based_terminal.md
|
||||
- operator-manual/config-management-plugins.md
|
||||
- operator-manual/deep_links.md
|
||||
- Notification:
|
||||
- Overview: operator-manual/notifications/index.md
|
||||
- operator-manual/notifications/triggers.md
|
||||
@@ -132,7 +134,6 @@ nav:
|
||||
- user-guide/import.md
|
||||
- user-guide/jsonnet.md
|
||||
- user-guide/directory.md
|
||||
- user-guide/config-management-plugins.md
|
||||
- user-guide/tool_detection.md
|
||||
- user-guide/projects.md
|
||||
- user-guide/private-repositories.md
|
||||
|
||||
@@ -361,6 +361,53 @@ func (m *GoogleAnalyticsConfig) GetAnonymizeUsers() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type SettingsPluginsResponse struct {
|
||||
Plugins []*Plugin `protobuf:"bytes,1,rep,name=plugins,proto3" json:"plugins,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *SettingsPluginsResponse) Reset() { *m = SettingsPluginsResponse{} }
|
||||
func (m *SettingsPluginsResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*SettingsPluginsResponse) ProtoMessage() {}
|
||||
func (*SettingsPluginsResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_a480d494da040caa, []int{3}
|
||||
}
|
||||
func (m *SettingsPluginsResponse) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *SettingsPluginsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_SettingsPluginsResponse.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *SettingsPluginsResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_SettingsPluginsResponse.Merge(m, src)
|
||||
}
|
||||
func (m *SettingsPluginsResponse) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *SettingsPluginsResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_SettingsPluginsResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_SettingsPluginsResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *SettingsPluginsResponse) GetPlugins() []*Plugin {
|
||||
if m != nil {
|
||||
return m.Plugins
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Help settings
|
||||
type Help struct {
|
||||
// the URL for getting chat help, this will typically be your Slack channel for support
|
||||
@@ -378,7 +425,7 @@ func (m *Help) Reset() { *m = Help{} }
|
||||
func (m *Help) String() string { return proto.CompactTextString(m) }
|
||||
func (*Help) ProtoMessage() {}
|
||||
func (*Help) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_a480d494da040caa, []int{3}
|
||||
return fileDescriptor_a480d494da040caa, []int{4}
|
||||
}
|
||||
func (m *Help) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -441,7 +488,7 @@ func (m *Plugin) Reset() { *m = Plugin{} }
|
||||
func (m *Plugin) String() string { return proto.CompactTextString(m) }
|
||||
func (*Plugin) ProtoMessage() {}
|
||||
func (*Plugin) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_a480d494da040caa, []int{4}
|
||||
return fileDescriptor_a480d494da040caa, []int{5}
|
||||
}
|
||||
func (m *Plugin) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -488,7 +535,7 @@ func (m *DexConfig) Reset() { *m = DexConfig{} }
|
||||
func (m *DexConfig) String() string { return proto.CompactTextString(m) }
|
||||
func (*DexConfig) ProtoMessage() {}
|
||||
func (*DexConfig) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_a480d494da040caa, []int{5}
|
||||
return fileDescriptor_a480d494da040caa, []int{6}
|
||||
}
|
||||
func (m *DexConfig) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -536,7 +583,7 @@ func (m *Connector) Reset() { *m = Connector{} }
|
||||
func (m *Connector) String() string { return proto.CompactTextString(m) }
|
||||
func (*Connector) ProtoMessage() {}
|
||||
func (*Connector) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_a480d494da040caa, []int{6}
|
||||
return fileDescriptor_a480d494da040caa, []int{7}
|
||||
}
|
||||
func (m *Connector) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -595,7 +642,7 @@ func (m *OIDCConfig) Reset() { *m = OIDCConfig{} }
|
||||
func (m *OIDCConfig) String() string { return proto.CompactTextString(m) }
|
||||
func (*OIDCConfig) ProtoMessage() {}
|
||||
func (*OIDCConfig) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_a480d494da040caa, []int{7}
|
||||
return fileDescriptor_a480d494da040caa, []int{8}
|
||||
}
|
||||
func (m *OIDCConfig) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -671,6 +718,7 @@ func init() {
|
||||
proto.RegisterType((*Settings)(nil), "cluster.Settings")
|
||||
proto.RegisterMapType((map[string]*v1alpha1.ResourceOverride)(nil), "cluster.Settings.ResourceOverridesEntry")
|
||||
proto.RegisterType((*GoogleAnalyticsConfig)(nil), "cluster.GoogleAnalyticsConfig")
|
||||
proto.RegisterType((*SettingsPluginsResponse)(nil), "cluster.SettingsPluginsResponse")
|
||||
proto.RegisterType((*Help)(nil), "cluster.Help")
|
||||
proto.RegisterMapType((map[string]string)(nil), "cluster.Help.BinaryUrlsEntry")
|
||||
proto.RegisterType((*Plugin)(nil), "cluster.Plugin")
|
||||
@@ -683,79 +731,82 @@ func init() {
|
||||
func init() { proto.RegisterFile("server/settings/settings.proto", fileDescriptor_a480d494da040caa) }
|
||||
|
||||
var fileDescriptor_a480d494da040caa = []byte{
|
||||
// 1148 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x4f, 0x6f, 0x1b, 0x45,
|
||||
0x14, 0xd7, 0xd6, 0x69, 0x62, 0x3f, 0x37, 0x75, 0x32, 0x6d, 0xd3, 0xad, 0x55, 0x92, 0xe0, 0x43,
|
||||
0x65, 0x10, 0xac, 0x1b, 0x57, 0x08, 0x84, 0xa8, 0xa0, 0xb6, 0xab, 0xd6, 0xd4, 0x6d, 0xc3, 0xb6,
|
||||
0xe9, 0x01, 0x09, 0x55, 0x93, 0xdd, 0xc7, 0x66, 0xf1, 0x7a, 0x66, 0x35, 0x33, 0x6b, 0xea, 0x1e,
|
||||
0xb9, 0x71, 0xe1, 0x02, 0x9f, 0x85, 0x03, 0x9f, 0x80, 0x23, 0x12, 0xf7, 0x08, 0x59, 0x7c, 0x10,
|
||||
0x34, 0xb3, 0x7f, 0xb2, 0xb1, 0x5d, 0x40, 0xea, 0x6d, 0xe6, 0xf7, 0x7b, 0xff, 0xe6, 0xcd, 0x7b,
|
||||
0x33, 0x0f, 0x76, 0x25, 0x8a, 0x29, 0x8a, 0x8e, 0x44, 0xa5, 0x42, 0x16, 0xc8, 0x62, 0xe1, 0xc4,
|
||||
0x82, 0x2b, 0x4e, 0x36, 0xbc, 0x28, 0x91, 0x0a, 0x45, 0xf3, 0x6a, 0xc0, 0x03, 0x6e, 0xb0, 0x8e,
|
||||
0x5e, 0xa5, 0x74, 0xf3, 0x66, 0xc0, 0x79, 0x10, 0x61, 0x87, 0xc6, 0x61, 0x87, 0x32, 0xc6, 0x15,
|
||||
0x55, 0x21, 0x67, 0x99, 0x72, 0x73, 0x14, 0x84, 0xea, 0x24, 0x39, 0x76, 0x3c, 0x3e, 0xe9, 0x50,
|
||||
0x61, 0xd4, 0xbf, 0x33, 0x8b, 0x0f, 0x3d, 0xbf, 0x33, 0xed, 0x76, 0xe2, 0x71, 0xa0, 0x35, 0x65,
|
||||
0x87, 0xc6, 0x71, 0x14, 0x7a, 0x46, 0xb7, 0x33, 0x3d, 0xa0, 0x51, 0x7c, 0x42, 0x0f, 0x3a, 0x01,
|
||||
0x32, 0x14, 0x54, 0xa1, 0x9f, 0x59, 0xfb, 0xe2, 0x3f, 0xac, 0x2d, 0x9e, 0x84, 0x87, 0xbe, 0xd7,
|
||||
0xf1, 0x22, 0x1a, 0x4e, 0xb2, 0x78, 0x5a, 0x0d, 0xd8, 0x7c, 0x96, 0xb1, 0x5f, 0x25, 0x28, 0x66,
|
||||
0xad, 0x5f, 0xeb, 0x50, 0xcd, 0x11, 0x72, 0x03, 0x2a, 0x89, 0x88, 0x6c, 0x6b, 0xdf, 0x6a, 0xd7,
|
||||
0x7a, 0x1b, 0xf3, 0xd3, 0xbd, 0xca, 0x91, 0x3b, 0x72, 0x35, 0x46, 0x6e, 0x43, 0xcd, 0xc7, 0x57,
|
||||
0x7d, 0xce, 0xbe, 0x0d, 0x03, 0xfb, 0xc2, 0xbe, 0xd5, 0xae, 0x77, 0x89, 0x93, 0x65, 0xc6, 0x19,
|
||||
0xe4, 0x8c, 0x7b, 0x26, 0x44, 0xfa, 0x00, 0xda, 0x7f, 0xa6, 0x52, 0x31, 0x2a, 0x57, 0x0a, 0x95,
|
||||
0xa7, 0xc3, 0x41, 0x3f, 0xa5, 0x7a, 0x97, 0xe7, 0xa7, 0x7b, 0x70, 0xb6, 0x77, 0x4b, 0x6a, 0x64,
|
||||
0x1f, 0xea, 0x34, 0x8e, 0x47, 0xf4, 0x18, 0xa3, 0x47, 0x38, 0xb3, 0xd7, 0x74, 0x64, 0x6e, 0x19,
|
||||
0x22, 0x2f, 0x60, 0x5b, 0xa0, 0xe4, 0x89, 0xf0, 0xf0, 0xe9, 0x14, 0x85, 0x08, 0x7d, 0x94, 0xf6,
|
||||
0xc5, 0xfd, 0x4a, 0xbb, 0xde, 0x6d, 0x17, 0xde, 0xf2, 0x13, 0x3a, 0xee, 0xa2, 0xe8, 0x7d, 0xa6,
|
||||
0xc4, 0xcc, 0x5d, 0x36, 0x41, 0x1c, 0x20, 0x52, 0x51, 0x95, 0xc8, 0x1e, 0xf5, 0x03, 0xbc, 0xcf,
|
||||
0xe8, 0x71, 0x84, 0xbe, 0xbd, 0xbe, 0x6f, 0xb5, 0xab, 0xee, 0x0a, 0x86, 0x3c, 0x84, 0x46, 0x5a,
|
||||
0x09, 0xf7, 0x18, 0x8d, 0x66, 0x2a, 0xf4, 0xa4, 0xbd, 0x61, 0xce, 0xbc, 0x5b, 0x44, 0xf1, 0xe0,
|
||||
0x3c, 0x9f, 0x1d, 0x77, 0x51, 0x8d, 0xbc, 0x86, 0xad, 0x71, 0x22, 0x15, 0x9f, 0x84, 0xaf, 0xf1,
|
||||
0x69, 0x6c, 0xaa, 0xc9, 0xae, 0x1a, 0x53, 0x4f, 0x9c, 0xb3, 0x02, 0x70, 0xf2, 0x02, 0x30, 0x8b,
|
||||
0x97, 0x9e, 0xef, 0x4c, 0xbb, 0x4e, 0x3c, 0x0e, 0x1c, 0x5d, 0x4e, 0x4e, 0xa9, 0x9c, 0x9c, 0xbc,
|
||||
0x9c, 0x9c, 0x47, 0x0b, 0x56, 0xdd, 0x25, 0x3f, 0xe4, 0x5d, 0x58, 0x3b, 0xc1, 0x28, 0xb6, 0x6b,
|
||||
0xc6, 0xdf, 0x66, 0x11, 0xfa, 0x43, 0x8c, 0x62, 0xd7, 0x50, 0xe4, 0x3d, 0xd8, 0x88, 0xa3, 0x24,
|
||||
0x08, 0x99, 0xb4, 0xc1, 0xa4, 0xb9, 0x51, 0x48, 0x1d, 0x1a, 0xdc, 0xcd, 0x79, 0x9d, 0xc3, 0x44,
|
||||
0xa2, 0x18, 0x71, 0xbd, 0x1b, 0x84, 0x32, 0xcd, 0x61, 0x3d, 0xcd, 0xe1, 0x32, 0x43, 0x7e, 0xb2,
|
||||
0xe0, 0xba, 0x67, 0xb2, 0xf2, 0x98, 0x32, 0x1a, 0xe0, 0x04, 0x99, 0x3a, 0xcc, 0x7c, 0x5d, 0x32,
|
||||
0xbe, 0x9e, 0xbf, 0x5d, 0x06, 0xfa, 0x2b, 0x8d, 0xbb, 0x6f, 0x72, 0x4a, 0x3e, 0x80, 0xed, 0x22,
|
||||
0x45, 0x2f, 0x50, 0x48, 0x73, 0x17, 0x9b, 0xfb, 0x95, 0x76, 0xcd, 0x5d, 0x26, 0x48, 0x13, 0xaa,
|
||||
0x49, 0xd8, 0x97, 0xf2, 0xc8, 0x1d, 0xd9, 0x97, 0x4d, 0xa5, 0x16, 0x7b, 0xd2, 0x86, 0x46, 0x12,
|
||||
0xf6, 0x28, 0x63, 0x28, 0xfa, 0x9c, 0x29, 0x64, 0xca, 0x6e, 0x18, 0x91, 0x45, 0x58, 0x97, 0x7c,
|
||||
0x0e, 0x69, 0x43, 0x5b, 0x69, 0xc9, 0x97, 0x20, 0x6d, 0x2b, 0xa6, 0x52, 0x7e, 0xcf, 0x85, 0x7f,
|
||||
0x48, 0x95, 0x42, 0xc1, 0xec, 0xed, 0xd4, 0xd6, 0x02, 0x4c, 0x6e, 0xc1, 0x65, 0x25, 0xa8, 0x37,
|
||||
0x0e, 0x59, 0xf0, 0x18, 0xd5, 0x09, 0xf7, 0x6d, 0x62, 0x04, 0x17, 0x50, 0x7d, 0xce, 0xdc, 0xc1,
|
||||
0x21, 0x8a, 0x09, 0x65, 0x3a, 0xbe, 0x2b, 0xe6, 0x9e, 0x96, 0x09, 0xf2, 0x3e, 0x6c, 0x15, 0x20,
|
||||
0x97, 0xa1, 0x4e, 0xb1, 0x7d, 0xd5, 0xd8, 0x5d, 0xc2, 0x17, 0xda, 0xc8, 0xe5, 0x5c, 0x1d, 0x89,
|
||||
0xc8, 0xbe, 0x66, 0xa4, 0x57, 0x30, 0xfa, 0xf4, 0xf8, 0x0a, 0xbd, 0xbc, 0xdf, 0x76, 0x4c, 0x0c,
|
||||
0x65, 0x88, 0xdc, 0x86, 0x2b, 0x1e, 0x67, 0x4a, 0xf0, 0x28, 0x42, 0xf1, 0x84, 0x4e, 0x50, 0xc6,
|
||||
0xd4, 0x43, 0xfb, 0xba, 0x31, 0xb9, 0x8a, 0x22, 0x9f, 0xc1, 0x0d, 0x1a, 0xc7, 0x72, 0xc8, 0xee,
|
||||
0xb1, 0x59, 0x81, 0xe6, 0x1e, 0x6c, 0xe3, 0xe1, 0xcd, 0x02, 0xcd, 0x5f, 0x2c, 0xd8, 0x59, 0xfd,
|
||||
0x6c, 0x90, 0x2d, 0xa8, 0x8c, 0x71, 0x96, 0xbe, 0x97, 0xae, 0x5e, 0x12, 0x1f, 0x2e, 0x4e, 0x69,
|
||||
0x94, 0x60, 0xf6, 0x44, 0xbe, 0x65, 0xc3, 0x2e, 0xba, 0x75, 0x53, 0xe3, 0x9f, 0x5e, 0xf8, 0xc4,
|
||||
0x6a, 0xbd, 0x84, 0x6b, 0x2b, 0xdf, 0x13, 0xb2, 0x0b, 0x90, 0xdf, 0xee, 0x70, 0x90, 0xc5, 0x56,
|
||||
0x42, 0x74, 0x4d, 0x50, 0xc6, 0xd9, 0x4c, 0x97, 0xee, 0x91, 0x44, 0x21, 0x4d, 0xac, 0x55, 0x77,
|
||||
0x01, 0x6d, 0xfd, 0x66, 0xc1, 0x9a, 0x6e, 0x7b, 0x62, 0xc3, 0x86, 0x77, 0x42, 0xcd, 0xbd, 0xa5,
|
||||
0xd6, 0xf2, 0xad, 0x2e, 0x78, 0xbd, 0x7c, 0x8e, 0xaf, 0x94, 0x31, 0x52, 0x73, 0x8b, 0x3d, 0xb9,
|
||||
0x0b, 0x70, 0x1c, 0x32, 0x2a, 0x66, 0x47, 0x22, 0x92, 0x76, 0xc5, 0x74, 0xef, 0x3b, 0xe7, 0xde,
|
||||
0x13, 0xa7, 0x57, 0xf0, 0xe9, 0x2b, 0x5c, 0x52, 0x68, 0xde, 0x85, 0xc6, 0x02, 0xbd, 0x22, 0xdb,
|
||||
0x57, 0xcb, 0xd9, 0xae, 0x95, 0xb3, 0x73, 0x13, 0xd6, 0xd3, 0x1e, 0x26, 0x04, 0xd6, 0x18, 0x9d,
|
||||
0x60, 0xa6, 0x66, 0xd6, 0xad, 0xcf, 0xa1, 0x56, 0x7c, 0x59, 0xa4, 0x0b, 0xe0, 0x71, 0xc6, 0xd0,
|
||||
0x53, 0x5c, 0x48, 0xdb, 0x32, 0x81, 0x9e, 0x7d, 0x6d, 0xfd, 0x9c, 0x72, 0x4b, 0x52, 0xad, 0x3b,
|
||||
0x50, 0x2b, 0x88, 0x55, 0x1e, 0x34, 0xa6, 0x66, 0x71, 0x1e, 0x98, 0x59, 0xb7, 0x7e, 0xac, 0x40,
|
||||
0xe9, 0x9b, 0x5b, 0xa9, 0xb6, 0x03, 0xeb, 0xa1, 0x94, 0x09, 0x8a, 0x4c, 0x31, 0xdb, 0x91, 0x36,
|
||||
0x54, 0xbd, 0x28, 0x44, 0xa6, 0x86, 0x03, 0xf3, 0x93, 0xd6, 0x7a, 0x97, 0xe6, 0xa7, 0x7b, 0xd5,
|
||||
0x7e, 0x86, 0xb9, 0x05, 0x4b, 0x0e, 0xa0, 0xee, 0x45, 0x61, 0x4e, 0xa4, 0x1f, 0x66, 0xaf, 0x31,
|
||||
0x3f, 0xdd, 0xab, 0xf7, 0x47, 0xc3, 0x42, 0xbe, 0x2c, 0xa3, 0x9d, 0x4a, 0x8f, 0xc7, 0xd9, 0xb7,
|
||||
0x59, 0x73, 0xb3, 0x1d, 0x79, 0x09, 0x9b, 0xa1, 0xff, 0x9c, 0x8f, 0x91, 0xf5, 0xcd, 0x08, 0x61,
|
||||
0xaf, 0x9b, 0xdc, 0xdc, 0x5a, 0xf1, 0x87, 0x3b, 0xc3, 0xb2, 0xa0, 0xb9, 0xae, 0xde, 0xf6, 0xfc,
|
||||
0x74, 0x6f, 0x73, 0x38, 0x28, 0xe1, 0xee, 0x79, 0x7b, 0xcd, 0x19, 0x90, 0x65, 0xbd, 0x15, 0xd7,
|
||||
0xfc, 0xf8, 0x7c, 0x53, 0x7d, 0xfc, 0xaf, 0x4d, 0x95, 0xce, 0x40, 0x4e, 0x31, 0xc4, 0xe9, 0x61,
|
||||
0xc2, 0x31, 0xf6, 0x4b, 0xf5, 0xd1, 0xfd, 0x06, 0x1a, 0xf9, 0x4c, 0xf0, 0x0c, 0xc5, 0x34, 0xf4,
|
||||
0x90, 0x7c, 0x09, 0x95, 0x07, 0xa8, 0xc8, 0xce, 0xd2, 0xd0, 0x60, 0x06, 0xa5, 0xe6, 0xf6, 0x12,
|
||||
0xde, 0xb2, 0x7f, 0xf8, 0xf3, 0xef, 0x9f, 0x2f, 0x10, 0xb2, 0x65, 0x86, 0xbf, 0xe9, 0x41, 0x31,
|
||||
0x78, 0xf5, 0xfa, 0xbf, 0xcf, 0x77, 0xad, 0x3f, 0xe6, 0xbb, 0xd6, 0x5f, 0xf3, 0x5d, 0xeb, 0xeb,
|
||||
0x8f, 0xfe, 0xdf, 0x10, 0x98, 0xde, 0x61, 0x61, 0xe4, 0x78, 0xdd, 0x8c, 0x6c, 0x77, 0xfe, 0x09,
|
||||
0x00, 0x00, 0xff, 0xff, 0xf0, 0x33, 0x47, 0xc2, 0xa1, 0x0a, 0x00, 0x00,
|
||||
// 1194 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0xcf, 0x6f, 0x1b, 0xc5,
|
||||
0x17, 0xd7, 0xd6, 0x69, 0x62, 0x3f, 0x37, 0x75, 0x32, 0x6d, 0xd3, 0xad, 0xd5, 0x6f, 0xe2, 0xaf,
|
||||
0x0f, 0x95, 0x41, 0xb0, 0x6e, 0x52, 0x21, 0x10, 0xa2, 0x82, 0xda, 0xae, 0x5a, 0xd3, 0xb4, 0x0d,
|
||||
0xdb, 0xa6, 0x07, 0x2e, 0xd5, 0x64, 0xf7, 0xb1, 0x59, 0xb2, 0x9e, 0x59, 0xcd, 0xcc, 0x9a, 0xba,
|
||||
0x47, 0x6e, 0x5c, 0xb8, 0xc0, 0xdf, 0xc2, 0x81, 0x7f, 0x00, 0x8e, 0x48, 0xdc, 0x23, 0x64, 0xf1,
|
||||
0x87, 0xa0, 0x99, 0xfd, 0x91, 0xcd, 0xda, 0x2d, 0x48, 0xbd, 0xcd, 0x7c, 0x3e, 0xef, 0xd7, 0xbc,
|
||||
0x79, 0xf3, 0xe6, 0xc1, 0xb6, 0x44, 0x31, 0x45, 0xd1, 0x97, 0xa8, 0x54, 0xc8, 0x02, 0x59, 0x2c,
|
||||
0x9c, 0x58, 0x70, 0xc5, 0xc9, 0x9a, 0x17, 0x25, 0x52, 0xa1, 0x68, 0x5f, 0x0d, 0x78, 0xc0, 0x0d,
|
||||
0xd6, 0xd7, 0xab, 0x94, 0x6e, 0xdf, 0x0c, 0x38, 0x0f, 0x22, 0xec, 0xd3, 0x38, 0xec, 0x53, 0xc6,
|
||||
0xb8, 0xa2, 0x2a, 0xe4, 0x2c, 0x53, 0x6e, 0xef, 0x07, 0xa1, 0x3a, 0x4e, 0x8e, 0x1c, 0x8f, 0x4f,
|
||||
0xfa, 0x54, 0x18, 0xf5, 0x6f, 0xcd, 0xe2, 0x43, 0xcf, 0xef, 0x4f, 0xf7, 0xfa, 0xf1, 0x49, 0xa0,
|
||||
0x35, 0x65, 0x9f, 0xc6, 0x71, 0x14, 0x7a, 0x46, 0xb7, 0x3f, 0xdd, 0xa5, 0x51, 0x7c, 0x4c, 0x77,
|
||||
0xfb, 0x01, 0x32, 0x14, 0x54, 0xa1, 0x9f, 0x59, 0xfb, 0xe2, 0x5f, 0xac, 0x55, 0x4f, 0xc2, 0x43,
|
||||
0xdf, 0xeb, 0x7b, 0x11, 0x0d, 0x27, 0x59, 0x3c, 0xdd, 0x16, 0xac, 0x3f, 0xcb, 0xd8, 0xaf, 0x12,
|
||||
0x14, 0xb3, 0xee, 0x2f, 0x4d, 0xa8, 0xe7, 0x08, 0xb9, 0x01, 0xb5, 0x44, 0x44, 0xb6, 0xd5, 0xb1,
|
||||
0x7a, 0x8d, 0xc1, 0xda, 0xfc, 0x74, 0xa7, 0x76, 0xe8, 0xee, 0xbb, 0x1a, 0x23, 0xb7, 0xa1, 0xe1,
|
||||
0xe3, 0xab, 0x21, 0x67, 0xdf, 0x84, 0x81, 0x7d, 0xa1, 0x63, 0xf5, 0x9a, 0x7b, 0xc4, 0xc9, 0x32,
|
||||
0xe3, 0x8c, 0x72, 0xc6, 0x3d, 0x13, 0x22, 0x43, 0x00, 0xed, 0x3f, 0x53, 0xa9, 0x19, 0x95, 0x2b,
|
||||
0x85, 0xca, 0xd3, 0xf1, 0x68, 0x98, 0x52, 0x83, 0xcb, 0xf3, 0xd3, 0x1d, 0x38, 0xdb, 0xbb, 0x25,
|
||||
0x35, 0xd2, 0x81, 0x26, 0x8d, 0xe3, 0x7d, 0x7a, 0x84, 0xd1, 0x23, 0x9c, 0xd9, 0x2b, 0x3a, 0x32,
|
||||
0xb7, 0x0c, 0x91, 0x17, 0xb0, 0x29, 0x50, 0xf2, 0x44, 0x78, 0xf8, 0x74, 0x8a, 0x42, 0x84, 0x3e,
|
||||
0x4a, 0xfb, 0x62, 0xa7, 0xd6, 0x6b, 0xee, 0xf5, 0x0a, 0x6f, 0xf9, 0x09, 0x1d, 0xb7, 0x2a, 0x7a,
|
||||
0x9f, 0x29, 0x31, 0x73, 0x17, 0x4d, 0x10, 0x07, 0x88, 0x54, 0x54, 0x25, 0x72, 0x40, 0xfd, 0x00,
|
||||
0xef, 0x33, 0x7a, 0x14, 0xa1, 0x6f, 0xaf, 0x76, 0xac, 0x5e, 0xdd, 0x5d, 0xc2, 0x90, 0x87, 0xd0,
|
||||
0x4a, 0x2b, 0xe1, 0x1e, 0xa3, 0xd1, 0x4c, 0x85, 0x9e, 0xb4, 0xd7, 0xcc, 0x99, 0xb7, 0x8b, 0x28,
|
||||
0x1e, 0x9c, 0xe7, 0xb3, 0xe3, 0x56, 0xd5, 0xc8, 0x6b, 0xd8, 0x38, 0x49, 0xa4, 0xe2, 0x93, 0xf0,
|
||||
0x35, 0x3e, 0x8d, 0x4d, 0x35, 0xd9, 0x75, 0x63, 0xea, 0x89, 0x73, 0x56, 0x00, 0x4e, 0x5e, 0x00,
|
||||
0x66, 0xf1, 0xd2, 0xf3, 0x9d, 0xe9, 0x9e, 0x13, 0x9f, 0x04, 0x8e, 0x2e, 0x27, 0xa7, 0x54, 0x4e,
|
||||
0x4e, 0x5e, 0x4e, 0xce, 0xa3, 0x8a, 0x55, 0x77, 0xc1, 0x0f, 0xf9, 0x3f, 0xac, 0x1c, 0x63, 0x14,
|
||||
0xdb, 0x0d, 0xe3, 0x6f, 0xbd, 0x08, 0xfd, 0x21, 0x46, 0xb1, 0x6b, 0x28, 0xf2, 0x1e, 0xac, 0xc5,
|
||||
0x51, 0x12, 0x84, 0x4c, 0xda, 0x60, 0xd2, 0xdc, 0x2a, 0xa4, 0x0e, 0x0c, 0xee, 0xe6, 0xbc, 0xce,
|
||||
0x61, 0x22, 0x51, 0xec, 0x73, 0xbd, 0x1b, 0x85, 0x32, 0xcd, 0x61, 0x33, 0xcd, 0xe1, 0x22, 0x43,
|
||||
0x7e, 0xb4, 0xe0, 0xba, 0x67, 0xb2, 0xf2, 0x98, 0x32, 0x1a, 0xe0, 0x04, 0x99, 0x3a, 0xc8, 0x7c,
|
||||
0x5d, 0x32, 0xbe, 0x9e, 0xbf, 0x5b, 0x06, 0x86, 0x4b, 0x8d, 0xbb, 0x6f, 0x72, 0x4a, 0x3e, 0x80,
|
||||
0xcd, 0x22, 0x45, 0x2f, 0x50, 0x48, 0x73, 0x17, 0xeb, 0x9d, 0x5a, 0xaf, 0xe1, 0x2e, 0x12, 0xa4,
|
||||
0x0d, 0xf5, 0x24, 0x1c, 0x4a, 0x79, 0xe8, 0xee, 0xdb, 0x97, 0x4d, 0xa5, 0x16, 0x7b, 0xd2, 0x83,
|
||||
0x56, 0x12, 0x0e, 0x28, 0x63, 0x28, 0x86, 0x9c, 0x29, 0x64, 0xca, 0x6e, 0x19, 0x91, 0x2a, 0xac,
|
||||
0x4b, 0x3e, 0x87, 0xb4, 0xa1, 0x8d, 0xb4, 0xe4, 0x4b, 0x90, 0xb6, 0x15, 0x53, 0x29, 0xbf, 0xe3,
|
||||
0xc2, 0x3f, 0xa0, 0x4a, 0xa1, 0x60, 0xf6, 0x66, 0x6a, 0xab, 0x02, 0x93, 0x5b, 0x70, 0x59, 0x09,
|
||||
0xea, 0x9d, 0x84, 0x2c, 0x78, 0x8c, 0xea, 0x98, 0xfb, 0x36, 0x31, 0x82, 0x15, 0x54, 0x9f, 0x33,
|
||||
0x77, 0x70, 0x80, 0x62, 0x42, 0x99, 0x8e, 0xef, 0x8a, 0xb9, 0xa7, 0x45, 0x82, 0xbc, 0x0f, 0x1b,
|
||||
0x05, 0xc8, 0x65, 0xa8, 0x53, 0x6c, 0x5f, 0x35, 0x76, 0x17, 0xf0, 0xca, 0x33, 0x72, 0x39, 0x57,
|
||||
0x87, 0x22, 0xb2, 0xaf, 0x19, 0xe9, 0x25, 0x8c, 0x3e, 0x3d, 0xbe, 0x42, 0x2f, 0x7f, 0x6f, 0x5b,
|
||||
0x26, 0x86, 0x32, 0x44, 0x6e, 0xc3, 0x15, 0x8f, 0x33, 0x25, 0x78, 0x14, 0xa1, 0x78, 0x42, 0x27,
|
||||
0x28, 0x63, 0xea, 0xa1, 0x7d, 0xdd, 0x98, 0x5c, 0x46, 0x91, 0xcf, 0xe0, 0x06, 0x8d, 0x63, 0x39,
|
||||
0x66, 0xf7, 0xd8, 0xac, 0x40, 0x73, 0x0f, 0xb6, 0xf1, 0xf0, 0x66, 0x81, 0xf6, 0xcf, 0x16, 0x6c,
|
||||
0x2d, 0x6f, 0x1b, 0x64, 0x03, 0x6a, 0x27, 0x38, 0x4b, 0xfb, 0xa5, 0xab, 0x97, 0xc4, 0x87, 0x8b,
|
||||
0x53, 0x1a, 0x25, 0x98, 0xb5, 0xc8, 0x77, 0x7c, 0xb0, 0x55, 0xb7, 0x6e, 0x6a, 0xfc, 0xd3, 0x0b,
|
||||
0x9f, 0x58, 0xdd, 0x97, 0x70, 0x6d, 0x69, 0x3f, 0x21, 0xdb, 0x00, 0xf9, 0xed, 0x8e, 0x47, 0x59,
|
||||
0x6c, 0x25, 0x44, 0xd7, 0x04, 0x65, 0x9c, 0xcd, 0x74, 0xe9, 0x1e, 0x4a, 0x14, 0xd2, 0xc4, 0x5a,
|
||||
0x77, 0x2b, 0x68, 0x77, 0x04, 0xd7, 0xf3, 0xb6, 0x99, 0x3d, 0x07, 0x17, 0x65, 0xcc, 0x99, 0xc4,
|
||||
0x72, 0x0b, 0xb0, 0xde, 0xde, 0x02, 0xba, 0xbf, 0x5a, 0xb0, 0xa2, 0x9b, 0x07, 0xb1, 0x61, 0xcd,
|
||||
0x3b, 0xa6, 0xe6, 0xf6, 0xd3, 0x98, 0xf2, 0xad, 0x7e, 0x36, 0x7a, 0xf9, 0x1c, 0x5f, 0x29, 0x13,
|
||||
0x4a, 0xc3, 0x2d, 0xf6, 0xe4, 0x2e, 0xc0, 0x51, 0xc8, 0xa8, 0x98, 0x1d, 0x8a, 0x48, 0xda, 0x35,
|
||||
0xe3, 0xec, 0x7f, 0xe7, 0xba, 0x92, 0x33, 0x28, 0xf8, 0xb4, 0x97, 0x97, 0x14, 0xda, 0x77, 0xa1,
|
||||
0x55, 0xa1, 0x97, 0xdc, 0xd9, 0xd5, 0xf2, 0x9d, 0x35, 0xca, 0x39, 0xbe, 0x09, 0xab, 0xe9, 0x79,
|
||||
0x08, 0x81, 0x15, 0x46, 0x27, 0x98, 0xa9, 0x99, 0x75, 0xf7, 0x73, 0x68, 0x14, 0x1f, 0x1f, 0xd9,
|
||||
0x03, 0xf0, 0x38, 0x63, 0xe8, 0x29, 0x2e, 0xf2, 0xac, 0x9c, 0x7d, 0x90, 0xc3, 0x9c, 0x72, 0x4b,
|
||||
0x52, 0xdd, 0x3b, 0xd0, 0x28, 0x88, 0x65, 0x1e, 0x34, 0xa6, 0x66, 0x71, 0x1e, 0x98, 0x59, 0x77,
|
||||
0x7f, 0xa8, 0x41, 0xe9, 0xb3, 0x5c, 0xaa, 0xb6, 0x05, 0xab, 0xa1, 0x94, 0x09, 0x8a, 0x4c, 0x31,
|
||||
0xdb, 0x91, 0x1e, 0xd4, 0xbd, 0x28, 0x44, 0xa6, 0xc6, 0x23, 0xf3, 0x1f, 0x37, 0x06, 0x97, 0xe6,
|
||||
0xa7, 0x3b, 0xf5, 0x61, 0x86, 0xb9, 0x05, 0x4b, 0x76, 0xa1, 0xe9, 0x45, 0x61, 0x4e, 0xa4, 0xdf,
|
||||
0xee, 0xa0, 0x35, 0x3f, 0xdd, 0x69, 0x0e, 0xf7, 0xc7, 0x85, 0x7c, 0x59, 0x46, 0x3b, 0x95, 0x1e,
|
||||
0x8f, 0xb3, 0xcf, 0xb7, 0xe1, 0x66, 0x3b, 0xf2, 0x12, 0xd6, 0x43, 0xff, 0x39, 0x3f, 0x41, 0x36,
|
||||
0x34, 0x83, 0x88, 0xbd, 0x6a, 0x72, 0x73, 0x6b, 0xc9, 0x24, 0xe0, 0x8c, 0xcb, 0x82, 0xe6, 0xba,
|
||||
0x06, 0x9b, 0xf3, 0xd3, 0x9d, 0xf5, 0xf1, 0xa8, 0x84, 0xbb, 0xe7, 0xed, 0xb5, 0x67, 0x40, 0x16,
|
||||
0xf5, 0x96, 0x5c, 0xf3, 0xe3, 0xf3, 0x4f, 0xf3, 0xe3, 0xb7, 0x3e, 0xcd, 0x74, 0x92, 0x72, 0x8a,
|
||||
0x51, 0x50, 0x8f, 0x24, 0x8e, 0xb1, 0x5f, 0xaa, 0x8f, 0xbd, 0xdf, 0x2c, 0x68, 0xe5, 0x6f, 0xe4,
|
||||
0x19, 0x8a, 0x69, 0xe8, 0x21, 0xf9, 0x12, 0x6a, 0x0f, 0x50, 0x91, 0xad, 0x85, 0xd9, 0xc3, 0xcc,
|
||||
0x5b, 0xed, 0xcd, 0x05, 0xbc, 0x6b, 0x7f, 0xff, 0xe7, 0xdf, 0x3f, 0x5d, 0x20, 0x64, 0xc3, 0xcc,
|
||||
0x90, 0xd3, 0xdd, 0x62, 0x7e, 0x23, 0xc7, 0x00, 0x0f, 0xb0, 0xf8, 0x8c, 0xde, 0x64, 0xb2, 0xb3,
|
||||
0x80, 0x57, 0xde, 0x6b, 0xb7, 0x63, 0x3c, 0xb4, 0x89, 0x5d, 0xf5, 0xd0, 0xcf, 0x9e, 0xe9, 0x60,
|
||||
0xf8, 0xfb, 0x7c, 0xdb, 0xfa, 0x63, 0xbe, 0x6d, 0xfd, 0x35, 0xdf, 0xb6, 0xbe, 0xfe, 0xe8, 0xbf,
|
||||
0x4d, 0xad, 0x69, 0xb9, 0x14, 0xc6, 0x8e, 0x56, 0xcd, 0x8c, 0x79, 0xe7, 0x9f, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xc5, 0x72, 0xeb, 0x5e, 0x52, 0x0b, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -772,6 +823,8 @@ const _ = grpc.SupportPackageIsVersion4
|
||||
type SettingsServiceClient interface {
|
||||
// Get returns Argo CD settings
|
||||
Get(ctx context.Context, in *SettingsQuery, opts ...grpc.CallOption) (*Settings, error)
|
||||
// Get returns Argo CD plugins
|
||||
GetPlugins(ctx context.Context, in *SettingsQuery, opts ...grpc.CallOption) (*SettingsPluginsResponse, error)
|
||||
}
|
||||
|
||||
type settingsServiceClient struct {
|
||||
@@ -791,10 +844,21 @@ func (c *settingsServiceClient) Get(ctx context.Context, in *SettingsQuery, opts
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *settingsServiceClient) GetPlugins(ctx context.Context, in *SettingsQuery, opts ...grpc.CallOption) (*SettingsPluginsResponse, error) {
|
||||
out := new(SettingsPluginsResponse)
|
||||
err := c.cc.Invoke(ctx, "/cluster.SettingsService/GetPlugins", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// SettingsServiceServer is the server API for SettingsService service.
|
||||
type SettingsServiceServer interface {
|
||||
// Get returns Argo CD settings
|
||||
Get(context.Context, *SettingsQuery) (*Settings, error)
|
||||
// Get returns Argo CD plugins
|
||||
GetPlugins(context.Context, *SettingsQuery) (*SettingsPluginsResponse, error)
|
||||
}
|
||||
|
||||
// UnimplementedSettingsServiceServer can be embedded to have forward compatible implementations.
|
||||
@@ -804,6 +868,9 @@ type UnimplementedSettingsServiceServer struct {
|
||||
func (*UnimplementedSettingsServiceServer) Get(ctx context.Context, req *SettingsQuery) (*Settings, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Get not implemented")
|
||||
}
|
||||
func (*UnimplementedSettingsServiceServer) GetPlugins(ctx context.Context, req *SettingsQuery) (*SettingsPluginsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetPlugins not implemented")
|
||||
}
|
||||
|
||||
func RegisterSettingsServiceServer(s *grpc.Server, srv SettingsServiceServer) {
|
||||
s.RegisterService(&_SettingsService_serviceDesc, srv)
|
||||
@@ -827,6 +894,24 @@ func _SettingsService_Get_Handler(srv interface{}, ctx context.Context, dec func
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SettingsService_GetPlugins_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SettingsQuery)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SettingsServiceServer).GetPlugins(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/cluster.SettingsService/GetPlugins",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SettingsServiceServer).GetPlugins(ctx, req.(*SettingsQuery))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _SettingsService_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "cluster.SettingsService",
|
||||
HandlerType: (*SettingsServiceServer)(nil),
|
||||
@@ -835,6 +920,10 @@ var _SettingsService_serviceDesc = grpc.ServiceDesc{
|
||||
MethodName: "Get",
|
||||
Handler: _SettingsService_Get_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetPlugins",
|
||||
Handler: _SettingsService_GetPlugins_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "server/settings/settings.proto",
|
||||
@@ -1199,6 +1288,47 @@ func (m *GoogleAnalyticsConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *SettingsPluginsResponse) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *SettingsPluginsResponse) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *SettingsPluginsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.XXX_unrecognized != nil {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.Plugins) > 0 {
|
||||
for iNdEx := len(m.Plugins) - 1; iNdEx >= 0; iNdEx-- {
|
||||
{
|
||||
size, err := m.Plugins[iNdEx].MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintSettings(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *Help) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
@@ -1625,6 +1755,24 @@ func (m *GoogleAnalyticsConfig) Size() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *SettingsPluginsResponse) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Plugins) > 0 {
|
||||
for _, e := range m.Plugins {
|
||||
l = e.Size()
|
||||
n += 1 + l + sovSettings(uint64(l))
|
||||
}
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *Help) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
@@ -2794,6 +2942,91 @@ func (m *GoogleAnalyticsConfig) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *SettingsPluginsResponse) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: SettingsPluginsResponse: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: SettingsPluginsResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Plugins", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Plugins = append(m.Plugins, &Plugin{})
|
||||
if err := m.Plugins[len(m.Plugins)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSettings(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *Help) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
|
||||
@@ -51,6 +51,24 @@ func local_request_SettingsService_Get_0(ctx context.Context, marshaler runtime.
|
||||
|
||||
}
|
||||
|
||||
func request_SettingsService_GetPlugins_0(ctx context.Context, marshaler runtime.Marshaler, client SettingsServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq SettingsQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := client.GetPlugins(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_SettingsService_GetPlugins_0(ctx context.Context, marshaler runtime.Marshaler, server SettingsServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq SettingsQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := server.GetPlugins(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterSettingsServiceHandlerServer registers the http handlers for service SettingsService to "mux".
|
||||
// UnaryRPC :call SettingsServiceServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
@@ -80,6 +98,29 @@ func RegisterSettingsServiceHandlerServer(ctx context.Context, mux *runtime.Serv
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_SettingsService_GetPlugins_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_SettingsService_GetPlugins_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_SettingsService_GetPlugins_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -141,13 +182,37 @@ func RegisterSettingsServiceHandlerClient(ctx context.Context, mux *runtime.Serv
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_SettingsService_GetPlugins_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_SettingsService_GetPlugins_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_SettingsService_GetPlugins_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_SettingsService_Get_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "settings"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_SettingsService_GetPlugins_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "settings", "plugins"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
)
|
||||
|
||||
var (
|
||||
forward_SettingsService_Get_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_SettingsService_GetPlugins_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
|
||||
@@ -47,6 +47,11 @@ type ApplicationSet struct {
|
||||
Status ApplicationSetStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
}
|
||||
|
||||
// RBACName formats fully qualified application name for RBAC check.
|
||||
func (a *ApplicationSet) RBACName() string {
|
||||
return fmt.Sprintf("%s/%s", a.Spec.Template.Spec.GetProject(), a.ObjectMeta.Name)
|
||||
}
|
||||
|
||||
// ApplicationSetSpec represents a class of application set state.
|
||||
type ApplicationSetSpec struct {
|
||||
GoTemplate bool `json:"goTemplate,omitempty" protobuf:"bytes,1,name=goTemplate"`
|
||||
@@ -308,7 +313,7 @@ type GitGenerator struct {
|
||||
Revision string `json:"revision" protobuf:"bytes,4,name=revision"`
|
||||
RequeueAfterSeconds *int64 `json:"requeueAfterSeconds,omitempty" protobuf:"bytes,5,name=requeueAfterSeconds"`
|
||||
Template ApplicationSetTemplate `json:"template,omitempty" protobuf:"bytes,6,name=template"`
|
||||
PathParamPrefix string `json:"pathParamPrefix" protobuf:"bytes,7,name=pathParamPrefix"`
|
||||
PathParamPrefix string `json:"pathParamPrefix,omitempty" protobuf:"bytes,7,name=pathParamPrefix"`
|
||||
}
|
||||
|
||||
type GitDirectoryGeneratorItem struct {
|
||||
|
||||
@@ -3066,13 +3066,12 @@ func schema_pkg_apis_application_v1alpha1_GitGenerator(ref common.ReferenceCallb
|
||||
},
|
||||
"pathParamPrefix": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"repoURL", "revision", "pathParamPrefix"},
|
||||
Required: []string{"repoURL", "revision"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/util/collections"
|
||||
"github.com/argoproj/argo-cd/v2/util/helm"
|
||||
"github.com/argoproj/argo-cd/v2/util/security"
|
||||
)
|
||||
|
||||
// Application is a definition of Application resource.
|
||||
@@ -2695,9 +2696,5 @@ func (a *Application) QualifiedName() string {
|
||||
// RBACName returns the full qualified RBAC resource name for the application
|
||||
// in a backwards-compatible way.
|
||||
func (a *Application) RBACName(defaultNS string) string {
|
||||
if defaultNS != "" && a.Namespace != defaultNS && a.Namespace != "" {
|
||||
return fmt.Sprintf("%s/%s/%s", a.Spec.GetProject(), a.Namespace, a.Name)
|
||||
} else {
|
||||
return fmt.Sprintf("%s/%s", a.Spec.GetProject(), a.Name)
|
||||
}
|
||||
return security.AppRBACName(defaultNS, a.Spec.GetProject(), a.Namespace, a.Name)
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ func (s *Service) runRepoOperation(
|
||||
if hasMultipleSources && source.Path == "" && source.Chart == "" {
|
||||
log.WithFields(map[string]interface{}{
|
||||
"source": source,
|
||||
}).Warnf("not generating manifests as path and chart fields are empty")
|
||||
}).Debugf("not generating manifests as path and chart fields are empty")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -54,6 +54,7 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/util/lua"
|
||||
"github.com/argoproj/argo-cd/v2/util/manifeststream"
|
||||
"github.com/argoproj/argo-cd/v2/util/rbac"
|
||||
"github.com/argoproj/argo-cd/v2/util/security"
|
||||
"github.com/argoproj/argo-cd/v2/util/session"
|
||||
"github.com/argoproj/argo-cd/v2/util/settings"
|
||||
)
|
||||
@@ -210,7 +211,7 @@ func (s *Server) Create(ctx context.Context, q *application.ApplicationCreateReq
|
||||
appNs := s.appNamespaceOrDefault(a.Namespace)
|
||||
|
||||
if !s.isNamespaceEnabled(appNs) {
|
||||
return nil, namespaceNotPermittedError(appNs)
|
||||
return nil, security.NamespaceNotPermittedError(appNs)
|
||||
}
|
||||
|
||||
created, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Create(ctx, a, metav1.CreateOptions{})
|
||||
@@ -343,7 +344,7 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan
|
||||
}
|
||||
|
||||
if !s.isNamespaceEnabled(a.Namespace) {
|
||||
return nil, namespaceNotPermittedError(a.Namespace)
|
||||
return nil, security.NamespaceNotPermittedError(a.Namespace)
|
||||
}
|
||||
|
||||
var manifestInfo *apiclient.ManifestResponse
|
||||
@@ -2350,9 +2351,5 @@ func (s *Server) appNamespaceOrDefault(appNs string) string {
|
||||
}
|
||||
|
||||
func (s *Server) isNamespaceEnabled(namespace string) bool {
|
||||
return namespace == s.ns || glob.MatchStringInList(s.enabledNamespaces, namespace, false)
|
||||
}
|
||||
|
||||
func namespaceNotPermittedError(namespace string) error {
|
||||
return fmt.Errorf("namespace '%s' is not permitted", namespace)
|
||||
return security.IsNamespaceEnabled(namespace, s.ns, s.enabledNamespaces)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
@@ -24,7 +23,9 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/util/argo"
|
||||
"github.com/argoproj/argo-cd/v2/util/db"
|
||||
"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 {
|
||||
@@ -35,10 +36,11 @@ type terminalHandler struct {
|
||||
appResourceTreeFn func(ctx context.Context, app *appv1.Application) (*appv1.ApplicationTree, error)
|
||||
allowedShells []string
|
||||
namespace string
|
||||
enabledNamespaces []string
|
||||
}
|
||||
|
||||
// NewHandler returns a new terminal handler.
|
||||
func NewHandler(appLister applisters.ApplicationLister, namespace string, db db.ArgoDB, enf *rbac.Enforcer, cache *servercache.Cache,
|
||||
func NewHandler(appLister applisters.ApplicationLister, namespace string, enabledNamespaces []string, db db.ArgoDB, enf *rbac.Enforcer, cache *servercache.Cache,
|
||||
appResourceTree AppResourceTreeFn, allowedShells []string) *terminalHandler {
|
||||
return &terminalHandler{
|
||||
appLister: appLister,
|
||||
@@ -48,6 +50,7 @@ func NewHandler(appLister applisters.ApplicationLister, namespace string, db db.
|
||||
appResourceTreeFn: appResourceTree,
|
||||
allowedShells: allowedShells,
|
||||
namespace: namespace,
|
||||
enabledNamespaces: enabledNamespaces,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,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()
|
||||
|
||||
@@ -107,6 +130,8 @@ func (s *terminalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
appNamespace := q.Get("appNamespace")
|
||||
|
||||
if !isValidPodName(podName) {
|
||||
http.Error(w, "Pod name is not valid", http.StatusBadRequest)
|
||||
return
|
||||
@@ -127,11 +152,26 @@ func (s *terminalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "Namespace name is not valid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if !isValidNamespaceName(appNamespace) {
|
||||
http.Error(w, "App namespace name is not valid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
ns := appNamespace
|
||||
if ns == "" {
|
||||
ns = s.namespace
|
||||
}
|
||||
|
||||
if !security.IsNamespaceEnabled(ns, s.namespace, s.enabledNamespaces) {
|
||||
http.Error(w, security.NamespaceNotPermittedError(ns).Error(), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
shell := q.Get("shell") // No need to validate. Will only be used if it's in the allow-list.
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
appRBACName := fmt.Sprintf("%s/%s", project, app)
|
||||
appRBACName := security.AppRBACName(s.namespace, project, appNamespace, app)
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, appRBACName); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusUnauthorized)
|
||||
return
|
||||
@@ -143,9 +183,9 @@ func (s *terminalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
fieldLog := log.WithFields(log.Fields{"application": app, "userName": sessionmgr.Username(ctx), "container": container,
|
||||
"podName": podName, "namespace": namespace, "cluster": project})
|
||||
"podName": podName, "namespace": namespace, "project": project, "appNamespace": appNamespace})
|
||||
|
||||
a, err := s.appLister.Applications(s.namespace).Get(app)
|
||||
a, err := s.appLister.Applications(ns).Get(app)
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
http.Error(w, "App not found", http.StatusNotFound)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/util/security"
|
||||
)
|
||||
|
||||
func TestPodExists(t *testing.T) {
|
||||
@@ -195,24 +196,24 @@ func TestTerminalHandler_ServeHTTP_empty_params(t *testing.T) {
|
||||
for _, testValue := range testValues {
|
||||
testValueCopy := testValue
|
||||
|
||||
t.Run(testKeyCopy+ " " + testValueCopy, func(t *testing.T) {
|
||||
t.Run(testKeyCopy+" "+testValueCopy, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
handler := terminalHandler{}
|
||||
params := map[string]string{
|
||||
"pod": "valid",
|
||||
"pod": "valid",
|
||||
"container": "valid",
|
||||
"app": "valid",
|
||||
"project": "valid",
|
||||
"app": "valid",
|
||||
"project": "valid",
|
||||
"namespace": "valid",
|
||||
}
|
||||
params[testKeyCopy] = testValueCopy
|
||||
var paramsArray []string
|
||||
for key, value := range params {
|
||||
paramsArray = append(paramsArray, key + "=" + value)
|
||||
paramsArray = append(paramsArray, key+"="+value)
|
||||
}
|
||||
paramsString := strings.Join(paramsArray, "&")
|
||||
request := httptest.NewRequest("GET", "https://argocd.example.com/api/v1/terminal?" + paramsString, nil)
|
||||
request := httptest.NewRequest("GET", "https://argocd.example.com/api/v1/terminal?"+paramsString, nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, request)
|
||||
response := recorder.Result()
|
||||
@@ -221,3 +222,13 @@ func TestTerminalHandler_ServeHTTP_empty_params(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTerminalHandler_ServeHTTP_disallowed_namespace(t *testing.T) {
|
||||
handler := terminalHandler{namespace: "argocd", enabledNamespaces: []string{"allowed"}}
|
||||
request := httptest.NewRequest("GET", "https://argocd.example.com/api/v1/terminal?pod=valid&container=valid&appName=valid&projectName=valid&namespace=test&appNamespace=disallowed", nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, request)
|
||||
response := recorder.Result()
|
||||
assert.Equal(t, http.StatusForbidden, response.StatusCode)
|
||||
assert.Equal(t, security.NamespaceNotPermittedError("disallowed").Error()+"\n", recorder.Body.String())
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
applisters "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
|
||||
servercache "github.com/argoproj/argo-cd/v2/server/cache"
|
||||
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
|
||||
apputil "github.com/argoproj/argo-cd/v2/util/appset"
|
||||
"github.com/argoproj/argo-cd/v2/util/argo"
|
||||
argoutil "github.com/argoproj/argo-cd/v2/util/argo"
|
||||
"github.com/argoproj/argo-cd/v2/util/db"
|
||||
@@ -89,7 +88,7 @@ func (s *Server) Get(ctx context.Context, q *applicationset.ApplicationSetGetQue
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting ApplicationSet: %w", err)
|
||||
}
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionGet, apputil.AppSetRBACName(a)); err != nil {
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionGet, a.RBACName()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -111,7 +110,7 @@ func (s *Server) List(ctx context.Context, q *applicationset.ApplicationSetListQ
|
||||
|
||||
newItems := make([]v1alpha1.ApplicationSet, 0)
|
||||
for _, a := range appsetList.Items {
|
||||
if s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionGet, apputil.AppSetRBACName(&a)) {
|
||||
if s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionGet, a.RBACName()) {
|
||||
newItems = append(newItems, a)
|
||||
}
|
||||
}
|
||||
@@ -182,7 +181,7 @@ func (s *Server) Create(ctx context.Context, q *applicationset.ApplicationSetCre
|
||||
if !q.Upsert {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "existing ApplicationSet spec is different, use upsert flag to force update")
|
||||
}
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionUpdate, apputil.AppSetRBACName(appset)); err != nil {
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionUpdate, appset.RBACName()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updated, err := s.updateAppSet(existing, appset, ctx, true)
|
||||
@@ -210,11 +209,11 @@ func (s *Server) updateAppSet(appset *v1alpha1.ApplicationSet, newAppset *v1alph
|
||||
if appset != nil && appset.Spec.Template.Spec.Project != newAppset.Spec.Template.Spec.Project {
|
||||
// When changing projects, caller must have applicationset create and update privileges in new project
|
||||
// NOTE: the update check was already verified in the caller to this function
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionCreate, apputil.AppSetRBACName(newAppset)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionCreate, newAppset.RBACName()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// They also need 'update' privileges in the old project
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionUpdate, apputil.AppSetRBACName(appset)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionUpdate, appset.RBACName()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -254,7 +253,7 @@ func (s *Server) Delete(ctx context.Context, q *applicationset.ApplicationSetDel
|
||||
return nil, fmt.Errorf("error getting ApplicationSets: %w", err)
|
||||
}
|
||||
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionDelete, apputil.AppSetRBACName(appset)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionDelete, appset.RBACName()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -290,7 +289,7 @@ func (s *Server) validateAppSet(ctx context.Context, appset *v1alpha1.Applicatio
|
||||
|
||||
func (s *Server) checkCreatePermissions(ctx context.Context, appset *v1alpha1.ApplicationSet, projectName string) error {
|
||||
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionCreate, apputil.AppSetRBACName(appset)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionCreate, appset.RBACName()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -906,40 +906,10 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
|
||||
}
|
||||
mux.Handle("/api/", handler)
|
||||
|
||||
terminalHandler := application.NewHandler(a.appLister, a.Namespace, 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)
|
||||
|
||||
// Dead code for now
|
||||
// Proxy extension is currently an experimental feature and is disabled
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
appstatecache "github.com/argoproj/argo-cd/v2/util/cache/appstate"
|
||||
"github.com/argoproj/argo-cd/v2/util/rbac"
|
||||
settings_util "github.com/argoproj/argo-cd/v2/util/settings"
|
||||
testutil "github.com/argoproj/argo-cd/v2/util/test"
|
||||
)
|
||||
|
||||
func fakeServer() (*ArgoCDServer, func()) {
|
||||
@@ -522,7 +523,7 @@ func dexMockHandler(t *testing.T, url string) func(http.ResponseWriter, *http.Re
|
||||
}
|
||||
}
|
||||
|
||||
func getTestServer(t *testing.T, anonymousEnabled bool, withFakeSSO bool) (argocd *ArgoCDServer, dexURL string) {
|
||||
func getTestServer(t *testing.T, anonymousEnabled bool, withFakeSSO bool, useDexForSSO bool) (argocd *ArgoCDServer, oidcURL string) {
|
||||
cm := test.NewFakeConfigMap()
|
||||
if anonymousEnabled {
|
||||
cm.Data["users.anonymous.enabled"] = "true"
|
||||
@@ -533,9 +534,14 @@ func getTestServer(t *testing.T, anonymousEnabled bool, withFakeSSO bool) (argoc
|
||||
ts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
dexMockHandler(t, ts.URL)(w, r)
|
||||
})
|
||||
oidcServer := ts
|
||||
if !useDexForSSO {
|
||||
oidcServer = testutil.GetOIDCTestServer(t)
|
||||
}
|
||||
if withFakeSSO {
|
||||
cm.Data["url"] = ts.URL
|
||||
cm.Data["dex.config"] = `
|
||||
if useDexForSSO {
|
||||
cm.Data["dex.config"] = `
|
||||
connectors:
|
||||
# OIDC
|
||||
- type: OIDC
|
||||
@@ -545,6 +551,19 @@ connectors:
|
||||
issuer: https://auth.example.gom
|
||||
clientID: test-client
|
||||
clientSecret: $dex.oidc.clientSecret`
|
||||
} else {
|
||||
oidcConfig := settings_util.OIDCConfig{
|
||||
Name: "Okta",
|
||||
Issuer: oidcServer.URL,
|
||||
ClientID: "argo-cd",
|
||||
ClientSecret: "$oidc.okta.clientSecret",
|
||||
}
|
||||
oidcConfigString, err := yaml.Marshal(oidcConfig)
|
||||
require.NoError(t, err)
|
||||
cm.Data["oidc.config"] = string(oidcConfigString)
|
||||
// Avoid bothering with certs for local tests.
|
||||
cm.Data["oidc.tls.insecure.skip.verify"] = "true"
|
||||
}
|
||||
}
|
||||
secret := test.NewFakeSecret()
|
||||
kubeclientset := fake.NewSimpleClientset(cm, secret)
|
||||
@@ -556,27 +575,32 @@ connectors:
|
||||
AppClientset: appClientSet,
|
||||
RepoClientset: mockRepoClient,
|
||||
}
|
||||
if withFakeSSO {
|
||||
if withFakeSSO && useDexForSSO {
|
||||
argoCDOpts.DexServerAddr = ts.URL
|
||||
}
|
||||
argocd = NewServer(context.Background(), argoCDOpts)
|
||||
return argocd, ts.URL
|
||||
return argocd, oidcServer.URL
|
||||
}
|
||||
|
||||
func TestAuthenticate_3rd_party_JWTs(t *testing.T) {
|
||||
// Marshaling single strings to strings is typical, so we test for this relatively common behavior.
|
||||
jwt.MarshalSingleStringAsArray = false
|
||||
|
||||
type testData struct {
|
||||
test string
|
||||
anonymousEnabled bool
|
||||
claims jwt.RegisteredClaims
|
||||
expectedErrorContains string
|
||||
expectedClaims interface{}
|
||||
useDex bool
|
||||
}
|
||||
var tests = []testData{
|
||||
// Dex
|
||||
{
|
||||
test: "anonymous disabled, no audience",
|
||||
anonymousEnabled: false,
|
||||
claims: jwt.RegisteredClaims{},
|
||||
expectedErrorContains: "no audience found in the token",
|
||||
claims: jwt.RegisteredClaims{ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))},
|
||||
expectedErrorContains: common.TokenVerificationError,
|
||||
expectedClaims: nil,
|
||||
},
|
||||
{
|
||||
@@ -589,31 +613,95 @@ func TestAuthenticate_3rd_party_JWTs(t *testing.T) {
|
||||
{
|
||||
test: "anonymous disabled, unexpired token, admin claim",
|
||||
anonymousEnabled: false,
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))},
|
||||
expectedErrorContains: "id token signed with unsupported algorithm",
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))},
|
||||
expectedErrorContains: common.TokenVerificationError,
|
||||
expectedClaims: nil,
|
||||
},
|
||||
{
|
||||
test: "anonymous enabled, unexpired token, admin claim",
|
||||
anonymousEnabled: true,
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))},
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))},
|
||||
expectedErrorContains: "",
|
||||
expectedClaims: "",
|
||||
},
|
||||
{
|
||||
test: "anonymous disabled, expired token, admin claim",
|
||||
anonymousEnabled: false,
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now())},
|
||||
expectedErrorContains: "token is expired",
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now())},
|
||||
expectedErrorContains: common.TokenVerificationError,
|
||||
expectedClaims: jwt.RegisteredClaims{Issuer: "sso"},
|
||||
},
|
||||
{
|
||||
test: "anonymous enabled, expired token, admin claim",
|
||||
anonymousEnabled: true,
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now())},
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now())},
|
||||
expectedErrorContains: "",
|
||||
expectedClaims: "",
|
||||
},
|
||||
{
|
||||
test: "anonymous disabled, unexpired token, admin claim, incorrect audience",
|
||||
anonymousEnabled: false,
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"incorrect-audience"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))},
|
||||
expectedErrorContains: common.TokenVerificationError,
|
||||
expectedClaims: nil,
|
||||
},
|
||||
// External OIDC (not bundled Dex)
|
||||
{
|
||||
test: "external OIDC: anonymous disabled, no audience",
|
||||
anonymousEnabled: false,
|
||||
claims: jwt.RegisteredClaims{ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))},
|
||||
useDex: true,
|
||||
expectedErrorContains: common.TokenVerificationError,
|
||||
expectedClaims: nil,
|
||||
},
|
||||
{
|
||||
test: "external OIDC: anonymous enabled, no audience",
|
||||
anonymousEnabled: true,
|
||||
claims: jwt.RegisteredClaims{},
|
||||
useDex: true,
|
||||
expectedErrorContains: "",
|
||||
expectedClaims: "",
|
||||
},
|
||||
{
|
||||
test: "external OIDC: anonymous disabled, unexpired token, admin claim",
|
||||
anonymousEnabled: false,
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))},
|
||||
useDex: true,
|
||||
expectedErrorContains: common.TokenVerificationError,
|
||||
expectedClaims: nil,
|
||||
},
|
||||
{
|
||||
test: "external OIDC: anonymous enabled, unexpired token, admin claim",
|
||||
anonymousEnabled: true,
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))},
|
||||
useDex: true,
|
||||
expectedErrorContains: "",
|
||||
expectedClaims: "",
|
||||
},
|
||||
{
|
||||
test: "external OIDC: anonymous disabled, expired token, admin claim",
|
||||
anonymousEnabled: false,
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now())},
|
||||
useDex: true,
|
||||
expectedErrorContains: common.TokenVerificationError,
|
||||
expectedClaims: jwt.RegisteredClaims{Issuer: "sso"},
|
||||
},
|
||||
{
|
||||
test: "external OIDC: anonymous enabled, expired token, admin claim",
|
||||
anonymousEnabled: true,
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now())},
|
||||
useDex: true,
|
||||
expectedErrorContains: "",
|
||||
expectedClaims: "",
|
||||
},
|
||||
{
|
||||
test: "external OIDC: anonymous disabled, unexpired token, admin claim, incorrect audience",
|
||||
anonymousEnabled: false,
|
||||
claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"incorrect-audience"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))},
|
||||
useDex: true,
|
||||
expectedErrorContains: common.TokenVerificationError,
|
||||
expectedClaims: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testData := range tests {
|
||||
@@ -625,8 +713,13 @@ func TestAuthenticate_3rd_party_JWTs(t *testing.T) {
|
||||
// Must be declared here to avoid race.
|
||||
ctx := context.Background() //nolint:ineffassign,staticcheck
|
||||
|
||||
argocd, dexURL := getTestServer(t, testDataCopy.anonymousEnabled, true)
|
||||
testDataCopy.claims.Issuer = fmt.Sprintf("%s/api/dex", dexURL)
|
||||
argocd, oidcURL := getTestServer(t, testDataCopy.anonymousEnabled, true, testDataCopy.useDex)
|
||||
|
||||
if testDataCopy.useDex {
|
||||
testDataCopy.claims.Issuer = fmt.Sprintf("%s/api/dex", oidcURL)
|
||||
} else {
|
||||
testDataCopy.claims.Issuer = oidcURL
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, testDataCopy.claims)
|
||||
tokenString, err := token.SignedString([]byte("key"))
|
||||
require.NoError(t, err)
|
||||
@@ -676,7 +769,7 @@ func TestAuthenticate_no_request_metadata(t *testing.T) {
|
||||
t.Run(testDataCopy.test, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
argocd, _ := getTestServer(t, testDataCopy.anonymousEnabled, true)
|
||||
argocd, _ := getTestServer(t, testDataCopy.anonymousEnabled, true, true)
|
||||
ctx := context.Background()
|
||||
|
||||
ctx, err := argocd.Authenticate(ctx)
|
||||
@@ -722,7 +815,7 @@ func TestAuthenticate_no_SSO(t *testing.T) {
|
||||
// Must be declared here to avoid race.
|
||||
ctx := context.Background() //nolint:ineffassign,staticcheck
|
||||
|
||||
argocd, dexURL := getTestServer(t, testDataCopy.anonymousEnabled, false)
|
||||
argocd, dexURL := getTestServer(t, testDataCopy.anonymousEnabled, false, true)
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{Issuer: fmt.Sprintf("%s/api/dex", dexURL)})
|
||||
tokenString, err := token.SignedString([]byte("key"))
|
||||
require.NoError(t, err)
|
||||
@@ -795,7 +888,7 @@ func TestAuthenticate_bad_request_metadata(t *testing.T) {
|
||||
test: "anonymous disabled, bad auth header",
|
||||
anonymousEnabled: false,
|
||||
metadata: metadata.MD{"authorization": []string{"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9.TGGTTHuuGpEU8WgobXxkrBtW3NiR3dgw5LR-1DEW3BQ"}},
|
||||
expectedErrorMessage: "no audience found in the token",
|
||||
expectedErrorMessage: common.TokenVerificationError,
|
||||
expectedClaims: nil,
|
||||
},
|
||||
{
|
||||
@@ -809,7 +902,7 @@ func TestAuthenticate_bad_request_metadata(t *testing.T) {
|
||||
test: "anonymous disabled, bad auth cookie",
|
||||
anonymousEnabled: false,
|
||||
metadata: metadata.MD{"grpcgateway-cookie": []string{"argocd.token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9.TGGTTHuuGpEU8WgobXxkrBtW3NiR3dgw5LR-1DEW3BQ"}},
|
||||
expectedErrorMessage: "no audience found in the token",
|
||||
expectedErrorMessage: common.TokenVerificationError,
|
||||
expectedClaims: nil,
|
||||
},
|
||||
{
|
||||
@@ -830,7 +923,7 @@ func TestAuthenticate_bad_request_metadata(t *testing.T) {
|
||||
// Must be declared here to avoid race.
|
||||
ctx := context.Background() //nolint:ineffassign,staticcheck
|
||||
|
||||
argocd, _ := getTestServer(t, testDataCopy.anonymousEnabled, true)
|
||||
argocd, _ := getTestServer(t, testDataCopy.anonymousEnabled, true, true)
|
||||
ctx = metadata.NewIncomingContext(context.Background(), testDataCopy.metadata)
|
||||
|
||||
ctx, err := argocd.Authenticate(ctx)
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
ioutil "github.com/argoproj/argo-cd/v2/util/io"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
ioutil "github.com/argoproj/argo-cd/v2/util/io"
|
||||
|
||||
sessionmgr "github.com/argoproj/argo-cd/v2/util/session"
|
||||
|
||||
@@ -62,7 +62,7 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plugins, err := s.plugins(ctx)
|
||||
plugins, err := s.plugins(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -158,29 +158,41 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin
|
||||
return &set, nil
|
||||
}
|
||||
|
||||
func (s *Server) plugins(ctx context.Context) ([]*settingspkg.Plugin, error) {
|
||||
// GetPlugins returns a list of plugins
|
||||
func (s *Server) GetPlugins(ctx context.Context, q *settingspkg.SettingsQuery) (*settingspkg.SettingsPluginsResponse, error) {
|
||||
plugins, err := s.plugins(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settingspkg.SettingsPluginsResponse{Plugins: plugins}, nil
|
||||
}
|
||||
|
||||
func (s *Server) plugins(ctx context.Context, includeV2Plugins bool) ([]*settingspkg.Plugin, error) {
|
||||
in, err := s.mgr.GetConfigManagementPlugins()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
closer, client, err := s.repoClient.NewRepoServerClient()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating repo server client: %w", err)
|
||||
}
|
||||
defer ioutil.Close(closer)
|
||||
|
||||
pluginList, err := client.ListPlugins(ctx, &empty.Empty{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list sidecar plugins from reposerver: %w", err)
|
||||
}
|
||||
out := []*settingspkg.Plugin{}
|
||||
var out []*settingspkg.Plugin
|
||||
for _, p := range in {
|
||||
out = append(out, &settingspkg.Plugin{Name: p.Name})
|
||||
|
||||
}
|
||||
if pluginList != nil && len(pluginList.Items) > 0 {
|
||||
for _, p := range pluginList.Items {
|
||||
out = append(out, &settingspkg.Plugin{Name: p.Name})
|
||||
|
||||
if includeV2Plugins {
|
||||
closer, client, err := s.repoClient.NewRepoServerClient()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating repo server client: %w", err)
|
||||
}
|
||||
defer ioutil.Close(closer)
|
||||
|
||||
pluginList, err := client.ListPlugins(ctx, &empty.Empty{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list sidecar plugins from reposerver: %w", err)
|
||||
}
|
||||
|
||||
if pluginList != nil && len(pluginList.Items) > 0 {
|
||||
for _, p := range pluginList.Items {
|
||||
out = append(out, &settingspkg.Plugin{Name: p.Name})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +201,11 @@ func (s *Server) plugins(ctx context.Context) ([]*settingspkg.Plugin, error) {
|
||||
|
||||
// AuthFuncOverride disables authentication for settings service
|
||||
func (s *Server) AuthFuncOverride(ctx context.Context, fullMethodName string) (context.Context, error) {
|
||||
// this authenticates the user, but ignores any error, so that we have claims populated
|
||||
ctx, _ = s.authenticator.Authenticate(ctx)
|
||||
return ctx, nil
|
||||
ctx, err := s.authenticator.Authenticate(ctx)
|
||||
if fullMethodName == "/cluster.SettingsService/Get" {
|
||||
// SettingsService/Get API is used by login page.
|
||||
// This authenticates the user, but ignores any error, so that we have claims populated
|
||||
err = nil
|
||||
}
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
@@ -48,6 +48,10 @@ message GoogleAnalyticsConfig {
|
||||
bool anonymizeUsers = 2;
|
||||
}
|
||||
|
||||
message SettingsPluginsResponse {
|
||||
repeated Plugin plugins = 1;
|
||||
}
|
||||
|
||||
// Help settings
|
||||
message Help {
|
||||
// the URL for getting chat help, this will typically be your Slack channel for support
|
||||
@@ -64,7 +68,6 @@ message Plugin {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
|
||||
message DexConfig {
|
||||
repeated Connector connectors = 1;
|
||||
}
|
||||
@@ -88,7 +91,11 @@ service SettingsService {
|
||||
|
||||
// Get returns Argo CD settings
|
||||
rpc Get(SettingsQuery) returns (Settings) {
|
||||
option (google.api.http).get = "/api/v1/settings";
|
||||
}
|
||||
option (google.api.http).get = "/api/v1/settings";
|
||||
}
|
||||
|
||||
// Get returns Argo CD plugins
|
||||
rpc GetPlugins(SettingsQuery) returns (SettingsPluginsResponse) {
|
||||
option (google.api.http).get = "/api/v1/settings/plugins";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -764,6 +764,17 @@ func TestNamespacedResourceDiffing(t *testing.T) {
|
||||
}).
|
||||
Given().
|
||||
When().
|
||||
// Now we migrate from client-side apply to server-side apply
|
||||
// This is necessary, as starting with kubectl 1.26, all previously
|
||||
// client-side owned fields have ownership migrated to the manager from
|
||||
// the first ssa.
|
||||
// More details: https://github.com/kubernetes/kubectl/issues/1337
|
||||
PatchApp(`[{
|
||||
"op": "add",
|
||||
"path": "/spec/syncPolicy",
|
||||
"value": { "syncOptions": ["ServerSideApply=true"] }
|
||||
}]`).
|
||||
Sync().
|
||||
And(func() {
|
||||
output, err := RunWithStdin(testdata.SSARevisionHistoryDeployment, "", "kubectl", "apply", "-n", DeploymentNamespace(), "--server-side=true", "--field-manager=revision-history-manager", "--validate=false", "--force-conflicts", "-f", "-")
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -742,6 +742,17 @@ func TestResourceDiffing(t *testing.T) {
|
||||
}).
|
||||
Given().
|
||||
When().
|
||||
// Now we migrate from client-side apply to server-side apply
|
||||
// This is necessary, as starting with kubectl 1.26, all previously
|
||||
// client-side owned fields have ownership migrated to the manager from
|
||||
// the first ssa.
|
||||
// More details: https://github.com/kubernetes/kubectl/issues/1337
|
||||
PatchApp(`[{
|
||||
"op": "add",
|
||||
"path": "/spec/syncPolicy",
|
||||
"value": { "syncOptions": ["ServerSideApply=true"] }
|
||||
}]`).
|
||||
Sync().
|
||||
And(func() {
|
||||
output, err := RunWithStdin(testdata.SSARevisionHistoryDeployment, "", "kubectl", "apply", "-n", DeploymentNamespace(), "--server-side=true", "--field-manager=revision-history-manager", "--validate=false", "--force-conflicts", "-f", "-")
|
||||
assert.NoError(t, err)
|
||||
|
||||
3
test/e2e/testdata/data.go
vendored
3
test/e2e/testdata/data.go
vendored
@@ -5,4 +5,7 @@ import _ "embed"
|
||||
var (
|
||||
//go:embed ssa-revision-history/deployment.yaml
|
||||
SSARevisionHistoryDeployment string
|
||||
|
||||
//go:embed guestbook/guestbook-ui-deployment.yaml
|
||||
GuestbookDeployment string
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {DropDownMenu, NotificationType, SlidingPanel} from 'argo-ui';
|
||||
import {DropDownMenu, NotificationType, SlidingPanel, Tooltip} from 'argo-ui';
|
||||
import * as classNames from 'classnames';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import * as React from 'react';
|
||||
@@ -24,7 +24,7 @@ import {ResourceDetails} from '../resource-details/resource-details';
|
||||
import * as AppUtils from '../utils';
|
||||
import {ApplicationResourceList} from './application-resource-list';
|
||||
import {Filters, FiltersProps} from './application-resource-filter';
|
||||
import {getAppDefaultSource, urlPattern} from '../utils';
|
||||
import {getAppDefaultSource, urlPattern, helpTip} from '../utils';
|
||||
import {ResourceStatus} from '../../../shared/models';
|
||||
import {ApplicationsDetailsAppDropdown} from './application-details-app-dropdown';
|
||||
import {useSidebarTarget} from '../../../sidebar/sidebar';
|
||||
@@ -613,6 +613,7 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{app
|
||||
const refreshing = app.metadata.annotations && app.metadata.annotations[appModels.AnnotationRefreshKey];
|
||||
const fullName = AppUtils.nodeKey({group: 'argoproj.io', kind: app.kind, name: app.metadata.name, namespace: app.metadata.namespace});
|
||||
const ActionMenuItem = (prop: {actionLabel: string}) => <span className={needOverlapLabelOnNarrowScreen ? 'show-for-large' : ''}>{prop.actionLabel}</span>;
|
||||
const hasMultipleSources = app.spec.sources && app.spec.sources.length > 0;
|
||||
return [
|
||||
{
|
||||
iconClassName: 'fa fa-info-circle',
|
||||
@@ -638,9 +639,18 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{app
|
||||
},
|
||||
{
|
||||
iconClassName: 'fa fa-history',
|
||||
title: <ActionMenuItem actionLabel='History and rollback' />,
|
||||
action: () => this.setRollbackPanelVisible(0),
|
||||
disabled: !app.status.operationState
|
||||
title: hasMultipleSources ? (
|
||||
<React.Fragment>
|
||||
<ActionMenuItem actionLabel=' History and rollback' />
|
||||
{helpTip('Rollback is not supported for apps with multiple sources')}
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<ActionMenuItem actionLabel='History and rollback' />
|
||||
),
|
||||
action: () => {
|
||||
this.setRollbackPanelVisible(0);
|
||||
},
|
||||
disabled: !app.status.operationState || hasMultipleSources
|
||||
},
|
||||
{
|
||||
iconClassName: 'fa fa-times-circle',
|
||||
|
||||
@@ -47,7 +47,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>
|
||||
|
||||
@@ -4,7 +4,7 @@ import {FieldApi, FormApi, FormField as ReactFormField, Text, TextArea} from 're
|
||||
|
||||
import {ArrayInputField, CheckboxField, EditablePanel, EditablePanelItem, Expandable, TagsInputField} from '../../../shared/components';
|
||||
import * as models from '../../../shared/models';
|
||||
import {ApplicationSourceDirectory, AuthSettings} from '../../../shared/models';
|
||||
import {ApplicationSourceDirectory, Plugin} from '../../../shared/models';
|
||||
import {services} from '../../../shared/services';
|
||||
import {ImageTagFieldEditor} from './kustomize';
|
||||
import * as kustomize from './kustomize-image';
|
||||
@@ -192,31 +192,21 @@ export const ApplicationParameters = (props: {
|
||||
/>
|
||||
)
|
||||
});
|
||||
if (source?.helm?.values) {
|
||||
attributes.push({
|
||||
title: 'VALUES',
|
||||
view: source.helm && (
|
||||
<Expandable>
|
||||
<pre>{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: source.helm && (
|
||||
<Expandable>
|
||||
<pre>{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>();
|
||||
@@ -268,9 +258,9 @@ export const ApplicationParameters = (props: {
|
||||
title: 'NAME',
|
||||
view: source.plugin && source.plugin.name,
|
||||
edit: (formApi: FormApi) => (
|
||||
<DataLoader load={() => services.authService.settings()}>
|
||||
{(settings: AuthSettings) => (
|
||||
<FormField formApi={formApi} field='spec.source.plugin.name' component={FormSelect} componentProps={{options: (settings.plugins || []).map(p => p.name)}} />
|
||||
<DataLoader load={() => services.authService.plugins()}>
|
||||
{(plugins: Plugin[]) => (
|
||||
<FormField formApi={formApi} field='spec.source.plugin.name' component={FormSelect} componentProps={{options: plugins.map(p => p.name)}} />
|
||||
)}
|
||||
</DataLoader>
|
||||
)
|
||||
|
||||
@@ -432,7 +432,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>
|
||||
)}
|
||||
@@ -651,7 +651,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>
|
||||
)}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {Timestamp} from '../../../shared/components/timestamp';
|
||||
import * as models from '../../../shared/models';
|
||||
import {services} from '../../../shared/services';
|
||||
import {ApplicationSyncWindowStatusIcon, ComparisonStatusIcon, getAppDefaultSource, getAppOperationState} from '../utils';
|
||||
import {getConditionCategory, HealthStatusIcon, OperationState, syncStatusMessage} from '../utils';
|
||||
import {getConditionCategory, HealthStatusIcon, OperationState, syncStatusMessage, helpTip} from '../utils';
|
||||
import {RevisionMetadataPanel} from './revision-metadata-panel';
|
||||
|
||||
import './application-status-panel.scss';
|
||||
@@ -30,13 +30,14 @@ const sectionLabel = (info: SectionInfo) => (
|
||||
</label>
|
||||
);
|
||||
|
||||
const sectionHeader = (info: SectionInfo, onClick?: () => any) => {
|
||||
const sectionHeader = (info: SectionInfo, hasMultipleSources: boolean, onClick?: () => any) => {
|
||||
return (
|
||||
<div style={{display: 'flex', alignItems: 'center'}}>
|
||||
{sectionLabel(info)}
|
||||
{onClick && (
|
||||
<button className='argo-button argo-button--base-o argo-button--sm application-status-panel__more-button' onClick={onClick}>
|
||||
MORE
|
||||
<button className='argo-button argo-button--base-o argo-button--sm application-status-panel__more-button' onClick={onClick} disabled={hasMultipleSources}>
|
||||
{hasMultipleSources && helpTip('More details are not supported for apps with multiple sources')}
|
||||
MORE
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@@ -65,6 +66,7 @@ export const ApplicationStatusPanel = ({application, showOperation, showConditio
|
||||
const warnings = cntByCategory.get('warning');
|
||||
const errors = cntByCategory.get('error');
|
||||
const source = getAppDefaultSource(application);
|
||||
const hasMultipleSources = application.spec.sources && application.spec.sources.length > 0;
|
||||
return (
|
||||
<div className='application-status-panel row'>
|
||||
<div className='application-status-panel__item'>
|
||||
@@ -83,6 +85,7 @@ export const ApplicationStatusPanel = ({application, showOperation, showConditio
|
||||
title: 'CURRENT SYNC STATUS',
|
||||
helpContent: 'Whether or not the version of your app is up to date with your repo. You may wish to sync your app if it is out-of-sync.'
|
||||
},
|
||||
hasMultipleSources,
|
||||
source.chart ? null : () => showMetadataInfo(application.status.sync ? application.status.sync.revision : '')
|
||||
)}
|
||||
<div className='application-status-panel__item-value'>
|
||||
@@ -115,6 +118,7 @@ export const ApplicationStatusPanel = ({application, showOperation, showConditio
|
||||
daysSinceLastSynchronized +
|
||||
' days since last sync. Click for the status of that sync.'
|
||||
},
|
||||
hasMultipleSources,
|
||||
source.chart ? null : () => showMetadataInfo(appOperationState.syncResult ? appOperationState.syncResult.revision : '')
|
||||
)}
|
||||
<div className={`application-status-panel__item-value application-status-panel__item-value--${appOperationState.phase}`}>
|
||||
|
||||
@@ -222,8 +222,8 @@ export const ApplicationSummary = (props: ApplicationSummaryProps) => {
|
||||
{
|
||||
title: 'PATH',
|
||||
view: (
|
||||
<Revision repoUrl={source.repoURL} revision={source.targetRevision || 'HEAD'} path={source.path}>
|
||||
{source.path}
|
||||
<Revision repoUrl={source.repoURL} revision={source.targetRevision || 'HEAD'} path={source.path} isForPath={true}>
|
||||
{source.path ?? ''}
|
||||
</Revision>
|
||||
),
|
||||
edit: (formApi: FormApi) => <FormField formApi={formApi} field='spec.source.path' component={Text} />
|
||||
|
||||
@@ -11,6 +11,7 @@ import {Context} from '../../../shared/context';
|
||||
import {ErrorNotification, NotificationType} from 'argo-ui';
|
||||
export interface PodTerminalViewerProps {
|
||||
applicationName: string;
|
||||
applicationNamespace: string;
|
||||
projectName: string;
|
||||
selectedNode: models.ResourceNode;
|
||||
podState: models.State;
|
||||
@@ -24,7 +25,15 @@ export interface ShellFrame {
|
||||
cols?: number;
|
||||
}
|
||||
|
||||
export const PodTerminalViewer: React.FC<PodTerminalViewerProps> = ({selectedNode, applicationName, projectName, podState, containerName, onClickContainer}) => {
|
||||
export const PodTerminalViewer: React.FC<PodTerminalViewerProps> = ({
|
||||
selectedNode,
|
||||
applicationName,
|
||||
applicationNamespace,
|
||||
projectName,
|
||||
podState,
|
||||
containerName,
|
||||
onClickContainer
|
||||
}) => {
|
||||
const terminalRef = React.useRef(null);
|
||||
const appContext = React.useContext(Context); // used to show toast
|
||||
const fitAddon = new FitAddon();
|
||||
@@ -145,7 +154,7 @@ export const PodTerminalViewer: React.FC<PodTerminalViewerProps> = ({selectedNod
|
||||
webSocket = new WebSocket(
|
||||
`${
|
||||
location.protocol === 'https:' ? 'wss' : 'ws'
|
||||
}://${url}/terminal?pod=${name}&container=${containerName}&appName=${applicationName}&projectName=${projectName}&namespace=${namespace}`
|
||||
}://${url}/terminal?pod=${name}&container=${containerName}&appName=${applicationName}&appNamespace=${applicationNamespace}&projectName=${projectName}&namespace=${namespace}`
|
||||
);
|
||||
webSocket.onopen = onConnectionOpen;
|
||||
webSocket.onclose = onConnectionClose;
|
||||
|
||||
@@ -129,6 +129,7 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
||||
content: (
|
||||
<PodTerminalViewer
|
||||
applicationName={application.metadata.name}
|
||||
applicationNamespace={application.metadata.namespace}
|
||||
projectName={application.spec.project}
|
||||
podState={podState}
|
||||
selectedNode={selectedNode}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import {revisionUrl} from './urls';
|
||||
|
||||
export const Revision = ({repoUrl, revision, path, children}: {repoUrl: string; revision: string; path?: string; children?: React.ReactNode}) => {
|
||||
export const Revision = ({repoUrl, revision, path, isForPath, children}: {repoUrl: string; revision: string; path?: string; isForPath?: boolean; children?: React.ReactNode}) => {
|
||||
if (isForPath && !path) {
|
||||
// This source literally has no path, so we won't show one.
|
||||
return <span />;
|
||||
}
|
||||
revision = revision || '';
|
||||
const hasPath = path && path !== '.';
|
||||
let url = revisionUrl(repoUrl, revision, hasPath);
|
||||
|
||||
@@ -26,7 +26,12 @@ export function repoUrl(url: string): string {
|
||||
}
|
||||
|
||||
export function revisionUrl(url: string, revision: string, forPath: boolean): string {
|
||||
const parsed = GitUrlParse(url);
|
||||
let parsed;
|
||||
try {
|
||||
parsed = GitUrlParse(url);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
let urlSubPath = isSHA(revision) ? 'commit' : 'tree';
|
||||
|
||||
if (url.indexOf('bitbucket') >= 0) {
|
||||
|
||||
@@ -459,7 +459,6 @@ export interface AuthSettings {
|
||||
chatText: string;
|
||||
binaryUrls: Record<string, string>;
|
||||
};
|
||||
plugins: Plugin[];
|
||||
userLoginsDisabled: boolean;
|
||||
kustomizeVersions: string[];
|
||||
uiCssURL: string;
|
||||
|
||||
@@ -289,10 +289,11 @@ export class ApplicationsService {
|
||||
.then(res => JSON.parse(res.manifest) as models.State);
|
||||
}
|
||||
|
||||
public getResourceActions(name: string, appNamspace: string, resource: models.ResourceNode): Promise<models.ResourceAction[]> {
|
||||
public getResourceActions(name: string, appNamespace: string, resource: models.ResourceNode): Promise<models.ResourceAction[]> {
|
||||
return requests
|
||||
.get(`/applications/${name}/resource/actions`)
|
||||
.query({
|
||||
appNamespace,
|
||||
namespace: resource.namespace,
|
||||
resourceName: resource.name,
|
||||
version: resource.version,
|
||||
@@ -306,10 +307,11 @@ export class ApplicationsService {
|
||||
});
|
||||
}
|
||||
|
||||
public runResourceAction(name: string, appNamspace: string, resource: models.ResourceNode, action: string): Promise<models.ResourceAction[]> {
|
||||
public runResourceAction(name: string, appNamespace: string, resource: models.ResourceNode, action: string): Promise<models.ResourceAction[]> {
|
||||
return requests
|
||||
.post(`/applications/${name}/resource/actions`)
|
||||
.query({
|
||||
appNamespace,
|
||||
namespace: resource.namespace,
|
||||
resourceName: resource.name,
|
||||
version: resource.version,
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import {AuthSettings} from '../models';
|
||||
import {AuthSettings, Plugin} from '../models';
|
||||
import requests from './requests';
|
||||
|
||||
export class AuthService {
|
||||
public settings(): Promise<AuthSettings> {
|
||||
return requests.get('/settings').then(res => res.body as AuthSettings);
|
||||
}
|
||||
|
||||
public plugins(): Promise<Plugin[]> {
|
||||
return requests.get('/settings/plugins').then(res => (res.body.plugins || []) as Plugin[]);
|
||||
}
|
||||
}
|
||||
|
||||
33
ui/yarn.lock
33
ui/yarn.lock
@@ -3544,10 +3544,10 @@ detect-node@^2.0.4:
|
||||
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
|
||||
integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
|
||||
|
||||
dezalgo@1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456"
|
||||
integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=
|
||||
dezalgo@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81"
|
||||
integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==
|
||||
dependencies:
|
||||
asap "^2.0.0"
|
||||
wrappy "1"
|
||||
@@ -4425,14 +4425,14 @@ form-data@^4.0.0:
|
||||
mime-types "^2.1.12"
|
||||
|
||||
formidable@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.0.1.tgz#4310bc7965d185536f9565184dee74fbb75557ff"
|
||||
integrity sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.1.1.tgz#81269cbea1a613240049f5f61a9d97731517414f"
|
||||
integrity sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ==
|
||||
dependencies:
|
||||
dezalgo "1.0.3"
|
||||
hexoid "1.0.0"
|
||||
once "1.4.0"
|
||||
qs "6.9.3"
|
||||
dezalgo "^1.0.4"
|
||||
hexoid "^1.0.0"
|
||||
once "^1.4.0"
|
||||
qs "^6.11.0"
|
||||
|
||||
forwarded@0.2.0:
|
||||
version "0.2.0"
|
||||
@@ -4702,7 +4702,7 @@ he@^1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||
|
||||
hexoid@1.0.0:
|
||||
hexoid@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18"
|
||||
integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==
|
||||
@@ -6671,7 +6671,7 @@ on-headers@~1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
|
||||
integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
|
||||
|
||||
once@1.4.0, once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
@@ -7178,18 +7178,13 @@ punycode@^2.1.0, punycode@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
qs@6.11.0, qs@^6.10.3:
|
||||
qs@6.11.0, qs@^6.10.3, qs@^6.11.0:
|
||||
version "6.11.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
|
||||
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
|
||||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
|
||||
qs@6.9.3:
|
||||
version "6.9.3"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.3.tgz#bfadcd296c2d549f1dffa560619132c977f5008e"
|
||||
integrity sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==
|
||||
|
||||
querystring@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package appset
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
// AppRBACName formats fully qualified application name for RBAC check
|
||||
func AppSetRBACName(appSet *v1alpha1.ApplicationSet) string {
|
||||
return fmt.Sprintf("%s/%s", appSet.Spec.Template.Spec.GetProject(), appSet.ObjectMeta.Name)
|
||||
}
|
||||
@@ -348,9 +348,9 @@ func GetRefSources(ctx context.Context, spec argoappv1.ApplicationSpec, db db.Ar
|
||||
refKeys := make(map[string]bool)
|
||||
for _, source := range spec.Sources {
|
||||
if source.Ref != "" {
|
||||
isValidRefKey := regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString
|
||||
isValidRefKey := regexp.MustCompile(`^[a-zA-Z0-9_-]+$`).MatchString
|
||||
if !isValidRefKey(source.Ref) {
|
||||
return nil, fmt.Errorf("source.ref %s cannot contain any special characters except '_' and '-'", source.Ref)
|
||||
return nil, fmt.Errorf("sources.ref %s cannot contain any special characters except '_' and '-'", source.Ref)
|
||||
}
|
||||
refKey := "$" + source.Ref
|
||||
if _, ok := refKeys[refKey]; ok {
|
||||
|
||||
@@ -1043,14 +1043,14 @@ func Test_GetRefSources(t *testing.T) {
|
||||
repoDB.On("GetRepository", context.Background(), repo.Repo).Return(repo, nil)
|
||||
|
||||
argoSpec := getMultiSourceAppSpec(argoappv1.ApplicationSources{
|
||||
{RepoURL: fmt.Sprintf("file://%s", repoPath), Ref: "source1"},
|
||||
{RepoURL: fmt.Sprintf("file://%s", repoPath), Ref: "source-1_2"},
|
||||
{RepoURL: fmt.Sprintf("file://%s", repoPath)},
|
||||
})
|
||||
|
||||
refSources, err := GetRefSources(context.TODO(), *argoSpec, repoDB)
|
||||
|
||||
expectedRefSource := argoappv1.RefTargetRevisionMapping{
|
||||
"$source1": &argoappv1.RefTarget{
|
||||
"$source-1_2": &argoappv1.RefTarget{
|
||||
Repo: *repo,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -353,9 +353,12 @@ func (a *ClientApp) HandleCallback(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "no id_token in token response", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
idToken, err := a.provider.Verify(a.clientID, idTokenRAW)
|
||||
|
||||
idToken, err := a.provider.Verify(idTokenRAW, a.settings)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("invalid session token: %v", err), http.StatusInternalServerError)
|
||||
log.Warnf("Failed to verify token: %s", err)
|
||||
http.Error(w, common.TokenVerificationError, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
path := "/"
|
||||
|
||||
@@ -90,7 +90,7 @@ func (p *fakeProvider) ParseConfig() (*OIDCConfiguration, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (p *fakeProvider) Verify(_, _ string) (*gooidc.IDToken, error) {
|
||||
func (p *fakeProvider) Verify(_ string, _ *settings.ArgoCDSettings) (*gooidc.IDToken, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -9,8 +10,13 @@ import (
|
||||
gooidc "github.com/coreos/go-oidc"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/util/security"
|
||||
"github.com/argoproj/argo-cd/v2/util/settings"
|
||||
)
|
||||
|
||||
var ErrTokenExpired = errors.New("token is expired")
|
||||
|
||||
// Provider is a wrapper around go-oidc provider to also provide the following features:
|
||||
// 1. lazy initialization/querying of the provider
|
||||
// 2. automatic detection of change in signing keys
|
||||
@@ -23,7 +29,7 @@ type Provider interface {
|
||||
|
||||
ParseConfig() (*OIDCConfiguration, error)
|
||||
|
||||
Verify(clientID, tokenString string) (*gooidc.IDToken, error)
|
||||
Verify(tokenString string, argoSettings *settings.ArgoCDSettings) (*gooidc.IDToken, error)
|
||||
}
|
||||
|
||||
type providerImpl struct {
|
||||
@@ -69,13 +75,70 @@ func (p *providerImpl) newGoOIDCProvider() (*gooidc.Provider, error) {
|
||||
return prov, nil
|
||||
}
|
||||
|
||||
func (p *providerImpl) Verify(clientID, tokenString string) (*gooidc.IDToken, error) {
|
||||
func (p *providerImpl) Verify(tokenString string, argoSettings *settings.ArgoCDSettings) (*gooidc.IDToken, error) {
|
||||
// According to the JWT spec, the aud claim is optional. The spec also says (emphasis mine):
|
||||
//
|
||||
// If the principal processing the claim does not identify itself with a value in the "aud" claim _when this
|
||||
// claim is present_, then the JWT MUST be rejected.
|
||||
//
|
||||
// - https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3
|
||||
//
|
||||
// If the claim is not present, we can skip the audience claim check (called the "ClientID check" in go-oidc's
|
||||
// terminology).
|
||||
//
|
||||
// The OIDC spec says that the aud claim is required (https://openid.net/specs/openid-connect-core-1_0.html#IDToken).
|
||||
// But we cannot assume that all OIDC providers will follow the spec. For Argo CD <2.6.0, we will default to
|
||||
// allowing the aud claim to be optional. In Argo CD >=2.6.0, we will default to requiring the aud claim to be
|
||||
// present and give users the skipAudienceCheckWhenTokenHasNoAudience setting to revert the behavior if necessary.
|
||||
//
|
||||
// At this point, we have not verified that the token has not been altered. All code paths below MUST VERIFY
|
||||
// THE TOKEN SIGNATURE to confirm that an attacker did not maliciously remove the "aud" claim.
|
||||
unverifiedHasAudClaim, err := security.UnverifiedHasAudClaim(tokenString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to determine whether the token has an aud claim: %w", err)
|
||||
}
|
||||
|
||||
var idToken *gooidc.IDToken
|
||||
if !unverifiedHasAudClaim {
|
||||
idToken, err = p.verify("", tokenString, argoSettings.SkipAudienceCheckWhenTokenHasNoAudience())
|
||||
} else {
|
||||
allowedAudiences := argoSettings.OAuth2AllowedAudiences()
|
||||
if len(allowedAudiences) == 0 {
|
||||
return nil, errors.New("token has an audience claim, but no allowed audiences are configured")
|
||||
}
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if strings.HasPrefix(err.Error(), "oidc: token is expired") {
|
||||
return nil, ErrTokenExpired
|
||||
}
|
||||
return nil, fmt.Errorf("failed to verify token: %w", err)
|
||||
}
|
||||
|
||||
return idToken, nil
|
||||
}
|
||||
|
||||
func (p *providerImpl) verify(clientID, tokenString string, skipClientIDCheck bool) (*gooidc.IDToken, error) {
|
||||
ctx := context.Background()
|
||||
prov, err := p.provider()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
verifier := prov.Verifier(&gooidc.Config{ClientID: clientID})
|
||||
config := &gooidc.Config{ClientID: clientID, SkipClientIDCheck: skipClientIDCheck}
|
||||
verifier := prov.Verifier(config)
|
||||
idToken, err := verifier.Verify(ctx, tokenString)
|
||||
if err != nil {
|
||||
// HACK: if we failed token verification, it's possible the reason was because dex
|
||||
@@ -93,7 +156,7 @@ func (p *providerImpl) Verify(clientID, tokenString string) (*gooidc.IDToken, er
|
||||
// return original error if we fail to re-initialize OIDC
|
||||
return nil, err
|
||||
}
|
||||
verifier = newProvider.Verifier(&gooidc.Config{ClientID: clientID})
|
||||
verifier = newProvider.Verifier(config)
|
||||
idToken, err = verifier.Verify(ctx, tokenString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/casbin/casbin/v2"
|
||||
"github.com/casbin/casbin/v2/model"
|
||||
"github.com/casbin/casbin/v2/util"
|
||||
jwt "github.com/golang-jwt/jwt/v4"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
gocache "github.com/patrickmn/go-cache"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
|
||||
15
util/security/application_namespaces.go
Normal file
15
util/security/application_namespaces.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/util/glob"
|
||||
)
|
||||
|
||||
func IsNamespaceEnabled(namespace string, serverNamespace string, enabledNamespaces []string) bool {
|
||||
return namespace == serverNamespace || glob.MatchStringInList(enabledNamespaces, namespace, false)
|
||||
}
|
||||
|
||||
func NamespaceNotPermittedError(namespace string) error {
|
||||
return fmt.Errorf("namespace '%s' is not permitted", namespace)
|
||||
}
|
||||
62
util/security/application_namespaces_test.go
Normal file
62
util/security/application_namespaces_test.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_IsNamespaceEnabled(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
namespace string
|
||||
serverNamespace string
|
||||
enabledNamespaces []string
|
||||
expectedResult bool
|
||||
}{
|
||||
{
|
||||
"namespace is empty",
|
||||
"argocd",
|
||||
"argocd",
|
||||
[]string{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"namespace is explicitly server namespace",
|
||||
"argocd",
|
||||
"argocd",
|
||||
[]string{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"namespace is allowed namespace",
|
||||
"allowed",
|
||||
"argocd",
|
||||
[]string{"allowed"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"namespace matches pattern",
|
||||
"test-ns",
|
||||
"argocd",
|
||||
[]string{"test-*"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"namespace is not allowed namespace",
|
||||
"disallowed",
|
||||
"argocd",
|
||||
[]string{"allowed"},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tcc := tc
|
||||
t.Run(tcc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
result := IsNamespaceEnabled(tcc.namespace, tcc.serverNamespace, tcc.enabledNamespaces)
|
||||
assert.Equal(t, tcc.expectedResult, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
80
util/security/jwt.go
Normal file
80
util/security/jwt.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// parseJWT parses a jwt and returns it as json bytes.
|
||||
//
|
||||
// This function DOES NOT VERIFY THE TOKEN. You still have to verify the token to confirm that the token holder has not
|
||||
// altered the claims.
|
||||
//
|
||||
// This code is copied almost verbatim from go-oidc (https://github.com/coreos/go-oidc).
|
||||
func parseJWT(p string) ([]byte, error) {
|
||||
parts := strings.Split(p, ".")
|
||||
if len(parts) < 2 {
|
||||
return nil, fmt.Errorf("malformed jwt, expected 3 parts got %d", len(parts))
|
||||
}
|
||||
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("malformed jwt payload: %v", err)
|
||||
}
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
type audience []string
|
||||
|
||||
// UnmarshalJSON allows us to unmarshal either a single audience or a list of audiences.
|
||||
// Taken from: https://github.com/coreos/go-oidc/blob/a8ceb9a2043fca2e43518633920db746808b1138/oidc/oidc.go#L475
|
||||
func (a *audience) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if json.Unmarshal(b, &s) == nil {
|
||||
*a = audience{s}
|
||||
return nil
|
||||
}
|
||||
var auds []string
|
||||
if err := json.Unmarshal(b, &auds); err != nil {
|
||||
return err
|
||||
}
|
||||
*a = auds
|
||||
return nil
|
||||
}
|
||||
|
||||
// jwtWithOnlyAudClaim represents a jwt where only the "aud" claim is present. This struct allows us to unmarshal a jwt
|
||||
// and be confident that the only information retrieved from that jwt is the "aud" claim.
|
||||
type jwtWithOnlyAudClaim struct {
|
||||
Aud audience `json:"aud"`
|
||||
}
|
||||
|
||||
// getUnverifiedAudClaim gets the "aud" claim from a jwt.
|
||||
//
|
||||
// This function DOES NOT VERIFY THE TOKEN. You still have to verify the token to confirm that the token holder has not
|
||||
// altered the "aud" claim.
|
||||
//
|
||||
// This code is copied almost verbatim from go-oidc (https://github.com/coreos/go-oidc).
|
||||
func getUnverifiedAudClaim(rawIDToken string) ([]string, error) {
|
||||
payload, err := parseJWT(rawIDToken)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("malformed jwt: %v", err)
|
||||
}
|
||||
var token jwtWithOnlyAudClaim
|
||||
if err = json.Unmarshal(payload, &token); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal claims: %v", err)
|
||||
}
|
||||
return token.Aud, nil
|
||||
}
|
||||
|
||||
// UnverifiedHasAudClaim returns whether the "aud" claim is present in the given JWT.
|
||||
//
|
||||
// This function DOES NOT VERIFY THE TOKEN. You still have to verify the token to confirm that the token holder has not
|
||||
// altered the "aud" claim.
|
||||
func UnverifiedHasAudClaim(rawIDToken string) (bool, error) {
|
||||
aud, err := getUnverifiedAudClaim(rawIDToken)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to determine whether token had an audience claim: %w", err)
|
||||
}
|
||||
return aud != nil, nil
|
||||
}
|
||||
56
util/security/jwt_test.go
Normal file
56
util/security/jwt_test.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
utiltest "github.com/argoproj/argo-cd/v2/util/test"
|
||||
)
|
||||
|
||||
func Test_UnverifiedHasAudClaim(t *testing.T) {
|
||||
tokenForAud := func(t *testing.T, aud jwt.ClaimStrings) string {
|
||||
claims := jwt.RegisteredClaims{Audience: aud, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodRS512, claims)
|
||||
key, err := jwt.ParseRSAPrivateKeyFromPEM(utiltest.PrivateKey)
|
||||
require.NoError(t, err)
|
||||
tokenString, err := token.SignedString(key)
|
||||
require.NoError(t, err)
|
||||
return tokenString
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
aud jwt.ClaimStrings
|
||||
expectedHasAud bool
|
||||
}{
|
||||
{
|
||||
name: "no audience",
|
||||
aud: jwt.ClaimStrings{},
|
||||
expectedHasAud: false,
|
||||
},
|
||||
{
|
||||
name: "one empty audience",
|
||||
aud: jwt.ClaimStrings{""},
|
||||
expectedHasAud: true,
|
||||
},
|
||||
{
|
||||
name: "one non-empty audience",
|
||||
aud: jwt.ClaimStrings{"test"},
|
||||
expectedHasAud: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
testCaseCopy := testCase
|
||||
t.Run(testCaseCopy.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
out, err := UnverifiedHasAudClaim(tokenForAud(t, testCaseCopy.aud))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testCaseCopy.expectedHasAud, out)
|
||||
})
|
||||
}
|
||||
}
|
||||
14
util/security/rbac.go
Normal file
14
util/security/rbac.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// AppRBACName constructs name of the app for use in RBAC checks.
|
||||
func AppRBACName(defaultNS string, project string, namespace string, name string) string {
|
||||
if defaultNS != "" && namespace != defaultNS && namespace != "" {
|
||||
return fmt.Sprintf("%s/%s/%s", project, namespace, name)
|
||||
} else {
|
||||
return fmt.Sprintf("%s/%s", project, name)
|
||||
}
|
||||
}
|
||||
52
util/security/rbac_test.go
Normal file
52
util/security/rbac_test.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_AppRBACName(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
defaultNS string
|
||||
project string
|
||||
namespace string
|
||||
appName string
|
||||
expectedResult string
|
||||
}{
|
||||
{
|
||||
"namespace is empty",
|
||||
"argocd",
|
||||
"default",
|
||||
"",
|
||||
"app",
|
||||
"default/app",
|
||||
},
|
||||
{
|
||||
"namespace is default namespace",
|
||||
"argocd",
|
||||
"default",
|
||||
"argocd",
|
||||
"app",
|
||||
"default/app",
|
||||
},
|
||||
{
|
||||
"namespace is not default namespace",
|
||||
"argocd",
|
||||
"default",
|
||||
"test",
|
||||
"app",
|
||||
"default/test/app",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tcc := tc
|
||||
t.Run(tcc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
result := AppRBACName(tcc.defaultNS, tcc.project, tcc.namespace, tcc.appName)
|
||||
assert.Equal(t, tcc.expectedResult, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
oidc "github.com/coreos/go-oidc"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -419,7 +418,7 @@ func (mgr *SessionManager) VerifyUsernamePassword(username string, password stri
|
||||
// introduces random delay to protect from timing-based user enumeration attack
|
||||
delayNanoseconds := verificationDelayNoiseMin.Nanoseconds() +
|
||||
int64(rand.Intn(int(verificationDelayNoiseMax.Nanoseconds()-verificationDelayNoiseMin.Nanoseconds())))
|
||||
// take into account amount of time spent since the request start
|
||||
// take into account amount of time spent since the request start
|
||||
delayNanoseconds = delayNanoseconds - time.Since(start).Nanoseconds()
|
||||
if delayNanoseconds > 0 {
|
||||
mgr.sleep(time.Duration(delayNanoseconds))
|
||||
@@ -463,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) {
|
||||
@@ -483,31 +523,28 @@ func (mgr *SessionManager) VerifyToken(tokenString string) (jwt.Claims, string,
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// Token must be verified for at least one audience
|
||||
// TODO(jannfis): Is this the right way? Shouldn't we know our audience and only validate for the correct one?
|
||||
var idToken *oidc.IDToken
|
||||
for _, aud := range claims.Audience {
|
||||
idToken, err = prov.Verify(aud, tokenString)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
argoSettings, err := mgr.settingsMgr.GetSettings()
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("cannot access settings while verifying the token: %w", err)
|
||||
}
|
||||
if argoSettings == nil {
|
||||
return nil, "", fmt.Errorf("settings are not available while verifying the token")
|
||||
}
|
||||
|
||||
idToken, err := prov.Verify(tokenString, argoSettings)
|
||||
|
||||
// The token verification has failed. If the token has expired, we will
|
||||
// return a dummy claims only containing a value for the issuer, so the
|
||||
// UI can handle expired tokens appropriately.
|
||||
if err != nil {
|
||||
if strings.HasPrefix(err.Error(), "oidc: token is expired") {
|
||||
log.Warnf("Failed to verify token: %s", err)
|
||||
if errors.Is(err, oidcutil.ErrTokenExpired) {
|
||||
claims = jwt.RegisteredClaims{
|
||||
Issuer: "sso",
|
||||
}
|
||||
return claims, "", err
|
||||
return claims, "", common.TokenVerificationErr
|
||||
}
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if idToken == nil {
|
||||
return nil, "", fmt.Errorf("no audience found in the token")
|
||||
return nil, "", common.TokenVerificationErr
|
||||
}
|
||||
|
||||
var claims jwt.MapClaims
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user