mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-03-22 16:28:48 +01:00
Compare commits
76 Commits
v2.14.5
...
release-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
206a6eeca5 | ||
|
|
8b31544069 | ||
|
|
9b7bf3e16d | ||
|
|
879895af78 | ||
|
|
1f98e3f989 | ||
|
|
741f00e2e3 | ||
|
|
e889f0a7ff | ||
|
|
7b219ee97f | ||
|
|
4ab9cd45bf | ||
|
|
ba5b938858 | ||
|
|
4a133ce41b | ||
|
|
376525eea2 | ||
|
|
9fa9bb8c89 | ||
|
|
4359b3c774 | ||
|
|
4f6686fc3f | ||
|
|
caa4dc1bd2 | ||
|
|
981e7f762a | ||
|
|
3d76aa5daa | ||
|
|
fca3a7ed2a | ||
|
|
2bb617d02a | ||
|
|
72e2387795 | ||
|
|
f8eba3e6e9 | ||
|
|
510b77546e | ||
|
|
d77ecdf113 | ||
|
|
f9bb3b608e | ||
|
|
5d0a4f0dd3 | ||
|
|
8a3b2fdd2b | ||
|
|
ddb6073e52 | ||
|
|
d95b710055 | ||
|
|
6c7d6940cd | ||
|
|
ec5198949e | ||
|
|
da2ef7db67 | ||
|
|
c6166fd531 | ||
|
|
3c68b26d7a | ||
|
|
5f890629a9 | ||
|
|
e24ee58f28 | ||
|
|
14fa0e0d9f | ||
|
|
2aceb1dc44 | ||
|
|
a2361bf850 | ||
|
|
5ad281ef56 | ||
|
|
24d57220ca | ||
|
|
d213c305e4 | ||
|
|
25e327bb9a | ||
|
|
efe5d2956e | ||
|
|
5bc6f4722b | ||
|
|
25235fbc2d | ||
|
|
3a9ab77537 | ||
|
|
ced6a7822e | ||
|
|
fe93963970 | ||
|
|
78e61ba71c | ||
|
|
f7ad2adf50 | ||
|
|
b163de0784 | ||
|
|
82831155c2 | ||
|
|
91f54459d4 | ||
|
|
0451723be1 | ||
|
|
f6f7d29c11 | ||
|
|
5feb8c21f2 | ||
|
|
4826fb0ab8 | ||
|
|
3b308d66e2 | ||
|
|
b31d700188 | ||
|
|
be81419f27 | ||
|
|
6b15a04509 | ||
|
|
38985bdcd6 | ||
|
|
c868711d03 | ||
|
|
31a554568a | ||
|
|
a7178be1c1 | ||
|
|
9a9e62d392 | ||
|
|
9f832cd099 | ||
|
|
ec45e33800 | ||
|
|
872319e8e7 | ||
|
|
7acdaa96e0 | ||
|
|
d107d4e41a | ||
|
|
39407827d3 | ||
|
|
fe2a6e91b6 | ||
|
|
38c03769af | ||
|
|
defd4be943 |
8
.github/workflows/ci-build.yaml
vendored
8
.github/workflows/ci-build.yaml
vendored
@@ -14,7 +14,7 @@ on:
|
||||
env:
|
||||
# Golang version to use across CI steps
|
||||
# renovate: datasource=golang-version packageName=golang
|
||||
GOLANG_VERSION: '1.23.3'
|
||||
GOLANG_VERSION: '1.24.6'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -109,10 +109,10 @@ jobs:
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
|
||||
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
|
||||
with:
|
||||
# renovate: datasource=go packageName=github.com/golangci/golangci-lint versioning=regex:^v(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)?$
|
||||
version: v1.62.2
|
||||
version: v2.1.6
|
||||
args: --verbose
|
||||
|
||||
test-go:
|
||||
@@ -486,7 +486,7 @@ jobs:
|
||||
run: |
|
||||
docker pull ghcr.io/dexidp/dex:v2.41.1
|
||||
docker pull argoproj/argo-cd-ci-builder:v1.0.0
|
||||
docker pull redis:7.0.15-alpine
|
||||
docker pull redis:7.2.11-alpine
|
||||
- name: Create target directory for binaries in the build-process
|
||||
run: |
|
||||
mkdir -p dist
|
||||
|
||||
4
.github/workflows/image.yaml
vendored
4
.github/workflows/image.yaml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
with:
|
||||
# Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations)
|
||||
# renovate: datasource=golang-version packageName=golang
|
||||
go-version: 1.23.3
|
||||
go-version: 1.24.6
|
||||
platforms: ${{ needs.set-vars.outputs.platforms }}
|
||||
push: false
|
||||
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
ghcr_image_name: ghcr.io/argoproj/argo-cd/argocd:${{ needs.set-vars.outputs.image-tag }}
|
||||
# Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations)
|
||||
# renovate: datasource=golang-version packageName=golang
|
||||
go-version: 1.23.3
|
||||
go-version: 1.24.6
|
||||
platforms: ${{ needs.set-vars.outputs.platforms }}
|
||||
push: true
|
||||
secrets:
|
||||
|
||||
70
.github/workflows/release.yaml
vendored
70
.github/workflows/release.yaml
vendored
@@ -11,7 +11,7 @@ permissions: {}
|
||||
|
||||
env:
|
||||
# renovate: datasource=golang-version packageName=golang
|
||||
GOLANG_VERSION: '1.23.3' # Note: go-version must also be set in job argocd-image.with.go-version
|
||||
GOLANG_VERSION: '1.24.6' # Note: go-version must also be set in job argocd-image.with.go-version
|
||||
|
||||
jobs:
|
||||
argocd-image:
|
||||
@@ -25,13 +25,49 @@ jobs:
|
||||
quay_image_name: quay.io/argoproj/argocd:${{ github.ref_name }}
|
||||
# Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations)
|
||||
# renovate: datasource=golang-version packageName=golang
|
||||
go-version: 1.23.3
|
||||
go-version: 1.24.6
|
||||
platforms: linux/amd64,linux/arm64,linux/s390x,linux/ppc64le
|
||||
push: true
|
||||
secrets:
|
||||
quay_username: ${{ secrets.RELEASE_QUAY_USERNAME }}
|
||||
quay_password: ${{ secrets.RELEASE_QUAY_TOKEN }}
|
||||
|
||||
setup-variables:
|
||||
name: Setup Release Variables
|
||||
if: github.repository == 'argoproj/argo-cd'
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
is_pre_release: ${{ steps.var.outputs.is_pre_release }}
|
||||
is_latest_release: ${{ steps.var.outputs.is_latest_release }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Setup variables
|
||||
id: var
|
||||
run: |
|
||||
set -xue
|
||||
# Fetch all tag information
|
||||
git fetch --prune --tags --force
|
||||
|
||||
LATEST_RELEASE_TAG=$(git -c 'versionsort.suffix=-rc' tag --list --sort=version:refname | grep -v '-' | tail -n1)
|
||||
|
||||
PRE_RELEASE=false
|
||||
# Check if latest tag is a pre-release
|
||||
if echo ${{ github.ref_name }} | grep -E -- '-rc[0-9]+$';then
|
||||
PRE_RELEASE=true
|
||||
fi
|
||||
|
||||
IS_LATEST=false
|
||||
# Ensure latest release tag matches github.ref_name
|
||||
if [[ $LATEST_RELEASE_TAG == ${{ github.ref_name }} ]];then
|
||||
IS_LATEST=true
|
||||
fi
|
||||
echo "is_pre_release=$PRE_RELEASE" >> $GITHUB_OUTPUT
|
||||
echo "is_latest_release=$IS_LATEST" >> $GITHUB_OUTPUT
|
||||
|
||||
argocd-image-provenance:
|
||||
needs: [argocd-image]
|
||||
permissions:
|
||||
@@ -50,15 +86,17 @@ jobs:
|
||||
|
||||
goreleaser:
|
||||
needs:
|
||||
- setup-variables
|
||||
- argocd-image
|
||||
- argocd-image-provenance
|
||||
permissions:
|
||||
contents: write # used for uploading assets
|
||||
if: github.repository == 'argoproj/argo-cd'
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
GORELEASER_MAKE_LATEST: ${{ needs.setup-variables.outputs.is_latest_release }}
|
||||
outputs:
|
||||
hashes: ${{ steps.hash.outputs.hashes }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
@@ -140,7 +178,7 @@ jobs:
|
||||
permissions:
|
||||
contents: write # Needed for release uploads
|
||||
outputs:
|
||||
hashes: ${{ steps.sbom-hash.outputs.hashes}}
|
||||
hashes: ${{ steps.sbom-hash.outputs.hashes }}
|
||||
if: github.repository == 'argoproj/argo-cd'
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
@@ -218,6 +256,7 @@ jobs:
|
||||
|
||||
post-release:
|
||||
needs:
|
||||
- setup-variables
|
||||
- argocd-image
|
||||
- goreleaser
|
||||
- generate-sbom
|
||||
@@ -226,6 +265,8 @@ jobs:
|
||||
pull-requests: write # Needed to create PR for VERSION update.
|
||||
if: github.repository == 'argoproj/argo-cd'
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
TAG_STABLE: ${{ needs.setup-variables.outputs.is_latest_release }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
@@ -239,27 +280,6 @@ jobs:
|
||||
git config --global user.email 'ci@argoproj.com'
|
||||
git config --global user.name 'CI'
|
||||
|
||||
- name: Check if tag is the latest version and not a pre-release
|
||||
run: |
|
||||
set -xue
|
||||
# Fetch all tag information
|
||||
git fetch --prune --tags --force
|
||||
|
||||
LATEST_TAG=$(git -c 'versionsort.suffix=-rc' tag --list --sort=version:refname | tail -n1)
|
||||
|
||||
PRE_RELEASE=false
|
||||
# Check if latest tag is a pre-release
|
||||
if echo $LATEST_TAG | grep -E -- '-rc[0-9]+$';then
|
||||
PRE_RELEASE=true
|
||||
fi
|
||||
|
||||
# Ensure latest tag matches github.ref_name & not a pre-release
|
||||
if [[ $LATEST_TAG == ${{ github.ref_name }} ]] && [[ $PRE_RELEASE != 'true' ]];then
|
||||
echo "TAG_STABLE=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "TAG_STABLE=false" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Update stable tag to latest version
|
||||
run: |
|
||||
git tag -f stable ${{ github.ref_name }}
|
||||
|
||||
130
.golangci.yaml
130
.golangci.yaml
@@ -1,20 +1,12 @@
|
||||
issues:
|
||||
exclude:
|
||||
- SA5011
|
||||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
exclude-rules:
|
||||
- path: '(.+)_test\.go'
|
||||
linters:
|
||||
- unparam
|
||||
version: "2"
|
||||
run:
|
||||
timeout: 50m
|
||||
linters:
|
||||
default: none
|
||||
enable:
|
||||
- errcheck
|
||||
- errorlint
|
||||
- gocritic
|
||||
- gofumpt
|
||||
- goimports
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- misspell
|
||||
@@ -25,35 +17,85 @@ linters:
|
||||
- unparam
|
||||
- unused
|
||||
- usestdlibvars
|
||||
- whitespace
|
||||
linters-settings:
|
||||
gocritic:
|
||||
disabled-checks:
|
||||
- appendAssign
|
||||
- assignOp # Keep it disabled for readability
|
||||
- badCond
|
||||
- commentFormatting
|
||||
- exitAfterDefer
|
||||
- ifElseChain
|
||||
- mapKey
|
||||
- singleCaseSwitch
|
||||
- typeSwitchVar
|
||||
goimports:
|
||||
local-prefixes: github.com/argoproj/argo-cd/v2
|
||||
perfsprint:
|
||||
# Optimizes even if it requires an int or uint type cast.
|
||||
int-conversion: true
|
||||
# Optimizes into `err.Error()` even if it is only equivalent for non-nil errors.
|
||||
err-error: false
|
||||
# Optimizes `fmt.Errorf`.
|
||||
errorf: false
|
||||
# Optimizes `fmt.Sprintf` with only one argument.
|
||||
sprintf1: true
|
||||
# Optimizes into strings concatenation.
|
||||
strconcat: false
|
||||
testifylint:
|
||||
enable-all: true
|
||||
disable:
|
||||
- go-require
|
||||
run:
|
||||
timeout: 50m
|
||||
- whitespace
|
||||
settings:
|
||||
gocritic:
|
||||
disabled-checks:
|
||||
- appendAssign
|
||||
- assignOp
|
||||
- badCond
|
||||
- commentFormatting
|
||||
- exitAfterDefer
|
||||
- ifElseChain
|
||||
- mapKey
|
||||
- singleCaseSwitch
|
||||
- typeSwitchVar
|
||||
perfsprint:
|
||||
int-conversion: true
|
||||
err-error: false
|
||||
errorf: false
|
||||
sprintf1: true
|
||||
strconcat: false
|
||||
staticcheck:
|
||||
checks:
|
||||
- "all"
|
||||
- "-ST1001" # dot imports are discouraged
|
||||
- "-ST1003" # poorly chosen identifier
|
||||
- "-ST1005" # incorrectly formatted error string
|
||||
- "-ST1011" # poorly chosen name for variable of type time.Duration
|
||||
- "-ST1012" # poorly chosen name for an error variable
|
||||
- "-ST1016" # use consistent method receiver names
|
||||
- "-ST1017" # don't use Yoda conditions
|
||||
- "-ST1019" # importing the same package multiple times
|
||||
- "-ST1023" # redundant type in variable declaration
|
||||
- "-QF1001" # apply De Morgan’s law
|
||||
- "-QF1003" # convert if/else-if chain to tagged switch
|
||||
- "-QF1006" # lift if+break into loop condition
|
||||
- "-QF1007" # merge conditional assignment into variable declaration
|
||||
- "-QF1008" # omit embedded fields from selector expression
|
||||
- "-QF1009" # use time.Time.Equal instead of == operator
|
||||
- "-QF1011" # omit redundant type from variable declaration
|
||||
- "-QF1012" # use fmt.Fprintf(x, ...) instead of x.Write(fmt.Sprintf(...))
|
||||
testifylint:
|
||||
enable-all: true
|
||||
disable:
|
||||
- go-require
|
||||
- equal-values
|
||||
- empty
|
||||
- len
|
||||
- expected-actual
|
||||
- formatter
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
rules:
|
||||
- linters:
|
||||
- unparam
|
||||
path: (.+)_test\.go
|
||||
- path: (.+)\.go$
|
||||
text: SA5011
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
issues:
|
||||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
formatters:
|
||||
enable:
|
||||
- gofumpt
|
||||
- goimports
|
||||
settings:
|
||||
goimports:
|
||||
local-prefixes:
|
||||
- github.com/argoproj/argo-cd/v2
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
|
||||
@@ -46,16 +46,17 @@ builds:
|
||||
archives:
|
||||
- id: argocd-archive
|
||||
builds:
|
||||
- argocd-cli
|
||||
- argocd-cli
|
||||
name_template: |-
|
||||
{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}
|
||||
format: binary
|
||||
formats: [binary]
|
||||
|
||||
checksum:
|
||||
name_template: 'cli_checksums.txt'
|
||||
algorithm: sha256
|
||||
|
||||
release:
|
||||
make_latest: '{{ .Env.GORELEASER_MAKE_LATEST }}'
|
||||
prerelease: auto
|
||||
draft: false
|
||||
header: |
|
||||
@@ -85,16 +86,14 @@ release:
|
||||
If upgrading from a different minor version, be sure to read the [upgrading](https://argo-cd.readthedocs.io/en/stable/operator-manual/upgrading/overview/) documentation.
|
||||
footer: |
|
||||
**Full Changelog**: https://github.com/argoproj/argo-cd/compare/{{ .PreviousTag }}...{{ .Tag }}
|
||||
|
||||
|
||||
<a href="https://argoproj.github.io/cd/"><img src="https://raw.githubusercontent.com/argoproj/argo-site/master/content/pages/cd/gitops-cd.png" width="25%" ></a>
|
||||
|
||||
|
||||
snapshot: #### To be removed for PR
|
||||
name_template: "2.6.0"
|
||||
name_template: '2.6.0'
|
||||
|
||||
changelog:
|
||||
use:
|
||||
github
|
||||
use: github
|
||||
sort: asc
|
||||
abbrev: 0
|
||||
groups: # Regex use RE2 syntax as defined here: https://github.com/google/re2/wiki/Syntax.
|
||||
@@ -117,7 +116,4 @@ changelog:
|
||||
- '^test:'
|
||||
- '^.*?Bump(\([[:word:]]+\))?.+$'
|
||||
- '^.*?\[Bot\](\([[:word:]]+\))?.+$'
|
||||
|
||||
|
||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
|
||||
|
||||
|
||||
@@ -74,3 +74,6 @@ packages:
|
||||
github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster:
|
||||
interfaces:
|
||||
ClusterServiceServer:
|
||||
github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/typed/application/v1alpha1:
|
||||
interfaces:
|
||||
AppProjectInterface:
|
||||
|
||||
@@ -4,7 +4,7 @@ ARG BASE_IMAGE=docker.io/library/ubuntu:24.04@sha256:3f85b7caad41a95462cf5b787d8
|
||||
# Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image
|
||||
# Also used as the image in CI jobs so needs all dependencies
|
||||
####################################################################################################
|
||||
FROM docker.io/library/golang:1.23.3@sha256:d56c3e08fe5b27729ee3834854ae8f7015af48fd651cd25d1e3bcf3c19830174 AS builder
|
||||
FROM docker.io/library/golang:1.24.6@sha256:2c89c41fb9efc3807029b59af69645867cfe978d2b877d475be0d72f6c6ce6f6 AS builder
|
||||
|
||||
RUN echo 'deb http://archive.debian.org/debian buster-backports main' >> /etc/apt/sources.list
|
||||
|
||||
@@ -101,7 +101,7 @@ RUN HOST_ARCH=$TARGETARCH NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OP
|
||||
####################################################################################################
|
||||
# Argo CD Build stage which performs the actual build of Argo CD binaries
|
||||
####################################################################################################
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.23.3@sha256:d56c3e08fe5b27729ee3834854ae8f7015af48fd651cd25d1e3bcf3c19830174 AS argocd-build
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.24.6@sha256:2c89c41fb9efc3807029b59af69645867cfe978d2b877d475be0d72f6c6ce6f6 AS argocd-build
|
||||
|
||||
WORKDIR /go/src/github.com/argoproj/argo-cd
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ type ApplicationSetReconciler struct {
|
||||
GlobalPreservedAnnotations []string
|
||||
GlobalPreservedLabels []string
|
||||
Metrics *metrics.ApplicationsetMetrics
|
||||
MaxResourcesStatusCount int
|
||||
}
|
||||
|
||||
// +kubebuilder:rbac:groups=argoproj.io,resources=applicationsets,verbs=get;list;watch;create;update;patch;delete
|
||||
@@ -127,8 +128,8 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
}()
|
||||
|
||||
// Do not attempt to further reconcile the ApplicationSet if it is being deleted.
|
||||
if applicationSetInfo.ObjectMeta.DeletionTimestamp != nil {
|
||||
appsetName := applicationSetInfo.ObjectMeta.Name
|
||||
if applicationSetInfo.DeletionTimestamp != nil {
|
||||
appsetName := applicationSetInfo.Name
|
||||
logCtx.Debugf("DeletionTimestamp is set on %s", appsetName)
|
||||
deleteAllowed := utils.DefaultPolicy(applicationSetInfo.Spec.SyncPolicy, r.Policy, r.EnablePolicyOverride).AllowDelete()
|
||||
if !deleteAllowed {
|
||||
@@ -155,6 +156,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
// desiredApplications is the main list of all expected Applications from all generators in this appset.
|
||||
desiredApplications, applicationSetReason, err := template.GenerateApplications(logCtx, applicationSetInfo, r.Generators, r.Renderer, r.Client)
|
||||
if err != nil {
|
||||
logCtx.Errorf("unable to generate applications: %v", err)
|
||||
_ = r.setApplicationSetStatusCondition(ctx,
|
||||
&applicationSetInfo,
|
||||
argov1alpha1.ApplicationSetCondition{
|
||||
@@ -164,7 +166,8 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
|
||||
}, parametersGenerated,
|
||||
)
|
||||
return ctrl.Result{RequeueAfter: ReconcileRequeueOnValidationError}, err
|
||||
// In order for the controller SDK to respect RequeueAfter, the error must be nil
|
||||
return ctrl.Result{RequeueAfter: ReconcileRequeueOnValidationError}, nil
|
||||
}
|
||||
|
||||
parametersGenerated = true
|
||||
@@ -208,16 +211,16 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
appSyncMap := map[string]bool{}
|
||||
|
||||
if r.EnableProgressiveSyncs {
|
||||
if applicationSetInfo.Spec.Strategy == nil && len(applicationSetInfo.Status.ApplicationStatus) > 0 {
|
||||
// If appset used progressive sync but stopped, clean up the progressive sync application statuses
|
||||
if !isRollingSyncStrategy(&applicationSetInfo) && len(applicationSetInfo.Status.ApplicationStatus) > 0 {
|
||||
// If an appset was previously syncing with a `RollingSync` strategy but it has switched to the default strategy, clean up the progressive sync application statuses
|
||||
logCtx.Infof("Removing %v unnecessary AppStatus entries from ApplicationSet %v", len(applicationSetInfo.Status.ApplicationStatus), applicationSetInfo.Name)
|
||||
|
||||
err := r.setAppSetApplicationStatus(ctx, logCtx, &applicationSetInfo, []argov1alpha1.ApplicationSetApplicationStatus{})
|
||||
if err != nil {
|
||||
return ctrl.Result{}, fmt.Errorf("failed to clear previous AppSet application statuses for %v: %w", applicationSetInfo.Name, err)
|
||||
}
|
||||
} else if applicationSetInfo.Spec.Strategy != nil {
|
||||
// appset uses progressive sync
|
||||
} else if isRollingSyncStrategy(&applicationSetInfo) {
|
||||
// The appset uses progressive sync with `RollingSync` strategy
|
||||
for _, app := range currentApplications {
|
||||
appMap[app.Name] = app
|
||||
}
|
||||
@@ -312,7 +315,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
|
||||
if applicationSetInfo.RefreshRequired() {
|
||||
delete(applicationSetInfo.Annotations, common.AnnotationApplicationSetRefresh)
|
||||
err := r.Client.Update(ctx, &applicationSetInfo)
|
||||
err := r.Update(ctx, &applicationSetInfo)
|
||||
if err != nil {
|
||||
logCtx.Warnf("error occurred while updating ApplicationSet: %v", err)
|
||||
_ = r.setApplicationSetStatusCondition(ctx,
|
||||
@@ -487,7 +490,7 @@ func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Con
|
||||
}
|
||||
|
||||
appProject := &argov1alpha1.AppProject{}
|
||||
err := r.Client.Get(ctx, types.NamespacedName{Name: app.Spec.Project, Namespace: r.ArgoCDNamespace}, appProject)
|
||||
err := r.Get(ctx, types.NamespacedName{Name: app.Spec.Project, Namespace: r.ArgoCDNamespace}, appProject)
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
errorsByIndex[i] = fmt.Errorf("application references project %s which does not exist", app.Spec.Project)
|
||||
@@ -551,12 +554,13 @@ func (r *ApplicationSetReconciler) SetupWithManager(mgr ctrl.Manager, enableProg
|
||||
return fmt.Errorf("error setting up with manager: %w", err)
|
||||
}
|
||||
|
||||
ownsHandler := getOwnsHandlerPredicates(enableProgressiveSyncs)
|
||||
appOwnsHandler := getApplicationOwnsHandler(enableProgressiveSyncs)
|
||||
appSetOwnsHandler := getApplicationSetOwnsHandler(enableProgressiveSyncs)
|
||||
|
||||
return ctrl.NewControllerManagedBy(mgr).WithOptions(controller.Options{
|
||||
MaxConcurrentReconciles: maxConcurrentReconciliations,
|
||||
}).For(&argov1alpha1.ApplicationSet{}).
|
||||
Owns(&argov1alpha1.Application{}, builder.WithPredicates(ownsHandler)).
|
||||
}).For(&argov1alpha1.ApplicationSet{}, builder.WithPredicates(appSetOwnsHandler)).
|
||||
Owns(&argov1alpha1.Application{}, builder.WithPredicates(appOwnsHandler)).
|
||||
WithEventFilter(ignoreNotAllowedNamespaces(r.ApplicationSetNamespaces)).
|
||||
Watches(
|
||||
&corev1.Secret{},
|
||||
@@ -564,7 +568,6 @@ func (r *ApplicationSetReconciler) SetupWithManager(mgr ctrl.Manager, enableProg
|
||||
Client: mgr.GetClient(),
|
||||
Log: log.WithField("type", "createSecretEventHandler"),
|
||||
}).
|
||||
// TODO: also watch Applications and respond on changes if we own them.
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
@@ -623,7 +626,7 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context,
|
||||
preservedAnnotations = append(preservedAnnotations, defaultPreservedAnnotations...)
|
||||
|
||||
for _, key := range preservedAnnotations {
|
||||
if state, exists := found.ObjectMeta.Annotations[key]; exists {
|
||||
if state, exists := found.Annotations[key]; exists {
|
||||
if generatedApp.Annotations == nil {
|
||||
generatedApp.Annotations = map[string]string{}
|
||||
}
|
||||
@@ -632,7 +635,7 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context,
|
||||
}
|
||||
|
||||
for _, key := range preservedLabels {
|
||||
if state, exists := found.ObjectMeta.Labels[key]; exists {
|
||||
if state, exists := found.Labels[key]; exists {
|
||||
if generatedApp.Labels == nil {
|
||||
generatedApp.Labels = map[string]string{}
|
||||
}
|
||||
@@ -642,7 +645,7 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context,
|
||||
|
||||
// Preserve post-delete finalizers:
|
||||
// https://github.com/argoproj/argo-cd/issues/17181
|
||||
for _, finalizer := range found.ObjectMeta.Finalizers {
|
||||
for _, finalizer := range found.Finalizers {
|
||||
if strings.HasPrefix(finalizer, argov1alpha1.PostDeleteFinalizerName) {
|
||||
if generatedApp.Finalizers == nil {
|
||||
generatedApp.Finalizers = []string{}
|
||||
@@ -651,10 +654,10 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context,
|
||||
}
|
||||
}
|
||||
|
||||
found.ObjectMeta.Annotations = generatedApp.Annotations
|
||||
found.Annotations = generatedApp.Annotations
|
||||
|
||||
found.ObjectMeta.Finalizers = generatedApp.Finalizers
|
||||
found.ObjectMeta.Labels = generatedApp.Labels
|
||||
found.Finalizers = generatedApp.Finalizers
|
||||
found.Labels = generatedApp.Labels
|
||||
|
||||
return controllerutil.SetControllerReference(&applicationSet, found, r.Scheme)
|
||||
})
|
||||
@@ -708,7 +711,7 @@ func (r *ApplicationSetReconciler) createInCluster(ctx context.Context, logCtx *
|
||||
|
||||
func (r *ApplicationSetReconciler) getCurrentApplications(ctx context.Context, applicationSet argov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error) {
|
||||
var current argov1alpha1.ApplicationList
|
||||
err := r.Client.List(ctx, ¤t, client.MatchingFields{".metadata.controller": applicationSet.Name}, client.InNamespace(applicationSet.Namespace))
|
||||
err := r.List(ctx, ¤t, client.MatchingFields{".metadata.controller": applicationSet.Name}, client.InNamespace(applicationSet.Namespace))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error retrieving applications: %w", err)
|
||||
}
|
||||
@@ -719,9 +722,6 @@ func (r *ApplicationSetReconciler) getCurrentApplications(ctx context.Context, a
|
||||
// deleteInCluster will delete Applications that are currently on the cluster, but not in appList.
|
||||
// The function must be called after all generators had been called and generated applications
|
||||
func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, logCtx *log.Entry, applicationSet argov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error {
|
||||
// settingsMgr := settings.NewSettingsManager(context.TODO(), r.KubeClientset, applicationSet.Namespace)
|
||||
// argoDB := db.NewDB(applicationSet.Namespace, settingsMgr, r.KubeClientset)
|
||||
// clusterList, err := argoDB.ListClusters(ctx)
|
||||
clusterList, err := utils.ListClusters(ctx, r.KubeClientset, r.ArgoCDNamespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing clusters: %w", err)
|
||||
@@ -756,7 +756,7 @@ func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, logCtx *
|
||||
continue
|
||||
}
|
||||
|
||||
err = r.Client.Delete(ctx, &app)
|
||||
err = r.Delete(ctx, &app)
|
||||
if err != nil {
|
||||
logCtx.WithError(err).Error("failed to delete Application")
|
||||
if firstError != nil {
|
||||
@@ -828,7 +828,7 @@ func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx conte
|
||||
if log.IsLevelEnabled(log.DebugLevel) {
|
||||
utils.LogPatch(appLog, patch, updated)
|
||||
}
|
||||
if err := r.Client.Patch(ctx, updated, patch); err != nil {
|
||||
if err := r.Patch(ctx, updated, patch); err != nil {
|
||||
return fmt.Errorf("error updating finalizers: %w", err)
|
||||
}
|
||||
// Application must have updated list of finalizers
|
||||
@@ -850,7 +850,7 @@ func (r *ApplicationSetReconciler) removeOwnerReferencesOnDeleteAppSet(ctx conte
|
||||
|
||||
for _, app := range applications {
|
||||
app.SetOwnerReferences([]metav1.OwnerReference{})
|
||||
err := r.Client.Update(ctx, &app)
|
||||
err := r.Update(ctx, &app)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error updating application: %w", err)
|
||||
}
|
||||
@@ -1006,8 +1006,14 @@ func appSyncEnabledForNextStep(appset *argov1alpha1.ApplicationSet, app argov1al
|
||||
return true
|
||||
}
|
||||
|
||||
func isRollingSyncStrategy(appset *argov1alpha1.ApplicationSet) bool {
|
||||
// It's only RollingSync if the type specifically sets it
|
||||
return appset.Spec.Strategy != nil && appset.Spec.Strategy.Type == "RollingSync" && appset.Spec.Strategy.RollingSync != nil
|
||||
}
|
||||
|
||||
func progressiveSyncsRollingSyncStrategyEnabled(appset *argov1alpha1.ApplicationSet) bool {
|
||||
return appset.Spec.Strategy != nil && appset.Spec.Strategy.RollingSync != nil && appset.Spec.Strategy.Type == "RollingSync" && len(appset.Spec.Strategy.RollingSync.Steps) > 0
|
||||
// ProgressiveSync is enabled if the strategy is set to `RollingSync` + steps slice is not empty
|
||||
return isRollingSyncStrategy(appset) && len(appset.Spec.Strategy.RollingSync.Steps) > 0
|
||||
}
|
||||
|
||||
func isApplicationHealthy(app argov1alpha1.Application) bool {
|
||||
@@ -1309,6 +1315,11 @@ func (r *ApplicationSetReconciler) updateResourcesStatus(ctx context.Context, lo
|
||||
sort.Slice(statuses, func(i, j int) bool {
|
||||
return statuses[i].Name < statuses[j].Name
|
||||
})
|
||||
|
||||
if r.MaxResourcesStatusCount > 0 && len(statuses) > r.MaxResourcesStatusCount {
|
||||
logCtx.Warnf("Truncating ApplicationSet %s resource status from %d to max allowed %d entries", appset.Name, len(statuses), r.MaxResourcesStatusCount)
|
||||
statuses = statuses[:r.MaxResourcesStatusCount]
|
||||
}
|
||||
appset.Status.Resources = statuses
|
||||
// DefaultRetry will retry 5 times with a backoff factor of 1, jitter of 0.1 and a duration of 10ms
|
||||
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
@@ -1456,7 +1467,7 @@ func syncApplication(application argov1alpha1.Application, prune bool) argov1alp
|
||||
return application
|
||||
}
|
||||
|
||||
func getOwnsHandlerPredicates(enableProgressiveSyncs bool) predicate.Funcs {
|
||||
func getApplicationOwnsHandler(enableProgressiveSyncs bool) predicate.Funcs {
|
||||
return predicate.Funcs{
|
||||
CreateFunc: func(e event.CreateEvent) bool {
|
||||
// if we are the owner and there is a create event, we most likely created it and do not need to
|
||||
@@ -1493,8 +1504,8 @@ func getOwnsHandlerPredicates(enableProgressiveSyncs bool) predicate.Funcs {
|
||||
if !isApp {
|
||||
return false
|
||||
}
|
||||
requeue := shouldRequeueApplicationSet(appOld, appNew, enableProgressiveSyncs)
|
||||
logCtx.WithField("requeue", requeue).Debugf("requeue: %t caused by application %s", requeue, appNew.Name)
|
||||
requeue := shouldRequeueForApplication(appOld, appNew, enableProgressiveSyncs)
|
||||
logCtx.WithField("requeue", requeue).Debugf("requeue caused by application %s", appNew.Name)
|
||||
return requeue
|
||||
},
|
||||
GenericFunc: func(e event.GenericEvent) bool {
|
||||
@@ -1511,13 +1522,13 @@ func getOwnsHandlerPredicates(enableProgressiveSyncs bool) predicate.Funcs {
|
||||
}
|
||||
}
|
||||
|
||||
// shouldRequeueApplicationSet determines when we want to requeue an ApplicationSet for reconciling based on an owned
|
||||
// shouldRequeueForApplication determines when we want to requeue an ApplicationSet for reconciling based on an owned
|
||||
// application change
|
||||
// The applicationset controller owns a subset of the Application CR.
|
||||
// We do not need to re-reconcile if parts of the application change outside the applicationset's control.
|
||||
// An example being, Application.ApplicationStatus.ReconciledAt which gets updated by the application controller.
|
||||
// Additionally, Application.ObjectMeta.ResourceVersion and Application.ObjectMeta.Generation which are set by K8s.
|
||||
func shouldRequeueApplicationSet(appOld *argov1alpha1.Application, appNew *argov1alpha1.Application, enableProgressiveSyncs bool) bool {
|
||||
func shouldRequeueForApplication(appOld *argov1alpha1.Application, appNew *argov1alpha1.Application, enableProgressiveSyncs bool) bool {
|
||||
if appOld == nil || appNew == nil {
|
||||
return false
|
||||
}
|
||||
@@ -1527,9 +1538,9 @@ func shouldRequeueApplicationSet(appOld *argov1alpha1.Application, appNew *argov
|
||||
// https://pkg.go.dev/reflect#DeepEqual
|
||||
// ApplicationDestination has an unexported field so we can just use the == for comparison
|
||||
if !cmp.Equal(appOld.Spec, appNew.Spec, cmpopts.EquateEmpty(), cmpopts.EquateComparable(argov1alpha1.ApplicationDestination{})) ||
|
||||
!cmp.Equal(appOld.ObjectMeta.GetAnnotations(), appNew.ObjectMeta.GetAnnotations(), cmpopts.EquateEmpty()) ||
|
||||
!cmp.Equal(appOld.ObjectMeta.GetLabels(), appNew.ObjectMeta.GetLabels(), cmpopts.EquateEmpty()) ||
|
||||
!cmp.Equal(appOld.ObjectMeta.GetFinalizers(), appNew.ObjectMeta.GetFinalizers(), cmpopts.EquateEmpty()) {
|
||||
!cmp.Equal(appOld.GetAnnotations(), appNew.GetAnnotations(), cmpopts.EquateEmpty()) ||
|
||||
!cmp.Equal(appOld.GetLabels(), appNew.GetLabels(), cmpopts.EquateEmpty()) ||
|
||||
!cmp.Equal(appOld.GetFinalizers(), appNew.GetFinalizers(), cmpopts.EquateEmpty()) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1550,4 +1561,90 @@ func shouldRequeueApplicationSet(appOld *argov1alpha1.Application, appNew *argov
|
||||
return false
|
||||
}
|
||||
|
||||
func getApplicationSetOwnsHandler(enableProgressiveSyncs bool) predicate.Funcs {
|
||||
return predicate.Funcs{
|
||||
CreateFunc: func(e event.CreateEvent) bool {
|
||||
appSet, isApp := e.Object.(*argov1alpha1.ApplicationSet)
|
||||
if !isApp {
|
||||
return false
|
||||
}
|
||||
log.WithField("applicationset", appSet.QualifiedName()).Debugln("received create event")
|
||||
// Always queue a new applicationset
|
||||
return true
|
||||
},
|
||||
DeleteFunc: func(e event.DeleteEvent) bool {
|
||||
appSet, isApp := e.Object.(*argov1alpha1.ApplicationSet)
|
||||
if !isApp {
|
||||
return false
|
||||
}
|
||||
log.WithField("applicationset", appSet.QualifiedName()).Debugln("received delete event")
|
||||
// Always queue for the deletion of an applicationset
|
||||
return true
|
||||
},
|
||||
UpdateFunc: func(e event.UpdateEvent) bool {
|
||||
appSetOld, isAppSet := e.ObjectOld.(*argov1alpha1.ApplicationSet)
|
||||
if !isAppSet {
|
||||
return false
|
||||
}
|
||||
appSetNew, isAppSet := e.ObjectNew.(*argov1alpha1.ApplicationSet)
|
||||
if !isAppSet {
|
||||
return false
|
||||
}
|
||||
requeue := shouldRequeueForApplicationSet(appSetOld, appSetNew, enableProgressiveSyncs)
|
||||
log.WithField("applicationset", appSetNew.QualifiedName()).
|
||||
WithField("requeue", requeue).Debugln("received update event")
|
||||
return requeue
|
||||
},
|
||||
GenericFunc: func(e event.GenericEvent) bool {
|
||||
appSet, isApp := e.Object.(*argov1alpha1.ApplicationSet)
|
||||
if !isApp {
|
||||
return false
|
||||
}
|
||||
log.WithField("applicationset", appSet.QualifiedName()).Debugln("received generic event")
|
||||
// Always queue for the generic of an applicationset
|
||||
return true
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// shouldRequeueForApplicationSet determines when we need to requeue an applicationset
|
||||
func shouldRequeueForApplicationSet(appSetOld, appSetNew *argov1alpha1.ApplicationSet, enableProgressiveSyncs bool) bool {
|
||||
if appSetOld == nil || appSetNew == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Requeue if any ApplicationStatus.Status changed for Progressive sync strategy
|
||||
if enableProgressiveSyncs {
|
||||
if !cmp.Equal(appSetOld.Status.ApplicationStatus, appSetNew.Status.ApplicationStatus, cmpopts.EquateEmpty()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// only compare the applicationset spec, annotations, labels and finalizers, deletionTimestamp, specifically avoiding
|
||||
// the status field. status is owned by the applicationset controller,
|
||||
// and we do not need to requeue when it does bookkeeping
|
||||
// NB: the ApplicationDestination comes from the ApplicationSpec being embedded
|
||||
// in the ApplicationSetTemplate from the generators
|
||||
if !cmp.Equal(appSetOld.Spec, appSetNew.Spec, cmpopts.EquateEmpty(), cmpopts.EquateComparable(argov1alpha1.ApplicationDestination{})) ||
|
||||
!cmp.Equal(appSetOld.GetLabels(), appSetNew.GetLabels(), cmpopts.EquateEmpty()) ||
|
||||
!cmp.Equal(appSetOld.GetFinalizers(), appSetNew.GetFinalizers(), cmpopts.EquateEmpty()) ||
|
||||
!cmp.Equal(appSetOld.DeletionTimestamp, appSetNew.DeletionTimestamp, cmpopts.EquateEmpty()) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Requeue only when the refresh annotation is newly added to the ApplicationSet.
|
||||
// Changes to other annotations made simultaneously might be missed, but such cases are rare.
|
||||
if !cmp.Equal(appSetOld.GetAnnotations(), appSetNew.GetAnnotations(), cmpopts.EquateEmpty()) {
|
||||
_, oldHasRefreshAnnotation := appSetOld.Annotations[common.AnnotationApplicationSetRefresh]
|
||||
_, newHasRefreshAnnotation := appSetNew.Annotations[common.AnnotationApplicationSetRefresh]
|
||||
|
||||
if oldHasRefreshAnnotation && !newHasRefreshAnnotation {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var _ handler.EventHandler = &clusterSecretEventHandler{}
|
||||
|
||||
@@ -1885,7 +1885,7 @@ func TestRequeueGeneratorFails(t *testing.T) {
|
||||
}
|
||||
|
||||
res, err := r.Reconcile(context.Background(), req)
|
||||
require.Error(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, ReconcileRequeueOnValidationError, res.RequeueAfter)
|
||||
}
|
||||
|
||||
@@ -6097,10 +6097,11 @@ func TestUpdateResourceStatus(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, cc := range []struct {
|
||||
name string
|
||||
appSet v1alpha1.ApplicationSet
|
||||
apps []v1alpha1.Application
|
||||
expectedResources []v1alpha1.ResourceStatus
|
||||
name string
|
||||
appSet v1alpha1.ApplicationSet
|
||||
apps []v1alpha1.Application
|
||||
expectedResources []v1alpha1.ResourceStatus
|
||||
maxResourcesStatusCount int
|
||||
}{
|
||||
{
|
||||
name: "handles an empty application list",
|
||||
@@ -6271,6 +6272,73 @@ func TestUpdateResourceStatus(t *testing.T) {
|
||||
apps: []v1alpha1.Application{},
|
||||
expectedResources: nil,
|
||||
},
|
||||
{
|
||||
name: "truncates resources status list to",
|
||||
appSet: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Status: v1alpha1.ApplicationSetStatus{
|
||||
Resources: []v1alpha1.ResourceStatus{
|
||||
{
|
||||
Name: "app1",
|
||||
Status: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
Health: &v1alpha1.HealthStatus{
|
||||
Status: health.HealthStatusProgressing,
|
||||
Message: "this is progressing",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "app2",
|
||||
Status: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
Health: &v1alpha1.HealthStatus{
|
||||
Status: health.HealthStatusProgressing,
|
||||
Message: "this is progressing",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apps: []v1alpha1.Application{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app1",
|
||||
},
|
||||
Status: v1alpha1.ApplicationStatus{
|
||||
Sync: v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
},
|
||||
Health: v1alpha1.HealthStatus{
|
||||
Status: health.HealthStatusHealthy,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app2",
|
||||
},
|
||||
Status: v1alpha1.ApplicationStatus{
|
||||
Sync: v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
},
|
||||
Health: v1alpha1.HealthStatus{
|
||||
Status: health.HealthStatusHealthy,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResources: []v1alpha1.ResourceStatus{
|
||||
{
|
||||
Name: "app1",
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
Health: &v1alpha1.HealthStatus{
|
||||
Status: health.HealthStatusHealthy,
|
||||
},
|
||||
},
|
||||
},
|
||||
maxResourcesStatusCount: 1,
|
||||
},
|
||||
} {
|
||||
t.Run(cc.name, func(t *testing.T) {
|
||||
kubeclientset := kubefake.NewSimpleClientset([]runtime.Object{}...)
|
||||
@@ -6279,13 +6347,14 @@ func TestUpdateResourceStatus(t *testing.T) {
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics(client)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
Scheme: scheme,
|
||||
Recorder: record.NewFakeRecorder(1),
|
||||
Generators: map[string]generators.Generator{},
|
||||
ArgoDB: &dbmocks.ArgoDB{},
|
||||
KubeClientset: kubeclientset,
|
||||
Metrics: metrics,
|
||||
Client: client,
|
||||
Scheme: scheme,
|
||||
Recorder: record.NewFakeRecorder(1),
|
||||
Generators: map[string]generators.Generator{},
|
||||
ArgoDB: &dbmocks.ArgoDB{},
|
||||
KubeClientset: kubeclientset,
|
||||
Metrics: metrics,
|
||||
MaxResourcesStatusCount: cc.maxResourcesStatusCount,
|
||||
}
|
||||
|
||||
err := r.updateResourcesStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
|
||||
@@ -6393,11 +6462,11 @@ func TestResourceStatusAreOrdered(t *testing.T) {
|
||||
|
||||
func TestOwnsHandler(t *testing.T) {
|
||||
// progressive syncs do not affect create, delete, or generic
|
||||
ownsHandler := getOwnsHandlerPredicates(true)
|
||||
ownsHandler := getApplicationOwnsHandler(true)
|
||||
assert.False(t, ownsHandler.CreateFunc(event.CreateEvent{}))
|
||||
assert.True(t, ownsHandler.DeleteFunc(event.DeleteEvent{}))
|
||||
assert.True(t, ownsHandler.GenericFunc(event.GenericEvent{}))
|
||||
ownsHandler = getOwnsHandlerPredicates(false)
|
||||
ownsHandler = getApplicationOwnsHandler(false)
|
||||
assert.False(t, ownsHandler.CreateFunc(event.CreateEvent{}))
|
||||
assert.True(t, ownsHandler.DeleteFunc(event.DeleteEvent{}))
|
||||
assert.True(t, ownsHandler.GenericFunc(event.GenericEvent{}))
|
||||
@@ -6577,7 +6646,7 @@ func TestOwnsHandler(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ownsHandler = getOwnsHandlerPredicates(tt.args.enableProgressiveSyncs)
|
||||
ownsHandler = getApplicationOwnsHandler(tt.args.enableProgressiveSyncs)
|
||||
assert.Equalf(t, tt.want, ownsHandler.UpdateFunc(tt.args.e), "UpdateFunc(%v)", tt.args.e)
|
||||
})
|
||||
}
|
||||
@@ -6654,6 +6723,358 @@ func TestMigrateStatus(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplicationSetOwnsHandlerUpdate(t *testing.T) {
|
||||
buildAppSet := func(annotations map[string]string) *v1alpha1.ApplicationSet {
|
||||
return &v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: annotations,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
appSetOld crtclient.Object
|
||||
appSetNew crtclient.Object
|
||||
enableProgressiveSyncs bool
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "Different Spec",
|
||||
appSetOld: &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{
|
||||
{List: &v1alpha1.ListGenerator{}},
|
||||
},
|
||||
},
|
||||
},
|
||||
appSetNew: &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{
|
||||
{Git: &v1alpha1.GitGenerator{}},
|
||||
},
|
||||
},
|
||||
},
|
||||
enableProgressiveSyncs: false,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "Different Annotations",
|
||||
appSetOld: buildAppSet(map[string]string{"key1": "value1"}),
|
||||
appSetNew: buildAppSet(map[string]string{"key1": "value2"}),
|
||||
enableProgressiveSyncs: false,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "Different Labels",
|
||||
appSetOld: &v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"key1": "value1"},
|
||||
},
|
||||
},
|
||||
appSetNew: &v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"key1": "value2"},
|
||||
},
|
||||
},
|
||||
enableProgressiveSyncs: false,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "Different Finalizers",
|
||||
appSetOld: &v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Finalizers: []string{"finalizer1"},
|
||||
},
|
||||
},
|
||||
appSetNew: &v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Finalizers: []string{"finalizer2"},
|
||||
},
|
||||
},
|
||||
enableProgressiveSyncs: false,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "No Changes",
|
||||
appSetOld: &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{
|
||||
{List: &v1alpha1.ListGenerator{}},
|
||||
},
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{"key1": "value1"},
|
||||
Labels: map[string]string{"key1": "value1"},
|
||||
Finalizers: []string{"finalizer1"},
|
||||
},
|
||||
},
|
||||
appSetNew: &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{
|
||||
{List: &v1alpha1.ListGenerator{}},
|
||||
},
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{"key1": "value1"},
|
||||
Labels: map[string]string{"key1": "value1"},
|
||||
Finalizers: []string{"finalizer1"},
|
||||
},
|
||||
},
|
||||
enableProgressiveSyncs: false,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "annotation removed",
|
||||
appSetOld: buildAppSet(map[string]string{
|
||||
argocommon.AnnotationApplicationSetRefresh: "true",
|
||||
}),
|
||||
appSetNew: buildAppSet(map[string]string{}),
|
||||
enableProgressiveSyncs: false,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "annotation not removed",
|
||||
appSetOld: buildAppSet(map[string]string{
|
||||
argocommon.AnnotationApplicationSetRefresh: "true",
|
||||
}),
|
||||
appSetNew: buildAppSet(map[string]string{
|
||||
argocommon.AnnotationApplicationSetRefresh: "true",
|
||||
}),
|
||||
enableProgressiveSyncs: false,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "annotation added",
|
||||
appSetOld: buildAppSet(map[string]string{}),
|
||||
appSetNew: buildAppSet(map[string]string{
|
||||
argocommon.AnnotationApplicationSetRefresh: "true",
|
||||
}),
|
||||
enableProgressiveSyncs: false,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "old object is not an appset",
|
||||
appSetOld: &v1alpha1.Application{},
|
||||
appSetNew: buildAppSet(map[string]string{}),
|
||||
enableProgressiveSyncs: false,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "new object is not an appset",
|
||||
appSetOld: buildAppSet(map[string]string{}),
|
||||
appSetNew: &v1alpha1.Application{},
|
||||
enableProgressiveSyncs: false,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "deletionTimestamp present when progressive sync enabled",
|
||||
appSetOld: buildAppSet(map[string]string{}),
|
||||
appSetNew: &v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
DeletionTimestamp: &metav1.Time{Time: time.Now()},
|
||||
},
|
||||
},
|
||||
enableProgressiveSyncs: true,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "deletionTimestamp present when progressive sync disabled",
|
||||
appSetOld: buildAppSet(map[string]string{}),
|
||||
appSetNew: &v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
DeletionTimestamp: &metav1.Time{Time: time.Now()},
|
||||
},
|
||||
},
|
||||
enableProgressiveSyncs: false,
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ownsHandler := getApplicationSetOwnsHandler(tt.enableProgressiveSyncs)
|
||||
requeue := ownsHandler.UpdateFunc(event.UpdateEvent{
|
||||
ObjectOld: tt.appSetOld,
|
||||
ObjectNew: tt.appSetNew,
|
||||
})
|
||||
assert.Equalf(t, tt.want, requeue, "ownsHandler.UpdateFunc(%v, %v, %t)", tt.appSetOld, tt.appSetNew, tt.enableProgressiveSyncs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplicationSetOwnsHandlerGeneric(t *testing.T) {
|
||||
ownsHandler := getApplicationSetOwnsHandler(false)
|
||||
tests := []struct {
|
||||
name string
|
||||
obj crtclient.Object
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "Object is ApplicationSet",
|
||||
obj: &v1alpha1.ApplicationSet{},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "Object is not ApplicationSet",
|
||||
obj: &v1alpha1.Application{},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
requeue := ownsHandler.GenericFunc(event.GenericEvent{
|
||||
Object: tt.obj,
|
||||
})
|
||||
assert.Equalf(t, tt.want, requeue, "ownsHandler.GenericFunc(%v)", tt.obj)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplicationSetOwnsHandlerCreate(t *testing.T) {
|
||||
ownsHandler := getApplicationSetOwnsHandler(false)
|
||||
tests := []struct {
|
||||
name string
|
||||
obj crtclient.Object
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "Object is ApplicationSet",
|
||||
obj: &v1alpha1.ApplicationSet{},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "Object is not ApplicationSet",
|
||||
obj: &v1alpha1.Application{},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
requeue := ownsHandler.CreateFunc(event.CreateEvent{
|
||||
Object: tt.obj,
|
||||
})
|
||||
assert.Equalf(t, tt.want, requeue, "ownsHandler.CreateFunc(%v)", tt.obj)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplicationSetOwnsHandlerDelete(t *testing.T) {
|
||||
ownsHandler := getApplicationSetOwnsHandler(false)
|
||||
tests := []struct {
|
||||
name string
|
||||
obj crtclient.Object
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "Object is ApplicationSet",
|
||||
obj: &v1alpha1.ApplicationSet{},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "Object is not ApplicationSet",
|
||||
obj: &v1alpha1.Application{},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
requeue := ownsHandler.DeleteFunc(event.DeleteEvent{
|
||||
Object: tt.obj,
|
||||
})
|
||||
assert.Equalf(t, tt.want, requeue, "ownsHandler.DeleteFunc(%v)", tt.obj)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldRequeueForApplicationSet(t *testing.T) {
|
||||
type args struct {
|
||||
appSetOld *v1alpha1.ApplicationSet
|
||||
appSetNew *v1alpha1.ApplicationSet
|
||||
enableProgressiveSyncs bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "NilAppSet",
|
||||
args: args{
|
||||
appSetNew: &v1alpha1.ApplicationSet{},
|
||||
appSetOld: nil,
|
||||
enableProgressiveSyncs: false,
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "ApplicationSetApplicationStatusChanged",
|
||||
args: args{
|
||||
appSetOld: &v1alpha1.ApplicationSet{
|
||||
Status: v1alpha1.ApplicationSetStatus{
|
||||
ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Status: "Healthy",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
appSetNew: &v1alpha1.ApplicationSet{
|
||||
Status: v1alpha1.ApplicationSetStatus{
|
||||
ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Status: "Waiting",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
enableProgressiveSyncs: true,
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "ApplicationSetWithDeletionTimestamp",
|
||||
args: args{
|
||||
appSetOld: &v1alpha1.ApplicationSet{
|
||||
Status: v1alpha1.ApplicationSetStatus{
|
||||
ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Status: "Healthy",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
appSetNew: &v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
DeletionTimestamp: &metav1.Time{Time: time.Now()},
|
||||
},
|
||||
Status: v1alpha1.ApplicationSetStatus{
|
||||
ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Status: "Waiting",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
enableProgressiveSyncs: false,
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equalf(t, tt.want, shouldRequeueForApplicationSet(tt.args.appSetOld, tt.args.appSetNew, tt.args.enableProgressiveSyncs), "shouldRequeueForApplicationSet(%v, %v)", tt.args.appSetOld, tt.args.appSetNew)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIgnoreNotAllowedNamespaces(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -6736,3 +7157,62 @@ func TestIgnoreNotAllowedNamespaces(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsRollingSyncStrategy(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
appset *v1alpha1.ApplicationSet
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "RollingSync strategy is explicitly set",
|
||||
appset: &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Strategy: &v1alpha1.ApplicationSetStrategy{
|
||||
Type: "RollingSync",
|
||||
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{
|
||||
Steps: []v1alpha1.ApplicationSetRolloutStep{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "AllAtOnce strategy is explicitly set",
|
||||
appset: &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Strategy: &v1alpha1.ApplicationSetStrategy{
|
||||
Type: "AllAtOnce",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Strategy is empty",
|
||||
appset: &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Strategy: &v1alpha1.ApplicationSetStrategy{},
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Strategy is nil",
|
||||
appset: &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Strategy: nil,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := isRollingSyncStrategy(tt.appset)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,10 +28,11 @@ type GitGenerator struct {
|
||||
namespace string
|
||||
}
|
||||
|
||||
func NewGitGenerator(repos services.Repos, namespace string) Generator {
|
||||
// NewGitGenerator creates a new instance of Git Generator
|
||||
func NewGitGenerator(repos services.Repos, controllerNamespace string) Generator {
|
||||
g := &GitGenerator{
|
||||
repos: repos,
|
||||
namespace: namespace,
|
||||
namespace: controllerNamespace,
|
||||
}
|
||||
|
||||
return g
|
||||
@@ -70,11 +71,11 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
|
||||
if !strings.Contains(appSet.Spec.Template.Spec.Project, "{{") {
|
||||
project := appSet.Spec.Template.Spec.Project
|
||||
appProject := &argoprojiov1alpha1.AppProject{}
|
||||
namespace := g.namespace
|
||||
if namespace == "" {
|
||||
namespace = appSet.Namespace
|
||||
controllerNamespace := g.namespace
|
||||
if controllerNamespace == "" {
|
||||
controllerNamespace = appSet.Namespace
|
||||
}
|
||||
if err := client.Get(context.TODO(), types.NamespacedName{Name: project, Namespace: namespace}, appProject); err != nil {
|
||||
if err := client.Get(context.TODO(), types.NamespacedName{Name: project, Namespace: controllerNamespace}, appProject); err != nil {
|
||||
return nil, fmt.Errorf("error getting project %s: %w", project, err)
|
||||
}
|
||||
// we need to verify the signature on the Git revision if GPG is enabled
|
||||
|
||||
2
applicationset/generators/mocks/Generator.go
generated
2
applicationset/generators/mocks/Generator.go
generated
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -10,15 +10,15 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services"
|
||||
)
|
||||
|
||||
func GetGenerators(ctx context.Context, c client.Client, k8sClient kubernetes.Interface, namespace string, argoCDService services.Repos, dynamicClient dynamic.Interface, scmConfig SCMConfig) map[string]Generator {
|
||||
func GetGenerators(ctx context.Context, c client.Client, k8sClient kubernetes.Interface, controllerNamespace string, argoCDService services.Repos, dynamicClient dynamic.Interface, scmConfig SCMConfig) map[string]Generator {
|
||||
terminalGenerators := map[string]Generator{
|
||||
"List": NewListGenerator(),
|
||||
"Clusters": NewClusterGenerator(c, ctx, k8sClient, namespace),
|
||||
"Git": NewGitGenerator(argoCDService, namespace),
|
||||
"Clusters": NewClusterGenerator(c, ctx, k8sClient, controllerNamespace),
|
||||
"Git": NewGitGenerator(argoCDService, controllerNamespace),
|
||||
"SCMProvider": NewSCMProviderGenerator(c, scmConfig),
|
||||
"ClusterDecisionResource": NewDuckTypeGenerator(ctx, dynamicClient, k8sClient, namespace),
|
||||
"ClusterDecisionResource": NewDuckTypeGenerator(ctx, dynamicClient, k8sClient, controllerNamespace),
|
||||
"PullRequest": NewPullRequestGenerator(c, scmConfig),
|
||||
"Plugin": NewPluginGenerator(c, ctx, k8sClient, namespace),
|
||||
"Plugin": NewPluginGenerator(c, ctx, k8sClient, controllerNamespace),
|
||||
}
|
||||
|
||||
nestedGenerators := map[string]Generator{
|
||||
|
||||
2
applicationset/services/mocks/Repos.go
generated
2
applicationset/services/mocks/Repos.go
generated
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
2
applicationset/utils/mocks/Renderer.go
generated
2
applicationset/utils/mocks/Renderer.go
generated
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -25,10 +25,14 @@ import (
|
||||
"github.com/go-playground/webhooks/v6/github"
|
||||
"github.com/go-playground/webhooks/v6/gitlab"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/util/guard"
|
||||
)
|
||||
|
||||
const payloadQueueSize = 50000
|
||||
|
||||
const panicMsgAppSet = "panic while processing applicationset-controller webhook event"
|
||||
|
||||
type WebhookHandler struct {
|
||||
sync.WaitGroup // for testing
|
||||
namespace string
|
||||
@@ -103,6 +107,7 @@ func NewWebhookHandler(namespace string, webhookParallelism int, argocdSettingsM
|
||||
}
|
||||
|
||||
func (h *WebhookHandler) startWorkerPool(webhookParallelism int) {
|
||||
compLog := log.WithField("component", "applicationset-webhook")
|
||||
for i := 0; i < webhookParallelism; i++ {
|
||||
h.Add(1)
|
||||
go func() {
|
||||
@@ -112,7 +117,7 @@ func (h *WebhookHandler) startWorkerPool(webhookParallelism int) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
h.HandleEvent(payload)
|
||||
guard.RecoverAndLog(func() { h.HandleEvent(payload) }, compLog, panicMsgAppSet)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ func NewCommand() *cobra.Command {
|
||||
selfHealBackoffTimeoutSeconds int
|
||||
selfHealBackoffFactor int
|
||||
selfHealBackoffCapSeconds int
|
||||
selfHealBackoffCooldownSeconds int
|
||||
syncTimeout int
|
||||
statusProcessors int
|
||||
operationProcessors int
|
||||
@@ -196,6 +197,7 @@ func NewCommand() *cobra.Command {
|
||||
time.Duration(appResyncJitter)*time.Second,
|
||||
time.Duration(selfHealTimeoutSeconds)*time.Second,
|
||||
selfHealBackoff,
|
||||
time.Duration(selfHealBackoffCooldownSeconds)*time.Second,
|
||||
time.Duration(syncTimeout)*time.Second,
|
||||
time.Duration(repoErrorGracePeriod)*time.Second,
|
||||
metricsPort,
|
||||
@@ -266,6 +268,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().IntVar(&selfHealBackoffTimeoutSeconds, "self-heal-backoff-timeout-seconds", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_TIMEOUT_SECONDS", 2, 0, math.MaxInt32), "Specifies initial timeout of exponential backoff between self heal attempts")
|
||||
command.Flags().IntVar(&selfHealBackoffFactor, "self-heal-backoff-factor", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_FACTOR", 3, 0, math.MaxInt32), "Specifies factor of exponential timeout between application self heal attempts")
|
||||
command.Flags().IntVar(&selfHealBackoffCapSeconds, "self-heal-backoff-cap-seconds", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_CAP_SECONDS", 300, 0, math.MaxInt32), "Specifies max timeout of exponential backoff between application self heal attempts")
|
||||
command.Flags().IntVar(&selfHealBackoffCooldownSeconds, "self-heal-backoff-cooldown-seconds", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_COOLDOWN_SECONDS", 330, 0, math.MaxInt32), "Specifies period of time the app needs to stay synced before the self heal backoff can reset")
|
||||
command.Flags().IntVar(&syncTimeout, "sync-timeout", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_SYNC_TIMEOUT", 0, 0, math.MaxInt32), "Specifies the timeout after which a sync would be terminated. 0 means no timeout (default 0).")
|
||||
command.Flags().Int64Var(&kubectlParallelismLimit, "kubectl-parallelism-limit", env.ParseInt64FromEnv("ARGOCD_APPLICATION_CONTROLLER_KUBECTL_PARALLELISM_LIMIT", 20, 0, math.MaxInt64), "Number of allowed concurrent kubectl fork/execs. Any value less than 1 means no limit.")
|
||||
command.Flags().BoolVar(&repoServerPlaintext, "repo-server-plaintext", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_PLAINTEXT", false), "Disable TLS on connections to repo server")
|
||||
|
||||
@@ -74,6 +74,7 @@ func NewCommand() *cobra.Command {
|
||||
enableScmProviders bool
|
||||
webhookParallelism int
|
||||
tokenRefStrictMode bool
|
||||
maxResourcesStatusCount int
|
||||
)
|
||||
scheme := runtime.NewScheme()
|
||||
_ = clientgoscheme.AddToScheme(scheme)
|
||||
@@ -227,6 +228,7 @@ func NewCommand() *cobra.Command {
|
||||
GlobalPreservedAnnotations: globalPreservedAnnotations,
|
||||
GlobalPreservedLabels: globalPreservedLabels,
|
||||
Metrics: &metrics,
|
||||
MaxResourcesStatusCount: maxResourcesStatusCount,
|
||||
}).SetupWithManager(mgr, enableProgressiveSyncs, maxConcurrentReconciliations); err != nil {
|
||||
log.Error(err, "unable to create controller", "controller", "ApplicationSet")
|
||||
os.Exit(1)
|
||||
@@ -270,6 +272,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().StringSliceVar(&globalPreservedLabels, "preserved-labels", env.StringsFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_LABELS", []string{}, ","), "Sets global preserved field values for labels")
|
||||
command.Flags().IntVar(&webhookParallelism, "webhook-parallelism-limit", env.ParseNumFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_WEBHOOK_PARALLELISM_LIMIT", 50, 1, 1000), "Number of webhook requests processed concurrently")
|
||||
command.Flags().StringSliceVar(&metricsAplicationsetLabels, "metrics-applicationset-labels", []string{}, "List of Application labels that will be added to the argocd_applicationset_labels metric")
|
||||
command.Flags().IntVar(&maxResourcesStatusCount, "max-resources-status-count", env.ParseNumFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_MAX_RESOURCES_STATUS_COUNT", 0, 0, math.MaxInt), "Max number of resources stored in appset status.")
|
||||
return &command
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,13 @@ import (
|
||||
"golang.org/x/term"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/util/rbac"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/cmd/argocd/commands/headless"
|
||||
"github.com/argoproj/argo-cd/v2/cmd/argocd/commands/utils"
|
||||
argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient"
|
||||
accountpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/account"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apiclient/session"
|
||||
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
|
||||
"github.com/argoproj/argo-cd/v2/util/cli"
|
||||
"github.com/argoproj/argo-cd/v2/util/errors"
|
||||
"github.com/argoproj/argo-cd/v2/util/io"
|
||||
@@ -218,7 +219,7 @@ argocd account can-i create clusters '*'
|
||||
|
||||
Actions: %v
|
||||
Resources: %v
|
||||
`, rbacpolicy.Actions, rbacpolicy.Resources),
|
||||
`, rbac.Actions, rbac.Resources),
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
ctx := c.Context()
|
||||
|
||||
@@ -262,7 +263,7 @@ func NewAccountListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comman
|
||||
Use: "list",
|
||||
Short: "List accounts",
|
||||
Example: "argocd account list",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
Run: func(c *cobra.Command, _ []string) {
|
||||
ctx := c.Context()
|
||||
|
||||
conn, client := headless.NewClientOrDie(clientOpts, c).NewAccountClientOrDie()
|
||||
@@ -309,7 +310,7 @@ argocd account get
|
||||
|
||||
# Get details for an account by name
|
||||
argocd account get --account <account-name>`,
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
Run: func(c *cobra.Command, _ []string) {
|
||||
ctx := c.Context()
|
||||
|
||||
clientset := headless.NewClientOrDie(clientOpts, c)
|
||||
@@ -358,7 +359,7 @@ func printAccountDetails(acc *accountpkg.Account) {
|
||||
expiresAt := time.Unix(t.ExpiresAt, 0)
|
||||
expiresAtFormatted = expiresAt.Format(time.RFC3339)
|
||||
if expiresAt.Before(time.Now()) {
|
||||
expiresAtFormatted = fmt.Sprintf("%s (expired)", expiresAtFormatted)
|
||||
expiresAtFormatted = expiresAtFormatted + " (expired)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,7 +383,7 @@ argocd account generate-token
|
||||
|
||||
# Generate token for the account with the specified name
|
||||
argocd account generate-token --account <account-name>`,
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
Run: func(c *cobra.Command, _ []string) {
|
||||
ctx := c.Context()
|
||||
|
||||
clientset := headless.NewClientOrDie(clientOpts, c)
|
||||
|
||||
@@ -9,13 +9,12 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
|
||||
"github.com/argoproj/argo-cd/v2/util/assets"
|
||||
"github.com/argoproj/argo-cd/v2/util/cli"
|
||||
"github.com/argoproj/argo-cd/v2/util/errors"
|
||||
@@ -28,94 +27,85 @@ type rbacTrait struct {
|
||||
allowPath bool
|
||||
}
|
||||
|
||||
// Provide a mapping of short-hand resource names to their RBAC counterparts
|
||||
// Provide a mapping of shorthand resource names to their RBAC counterparts
|
||||
var resourceMap = map[string]string{
|
||||
"account": rbacpolicy.ResourceAccounts,
|
||||
"app": rbacpolicy.ResourceApplications,
|
||||
"apps": rbacpolicy.ResourceApplications,
|
||||
"application": rbacpolicy.ResourceApplications,
|
||||
"applicationsets": rbacpolicy.ResourceApplicationSets,
|
||||
"cert": rbacpolicy.ResourceCertificates,
|
||||
"certs": rbacpolicy.ResourceCertificates,
|
||||
"certificate": rbacpolicy.ResourceCertificates,
|
||||
"cluster": rbacpolicy.ResourceClusters,
|
||||
"extension": rbacpolicy.ResourceExtensions,
|
||||
"gpgkey": rbacpolicy.ResourceGPGKeys,
|
||||
"key": rbacpolicy.ResourceGPGKeys,
|
||||
"log": rbacpolicy.ResourceLogs,
|
||||
"logs": rbacpolicy.ResourceLogs,
|
||||
"exec": rbacpolicy.ResourceExec,
|
||||
"proj": rbacpolicy.ResourceProjects,
|
||||
"projs": rbacpolicy.ResourceProjects,
|
||||
"project": rbacpolicy.ResourceProjects,
|
||||
"repo": rbacpolicy.ResourceRepositories,
|
||||
"repos": rbacpolicy.ResourceRepositories,
|
||||
"repository": rbacpolicy.ResourceRepositories,
|
||||
}
|
||||
|
||||
var projectScoped = map[string]bool{
|
||||
rbacpolicy.ResourceApplications: true,
|
||||
rbacpolicy.ResourceApplicationSets: true,
|
||||
rbacpolicy.ResourceLogs: true,
|
||||
rbacpolicy.ResourceExec: true,
|
||||
rbacpolicy.ResourceClusters: true,
|
||||
rbacpolicy.ResourceRepositories: true,
|
||||
"account": rbac.ResourceAccounts,
|
||||
"app": rbac.ResourceApplications,
|
||||
"apps": rbac.ResourceApplications,
|
||||
"application": rbac.ResourceApplications,
|
||||
"applicationsets": rbac.ResourceApplicationSets,
|
||||
"cert": rbac.ResourceCertificates,
|
||||
"certs": rbac.ResourceCertificates,
|
||||
"certificate": rbac.ResourceCertificates,
|
||||
"cluster": rbac.ResourceClusters,
|
||||
"extension": rbac.ResourceExtensions,
|
||||
"gpgkey": rbac.ResourceGPGKeys,
|
||||
"key": rbac.ResourceGPGKeys,
|
||||
"log": rbac.ResourceLogs,
|
||||
"logs": rbac.ResourceLogs,
|
||||
"exec": rbac.ResourceExec,
|
||||
"proj": rbac.ResourceProjects,
|
||||
"projs": rbac.ResourceProjects,
|
||||
"project": rbac.ResourceProjects,
|
||||
"repo": rbac.ResourceRepositories,
|
||||
"repos": rbac.ResourceRepositories,
|
||||
"repository": rbac.ResourceRepositories,
|
||||
}
|
||||
|
||||
// List of allowed RBAC resources
|
||||
var validRBACResourcesActions = map[string]actionTraitMap{
|
||||
rbacpolicy.ResourceAccounts: accountsActions,
|
||||
rbacpolicy.ResourceApplications: applicationsActions,
|
||||
rbacpolicy.ResourceApplicationSets: defaultCRUDActions,
|
||||
rbacpolicy.ResourceCertificates: defaultCRDActions,
|
||||
rbacpolicy.ResourceClusters: defaultCRUDActions,
|
||||
rbacpolicy.ResourceExtensions: extensionActions,
|
||||
rbacpolicy.ResourceGPGKeys: defaultCRDActions,
|
||||
rbacpolicy.ResourceLogs: logsActions,
|
||||
rbacpolicy.ResourceExec: execActions,
|
||||
rbacpolicy.ResourceProjects: defaultCRUDActions,
|
||||
rbacpolicy.ResourceRepositories: defaultCRUDActions,
|
||||
rbac.ResourceAccounts: accountsActions,
|
||||
rbac.ResourceApplications: applicationsActions,
|
||||
rbac.ResourceApplicationSets: defaultCRUDActions,
|
||||
rbac.ResourceCertificates: defaultCRDActions,
|
||||
rbac.ResourceClusters: defaultCRUDActions,
|
||||
rbac.ResourceExtensions: extensionActions,
|
||||
rbac.ResourceGPGKeys: defaultCRDActions,
|
||||
rbac.ResourceLogs: logsActions,
|
||||
rbac.ResourceExec: execActions,
|
||||
rbac.ResourceProjects: defaultCRUDActions,
|
||||
rbac.ResourceRepositories: defaultCRUDActions,
|
||||
}
|
||||
|
||||
// List of allowed RBAC actions
|
||||
var defaultCRUDActions = actionTraitMap{
|
||||
rbacpolicy.ActionCreate: rbacTrait{},
|
||||
rbacpolicy.ActionGet: rbacTrait{},
|
||||
rbacpolicy.ActionUpdate: rbacTrait{},
|
||||
rbacpolicy.ActionDelete: rbacTrait{},
|
||||
rbac.ActionCreate: rbacTrait{},
|
||||
rbac.ActionGet: rbacTrait{},
|
||||
rbac.ActionUpdate: rbacTrait{},
|
||||
rbac.ActionDelete: rbacTrait{},
|
||||
}
|
||||
|
||||
var defaultCRDActions = actionTraitMap{
|
||||
rbacpolicy.ActionCreate: rbacTrait{},
|
||||
rbacpolicy.ActionGet: rbacTrait{},
|
||||
rbacpolicy.ActionDelete: rbacTrait{},
|
||||
rbac.ActionCreate: rbacTrait{},
|
||||
rbac.ActionGet: rbacTrait{},
|
||||
rbac.ActionDelete: rbacTrait{},
|
||||
}
|
||||
|
||||
var applicationsActions = actionTraitMap{
|
||||
rbacpolicy.ActionCreate: rbacTrait{},
|
||||
rbacpolicy.ActionGet: rbacTrait{},
|
||||
rbacpolicy.ActionUpdate: rbacTrait{allowPath: true},
|
||||
rbacpolicy.ActionDelete: rbacTrait{allowPath: true},
|
||||
rbacpolicy.ActionAction: rbacTrait{allowPath: true},
|
||||
rbacpolicy.ActionOverride: rbacTrait{},
|
||||
rbacpolicy.ActionSync: rbacTrait{},
|
||||
rbac.ActionCreate: rbacTrait{},
|
||||
rbac.ActionGet: rbacTrait{},
|
||||
rbac.ActionUpdate: rbacTrait{allowPath: true},
|
||||
rbac.ActionDelete: rbacTrait{allowPath: true},
|
||||
rbac.ActionAction: rbacTrait{allowPath: true},
|
||||
rbac.ActionOverride: rbacTrait{},
|
||||
rbac.ActionSync: rbacTrait{},
|
||||
}
|
||||
|
||||
var accountsActions = actionTraitMap{
|
||||
rbacpolicy.ActionCreate: rbacTrait{},
|
||||
rbacpolicy.ActionUpdate: rbacTrait{},
|
||||
rbac.ActionCreate: rbacTrait{},
|
||||
rbac.ActionUpdate: rbacTrait{},
|
||||
}
|
||||
|
||||
var execActions = actionTraitMap{
|
||||
rbacpolicy.ActionCreate: rbacTrait{},
|
||||
rbac.ActionCreate: rbacTrait{},
|
||||
}
|
||||
|
||||
var logsActions = actionTraitMap{
|
||||
rbacpolicy.ActionGet: rbacTrait{},
|
||||
rbac.ActionGet: rbacTrait{},
|
||||
}
|
||||
|
||||
var extensionActions = actionTraitMap{
|
||||
rbacpolicy.ActionInvoke: rbacTrait{},
|
||||
rbac.ActionInvoke: rbacTrait{},
|
||||
}
|
||||
|
||||
// NewRBACCommand is the command for 'rbac'
|
||||
@@ -226,7 +216,7 @@ argocd admin settings rbac can someuser create application 'default/app' --defau
|
||||
// even if there is no explicit RBAC allow, or if there is an explicit RBAC deny)
|
||||
var isLogRbacEnforced func() bool
|
||||
if nsOverride && policyFile == "" {
|
||||
if resolveRBACResourceName(resource) == rbacpolicy.ResourceLogs {
|
||||
if resolveRBACResourceName(resource) == rbac.ResourceLogs {
|
||||
isLogRbacEnforced = func() bool {
|
||||
if opts, ok := cmdCtx.(*settingsOpts); ok {
|
||||
opts.loadClusterSettings = true
|
||||
@@ -248,12 +238,11 @@ argocd admin settings rbac can someuser create application 'default/app' --defau
|
||||
fmt.Println("Yes")
|
||||
}
|
||||
os.Exit(0)
|
||||
} else {
|
||||
if !quiet {
|
||||
fmt.Println("No")
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
if !quiet {
|
||||
fmt.Println("No")
|
||||
}
|
||||
os.Exit(1)
|
||||
},
|
||||
}
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(command)
|
||||
@@ -321,13 +310,11 @@ argocd admin settings rbac validate --namespace argocd
|
||||
if err := rbac.ValidatePolicy(userPolicy); err == nil {
|
||||
fmt.Printf("Policy is valid.\n")
|
||||
os.Exit(0)
|
||||
} else {
|
||||
fmt.Printf("Policy is invalid: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
log.Fatalf("Policy is empty or could not be loaded.")
|
||||
fmt.Printf("Policy is invalid: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
log.Fatalf("Policy is empty or could not be loaded.")
|
||||
},
|
||||
}
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(command)
|
||||
@@ -402,7 +389,7 @@ func getPolicyFromConfigMap(cm *corev1.ConfigMap) (string, string, string) {
|
||||
|
||||
// getPolicyConfigMap fetches the RBAC config map from K8s cluster
|
||||
func getPolicyConfigMap(ctx context.Context, client kubernetes.Interface, namespace string) (*corev1.ConfigMap, error) {
|
||||
cm, err := client.CoreV1().ConfigMaps(namespace).Get(ctx, common.ArgoCDRBACConfigMapName, v1.GetOptions{})
|
||||
cm, err := client.CoreV1().ConfigMaps(namespace).Get(ctx, common.ArgoCDRBACConfigMapName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -448,12 +435,12 @@ func checkPolicy(subject, action, resource, subResource, builtinPolicy, userPoli
|
||||
// Some project scoped resources have a special notation - for simplicity's sake,
|
||||
// if user gives no sub-resource (or specifies simple '*'), we construct
|
||||
// the required notation by setting subresource to '*/*'.
|
||||
if projectScoped[realResource] {
|
||||
if rbac.ProjectScoped[realResource] {
|
||||
if subResource == "*" || subResource == "" {
|
||||
subResource = "*/*"
|
||||
}
|
||||
}
|
||||
if realResource == rbacpolicy.ResourceLogs {
|
||||
if realResource == rbac.ResourceLogs {
|
||||
if isLogRbacEnforced != nil && !isLogRbacEnforced() {
|
||||
return true
|
||||
}
|
||||
@@ -466,9 +453,8 @@ func checkPolicy(subject, action, resource, subResource, builtinPolicy, userPoli
|
||||
func resolveRBACResourceName(name string) string {
|
||||
if res, ok := resourceMap[name]; ok {
|
||||
return res
|
||||
} else {
|
||||
return name
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// validateRBACResourceAction checks whether a given resource is a valid RBAC resource.
|
||||
|
||||
@@ -7,14 +7,15 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
|
||||
"github.com/argoproj/argo-cd/v2/util/rbac"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/util/assets"
|
||||
)
|
||||
|
||||
@@ -56,8 +57,8 @@ func Test_validateRBACResourceAction(t *testing.T) {
|
||||
{
|
||||
name: "Test valid resource and action",
|
||||
args: args{
|
||||
resource: rbacpolicy.ResourceApplications,
|
||||
action: rbacpolicy.ActionCreate,
|
||||
resource: rbac.ResourceApplications,
|
||||
action: rbac.ActionCreate,
|
||||
},
|
||||
valid: true,
|
||||
},
|
||||
@@ -71,7 +72,7 @@ func Test_validateRBACResourceAction(t *testing.T) {
|
||||
{
|
||||
name: "Test invalid action",
|
||||
args: args{
|
||||
resource: rbacpolicy.ResourceApplications,
|
||||
resource: rbac.ResourceApplications,
|
||||
action: "invalid",
|
||||
},
|
||||
valid: false,
|
||||
@@ -79,24 +80,24 @@ func Test_validateRBACResourceAction(t *testing.T) {
|
||||
{
|
||||
name: "Test invalid action for resource",
|
||||
args: args{
|
||||
resource: rbacpolicy.ResourceLogs,
|
||||
action: rbacpolicy.ActionCreate,
|
||||
resource: rbac.ResourceLogs,
|
||||
action: rbac.ActionCreate,
|
||||
},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
name: "Test valid action with path",
|
||||
args: args{
|
||||
resource: rbacpolicy.ResourceApplications,
|
||||
action: rbacpolicy.ActionAction + "/apps/Deployment/restart",
|
||||
resource: rbac.ResourceApplications,
|
||||
action: rbac.ActionAction + "/apps/Deployment/restart",
|
||||
},
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
name: "Test invalid action with path",
|
||||
args: args{
|
||||
resource: rbacpolicy.ResourceApplications,
|
||||
action: rbacpolicy.ActionGet + "/apps/Deployment/restart",
|
||||
resource: rbac.ResourceApplications,
|
||||
action: rbac.ActionGet + "/apps/Deployment/restart",
|
||||
},
|
||||
valid: false,
|
||||
},
|
||||
@@ -147,7 +148,7 @@ func Test_PolicyFromK8s(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
require.NoError(t, err)
|
||||
kubeclientset := fake.NewClientset(&v1.ConfigMap{
|
||||
kubeclientset := fake.NewClientset(&corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "argocd-rbac-cm",
|
||||
Namespace: "argocd",
|
||||
@@ -280,7 +281,7 @@ p, role:user, logs, get, .*/.*, allow
|
||||
p, role:user, exec, create, .*/.*, allow
|
||||
`
|
||||
|
||||
kubeclientset := fake.NewClientset(&v1.ConfigMap{
|
||||
kubeclientset := fake.NewClientset(&corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "argocd-rbac-cm",
|
||||
Namespace: "argocd",
|
||||
|
||||
@@ -69,7 +69,7 @@ func newSettingsManager(data map[string]string) *settings.SettingsManager {
|
||||
|
||||
type fakeCmdContext struct {
|
||||
mgr *settings.SettingsManager
|
||||
// nolint:unused,structcheck
|
||||
// nolint:unused
|
||||
out bytes.Buffer
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ func (p *Prompt) ConfirmBaseOnCount(messageForSingle string, messageForArray str
|
||||
}
|
||||
|
||||
if count == 1 {
|
||||
return p.Confirm(messageForSingle), true
|
||||
return p.Confirm(messageForSingle), false
|
||||
}
|
||||
|
||||
return p.ConfirmAll(messageForArray)
|
||||
|
||||
@@ -38,11 +38,47 @@ func TestConfirmBaseOnCountPromptDisabled(t *testing.T) {
|
||||
assert.True(t, result2)
|
||||
}
|
||||
|
||||
func TestConfirmBaseOnCountZeroApps(t *testing.T) {
|
||||
p := &Prompt{enabled: true}
|
||||
result1, result2 := p.ConfirmBaseOnCount("Proceed?", "Process all?", 0)
|
||||
assert.True(t, result1)
|
||||
assert.True(t, result2)
|
||||
func TestConfirmBaseOnCount(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
output bool
|
||||
count int
|
||||
}{
|
||||
{
|
||||
input: "y\n",
|
||||
output: true,
|
||||
count: 0,
|
||||
},
|
||||
{
|
||||
input: "y\n",
|
||||
output: true,
|
||||
count: 1,
|
||||
},
|
||||
{
|
||||
input: "n\n",
|
||||
output: false,
|
||||
count: 1,
|
||||
},
|
||||
}
|
||||
|
||||
origStdin := os.Stdin
|
||||
|
||||
for _, tt := range tests {
|
||||
tmpFile, err := writeToStdin(tt.input)
|
||||
require.NoError(t, err)
|
||||
p := &Prompt{enabled: true}
|
||||
result1, result2 := p.ConfirmBaseOnCount("Proceed?", "Proceed all?", tt.count)
|
||||
assert.Equal(t, tt.output, result1)
|
||||
if tt.count == 1 {
|
||||
assert.False(t, result2)
|
||||
} else {
|
||||
assert.Equal(t, tt.output, result2)
|
||||
}
|
||||
_ = tmpFile.Close()
|
||||
os.Remove(tmpFile.Name())
|
||||
}
|
||||
|
||||
os.Stdin = origStdin
|
||||
}
|
||||
|
||||
func TestConfirmPrompt(t *testing.T) {
|
||||
@@ -62,8 +98,8 @@ func TestConfirmPrompt(t *testing.T) {
|
||||
p := &Prompt{enabled: true}
|
||||
result := p.Confirm("Are you sure you want to run this command? (y/n) \n")
|
||||
assert.Equal(t, c.output, result)
|
||||
os.Remove(tmpFile.Name())
|
||||
_ = tmpFile.Close()
|
||||
os.Remove(tmpFile.Name())
|
||||
}
|
||||
|
||||
os.Stdin = origStdin
|
||||
@@ -89,8 +125,8 @@ func TestConfirmAllPrompt(t *testing.T) {
|
||||
confirm, confirmAll := p.ConfirmAll("Are you sure you want to run this command? (y/n) \n")
|
||||
assert.Equal(t, c.confirm, confirm)
|
||||
assert.Equal(t, c.confirmAll, confirmAll)
|
||||
os.Remove(tmpFile.Name())
|
||||
_ = tmpFile.Close()
|
||||
os.Remove(tmpFile.Name())
|
||||
}
|
||||
|
||||
os.Stdin = origStdin
|
||||
|
||||
@@ -18,11 +18,13 @@ func TestProjectOpts_ResourceLists(t *testing.T) {
|
||||
}
|
||||
|
||||
assert.ElementsMatch(t,
|
||||
[]v1.GroupKind{{Kind: "ConfigMap"}}, opts.GetAllowedNamespacedResources(),
|
||||
[]v1.GroupKind{{Group: "apps", Kind: "DaemonSet"}}, opts.GetDeniedNamespacedResources(),
|
||||
[]v1.GroupKind{{Group: "apiextensions.k8s.io", Kind: "CustomResourceDefinition"}}, opts.GetAllowedClusterResources(),
|
||||
[]v1.GroupKind{{Group: "rbac.authorization.k8s.io", Kind: "ClusterRole"}}, opts.GetDeniedClusterResources(),
|
||||
)
|
||||
[]v1.GroupKind{{Kind: "ConfigMap"}}, opts.GetAllowedNamespacedResources())
|
||||
assert.ElementsMatch(t,
|
||||
[]v1.GroupKind{{Group: "apps", Kind: "DaemonSet"}}, opts.GetDeniedNamespacedResources())
|
||||
assert.ElementsMatch(t,
|
||||
[]v1.GroupKind{{Group: "apiextensions.k8s.io", Kind: "CustomResourceDefinition"}}, opts.GetAllowedClusterResources())
|
||||
assert.ElementsMatch(t,
|
||||
[]v1.GroupKind{{Group: "rbac.authorization.k8s.io", Kind: "ClusterRole"}}, opts.GetDeniedClusterResources())
|
||||
}
|
||||
|
||||
func TestProjectOpts_GetDestinationServiceAccounts(t *testing.T) {
|
||||
|
||||
@@ -45,7 +45,7 @@ func AddRepoFlags(command *cobra.Command, opts *RepoOptions) {
|
||||
command.Flags().StringVar(&opts.GithubAppPrivateKeyPath, "github-app-private-key-path", "", "private key of the GitHub Application")
|
||||
command.Flags().StringVar(&opts.GitHubAppEnterpriseBaseURL, "github-app-enterprise-base-url", "", "base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3")
|
||||
command.Flags().StringVar(&opts.Proxy, "proxy", "", "use proxy to access repository")
|
||||
command.Flags().StringVar(&opts.Proxy, "no-proxy", "", "don't access these targets via proxy")
|
||||
command.Flags().StringVar(&opts.NoProxy, "no-proxy", "", "don't access these targets via proxy")
|
||||
command.Flags().StringVar(&opts.GCPServiceAccountKeyPath, "gcp-service-account-key-path", "", "service account key for the Google Cloud Platform")
|
||||
command.Flags().BoolVar(&opts.ForceHttpBasicAuth, "force-http-basic-auth", false, "whether to force use of basic auth when connecting repository via HTTP")
|
||||
}
|
||||
|
||||
4
commitserver/apiclient/mocks/Clientset.go
generated
4
commitserver/apiclient/mocks/Clientset.go
generated
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
@@ -14,7 +14,7 @@ type Clientset struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// NewCommitServerClient provides a mock function with given fields:
|
||||
// NewCommitServerClient provides a mock function with no fields
|
||||
func (_m *Clientset) NewCommitServerClient() (io.Closer, apiclient.CommitServiceClient, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
2
commitserver/commit/mocks/RepoClientFactory.go
generated
2
commitserver/commit/mocks/RepoClientFactory.go
generated
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
commitclient "github.com/argoproj/argo-cd/v2/commitserver/apiclient"
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
@@ -135,6 +136,7 @@ type ApplicationController struct {
|
||||
statusRefreshJitter time.Duration
|
||||
selfHealTimeout time.Duration
|
||||
selfHealBackOff *wait.Backoff
|
||||
selfHealBackoffCooldown time.Duration
|
||||
syncTimeout time.Duration
|
||||
db db.ArgoDB
|
||||
settingsMgr *settings_util.SettingsManager
|
||||
@@ -169,6 +171,7 @@ func NewApplicationController(
|
||||
appResyncJitter time.Duration,
|
||||
selfHealTimeout time.Duration,
|
||||
selfHealBackoff *wait.Backoff,
|
||||
selfHealBackoffCooldown time.Duration,
|
||||
syncTimeout time.Duration,
|
||||
repoErrorGracePeriod time.Duration,
|
||||
metricsPort int,
|
||||
@@ -214,6 +217,7 @@ func NewApplicationController(
|
||||
settingsMgr: settingsMgr,
|
||||
selfHealTimeout: selfHealTimeout,
|
||||
selfHealBackOff: selfHealBackoff,
|
||||
selfHealBackoffCooldown: selfHealBackoffCooldown,
|
||||
syncTimeout: syncTimeout,
|
||||
clusterSharding: clusterSharding,
|
||||
projByNameCache: sync.Map{},
|
||||
@@ -1193,7 +1197,7 @@ func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Applic
|
||||
isValid, cluster := ctrl.isValidDestination(app)
|
||||
if !isValid {
|
||||
app.UnSetCascadedDeletion()
|
||||
app.UnSetPostDeleteFinalizer()
|
||||
app.UnSetPostDeleteFinalizerAll()
|
||||
if err := ctrl.updateFinalizers(app); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1472,7 +1476,7 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
|
||||
} else {
|
||||
state.Phase = synccommon.OperationRunning
|
||||
state.RetryCount++
|
||||
state.Message = fmt.Sprintf("%s. Retrying attempt #%d at %s.", state.Message, state.RetryCount, retryAt.Format(time.Kitchen))
|
||||
state.Message = fmt.Sprintf("%s due to application controller sync timeout. Retrying attempt #%d at %s.", state.Message, state.RetryCount, retryAt.Format(time.Kitchen))
|
||||
}
|
||||
} else if state.RetryCount > 0 {
|
||||
state.Message = fmt.Sprintf("%s (retried %d times).", state.Message, state.RetryCount)
|
||||
@@ -1674,11 +1678,9 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
||||
|
||||
project, hasErrors := ctrl.refreshAppConditions(app)
|
||||
ts.AddCheckpoint("refresh_app_conditions_ms")
|
||||
now := metav1.Now()
|
||||
if hasErrors {
|
||||
app.Status.Sync.Status = appv1.SyncStatusCodeUnknown
|
||||
app.Status.Health.Status = health.HealthStatusUnknown
|
||||
app.Status.Health.LastTransitionTime = &now
|
||||
patchMs = ctrl.persistAppStatus(origApp, &app.Status)
|
||||
|
||||
if err := ctrl.cache.SetAppResourcesTree(app.InstanceName(ctrl.namespace), &appv1.ApplicationTree{}); err != nil {
|
||||
@@ -1769,6 +1771,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
||||
ts.AddCheckpoint("auto_sync_ms")
|
||||
|
||||
if app.Status.ReconciledAt == nil || comparisonLevel >= CompareWithLatest {
|
||||
now := metav1.Now()
|
||||
app.Status.ReconciledAt = &now
|
||||
}
|
||||
app.Status.Sync = *compareResult.syncStatus
|
||||
@@ -1999,9 +2002,15 @@ func (ctrl *ApplicationController) persistAppStatus(orig *appv1.Application, new
|
||||
ctrl.logAppEvent(orig, argo.EventInfo{Reason: argo.EventReasonResourceUpdated, Type: v1.EventTypeNormal}, message, context.TODO())
|
||||
}
|
||||
if orig.Status.Health.Status != newStatus.Health.Status {
|
||||
now := metav1.Now()
|
||||
newStatus.Health.LastTransitionTime = &now
|
||||
message := fmt.Sprintf("Updated health status: %s -> %s", orig.Status.Health.Status, newStatus.Health.Status)
|
||||
ctrl.logAppEvent(orig, argo.EventInfo{Reason: argo.EventReasonResourceUpdated, Type: v1.EventTypeNormal}, message, context.TODO())
|
||||
} else {
|
||||
// make sure the last transition time is the same and populated if the health is the same
|
||||
newStatus.Health.LastTransitionTime = orig.Status.Health.LastTransitionTime
|
||||
}
|
||||
|
||||
var newAnnotations map[string]string
|
||||
if orig.GetAnnotations() != nil {
|
||||
newAnnotations = make(map[string]string)
|
||||
@@ -2103,9 +2112,7 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
|
||||
InitiatedBy: appv1.OperationInitiator{Automated: true},
|
||||
Retry: appv1.RetryStrategy{Limit: 5},
|
||||
}
|
||||
if app.Status.OperationState != nil && app.Status.OperationState.Operation.Sync != nil {
|
||||
op.Sync.SelfHealAttemptsCount = app.Status.OperationState.Operation.Sync.SelfHealAttemptsCount
|
||||
}
|
||||
|
||||
if app.Spec.SyncPolicy.Retry != nil {
|
||||
op.Retry = *app.Spec.SyncPolicy.Retry
|
||||
}
|
||||
@@ -2121,8 +2128,18 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
|
||||
}
|
||||
logCtx.Infof("Skipping auto-sync: most recent sync already to %s", desiredCommitSHA)
|
||||
return nil, 0
|
||||
} else if alreadyAttempted && selfHeal {
|
||||
if shouldSelfHeal, retryAfter := ctrl.shouldSelfHeal(app); shouldSelfHeal {
|
||||
} else if selfHeal {
|
||||
shouldSelfHeal, retryAfter := ctrl.shouldSelfHeal(app, alreadyAttempted)
|
||||
if app.Status.OperationState != nil && app.Status.OperationState.Operation.Sync != nil {
|
||||
op.Sync.SelfHealAttemptsCount = app.Status.OperationState.Operation.Sync.SelfHealAttemptsCount
|
||||
}
|
||||
|
||||
if alreadyAttempted {
|
||||
if !shouldSelfHeal {
|
||||
logCtx.Infof("Skipping auto-sync: already attempted sync to %s with timeout %v (retrying in %v)", desiredCommitSHA, ctrl.selfHealTimeout, retryAfter)
|
||||
ctrl.requestAppRefresh(app.QualifiedName(), CompareWithLatest.Pointer(), &retryAfter)
|
||||
return nil, 0
|
||||
}
|
||||
op.Sync.SelfHealAttemptsCount++
|
||||
for _, resource := range resources {
|
||||
if resource.Status != appv1.SyncStatusCodeSynced {
|
||||
@@ -2133,10 +2150,6 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logCtx.Infof("Skipping auto-sync: already attempted sync to %s with timeout %v (retrying in %v)", desiredCommitSHA, ctrl.selfHealTimeout, retryAfter)
|
||||
ctrl.requestAppRefresh(app.QualifiedName(), CompareWithLatest.Pointer(), &retryAfter)
|
||||
return nil, 0
|
||||
}
|
||||
}
|
||||
ts.AddCheckpoint("already_attempted_check_ms")
|
||||
@@ -2220,29 +2233,41 @@ func alreadyAttemptedSync(app *appv1.Application, commitSHA string, commitSHAsMS
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) shouldSelfHeal(app *appv1.Application) (bool, time.Duration) {
|
||||
func (ctrl *ApplicationController) shouldSelfHeal(app *appv1.Application, alreadyAttempted bool) (bool, time.Duration) {
|
||||
if app.Status.OperationState == nil {
|
||||
return true, time.Duration(0)
|
||||
}
|
||||
|
||||
var timeSinceOperation *time.Duration
|
||||
if app.Status.OperationState.FinishedAt != nil {
|
||||
timeSinceOperation = ptr.To(time.Since(app.Status.OperationState.FinishedAt.Time))
|
||||
}
|
||||
|
||||
// Reset counter if the prior sync was successful and the cooldown period is over OR if the revision has changed
|
||||
if !alreadyAttempted || (timeSinceOperation != nil && *timeSinceOperation >= ctrl.selfHealBackoffCooldown && app.Status.Sync.Status == appv1.SyncStatusCodeSynced) {
|
||||
app.Status.OperationState.Operation.Sync.SelfHealAttemptsCount = 0
|
||||
}
|
||||
|
||||
var retryAfter time.Duration
|
||||
if ctrl.selfHealBackOff == nil {
|
||||
if app.Status.OperationState.FinishedAt == nil {
|
||||
if timeSinceOperation == nil {
|
||||
retryAfter = ctrl.selfHealTimeout
|
||||
} else {
|
||||
retryAfter = ctrl.selfHealTimeout - time.Since(app.Status.OperationState.FinishedAt.Time)
|
||||
retryAfter = ctrl.selfHealTimeout - *timeSinceOperation
|
||||
}
|
||||
} else {
|
||||
backOff := *ctrl.selfHealBackOff
|
||||
backOff.Steps = int(app.Status.OperationState.Operation.Sync.SelfHealAttemptsCount)
|
||||
var delay time.Duration
|
||||
for backOff.Steps > 0 {
|
||||
steps := backOff.Steps
|
||||
for i := 0; i < steps; i++ {
|
||||
delay = backOff.Step()
|
||||
}
|
||||
if app.Status.OperationState.FinishedAt == nil {
|
||||
|
||||
if timeSinceOperation == nil {
|
||||
retryAfter = delay
|
||||
} else {
|
||||
retryAfter = delay - time.Since(app.Status.OperationState.FinishedAt.Time)
|
||||
retryAfter = delay - *timeSinceOperation
|
||||
}
|
||||
}
|
||||
return retryAfter <= 0, retryAfter
|
||||
|
||||
@@ -171,6 +171,7 @@ func newFakeControllerWithResync(data *fakeData, appResyncPeriod time.Duration,
|
||||
time.Second,
|
||||
time.Minute,
|
||||
nil,
|
||||
time.Minute,
|
||||
0,
|
||||
time.Second*10,
|
||||
common.DefaultPortArgoCDMetrics,
|
||||
@@ -1837,7 +1838,7 @@ apps/Deployment:
|
||||
hs = {}
|
||||
hs.status = ""
|
||||
hs.message = ""
|
||||
|
||||
|
||||
if obj.metadata ~= nil then
|
||||
if obj.metadata.labels ~= nil then
|
||||
current_status = obj.metadata.labels["status"]
|
||||
@@ -2061,7 +2062,7 @@ func TestProcessRequestedAppOperation_FailedHasRetries(t *testing.T) {
|
||||
phase, _, _ := unstructured.NestedString(receivedPatch, "status", "operationState", "phase")
|
||||
assert.Equal(t, string(synccommon.OperationRunning), phase)
|
||||
message, _, _ := unstructured.NestedString(receivedPatch, "status", "operationState", "message")
|
||||
assert.Contains(t, message, "Retrying attempt #1")
|
||||
assert.Contains(t, message, "due to application controller sync timeout. Retrying attempt #1")
|
||||
retryCount, _, _ := unstructured.NestedFloat64(receivedPatch, "status", "operationState", "retryCount")
|
||||
assert.InEpsilon(t, float64(1), retryCount, 0.0001)
|
||||
}
|
||||
@@ -2533,7 +2534,7 @@ func TestSelfHealExponentialBackoff(t *testing.T) {
|
||||
ctrl.selfHealBackOff = &wait.Backoff{
|
||||
Factor: 3,
|
||||
Duration: 2 * time.Second,
|
||||
Cap: 5 * time.Minute,
|
||||
Cap: 2 * time.Minute,
|
||||
}
|
||||
|
||||
app := &v1alpha1.Application{
|
||||
@@ -2548,29 +2549,92 @@ func TestSelfHealExponentialBackoff(t *testing.T) {
|
||||
|
||||
testCases := []struct {
|
||||
attempts int64
|
||||
expectedAttempts int64
|
||||
finishedAt *metav1.Time
|
||||
expectedDuration time.Duration
|
||||
shouldSelfHeal bool
|
||||
alreadyAttempted bool
|
||||
syncStatus v1alpha1.SyncStatusCode
|
||||
}{{
|
||||
attempts: 0,
|
||||
finishedAt: ptr.To(metav1.Now()),
|
||||
expectedDuration: 0,
|
||||
shouldSelfHeal: true,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 0,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 1,
|
||||
finishedAt: ptr.To(metav1.Now()),
|
||||
expectedDuration: 2 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 1,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 2,
|
||||
finishedAt: ptr.To(metav1.Now()),
|
||||
expectedDuration: 6 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 2,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 3,
|
||||
finishedAt: nil,
|
||||
expectedDuration: 18 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 3,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 4,
|
||||
finishedAt: nil,
|
||||
expectedDuration: 54 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 4,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 5,
|
||||
finishedAt: nil,
|
||||
expectedDuration: 120 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 5,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 6,
|
||||
finishedAt: nil,
|
||||
expectedDuration: 120 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 6,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, {
|
||||
attempts: 6,
|
||||
finishedAt: nil,
|
||||
expectedDuration: 0,
|
||||
shouldSelfHeal: true,
|
||||
alreadyAttempted: false,
|
||||
expectedAttempts: 0,
|
||||
syncStatus: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
}, { // backoff will not reset as finished tme isn't >= cooldown
|
||||
attempts: 6,
|
||||
finishedAt: ptr.To(metav1.Now()),
|
||||
expectedDuration: 120 * time.Second,
|
||||
shouldSelfHeal: false,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 6,
|
||||
syncStatus: v1alpha1.SyncStatusCodeSynced,
|
||||
}, { // backoff will reset as finished time is >= cooldown
|
||||
attempts: 40,
|
||||
finishedAt: &metav1.Time{Time: time.Now().Add(-(1 * time.Minute))},
|
||||
expectedDuration: -60 * time.Second,
|
||||
shouldSelfHeal: true,
|
||||
alreadyAttempted: true,
|
||||
expectedAttempts: 0,
|
||||
syncStatus: v1alpha1.SyncStatusCodeSynced,
|
||||
}}
|
||||
|
||||
for i := range testCases {
|
||||
@@ -2578,8 +2642,10 @@ func TestSelfHealExponentialBackoff(t *testing.T) {
|
||||
t.Run(fmt.Sprintf("test case %d", i), func(t *testing.T) {
|
||||
app.Status.OperationState.Operation.Sync.SelfHealAttemptsCount = tc.attempts
|
||||
app.Status.OperationState.FinishedAt = tc.finishedAt
|
||||
ok, duration := ctrl.shouldSelfHeal(app)
|
||||
app.Status.Sync.Status = tc.syncStatus
|
||||
ok, duration := ctrl.shouldSelfHeal(app, tc.alreadyAttempted)
|
||||
require.Equal(t, ok, tc.shouldSelfHeal)
|
||||
require.Equal(t, tc.expectedAttempts, app.Status.OperationState.Operation.Sync.SelfHealAttemptsCount)
|
||||
assertDurationAround(t, tc.expectedDuration, duration)
|
||||
})
|
||||
}
|
||||
|
||||
6
controller/cache/mocks/LiveStateCache.go
generated
vendored
6
controller/cache/mocks/LiveStateCache.go
generated
vendored
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
@@ -55,7 +55,7 @@ func (_m *LiveStateCache) GetClusterCache(server string) (cache.ClusterCache, er
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetClustersInfo provides a mock function with given fields:
|
||||
// GetClustersInfo provides a mock function with no fields
|
||||
func (_m *LiveStateCache) GetClustersInfo() []cache.ClusterInfo {
|
||||
ret := _m.Called()
|
||||
|
||||
@@ -172,7 +172,7 @@ func (_m *LiveStateCache) GetVersionsInfo(serverURL string) (string, []kube.APIR
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// Init provides a mock function with given fields:
|
||||
// Init provides a mock function with no fields
|
||||
func (_m *LiveStateCache) Init() error {
|
||||
ret := _m.Called()
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/argoproj/gitops-engine/pkg/sync/ignore"
|
||||
kubeutil "github.com/argoproj/gitops-engine/pkg/utils/kube"
|
||||
log "github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
@@ -22,7 +21,9 @@ func setApplicationHealth(resources []managedResource, statuses []appv1.Resource
|
||||
var savedErr error
|
||||
var errCount uint
|
||||
|
||||
appHealth := appv1.HealthStatus{Status: health.HealthStatusHealthy}
|
||||
appHealth := app.Status.Health.DeepCopy()
|
||||
appHealth.Status = health.HealthStatusHealthy
|
||||
|
||||
for i, res := range resources {
|
||||
if res.Target != nil && hookutil.Skip(res.Target) {
|
||||
continue
|
||||
@@ -82,18 +83,11 @@ func setApplicationHealth(resources []managedResource, statuses []appv1.Resource
|
||||
}
|
||||
if persistResourceHealth {
|
||||
app.Status.ResourceHealthSource = appv1.ResourceHealthLocationInline
|
||||
// if the status didn't change, don't update the timestamp
|
||||
if app.Status.Health.Status == appHealth.Status && app.Status.Health.LastTransitionTime != nil {
|
||||
appHealth.LastTransitionTime = app.Status.Health.LastTransitionTime
|
||||
} else {
|
||||
now := metav1.Now()
|
||||
appHealth.LastTransitionTime = &now
|
||||
}
|
||||
} else {
|
||||
app.Status.ResourceHealthSource = appv1.ResourceHealthLocationAppTree
|
||||
}
|
||||
if savedErr != nil && errCount > 1 {
|
||||
savedErr = fmt.Errorf("see application-controller logs for %d other errors; most recent error was: %w", errCount-1, savedErr)
|
||||
}
|
||||
return &appHealth, savedErr
|
||||
return appHealth, savedErr
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@ func TestSetApplicationHealth(t *testing.T) {
|
||||
assert.NotNil(t, healthStatus.LastTransitionTime)
|
||||
assert.Nil(t, resourceStatuses[0].Health.LastTransitionTime)
|
||||
assert.Nil(t, resourceStatuses[1].Health.LastTransitionTime)
|
||||
previousLastTransitionTime := healthStatus.LastTransitionTime
|
||||
app.Status.Health = *healthStatus
|
||||
|
||||
// now mark the job as a hook and retry. it should ignore the hook and consider the app healthy
|
||||
@@ -81,9 +80,8 @@ func TestSetApplicationHealth(t *testing.T) {
|
||||
healthStatus, err = setApplicationHealth(resources, resourceStatuses, nil, app, true)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, health.HealthStatusHealthy, healthStatus.Status)
|
||||
// change in health, timestamp should change
|
||||
assert.NotEqual(t, *previousLastTransitionTime, *healthStatus.LastTransitionTime)
|
||||
previousLastTransitionTime = healthStatus.LastTransitionTime
|
||||
// timestamp should be the same in case health did not change
|
||||
assert.Equal(t, app.Status.Health.LastTransitionTime, healthStatus.LastTransitionTime)
|
||||
app.Status.Health = *healthStatus
|
||||
|
||||
// now we set the `argocd.argoproj.io/ignore-healthcheck: "true"` annotation on the job's target.
|
||||
@@ -94,8 +92,7 @@ func TestSetApplicationHealth(t *testing.T) {
|
||||
healthStatus, err = setApplicationHealth(resources, resourceStatuses, nil, app, true)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, health.HealthStatusHealthy, healthStatus.Status)
|
||||
// no change in health, timestamp shouldn't change
|
||||
assert.Equal(t, *previousLastTransitionTime, *healthStatus.LastTransitionTime)
|
||||
assert.Equal(t, app.Status.Health.LastTransitionTime, healthStatus.LastTransitionTime)
|
||||
}
|
||||
|
||||
func TestSetApplicationHealth_ResourceHealthNotPersisted(t *testing.T) {
|
||||
@@ -124,7 +121,7 @@ func TestSetApplicationHealth_MissingResource(t *testing.T) {
|
||||
healthStatus, err := setApplicationHealth(resources, resourceStatuses, lua.ResourceHealthOverrides{}, app, true)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, health.HealthStatusMissing, healthStatus.Status)
|
||||
assert.False(t, healthStatus.LastTransitionTime.IsZero())
|
||||
assert.Equal(t, app.Status.Health.LastTransitionTime, healthStatus.LastTransitionTime)
|
||||
}
|
||||
|
||||
func TestSetApplicationHealth_HealthImproves(t *testing.T) {
|
||||
@@ -156,7 +153,7 @@ func TestSetApplicationHealth_HealthImproves(t *testing.T) {
|
||||
healthStatus, err := setApplicationHealth(resources, resourceStatuses, overrides, app, true)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.newStatus, healthStatus.Status)
|
||||
assert.NotEqual(t, testTimestamp, *healthStatus.LastTransitionTime)
|
||||
assert.Equal(t, app.Status.Health.LastTransitionTime, healthStatus.LastTransitionTime)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -173,6 +170,7 @@ func TestSetApplicationHealth_MissingResourceNoBuiltHealthCheck(t *testing.T) {
|
||||
healthStatus, err := setApplicationHealth(resources, resourceStatuses, lua.ResourceHealthOverrides{}, app, true)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, health.HealthStatusHealthy, healthStatus.Status)
|
||||
assert.Equal(t, app.Status.Health.LastTransitionTime, healthStatus.LastTransitionTime)
|
||||
assert.Equal(t, health.HealthStatusMissing, resourceStatuses[0].Health.Status)
|
||||
})
|
||||
|
||||
@@ -184,7 +182,7 @@ func TestSetApplicationHealth_MissingResourceNoBuiltHealthCheck(t *testing.T) {
|
||||
}, app, true)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, health.HealthStatusMissing, healthStatus.Status)
|
||||
assert.False(t, healthStatus.LastTransitionTime.IsZero())
|
||||
assert.Equal(t, app.Status.Health.LastTransitionTime, healthStatus.LastTransitionTime)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -481,7 +481,6 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1
|
||||
|
||||
// return unknown comparison result if basic comparison settings cannot be loaded
|
||||
if err != nil {
|
||||
now := metav1.Now()
|
||||
if hasMultipleSources {
|
||||
return &comparisonResult{
|
||||
syncStatus: &v1alpha1.SyncStatus{
|
||||
@@ -489,7 +488,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1
|
||||
Status: v1alpha1.SyncStatusCodeUnknown,
|
||||
Revisions: revisions,
|
||||
},
|
||||
healthStatus: &v1alpha1.HealthStatus{Status: health.HealthStatusUnknown, LastTransitionTime: &now},
|
||||
healthStatus: &v1alpha1.HealthStatus{Status: health.HealthStatusUnknown},
|
||||
}, nil
|
||||
} else {
|
||||
return &comparisonResult{
|
||||
@@ -498,7 +497,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1
|
||||
Status: v1alpha1.SyncStatusCodeUnknown,
|
||||
Revision: revisions[0],
|
||||
},
|
||||
healthStatus: &v1alpha1.HealthStatus{Status: health.HealthStatusUnknown, LastTransitionTime: &now},
|
||||
healthStatus: &v1alpha1.HealthStatus{Status: health.HealthStatusUnknown},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -715,7 +715,7 @@ func TestSetHealth(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, health.HealthStatusHealthy, compRes.healthStatus.Status)
|
||||
assert.False(t, compRes.healthStatus.LastTransitionTime.IsZero())
|
||||
assert.Equal(t, app.Status.Health.LastTransitionTime, compRes.healthStatus.LastTransitionTime)
|
||||
}
|
||||
|
||||
func TestPreserveStatusTimestamp(t *testing.T) {
|
||||
@@ -790,7 +790,7 @@ func TestSetHealthSelfReferencedApp(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, health.HealthStatusHealthy, compRes.healthStatus.Status)
|
||||
assert.False(t, compRes.healthStatus.LastTransitionTime.IsZero())
|
||||
assert.Equal(t, app.Status.Health.LastTransitionTime, compRes.healthStatus.LastTransitionTime)
|
||||
}
|
||||
|
||||
func TestSetManagedResourcesWithOrphanedResources(t *testing.T) {
|
||||
@@ -866,7 +866,7 @@ func TestReturnUnknownComparisonStateOnSettingLoadError(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, health.HealthStatusUnknown, compRes.healthStatus.Status)
|
||||
assert.False(t, compRes.healthStatus.LastTransitionTime.IsZero())
|
||||
assert.Equal(t, app.Status.Health.LastTransitionTime, compRes.healthStatus.LastTransitionTime)
|
||||
assert.Equal(t, argoappv1.SyncStatusCodeUnknown, compRes.syncStatus.Status)
|
||||
}
|
||||
|
||||
|
||||
@@ -114,15 +114,6 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
|
||||
}
|
||||
syncOp = *state.Operation.Sync
|
||||
|
||||
// validates if it should fail the sync if it finds shared resources
|
||||
hasSharedResource, sharedResourceMessage := hasSharedResourceCondition(app)
|
||||
if syncOp.SyncOptions.HasOption("FailOnSharedResource=true") &&
|
||||
hasSharedResource {
|
||||
state.Phase = common.OperationFailed
|
||||
state.Message = fmt.Sprintf("Shared resource found: %s", sharedResourceMessage)
|
||||
return
|
||||
}
|
||||
|
||||
isMultiSourceRevision := app.Spec.HasMultipleSources()
|
||||
rollback := len(syncOp.Sources) > 0 || syncOp.Source != nil
|
||||
if rollback {
|
||||
@@ -213,6 +204,15 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
|
||||
syncRes.Revision = compareResult.syncStatus.Revision
|
||||
syncRes.Revisions = compareResult.syncStatus.Revisions
|
||||
|
||||
// validates if it should fail the sync if it finds shared resources
|
||||
hasSharedResource, sharedResourceMessage := hasSharedResourceCondition(app)
|
||||
if syncOp.SyncOptions.HasOption("FailOnSharedResource=true") &&
|
||||
hasSharedResource {
|
||||
state.Phase = common.OperationFailed
|
||||
state.Message = fmt.Sprintf("Shared resource found: %s", sharedResourceMessage)
|
||||
return
|
||||
}
|
||||
|
||||
// If there are any comparison or spec errors error conditions do not perform the operation
|
||||
if errConditions := app.Status.GetConditions(map[v1alpha1.ApplicationConditionType]bool{
|
||||
v1alpha1.ApplicationConditionComparisonError: true,
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
argocommon "github.com/argoproj/argo-cd/v2/common"
|
||||
"github.com/argoproj/argo-cd/v2/controller/testdata"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
@@ -190,17 +191,23 @@ func TestSyncComparisonError(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAppStateManager_SyncAppState(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type fixture struct {
|
||||
project *v1alpha1.AppProject
|
||||
application *v1alpha1.Application
|
||||
project *v1alpha1.AppProject
|
||||
controller *ApplicationController
|
||||
}
|
||||
|
||||
setup := func() *fixture {
|
||||
setup := func(liveObjects map[kube.ResourceKey]*unstructured.Unstructured) *fixture {
|
||||
app := newFakeApp()
|
||||
app.Status.OperationState = nil
|
||||
app.Status.History = nil
|
||||
|
||||
if liveObjects == nil {
|
||||
liveObjects = make(map[kube.ResourceKey]*unstructured.Unstructured)
|
||||
}
|
||||
|
||||
project := &v1alpha1.AppProject{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: test.FakeArgoCDNamespace,
|
||||
@@ -208,6 +215,12 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
|
||||
},
|
||||
Spec: v1alpha1.AppProjectSpec{
|
||||
SignatureKeys: []v1alpha1.SignatureKey{{KeyID: "test"}},
|
||||
Destinations: []v1alpha1.ApplicationDestination{
|
||||
{
|
||||
Namespace: "*",
|
||||
Server: "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
data := fakeData{
|
||||
@@ -218,13 +231,13 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
|
||||
Server: test.FakeClusterURL,
|
||||
Revision: "abc123",
|
||||
},
|
||||
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
|
||||
managedLiveObjs: liveObjects,
|
||||
}
|
||||
ctrl := newFakeController(&data, nil)
|
||||
|
||||
return &fixture{
|
||||
project: project,
|
||||
application: app,
|
||||
project: project,
|
||||
controller: ctrl,
|
||||
}
|
||||
}
|
||||
@@ -232,13 +245,23 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
|
||||
t.Run("will fail the sync if finds shared resources", func(t *testing.T) {
|
||||
// given
|
||||
t.Parallel()
|
||||
f := setup()
|
||||
syncErrorMsg := "deployment already applied by another application"
|
||||
condition := v1alpha1.ApplicationCondition{
|
||||
Type: v1alpha1.ApplicationConditionSharedResourceWarning,
|
||||
Message: syncErrorMsg,
|
||||
}
|
||||
f.application.Status.Conditions = append(f.application.Status.Conditions, condition)
|
||||
|
||||
sharedObject := kube.MustToUnstructured(&corev1.ConfigMap{
|
||||
TypeMeta: v1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "configmap1",
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{
|
||||
argocommon.LabelKeyAppInstance: "another-app",
|
||||
},
|
||||
},
|
||||
})
|
||||
liveObjects := make(map[kube.ResourceKey]*unstructured.Unstructured)
|
||||
liveObjects[kube.GetResourceKey(sharedObject)] = sharedObject
|
||||
f := setup(liveObjects)
|
||||
|
||||
// Sync with source unspecified
|
||||
opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{
|
||||
@@ -253,7 +276,7 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
|
||||
|
||||
// then
|
||||
assert.Equal(t, common.OperationFailed, opState.Phase)
|
||||
assert.Contains(t, opState.Message, syncErrorMsg)
|
||||
assert.Contains(t, opState.Message, "ConfigMap/configmap1 is part of applications fake-argocd-ns/my-app and another-app")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -272,6 +272,8 @@ data:
|
||||
applicationsetcontroller.requeue.after: "3m"
|
||||
# Enable strict mode for tokenRef in ApplicationSet resources. When enabled, the referenced secret must have a label `argocd.argoproj.io/secret-type` with value `scm-creds`.
|
||||
applicationsetcontroller.enable.tokenref.strict.mode: "false"
|
||||
# The maximum number of resources stored in the status of an ApplicationSet. This is a safeguard to prevent the status from growing too large.
|
||||
applicationsetcontroller.status.max.resources.count: "5000"
|
||||
|
||||
## Argo CD Notifications Controller Properties
|
||||
# Set the logging level. One of: debug|info|warn|error (default "info")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Argo CD is largely stateless. All data is persisted as Kubernetes objects, which in turn is stored in Kubernetes' etcd. Redis is only used as a throw-away cache and can be lost. When lost, it will be rebuilt without loss of service.
|
||||
|
||||
A set of [HA manifests](https://github.com/argoproj/argo-cd/tree/master/manifests/ha) are provided for users who wish to run Argo CD in a highly available manner. This runs more containers, and runs Redis in HA mode.
|
||||
A set of [HA manifests](https://github.com/argoproj/argo-cd/tree/stable/manifests/ha) are provided for users who wish to run Argo CD in a highly available manner. This runs more containers, and runs Redis in HA mode.
|
||||
|
||||
> **NOTE:** The HA installation will require at least three different nodes due to pod anti-affinity roles in the
|
||||
> specs. Additionally, IPv6 only clusters are not supported.
|
||||
|
||||
@@ -70,6 +70,7 @@ argocd-application-controller [flags]
|
||||
--repo-server-timeout-seconds int Repo server RPC call timeout seconds. (default 60)
|
||||
--request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0")
|
||||
--self-heal-backoff-cap-seconds int Specifies max timeout of exponential backoff between application self heal attempts (default 300)
|
||||
--self-heal-backoff-cooldown-seconds int Specifies period of time the app needs to stay synced before the self heal backoff can reset (default 330)
|
||||
--self-heal-backoff-factor int Specifies factor of exponential timeout between application self heal attempts (default 3)
|
||||
--self-heal-backoff-timeout-seconds int Specifies initial timeout of exponential backoff between self heal attempts (default 2)
|
||||
--self-heal-timeout-seconds int Specifies timeout between application self heal attempts
|
||||
|
||||
@@ -3,4 +3,12 @@
|
||||
## Upgraded Helm Version
|
||||
|
||||
Helm was upgraded to 3.16.2 and the skipSchemaValidation Flag was added to
|
||||
the [CLI and Application CR](https://argo-cd.readthedocs.io/en/latest/user-guide/helm/#helm-skip-schema-validation).
|
||||
the [CLI and Application CR](https://argo-cd.readthedocs.io/en/latest/user-guide/helm/#helm-skip-schema-validation).
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
## Sanitized project API response
|
||||
|
||||
Due to security reasons ([GHSA-786q-9hcg-v9ff](https://github.com/argoproj/argo-cd/security/advisories/GHSA-786q-9hcg-v9ff)),
|
||||
the project API response was sanitized to remove sensitive information. This includes
|
||||
credentials of project-scoped repositories and clusters.
|
||||
|
||||
36
go.mod
36
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/argoproj/argo-cd/v2
|
||||
|
||||
go 1.22.0
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
code.gitea.io/sdk/gitea v0.19.0
|
||||
@@ -10,7 +10,7 @@ require (
|
||||
github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d
|
||||
github.com/alicebob/miniredis/v2 v2.33.0
|
||||
github.com/antonmedv/expr v1.15.1
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20250304190342-43fce7ce19f1
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20250521000818-c08b0a72c1f1
|
||||
github.com/argoproj/notifications-engine v0.4.1-0.20241007194503-2fef5c9049fd
|
||||
github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1
|
||||
github.com/aws/aws-sdk-go v1.55.5
|
||||
@@ -22,14 +22,14 @@ require (
|
||||
github.com/cespare/xxhash/v2 v2.3.0
|
||||
github.com/chainguard-dev/git-urls v1.0.2
|
||||
github.com/coreos/go-oidc/v3 v3.11.0
|
||||
github.com/cyphar/filepath-securejoin v0.3.5
|
||||
github.com/cyphar/filepath-securejoin v0.3.6
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/evanphx/json-patch v5.9.0+incompatible
|
||||
github.com/expr-lang/expr v1.16.9
|
||||
github.com/expr-lang/expr v1.17.0
|
||||
github.com/felixge/httpsnoop v1.0.4
|
||||
github.com/fsnotify/fsnotify v1.8.0
|
||||
github.com/gfleury/go-bitbucket-v1 v0.0.0-20220301131131-8e7ed04b843e
|
||||
github.com/go-git/go-git/v5 v5.12.0
|
||||
github.com/go-git/go-git/v5 v5.13.2
|
||||
github.com/go-jose/go-jose/v3 v3.0.3
|
||||
github.com/go-logr/logr v1.4.2
|
||||
github.com/go-openapi/loads v0.22.0
|
||||
@@ -39,7 +39,7 @@ require (
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/gogits/go-gogs-client v0.0.0-20200905025246-8bb8a50cb355
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2
|
||||
github.com/golang/protobuf v1.5.4
|
||||
github.com/google/btree v1.1.3
|
||||
github.com/google/go-cmp v0.6.0
|
||||
@@ -68,7 +68,7 @@ require (
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
github.com/r3labs/diff v1.1.0
|
||||
github.com/redis/go-redis/v9 v9.7.1
|
||||
github.com/redis/go-redis/v9 v9.7.3
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c
|
||||
@@ -83,12 +83,12 @@ require (
|
||||
go.opentelemetry.io/otel v1.33.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0
|
||||
go.opentelemetry.io/otel/sdk v1.33.0
|
||||
golang.org/x/crypto v0.32.0
|
||||
golang.org/x/crypto v0.37.0
|
||||
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f
|
||||
golang.org/x/net v0.34.0
|
||||
golang.org/x/net v0.39.0
|
||||
golang.org/x/oauth2 v0.24.0
|
||||
golang.org/x/sync v0.10.0
|
||||
golang.org/x/term v0.28.0
|
||||
golang.org/x/sync v0.13.0
|
||||
golang.org/x/term v0.31.0
|
||||
golang.org/x/time v0.8.0
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28
|
||||
google.golang.org/grpc v1.68.1
|
||||
@@ -137,7 +137,7 @@ require (
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/go-fed/httpsig v1.1.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
@@ -151,8 +151,8 @@ require (
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
golang.org/x/tools v0.27.0 // indirect
|
||||
google.golang.org/api v0.171.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||
@@ -176,7 +176,7 @@ require (
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/PagerDuty/go-pagerduty v1.7.0 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.0.0 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.5 // indirect
|
||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 // indirect
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
@@ -198,7 +198,7 @@ require (
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.5.0 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/analysis v0.23.0 // indirect
|
||||
github.com/go-openapi/errors v0.22.0 // indirect
|
||||
@@ -249,7 +249,7 @@ require (
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.5 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_model v0.6.1
|
||||
@@ -260,7 +260,7 @@ require (
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/skeema/knownhosts v1.2.2 // indirect
|
||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||
github.com/slack-go/slack v0.12.2 // indirect
|
||||
github.com/spf13/cast v1.7.0 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
|
||||
83
go.sum
83
go.sum
@@ -61,8 +61,8 @@ github.com/OvyFlash/telegram-bot-api/v5 v5.0.0-20240108230938-63e5c59035bf h1:a7
|
||||
github.com/OvyFlash/telegram-bot-api/v5 v5.0.0-20240108230938-63e5c59035bf/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8=
|
||||
github.com/PagerDuty/go-pagerduty v1.7.0 h1:S1NcMKECxT5hJwV4VT+QzeSsSiv4oWl1s2821dUqG/8=
|
||||
github.com/PagerDuty/go-pagerduty v1.7.0/go.mod h1:PuFyJKRz1liIAH4h5KVXVD18Obpp1ZXRdxHvmGXooro=
|
||||
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
|
||||
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
|
||||
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 h1:prBTRx78AQnXzivNT9Crhu564W/zPPr3ibSlpT9xKcE=
|
||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60/go.mod h1:rjP7sIipbZcagro/6TCk6X0ZeFT2eyudH5+fve/cbBA=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
@@ -88,8 +88,8 @@ github.com/antonmedv/expr v1.15.1/go.mod h1:0E/6TxnOlRNp81GMzX9QfDPAmHo2Phg00y4J
|
||||
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.20250304190342-43fce7ce19f1 h1:3qG1uQNtjCIunZ5b3qmO1JS8OBLCssll41VwBYYlKio=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20250304190342-43fce7ce19f1/go.mod h1:WsnykM8idYRUnneeT31cM/Fq/ZsjkefCbjiD8ioCJkU=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20250521000818-c08b0a72c1f1 h1:Ze4U6kV49vSzlUBhH10HkO52bYKAIXS4tHr/MlNDfdU=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20250521000818-c08b0a72c1f1/go.mod h1:WsnykM8idYRUnneeT31cM/Fq/ZsjkefCbjiD8ioCJkU=
|
||||
github.com/argoproj/notifications-engine v0.4.1-0.20241007194503-2fef5c9049fd h1:lOVVoK89j9Nd4+JYJiKAaMNYC1402C0jICROOfUPWn0=
|
||||
github.com/argoproj/notifications-engine v0.4.1-0.20241007194503-2fef5c9049fd/go.mod h1:N0A4sEws2soZjEpY4hgZpQS8mRIEw6otzwfkgc3g9uQ=
|
||||
github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 h1:qsHwwOJ21K2Ao0xPju1sNuqphyMnMYkyB3ZLoLtxWpo=
|
||||
@@ -157,7 +157,6 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/casbin/casbin/v2 v2.102.0 h1:weq9iSThUSL21SH3VrwoKa2DgRsaYMfjRNX/yOU3Foo=
|
||||
@@ -189,7 +188,6 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
@@ -210,8 +208,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/cyphar/filepath-securejoin v0.3.5 h1:L81NHjquoQmcPgXcttUS9qTSR/+bXry6pbSINQGpjj4=
|
||||
github.com/cyphar/filepath-securejoin v0.3.5/go.mod h1:edhVd3c6OXKjUmSrVa/tGJRS9joFTxlslFCAyaxigkE=
|
||||
github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
|
||||
github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
@@ -235,8 +233,8 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM=
|
||||
github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ=
|
||||
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
@@ -253,8 +251,8 @@ github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0
|
||||
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
|
||||
github.com/expr-lang/expr v1.16.9 h1:WUAzmR0JNI9JCiF0/ewwHB1gmcGw5wW7nWt8gc6PpCI=
|
||||
github.com/expr-lang/expr v1.16.9/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
|
||||
github.com/expr-lang/expr v1.17.0 h1:+vpszOyzKLQXC9VF+wA8cVA0tlA984/Wabc/1hF9Whg=
|
||||
github.com/expr-lang/expr v1.17.0/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
|
||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
|
||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
|
||||
@@ -285,20 +283,20 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
|
||||
github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
|
||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
|
||||
github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
|
||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
|
||||
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
|
||||
github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0=
|
||||
github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
|
||||
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
||||
@@ -392,10 +390,10 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY=
|
||||
github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
@@ -766,8 +764,9 @@ github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJK
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY=
|
||||
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
|
||||
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
@@ -794,8 +793,8 @@ github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+v
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
|
||||
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
@@ -844,8 +843,8 @@ github.com/r3labs/diff v1.1.0 h1:V53xhrbTHrWFWq3gI4b94AjgEJOerO1+1l0xyHOBi8M=
|
||||
github.com/r3labs/diff v1.1.0/go.mod h1:7WjXasNzi0vJetRcB/RqNl5dlIsmXcTTLmF5IoH6Xig=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/redis/go-redis/v9 v9.0.0-rc.4/go.mod h1:Vo3EsyWnicKnSKCA7HhgnvnyA74wOA69Cd2Meli5mmA=
|
||||
github.com/redis/go-redis/v9 v9.7.1 h1:4LhKRCIduqXqtvCUlaq9c8bdHOkICjDMrr1+Zb3osAc=
|
||||
github.com/redis/go-redis/v9 v9.7.1/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
|
||||
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
||||
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
@@ -884,8 +883,8 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
|
||||
github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
|
||||
github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
|
||||
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
|
||||
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
|
||||
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c h1:fyKiXKO1/I/B6Y2U8T7WdQGWzwehOuGIrljPtt7YTTI=
|
||||
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||
github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ=
|
||||
@@ -1033,9 +1032,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
@@ -1049,8 +1046,8 @@ golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOM
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
|
||||
@@ -1135,8 +1132,8 @@ golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1160,8 +1157,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1231,8 +1228,8 @@ golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -1257,8 +1254,8 @@ golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -1277,8 +1274,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
declare -a services=("controller" "api-server" "redis" "repo-server" "ui")
|
||||
declare -a services=("controller" "api-server" "redis" "repo-server" "cmp-server" "ui" "applicationset-controller" "commit-server" "notification" "dex" "git-server" "helm-registry" "dev-mounter")
|
||||
|
||||
EXCLUDE=$exclude
|
||||
|
||||
|
||||
@@ -54,4 +54,4 @@ go install github.com/go-swagger/go-swagger/cmd/swagger@v0.28.0
|
||||
go install golang.org/x/tools/cmd/goimports@v0.1.8
|
||||
|
||||
# mockery is used to generate mock
|
||||
go install github.com/vektra/mockery/v2@v2.43.2
|
||||
go install github.com/vektra/mockery/v2@v2.53.4
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
set -eux -o pipefail
|
||||
|
||||
# renovate: datasource=go packageName=github.com/golangci/golangci-lint
|
||||
GOLANGCI_LINT_VERSION=1.62.2
|
||||
GOLANGCI_LINT_VERSION=2.1.6
|
||||
|
||||
GO111MODULE=on go install "github.com/golangci/golangci-lint/cmd/golangci-lint@v${GOLANGCI_LINT_VERSION}"
|
||||
|
||||
@@ -35,6 +35,10 @@ cd ${SRCROOT}/manifests/base && $KUSTOMIZE edit set image quay.io/argoproj/argoc
|
||||
cd ${SRCROOT}/manifests/ha/base && $KUSTOMIZE edit set image quay.io/argoproj/argocd=${IMAGE_NAMESPACE}/argocd:${IMAGE_TAG}
|
||||
cd ${SRCROOT}/manifests/core-install && $KUSTOMIZE edit set image quay.io/argoproj/argocd=${IMAGE_NAMESPACE}/argocd:${IMAGE_TAG}
|
||||
|
||||
# Because commit-server is added as a resource outside the base, we have to explicitly set the image override here.
|
||||
# If/when commit-server is added to the base, this can be removed.
|
||||
cd ${SRCROOT}/manifests/base/commit-server && $KUSTOMIZE edit set image quay.io/argoproj/argocd=${IMAGE_NAMESPACE}/argocd:${IMAGE_TAG}
|
||||
|
||||
echo "${AUTOGENMSG}" > "${SRCROOT}/manifests/install.yaml"
|
||||
$KUSTOMIZE build "${SRCROOT}/manifests/cluster-install" >> "${SRCROOT}/manifests/install.yaml"
|
||||
|
||||
|
||||
@@ -115,6 +115,12 @@ spec:
|
||||
name: argocd-cmd-params-cm
|
||||
key: controller.self.heal.backoff.cap.seconds
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_COOLDOWN_SECONDS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: argocd-cmd-params-cm
|
||||
key: controller.self.heal.backoff.cooldown.seconds
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SYNC_TIMEOUT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@@ -241,6 +247,12 @@ spec:
|
||||
name: argocd-cmd-params-cm
|
||||
key: controller.cluster.cache.events.processing.interval
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: argocd-cmd-params-cm
|
||||
key: commit.server
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
|
||||
@@ -118,6 +118,12 @@ spec:
|
||||
name: argocd-cmd-params-cm
|
||||
key: controller.self.heal.backoff.cap.seconds
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_COOLDOWN_SECONDS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: argocd-cmd-params-cm
|
||||
key: controller.self.heal.backoff.cooldown.seconds
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SYNC_TIMEOUT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@@ -250,6 +256,12 @@ spec:
|
||||
name: argocd-cmd-params-cm
|
||||
key: controller.cluster.cache.events.processing.interval
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: argocd-cmd-params-cm
|
||||
key: commit.server
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
|
||||
@@ -175,6 +175,12 @@ spec:
|
||||
name: argocd-cmd-params-cm
|
||||
key: applicationsetcontroller.requeue.after
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_MAX_RESOURCES_STATUS_COUNT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: argocd-cmd-params-cm
|
||||
key: applicationsetcontroller.status.max.resources.count
|
||||
optional: true
|
||||
volumeMounts:
|
||||
- mountPath: /app/config/ssh
|
||||
name: ssh-known-hosts
|
||||
|
||||
@@ -6,3 +6,10 @@ resources:
|
||||
- argocd-commit-server-deployment.yaml
|
||||
- argocd-commit-server-service.yaml
|
||||
- argocd-commit-server-network-policy.yaml
|
||||
|
||||
# Because commit-server is added as a resource outside the base, we have to explicitly set the image override here.
|
||||
# If/when commit-server is added to the base, this can be removed.
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.14.21
|
||||
|
||||
@@ -5,7 +5,7 @@ kind: Kustomization
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.14.5
|
||||
newTag: v2.14.21
|
||||
resources:
|
||||
- ./application-controller
|
||||
- ./dex
|
||||
|
||||
@@ -40,7 +40,7 @@ spec:
|
||||
serviceAccountName: argocd-redis
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7.0.15-alpine
|
||||
image: redis:7.2.11-alpine
|
||||
imagePullPolicy: Always
|
||||
args:
|
||||
- "--save"
|
||||
|
||||
@@ -24165,7 +24165,13 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_MAX_RESOURCES_STATUS_COUNT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.status.max.resources.count
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -24285,7 +24291,7 @@ spec:
|
||||
key: commitserver.log.level
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -24331,7 +24337,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.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -24419,7 +24425,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: redis:7.0.15-alpine
|
||||
image: redis:7.2.11-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -24435,7 +24441,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -24696,7 +24702,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -24748,7 +24754,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -24932,6 +24938,12 @@ spec:
|
||||
key: controller.self.heal.backoff.cap.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_COOLDOWN_SECONDS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: controller.self.heal.backoff.cooldown.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SYNC_TIMEOUT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@@ -25064,9 +25076,15 @@ spec:
|
||||
key: controller.cluster.cache.events.processing.interval
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: commit.server
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
30
manifests/core-install.yaml
generated
30
manifests/core-install.yaml
generated
@@ -24133,7 +24133,13 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_MAX_RESOURCES_STATUS_COUNT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.status.max.resources.count
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -24237,7 +24243,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: redis:7.0.15-alpine
|
||||
image: redis:7.2.11-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -24253,7 +24259,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -24514,7 +24520,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -24566,7 +24572,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -24750,6 +24756,12 @@ spec:
|
||||
key: controller.self.heal.backoff.cap.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_COOLDOWN_SECONDS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: controller.self.heal.backoff.cooldown.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SYNC_TIMEOUT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@@ -24882,9 +24894,15 @@ spec:
|
||||
key: controller.cluster.cache.events.processing.interval
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: commit.server
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -12,4 +12,4 @@ resources:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.14.5
|
||||
newTag: v2.14.21
|
||||
|
||||
@@ -12,7 +12,7 @@ patches:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.14.5
|
||||
newTag: v2.14.21
|
||||
resources:
|
||||
- ../../base/application-controller
|
||||
- ../../base/applicationset-controller
|
||||
|
||||
@@ -1219,7 +1219,7 @@ spec:
|
||||
automountServiceAccountToken: false
|
||||
initContainers:
|
||||
- name: config-init
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
{}
|
||||
@@ -1258,7 +1258,7 @@ spec:
|
||||
|
||||
containers:
|
||||
- name: redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- redis-server
|
||||
@@ -1321,7 +1321,7 @@ spec:
|
||||
- /bin/sh
|
||||
- /readonly-config/trigger-failover-if-master.sh
|
||||
- name: sentinel
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- redis-sentinel
|
||||
@@ -1383,7 +1383,7 @@ spec:
|
||||
- sleep 30; redis-cli -p 26379 sentinel reset argocd
|
||||
|
||||
- name: split-brain-fix
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- sh
|
||||
|
||||
@@ -23,7 +23,7 @@ redis-ha:
|
||||
metrics:
|
||||
enabled: true
|
||||
image:
|
||||
tag: 7.0.15-alpine
|
||||
tag: 7.2.11-alpine
|
||||
containerSecurityContext: null
|
||||
sentinel:
|
||||
bind: '0.0.0.0'
|
||||
|
||||
@@ -25506,7 +25506,13 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_MAX_RESOURCES_STATUS_COUNT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.status.max.resources.count
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -25626,7 +25632,7 @@ spec:
|
||||
key: commitserver.log.level
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -25672,7 +25678,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.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -25793,7 +25799,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -25883,7 +25889,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -26004,7 +26010,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -26291,7 +26297,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -26343,7 +26349,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -26705,7 +26711,7 @@ spec:
|
||||
key: hydrator.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -26925,6 +26931,12 @@ spec:
|
||||
key: controller.self.heal.backoff.cap.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_COOLDOWN_SECONDS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: controller.self.heal.backoff.cooldown.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SYNC_TIMEOUT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@@ -27057,9 +27069,15 @@ spec:
|
||||
key: controller.cluster.cache.events.processing.interval
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: commit.server
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
@@ -27157,7 +27175,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
preStop:
|
||||
@@ -27217,7 +27235,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
postStart:
|
||||
@@ -27281,7 +27299,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: split-brain-fix
|
||||
resources: {}
|
||||
@@ -27316,7 +27334,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
|
||||
42
manifests/ha/install.yaml
generated
42
manifests/ha/install.yaml
generated
@@ -25476,7 +25476,13 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_MAX_RESOURCES_STATUS_COUNT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.status.max.resources.count
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -25613,7 +25619,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -25703,7 +25709,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -25824,7 +25830,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -26111,7 +26117,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -26163,7 +26169,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -26525,7 +26531,7 @@ spec:
|
||||
key: hydrator.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -26745,6 +26751,12 @@ spec:
|
||||
key: controller.self.heal.backoff.cap.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_COOLDOWN_SECONDS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: controller.self.heal.backoff.cooldown.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SYNC_TIMEOUT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@@ -26877,9 +26889,15 @@ spec:
|
||||
key: controller.cluster.cache.events.processing.interval
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: commit.server
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
@@ -26977,7 +26995,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
preStop:
|
||||
@@ -27037,7 +27055,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
postStart:
|
||||
@@ -27101,7 +27119,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: split-brain-fix
|
||||
resources: {}
|
||||
@@ -27136,7 +27154,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
|
||||
@@ -1736,7 +1736,13 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_MAX_RESOURCES_STATUS_COUNT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.status.max.resources.count
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -1856,7 +1862,7 @@ spec:
|
||||
key: commitserver.log.level
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1902,7 +1908,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.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -2023,7 +2029,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -2113,7 +2119,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -2234,7 +2240,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -2521,7 +2527,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -2573,7 +2579,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -2935,7 +2941,7 @@ spec:
|
||||
key: hydrator.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -3155,6 +3161,12 @@ spec:
|
||||
key: controller.self.heal.backoff.cap.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_COOLDOWN_SECONDS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: controller.self.heal.backoff.cooldown.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SYNC_TIMEOUT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@@ -3287,9 +3299,15 @@ spec:
|
||||
key: controller.cluster.cache.events.processing.interval
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: commit.server
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
@@ -3387,7 +3405,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
preStop:
|
||||
@@ -3447,7 +3465,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
postStart:
|
||||
@@ -3511,7 +3529,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: split-brain-fix
|
||||
resources: {}
|
||||
@@ -3546,7 +3564,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
|
||||
42
manifests/ha/namespace-install.yaml
generated
42
manifests/ha/namespace-install.yaml
generated
@@ -1706,7 +1706,13 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_MAX_RESOURCES_STATUS_COUNT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.status.max.resources.count
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -1843,7 +1849,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -1933,7 +1939,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -2054,7 +2060,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -2341,7 +2347,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -2393,7 +2399,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -2755,7 +2761,7 @@ spec:
|
||||
key: hydrator.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2975,6 +2981,12 @@ spec:
|
||||
key: controller.self.heal.backoff.cap.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_COOLDOWN_SECONDS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: controller.self.heal.backoff.cooldown.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SYNC_TIMEOUT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@@ -3107,9 +3119,15 @@ spec:
|
||||
key: controller.cluster.cache.events.processing.interval
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: commit.server
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
@@ -3207,7 +3225,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
preStop:
|
||||
@@ -3267,7 +3285,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
postStart:
|
||||
@@ -3331,7 +3349,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: split-brain-fix
|
||||
resources: {}
|
||||
@@ -3366,7 +3384,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
|
||||
image: public.ecr.aws/docker/library/redis:7.2.11-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
|
||||
@@ -24625,7 +24625,13 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_MAX_RESOURCES_STATUS_COUNT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.status.max.resources.count
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -24745,7 +24751,7 @@ spec:
|
||||
key: commitserver.log.level
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -24791,7 +24797,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.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -24912,7 +24918,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -25002,7 +25008,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -25088,7 +25094,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: redis:7.0.15-alpine
|
||||
image: redis:7.2.11-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -25104,7 +25110,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -25365,7 +25371,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -25417,7 +25423,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -25777,7 +25783,7 @@ spec:
|
||||
key: hydrator.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -25997,6 +26003,12 @@ spec:
|
||||
key: controller.self.heal.backoff.cap.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_COOLDOWN_SECONDS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: controller.self.heal.backoff.cooldown.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SYNC_TIMEOUT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@@ -26129,9 +26141,15 @@ spec:
|
||||
key: controller.cluster.cache.events.processing.interval
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: commit.server
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
36
manifests/install.yaml
generated
36
manifests/install.yaml
generated
@@ -24593,7 +24593,13 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_MAX_RESOURCES_STATUS_COUNT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.status.max.resources.count
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -24730,7 +24736,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -24820,7 +24826,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -24906,7 +24912,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: redis:7.0.15-alpine
|
||||
image: redis:7.2.11-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -24922,7 +24928,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -25183,7 +25189,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -25235,7 +25241,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -25595,7 +25601,7 @@ spec:
|
||||
key: hydrator.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -25815,6 +25821,12 @@ spec:
|
||||
key: controller.self.heal.backoff.cap.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_COOLDOWN_SECONDS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: controller.self.heal.backoff.cooldown.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SYNC_TIMEOUT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@@ -25947,9 +25959,15 @@ spec:
|
||||
key: controller.cluster.cache.events.processing.interval
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: commit.server
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -855,7 +855,13 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_MAX_RESOURCES_STATUS_COUNT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.status.max.resources.count
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -975,7 +981,7 @@ spec:
|
||||
key: commitserver.log.level
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1021,7 +1027,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.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -1142,7 +1148,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -1232,7 +1238,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -1318,7 +1324,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: redis:7.0.15-alpine
|
||||
image: redis:7.2.11-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -1334,7 +1340,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -1595,7 +1601,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1647,7 +1653,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -2007,7 +2013,7 @@ spec:
|
||||
key: hydrator.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2227,6 +2233,12 @@ spec:
|
||||
key: controller.self.heal.backoff.cap.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_COOLDOWN_SECONDS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: controller.self.heal.backoff.cooldown.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SYNC_TIMEOUT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@@ -2359,9 +2371,15 @@ spec:
|
||||
key: controller.cluster.cache.events.processing.interval
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: commit.server
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
36
manifests/namespace-install.yaml
generated
36
manifests/namespace-install.yaml
generated
@@ -823,7 +823,13 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_MAX_RESOURCES_STATUS_COUNT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: applicationsetcontroller.status.max.resources.count
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -960,7 +966,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -1050,7 +1056,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -1136,7 +1142,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: redis:7.0.15-alpine
|
||||
image: redis:7.2.11-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -1152,7 +1158,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -1413,7 +1419,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1465,7 +1471,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -1825,7 +1831,7 @@ spec:
|
||||
key: hydrator.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2045,6 +2051,12 @@ spec:
|
||||
key: controller.self.heal.backoff.cap.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_BACKOFF_COOLDOWN_SECONDS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: controller.self.heal.backoff.cooldown.seconds
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_SYNC_TIMEOUT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
@@ -2177,9 +2189,15 @@ spec:
|
||||
key: controller.cluster.cache.events.processing.interval
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: commit.server
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v2.14.5
|
||||
image: quay.io/argoproj/argocd:v2.14.21
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -290,7 +290,6 @@ func (m *Repository) Sanitized() *Repository {
|
||||
Repo: m.Repo,
|
||||
Type: m.Type,
|
||||
Name: m.Name,
|
||||
Username: m.Username,
|
||||
Insecure: m.IsInsecure(),
|
||||
EnableLFS: m.EnableLFS,
|
||||
EnableOCI: m.EnableOCI,
|
||||
|
||||
@@ -2,6 +2,7 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"math"
|
||||
@@ -25,7 +26,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -38,6 +39,8 @@ import (
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/util/rbac"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
"github.com/argoproj/argo-cd/v2/util/env"
|
||||
"github.com/argoproj/argo-cd/v2/util/helm"
|
||||
@@ -166,9 +169,8 @@ func (e Env) Envsubst(s string) string {
|
||||
// allow escaping $ with $$
|
||||
if s == "$" {
|
||||
return "$"
|
||||
} else {
|
||||
return valByEnv[s]
|
||||
}
|
||||
return valByEnv[s]
|
||||
})
|
||||
}
|
||||
|
||||
@@ -201,12 +203,12 @@ type ApplicationSource struct {
|
||||
// ApplicationSources contains list of required information about the sources of an application
|
||||
type ApplicationSources []ApplicationSource
|
||||
|
||||
func (s ApplicationSources) Equals(other ApplicationSources) bool {
|
||||
if len(s) != len(other) {
|
||||
func (a ApplicationSources) Equals(other ApplicationSources) bool {
|
||||
if len(a) != len(other) {
|
||||
return false
|
||||
}
|
||||
for i := range s {
|
||||
if !s[i].Equals(&other[i]) {
|
||||
for i := range a {
|
||||
if !a[i].Equals(&other[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -218,154 +220,153 @@ func (a ApplicationSources) IsZero() bool {
|
||||
return len(a) == 0
|
||||
}
|
||||
|
||||
func (a *ApplicationSpec) GetSource() ApplicationSource {
|
||||
if a.SourceHydrator != nil {
|
||||
return a.SourceHydrator.GetSyncSource()
|
||||
func (spec *ApplicationSpec) GetSource() ApplicationSource {
|
||||
if spec.SourceHydrator != nil {
|
||||
return spec.SourceHydrator.GetSyncSource()
|
||||
}
|
||||
// if Application has multiple sources, return the first source in sources
|
||||
if a.HasMultipleSources() {
|
||||
return a.Sources[0]
|
||||
if spec.HasMultipleSources() {
|
||||
return spec.Sources[0]
|
||||
}
|
||||
if a.Source != nil {
|
||||
return *a.Source
|
||||
if spec.Source != nil {
|
||||
return *spec.Source
|
||||
}
|
||||
return ApplicationSource{}
|
||||
}
|
||||
|
||||
// GetHydrateToSource returns the hydrateTo source if it exists, otherwise returns the sync source.
|
||||
func (a *ApplicationSpec) GetHydrateToSource() ApplicationSource {
|
||||
if a.SourceHydrator != nil {
|
||||
targetRevision := a.SourceHydrator.SyncSource.TargetBranch
|
||||
if a.SourceHydrator.HydrateTo != nil {
|
||||
targetRevision = a.SourceHydrator.HydrateTo.TargetBranch
|
||||
func (spec *ApplicationSpec) GetHydrateToSource() ApplicationSource {
|
||||
if spec.SourceHydrator != nil {
|
||||
targetRevision := spec.SourceHydrator.SyncSource.TargetBranch
|
||||
if spec.SourceHydrator.HydrateTo != nil {
|
||||
targetRevision = spec.SourceHydrator.HydrateTo.TargetBranch
|
||||
}
|
||||
return ApplicationSource{
|
||||
RepoURL: a.SourceHydrator.DrySource.RepoURL,
|
||||
Path: a.SourceHydrator.SyncSource.Path,
|
||||
RepoURL: spec.SourceHydrator.DrySource.RepoURL,
|
||||
Path: spec.SourceHydrator.SyncSource.Path,
|
||||
TargetRevision: targetRevision,
|
||||
}
|
||||
}
|
||||
return ApplicationSource{}
|
||||
}
|
||||
|
||||
func (a *ApplicationSpec) GetSources() ApplicationSources {
|
||||
if a.SourceHydrator != nil {
|
||||
return ApplicationSources{a.SourceHydrator.GetSyncSource()}
|
||||
func (spec *ApplicationSpec) GetSources() ApplicationSources {
|
||||
if spec.SourceHydrator != nil {
|
||||
return ApplicationSources{spec.SourceHydrator.GetSyncSource()}
|
||||
}
|
||||
if a.HasMultipleSources() {
|
||||
return a.Sources
|
||||
if spec.HasMultipleSources() {
|
||||
return spec.Sources
|
||||
}
|
||||
if a.Source != nil {
|
||||
return ApplicationSources{*a.Source}
|
||||
if spec.Source != nil {
|
||||
return ApplicationSources{*spec.Source}
|
||||
}
|
||||
return ApplicationSources{}
|
||||
}
|
||||
|
||||
func (a *ApplicationSpec) HasMultipleSources() bool {
|
||||
return a.SourceHydrator == nil && len(a.Sources) > 0
|
||||
func (spec *ApplicationSpec) HasMultipleSources() bool {
|
||||
return spec.SourceHydrator == nil && len(spec.Sources) > 0
|
||||
}
|
||||
|
||||
func (a *ApplicationSpec) GetSourcePtrByPosition(sourcePosition int) *ApplicationSource {
|
||||
func (spec *ApplicationSpec) GetSourcePtrByPosition(sourcePosition int) *ApplicationSource {
|
||||
// if Application has multiple sources, return the first source in sources
|
||||
return a.GetSourcePtrByIndex(sourcePosition - 1)
|
||||
return spec.GetSourcePtrByIndex(sourcePosition - 1)
|
||||
}
|
||||
|
||||
func (a *ApplicationSpec) GetSourcePtrByIndex(sourceIndex int) *ApplicationSource {
|
||||
if a.SourceHydrator != nil {
|
||||
source := a.SourceHydrator.GetSyncSource()
|
||||
func (spec *ApplicationSpec) GetSourcePtrByIndex(sourceIndex int) *ApplicationSource {
|
||||
if spec.SourceHydrator != nil {
|
||||
source := spec.SourceHydrator.GetSyncSource()
|
||||
return &source
|
||||
}
|
||||
// if Application has multiple sources, return the first source in sources
|
||||
if a.HasMultipleSources() {
|
||||
if spec.HasMultipleSources() {
|
||||
if sourceIndex > 0 {
|
||||
return &a.Sources[sourceIndex]
|
||||
return &spec.Sources[sourceIndex]
|
||||
}
|
||||
return &a.Sources[0]
|
||||
return &spec.Sources[0]
|
||||
}
|
||||
return a.Source
|
||||
return spec.Source
|
||||
}
|
||||
|
||||
// AllowsConcurrentProcessing returns true if given application source can be processed concurrently
|
||||
func (a *ApplicationSource) AllowsConcurrentProcessing() bool {
|
||||
switch {
|
||||
func (source *ApplicationSource) AllowsConcurrentProcessing() bool {
|
||||
// Kustomize with parameters requires changing kustomization.yaml file
|
||||
case a.Kustomize != nil:
|
||||
return a.Kustomize.AllowsConcurrentProcessing()
|
||||
if source.Kustomize != nil {
|
||||
return source.Kustomize.AllowsConcurrentProcessing()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRef returns true when the application source is of type Ref
|
||||
func (a *ApplicationSource) IsRef() bool {
|
||||
return a.Ref != ""
|
||||
func (source *ApplicationSource) IsRef() bool {
|
||||
return source.Ref != ""
|
||||
}
|
||||
|
||||
// IsHelm returns true when the application source is of type Helm
|
||||
func (a *ApplicationSource) IsHelm() bool {
|
||||
return a.Chart != ""
|
||||
func (source *ApplicationSource) IsHelm() bool {
|
||||
return source.Chart != ""
|
||||
}
|
||||
|
||||
// IsHelmOci returns true when the application source is of type Helm OCI
|
||||
func (a *ApplicationSource) IsHelmOci() bool {
|
||||
if a.Chart == "" {
|
||||
func (source *ApplicationSource) IsHelmOci() bool {
|
||||
if source.Chart == "" {
|
||||
return false
|
||||
}
|
||||
return helm.IsHelmOciRepo(a.RepoURL)
|
||||
return helm.IsHelmOciRepo(source.RepoURL)
|
||||
}
|
||||
|
||||
// IsZero returns true if the application source is considered empty
|
||||
func (a *ApplicationSource) IsZero() bool {
|
||||
return a == nil ||
|
||||
a.RepoURL == "" &&
|
||||
a.Path == "" &&
|
||||
a.TargetRevision == "" &&
|
||||
a.Helm.IsZero() &&
|
||||
a.Kustomize.IsZero() &&
|
||||
a.Directory.IsZero() &&
|
||||
a.Plugin.IsZero()
|
||||
func (source *ApplicationSource) IsZero() bool {
|
||||
return source == nil ||
|
||||
source.RepoURL == "" &&
|
||||
source.Path == "" &&
|
||||
source.TargetRevision == "" &&
|
||||
source.Helm.IsZero() &&
|
||||
source.Kustomize.IsZero() &&
|
||||
source.Directory.IsZero() &&
|
||||
source.Plugin.IsZero()
|
||||
}
|
||||
|
||||
// GetNamespaceOrDefault gets the static namespace configured in the source. If none is configured, returns the given
|
||||
// default.
|
||||
func (a *ApplicationSource) GetNamespaceOrDefault(defaultNamespace string) string {
|
||||
if a == nil {
|
||||
func (source *ApplicationSource) GetNamespaceOrDefault(defaultNamespace string) string {
|
||||
if source == nil {
|
||||
return defaultNamespace
|
||||
}
|
||||
if a.Helm != nil && a.Helm.Namespace != "" {
|
||||
return a.Helm.Namespace
|
||||
if source.Helm != nil && source.Helm.Namespace != "" {
|
||||
return source.Helm.Namespace
|
||||
}
|
||||
if a.Kustomize != nil && a.Kustomize.Namespace != "" {
|
||||
return a.Kustomize.Namespace
|
||||
if source.Kustomize != nil && source.Kustomize.Namespace != "" {
|
||||
return source.Kustomize.Namespace
|
||||
}
|
||||
return defaultNamespace
|
||||
}
|
||||
|
||||
// GetKubeVersionOrDefault gets the static Kubernetes API version configured in the source. If none is configured,
|
||||
// returns the given default.
|
||||
func (a *ApplicationSource) GetKubeVersionOrDefault(defaultKubeVersion string) string {
|
||||
if a == nil {
|
||||
func (source *ApplicationSource) GetKubeVersionOrDefault(defaultKubeVersion string) string {
|
||||
if source == nil {
|
||||
return defaultKubeVersion
|
||||
}
|
||||
if a.Helm != nil && a.Helm.KubeVersion != "" {
|
||||
return a.Helm.KubeVersion
|
||||
if source.Helm != nil && source.Helm.KubeVersion != "" {
|
||||
return source.Helm.KubeVersion
|
||||
}
|
||||
if a.Kustomize != nil && a.Kustomize.KubeVersion != "" {
|
||||
return a.Kustomize.KubeVersion
|
||||
if source.Kustomize != nil && source.Kustomize.KubeVersion != "" {
|
||||
return source.Kustomize.KubeVersion
|
||||
}
|
||||
return defaultKubeVersion
|
||||
}
|
||||
|
||||
// GetAPIVersionsOrDefault gets the static API versions list configured in the source. If none is configured, returns
|
||||
// the given default.
|
||||
func (a *ApplicationSource) GetAPIVersionsOrDefault(defaultAPIVersions []string) []string {
|
||||
if a == nil {
|
||||
func (source *ApplicationSource) GetAPIVersionsOrDefault(defaultAPIVersions []string) []string {
|
||||
if source == nil {
|
||||
return defaultAPIVersions
|
||||
}
|
||||
if a.Helm != nil && len(a.Helm.APIVersions) > 0 {
|
||||
return a.Helm.APIVersions
|
||||
if source.Helm != nil && len(source.Helm.APIVersions) > 0 {
|
||||
return source.Helm.APIVersions
|
||||
}
|
||||
if a.Kustomize != nil && len(a.Kustomize.APIVersions) > 0 {
|
||||
return a.Kustomize.APIVersions
|
||||
if source.Kustomize != nil && len(source.Kustomize.APIVersions) > 0 {
|
||||
return source.Kustomize.APIVersions
|
||||
}
|
||||
return defaultAPIVersions
|
||||
}
|
||||
@@ -564,39 +565,39 @@ func NewHelmFileParameter(text string) (*HelmFileParameter, error) {
|
||||
|
||||
// AddParameter adds a HelmParameter to the application source. If a parameter with the same name already
|
||||
// exists, its value will be overwritten. Otherwise, the HelmParameter will be appended as a new entry.
|
||||
func (in *ApplicationSourceHelm) AddParameter(p HelmParameter) {
|
||||
func (ash *ApplicationSourceHelm) AddParameter(p HelmParameter) {
|
||||
found := false
|
||||
for i, cp := range in.Parameters {
|
||||
for i, cp := range ash.Parameters {
|
||||
if cp.Name == p.Name {
|
||||
found = true
|
||||
in.Parameters[i] = p
|
||||
ash.Parameters[i] = p
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
in.Parameters = append(in.Parameters, p)
|
||||
ash.Parameters = append(ash.Parameters, p)
|
||||
}
|
||||
}
|
||||
|
||||
// AddFileParameter adds a HelmFileParameter to the application source. If a file parameter with the same name already
|
||||
// exists, its value will be overwritten. Otherwise, the HelmFileParameter will be appended as a new entry.
|
||||
func (in *ApplicationSourceHelm) AddFileParameter(p HelmFileParameter) {
|
||||
func (ash *ApplicationSourceHelm) AddFileParameter(p HelmFileParameter) {
|
||||
found := false
|
||||
for i, cp := range in.FileParameters {
|
||||
for i, cp := range ash.FileParameters {
|
||||
if cp.Name == p.Name {
|
||||
found = true
|
||||
in.FileParameters[i] = p
|
||||
ash.FileParameters[i] = p
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
in.FileParameters = append(in.FileParameters, p)
|
||||
ash.FileParameters = append(ash.FileParameters, p)
|
||||
}
|
||||
}
|
||||
|
||||
// IsZero Returns true if the Helm options in an application source are considered zero
|
||||
func (h *ApplicationSourceHelm) IsZero() bool {
|
||||
return h == nil || (h.Version == "") && (h.ReleaseName == "") && len(h.ValueFiles) == 0 && len(h.Parameters) == 0 && len(h.FileParameters) == 0 && h.ValuesIsEmpty() && !h.PassCredentials && !h.IgnoreMissingValueFiles && !h.SkipCrds && !h.SkipTests && !h.SkipSchemaValidation && h.KubeVersion == "" && len(h.APIVersions) == 0 && h.Namespace == ""
|
||||
func (ash *ApplicationSourceHelm) IsZero() bool {
|
||||
return ash == nil || (ash.Version == "") && (ash.ReleaseName == "") && len(ash.ValueFiles) == 0 && len(ash.Parameters) == 0 && len(ash.FileParameters) == 0 && ash.ValuesIsEmpty() && !ash.PassCredentials && !ash.IgnoreMissingValueFiles && !ash.SkipCrds && !ash.SkipTests && !ash.SkipSchemaValidation && ash.KubeVersion == "" && len(ash.APIVersions) == 0 && ash.Namespace == ""
|
||||
}
|
||||
|
||||
// KustomizeImage represents a Kustomize image definition in the format [old_image_name=]<image_name>:<image_tag>
|
||||
@@ -684,14 +685,13 @@ type KustomizeReplicas []KustomizeReplica
|
||||
// If parsing error occurs, returns 0 and error.
|
||||
func (kr KustomizeReplica) GetIntCount() (int, error) {
|
||||
if kr.Count.Type == intstr.String {
|
||||
if count, err := strconv.Atoi(kr.Count.StrVal); err != nil {
|
||||
count, err := strconv.Atoi(kr.Count.StrVal)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("expected integer value for count. Received: %s", kr.Count.StrVal)
|
||||
} else {
|
||||
return count, nil
|
||||
}
|
||||
} else {
|
||||
return kr.Count.IntValue(), nil
|
||||
return count, nil
|
||||
}
|
||||
return kr.Count.IntValue(), nil
|
||||
}
|
||||
|
||||
// NewKustomizeReplica parses a string in format name=count into a KustomizeReplica object and returns it
|
||||
@@ -821,9 +821,8 @@ func NewJsonnetVar(s string, code bool) JsonnetVar {
|
||||
parts := strings.SplitN(s, "=", 2)
|
||||
if len(parts) == 2 {
|
||||
return JsonnetVar{Name: parts[0], Value: parts[1], Code: code}
|
||||
} else {
|
||||
return JsonnetVar{Name: s, Code: code}
|
||||
}
|
||||
return JsonnetVar{Name: s, Code: code}
|
||||
}
|
||||
|
||||
// ApplicationSourceJsonnet holds options specific to applications of type Jsonnet
|
||||
@@ -935,7 +934,7 @@ type ApplicationSourcePluginParameter struct {
|
||||
// Name is the name identifying a parameter.
|
||||
Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"`
|
||||
// String_ is the value of a string type parameter.
|
||||
String_ *string `json:"string,omitempty" protobuf:"bytes,5,opt,name=string"`
|
||||
String_ *string `json:"string,omitempty" protobuf:"bytes,5,opt,name=string"` //nolint:revive //FIXME(var-naming)
|
||||
// Map is the value of a map type parameter.
|
||||
*OptionalMap `json:",omitempty" protobuf:"bytes,3,rep,name=map"`
|
||||
// Array is the value of an array type parameter.
|
||||
@@ -959,7 +958,7 @@ func (p ApplicationSourcePluginParameter) Equals(other ApplicationSourcePluginPa
|
||||
//
|
||||
// There are efforts to change things upstream, but nothing has been merged yet. See https://github.com/golang/go/issues/37711
|
||||
func (p ApplicationSourcePluginParameter) MarshalJSON() ([]byte, error) {
|
||||
out := map[string]interface{}{}
|
||||
out := map[string]any{}
|
||||
out["name"] = p.Name
|
||||
if p.String_ != nil {
|
||||
out["string"] = p.String_
|
||||
@@ -1016,12 +1015,12 @@ func (p ApplicationSourcePluginParameters) Environ() ([]string, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal plugin parameters: %w", err)
|
||||
}
|
||||
jsonParam := fmt.Sprintf("ARGOCD_APP_PARAMETERS=%s", string(out))
|
||||
jsonParam := "ARGOCD_APP_PARAMETERS=" + string(out)
|
||||
|
||||
env := []string{jsonParam}
|
||||
|
||||
for _, param := range p {
|
||||
envBaseName := fmt.Sprintf("PARAM_%s", escaped(param.Name))
|
||||
envBaseName := "PARAM_" + escaped(param.Name)
|
||||
if param.String_ != nil {
|
||||
env = append(env, fmt.Sprintf("%s=%s", envBaseName, *param.String_))
|
||||
}
|
||||
@@ -1175,9 +1174,9 @@ type SourceHydratorStatus struct {
|
||||
CurrentOperation *HydrateOperation `json:"currentOperation,omitempty" protobuf:"bytes,2,opt,name=currentOperation"`
|
||||
}
|
||||
|
||||
func (a *ApplicationStatus) FindResource(key kube.ResourceKey) (*ResourceStatus, bool) {
|
||||
for i := range a.Resources {
|
||||
res := a.Resources[i]
|
||||
func (status *ApplicationStatus) FindResource(key kube.ResourceKey) (*ResourceStatus, bool) {
|
||||
for i := range status.Resources {
|
||||
res := status.Resources[i]
|
||||
if kube.NewResourceKey(res.Group, res.Kind, res.Namespace, res.Name) == key {
|
||||
return &res, true
|
||||
}
|
||||
@@ -1227,12 +1226,12 @@ const (
|
||||
// If app has multisources, it will return all corresponding revisions preserving
|
||||
// order from the app.spec.sources. If app has only one source, it will return a
|
||||
// single revision in the list.
|
||||
func (a *ApplicationStatus) GetRevisions() []string {
|
||||
func (status *ApplicationStatus) GetRevisions() []string {
|
||||
revisions := []string{}
|
||||
if len(a.Sync.Revisions) > 0 {
|
||||
revisions = a.Sync.Revisions
|
||||
} else if a.Sync.Revision != "" {
|
||||
revisions = append(revisions, a.Sync.Revision)
|
||||
if len(status.Sync.Revisions) > 0 {
|
||||
revisions = status.Sync.Revisions
|
||||
} else if status.Sync.Revision != "" {
|
||||
revisions = append(revisions, status.Sync.Revision)
|
||||
}
|
||||
return revisions
|
||||
}
|
||||
@@ -1528,15 +1527,15 @@ type SyncStrategy struct {
|
||||
|
||||
// Force returns true if the sync strategy specifies to perform a forced sync
|
||||
func (m *SyncStrategy) Force() bool {
|
||||
if m == nil {
|
||||
switch {
|
||||
case m == nil:
|
||||
return false
|
||||
} else if m.Apply != nil {
|
||||
case m.Apply != nil:
|
||||
return m.Apply.Force
|
||||
} else if m.Hook != nil {
|
||||
case m.Hook != nil:
|
||||
return m.Hook.Force
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SyncStrategyApply uses `kubectl apply` to perform the apply
|
||||
@@ -1796,29 +1795,29 @@ type InfoItem struct {
|
||||
// ResourceNetworkingInfo holds networking resource related information
|
||||
// TODO: describe members of this type
|
||||
type ResourceNetworkingInfo struct {
|
||||
TargetLabels map[string]string `json:"targetLabels,omitempty" protobuf:"bytes,1,opt,name=targetLabels"`
|
||||
TargetRefs []ResourceRef `json:"targetRefs,omitempty" protobuf:"bytes,2,opt,name=targetRefs"`
|
||||
Labels map[string]string `json:"labels,omitempty" protobuf:"bytes,3,opt,name=labels"`
|
||||
Ingress []v1.LoadBalancerIngress `json:"ingress,omitempty" protobuf:"bytes,4,opt,name=ingress"`
|
||||
TargetLabels map[string]string `json:"targetLabels,omitempty" protobuf:"bytes,1,opt,name=targetLabels"`
|
||||
TargetRefs []ResourceRef `json:"targetRefs,omitempty" protobuf:"bytes,2,opt,name=targetRefs"`
|
||||
Labels map[string]string `json:"labels,omitempty" protobuf:"bytes,3,opt,name=labels"`
|
||||
Ingress []corev1.LoadBalancerIngress `json:"ingress,omitempty" protobuf:"bytes,4,opt,name=ingress"`
|
||||
// ExternalURLs holds list of URLs which should be available externally. List is populated for ingress resources using rules hostnames.
|
||||
ExternalURLs []string `json:"externalURLs,omitempty" protobuf:"bytes,5,opt,name=externalURLs"`
|
||||
}
|
||||
|
||||
// TODO: describe this type
|
||||
type HostResourceInfo struct {
|
||||
ResourceName v1.ResourceName `json:"resourceName,omitempty" protobuf:"bytes,1,name=resourceName"`
|
||||
RequestedByApp int64 `json:"requestedByApp,omitempty" protobuf:"bytes,2,name=requestedByApp"`
|
||||
RequestedByNeighbors int64 `json:"requestedByNeighbors,omitempty" protobuf:"bytes,3,name=requestedByNeighbors"`
|
||||
Capacity int64 `json:"capacity,omitempty" protobuf:"bytes,4,name=capacity"`
|
||||
ResourceName corev1.ResourceName `json:"resourceName,omitempty" protobuf:"bytes,1,name=resourceName"`
|
||||
RequestedByApp int64 `json:"requestedByApp,omitempty" protobuf:"bytes,2,name=requestedByApp"`
|
||||
RequestedByNeighbors int64 `json:"requestedByNeighbors,omitempty" protobuf:"bytes,3,name=requestedByNeighbors"`
|
||||
Capacity int64 `json:"capacity,omitempty" protobuf:"bytes,4,name=capacity"`
|
||||
}
|
||||
|
||||
// HostInfo holds host name and resources metrics
|
||||
// TODO: describe purpose of this type
|
||||
// TODO: describe members of this type
|
||||
type HostInfo struct {
|
||||
Name string `json:"name,omitempty" protobuf:"bytes,1,name=name"`
|
||||
ResourcesInfo []HostResourceInfo `json:"resourcesInfo,omitempty" protobuf:"bytes,2,name=resourcesInfo"`
|
||||
SystemInfo v1.NodeSystemInfo `json:"systemInfo,omitempty" protobuf:"bytes,3,opt,name=systemInfo"`
|
||||
Name string `json:"name,omitempty" protobuf:"bytes,1,name=name"`
|
||||
ResourcesInfo []HostResourceInfo `json:"resourcesInfo,omitempty" protobuf:"bytes,2,name=resourcesInfo"`
|
||||
SystemInfo corev1.NodeSystemInfo `json:"systemInfo,omitempty" protobuf:"bytes,3,opt,name=systemInfo"`
|
||||
}
|
||||
|
||||
// ApplicationTree holds nodes which belongs to the application
|
||||
@@ -1938,7 +1937,8 @@ func (t *ApplicationTree) GetSummary(app *Application) ApplicationSummary {
|
||||
urlsSet[v] = true
|
||||
}
|
||||
}
|
||||
urls := make([]string, 0)
|
||||
|
||||
urls := make([]string, 0, len(urlsSet))
|
||||
for url := range urlsSet {
|
||||
urls = append(urls, url)
|
||||
}
|
||||
@@ -2099,6 +2099,32 @@ type Cluster struct {
|
||||
Annotations map[string]string `json:"annotations,omitempty" protobuf:"bytes,13,opt,name=annotations"`
|
||||
}
|
||||
|
||||
func (c *Cluster) Sanitized() *Cluster {
|
||||
return &Cluster{
|
||||
ID: c.ID,
|
||||
Server: c.Server,
|
||||
Name: c.Name,
|
||||
Project: c.Project,
|
||||
Namespaces: c.Namespaces,
|
||||
Shard: c.Shard,
|
||||
Labels: c.Labels,
|
||||
Annotations: c.Annotations,
|
||||
ClusterResources: c.ClusterResources,
|
||||
ConnectionState: c.ConnectionState,
|
||||
ServerVersion: c.ServerVersion,
|
||||
Info: c.Info,
|
||||
RefreshRequestedAt: c.RefreshRequestedAt,
|
||||
Config: ClusterConfig{
|
||||
AWSAuthConfig: c.Config.AWSAuthConfig,
|
||||
ProxyUrl: c.Config.ProxyUrl,
|
||||
DisableCompression: c.Config.DisableCompression,
|
||||
TLSClientConfig: TLSClientConfig{
|
||||
Insecure: c.Config.Insecure,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Equals returns true if two cluster objects are considered to be equal
|
||||
func (c *Cluster) Equals(other *Cluster) bool {
|
||||
if c.Server != other.Server {
|
||||
@@ -2155,7 +2181,7 @@ func (c *ClusterInfo) GetKubeVersion() string {
|
||||
return c.ServerVersion
|
||||
}
|
||||
|
||||
func (c *ClusterInfo) GetApiVersions() []string {
|
||||
func (c *ClusterInfo) GetApiVersions() []string { //nolint:revive //FIXME(var-naming)
|
||||
return c.APIVersions
|
||||
}
|
||||
|
||||
@@ -2231,7 +2257,7 @@ type ClusterConfig struct {
|
||||
DisableCompression bool `json:"disableCompression,omitempty" protobuf:"bytes,7,opt,name=disableCompression"`
|
||||
|
||||
// ProxyURL is the URL to the proxy to be used for all requests send to the server
|
||||
ProxyUrl string `json:"proxyUrl,omitempty" protobuf:"bytes,8,opt,name=proxyUrl"`
|
||||
ProxyUrl string `json:"proxyUrl,omitempty" protobuf:"bytes,8,opt,name=proxyUrl"` //nolint:revive //FIXME(var-naming)
|
||||
}
|
||||
|
||||
// TLSClientConfig contains settings to enable transport layer security
|
||||
@@ -2293,21 +2319,23 @@ type ResourceOverride struct {
|
||||
KnownTypeFields []KnownTypeField `protobuf:"bytes,4,opt,name=knownTypeFields"`
|
||||
}
|
||||
|
||||
// TODO: describe this method
|
||||
func (s *ResourceOverride) UnmarshalJSON(data []byte) error {
|
||||
// UnmarshalJSON unmarshals a JSON byte slice into a ResourceOverride object.
|
||||
// It parses the raw input data and handles special processing for `IgnoreDifferences`
|
||||
// and `IgnoreResourceUpdates` fields using YAML format.
|
||||
func (ro *ResourceOverride) UnmarshalJSON(data []byte) error {
|
||||
raw := &rawResourceOverride{}
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return err
|
||||
}
|
||||
s.KnownTypeFields = raw.KnownTypeFields
|
||||
s.HealthLua = raw.HealthLua
|
||||
s.UseOpenLibs = raw.UseOpenLibs
|
||||
s.Actions = raw.Actions
|
||||
err := yaml.Unmarshal([]byte(raw.IgnoreDifferences), &s.IgnoreDifferences)
|
||||
ro.KnownTypeFields = raw.KnownTypeFields
|
||||
ro.HealthLua = raw.HealthLua
|
||||
ro.UseOpenLibs = raw.UseOpenLibs
|
||||
ro.Actions = raw.Actions
|
||||
err := yaml.Unmarshal([]byte(raw.IgnoreDifferences), &ro.IgnoreDifferences)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = yaml.Unmarshal([]byte(raw.IgnoreResourceUpdates), &s.IgnoreResourceUpdates)
|
||||
err = yaml.Unmarshal([]byte(raw.IgnoreResourceUpdates), &ro.IgnoreResourceUpdates)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -2372,7 +2400,7 @@ type ResourceActionParam struct {
|
||||
Default string `json:"default,omitempty" protobuf:"bytes,4,opt,name=default"`
|
||||
}
|
||||
|
||||
// TODO: refactor to use rbacpolicy.ActionGet, rbacpolicy.ActionCreate, without import cycle
|
||||
// TODO: refactor to use rbac.ActionGet, rbac.ActionCreate, without import cycle
|
||||
var validActions = map[string]bool{
|
||||
"get": true,
|
||||
"create": true,
|
||||
@@ -2401,19 +2429,6 @@ func isValidAction(action string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO: same as validActions, refacotor to use rbacpolicy.ResourceApplications etc.
|
||||
var validResources = map[string]bool{
|
||||
"applications": true,
|
||||
"repositories": true,
|
||||
"clusters": true,
|
||||
"exec": true,
|
||||
"logs": true,
|
||||
}
|
||||
|
||||
func isValidResource(resource string) bool {
|
||||
return validResources[resource]
|
||||
}
|
||||
|
||||
func isValidObject(proj string, object string) bool {
|
||||
// match against <PROJECT>[/<NAMESPACE>]/<APPLICATION>
|
||||
objectRegexp, err := regexp.Compile(fmt.Sprintf(`^%s(/[*\w-.]+)?/[*\w-.]+$`, regexp.QuoteMeta(proj)))
|
||||
@@ -2433,8 +2448,8 @@ func validatePolicy(proj string, role string, policy string) error {
|
||||
}
|
||||
// resource
|
||||
resource := strings.Trim(policyComponents[2], " ")
|
||||
if !isValidResource(resource) {
|
||||
return status.Errorf(codes.InvalidArgument, "invalid policy rule '%s': project resource must be: 'applications', 'repositories' or 'clusters', not '%s'", policy, resource)
|
||||
if !rbac.ProjectScoped[resource] {
|
||||
return status.Errorf(codes.InvalidArgument, "invalid policy rule '%s': project resource must be: 'applications', 'applicationsets', 'repositories', 'exec', 'logs' or 'clusters', not '%s'", policy, resource)
|
||||
}
|
||||
// action
|
||||
action := strings.Trim(policyComponents[3], " ")
|
||||
@@ -2571,24 +2586,24 @@ type SyncWindow struct {
|
||||
}
|
||||
|
||||
// HasWindows returns true if SyncWindows has one or more SyncWindow
|
||||
func (s *SyncWindows) HasWindows() bool {
|
||||
return s != nil && len(*s) > 0
|
||||
func (w *SyncWindows) HasWindows() bool {
|
||||
return w != nil && len(*w) > 0
|
||||
}
|
||||
|
||||
// Active returns a list of sync windows that are currently active
|
||||
func (s *SyncWindows) Active() (*SyncWindows, error) {
|
||||
return s.active(time.Now())
|
||||
func (w *SyncWindows) Active() (*SyncWindows, error) {
|
||||
return w.active(time.Now())
|
||||
}
|
||||
|
||||
func (s *SyncWindows) active(currentTime time.Time) (*SyncWindows, error) {
|
||||
func (w *SyncWindows) active(currentTime time.Time) (*SyncWindows, error) {
|
||||
// If SyncWindows.Active() is called outside of a UTC locale, it should be
|
||||
// first converted to UTC before we scan through the SyncWindows.
|
||||
currentTime = currentTime.In(time.UTC)
|
||||
|
||||
if s.HasWindows() {
|
||||
if w.HasWindows() {
|
||||
var active SyncWindows
|
||||
specParser := cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow)
|
||||
for _, w := range *s {
|
||||
for _, w := range *w {
|
||||
schedule, sErr := specParser.Parse(w.Schedule)
|
||||
if sErr != nil {
|
||||
return nil, fmt.Errorf("cannot parse schedule '%s': %w", w.Schedule, sErr)
|
||||
@@ -2615,19 +2630,19 @@ func (s *SyncWindows) active(currentTime time.Time) (*SyncWindows, error) {
|
||||
// InactiveAllows will iterate over the SyncWindows and return all inactive allow windows
|
||||
// for the current time. If the current time is in an inactive allow window, syncs will
|
||||
// be denied.
|
||||
func (s *SyncWindows) InactiveAllows() (*SyncWindows, error) {
|
||||
return s.inactiveAllows(time.Now())
|
||||
func (w *SyncWindows) InactiveAllows() (*SyncWindows, error) {
|
||||
return w.inactiveAllows(time.Now())
|
||||
}
|
||||
|
||||
func (s *SyncWindows) inactiveAllows(currentTime time.Time) (*SyncWindows, error) {
|
||||
func (w *SyncWindows) inactiveAllows(currentTime time.Time) (*SyncWindows, error) {
|
||||
// If SyncWindows.InactiveAllows() is called outside of a UTC locale, it should be
|
||||
// first converted to UTC before we scan through the SyncWindows.
|
||||
currentTime = currentTime.In(time.UTC)
|
||||
|
||||
if s.HasWindows() {
|
||||
if w.HasWindows() {
|
||||
var inactive SyncWindows
|
||||
specParser := cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow)
|
||||
for _, w := range *s {
|
||||
for _, w := range *w {
|
||||
if w.Kind == "allow" {
|
||||
schedule, sErr := specParser.Parse(w.Schedule)
|
||||
if sErr != nil {
|
||||
@@ -2664,9 +2679,9 @@ func (w *SyncWindow) scheduleOffsetByTimeZone() time.Duration {
|
||||
}
|
||||
|
||||
// AddWindow adds a sync window with the given parameters to the AppProject
|
||||
func (s *AppProjectSpec) AddWindow(knd string, sch string, dur string, app []string, ns []string, cl []string, ms bool, timeZone string) error {
|
||||
func (spec *AppProjectSpec) AddWindow(knd string, sch string, dur string, app []string, ns []string, cl []string, ms bool, timeZone string) error {
|
||||
if len(knd) == 0 || len(sch) == 0 || len(dur) == 0 {
|
||||
return fmt.Errorf("cannot create window: require kind, schedule, duration and one or more of applications, namespaces and clusters")
|
||||
return errors.New("cannot create window: require kind, schedule, duration and one or more of applications, namespaces and clusters")
|
||||
}
|
||||
|
||||
window := &SyncWindow{
|
||||
@@ -2692,18 +2707,18 @@ func (s *AppProjectSpec) AddWindow(knd string, sch string, dur string, app []str
|
||||
return err
|
||||
}
|
||||
|
||||
s.SyncWindows = append(s.SyncWindows, window)
|
||||
spec.SyncWindows = append(spec.SyncWindows, window)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteWindow deletes a sync window with the given id from the AppProject
|
||||
func (s *AppProjectSpec) DeleteWindow(id int) error {
|
||||
func (spec *AppProjectSpec) DeleteWindow(id int) error {
|
||||
var exists bool
|
||||
for i := range s.SyncWindows {
|
||||
for i := range spec.SyncWindows {
|
||||
if i == id {
|
||||
exists = true
|
||||
s.SyncWindows = append(s.SyncWindows[:i], s.SyncWindows[i+1:]...)
|
||||
spec.SyncWindows = append(spec.SyncWindows[:i], spec.SyncWindows[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -2768,9 +2783,8 @@ func (w *SyncWindows) CanSync(isManual bool) (bool, error) {
|
||||
if hasActiveDeny {
|
||||
if isManual && manualEnabled {
|
||||
return true, nil
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if active.hasAllow() {
|
||||
@@ -2784,9 +2798,8 @@ func (w *SyncWindows) CanSync(isManual bool) (bool, error) {
|
||||
if inactiveAllows.HasWindows() {
|
||||
if isManual && inactiveAllows.manualEnabled() {
|
||||
return true, nil
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
@@ -2873,7 +2886,7 @@ func (w SyncWindow) active(currentTime time.Time) (bool, error) {
|
||||
// Update updates a sync window's settings with the given parameter
|
||||
func (w *SyncWindow) Update(s string, d string, a []string, n []string, c []string, tz string) error {
|
||||
if len(s) == 0 && len(d) == 0 && len(a) == 0 && len(n) == 0 && len(c) == 0 {
|
||||
return fmt.Errorf("cannot update: require one or more of schedule, duration, application, namespace, or cluster")
|
||||
return errors.New("cannot update: require one or more of schedule, duration, application, namespace, or cluster")
|
||||
}
|
||||
|
||||
if len(s) > 0 {
|
||||
@@ -2927,10 +2940,10 @@ func (w *SyncWindow) Validate() error {
|
||||
}
|
||||
|
||||
// DestinationClusters returns a list of cluster URLs allowed as destination in an AppProject
|
||||
func (d AppProjectSpec) DestinationClusters() []string {
|
||||
func (spec AppProjectSpec) DestinationClusters() []string {
|
||||
servers := make([]string, 0)
|
||||
|
||||
for _, d := range d.Destinations {
|
||||
for _, d := range spec.Destinations {
|
||||
servers = append(servers, d.Server)
|
||||
}
|
||||
|
||||
@@ -3047,6 +3060,14 @@ func (app *Application) SetPostDeleteFinalizer(stage ...string) {
|
||||
setFinalizer(&app.ObjectMeta, strings.Join(append([]string{PostDeleteFinalizerName}, stage...), "/"), true)
|
||||
}
|
||||
|
||||
func (app *Application) UnSetPostDeleteFinalizerAll() {
|
||||
for _, finalizer := range app.Finalizers {
|
||||
if strings.HasPrefix(finalizer, PostDeleteFinalizerName) {
|
||||
setFinalizer(&app.ObjectMeta, finalizer, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (app *Application) UnSetPostDeleteFinalizer(stage ...string) {
|
||||
setFinalizer(&app.ObjectMeta, strings.Join(append([]string{PostDeleteFinalizerName}, stage...), "/"), false)
|
||||
}
|
||||
@@ -3349,7 +3370,7 @@ func SetK8SConfigDefaults(config *rest.Config) error {
|
||||
}
|
||||
|
||||
// ParseProxyUrl returns a parsed url and verifies that schema is correct
|
||||
func ParseProxyUrl(proxyUrl string) (*url.URL, error) {
|
||||
func ParseProxyUrl(proxyUrl string) (*url.URL, error) { //nolint:revive //FIXME(var-naming)
|
||||
u, err := url.Parse(proxyUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -3366,7 +3387,9 @@ func ParseProxyUrl(proxyUrl string) (*url.URL, error) {
|
||||
func (c *Cluster) RawRestConfig() (*rest.Config, error) {
|
||||
var config *rest.Config
|
||||
var err error
|
||||
if c.Server == KubernetesInternalAPIServerAddr && env.ParseBoolFromEnv(EnvVarFakeInClusterConfig, false) {
|
||||
|
||||
switch {
|
||||
case c.Server == KubernetesInternalAPIServerAddr && env.ParseBoolFromEnv(EnvVarFakeInClusterConfig, false):
|
||||
conf, exists := os.LookupEnv("KUBECONFIG")
|
||||
if exists {
|
||||
config, err = clientcmd.BuildConfigFromFlags("", conf)
|
||||
@@ -3378,9 +3401,9 @@ func (c *Cluster) RawRestConfig() (*rest.Config, error) {
|
||||
}
|
||||
config, err = clientcmd.BuildConfigFromFlags("", filepath.Join(homeDir, ".kube", "config"))
|
||||
}
|
||||
} else if c.Server == KubernetesInternalAPIServerAddr && c.Config.Username == "" && c.Config.Password == "" && c.Config.BearerToken == "" {
|
||||
case c.Server == KubernetesInternalAPIServerAddr && c.Config.Username == "" && c.Config.Password == "" && c.Config.BearerToken == "":
|
||||
config, err = rest.InClusterConfig()
|
||||
} else if c.Server == KubernetesInternalAPIServerAddr {
|
||||
case c.Server == KubernetesInternalAPIServerAddr:
|
||||
config, err = rest.InClusterConfig()
|
||||
if err == nil {
|
||||
config.Username = c.Config.Username
|
||||
@@ -3388,7 +3411,7 @@ func (c *Cluster) RawRestConfig() (*rest.Config, error) {
|
||||
config.BearerToken = c.Config.BearerToken
|
||||
config.BearerTokenFile = ""
|
||||
}
|
||||
} else {
|
||||
default:
|
||||
tlsClientConfig := rest.TLSClientConfig{
|
||||
Insecure: c.Config.TLSClientConfig.Insecure,
|
||||
ServerName: c.Config.TLSClientConfig.ServerName,
|
||||
@@ -3396,7 +3419,8 @@ func (c *Cluster) RawRestConfig() (*rest.Config, error) {
|
||||
KeyData: c.Config.TLSClientConfig.KeyData,
|
||||
CAData: c.Config.TLSClientConfig.CAData,
|
||||
}
|
||||
if c.Config.AWSAuthConfig != nil {
|
||||
switch {
|
||||
case c.Config.AWSAuthConfig != nil:
|
||||
args := []string{"aws", "--cluster-name", c.Config.AWSAuthConfig.ClusterName}
|
||||
if c.Config.AWSAuthConfig.RoleARN != "" {
|
||||
args = append(args, "--role-arn", c.Config.AWSAuthConfig.RoleARN)
|
||||
@@ -3414,7 +3438,7 @@ func (c *Cluster) RawRestConfig() (*rest.Config, error) {
|
||||
InteractiveMode: api.NeverExecInteractiveMode,
|
||||
},
|
||||
}
|
||||
} else if c.Config.ExecProviderConfig != nil {
|
||||
case c.Config.ExecProviderConfig != nil:
|
||||
var env []api.ExecEnvVar
|
||||
if c.Config.ExecProviderConfig.Env != nil {
|
||||
for key, value := range c.Config.ExecProviderConfig.Env {
|
||||
@@ -3436,7 +3460,7 @@ func (c *Cluster) RawRestConfig() (*rest.Config, error) {
|
||||
InteractiveMode: api.NeverExecInteractiveMode,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
default:
|
||||
config = &rest.Config{
|
||||
Host: c.Server,
|
||||
Username: c.Config.Username,
|
||||
@@ -3545,37 +3569,36 @@ func (d *ApplicationDestination) MarshalJSON() ([]byte, error) {
|
||||
// tracking values, i.e. in the format <namespace>_<name>. When the namespace
|
||||
// of the application is similar to the value of defaultNs, only the name of
|
||||
// the application is returned to keep backwards compatibility.
|
||||
func (a *Application) InstanceName(defaultNs string) string {
|
||||
func (app *Application) InstanceName(defaultNs string) string {
|
||||
// When app has no namespace set, or the namespace is the default ns, we
|
||||
// return just the application name
|
||||
if a.Namespace == "" || a.Namespace == defaultNs {
|
||||
return a.Name
|
||||
if app.Namespace == "" || app.Namespace == defaultNs {
|
||||
return app.Name
|
||||
}
|
||||
return a.Namespace + "_" + a.Name
|
||||
return app.Namespace + "_" + app.Name
|
||||
}
|
||||
|
||||
// QualifiedName returns the full qualified name of the application, including
|
||||
// the name of the namespace it is created in delimited by a forward slash,
|
||||
// i.e. <namespace>/<appname>
|
||||
func (a *Application) QualifiedName() string {
|
||||
if a.Namespace == "" {
|
||||
return a.Name
|
||||
} else {
|
||||
return a.Namespace + "/" + a.Name
|
||||
func (app *Application) QualifiedName() string {
|
||||
if app.Namespace == "" {
|
||||
return app.Name
|
||||
}
|
||||
return app.Namespace + "/" + app.Name
|
||||
}
|
||||
|
||||
// RBACName returns the full qualified RBAC resource name for the application
|
||||
// in a backwards-compatible way.
|
||||
func (a *Application) RBACName(defaultNS string) string {
|
||||
return security.RBACName(defaultNS, a.Spec.GetProject(), a.Namespace, a.Name)
|
||||
func (app *Application) RBACName(defaultNS string) string {
|
||||
return security.RBACName(defaultNS, app.Spec.GetProject(), app.Namespace, app.Name)
|
||||
}
|
||||
|
||||
// GetAnnotation returns the value of the specified annotation if it exists,
|
||||
// e.g., a.GetAnnotation("argocd.argoproj.io/manifest-generate-paths").
|
||||
// If the annotation does not exist, it returns an empty string.
|
||||
func (a *Application) GetAnnotation(annotation string) string {
|
||||
v, exists := a.Annotations[annotation]
|
||||
func (app *Application) GetAnnotation(annotation string) string {
|
||||
v, exists := app.Annotations[annotation]
|
||||
if !exists {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -3513,6 +3513,8 @@ func Test_validatePolicy_projIsNotRegex(t *testing.T) {
|
||||
func Test_validatePolicy_ValidResource(t *testing.T) {
|
||||
err := validatePolicy("some-project", "org-admin", "p, proj:some-project:org-admin, applications, *, some-project/*, allow")
|
||||
require.NoError(t, err)
|
||||
err = validatePolicy("some-project", "org-admin", "p, proj:some-project:org-admin, applicationsets, *, some-project/*, allow")
|
||||
require.NoError(t, err)
|
||||
err = validatePolicy("some-project", "org-admin", "p, proj:some-project:org-admin, repositories, *, some-project/*, allow")
|
||||
require.NoError(t, err)
|
||||
err = validatePolicy("some-project", "org-admin", "p, proj:some-project:org-admin, clusters, *, some-project/*, allow")
|
||||
@@ -4346,3 +4348,58 @@ func TestCluster_ParseProxyUrl(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSanitized(t *testing.T) {
|
||||
now := metav1.Now()
|
||||
cluster := &Cluster{
|
||||
ID: "123",
|
||||
Server: "https://example.com",
|
||||
Name: "example",
|
||||
ServerVersion: "v1.0.0",
|
||||
Namespaces: []string{"default", "kube-system"},
|
||||
Project: "default",
|
||||
Labels: map[string]string{
|
||||
"env": "production",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"annotation-key": "annotation-value",
|
||||
},
|
||||
ConnectionState: ConnectionState{
|
||||
Status: ConnectionStatusSuccessful,
|
||||
Message: "Connection successful",
|
||||
ModifiedAt: &now,
|
||||
},
|
||||
Config: ClusterConfig{
|
||||
Username: "admin",
|
||||
Password: "password123",
|
||||
BearerToken: "abc",
|
||||
TLSClientConfig: TLSClientConfig{
|
||||
Insecure: true,
|
||||
},
|
||||
ExecProviderConfig: &ExecProviderConfig{
|
||||
Command: "test",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, &Cluster{
|
||||
ID: "123",
|
||||
Server: "https://example.com",
|
||||
Name: "example",
|
||||
ServerVersion: "v1.0.0",
|
||||
Namespaces: []string{"default", "kube-system"},
|
||||
Project: "default",
|
||||
Labels: map[string]string{"env": "production"},
|
||||
Annotations: map[string]string{"annotation-key": "annotation-value"},
|
||||
ConnectionState: ConnectionState{
|
||||
Status: ConnectionStatusSuccessful,
|
||||
Message: "Connection successful",
|
||||
ModifiedAt: &now,
|
||||
},
|
||||
Config: ClusterConfig{
|
||||
TLSClientConfig: TLSClientConfig{
|
||||
Insecure: true,
|
||||
},
|
||||
},
|
||||
}, cluster.Sanitized())
|
||||
}
|
||||
|
||||
258
pkg/client/clientset/versioned/typed/application/v1alpha1/mocks/AppProjectInterface.go
generated
Normal file
258
pkg/client/clientset/versioned/typed/application/v1alpha1/mocks/AppProjectInterface.go
generated
Normal file
@@ -0,0 +1,258 @@
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
v1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
)
|
||||
|
||||
// AppProjectInterface is an autogenerated mock type for the AppProjectInterface type
|
||||
type AppProjectInterface struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Create provides a mock function with given fields: ctx, appProject, opts
|
||||
func (_m *AppProjectInterface) Create(ctx context.Context, appProject *v1alpha1.AppProject, opts v1.CreateOptions) (*v1alpha1.AppProject, error) {
|
||||
ret := _m.Called(ctx, appProject, opts)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Create")
|
||||
}
|
||||
|
||||
var r0 *v1alpha1.AppProject
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *v1alpha1.AppProject, v1.CreateOptions) (*v1alpha1.AppProject, error)); ok {
|
||||
return rf(ctx, appProject, opts)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *v1alpha1.AppProject, v1.CreateOptions) *v1alpha1.AppProject); ok {
|
||||
r0 = rf(ctx, appProject, opts)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.AppProject)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *v1alpha1.AppProject, v1.CreateOptions) error); ok {
|
||||
r1 = rf(ctx, appProject, opts)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: ctx, name, opts
|
||||
func (_m *AppProjectInterface) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
ret := _m.Called(ctx, name, opts)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Delete")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, v1.DeleteOptions) error); ok {
|
||||
r0 = rf(ctx, name, opts)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteCollection provides a mock function with given fields: ctx, opts, listOpts
|
||||
func (_m *AppProjectInterface) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
ret := _m.Called(ctx, opts, listOpts)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteCollection")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, v1.DeleteOptions, v1.ListOptions) error); ok {
|
||||
r0 = rf(ctx, opts, listOpts)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Get provides a mock function with given fields: ctx, name, opts
|
||||
func (_m *AppProjectInterface) Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.AppProject, error) {
|
||||
ret := _m.Called(ctx, name, opts)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Get")
|
||||
}
|
||||
|
||||
var r0 *v1alpha1.AppProject
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, v1.GetOptions) (*v1alpha1.AppProject, error)); ok {
|
||||
return rf(ctx, name, opts)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, v1.GetOptions) *v1alpha1.AppProject); ok {
|
||||
r0 = rf(ctx, name, opts)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.AppProject)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, v1.GetOptions) error); ok {
|
||||
r1 = rf(ctx, name, opts)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// List provides a mock function with given fields: ctx, opts
|
||||
func (_m *AppProjectInterface) List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.AppProjectList, error) {
|
||||
ret := _m.Called(ctx, opts)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for List")
|
||||
}
|
||||
|
||||
var r0 *v1alpha1.AppProjectList
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, v1.ListOptions) (*v1alpha1.AppProjectList, error)); ok {
|
||||
return rf(ctx, opts)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, v1.ListOptions) *v1alpha1.AppProjectList); ok {
|
||||
r0 = rf(ctx, opts)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.AppProjectList)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, v1.ListOptions) error); ok {
|
||||
r1 = rf(ctx, opts)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Patch provides a mock function with given fields: ctx, name, pt, data, opts, subresources
|
||||
func (_m *AppProjectInterface) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (*v1alpha1.AppProject, error) {
|
||||
_va := make([]interface{}, len(subresources))
|
||||
for _i := range subresources {
|
||||
_va[_i] = subresources[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx, name, pt, data, opts)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Patch")
|
||||
}
|
||||
|
||||
var r0 *v1alpha1.AppProject
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, types.PatchType, []byte, v1.PatchOptions, ...string) (*v1alpha1.AppProject, error)); ok {
|
||||
return rf(ctx, name, pt, data, opts, subresources...)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, types.PatchType, []byte, v1.PatchOptions, ...string) *v1alpha1.AppProject); ok {
|
||||
r0 = rf(ctx, name, pt, data, opts, subresources...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.AppProject)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, types.PatchType, []byte, v1.PatchOptions, ...string) error); ok {
|
||||
r1 = rf(ctx, name, pt, data, opts, subresources...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Update provides a mock function with given fields: ctx, appProject, opts
|
||||
func (_m *AppProjectInterface) Update(ctx context.Context, appProject *v1alpha1.AppProject, opts v1.UpdateOptions) (*v1alpha1.AppProject, error) {
|
||||
ret := _m.Called(ctx, appProject, opts)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Update")
|
||||
}
|
||||
|
||||
var r0 *v1alpha1.AppProject
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *v1alpha1.AppProject, v1.UpdateOptions) (*v1alpha1.AppProject, error)); ok {
|
||||
return rf(ctx, appProject, opts)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *v1alpha1.AppProject, v1.UpdateOptions) *v1alpha1.AppProject); ok {
|
||||
r0 = rf(ctx, appProject, opts)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.AppProject)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *v1alpha1.AppProject, v1.UpdateOptions) error); ok {
|
||||
r1 = rf(ctx, appProject, opts)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Watch provides a mock function with given fields: ctx, opts
|
||||
func (_m *AppProjectInterface) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
ret := _m.Called(ctx, opts)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Watch")
|
||||
}
|
||||
|
||||
var r0 watch.Interface
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, v1.ListOptions) (watch.Interface, error)); ok {
|
||||
return rf(ctx, opts)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, v1.ListOptions) watch.Interface); ok {
|
||||
r0 = rf(ctx, opts)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(watch.Interface)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, v1.ListOptions) error); ok {
|
||||
r1 = rf(ctx, opts)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// NewAppProjectInterface creates a new instance of AppProjectInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewAppProjectInterface(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *AppProjectInterface {
|
||||
mock := &AppProjectInterface{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
@@ -17,7 +17,7 @@ type RepoServerService_GenerateManifestWithFilesClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// CloseAndRecv provides a mock function with given fields:
|
||||
// CloseAndRecv provides a mock function with no fields
|
||||
func (_m *RepoServerService_GenerateManifestWithFilesClient) CloseAndRecv() (*apiclient.ManifestResponse, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
@@ -47,7 +47,7 @@ func (_m *RepoServerService_GenerateManifestWithFilesClient) CloseAndRecv() (*ap
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CloseSend provides a mock function with given fields:
|
||||
// CloseSend provides a mock function with no fields
|
||||
func (_m *RepoServerService_GenerateManifestWithFilesClient) CloseSend() error {
|
||||
ret := _m.Called()
|
||||
|
||||
@@ -65,7 +65,7 @@ func (_m *RepoServerService_GenerateManifestWithFilesClient) CloseSend() error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// Context provides a mock function with given fields:
|
||||
// Context provides a mock function with no fields
|
||||
func (_m *RepoServerService_GenerateManifestWithFilesClient) Context() context.Context {
|
||||
ret := _m.Called()
|
||||
|
||||
@@ -85,7 +85,7 @@ func (_m *RepoServerService_GenerateManifestWithFilesClient) Context() context.C
|
||||
return r0
|
||||
}
|
||||
|
||||
// Header provides a mock function with given fields:
|
||||
// Header provides a mock function with no fields
|
||||
func (_m *RepoServerService_GenerateManifestWithFilesClient) Header() (metadata.MD, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
@@ -169,7 +169,7 @@ func (_m *RepoServerService_GenerateManifestWithFilesClient) SendMsg(m interface
|
||||
return r0
|
||||
}
|
||||
|
||||
// Trailer provides a mock function with given fields:
|
||||
// Trailer provides a mock function with no fields
|
||||
func (_m *RepoServerService_GenerateManifestWithFilesClient) Trailer() metadata.MD {
|
||||
ret := _m.Called()
|
||||
|
||||
|
||||
@@ -345,7 +345,7 @@ func (s *Service) runRepoOperation(
|
||||
|
||||
if source.IsHelm() {
|
||||
if settings.noCache {
|
||||
err = helmClient.CleanChartCache(source.Chart, revision, repo.Project)
|
||||
err = helmClient.CleanChartCache(source.Chart, revision)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -354,7 +354,7 @@ func (s *Service) runRepoOperation(
|
||||
if source.Helm != nil {
|
||||
helmPassCredentials = source.Helm.PassCredentials
|
||||
}
|
||||
chartPath, closer, err := helmClient.ExtractChart(source.Chart, revision, repo.Project, helmPassCredentials, s.initConstants.HelmManifestMaxExtractedSize, s.initConstants.DisableHelmManifestMaxExtractedSize)
|
||||
chartPath, closer, err := helmClient.ExtractChart(source.Chart, revision, helmPassCredentials, s.initConstants.HelmManifestMaxExtractedSize, s.initConstants.DisableHelmManifestMaxExtractedSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1180,7 +1180,7 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
|
||||
referencedSource := getReferencedSource(p.Path, q.RefSources)
|
||||
if referencedSource != nil {
|
||||
// If the $-prefixed path appears to reference another source, do env substitution _after_ resolving the source
|
||||
resolvedPath, err = getResolvedRefValueFile(p.Path, env, q.GetValuesFileSchemes(), referencedSource.Repo.Repo, gitRepoPaths, referencedSource.Repo.Project)
|
||||
resolvedPath, err = getResolvedRefValueFile(p.Path, env, q.GetValuesFileSchemes(), referencedSource.Repo.Repo, gitRepoPaths)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("error resolving set-file path: %w", err)
|
||||
}
|
||||
@@ -1306,7 +1306,7 @@ func getResolvedValueFiles(
|
||||
referencedSource := getReferencedSource(rawValueFile, refSources)
|
||||
if referencedSource != nil {
|
||||
// If the $-prefixed path appears to reference another source, do env substitution _after_ resolving that source.
|
||||
resolvedPath, err = getResolvedRefValueFile(rawValueFile, env, allowedValueFilesSchemas, referencedSource.Repo.Repo, gitRepoPaths, referencedSource.Repo.Project)
|
||||
resolvedPath, err = getResolvedRefValueFile(rawValueFile, env, allowedValueFilesSchemas, referencedSource.Repo.Repo, gitRepoPaths)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error resolving value file path: %w", err)
|
||||
}
|
||||
@@ -1339,15 +1339,9 @@ func getResolvedRefValueFile(
|
||||
allowedValueFilesSchemas []string,
|
||||
refSourceRepo string,
|
||||
gitRepoPaths io.TempPaths,
|
||||
project string,
|
||||
) (pathutil.ResolvedFilePath, error) {
|
||||
pathStrings := strings.Split(rawValueFile, "/")
|
||||
|
||||
keyData, err := json.Marshal(map[string]string{"url": git.NormalizeGitURL(refSourceRepo), "project": project})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
repoPath := gitRepoPaths.GetPathIfExists(string(keyData))
|
||||
repoPath := gitRepoPaths.GetPathIfExists(git.NormalizeGitURL(refSourceRepo))
|
||||
if repoPath == "" {
|
||||
return "", fmt.Errorf("failed to find repo %q", refSourceRepo)
|
||||
}
|
||||
@@ -2382,7 +2376,7 @@ func (s *Service) GetRevisionChartDetails(ctx context.Context, q *apiclient.Repo
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("helm client error: %w", err)
|
||||
}
|
||||
chartPath, closer, err := helmClient.ExtractChart(q.Name, revision, q.Repo.Project, false, s.initConstants.HelmManifestMaxExtractedSize, s.initConstants.DisableHelmManifestMaxExtractedSize)
|
||||
chartPath, closer, err := helmClient.ExtractChart(q.Name, revision, false, s.initConstants.HelmManifestMaxExtractedSize, s.initConstants.DisableHelmManifestMaxExtractedSize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error extracting chart: %w", err)
|
||||
}
|
||||
@@ -2412,11 +2406,7 @@ func fileParameters(q *apiclient.RepoServerAppDetailsQuery) []v1alpha1.HelmFileP
|
||||
}
|
||||
|
||||
func (s *Service) newClient(repo *v1alpha1.Repository, opts ...git.ClientOpts) (git.Client, error) {
|
||||
keyData, err := json.Marshal(map[string]string{"url": git.NormalizeGitURL(repo.Repo), "project": repo.Project})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repoPath, err := s.gitRepoPaths.GetPath(string(keyData))
|
||||
repoPath, err := s.gitRepoPaths.GetPath(git.NormalizeGitURL(repo.Repo))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -127,10 +127,10 @@ func newServiceWithMocks(t *testing.T, root string, signed bool) (*Service, *git
|
||||
chart: {{Version: "1.0.0"}, {Version: version}},
|
||||
oobChart: {{Version: "1.0.0"}, {Version: version}},
|
||||
}}, nil)
|
||||
helmClient.On("ExtractChart", chart, version, "", false, int64(0), false).Return("./testdata/my-chart", io.NopCloser, nil)
|
||||
helmClient.On("ExtractChart", oobChart, version, "", false, int64(0), false).Return("./testdata2/out-of-bounds-chart", io.NopCloser, nil)
|
||||
helmClient.On("CleanChartCache", chart, version, "").Return(nil)
|
||||
helmClient.On("CleanChartCache", oobChart, version, "").Return(nil)
|
||||
helmClient.On("ExtractChart", chart, version, false, int64(0), false).Return("./testdata/my-chart", io.NopCloser, nil)
|
||||
helmClient.On("ExtractChart", oobChart, version, false, int64(0), false).Return("./testdata2/out-of-bounds-chart", io.NopCloser, nil)
|
||||
helmClient.On("CleanChartCache", chart, version).Return(nil)
|
||||
helmClient.On("CleanChartCache", oobChart, version).Return(nil)
|
||||
helmClient.On("DependencyBuild").Return(nil)
|
||||
|
||||
paths.On("Add", mock.Anything, mock.Anything).Return(root, nil)
|
||||
@@ -3283,8 +3283,7 @@ func Test_getResolvedValueFiles(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
paths := io.NewRandomizedTempPaths(tempDir)
|
||||
|
||||
key, _ := json.Marshal(map[string]string{"url": git.NormalizeGitURL("https://github.com/org/repo1"), "project": ""})
|
||||
paths.Add(string(key), path.Join(tempDir, "repo1"))
|
||||
paths.Add(git.NormalizeGitURL("https://github.com/org/repo1"), path.Join(tempDir, "repo1"))
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
||||
@@ -7,8 +7,18 @@ if obj.status == nil or obj.status.conditions == nil then
|
||||
end
|
||||
|
||||
-- Sort conditions by lastTransitionTime, from old to new.
|
||||
-- Ensure that conditions with nil lastTransitionTime are always sorted after those with non-nil values.
|
||||
table.sort(obj.status.conditions, function(a, b)
|
||||
return a.lastTransitionTime < b.lastTransitionTime
|
||||
-- Nil values are considered "less than" non-nil values.
|
||||
-- This means that conditions with nil lastTransitionTime will be sorted to the end.
|
||||
if a.lastTransitionTime == nil then
|
||||
return false
|
||||
elseif b.lastTransitionTime == nil then
|
||||
return true
|
||||
else
|
||||
-- If both have non-nil lastTransitionTime, compare them normally.
|
||||
return a.lastTransitionTime < b.lastTransitionTime
|
||||
end
|
||||
end)
|
||||
|
||||
for _, condition in ipairs(obj.status.conditions) do
|
||||
|
||||
@@ -14,4 +14,8 @@ tests:
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: "Has Errors: Waiting for foo/keycloak-1 due to CrashLoopBackOff: back-off 10s"
|
||||
inputPath: testdata/degraded.yaml
|
||||
inputPath: testdata/degraded.yaml
|
||||
- healthStatus:
|
||||
status: Healthy
|
||||
message: ""
|
||||
inputPath: testdata/nil_last_transition_time.yaml
|
||||
13
resource_customizations/k8s.keycloak.org/Keycloak/testdata/nil_last_transition_time.yaml
vendored
Normal file
13
resource_customizations/k8s.keycloak.org/Keycloak/testdata/nil_last_transition_time.yaml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
apiVersion: k8s.keycloak.org/v1alpha1
|
||||
kind: Keycloak
|
||||
metadata:
|
||||
name: keycloak-23
|
||||
namespace: keycloak
|
||||
status:
|
||||
conditions:
|
||||
- type: Ready
|
||||
status: "True"
|
||||
lastTransitionTime: "2025-05-06T12:00:00Z" # Non-nil lastTransitionTime
|
||||
- type: HasErrors
|
||||
status: "False"
|
||||
lastTransitionTime: null # Nil lastTransitionTime
|
||||
@@ -4,6 +4,13 @@ if obj.spec.suspend ~= nil and obj.spec.suspend == true then
|
||||
hs.status = "Suspended"
|
||||
return hs
|
||||
end
|
||||
-- Helm repositories of type "oci" do not contain any information in the status
|
||||
-- https://fluxcd.io/flux/components/source/helmrepositories/#helmrepository-status
|
||||
if obj.spec.type ~= nil and obj.spec.type == "oci" then
|
||||
hs.message = "Helm repositories of type 'oci' do not contain any information in the status."
|
||||
hs.status = "Healthy"
|
||||
return hs
|
||||
end
|
||||
if obj.status ~= nil then
|
||||
if obj.status.conditions ~= nil then
|
||||
local numProgressing = 0
|
||||
|
||||
@@ -11,3 +11,7 @@ tests:
|
||||
status: Healthy
|
||||
message: Succeeded
|
||||
inputPath: testdata/healthy.yaml
|
||||
- healthStatus:
|
||||
status: Healthy
|
||||
message: "Helm repositories of type 'oci' do not contain any information in the status."
|
||||
inputPath: testdata/oci.yaml
|
||||
|
||||
10
resource_customizations/source.toolkit.fluxcd.io/HelmRepository/testdata/oci.yaml
vendored
Normal file
10
resource_customizations/source.toolkit.fluxcd.io/HelmRepository/testdata/oci.yaml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: HelmRepository
|
||||
metadata:
|
||||
name: podinfo
|
||||
namespace: default
|
||||
spec:
|
||||
type: "oci"
|
||||
interval: 5m0s
|
||||
url: oci://ghcr.io/stefanprodan/charts
|
||||
status: {}
|
||||
@@ -47,7 +47,7 @@ func (s *Server) UpdatePassword(ctx context.Context, q *account.UpdatePasswordRe
|
||||
// check for permission is user is trying to change someone else's password
|
||||
// assuming user is trying to update someone else if username is different or issuer is not Argo CD
|
||||
if updatedUsername != username || issuer != session.SessionManagerClaimsIssuer {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceAccounts, rbacpolicy.ActionUpdate, q.Name); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceAccounts, rbac.ActionUpdate, q.Name); err != nil {
|
||||
return nil, fmt.Errorf("permission denied: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -118,11 +118,11 @@ func (s *Server) UpdatePassword(ctx context.Context, q *account.UpdatePasswordRe
|
||||
|
||||
// CanI checks if the current account has permission to perform an action
|
||||
func (s *Server) CanI(ctx context.Context, r *account.CanIRequest) (*account.CanIResponse, error) {
|
||||
if !slice.ContainsString(rbacpolicy.Actions, r.Action, nil) {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "%v does not contain %s", rbacpolicy.Actions, r.Action)
|
||||
if !slice.ContainsString(rbac.Actions, r.Action, nil) {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "%v does not contain %s", rbac.Actions, r.Action)
|
||||
}
|
||||
if !slice.ContainsString(rbacpolicy.Resources, r.Resource, nil) {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "%v does not contain %s", rbacpolicy.Resources, r.Resource)
|
||||
if !slice.ContainsString(rbac.Resources, r.Resource, nil) {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "%v does not contain %s", rbac.Resources, r.Resource)
|
||||
}
|
||||
|
||||
// Logs RBAC will be enforced only if an internal var serverRBACLogEnforceEnable (representing server.rbac.log.enforce.enable env var)
|
||||
@@ -143,12 +143,11 @@ func (s *Server) CanI(ctx context.Context, r *account.CanIRequest) (*account.Can
|
||||
ok := s.enf.Enforce(ctx.Value("claims"), r.Resource, r.Action, r.Subresource)
|
||||
if ok {
|
||||
return &account.CanIResponse{Value: "yes"}, nil
|
||||
} else {
|
||||
return &account.CanIResponse{Value: "no"}, nil
|
||||
}
|
||||
return &account.CanIResponse{Value: "no"}, nil
|
||||
}
|
||||
|
||||
func toApiAccount(name string, a settings.Account) *account.Account {
|
||||
func toAPIAccount(name string, a settings.Account) *account.Account {
|
||||
var capabilities []string
|
||||
for _, c := range a.Capabilities {
|
||||
capabilities = append(capabilities, string(c))
|
||||
@@ -173,22 +172,22 @@ func (s *Server) ensureHasAccountPermission(ctx context.Context, action string,
|
||||
if session.Sub(ctx) == account && session.Iss(ctx) == session.SessionManagerClaimsIssuer {
|
||||
return nil
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceAccounts, action, account); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceAccounts, action, account); err != nil {
|
||||
return fmt.Errorf("permission denied for account %s with action %s: %w", account, action, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListAccounts returns the list of accounts
|
||||
func (s *Server) ListAccounts(ctx context.Context, r *account.ListAccountRequest) (*account.AccountsList, error) {
|
||||
func (s *Server) ListAccounts(ctx context.Context, _ *account.ListAccountRequest) (*account.AccountsList, error) {
|
||||
resp := account.AccountsList{}
|
||||
accounts, err := s.settingsMgr.GetAccounts()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get accounts: %w", err)
|
||||
}
|
||||
for name, a := range accounts {
|
||||
if err := s.ensureHasAccountPermission(ctx, rbacpolicy.ActionGet, name); err == nil {
|
||||
resp.Items = append(resp.Items, toApiAccount(name, a))
|
||||
if err := s.ensureHasAccountPermission(ctx, rbac.ActionGet, name); err == nil {
|
||||
resp.Items = append(resp.Items, toAPIAccount(name, a))
|
||||
}
|
||||
}
|
||||
sort.Slice(resp.Items, func(i, j int) bool {
|
||||
@@ -199,19 +198,19 @@ func (s *Server) ListAccounts(ctx context.Context, r *account.ListAccountRequest
|
||||
|
||||
// GetAccount returns an account
|
||||
func (s *Server) GetAccount(ctx context.Context, r *account.GetAccountRequest) (*account.Account, error) {
|
||||
if err := s.ensureHasAccountPermission(ctx, rbacpolicy.ActionGet, r.Name); err != nil {
|
||||
if err := s.ensureHasAccountPermission(ctx, rbac.ActionGet, r.Name); err != nil {
|
||||
return nil, fmt.Errorf("permission denied to get account %s: %w", r.Name, err)
|
||||
}
|
||||
a, err := s.settingsMgr.GetAccount(r.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get account %s: %w", r.Name, err)
|
||||
}
|
||||
return toApiAccount(r.Name, *a), nil
|
||||
return toAPIAccount(r.Name, *a), nil
|
||||
}
|
||||
|
||||
// CreateToken creates a token
|
||||
func (s *Server) CreateToken(ctx context.Context, r *account.CreateTokenRequest) (*account.CreateTokenResponse, error) {
|
||||
if err := s.ensureHasAccountPermission(ctx, rbacpolicy.ActionUpdate, r.Name); err != nil {
|
||||
if err := s.ensureHasAccountPermission(ctx, rbac.ActionUpdate, r.Name); err != nil {
|
||||
return nil, fmt.Errorf("permission denied to create token for account %s: %w", r.Name, err)
|
||||
}
|
||||
|
||||
@@ -259,7 +258,7 @@ func (s *Server) CreateToken(ctx context.Context, r *account.CreateTokenRequest)
|
||||
|
||||
// DeleteToken deletes a token
|
||||
func (s *Server) DeleteToken(ctx context.Context, r *account.DeleteTokenRequest) (*account.EmptyResponse, error) {
|
||||
if err := s.ensureHasAccountPermission(ctx, rbacpolicy.ActionUpdate, r.Name); err != nil {
|
||||
if err := s.ensureHasAccountPermission(ctx, rbac.ActionUpdate, r.Name); err != nil {
|
||||
return nil, fmt.Errorf("permission denied to delete account %s: %w", r.Name, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
@@ -45,7 +45,6 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
servercache "github.com/argoproj/argo-cd/v2/server/cache"
|
||||
"github.com/argoproj/argo-cd/v2/server/deeplinks"
|
||||
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
|
||||
"github.com/argoproj/argo-cd/v2/util/argo"
|
||||
argoutil "github.com/argoproj/argo-cd/v2/util/argo"
|
||||
cacheutil "github.com/argoproj/argo-cd/v2/util/cache"
|
||||
@@ -125,8 +124,8 @@ func NewServer(
|
||||
}
|
||||
s := &Server{
|
||||
ns: namespace,
|
||||
appclientset: appclientset,
|
||||
appLister: appLister,
|
||||
appclientset: &deepCopyAppClientset{appclientset},
|
||||
appLister: &deepCopyApplicationLister{appLister},
|
||||
appInformer: appInformer,
|
||||
appBroadcaster: appBroadcaster,
|
||||
kubeclientset: kubeclientset,
|
||||
@@ -159,7 +158,7 @@ func (s *Server) getAppEnforceRBAC(ctx context.Context, action, project, namespa
|
||||
if user == "" {
|
||||
user = "Unknown user"
|
||||
}
|
||||
logCtx := log.WithFields(map[string]interface{}{
|
||||
logCtx := log.WithFields(map[string]any{
|
||||
"user": user,
|
||||
"application": name,
|
||||
"namespace": namespace,
|
||||
@@ -167,8 +166,8 @@ func (s *Server) getAppEnforceRBAC(ctx context.Context, action, project, namespa
|
||||
if project != "" {
|
||||
// The user has provided everything we need to perform an initial RBAC check.
|
||||
givenRBACName := security.RBACName(s.ns, project, namespace, name)
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, action, givenRBACName); err != nil {
|
||||
logCtx.WithFields(map[string]interface{}{
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplications, action, givenRBACName); err != nil {
|
||||
logCtx.WithFields(map[string]any{
|
||||
"project": project,
|
||||
argocommon.SecurityField: argocommon.SecurityMedium,
|
||||
}).Warnf("user tried to %s application which they do not have access to: %s", action, err)
|
||||
@@ -181,10 +180,10 @@ func (s *Server) getAppEnforceRBAC(ctx context.Context, action, project, namespa
|
||||
}
|
||||
a, err := getApp()
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
if apierrors.IsNotFound(err) {
|
||||
if project != "" {
|
||||
// We know that the user was allowed to get the Application, but the Application does not exist. Return 404.
|
||||
return nil, nil, status.Error(codes.NotFound, apierr.NewNotFound(schema.GroupResource{Group: "argoproj.io", Resource: "applications"}, name).Error())
|
||||
return nil, nil, status.Error(codes.NotFound, apierrors.NewNotFound(schema.GroupResource{Group: "argoproj.io", Resource: "applications"}, name).Error())
|
||||
}
|
||||
// We don't know if the user was allowed to get the Application, and we don't want to leak information about
|
||||
// the Application's existence. Return 403.
|
||||
@@ -197,8 +196,8 @@ func (s *Server) getAppEnforceRBAC(ctx context.Context, action, project, namespa
|
||||
// Even if we performed an initial RBAC check (because the request was fully parameterized), we still need to
|
||||
// perform a second RBAC check to ensure that the user has access to the actual Application's project (not just the
|
||||
// project they specified in the request).
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, action, a.RBACName(s.ns)); err != nil {
|
||||
logCtx.WithFields(map[string]interface{}{
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplications, action, a.RBACName(s.ns)); err != nil {
|
||||
logCtx.WithFields(map[string]any{
|
||||
"project": a.Spec.Project,
|
||||
argocommon.SecurityField: argocommon.SecurityMedium,
|
||||
}).Warnf("user tried to %s application which they do not have access to: %s", action, err)
|
||||
@@ -206,7 +205,7 @@ func (s *Server) getAppEnforceRBAC(ctx context.Context, action, project, namespa
|
||||
// The user specified a project. We would have returned a 404 if the user had access to the app, but the app
|
||||
// did not exist. So we have to return a 404 when the app does exist, but the user does not have access.
|
||||
// Otherwise, they could infer that the app exists based on the error code.
|
||||
return nil, nil, status.Error(codes.NotFound, apierr.NewNotFound(schema.GroupResource{Group: "argoproj.io", Resource: "applications"}, name).Error())
|
||||
return nil, nil, status.Error(codes.NotFound, apierrors.NewNotFound(schema.GroupResource{Group: "argoproj.io", Resource: "applications"}, name).Error())
|
||||
}
|
||||
// The user didn't specify a project. We always return permission denied for both lack of access and lack of
|
||||
// existence.
|
||||
@@ -217,13 +216,13 @@ func (s *Server) getAppEnforceRBAC(ctx context.Context, action, project, namespa
|
||||
effectiveProject = a.Spec.Project
|
||||
}
|
||||
if project != "" && effectiveProject != project {
|
||||
logCtx.WithFields(map[string]interface{}{
|
||||
logCtx.WithFields(map[string]any{
|
||||
"project": a.Spec.Project,
|
||||
argocommon.SecurityField: argocommon.SecurityMedium,
|
||||
}).Warnf("user tried to %s application in project %s, but the application is in project %s", action, project, effectiveProject)
|
||||
// The user has access to the app, but the app is in a different project. Return 404, meaning "app doesn't
|
||||
// exist in that project".
|
||||
return nil, nil, status.Error(codes.NotFound, apierr.NewNotFound(schema.GroupResource{Group: "argoproj.io", Resource: "applications"}, name).Error())
|
||||
return nil, nil, status.Error(codes.NotFound, apierrors.NewNotFound(schema.GroupResource{Group: "argoproj.io", Resource: "applications"}, name).Error())
|
||||
}
|
||||
// Get the app's associated project, and make sure all project restrictions are enforced.
|
||||
proj, err := s.getAppProject(ctx, a, logCtx)
|
||||
@@ -293,7 +292,7 @@ func (s *Server) List(ctx context.Context, q *application.ApplicationQuery) (*ap
|
||||
if !s.isNamespaceEnabled(a.Namespace) {
|
||||
continue
|
||||
}
|
||||
if s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)) {
|
||||
if s.enf.Enforce(ctx.Value("claims"), rbac.ResourceApplications, rbac.ActionGet, a.RBACName(s.ns)) {
|
||||
newItems = append(newItems, *a)
|
||||
}
|
||||
}
|
||||
@@ -315,11 +314,11 @@ func (s *Server) List(ctx context.Context, q *application.ApplicationQuery) (*ap
|
||||
// Create creates an application
|
||||
func (s *Server) Create(ctx context.Context, q *application.ApplicationCreateRequest) (*appv1.Application, error) {
|
||||
if q.GetApplication() == nil {
|
||||
return nil, fmt.Errorf("error creating application: application is nil in request")
|
||||
return nil, errors.New("error creating application: application is nil in request")
|
||||
}
|
||||
a := q.GetApplication()
|
||||
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionCreate, a.RBACName(s.ns)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplications, rbac.ActionCreate, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -362,7 +361,7 @@ func (s *Server) Create(ctx context.Context, q *application.ApplicationCreateReq
|
||||
s.waitSync(created)
|
||||
return created, nil
|
||||
}
|
||||
if !apierr.IsAlreadyExists(err) {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return nil, fmt.Errorf("error creating application: %w", err)
|
||||
}
|
||||
|
||||
@@ -388,7 +387,7 @@ func (s *Server) Create(ctx context.Context, q *application.ApplicationCreateReq
|
||||
if q.Upsert == nil || !*q.Upsert {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "existing application spec is different, use upsert flag to force update")
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, a.RBACName(s.ns)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplications, rbac.ActionUpdate, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updated, err := s.updateApp(existing, a, ctx, true)
|
||||
@@ -443,9 +442,9 @@ func (s *Server) queryRepoServer(ctx context.Context, proj *appv1.AppProject, ac
|
||||
// GetManifests returns application manifests
|
||||
func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationManifestQuery) (*apiclient.ManifestResponse, error) {
|
||||
if q.Name == nil || *q.Name == "" {
|
||||
return nil, fmt.Errorf("invalid request: application name is missing")
|
||||
return nil, errors.New("invalid request: application name is missing")
|
||||
}
|
||||
a, proj, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName())
|
||||
a, proj, err := s.getApplicationEnforceRBACInformer(ctx, rbac.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -479,7 +478,7 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan
|
||||
}
|
||||
|
||||
sources := make([]appv1.ApplicationSource, 0)
|
||||
appSpec := a.Spec.DeepCopy()
|
||||
appSpec := a.Spec
|
||||
if a.Spec.HasMultipleSources() {
|
||||
numOfSources := int64(len(a.Spec.GetSources()))
|
||||
for i, pos := range q.SourcePositions {
|
||||
@@ -590,10 +589,10 @@ func (s *Server) GetManifestsWithFiles(stream application.ApplicationService_Get
|
||||
}
|
||||
|
||||
if query.Name == nil || *query.Name == "" {
|
||||
return fmt.Errorf("invalid request: application name is missing")
|
||||
return errors.New("invalid request: application name is missing")
|
||||
}
|
||||
|
||||
a, proj, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, query.GetProject(), query.GetAppNamespace(), query.GetName())
|
||||
a, proj, err := s.getApplicationEnforceRBACInformer(ctx, rbac.ActionGet, query.GetProject(), query.GetAppNamespace(), query.GetName())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -724,7 +723,7 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app
|
||||
// We must use a client Get instead of an informer Get, because it's common to call Get immediately
|
||||
// following a Watch (which is not yet powered by an informer), and the Get must reflect what was
|
||||
// previously seen by the client.
|
||||
a, proj, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, project, appNs, appName, q.GetResourceVersion())
|
||||
a, proj, err := s.getApplicationEnforceRBACClient(ctx, rbac.ActionGet, project, appNs, appName, q.GetResourceVersion())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -800,7 +799,7 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, fmt.Errorf("application refresh deadline exceeded")
|
||||
return nil, errors.New("application refresh deadline exceeded")
|
||||
case event := <-events:
|
||||
if appVersion, err := strconv.Atoi(event.Application.ResourceVersion); err == nil && appVersion > minVersion {
|
||||
annotations := event.Application.GetAnnotations()
|
||||
@@ -816,8 +815,8 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app
|
||||
}
|
||||
|
||||
// ListResourceEvents returns a list of event resources
|
||||
func (s *Server) ListResourceEvents(ctx context.Context, q *application.ApplicationResourceEventsQuery) (*v1.EventList, error) {
|
||||
a, _, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName())
|
||||
func (s *Server) ListResourceEvents(ctx context.Context, q *application.ApplicationResourceEventsQuery) (*corev1.EventList, error) {
|
||||
a, _, err := s.getApplicationEnforceRBACInformer(ctx, rbac.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -876,7 +875,7 @@ func (s *Server) ListResourceEvents(ctx context.Context, q *application.Applicat
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing resource events: %w", err)
|
||||
}
|
||||
return list, nil
|
||||
return list.DeepCopy(), nil
|
||||
}
|
||||
|
||||
// validateAndUpdateApp validates and updates the application. currentProject is the name of the project the app
|
||||
@@ -954,7 +953,7 @@ func (s *Server) updateApp(app *appv1.Application, newApp *appv1.Application, ct
|
||||
s.waitSync(res)
|
||||
return res, nil
|
||||
}
|
||||
if !apierr.IsConflict(err) {
|
||||
if !apierrors.IsConflict(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -970,10 +969,10 @@ func (s *Server) updateApp(app *appv1.Application, newApp *appv1.Application, ct
|
||||
// Update updates an application
|
||||
func (s *Server) Update(ctx context.Context, q *application.ApplicationUpdateRequest) (*appv1.Application, error) {
|
||||
if q.GetApplication() == nil {
|
||||
return nil, fmt.Errorf("error updating application: application is nil in request")
|
||||
return nil, errors.New("error updating application: application is nil in request")
|
||||
}
|
||||
a := q.GetApplication()
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, a.RBACName(s.ns)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplications, rbac.ActionUpdate, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -981,15 +980,15 @@ func (s *Server) Update(ctx context.Context, q *application.ApplicationUpdateReq
|
||||
if q.Validate != nil {
|
||||
validate = *q.Validate
|
||||
}
|
||||
return s.validateAndUpdateApp(ctx, q.Application, false, validate, rbacpolicy.ActionUpdate, q.GetProject())
|
||||
return s.validateAndUpdateApp(ctx, q.Application, false, validate, rbac.ActionUpdate, q.GetProject())
|
||||
}
|
||||
|
||||
// UpdateSpec updates an application spec and filters out any invalid parameter overrides
|
||||
func (s *Server) UpdateSpec(ctx context.Context, q *application.ApplicationUpdateSpecRequest) (*appv1.ApplicationSpec, error) {
|
||||
if q.GetSpec() == nil {
|
||||
return nil, fmt.Errorf("error updating application spec: spec is nil in request")
|
||||
return nil, errors.New("error updating application spec: spec is nil in request")
|
||||
}
|
||||
a, _, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionUpdate, q.GetProject(), q.GetAppNamespace(), q.GetName(), "")
|
||||
a, _, err := s.getApplicationEnforceRBACClient(ctx, rbac.ActionUpdate, q.GetProject(), q.GetAppNamespace(), q.GetName(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -999,7 +998,7 @@ func (s *Server) UpdateSpec(ctx context.Context, q *application.ApplicationUpdat
|
||||
if q.Validate != nil {
|
||||
validate = *q.Validate
|
||||
}
|
||||
a, err = s.validateAndUpdateApp(ctx, a, false, validate, rbacpolicy.ActionUpdate, q.GetProject())
|
||||
a, err = s.validateAndUpdateApp(ctx, a, false, validate, rbac.ActionUpdate, q.GetProject())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error validating and updating app: %w", err)
|
||||
}
|
||||
@@ -1008,12 +1007,12 @@ func (s *Server) UpdateSpec(ctx context.Context, q *application.ApplicationUpdat
|
||||
|
||||
// Patch patches an application
|
||||
func (s *Server) Patch(ctx context.Context, q *application.ApplicationPatchRequest) (*appv1.Application, error) {
|
||||
app, _, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName(), "")
|
||||
app, _, err := s.getApplicationEnforceRBACClient(ctx, rbac.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, app.RBACName(s.ns)); err != nil {
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplications, rbac.ActionUpdate, app.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1048,7 +1047,7 @@ func (s *Server) Patch(ctx context.Context, q *application.ApplicationPatchReque
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error unmarshaling patched app: %w", err)
|
||||
}
|
||||
return s.validateAndUpdateApp(ctx, newApp, false, true, rbacpolicy.ActionUpdate, q.GetProject())
|
||||
return s.validateAndUpdateApp(ctx, newApp, false, true, rbac.ActionUpdate, q.GetProject())
|
||||
}
|
||||
|
||||
func (s *Server) getAppProject(ctx context.Context, a *appv1.Application, logCtx *log.Entry) (*appv1.AppProject, error) {
|
||||
@@ -1060,13 +1059,13 @@ func (s *Server) getAppProject(ctx context.Context, a *appv1.Application, logCtx
|
||||
// If there's a permission issue or the app doesn't exist, return a vague error to avoid letting the user enumerate project names.
|
||||
vagueError := status.Errorf(codes.InvalidArgument, "app is not allowed in project %q, or the project does not exist", a.Spec.Project)
|
||||
|
||||
if apierr.IsNotFound(err) {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return nil, vagueError
|
||||
}
|
||||
|
||||
var applicationNotAllowedToUseProjectErr *appv1.ErrApplicationNotAllowedToUseProject
|
||||
if errors.As(err, &applicationNotAllowedToUseProjectErr) {
|
||||
logCtx.WithFields(map[string]interface{}{
|
||||
logCtx.WithFields(map[string]any{
|
||||
"project": a.Spec.Project,
|
||||
argocommon.SecurityField: argocommon.SecurityMedium,
|
||||
}).Warnf("error getting app project: %s", err)
|
||||
@@ -1080,7 +1079,7 @@ func (s *Server) getAppProject(ctx context.Context, a *appv1.Application, logCtx
|
||||
func (s *Server) Delete(ctx context.Context, q *application.ApplicationDeleteRequest) (*application.ApplicationResponse, error) {
|
||||
appName := q.GetName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
a, _, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, q.GetProject(), appNs, appName, "")
|
||||
a, _, err := s.getApplicationEnforceRBACClient(ctx, rbac.ActionGet, q.GetProject(), appNs, appName, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1088,7 +1087,7 @@ func (s *Server) Delete(ctx context.Context, q *application.ApplicationDeleteReq
|
||||
s.projectLock.RLock(a.Spec.Project)
|
||||
defer s.projectLock.RUnlock(a.Spec.Project)
|
||||
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionDelete, a.RBACName(s.ns)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplications, rbac.ActionDelete, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1116,8 +1115,8 @@ func (s *Server) Delete(ctx context.Context, q *application.ApplicationDeleteReq
|
||||
// Although the cascaded deletion/propagation policy finalizer is not set when apps are created via
|
||||
// API, they will often be set by the user as part of declarative config. As part of a delete
|
||||
// request, we always calculate the patch to see if we need to set/unset the finalizer.
|
||||
patch, err := json.Marshal(map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
patch, err := json.Marshal(map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"finalizers": a.Finalizers,
|
||||
},
|
||||
})
|
||||
@@ -1155,7 +1154,7 @@ func (s *Server) isApplicationPermitted(selector labels.Selector, minVersion int
|
||||
return false
|
||||
}
|
||||
|
||||
if !s.enf.Enforce(claims, rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)) {
|
||||
if !s.enf.Enforce(claims, rbac.ResourceApplications, rbac.ActionGet, a.RBACName(s.ns)) {
|
||||
// do not emit apps user does not have accessing
|
||||
return false
|
||||
}
|
||||
@@ -1235,7 +1234,7 @@ func (s *Server) Watch(q *application.ApplicationQuery, ws application.Applicati
|
||||
|
||||
func (s *Server) validateAndNormalizeApp(ctx context.Context, app *appv1.Application, proj *appv1.AppProject, validate bool) error {
|
||||
if app.GetName() == "" {
|
||||
return fmt.Errorf("resource name may not be empty")
|
||||
return errors.New("resource name may not be empty")
|
||||
}
|
||||
|
||||
// ensure sources names are unique
|
||||
@@ -1252,7 +1251,7 @@ func (s *Server) validateAndNormalizeApp(ctx context.Context, app *appv1.Applica
|
||||
appNs := s.appNamespaceOrDefault(app.Namespace)
|
||||
currApp, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, app.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if !apierr.IsNotFound(err) {
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return fmt.Errorf("error getting application by name: %w", err)
|
||||
}
|
||||
// Kubernetes go-client will return a pointer to a zero-value app instead of nil, even
|
||||
@@ -1262,11 +1261,11 @@ func (s *Server) validateAndNormalizeApp(ctx context.Context, app *appv1.Applica
|
||||
if currApp != nil && currApp.Spec.GetProject() != app.Spec.GetProject() {
|
||||
// When changing projects, caller must have application create & 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.ResourceApplications, rbacpolicy.ActionCreate, app.RBACName(s.ns)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplications, rbac.ActionCreate, app.RBACName(s.ns)); err != nil {
|
||||
return err
|
||||
}
|
||||
// They also need 'update' privileges in the old project
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, currApp.RBACName(s.ns)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplications, rbac.ActionUpdate, currApp.RBACName(s.ns)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -1361,11 +1360,11 @@ func (s *Server) getAppLiveResource(ctx context.Context, action string, q *appli
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
if fineGrainedInheritanceDisabled && (action == rbacpolicy.ActionDelete || action == rbacpolicy.ActionUpdate) {
|
||||
if fineGrainedInheritanceDisabled && (action == rbac.ActionDelete || action == rbac.ActionUpdate) {
|
||||
action = fmt.Sprintf("%s/%s/%s/%s/%s", action, q.GetGroup(), q.GetKind(), q.GetNamespace(), q.GetResourceName())
|
||||
}
|
||||
a, _, err := s.getApplicationEnforceRBACInformer(ctx, action, q.GetProject(), q.GetAppNamespace(), q.GetName())
|
||||
if !fineGrainedInheritanceDisabled && err != nil && errors.Is(err, argocommon.PermissionDeniedAPIError) && (action == rbacpolicy.ActionDelete || action == rbacpolicy.ActionUpdate) {
|
||||
if !fineGrainedInheritanceDisabled && err != nil && errors.Is(err, argocommon.PermissionDeniedAPIError) && (action == rbac.ActionDelete || action == rbac.ActionUpdate) {
|
||||
action = fmt.Sprintf("%s/%s/%s/%s/%s", action, q.GetGroup(), q.GetKind(), q.GetNamespace(), q.GetResourceName())
|
||||
a, _, err = s.getApplicationEnforceRBACInformer(ctx, action, q.GetProject(), q.GetAppNamespace(), q.GetName())
|
||||
}
|
||||
@@ -1390,7 +1389,7 @@ func (s *Server) getAppLiveResource(ctx context.Context, action string, q *appli
|
||||
}
|
||||
|
||||
func (s *Server) GetResource(ctx context.Context, q *application.ApplicationResourceRequest) (*application.ApplicationResourceResponse, error) {
|
||||
res, config, _, err := s.getAppLiveResource(ctx, rbacpolicy.ActionGet, q)
|
||||
res, config, _, err := s.getAppLiveResource(ctx, rbac.ActionGet, q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1438,7 +1437,7 @@ func (s *Server) PatchResource(ctx context.Context, q *application.ApplicationRe
|
||||
Group: q.Group,
|
||||
Project: q.Project,
|
||||
}
|
||||
res, config, a, err := s.getAppLiveResource(ctx, rbacpolicy.ActionUpdate, resourceRequest)
|
||||
res, config, a, err := s.getAppLiveResource(ctx, rbac.ActionUpdate, resourceRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1452,7 +1451,7 @@ func (s *Server) PatchResource(ctx context.Context, q *application.ApplicationRe
|
||||
return nil, fmt.Errorf("error patching resource: %w", err)
|
||||
}
|
||||
if manifest == nil {
|
||||
return nil, fmt.Errorf("failed to patch resource: manifest was nil")
|
||||
return nil, errors.New("failed to patch resource: manifest was nil")
|
||||
}
|
||||
manifest, err = s.replaceSecretValues(manifest)
|
||||
if err != nil {
|
||||
@@ -1481,19 +1480,20 @@ func (s *Server) DeleteResource(ctx context.Context, q *application.ApplicationR
|
||||
Group: q.Group,
|
||||
Project: q.Project,
|
||||
}
|
||||
res, config, a, err := s.getAppLiveResource(ctx, rbacpolicy.ActionDelete, resourceRequest)
|
||||
res, config, a, err := s.getAppLiveResource(ctx, rbac.ActionDelete, resourceRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var deleteOption metav1.DeleteOptions
|
||||
if q.GetOrphan() {
|
||||
switch {
|
||||
case q.GetOrphan():
|
||||
propagationPolicy := metav1.DeletePropagationOrphan
|
||||
deleteOption = metav1.DeleteOptions{PropagationPolicy: &propagationPolicy}
|
||||
} else if q.GetForce() {
|
||||
case q.GetForce():
|
||||
propagationPolicy := metav1.DeletePropagationBackground
|
||||
zeroGracePeriod := int64(0)
|
||||
deleteOption = metav1.DeleteOptions{PropagationPolicy: &propagationPolicy, GracePeriodSeconds: &zeroGracePeriod}
|
||||
} else {
|
||||
default:
|
||||
propagationPolicy := metav1.DeletePropagationForeground
|
||||
deleteOption = metav1.DeleteOptions{PropagationPolicy: &propagationPolicy}
|
||||
}
|
||||
@@ -1506,7 +1506,7 @@ func (s *Server) DeleteResource(ctx context.Context, q *application.ApplicationR
|
||||
}
|
||||
|
||||
func (s *Server) ResourceTree(ctx context.Context, q *application.ResourcesQuery) (*appv1.ApplicationTree, error) {
|
||||
a, _, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetApplicationName())
|
||||
a, _, err := s.getApplicationEnforceRBACInformer(ctx, rbac.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetApplicationName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1515,7 +1515,7 @@ func (s *Server) ResourceTree(ctx context.Context, q *application.ResourcesQuery
|
||||
}
|
||||
|
||||
func (s *Server) WatchResourceTree(q *application.ResourcesQuery, ws application.ApplicationService_WatchResourceTreeServer) error {
|
||||
_, _, err := s.getApplicationEnforceRBACInformer(ws.Context(), rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetApplicationName())
|
||||
_, _, err := s.getApplicationEnforceRBACInformer(ws.Context(), rbac.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetApplicationName())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1532,7 +1532,7 @@ func (s *Server) WatchResourceTree(q *application.ResourcesQuery, ws application
|
||||
}
|
||||
|
||||
func (s *Server) RevisionMetadata(ctx context.Context, q *application.RevisionMetadataQuery) (*appv1.RevisionMetadata, error) {
|
||||
a, proj, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName())
|
||||
a, proj, err := s.getApplicationEnforceRBACInformer(ctx, rbac.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1560,7 +1560,7 @@ func (s *Server) RevisionMetadata(ctx context.Context, q *application.RevisionMe
|
||||
|
||||
// RevisionChartDetails returns the helm chart metadata, as fetched from the reposerver
|
||||
func (s *Server) RevisionChartDetails(ctx context.Context, q *application.RevisionMetadataQuery) (*appv1.ChartDetails, error) {
|
||||
a, _, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName())
|
||||
a, _, err := s.getApplicationEnforceRBACInformer(ctx, rbac.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1667,7 +1667,7 @@ func isMatchingResource(q *application.ResourcesQuery, key kube.ResourceKey) boo
|
||||
}
|
||||
|
||||
func (s *Server) ManagedResources(ctx context.Context, q *application.ResourcesQuery) (*application.ManagedResourcesResponse, error) {
|
||||
a, _, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetApplicationName())
|
||||
a, _, err := s.getApplicationEnforceRBACInformer(ctx, rbac.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetApplicationName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1706,12 +1706,12 @@ func (s *Server) PodLogs(q *application.ApplicationPodLogsQuery, ws application.
|
||||
}
|
||||
var untilTime *metav1.Time
|
||||
if q.GetUntilTime() != "" {
|
||||
if val, err := time.Parse(time.RFC3339Nano, q.GetUntilTime()); err != nil {
|
||||
val, err := time.Parse(time.RFC3339Nano, q.GetUntilTime())
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid untilTime parameter value: %w", err)
|
||||
} else {
|
||||
untilTimeVal := metav1.NewTime(val)
|
||||
untilTime = &untilTimeVal
|
||||
}
|
||||
untilTimeVal := metav1.NewTime(val)
|
||||
untilTime = &untilTimeVal
|
||||
}
|
||||
|
||||
literal := ""
|
||||
@@ -1724,7 +1724,7 @@ func (s *Server) PodLogs(q *application.ApplicationPodLogsQuery, ws application.
|
||||
}
|
||||
}
|
||||
|
||||
a, _, err := s.getApplicationEnforceRBACInformer(ws.Context(), rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName())
|
||||
a, _, err := s.getApplicationEnforceRBACInformer(ws.Context(), rbac.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1739,7 +1739,7 @@ func (s *Server) PodLogs(q *application.ApplicationPodLogsQuery, ws application.
|
||||
}
|
||||
|
||||
if serverRBACLogEnforceEnable {
|
||||
if err := s.enf.EnforceErr(ws.Context().Value("claims"), rbacpolicy.ResourceLogs, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
if err := s.enf.EnforceErr(ws.Context().Value("claims"), rbac.ResourceLogs, rbac.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -1777,7 +1777,7 @@ func (s *Server) PodLogs(q *application.ApplicationPodLogsQuery, ws application.
|
||||
var streams []chan logEntry
|
||||
|
||||
for _, pod := range pods {
|
||||
stream, err := kubeClientset.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &v1.PodLogOptions{
|
||||
stream, err := kubeClientset.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &corev1.PodLogOptions{
|
||||
Container: q.GetContainer(),
|
||||
Follow: q.GetFollow(),
|
||||
Timestamps: true,
|
||||
@@ -1813,37 +1813,35 @@ func (s *Server) PodLogs(q *application.ApplicationPodLogsQuery, ws application.
|
||||
if entry.err != nil {
|
||||
done <- entry.err
|
||||
return
|
||||
} else {
|
||||
if q.Filter != nil {
|
||||
lineContainsFilter := strings.Contains(entry.line, literal)
|
||||
if (inverse && lineContainsFilter) || (!inverse && !lineContainsFilter) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
ts := metav1.NewTime(entry.timeStamp)
|
||||
if untilTime != nil && entry.timeStamp.After(untilTime.Time) {
|
||||
done <- ws.Send(&application.LogEntry{
|
||||
Last: ptr.To(true),
|
||||
PodName: &entry.podName,
|
||||
Content: &entry.line,
|
||||
TimeStampStr: ptr.To(entry.timeStamp.Format(time.RFC3339Nano)),
|
||||
TimeStamp: &ts,
|
||||
})
|
||||
return
|
||||
} else {
|
||||
sentCount++
|
||||
if err := ws.Send(&application.LogEntry{
|
||||
PodName: &entry.podName,
|
||||
Content: &entry.line,
|
||||
TimeStampStr: ptr.To(entry.timeStamp.Format(time.RFC3339Nano)),
|
||||
TimeStamp: &ts,
|
||||
Last: ptr.To(false),
|
||||
}); err != nil {
|
||||
done <- err
|
||||
break
|
||||
}
|
||||
}
|
||||
if q.Filter != nil {
|
||||
lineContainsFilter := strings.Contains(entry.line, literal)
|
||||
if (inverse && lineContainsFilter) || (!inverse && !lineContainsFilter) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
ts := metav1.NewTime(entry.timeStamp)
|
||||
if untilTime != nil && entry.timeStamp.After(untilTime.Time) {
|
||||
done <- ws.Send(&application.LogEntry{
|
||||
Last: ptr.To(true),
|
||||
PodName: &entry.podName,
|
||||
Content: &entry.line,
|
||||
TimeStampStr: ptr.To(entry.timeStamp.Format(time.RFC3339Nano)),
|
||||
TimeStamp: &ts,
|
||||
})
|
||||
return
|
||||
}
|
||||
sentCount++
|
||||
if err := ws.Send(&application.LogEntry{
|
||||
PodName: &entry.podName,
|
||||
Content: &entry.line,
|
||||
TimeStampStr: ptr.To(entry.timeStamp.Format(time.RFC3339Nano)),
|
||||
TimeStamp: &ts,
|
||||
Last: ptr.To(false),
|
||||
}); err != nil {
|
||||
done <- err
|
||||
break
|
||||
}
|
||||
}
|
||||
now := time.Now()
|
||||
nowTS := metav1.NewTime(now)
|
||||
@@ -1921,7 +1919,7 @@ func isTheSelectedOne(currentNode *appv1.ResourceNode, q *application.Applicatio
|
||||
|
||||
// Sync syncs an application to its target state
|
||||
func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncRequest) (*appv1.Application, error) {
|
||||
a, proj, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, syncReq.GetProject(), syncReq.GetAppNamespace(), syncReq.GetName(), "")
|
||||
a, proj, err := s.getApplicationEnforceRBACClient(ctx, rbac.ActionGet, syncReq.GetProject(), syncReq.GetAppNamespace(), syncReq.GetName(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1936,12 +1934,12 @@ func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncR
|
||||
return a, status.Errorf(codes.PermissionDenied, "cannot sync: blocked by sync window")
|
||||
}
|
||||
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionSync, a.RBACName(s.ns)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplications, rbac.ActionSync, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if syncReq.Manifests != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionOverride, a.RBACName(s.ns)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplications, rbac.ActionOverride, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if a.Spec.SyncPolicy != nil && a.Spec.SyncPolicy.Automated != nil && !syncReq.GetDryRun() {
|
||||
@@ -2035,7 +2033,7 @@ func (s *Server) resolveSourceRevisions(ctx context.Context, a *appv1.Applicatio
|
||||
sources := a.Spec.GetSources()
|
||||
for i, pos := range syncReq.SourcePositions {
|
||||
if pos <= 0 || pos > numOfSources {
|
||||
return "", "", nil, nil, fmt.Errorf("source position is out of range")
|
||||
return "", "", nil, nil, errors.New("source position is out of range")
|
||||
}
|
||||
sources[pos-1].TargetRevision = syncReq.Revisions[i]
|
||||
}
|
||||
@@ -2053,23 +2051,22 @@ func (s *Server) resolveSourceRevisions(ctx context.Context, a *appv1.Applicatio
|
||||
displayRevisions[index] = displayRevision
|
||||
}
|
||||
return "", "", sourceRevisions, displayRevisions, nil
|
||||
} else {
|
||||
source := a.Spec.GetSource()
|
||||
if a.Spec.SyncPolicy != nil && a.Spec.SyncPolicy.Automated != nil && !syncReq.GetDryRun() {
|
||||
if syncReq.GetRevision() != "" && syncReq.GetRevision() != text.FirstNonEmpty(source.TargetRevision, "HEAD") {
|
||||
return "", "", nil, nil, status.Errorf(codes.FailedPrecondition, "Cannot sync to %s: auto-sync currently set to %s", syncReq.GetRevision(), source.TargetRevision)
|
||||
}
|
||||
}
|
||||
revision, displayRevision, err := s.resolveRevision(ctx, a, syncReq, -1)
|
||||
if err != nil {
|
||||
return "", "", nil, nil, status.Error(codes.FailedPrecondition, err.Error())
|
||||
}
|
||||
return revision, displayRevision, nil, nil, nil
|
||||
}
|
||||
source := a.Spec.GetSource()
|
||||
if a.Spec.SyncPolicy != nil && a.Spec.SyncPolicy.Automated != nil && !syncReq.GetDryRun() {
|
||||
if syncReq.GetRevision() != "" && syncReq.GetRevision() != text.FirstNonEmpty(source.TargetRevision, "HEAD") {
|
||||
return "", "", nil, nil, status.Errorf(codes.FailedPrecondition, "Cannot sync to %s: auto-sync currently set to %s", syncReq.GetRevision(), source.TargetRevision)
|
||||
}
|
||||
}
|
||||
revision, displayRevision, err := s.resolveRevision(ctx, a, syncReq, -1)
|
||||
if err != nil {
|
||||
return "", "", nil, nil, status.Error(codes.FailedPrecondition, err.Error())
|
||||
}
|
||||
return revision, displayRevision, nil, nil, nil
|
||||
}
|
||||
|
||||
func (s *Server) Rollback(ctx context.Context, rollbackReq *application.ApplicationRollbackRequest) (*appv1.Application, error) {
|
||||
a, _, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionSync, rollbackReq.GetProject(), rollbackReq.GetAppNamespace(), rollbackReq.GetName(), "")
|
||||
a, _, err := s.getApplicationEnforceRBACClient(ctx, rbac.ActionSync, rollbackReq.GetProject(), rollbackReq.GetAppNamespace(), rollbackReq.GetName(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2131,7 +2128,7 @@ func (s *Server) Rollback(ctx context.Context, rollbackReq *application.Applicat
|
||||
}
|
||||
|
||||
func (s *Server) ListLinks(ctx context.Context, req *application.ListAppLinksRequest) (*application.LinksResponse, error) {
|
||||
a, proj, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, req.GetProject(), req.GetNamespace(), req.GetName(), "")
|
||||
a, proj, err := s.getApplicationEnforceRBACClient(ctx, rbac.ActionGet, req.GetProject(), req.GetNamespace(), req.GetName(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2205,7 +2202,7 @@ func (s *Server) getObjectsForDeepLinks(ctx context.Context, app *appv1.Applicat
|
||||
}
|
||||
|
||||
func (s *Server) ListResourceLinks(ctx context.Context, req *application.ApplicationResourceRequest) (*application.LinksResponse, error) {
|
||||
obj, _, app, _, err := s.getUnstructuredLiveResourceOrApp(ctx, rbacpolicy.ActionGet, req)
|
||||
obj, _, app, _, err := s.getUnstructuredLiveResourceOrApp(ctx, rbac.ActionGet, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2272,12 +2269,12 @@ func (s *Server) resolveRevision(ctx context.Context, app *appv1.Application, sy
|
||||
|
||||
ambiguousRevision := getAmbiguousRevision(app, syncReq, sourceIndex)
|
||||
|
||||
repoUrl := app.Spec.GetSource().RepoURL
|
||||
repoURL := app.Spec.GetSource().RepoURL
|
||||
if app.Spec.HasMultipleSources() {
|
||||
repoUrl = app.Spec.Sources[sourceIndex].RepoURL
|
||||
repoURL = app.Spec.Sources[sourceIndex].RepoURL
|
||||
}
|
||||
|
||||
repo, err := s.db.GetRepository(ctx, repoUrl, app.Spec.Project)
|
||||
repo, err := s.db.GetRepository(ctx, repoURL, app.Spec.Project)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("error getting repository by URL: %w", err)
|
||||
}
|
||||
@@ -2310,7 +2307,7 @@ func (s *Server) resolveRevision(ctx context.Context, app *appv1.Application, sy
|
||||
func (s *Server) TerminateOperation(ctx context.Context, termOpReq *application.OperationTerminateRequest) (*application.OperationTerminateResponse, error) {
|
||||
appName := termOpReq.GetName()
|
||||
appNs := s.appNamespaceOrDefault(termOpReq.GetAppNamespace())
|
||||
a, _, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionSync, termOpReq.GetProject(), appNs, appName, "")
|
||||
a, _, err := s.getApplicationEnforceRBACClient(ctx, rbac.ActionSync, termOpReq.GetProject(), appNs, appName, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2326,12 +2323,12 @@ func (s *Server) TerminateOperation(ctx context.Context, termOpReq *application.
|
||||
s.logAppEvent(a, ctx, argo.EventReasonResourceUpdated, "terminated running operation")
|
||||
return &application.OperationTerminateResponse{}, nil
|
||||
}
|
||||
if !apierr.IsConflict(err) {
|
||||
if !apierrors.IsConflict(err) {
|
||||
return nil, fmt.Errorf("error updating application: %w", err)
|
||||
}
|
||||
log.Warnf("failed to set operation for app %q due to update conflict. retrying again...", *termOpReq.Name)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
a, err = s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{})
|
||||
_, err = s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application by name: %w", err)
|
||||
}
|
||||
@@ -2340,7 +2337,7 @@ func (s *Server) TerminateOperation(ctx context.Context, termOpReq *application.
|
||||
}
|
||||
|
||||
func (s *Server) logAppEvent(a *appv1.Application, ctx context.Context, reason string, action string) {
|
||||
eventInfo := argo.EventInfo{Type: v1.EventTypeNormal, Reason: reason}
|
||||
eventInfo := argo.EventInfo{Type: corev1.EventTypeNormal, Reason: reason}
|
||||
user := session.Username(ctx)
|
||||
if user == "" {
|
||||
user = "Unknown user"
|
||||
@@ -2351,7 +2348,7 @@ func (s *Server) logAppEvent(a *appv1.Application, ctx context.Context, reason s
|
||||
}
|
||||
|
||||
func (s *Server) logResourceEvent(res *appv1.ResourceNode, ctx context.Context, reason string, action string) {
|
||||
eventInfo := argo.EventInfo{Type: v1.EventTypeNormal, Reason: reason}
|
||||
eventInfo := argo.EventInfo{Type: corev1.EventTypeNormal, Reason: reason}
|
||||
user := session.Username(ctx)
|
||||
if user == "" {
|
||||
user = "Unknown user"
|
||||
@@ -2361,7 +2358,7 @@ func (s *Server) logResourceEvent(res *appv1.ResourceNode, ctx context.Context,
|
||||
}
|
||||
|
||||
func (s *Server) ListResourceActions(ctx context.Context, q *application.ApplicationResourceRequest) (*application.ResourceActionsListResponse, error) {
|
||||
obj, _, _, _, err := s.getUnstructuredLiveResourceOrApp(ctx, rbacpolicy.ActionGet, q)
|
||||
obj, _, _, _, err := s.getUnstructuredLiveResourceOrApp(ctx, rbac.ActionGet, q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2388,7 +2385,7 @@ func (s *Server) getUnstructuredLiveResourceOrApp(ctx context.Context, rbacReque
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacRequest, app.RBACName(s.ns)); err != nil {
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplications, rbacRequest, app.RBACName(s.ns)); err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
config, err = s.getApplicationClusterConfig(ctx, app)
|
||||
@@ -2439,7 +2436,7 @@ func (s *Server) RunResourceAction(ctx context.Context, q *application.ResourceA
|
||||
Group: q.Group,
|
||||
Project: q.Project,
|
||||
}
|
||||
actionRequest := fmt.Sprintf("%s/%s/%s/%s", rbacpolicy.ActionAction, q.GetGroup(), q.GetKind(), q.GetAction())
|
||||
actionRequest := fmt.Sprintf("%s/%s/%s/%s", rbac.ActionAction, q.GetGroup(), q.GetKind(), q.GetAction())
|
||||
liveObj, res, a, config, err := s.getUnstructuredLiveResourceOrApp(ctx, actionRequest, resourceRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -2483,6 +2480,12 @@ func (s *Server) RunResourceAction(ctx context.Context, q *application.ResourceA
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Validate the destination, which has the side effect of populating the cluster name and server URL in the app
|
||||
// spec. This ensures that calls to `verifyResourcePermitted` below act on a fully-populated app spec.
|
||||
if err = argo.ValidateDestination(ctx, &app.Spec.Destination, s.db); err != nil {
|
||||
return nil, fmt.Errorf("error validating destination cluster: %w", err)
|
||||
}
|
||||
|
||||
// First, make sure all the returned resources are permitted, for each operation.
|
||||
// Also perform create with dry-runs for all create-operation resources.
|
||||
// This is performed separately to reduce the risk of only some of the resources being successfully created later.
|
||||
@@ -2494,8 +2497,7 @@ func (s *Server) RunResourceAction(ctx context.Context, q *application.ResourceA
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch impactedResource.K8SOperation {
|
||||
case lua.CreateOperation:
|
||||
if impactedResource.K8SOperation == lua.CreateOperation {
|
||||
createOptions := metav1.CreateOptions{DryRun: []string{"All"}}
|
||||
_, err := s.kubectl.CreateResource(ctx, config, newObj.GroupVersionKind(), newObj.GetName(), newObj.GetNamespace(), newObj, createOptions)
|
||||
if err != nil {
|
||||
@@ -2563,7 +2565,7 @@ func (s *Server) patchResource(ctx context.Context, config *rest.Config, liveObj
|
||||
if statusPatch != nil {
|
||||
_, err = s.kubectl.PatchResource(ctx, config, newObj.GroupVersionKind(), newObj.GetName(), newObj.GetNamespace(), types.MergePatchType, diffBytes, "status")
|
||||
if err != nil {
|
||||
if !apierr.IsNotFound(err) {
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return nil, fmt.Errorf("error patching resource: %w", err)
|
||||
}
|
||||
// K8s API server returns 404 NotFound when the CRD does not support the status subresource
|
||||
@@ -2612,7 +2614,7 @@ func (s *Server) createResource(ctx context.Context, config *rest.Config, newObj
|
||||
// splitStatusPatch splits a patch into two: one for a non-status patch, and the status-only patch.
|
||||
// Returns nil for either if the patch doesn't have modifications to non-status, or status, respectively.
|
||||
func splitStatusPatch(patch []byte) ([]byte, []byte, error) {
|
||||
var obj map[string]interface{}
|
||||
var obj map[string]any
|
||||
err := json.Unmarshal(patch, &obj)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -2620,7 +2622,7 @@ func splitStatusPatch(patch []byte) ([]byte, []byte, error) {
|
||||
var nonStatusPatch, statusPatch []byte
|
||||
if statusVal, ok := obj["status"]; ok {
|
||||
// calculate the status-only patch
|
||||
statusObj := map[string]interface{}{
|
||||
statusObj := map[string]any{
|
||||
"status": statusVal,
|
||||
}
|
||||
statusPatch, err = json.Marshal(statusObj)
|
||||
@@ -2643,7 +2645,7 @@ func splitStatusPatch(patch []byte) ([]byte, []byte, error) {
|
||||
}
|
||||
|
||||
func (s *Server) GetApplicationSyncWindows(ctx context.Context, q *application.ApplicationSyncWindowsQuery) (*application.ApplicationSyncWindowsResponse, error) {
|
||||
a, proj, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName(), "")
|
||||
a, proj, err := s.getApplicationEnforceRBACClient(ctx, rbac.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2670,7 +2672,7 @@ func (s *Server) GetApplicationSyncWindows(ctx context.Context, q *application.A
|
||||
func (s *Server) inferResourcesStatusHealth(app *appv1.Application) {
|
||||
if app.Status.ResourceHealthSource == appv1.ResourceHealthLocationAppTree {
|
||||
tree := &appv1.ApplicationTree{}
|
||||
if err := s.cache.GetAppResourcesTree(app.Name, tree); err == nil {
|
||||
if err := s.cache.GetAppResourcesTree(app.InstanceName(s.ns), tree); err == nil {
|
||||
healthByKey := map[kube.ResourceKey]*appv1.HealthStatus{}
|
||||
for _, node := range tree.Nodes {
|
||||
healthByKey[kube.NewResourceKey(node.Group, node.Kind, node.Namespace, node.Name)] = node.Health
|
||||
@@ -2718,9 +2720,8 @@ func getPropagationPolicyFinalizer(policy string) string {
|
||||
func (s *Server) appNamespaceOrDefault(appNs string) string {
|
||||
if appNs == "" {
|
||||
return s.ns
|
||||
} else {
|
||||
return appNs
|
||||
}
|
||||
return appNs
|
||||
}
|
||||
|
||||
func (s *Server) isNamespaceEnabled(namespace string) bool {
|
||||
|
||||
@@ -5,13 +5,13 @@ import (
|
||||
coreerrors "errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"github.com/argoproj/gitops-engine/pkg/health"
|
||||
synccommon "github.com/argoproj/gitops-engine/pkg/sync/common"
|
||||
"github.com/argoproj/gitops-engine/pkg/utils/kube"
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
@@ -1554,7 +1555,7 @@ func TestDeleteApp(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, app)
|
||||
|
||||
fakeAppCs := appServer.appclientset.(*apps.Clientset)
|
||||
fakeAppCs := appServer.appclientset.(*deepCopyAppClientset).GetUnderlyingClientSet().(*apps.Clientset)
|
||||
// this removes the default */* reactor so we can set our own patch/delete reactor
|
||||
fakeAppCs.ReactionChain = nil
|
||||
patched := false
|
||||
@@ -2076,9 +2077,9 @@ func TestGetCachedAppState(t *testing.T) {
|
||||
},
|
||||
}
|
||||
appServer := newTestAppServer(t, testApp, testProj)
|
||||
fakeClientSet := appServer.appclientset.(*apps.Clientset)
|
||||
fakeClientSet.AddReactor("get", "applications", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, &appsv1.Application{Spec: appsv1.ApplicationSpec{Source: &appsv1.ApplicationSource{}}}, nil
|
||||
fakeClientSet := appServer.appclientset.(*deepCopyAppClientset).GetUnderlyingClientSet().(*apps.Clientset)
|
||||
fakeClientSet.AddReactor("get", "applications", func(_ kubetesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, &appv1.Application{Spec: appv1.ApplicationSpec{Source: &appv1.ApplicationSource{}}}, nil
|
||||
})
|
||||
t.Run("NoError", func(t *testing.T) {
|
||||
err := appServer.getCachedAppState(context.Background(), testApp, func() error {
|
||||
@@ -2338,7 +2339,6 @@ func refreshAnnotationRemover(t *testing.T, ctx context.Context, patched *int32,
|
||||
aName, appNs := argo.ParseFromQualifiedName(appName, appServer.ns)
|
||||
a, err := appServer.appLister.Applications(appNs).Get(aName)
|
||||
require.NoError(t, err)
|
||||
a = a.DeepCopy()
|
||||
if a.GetAnnotations() != nil && a.GetAnnotations()[appsv1.AnnotationKeyRefresh] != "" {
|
||||
a.SetAnnotations(map[string]string{})
|
||||
a.SetResourceVersion("999")
|
||||
@@ -3358,3 +3358,274 @@ func Test_RevisionMetadata(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_DeepCopyInformers(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
namespace := "test-namespace"
|
||||
var ro []runtime.Object
|
||||
appOne := newTestApp(func(app *appsv1.Application) {
|
||||
app.Name = "appOne"
|
||||
app.ObjectMeta.Namespace = namespace
|
||||
app.Spec = appsv1.ApplicationSpec{}
|
||||
})
|
||||
appTwo := newTestApp(func(app *appsv1.Application) {
|
||||
app.Name = "appTwo"
|
||||
app.ObjectMeta.Namespace = namespace
|
||||
app.Spec = appsv1.ApplicationSpec{}
|
||||
})
|
||||
appThree := newTestApp(func(app *appsv1.Application) {
|
||||
app.Name = "appThree"
|
||||
app.ObjectMeta.Namespace = namespace
|
||||
app.Spec = appsv1.ApplicationSpec{}
|
||||
})
|
||||
ro = append(ro, appOne, appTwo, appThree)
|
||||
appls := []appsv1.Application{*appOne, *appTwo, *appThree}
|
||||
|
||||
appSetOne := &appsv1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "appSetOne", Namespace: namespace},
|
||||
Spec: appsv1.ApplicationSetSpec{},
|
||||
}
|
||||
appSetTwo := &appsv1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "appSetTwo", Namespace: namespace},
|
||||
Spec: appsv1.ApplicationSetSpec{},
|
||||
}
|
||||
appSetThree := &appsv1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "appSetThree", Namespace: namespace},
|
||||
Spec: appsv1.ApplicationSetSpec{},
|
||||
}
|
||||
ro = append(ro, appSetOne, appSetTwo, appSetThree)
|
||||
appSets := []appsv1.ApplicationSet{*appSetOne, *appSetTwo, *appSetThree}
|
||||
|
||||
appProjects := createAppProject("projOne", "projTwo", "projThree")
|
||||
for i := range appProjects {
|
||||
ro = append(ro, &appProjects[i])
|
||||
}
|
||||
|
||||
s := newTestAppServer(t, ro...)
|
||||
|
||||
appList, err := s.appclientset.ArgoprojV1alpha1().Applications(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.ElementsMatch(t, appls, appList.Items)
|
||||
sAppList := appList.Items
|
||||
slices.SortFunc(sAppList, func(a, b appsv1.Application) int {
|
||||
return strings.Compare(a.Name, b.Name)
|
||||
})
|
||||
slices.SortFunc(appls, func(a, b appsv1.Application) int {
|
||||
return strings.Compare(a.Name, b.Name)
|
||||
})
|
||||
// ensure there is a deep copy
|
||||
for i := range appls {
|
||||
assert.NotSame(t, &appls[i], &sAppList[i])
|
||||
assert.NotSame(t, &appls[i].Spec, &sAppList[i].Spec)
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(namespace).Get(context.Background(), sAppList[i].Name, metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.NotSame(t, a, &sAppList[i])
|
||||
}
|
||||
|
||||
appSetList, err := s.appclientset.ArgoprojV1alpha1().ApplicationSets(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.ElementsMatch(t, appSets, appSetList.Items)
|
||||
sAppSetList := appSetList.Items
|
||||
slices.SortFunc(sAppSetList, func(a, b appsv1.ApplicationSet) int {
|
||||
return strings.Compare(a.Name, b.Name)
|
||||
})
|
||||
slices.SortFunc(appSets, func(a, b appsv1.ApplicationSet) int {
|
||||
return strings.Compare(a.Name, b.Name)
|
||||
})
|
||||
for i := range appSets {
|
||||
assert.NotSame(t, &appSets[i], &sAppSetList[i])
|
||||
assert.NotSame(t, &appSets[i].Spec, &sAppSetList[i].Spec)
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().ApplicationSets(namespace).Get(context.Background(),
|
||||
sAppSetList[i].Name, metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.NotSame(t, a, &sAppSetList[i])
|
||||
}
|
||||
|
||||
projList, err := s.appclientset.ArgoprojV1alpha1().AppProjects("deep-copy-ns").List(context.Background(), metav1.ListOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.ElementsMatch(t, appProjects, projList.Items)
|
||||
spList := projList.Items
|
||||
slices.SortFunc(spList, func(a, b appsv1.AppProject) int {
|
||||
return strings.Compare(a.Name, b.Name)
|
||||
})
|
||||
slices.SortFunc(appProjects, func(a, b appsv1.AppProject) int {
|
||||
return strings.Compare(a.Name, b.Name)
|
||||
})
|
||||
for i := range appProjects {
|
||||
assert.NotSame(t, &appProjects[i], &spList[i])
|
||||
assert.NotSame(t, &appProjects[i].Spec, &spList[i].Spec)
|
||||
p, err := s.appclientset.ArgoprojV1alpha1().AppProjects("deep-copy-ns").Get(context.Background(),
|
||||
spList[i].Name, metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.NotSame(t, p, &spList[i])
|
||||
}
|
||||
}
|
||||
|
||||
func Test_RunResourceActionDestinationInference(t *testing.T) {
|
||||
t.Parallel()
|
||||
deployment := k8sappsv1.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test",
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
|
||||
testServer := newTestApp(func(app *appsv1.Application) {
|
||||
app.ObjectMeta.Namespace = "default"
|
||||
app.Name = "test-server"
|
||||
app.Status.Resources = []appsv1.ResourceStatus{
|
||||
{
|
||||
Group: deployment.GroupVersionKind().Group,
|
||||
Kind: deployment.GroupVersionKind().Kind,
|
||||
Version: deployment.GroupVersionKind().Version,
|
||||
Name: deployment.Name,
|
||||
Namespace: deployment.Namespace,
|
||||
Status: "Synced",
|
||||
},
|
||||
}
|
||||
app.Status.History = []appsv1.RevisionHistory{
|
||||
{
|
||||
ID: 0,
|
||||
Source: appsv1.ApplicationSource{
|
||||
TargetRevision: "something-old",
|
||||
},
|
||||
},
|
||||
}
|
||||
app.Spec.Destination = appsv1.ApplicationDestination{
|
||||
Server: "https://cluster-api.example.com",
|
||||
Namespace: "default",
|
||||
Name: "",
|
||||
}
|
||||
})
|
||||
testName := newTestApp(func(app *appsv1.Application) {
|
||||
app.ObjectMeta.Namespace = "default"
|
||||
app.Name = "test-name"
|
||||
app.Status.Resources = []appsv1.ResourceStatus{
|
||||
{
|
||||
Group: deployment.GroupVersionKind().Group,
|
||||
Kind: deployment.GroupVersionKind().Kind,
|
||||
Version: deployment.GroupVersionKind().Version,
|
||||
Name: deployment.Name,
|
||||
Namespace: deployment.Namespace,
|
||||
Status: "Synced",
|
||||
},
|
||||
}
|
||||
app.Status.History = []appsv1.RevisionHistory{
|
||||
{
|
||||
ID: 0,
|
||||
Source: appsv1.ApplicationSource{
|
||||
TargetRevision: "something-old",
|
||||
},
|
||||
},
|
||||
}
|
||||
app.Spec.Destination = appsv1.ApplicationDestination{
|
||||
Server: "",
|
||||
Namespace: "default",
|
||||
Name: "fake-cluster",
|
||||
}
|
||||
})
|
||||
testBoth := newTestApp(func(app *appsv1.Application) {
|
||||
app.ObjectMeta.Namespace = "default"
|
||||
app.Name = "test-both"
|
||||
app.Status.Resources = []appsv1.ResourceStatus{
|
||||
{
|
||||
Group: deployment.GroupVersionKind().Group,
|
||||
Kind: deployment.GroupVersionKind().Kind,
|
||||
Version: deployment.GroupVersionKind().Version,
|
||||
Name: deployment.Name,
|
||||
Namespace: deployment.Namespace,
|
||||
Status: "Synced",
|
||||
},
|
||||
}
|
||||
app.Status.History = []appsv1.RevisionHistory{
|
||||
{
|
||||
ID: 0,
|
||||
Source: appsv1.ApplicationSource{
|
||||
TargetRevision: "something-old",
|
||||
},
|
||||
},
|
||||
}
|
||||
app.Spec.Destination = appsv1.ApplicationDestination{
|
||||
Server: "https://cluster-api.example.com",
|
||||
Namespace: "default",
|
||||
Name: "fake-cluster",
|
||||
}
|
||||
})
|
||||
testDeployment := kube.MustToUnstructured(&deployment)
|
||||
server := newTestAppServer(t, testServer, testName, testBoth, testDeployment)
|
||||
// nolint:staticcheck
|
||||
adminCtx := context.WithValue(context.Background(), "claims", &jwt.MapClaims{"groups": []string{"admin"}})
|
||||
|
||||
type fields struct {
|
||||
Server
|
||||
}
|
||||
type args struct {
|
||||
q *application.ResourceActionRunRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want *application.ApplicationResponse
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "InferServerUrl", fields: fields{*server}, args: args{
|
||||
q: &application.ResourceActionRunRequest{
|
||||
Name: ptr.To(testName.Name),
|
||||
Namespace: ptr.To(testName.Namespace),
|
||||
ResourceName: ptr.To(deployment.Name),
|
||||
Group: ptr.To(deployment.GroupVersionKind().Group),
|
||||
Kind: ptr.To(deployment.GroupVersionKind().Kind),
|
||||
Version: ptr.To(deployment.GroupVersionKind().Version),
|
||||
Action: ptr.To("restart"),
|
||||
},
|
||||
},
|
||||
want: &application.ApplicationResponse{}, wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "InferName", fields: fields{*server}, args: args{
|
||||
q: &application.ResourceActionRunRequest{
|
||||
Name: ptr.To(testServer.Name),
|
||||
Namespace: ptr.To(testServer.Namespace),
|
||||
ResourceName: ptr.To(deployment.Name),
|
||||
Group: ptr.To(deployment.GroupVersionKind().Group),
|
||||
Kind: ptr.To(deployment.GroupVersionKind().Kind),
|
||||
Version: ptr.To(deployment.GroupVersionKind().Version),
|
||||
Action: ptr.To("restart"),
|
||||
},
|
||||
},
|
||||
want: &application.ApplicationResponse{}, wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "ErrorOnBoth", fields: fields{*server}, args: args{
|
||||
q: &application.ResourceActionRunRequest{
|
||||
Name: ptr.To(testBoth.Name),
|
||||
Namespace: ptr.To(testBoth.Namespace),
|
||||
ResourceName: ptr.To(deployment.Name),
|
||||
Group: ptr.To(deployment.GroupVersionKind().Group),
|
||||
Kind: ptr.To(deployment.GroupVersionKind().Kind),
|
||||
Version: ptr.To(deployment.GroupVersionKind().Version),
|
||||
Action: ptr.To("restart"),
|
||||
},
|
||||
},
|
||||
want: nil, wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
|
||||
return assert.ErrorContains(t, err, "application destination can't have both name and server defined")
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := tt.fields.Server.RunResourceAction(adminCtx, tt.args.q)
|
||||
if !tt.wantErr(t, err, fmt.Sprintf("RunResourceAction(%v)", tt.args.q)) {
|
||||
return
|
||||
}
|
||||
assert.Equalf(t, tt.want, got, "RunResourceAction(%v)", tt.args.q)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
164
server/application/deepinformer.go
Normal file
164
server/application/deepinformer.go
Normal file
@@ -0,0 +1,164 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
|
||||
argoprojv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/typed/application/v1alpha1"
|
||||
applisters "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/util"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
// deepCopyApplicationLister wraps an ApplicationLister and returns deep copies of the applications.
|
||||
type deepCopyApplicationLister struct {
|
||||
applisters.ApplicationLister
|
||||
}
|
||||
|
||||
// List lists all Applications in the indexer and returns deep copies.
|
||||
func (d *deepCopyApplicationLister) List(selector labels.Selector) ([]*v1alpha1.Application, error) {
|
||||
apps, err := d.ApplicationLister.List(selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deepCopiedApps := util.SliceCopy(apps)
|
||||
return deepCopiedApps, nil
|
||||
}
|
||||
|
||||
// Applications return an object that can list and get Applications and returns deep copies.
|
||||
func (d *deepCopyApplicationLister) Applications(namespace string) applisters.ApplicationNamespaceLister {
|
||||
return &deepCopyApplicationNamespaceLister{
|
||||
ApplicationNamespaceLister: d.ApplicationLister.Applications(namespace),
|
||||
}
|
||||
}
|
||||
|
||||
// deepCopyApplicationNamespaceLister wraps an ApplicationNamespaceLister and returns deep copies of the applications.
|
||||
type deepCopyApplicationNamespaceLister struct {
|
||||
applisters.ApplicationNamespaceLister
|
||||
}
|
||||
|
||||
// List lists all Applications in the indexer for a given namespace and returns deep copies.
|
||||
func (d *deepCopyApplicationNamespaceLister) List(selector labels.Selector) ([]*v1alpha1.Application, error) {
|
||||
apps, err := d.ApplicationNamespaceLister.List(selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deepCopiedApps := util.SliceCopy(apps)
|
||||
return deepCopiedApps, nil
|
||||
}
|
||||
|
||||
// Get retrieves the Application from the indexer for a given namespace and name and returns a deep copy.
|
||||
func (d *deepCopyApplicationNamespaceLister) Get(name string) (*v1alpha1.Application, error) {
|
||||
app, err := d.ApplicationNamespaceLister.Get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return app.DeepCopy(), nil
|
||||
}
|
||||
|
||||
type deepCopyAppClientset struct {
|
||||
appclientset.Interface
|
||||
}
|
||||
|
||||
func (d *deepCopyAppClientset) ArgoprojV1alpha1() argoprojv1alpha1.ArgoprojV1alpha1Interface {
|
||||
return &deepCopyArgoprojV1alpha1Client{
|
||||
ArgoprojV1alpha1Interface: d.Interface.ArgoprojV1alpha1(),
|
||||
}
|
||||
}
|
||||
|
||||
// GetUnderlyingClientSet returns the underlying clientset.Interface.
|
||||
// Unit tests should only call this
|
||||
func (d *deepCopyAppClientset) GetUnderlyingClientSet() appclientset.Interface {
|
||||
return d.Interface
|
||||
}
|
||||
|
||||
type deepCopyArgoprojV1alpha1Client struct {
|
||||
argoprojv1alpha1.ArgoprojV1alpha1Interface
|
||||
}
|
||||
|
||||
func (d *deepCopyArgoprojV1alpha1Client) RESTClient() rest.Interface {
|
||||
return d.ArgoprojV1alpha1Interface.RESTClient()
|
||||
}
|
||||
|
||||
func (d *deepCopyArgoprojV1alpha1Client) AppProjects(namespace string) argoprojv1alpha1.AppProjectInterface {
|
||||
return &deepCopyAppProjectClient{
|
||||
AppProjectInterface: d.ArgoprojV1alpha1Interface.AppProjects(namespace),
|
||||
}
|
||||
}
|
||||
|
||||
func (d *deepCopyArgoprojV1alpha1Client) ApplicationSets(namespace string) argoprojv1alpha1.ApplicationSetInterface {
|
||||
return &deepCopyApplicationSetClient{
|
||||
ApplicationSetInterface: d.ArgoprojV1alpha1Interface.ApplicationSets(namespace),
|
||||
}
|
||||
}
|
||||
|
||||
func (d *deepCopyArgoprojV1alpha1Client) Applications(namespace string) argoprojv1alpha1.ApplicationInterface {
|
||||
return &deepCopyApplicationClient{
|
||||
ApplicationInterface: d.ArgoprojV1alpha1Interface.Applications(namespace),
|
||||
}
|
||||
}
|
||||
|
||||
type deepCopyApplicationClient struct {
|
||||
argoprojv1alpha1.ApplicationInterface
|
||||
}
|
||||
|
||||
func (d *deepCopyApplicationClient) Get(ctx context.Context, name string, options metav1.GetOptions) (*v1alpha1.Application, error) {
|
||||
app, err := d.ApplicationInterface.Get(ctx, name, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return app.DeepCopy(), nil
|
||||
}
|
||||
|
||||
func (d *deepCopyApplicationClient) List(ctx context.Context, opts metav1.ListOptions) (*v1alpha1.ApplicationList, error) {
|
||||
appList, err := d.ApplicationInterface.List(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return appList.DeepCopy(), nil
|
||||
}
|
||||
|
||||
type deepCopyAppProjectClient struct {
|
||||
argoprojv1alpha1.AppProjectInterface
|
||||
}
|
||||
|
||||
func (d *deepCopyAppProjectClient) Get(ctx context.Context, name string, options metav1.GetOptions) (*v1alpha1.AppProject, error) {
|
||||
appProject, err := d.AppProjectInterface.Get(ctx, name, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return appProject.DeepCopy(), nil
|
||||
}
|
||||
|
||||
func (d *deepCopyAppProjectClient) List(ctx context.Context, opts metav1.ListOptions) (*v1alpha1.AppProjectList, error) {
|
||||
appProjectList, err := d.AppProjectInterface.List(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return appProjectList.DeepCopy(), nil
|
||||
}
|
||||
|
||||
type deepCopyApplicationSetClient struct {
|
||||
argoprojv1alpha1.ApplicationSetInterface
|
||||
}
|
||||
|
||||
func (d *deepCopyApplicationSetClient) Get(ctx context.Context, name string, options metav1.GetOptions) (*v1alpha1.ApplicationSet, error) {
|
||||
appSet, err := d.ApplicationSetInterface.Get(ctx, name, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return appSet.DeepCopy(), nil
|
||||
}
|
||||
|
||||
func (d *deepCopyApplicationSetClient) List(ctx context.Context, opts metav1.ListOptions) (*v1alpha1.ApplicationSetList, error) {
|
||||
appSetList, err := d.ApplicationSetInterface.List(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return appSetList.DeepCopy(), nil
|
||||
}
|
||||
150
server/application/deepinformer_test.go
Normal file
150
server/application/deepinformer_test.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/fake"
|
||||
clientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/typed/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/typed/application/v1alpha1/mocks"
|
||||
)
|
||||
|
||||
func Test_deepCopyAppProjectClient_Get(t *testing.T) {
|
||||
type fields struct {
|
||||
AppProjectInterface clientset.AppProjectInterface
|
||||
}
|
||||
type args struct {
|
||||
name string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want *v1alpha1.AppProject
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{name: "Get an app project", fields: fields{AppProjectInterface: setupAppProjects("appproject")}, args: args{
|
||||
name: "appproject",
|
||||
}, want: &v1alpha1.AppProject{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "appproject", Namespace: "deep-copy-ns"},
|
||||
}, wantErr: assert.NoError},
|
||||
{
|
||||
name: "Error getting an app project",
|
||||
fields: fields{
|
||||
AppProjectInterface: func() clientset.AppProjectInterface {
|
||||
appProject := mocks.AppProjectInterface{}
|
||||
appProject.On("Get", context.Background(), "appproject2", metav1.GetOptions{}).Return(nil, errors.New("error"))
|
||||
return &appProject
|
||||
}(),
|
||||
},
|
||||
args: args{
|
||||
name: "appproject2",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: assert.Error,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
d := &deepCopyAppProjectClient{
|
||||
AppProjectInterface: tt.fields.AppProjectInterface,
|
||||
}
|
||||
got, err := d.Get(context.Background(), tt.args.name, metav1.GetOptions{})
|
||||
if !tt.wantErr(t, err, fmt.Sprintf("Get(%v)", tt.args.name)) {
|
||||
return
|
||||
}
|
||||
assert.Equalf(t, tt.want, got, "Get(%v)", tt.args.name)
|
||||
if tt.want != nil {
|
||||
assert.NotSamef(t, tt.want, got, "%v and %v are the same ptr", tt.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_deepCopyAppProjectClient_List(t *testing.T) {
|
||||
type fields struct {
|
||||
AppProjectInterface clientset.AppProjectInterface
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want []v1alpha1.AppProject
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "List app projects", fields: fields{AppProjectInterface: setupAppProjects("proj1", "proj2")},
|
||||
want: createAppProject("proj1", "proj2"), wantErr: assert.NoError,
|
||||
},
|
||||
{name: "Error listing app project", fields: fields{
|
||||
AppProjectInterface: func() clientset.AppProjectInterface {
|
||||
appProject := mocks.AppProjectInterface{}
|
||||
appProject.On("List", context.Background(), metav1.ListOptions{}).Return(nil, errors.New("error"))
|
||||
return &appProject
|
||||
}(),
|
||||
}, want: nil, wantErr: assert.Error},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
d := &deepCopyAppProjectClient{
|
||||
AppProjectInterface: tt.fields.AppProjectInterface,
|
||||
}
|
||||
got, err := d.List(context.Background(), metav1.ListOptions{})
|
||||
if !tt.wantErr(t, err, "List") {
|
||||
return
|
||||
}
|
||||
if tt.want != nil {
|
||||
assert.Equalf(t, tt.want, got.Items, "List")
|
||||
for i := range tt.want {
|
||||
assert.NotSamef(t, &tt.want[i], &got.Items[i], "%v and %v are the same ptr", tt.want, got)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func createAppProject(projects ...string) []v1alpha1.AppProject {
|
||||
appProjects := make([]v1alpha1.AppProject, len(projects))
|
||||
for i, p := range projects {
|
||||
appProjects[i] = v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: p, Namespace: "deep-copy-ns"}}
|
||||
}
|
||||
return appProjects
|
||||
}
|
||||
|
||||
func setupAppProjects(projects ...string) clientset.AppProjectInterface {
|
||||
appProjects := createAppProject(projects...)
|
||||
ro := make([]runtime.Object, len(appProjects))
|
||||
for i := range appProjects {
|
||||
ro[i] = &appProjects[i]
|
||||
}
|
||||
return fake.NewSimpleClientset(ro...).ArgoprojV1alpha1().AppProjects("deep-copy-ns")
|
||||
}
|
||||
|
||||
func Test_deepCopyArgoprojV1alpha1Client_RESTClient(t *testing.T) {
|
||||
fclientset := fake.NewSimpleClientset().ArgoprojV1alpha1()
|
||||
type fields struct {
|
||||
ArgoprojV1alpha1Interface clientset.ArgoprojV1alpha1Interface
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want rest.Interface
|
||||
}{
|
||||
{name: "RestClientGetter", fields: fields{ArgoprojV1alpha1Interface: fclientset}, want: fclientset.RESTClient()},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
d := &deepCopyArgoprojV1alpha1Client{
|
||||
ArgoprojV1alpha1Interface: tt.fields.ArgoprojV1alpha1Interface,
|
||||
}
|
||||
assert.Equalf(t, tt.want, d.RESTClient(), "RESTClient()")
|
||||
})
|
||||
}
|
||||
}
|
||||
2
server/application/mocks/Broadcaster.go
generated
2
server/application/mocks/Broadcaster.go
generated
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
|
||||
"github.com/argoproj/gitops-engine/pkg/utils/kube"
|
||||
log "github.com/sirupsen/logrus"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
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"
|
||||
"github.com/argoproj/argo-cd/v2/util/argo"
|
||||
"github.com/argoproj/argo-cd/v2/util/db"
|
||||
"github.com/argoproj/argo-cd/v2/util/rbac"
|
||||
@@ -153,12 +152,12 @@ func (s *terminalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
appRBACName := security.RBACName(s.namespace, project, appNamespace, app)
|
||||
if err := s.terminalOptions.Enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, appRBACName); err != nil {
|
||||
if err := s.terminalOptions.Enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplications, rbac.ActionGet, appRBACName); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.terminalOptions.Enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceExec, rbacpolicy.ActionCreate, appRBACName); err != nil {
|
||||
if err := s.terminalOptions.Enf.EnforceErr(ctx.Value("claims"), rbac.ResourceExec, rbac.ActionCreate, appRBACName); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
@@ -170,7 +169,7 @@ func (s *terminalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
a, err := s.appLister.Applications(ns).Get(app)
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
if apierrors.IsNotFound(err) {
|
||||
http.Error(w, "App not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
@@ -216,7 +215,7 @@ func (s *terminalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if pod.Status.Phase != v1.PodRunning {
|
||||
if pod.Status.Phase != corev1.PodRunning {
|
||||
http.Error(w, "Pod not running", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
@@ -309,7 +308,7 @@ func startProcess(k8sClient kubernetes.Interface, cfg *rest.Config, namespace, p
|
||||
Namespace(namespace).
|
||||
SubResource("exec")
|
||||
|
||||
req.VersionedParams(&v1.PodExecOptions{
|
||||
req.VersionedParams(&corev1.PodExecOptions{
|
||||
Container: containerName,
|
||||
Command: cmd,
|
||||
Stdin: true,
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
|
||||
httputil "github.com/argoproj/argo-cd/v2/util/http"
|
||||
"github.com/argoproj/argo-cd/v2/util/rbac"
|
||||
util_session "github.com/argoproj/argo-cd/v2/util/session"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
@@ -26,7 +26,7 @@ const (
|
||||
var upgrader = func() websocket.Upgrader {
|
||||
upgrader := websocket.Upgrader{}
|
||||
upgrader.HandshakeTimeout = time.Second * 2
|
||||
upgrader.CheckOrigin = func(r *http.Request) bool {
|
||||
upgrader.CheckOrigin = func(_ *http.Request) bool {
|
||||
return true
|
||||
}
|
||||
return upgrader
|
||||
@@ -139,7 +139,7 @@ func (t *terminalSession) validatePermissions(p []byte) (int, error) {
|
||||
Operation: "stdout",
|
||||
Data: "Permission denied",
|
||||
})
|
||||
if err := t.terminalOpts.Enf.EnforceErr(t.ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, t.appRBACName); err != nil {
|
||||
if err := t.terminalOpts.Enf.EnforceErr(t.ctx.Value("claims"), rbac.ResourceApplications, rbac.ActionGet, t.appRBACName); err != nil {
|
||||
err = t.wsConn.WriteMessage(websocket.TextMessage, permissionDeniedMessage)
|
||||
if err != nil {
|
||||
log.Errorf("permission denied message err: %v", err)
|
||||
@@ -147,7 +147,7 @@ func (t *terminalSession) validatePermissions(p []byte) (int, error) {
|
||||
return copy(p, EndOfTransmission), permissionDeniedErr
|
||||
}
|
||||
|
||||
if err := t.terminalOpts.Enf.EnforceErr(t.ctx.Value("claims"), rbacpolicy.ResourceExec, rbacpolicy.ActionCreate, t.appRBACName); err != nil {
|
||||
if err := t.terminalOpts.Enf.EnforceErr(t.ctx.Value("claims"), rbac.ResourceExec, rbac.ActionCreate, t.appRBACName); err != nil {
|
||||
err = t.wsConn.WriteMessage(websocket.TextMessage, permissionDeniedMessage)
|
||||
if err != nil {
|
||||
log.Errorf("permission denied message err: %v", err)
|
||||
@@ -178,7 +178,7 @@ func (t *terminalSession) performValidationsAndReconnect(p []byte) (int, error)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Read called in a loop from remotecommand as long as the process is running
|
||||
// Read called in a loop from remote command as long as the process is running
|
||||
func (t *terminalSession) Read(p []byte) (int, error) {
|
||||
code, err := t.performValidationsAndReconnect(p)
|
||||
if err != nil {
|
||||
@@ -219,7 +219,7 @@ func (t *terminalSession) Ping() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write called from remotecommand whenever there is any output
|
||||
// Write called from remote command whenever there is any output
|
||||
func (t *terminalSession) Write(p []byte) (int, error) {
|
||||
msg, err := json.Marshal(TerminalMessage{
|
||||
Operation: "stdout",
|
||||
|
||||
@@ -3,6 +3,7 @@ package applicationset
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
@@ -14,8 +15,8 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/dynamic"
|
||||
@@ -33,7 +34,6 @@ import (
|
||||
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
|
||||
applisters "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
|
||||
repoapiclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
|
||||
"github.com/argoproj/argo-cd/v2/util/argo"
|
||||
"github.com/argoproj/argo-cd/v2/util/collections"
|
||||
"github.com/argoproj/argo-cd/v2/util/db"
|
||||
@@ -126,7 +126,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, a.RBACName(s.ns)); err != nil {
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplicationSets, rbac.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ func (s *Server) List(ctx context.Context, q *applicationset.ApplicationSetListQ
|
||||
continue
|
||||
}
|
||||
|
||||
if s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionGet, a.RBACName(s.ns)) {
|
||||
if s.enf.Enforce(ctx.Value("claims"), rbac.ResourceApplicationSets, rbac.ActionGet, a.RBACName(s.ns)) {
|
||||
newItems = append(newItems, *a)
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,7 @@ func (s *Server) Create(ctx context.Context, q *applicationset.ApplicationSetCre
|
||||
appset := q.GetApplicationset()
|
||||
|
||||
if appset == nil {
|
||||
return nil, fmt.Errorf("error creating ApplicationSets: ApplicationSets is nil in request")
|
||||
return nil, errors.New("error creating ApplicationSets: ApplicationSets is nil in request")
|
||||
}
|
||||
|
||||
projectName, err := s.validateAppSet(appset)
|
||||
@@ -203,7 +203,7 @@ func (s *Server) Create(ctx context.Context, q *applicationset.ApplicationSetCre
|
||||
}
|
||||
|
||||
if q.GetDryRun() {
|
||||
apps, err := s.generateApplicationSetApps(ctx, log.WithField("applicationset", appset.Name), *appset, namespace)
|
||||
apps, err := s.generateApplicationSetApps(ctx, log.WithField("applicationset", appset.Name), *appset)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to generate Applications of ApplicationSet: %w", err)
|
||||
}
|
||||
@@ -229,7 +229,7 @@ func (s *Server) Create(ctx context.Context, q *applicationset.ApplicationSetCre
|
||||
return created, nil
|
||||
}
|
||||
|
||||
if !apierr.IsAlreadyExists(err) {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return nil, fmt.Errorf("error creating ApplicationSet: %w", err)
|
||||
}
|
||||
// act idempotent if existing spec matches new spec
|
||||
@@ -252,7 +252,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, appset.RBACName(s.ns)); err != nil {
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplicationSets, rbac.ActionUpdate, appset.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updated, err := s.updateAppSet(existing, appset, ctx, true)
|
||||
@@ -262,7 +262,7 @@ func (s *Server) Create(ctx context.Context, q *applicationset.ApplicationSetCre
|
||||
return updated, nil
|
||||
}
|
||||
|
||||
func (s *Server) generateApplicationSetApps(ctx context.Context, logEntry *log.Entry, appset v1alpha1.ApplicationSet, namespace string) ([]v1alpha1.Application, error) {
|
||||
func (s *Server) generateApplicationSetApps(ctx context.Context, logEntry *log.Entry, appset v1alpha1.ApplicationSet) ([]v1alpha1.Application, error) {
|
||||
argoCDDB := s.db
|
||||
|
||||
scmConfig := generators.NewSCMConfig(s.ScmRootCAPath, s.AllowedScmProviders, s.EnableScmProviders, github_app.NewAuthCredentials(argoCDDB.(db.RepoCredsDB)), true)
|
||||
@@ -275,7 +275,7 @@ func (s *Server) generateApplicationSetApps(ctx context.Context, logEntry *log.E
|
||||
return nil, fmt.Errorf("error creating ArgoCDService: %w", err)
|
||||
}
|
||||
|
||||
appSetGenerators := generators.GetGenerators(ctx, s.client, s.k8sClient, namespace, argoCDService, s.dynamicClient, scmConfig)
|
||||
appSetGenerators := generators.GetGenerators(ctx, s.client, s.k8sClient, s.ns, argoCDService, s.dynamicClient, scmConfig)
|
||||
|
||||
apps, _, err := appsettemplate.GenerateApplications(logEntry, appset, appSetGenerators, &appsetutils.Render{}, s.client)
|
||||
if err != nil {
|
||||
@@ -288,11 +288,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, newAppset.RBACName(s.ns)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplicationSets, rbac.ActionCreate, newAppset.RBACName(s.ns)); 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, appset.RBACName(s.ns)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplicationSets, rbac.ActionUpdate, appset.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -313,7 +313,7 @@ func (s *Server) updateAppSet(appset *v1alpha1.ApplicationSet, newAppset *v1alph
|
||||
s.waitSync(res)
|
||||
return res, nil
|
||||
}
|
||||
if !apierr.IsConflict(err) {
|
||||
if !apierrors.IsConflict(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -333,7 +333,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, appset.RBACName(s.ns)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplicationSets, rbac.ActionDelete, appset.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -359,7 +359,7 @@ func (s *Server) ResourceTree(ctx context.Context, q *applicationset.Application
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting ApplicationSet: %w", err)
|
||||
}
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplicationSets, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplicationSets, rbac.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -370,13 +370,17 @@ func (s *Server) Generate(ctx context.Context, q *applicationset.ApplicationSetG
|
||||
appset := q.GetApplicationSet()
|
||||
|
||||
if appset == nil {
|
||||
return nil, fmt.Errorf("error creating ApplicationSets: ApplicationSets is nil in request")
|
||||
return nil, errors.New("error creating ApplicationSets: ApplicationSets is nil in request")
|
||||
}
|
||||
namespace := s.appsetNamespaceOrDefault(appset.Namespace)
|
||||
|
||||
// The RBAC check needs to be performed against the appset namespace
|
||||
// However, when trying to generate params, the server namespace needs
|
||||
// to be passed.
|
||||
namespace := s.appsetNamespaceOrDefault(appset.Namespace)
|
||||
if !s.isNamespaceEnabled(namespace) {
|
||||
return nil, security.NamespaceNotPermittedError(namespace)
|
||||
}
|
||||
|
||||
projectName, err := s.validateAppSet(appset)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error validating ApplicationSets: %w", err)
|
||||
@@ -389,7 +393,16 @@ func (s *Server) Generate(ctx context.Context, q *applicationset.ApplicationSetG
|
||||
logger := log.New()
|
||||
logger.SetOutput(logs)
|
||||
|
||||
apps, err := s.generateApplicationSetApps(ctx, logger.WithField("applicationset", appset.Name), *appset, namespace)
|
||||
// The server namespace will be used in the function
|
||||
// since this is the exact namespace that is being used
|
||||
// to generate parameters (especially for git generator).
|
||||
//
|
||||
// In case of Git generator, if the namespace is set to
|
||||
// appset namespace, we'll look for a project in the appset
|
||||
// namespace that would lead to error when generating params
|
||||
// for an appset in any namespace feature.
|
||||
// See https://github.com/argoproj/argo-cd/issues/22942
|
||||
apps, err := s.generateApplicationSetApps(ctx, logger.WithField("applicationset", appset.Name), *appset)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to generate Applications of ApplicationSet: %w\n%s", err, logs.String())
|
||||
}
|
||||
@@ -429,13 +442,13 @@ func (s *Server) buildApplicationSetTree(a *v1alpha1.ApplicationSet) (*v1alpha1.
|
||||
|
||||
func (s *Server) validateAppSet(appset *v1alpha1.ApplicationSet) (string, error) {
|
||||
if appset == nil {
|
||||
return "", fmt.Errorf("ApplicationSet cannot be validated for nil value")
|
||||
return "", errors.New("ApplicationSet cannot be validated for nil value")
|
||||
}
|
||||
|
||||
projectName := appset.Spec.Template.Spec.Project
|
||||
|
||||
if strings.Contains(projectName, "{{") {
|
||||
return "", fmt.Errorf("the Argo CD API does not currently support creating ApplicationSets with templated `project` fields")
|
||||
return "", errors.New("the Argo CD API does not currently support creating ApplicationSets with templated `project` fields")
|
||||
}
|
||||
|
||||
if err := appsetutils.CheckInvalidGenerators(appset); err != nil {
|
||||
@@ -446,13 +459,13 @@ func (s *Server) validateAppSet(appset *v1alpha1.ApplicationSet) (string, error)
|
||||
}
|
||||
|
||||
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, appset.RBACName(s.ns)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceApplicationSets, rbac.ActionCreate, appset.RBACName(s.ns)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Get(ctx, projectName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return status.Errorf(codes.InvalidArgument, "ApplicationSet references project %s which does not exist", projectName)
|
||||
}
|
||||
return fmt.Errorf("error getting ApplicationSet's project %q: %w", projectName, err)
|
||||
@@ -495,7 +508,7 @@ func (s *Server) waitSync(appset *v1alpha1.ApplicationSet) {
|
||||
}
|
||||
|
||||
func (s *Server) logAppSetEvent(a *v1alpha1.ApplicationSet, ctx context.Context, reason string, action string) {
|
||||
eventInfo := argo.EventInfo{Type: v1.EventTypeNormal, Reason: reason}
|
||||
eventInfo := argo.EventInfo{Type: corev1.EventTypeNormal, Reason: reason}
|
||||
user := session.Username(ctx)
|
||||
if user == "" {
|
||||
user = "Unknown user"
|
||||
@@ -507,9 +520,8 @@ func (s *Server) logAppSetEvent(a *v1alpha1.ApplicationSet, ctx context.Context,
|
||||
func (s *Server) appsetNamespaceOrDefault(appNs string) string {
|
||||
if appNs == "" {
|
||||
return s.ns
|
||||
} else {
|
||||
return appNs
|
||||
}
|
||||
return appNs
|
||||
}
|
||||
|
||||
func (s *Server) isNamespaceEnabled(namespace string) bool {
|
||||
|
||||
@@ -5,6 +5,9 @@ import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
cr_fake "sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
"github.com/argoproj/gitops-engine/pkg/health"
|
||||
"github.com/argoproj/pkg/sync"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -52,26 +55,29 @@ func fakeCluster() *appsv1.Cluster {
|
||||
}
|
||||
|
||||
// return an ApplicationServiceServer which returns fake data
|
||||
func newTestAppSetServer(objects ...runtime.Object) *Server {
|
||||
func newTestAppSetServer(t *testing.T, objects ...client.Object) *Server {
|
||||
t.Helper()
|
||||
f := func(enf *rbac.Enforcer) {
|
||||
_ = enf.SetBuiltinPolicy(assets.BuiltinPolicyCSV)
|
||||
enf.SetDefaultRole("role:admin")
|
||||
}
|
||||
scopedNamespaces := ""
|
||||
return newTestAppSetServerWithEnforcerConfigure(f, scopedNamespaces, objects...)
|
||||
return newTestAppSetServerWithEnforcerConfigure(t, f, scopedNamespaces, objects...)
|
||||
}
|
||||
|
||||
// return an ApplicationServiceServer which returns fake data
|
||||
func newTestNamespacedAppSetServer(objects ...runtime.Object) *Server {
|
||||
func newTestNamespacedAppSetServer(t *testing.T, objects ...client.Object) *Server {
|
||||
t.Helper()
|
||||
f := func(enf *rbac.Enforcer) {
|
||||
_ = enf.SetBuiltinPolicy(assets.BuiltinPolicyCSV)
|
||||
enf.SetDefaultRole("role:admin")
|
||||
}
|
||||
scopedNamespaces := "argocd"
|
||||
return newTestAppSetServerWithEnforcerConfigure(f, scopedNamespaces, objects...)
|
||||
return newTestAppSetServerWithEnforcerConfigure(t, f, scopedNamespaces, objects...)
|
||||
}
|
||||
|
||||
func newTestAppSetServerWithEnforcerConfigure(f func(*rbac.Enforcer), namespace string, objects ...runtime.Object) *Server {
|
||||
func newTestAppSetServerWithEnforcerConfigure(t *testing.T, f func(*rbac.Enforcer), namespace string, objects ...client.Object) *Server {
|
||||
t.Helper()
|
||||
kubeclientset := fake.NewClientset(&v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testNamespace,
|
||||
@@ -114,8 +120,12 @@ func newTestAppSetServerWithEnforcerConfigure(f func(*rbac.Enforcer), namespace
|
||||
|
||||
objects = append(objects, defaultProj, myProj)
|
||||
|
||||
fakeAppsClientset := apps.NewSimpleClientset(objects...)
|
||||
factory := appinformer.NewSharedInformerFactoryWithOptions(fakeAppsClientset, 0, appinformer.WithNamespace(namespace), appinformer.WithTweakListOptions(func(options *metav1.ListOptions) {}))
|
||||
runtimeObjects := make([]runtime.Object, len(objects))
|
||||
for i := range objects {
|
||||
runtimeObjects[i] = objects[i]
|
||||
}
|
||||
fakeAppsClientset := apps.NewSimpleClientset(runtimeObjects...)
|
||||
factory := appinformer.NewSharedInformerFactoryWithOptions(fakeAppsClientset, 0, appinformer.WithNamespace(namespace), appinformer.WithTweakListOptions(func(_ *metav1.ListOptions) {}))
|
||||
fakeProjLister := factory.Argoproj().V1alpha1().AppProjects().Lister().AppProjects(testNamespace)
|
||||
|
||||
enforcer := rbac.NewEnforcer(kubeclientset, testNamespace, common.ArgoCDRBACConfigMapName, nil)
|
||||
@@ -139,6 +149,13 @@ func newTestAppSetServerWithEnforcerConfigure(f func(*rbac.Enforcer), namespace
|
||||
panic("Timed out waiting for caches to sync")
|
||||
}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
err = appsv1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
err = v1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
crClient := cr_fake.NewClientBuilder().WithScheme(scheme).WithObjects(objects...).Build()
|
||||
|
||||
projInformer := factory.Argoproj().V1alpha1().AppProjects().Informer()
|
||||
go projInformer.Run(ctx.Done())
|
||||
if !k8scache.WaitForCacheSync(ctx.Done(), projInformer.HasSynced) {
|
||||
@@ -149,7 +166,7 @@ func newTestAppSetServerWithEnforcerConfigure(f func(*rbac.Enforcer), namespace
|
||||
db,
|
||||
kubeclientset,
|
||||
nil,
|
||||
nil,
|
||||
crClient,
|
||||
enforcer,
|
||||
nil,
|
||||
fakeAppsClientset,
|
||||
@@ -274,17 +291,17 @@ func testListAppsetsWithLabels(t *testing.T, appsetQuery applicationset.Applicat
|
||||
|
||||
func TestListAppSetsInNamespaceWithLabels(t *testing.T) {
|
||||
testNamespace := "test-namespace"
|
||||
appSetServer := newTestAppSetServer(newTestAppSet(func(appset *appsv1.ApplicationSet) {
|
||||
appSetServer := newTestAppSetServer(t, newTestAppSet(func(appset *appsv1.ApplicationSet) {
|
||||
appset.Name = "AppSet1"
|
||||
appset.ObjectMeta.Namespace = testNamespace
|
||||
appset.Namespace = testNamespace
|
||||
appset.SetLabels(map[string]string{"key1": "value1", "key2": "value1"})
|
||||
}), newTestAppSet(func(appset *appsv1.ApplicationSet) {
|
||||
appset.Name = "AppSet2"
|
||||
appset.ObjectMeta.Namespace = testNamespace
|
||||
appset.Namespace = testNamespace
|
||||
appset.SetLabels(map[string]string{"key1": "value2"})
|
||||
}), newTestAppSet(func(appset *appsv1.ApplicationSet) {
|
||||
appset.Name = "AppSet3"
|
||||
appset.ObjectMeta.Namespace = testNamespace
|
||||
appset.Namespace = testNamespace
|
||||
appset.SetLabels(map[string]string{"key1": "value3"})
|
||||
}))
|
||||
appSetServer.enabledNamespaces = []string{testNamespace}
|
||||
@@ -294,7 +311,7 @@ func TestListAppSetsInNamespaceWithLabels(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestListAppSetsInDefaultNSWithLabels(t *testing.T) {
|
||||
appSetServer := newTestAppSetServer(newTestAppSet(func(appset *appsv1.ApplicationSet) {
|
||||
appSetServer := newTestAppSetServer(t, newTestAppSet(func(appset *appsv1.ApplicationSet) {
|
||||
appset.Name = "AppSet1"
|
||||
appset.SetLabels(map[string]string{"key1": "value1", "key2": "value1"})
|
||||
}), newTestAppSet(func(appset *appsv1.ApplicationSet) {
|
||||
@@ -314,30 +331,30 @@ func TestListAppSetsInDefaultNSWithLabels(t *testing.T) {
|
||||
// default namespace must be used and not all the namespaces
|
||||
func TestListAppSetsWithoutNamespace(t *testing.T) {
|
||||
testNamespace := "test-namespace"
|
||||
appSetServer := newTestNamespacedAppSetServer(newTestAppSet(func(appset *appsv1.ApplicationSet) {
|
||||
appSetServer := newTestNamespacedAppSetServer(t, newTestAppSet(func(appset *appsv1.ApplicationSet) {
|
||||
appset.Name = "AppSet1"
|
||||
appset.ObjectMeta.Namespace = testNamespace
|
||||
appset.Namespace = testNamespace
|
||||
appset.SetLabels(map[string]string{"key1": "value1", "key2": "value1"})
|
||||
}), newTestAppSet(func(appset *appsv1.ApplicationSet) {
|
||||
appset.Name = "AppSet2"
|
||||
appset.ObjectMeta.Namespace = testNamespace
|
||||
appset.Namespace = testNamespace
|
||||
appset.SetLabels(map[string]string{"key1": "value2"})
|
||||
}), newTestAppSet(func(appset *appsv1.ApplicationSet) {
|
||||
appset.Name = "AppSet3"
|
||||
appset.ObjectMeta.Namespace = testNamespace
|
||||
appset.Namespace = testNamespace
|
||||
appset.SetLabels(map[string]string{"key1": "value3"})
|
||||
}))
|
||||
appSetServer.enabledNamespaces = []string{testNamespace}
|
||||
appsetQuery := applicationset.ApplicationSetListQuery{}
|
||||
|
||||
res, err := appSetServer.List(context.Background(), &appsetQuery)
|
||||
res, err := appSetServer.List(t.Context(), &appsetQuery)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, res.Items)
|
||||
}
|
||||
|
||||
func TestCreateAppSet(t *testing.T) {
|
||||
testAppSet := newTestAppSet()
|
||||
appServer := newTestAppSetServer()
|
||||
appServer := newTestAppSetServer(t)
|
||||
testAppSet.Spec.Generators = []appsv1.ApplicationSetGenerator{
|
||||
{
|
||||
List: &appsv1.ListGenerator{},
|
||||
@@ -346,36 +363,36 @@ func TestCreateAppSet(t *testing.T) {
|
||||
createReq := applicationset.ApplicationSetCreateRequest{
|
||||
Applicationset: testAppSet,
|
||||
}
|
||||
_, err := appServer.Create(context.Background(), &createReq)
|
||||
_, err := appServer.Create(t.Context(), &createReq)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCreateAppSetTemplatedProject(t *testing.T) {
|
||||
testAppSet := newTestAppSet()
|
||||
appServer := newTestAppSetServer()
|
||||
appServer := newTestAppSetServer(t)
|
||||
testAppSet.Spec.Template.Spec.Project = "{{ .project }}"
|
||||
createReq := applicationset.ApplicationSetCreateRequest{
|
||||
Applicationset: testAppSet,
|
||||
}
|
||||
_, err := appServer.Create(context.Background(), &createReq)
|
||||
_, err := appServer.Create(t.Context(), &createReq)
|
||||
assert.EqualError(t, err, "error validating ApplicationSets: the Argo CD API does not currently support creating ApplicationSets with templated `project` fields")
|
||||
}
|
||||
|
||||
func TestCreateAppSetWrongNamespace(t *testing.T) {
|
||||
testAppSet := newTestAppSet()
|
||||
appServer := newTestAppSetServer()
|
||||
testAppSet.ObjectMeta.Namespace = "NOT-ALLOWED"
|
||||
appServer := newTestAppSetServer(t)
|
||||
testAppSet.Namespace = "NOT-ALLOWED"
|
||||
createReq := applicationset.ApplicationSetCreateRequest{
|
||||
Applicationset: testAppSet,
|
||||
}
|
||||
_, err := appServer.Create(context.Background(), &createReq)
|
||||
_, err := appServer.Create(t.Context(), &createReq)
|
||||
|
||||
assert.EqualError(t, err, "namespace 'NOT-ALLOWED' is not permitted")
|
||||
}
|
||||
|
||||
func TestCreateAppSetDryRun(t *testing.T) {
|
||||
testAppSet := newTestAppSet()
|
||||
appServer := newTestAppSetServer()
|
||||
appServer := newTestAppSetServer(t)
|
||||
testAppSet.Spec.Template.Name = "{{name}}"
|
||||
testAppSet.Spec.Generators = []appsv1.ApplicationSetGenerator{
|
||||
{
|
||||
@@ -388,7 +405,7 @@ func TestCreateAppSetDryRun(t *testing.T) {
|
||||
Applicationset: testAppSet,
|
||||
DryRun: true,
|
||||
}
|
||||
result, err := appServer.Create(context.Background(), &createReq)
|
||||
result, err := appServer.Create(t.Context(), &createReq)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, result.Status.Resources, 2)
|
||||
@@ -406,7 +423,7 @@ func TestCreateAppSetDryRun(t *testing.T) {
|
||||
|
||||
func TestCreateAppSetDryRunWithDuplicate(t *testing.T) {
|
||||
testAppSet := newTestAppSet()
|
||||
appServer := newTestAppSetServer()
|
||||
appServer := newTestAppSetServer(t)
|
||||
testAppSet.Spec.Template.Name = "{{name}}"
|
||||
testAppSet.Spec.Generators = []appsv1.ApplicationSetGenerator{
|
||||
{
|
||||
@@ -419,7 +436,7 @@ func TestCreateAppSetDryRunWithDuplicate(t *testing.T) {
|
||||
Applicationset: testAppSet,
|
||||
DryRun: true,
|
||||
}
|
||||
result, err := appServer.Create(context.Background(), &createReq)
|
||||
result, err := appServer.Create(t.Context(), &createReq)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, result.Status.Resources, 1)
|
||||
@@ -441,7 +458,7 @@ func TestGetAppSet(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Get in default namespace", func(t *testing.T) {
|
||||
appSetServer := newTestAppSetServer(appSet1, appSet2, appSet3)
|
||||
appSetServer := newTestAppSetServer(t, appSet1, appSet2, appSet3)
|
||||
|
||||
appsetQuery := applicationset.ApplicationSetGetQuery{Name: "AppSet1"}
|
||||
|
||||
@@ -451,7 +468,7 @@ func TestGetAppSet(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Get in named namespace", func(t *testing.T) {
|
||||
appSetServer := newTestAppSetServer(appSet1, appSet2, appSet3)
|
||||
appSetServer := newTestAppSetServer(t, appSet1, appSet2, appSet3)
|
||||
|
||||
appsetQuery := applicationset.ApplicationSetGetQuery{Name: "AppSet1", AppsetNamespace: testNamespace}
|
||||
|
||||
@@ -461,7 +478,7 @@ func TestGetAppSet(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Get in not allowed namespace", func(t *testing.T) {
|
||||
appSetServer := newTestAppSetServer(appSet1, appSet2, appSet3)
|
||||
appSetServer := newTestAppSetServer(t, appSet1, appSet2, appSet3)
|
||||
|
||||
appsetQuery := applicationset.ApplicationSetGetQuery{Name: "AppSet1", AppsetNamespace: "NOT-ALLOWED"}
|
||||
|
||||
@@ -484,7 +501,7 @@ func TestDeleteAppSet(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Delete in default namespace", func(t *testing.T) {
|
||||
appSetServer := newTestAppSetServer(appSet1, appSet2, appSet3)
|
||||
appSetServer := newTestAppSetServer(t, appSet1, appSet2, appSet3)
|
||||
|
||||
appsetQuery := applicationset.ApplicationSetDeleteRequest{Name: "AppSet1"}
|
||||
|
||||
@@ -494,7 +511,7 @@ func TestDeleteAppSet(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Delete in named namespace", func(t *testing.T) {
|
||||
appSetServer := newTestAppSetServer(appSet1, appSet2, appSet3)
|
||||
appSetServer := newTestAppSetServer(t, appSet1, appSet2, appSet3)
|
||||
|
||||
appsetQuery := applicationset.ApplicationSetDeleteRequest{Name: "AppSet1", AppsetNamespace: testNamespace}
|
||||
|
||||
@@ -526,7 +543,7 @@ func TestUpdateAppSet(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Update merge", func(t *testing.T) {
|
||||
appServer := newTestAppSetServer(appSet)
|
||||
appServer := newTestAppSetServer(t, appSet)
|
||||
|
||||
updated, err := appServer.updateAppSet(appSet, newAppSet, context.Background(), true)
|
||||
|
||||
@@ -542,7 +559,7 @@ func TestUpdateAppSet(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Update no merge", func(t *testing.T) {
|
||||
appServer := newTestAppSetServer(appSet)
|
||||
appServer := newTestAppSetServer(t, appSet)
|
||||
|
||||
updated, err := appServer.updateAppSet(appSet, newAppSet, context.Background(), false)
|
||||
|
||||
@@ -611,7 +628,7 @@ func TestResourceTree(t *testing.T) {
|
||||
}
|
||||
|
||||
t.Run("ResourceTree in default namespace", func(t *testing.T) {
|
||||
appSetServer := newTestAppSetServer(appSet1, appSet2, appSet3)
|
||||
appSetServer := newTestAppSetServer(t, appSet1, appSet2, appSet3)
|
||||
|
||||
appsetQuery := applicationset.ApplicationSetTreeQuery{Name: "AppSet1"}
|
||||
|
||||
@@ -621,7 +638,7 @@ func TestResourceTree(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("ResourceTree in named namespace", func(t *testing.T) {
|
||||
appSetServer := newTestAppSetServer(appSet1, appSet2, appSet3)
|
||||
appSetServer := newTestAppSetServer(t, appSet1, appSet2, appSet3)
|
||||
|
||||
appsetQuery := applicationset.ApplicationSetTreeQuery{Name: "AppSet1", AppsetNamespace: testNamespace}
|
||||
|
||||
@@ -631,7 +648,7 @@ func TestResourceTree(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("ResourceTree in not allowed namespace", func(t *testing.T) {
|
||||
appSetServer := newTestAppSetServer(appSet1, appSet2, appSet3)
|
||||
appSetServer := newTestAppSetServer(t, appSet1, appSet2, appSet3)
|
||||
|
||||
appsetQuery := applicationset.ApplicationSetTreeQuery{Name: "AppSet1", AppsetNamespace: "NOT-ALLOWED"}
|
||||
|
||||
@@ -639,3 +656,54 @@ func TestResourceTree(t *testing.T) {
|
||||
assert.EqualError(t, err, "namespace 'NOT-ALLOWED' is not permitted")
|
||||
})
|
||||
}
|
||||
|
||||
func TestAppSet_Generate_Cluster(t *testing.T) {
|
||||
appSet1 := newTestAppSet(func(appset *appsv1.ApplicationSet) {
|
||||
appset.Name = "AppSet1"
|
||||
appset.Spec.Template.Name = "{{name}}"
|
||||
appset.Spec.Generators = []appsv1.ApplicationSetGenerator{
|
||||
{
|
||||
Clusters: &appsv1.ClusterGenerator{},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Generate in default namespace", func(t *testing.T) {
|
||||
appSetServer := newTestAppSetServer(t, appSet1)
|
||||
appsetQuery := applicationset.ApplicationSetGenerateRequest{
|
||||
ApplicationSet: appSet1,
|
||||
}
|
||||
|
||||
res, err := appSetServer.Generate(t.Context(), &appsetQuery)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, res.Applications, 2)
|
||||
assert.Equal(t, "fake-cluster", res.Applications[0].Name)
|
||||
assert.Equal(t, "in-cluster", res.Applications[1].Name)
|
||||
})
|
||||
|
||||
t.Run("Generate in different namespace", func(t *testing.T) {
|
||||
appSetServer := newTestAppSetServer(t, appSet1)
|
||||
|
||||
appSet1Ns := appSet1.DeepCopy()
|
||||
appSet1Ns.Namespace = "external-namespace"
|
||||
appsetQuery := applicationset.ApplicationSetGenerateRequest{ApplicationSet: appSet1Ns}
|
||||
|
||||
res, err := appSetServer.Generate(t.Context(), &appsetQuery)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, res.Applications, 2)
|
||||
assert.Equal(t, "fake-cluster", res.Applications[0].Name)
|
||||
assert.Equal(t, "in-cluster", res.Applications[1].Name)
|
||||
})
|
||||
|
||||
t.Run("Generate in not allowed namespace", func(t *testing.T) {
|
||||
appSetServer := newTestAppSetServer(t, appSet1)
|
||||
|
||||
appSet1Ns := appSet1.DeepCopy()
|
||||
appSet1Ns.Namespace = "NOT-ALLOWED"
|
||||
|
||||
appsetQuery := applicationset.ApplicationSetGenerateRequest{ApplicationSet: appSet1Ns}
|
||||
|
||||
_, err := appSetServer.Generate(t.Context(), &appsetQuery)
|
||||
assert.EqualError(t, err, "namespace 'NOT-ALLOWED' is not permitted")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
certificatepkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/certificate"
|
||||
appsv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
|
||||
"github.com/argoproj/argo-cd/v2/util/db"
|
||||
"github.com/argoproj/argo-cd/v2/util/rbac"
|
||||
)
|
||||
@@ -37,7 +36,7 @@ func NewServer(
|
||||
|
||||
// Returns a list of configured certificates that match the query
|
||||
func (s *Server) ListCertificates(ctx context.Context, q *certificatepkg.RepositoryCertificateQuery) (*appsv1.RepositoryCertificateList, error) {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceCertificates, rbacpolicy.ActionGet, ""); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceCertificates, rbac.ActionGet, ""); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certList, err := s.db.ListRepoCertificates(ctx, &db.CertificateListSelector{
|
||||
@@ -53,7 +52,7 @@ func (s *Server) ListCertificates(ctx context.Context, q *certificatepkg.Reposit
|
||||
|
||||
// Batch creates certificates for verifying repositories
|
||||
func (s *Server) CreateCertificate(ctx context.Context, q *certificatepkg.RepositoryCertificateCreateRequest) (*appsv1.RepositoryCertificateList, error) {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceCertificates, rbacpolicy.ActionCreate, ""); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceCertificates, rbac.ActionCreate, ""); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certs, err := s.db.CreateRepoCertificate(ctx, q.Certificates, q.Upsert)
|
||||
@@ -66,7 +65,7 @@ func (s *Server) CreateCertificate(ctx context.Context, q *certificatepkg.Reposi
|
||||
|
||||
// Batch deletes a list of certificates that match the query
|
||||
func (s *Server) DeleteCertificate(ctx context.Context, q *certificatepkg.RepositoryCertificateQuery) (*appsv1.RepositoryCertificateList, error) {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceCertificates, rbacpolicy.ActionDelete, ""); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceCertificates, rbac.ActionDelete, ""); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certs, err := s.db.RemoveRepoCertificates(ctx, &db.CertificateListSelector{
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster"
|
||||
appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
servercache "github.com/argoproj/argo-cd/v2/server/cache"
|
||||
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
|
||||
"github.com/argoproj/argo-cd/v2/util/argo"
|
||||
"github.com/argoproj/argo-cd/v2/util/clusterauth"
|
||||
"github.com/argoproj/argo-cd/v2/util/db"
|
||||
@@ -72,7 +71,7 @@ func (s *Server) List(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Clus
|
||||
|
||||
items := make([]appv1.Cluster, 0)
|
||||
for _, clust := range filteredItems {
|
||||
if s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionGet, CreateClusterRBACObject(clust.Project, clust.Server)) {
|
||||
if s.enf.Enforce(ctx.Value("claims"), rbac.ResourceClusters, rbac.ActionGet, CreateClusterRBACObject(clust.Project, clust.Server)) {
|
||||
items = append(items, clust)
|
||||
}
|
||||
}
|
||||
@@ -143,7 +142,7 @@ func filterClustersByServer(clusters []appv1.Cluster, server string) []appv1.Clu
|
||||
|
||||
// Create creates a cluster
|
||||
func (s *Server) Create(ctx context.Context, q *cluster.ClusterCreateRequest) (*appv1.Cluster, error) {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionCreate, CreateClusterRBACObject(q.Cluster.Project, q.Cluster.Server)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceClusters, rbac.ActionCreate, CreateClusterRBACObject(q.Cluster.Project, q.Cluster.Server)); err != nil {
|
||||
return nil, fmt.Errorf("permission denied while creating cluster: %w", err)
|
||||
}
|
||||
c := q.Cluster
|
||||
@@ -182,7 +181,7 @@ func (s *Server) Create(ctx context.Context, q *cluster.ClusterCreateRequest) (*
|
||||
ServerVersion: serverVersion,
|
||||
ConnectionState: appv1.ConnectionState{
|
||||
Status: appv1.ConnectionStatusSuccessful,
|
||||
ModifiedAt: &v1.Time{Time: time.Now()},
|
||||
ModifiedAt: &metav1.Time{Time: time.Now()},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -193,7 +192,7 @@ func (s *Server) Create(ctx context.Context, q *cluster.ClusterCreateRequest) (*
|
||||
|
||||
// Get returns a cluster from a query
|
||||
func (s *Server) Get(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Cluster, error) {
|
||||
c, err := s.getClusterAndVerifyAccess(ctx, q, rbacpolicy.ActionGet)
|
||||
c, err := s.getClusterAndVerifyAccess(ctx, q, rbac.ActionGet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error verifying access to update cluster: %w", err)
|
||||
}
|
||||
@@ -216,7 +215,7 @@ func (s *Server) getClusterAndVerifyAccess(ctx context.Context, q *cluster.Clust
|
||||
}
|
||||
|
||||
// verify that user can do the specified action inside project where cluster is located
|
||||
if !s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceClusters, action, CreateClusterRBACObject(c.Project, c.Server)) {
|
||||
if !s.enf.Enforce(ctx.Value("claims"), rbac.ResourceClusters, action, CreateClusterRBACObject(c.Project, c.Server)) {
|
||||
log.WithField("cluster", q.Server).Warnf("encountered permissions issue while processing request: %v", err)
|
||||
return nil, common.PermissionDeniedAPIError
|
||||
}
|
||||
@@ -228,15 +227,16 @@ func (s *Server) getCluster(ctx context.Context, q *cluster.ClusterQuery) (*appv
|
||||
if q.Id != nil {
|
||||
q.Server = ""
|
||||
q.Name = ""
|
||||
if q.Id.Type == "name" {
|
||||
switch q.Id.Type {
|
||||
case "name":
|
||||
q.Name = q.Id.Value
|
||||
} else if q.Id.Type == "name_escaped" {
|
||||
case "name_escaped":
|
||||
nameUnescaped, err := url.QueryUnescape(q.Id.Value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unescape cluster name: %w", err)
|
||||
}
|
||||
q.Name = nameUnescaped
|
||||
} else {
|
||||
default:
|
||||
q.Server = q.Id.Value
|
||||
}
|
||||
}
|
||||
@@ -299,14 +299,14 @@ func (s *Server) Update(ctx context.Context, q *cluster.ClusterUpdateRequest) (*
|
||||
Server: q.Cluster.Server,
|
||||
Name: q.Cluster.Name,
|
||||
Id: q.Id,
|
||||
}, rbacpolicy.ActionUpdate)
|
||||
}, rbac.ActionUpdate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to verify access for updating cluster: %w", err)
|
||||
}
|
||||
|
||||
if len(q.UpdatedFields) == 0 || sets.NewString(q.UpdatedFields...).Has("project") {
|
||||
// verify that user can do update inside project where cluster will be located
|
||||
if !s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(q.Cluster.Project, c.Server)) {
|
||||
if !s.enf.Enforce(ctx.Value("claims"), rbac.ResourceClusters, rbac.ActionUpdate, CreateClusterRBACObject(q.Cluster.Project, c.Server)) {
|
||||
return nil, common.PermissionDeniedAPIError
|
||||
}
|
||||
}
|
||||
@@ -338,7 +338,7 @@ func (s *Server) Update(ctx context.Context, q *cluster.ClusterUpdateRequest) (*
|
||||
ServerVersion: serverVersion,
|
||||
ConnectionState: appv1.ConnectionState{
|
||||
Status: appv1.ConnectionStatusSuccessful,
|
||||
ModifiedAt: &v1.Time{Time: time.Now()},
|
||||
ModifiedAt: &metav1.Time{Time: time.Now()},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -375,14 +375,11 @@ func (s *Server) Delete(ctx context.Context, q *cluster.ClusterQuery) (*cluster.
|
||||
}
|
||||
|
||||
func enforceAndDelete(s *Server, ctx context.Context, server, project string) error {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionDelete, CreateClusterRBACObject(project, server)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceClusters, rbac.ActionDelete, CreateClusterRBACObject(project, server)); err != nil {
|
||||
log.WithField("cluster", server).Warnf("encountered permissions issue while processing request: %v", err)
|
||||
return common.PermissionDeniedAPIError
|
||||
}
|
||||
if err := s.db.DeleteCluster(ctx, server); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return s.db.DeleteCluster(ctx, server)
|
||||
}
|
||||
|
||||
// RotateAuth rotates the bearer token used for a cluster
|
||||
@@ -400,13 +397,13 @@ func (s *Server) RotateAuth(ctx context.Context, q *cluster.ClusterQuery) (*clus
|
||||
return nil, common.PermissionDeniedAPIError
|
||||
}
|
||||
for _, server := range servers {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(clust.Project, server)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceClusters, rbac.ActionUpdate, CreateClusterRBACObject(clust.Project, server)); err != nil {
|
||||
log.WithField("cluster", server).Warnf("encountered permissions issue while processing request: %v", err)
|
||||
return nil, common.PermissionDeniedAPIError
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(clust.Project, q.Server)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceClusters, rbac.ActionUpdate, CreateClusterRBACObject(clust.Project, q.Server)); err != nil {
|
||||
log.WithField("cluster", q.Server).Warnf("encountered permissions issue while processing request: %v", err)
|
||||
return nil, common.PermissionDeniedAPIError
|
||||
}
|
||||
@@ -458,7 +455,7 @@ func (s *Server) RotateAuth(ctx context.Context, q *cluster.ClusterQuery) (*clus
|
||||
ServerVersion: serverVersion,
|
||||
ConnectionState: appv1.ConnectionState{
|
||||
Status: appv1.ConnectionStatusSuccessful,
|
||||
ModifiedAt: &v1.Time{Time: time.Now()},
|
||||
ModifiedAt: &metav1.Time{Time: time.Now()},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -474,19 +471,8 @@ func (s *Server) RotateAuth(ctx context.Context, q *cluster.ClusterQuery) (*clus
|
||||
}
|
||||
|
||||
func (s *Server) toAPIResponse(clust *appv1.Cluster) *appv1.Cluster {
|
||||
clust = clust.Sanitized()
|
||||
_ = s.cache.GetClusterInfo(clust.Server, &clust.Info)
|
||||
|
||||
clust.Config.Password = ""
|
||||
clust.Config.BearerToken = ""
|
||||
clust.Config.TLSClientConfig.KeyData = nil
|
||||
if clust.Config.ExecProviderConfig != nil {
|
||||
// We can't know what the user has put into args or
|
||||
// env vars on the exec provider that might be sensitive
|
||||
// (e.g. --private-key=XXX, PASSWORD=XXX)
|
||||
// Implicitly assumes the command executable name is non-sensitive
|
||||
clust.Config.ExecProviderConfig.Env = make(map[string]string)
|
||||
clust.Config.ExecProviderConfig.Args = nil
|
||||
}
|
||||
// populate deprecated fields for backward compatibility
|
||||
// nolint:staticcheck
|
||||
clust.ServerVersion = clust.Info.ServerVersion
|
||||
@@ -497,11 +483,11 @@ func (s *Server) toAPIResponse(clust *appv1.Cluster) *appv1.Cluster {
|
||||
|
||||
// InvalidateCache invalidates cluster cache
|
||||
func (s *Server) InvalidateCache(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Cluster, error) {
|
||||
cls, err := s.getClusterAndVerifyAccess(ctx, q, rbacpolicy.ActionUpdate)
|
||||
cls, err := s.getClusterAndVerifyAccess(ctx, q, rbac.ActionUpdate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to verify access for cluster: %w", err)
|
||||
}
|
||||
now := v1.Now()
|
||||
now := metav1.Now()
|
||||
cls.RefreshRequestedAt = &now
|
||||
cls, err = s.db.UpdateCluster(ctx, cls)
|
||||
if err != nil {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user