mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-03-06 08:28:50 +01:00
Compare commits
13 Commits
v3.2.0
...
renovate/g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f04ca4a967 | ||
|
|
9ef837c326 | ||
|
|
c11d35a20f | ||
|
|
a7a07e2cd8 | ||
|
|
9faa6098ed | ||
|
|
0fb6c51f9d | ||
|
|
dbef22c843 | ||
|
|
47142b89f4 | ||
|
|
98a22612dd | ||
|
|
6cce4b29b9 | ||
|
|
9087ad7282 | ||
|
|
c377101491 | ||
|
|
1d13ebc372 |
18
.github/workflows/ci-build.yaml
vendored
18
.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.25.0'
|
||||
GOLANG_VERSION: '1.25.1'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -308,7 +308,7 @@ jobs:
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
with:
|
||||
# renovate: datasource=node-version packageName=node versioning=node
|
||||
node-version: '22.9.0'
|
||||
node-version: '22.19.0'
|
||||
- name: Restore node dependency cache
|
||||
id: cache-dependencies
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
@@ -407,7 +407,7 @@ jobs:
|
||||
test-e2e:
|
||||
name: Run end-to-end tests
|
||||
if: ${{ needs.changes.outputs.backend == 'true' }}
|
||||
runs-on: oracle-vm-16cpu-64gb-x86-64
|
||||
runs-on: ubuntu-latest-16-cores
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -426,7 +426,7 @@ jobs:
|
||||
- build-go
|
||||
- changes
|
||||
env:
|
||||
GOPATH: /home/ubuntu/go
|
||||
GOPATH: /home/runner/go
|
||||
ARGOCD_FAKE_IN_CLUSTER: 'true'
|
||||
ARGOCD_SSH_DATA_PATH: '/tmp/argo-e2e/app/config/ssh'
|
||||
ARGOCD_TLS_DATA_PATH: '/tmp/argo-e2e/app/config/tls'
|
||||
@@ -462,9 +462,9 @@ jobs:
|
||||
set -x
|
||||
curl -sfL https://get.k3s.io | sh -
|
||||
sudo chmod -R a+rw /etc/rancher/k3s
|
||||
sudo mkdir -p $HOME/.kube && sudo chown -R ubuntu $HOME/.kube
|
||||
sudo mkdir -p $HOME/.kube && sudo chown -R runner $HOME/.kube
|
||||
sudo k3s kubectl config view --raw > $HOME/.kube/config
|
||||
sudo chown ubuntu $HOME/.kube/config
|
||||
sudo chown runner $HOME/.kube/config
|
||||
sudo chmod go-r $HOME/.kube/config
|
||||
kubectl version
|
||||
- name: Restore go build cache
|
||||
@@ -474,7 +474,7 @@ jobs:
|
||||
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
|
||||
- name: Add ~/go/bin to PATH
|
||||
run: |
|
||||
echo "/home/ubuntu/go/bin" >> $GITHUB_PATH
|
||||
echo "/home/runner/go/bin" >> $GITHUB_PATH
|
||||
- name: Add /usr/local/bin to PATH
|
||||
run: |
|
||||
echo "/usr/local/bin" >> $GITHUB_PATH
|
||||
@@ -496,11 +496,11 @@ jobs:
|
||||
run: |
|
||||
docker pull ghcr.io/dexidp/dex:v2.43.0
|
||||
docker pull argoproj/argo-cd-ci-builder:v1.0.0
|
||||
docker pull redis:8.2.2-alpine
|
||||
docker pull redis:8.2.1-alpine
|
||||
- name: Create target directory for binaries in the build-process
|
||||
run: |
|
||||
mkdir -p dist
|
||||
chown ubuntu dist
|
||||
chown runner dist
|
||||
- name: Run E2E server and wait for it being available
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
|
||||
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.25.0
|
||||
go-version: 1.25.1
|
||||
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.25.0
|
||||
go-version: 1.25.1
|
||||
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.25.0' # Note: go-version must also be set in job argocd-image.with.go-version
|
||||
GOLANG_VERSION: '1.25.1' # Note: go-version must also be set in job argocd-image.with.go-version
|
||||
|
||||
jobs:
|
||||
argocd-image:
|
||||
@@ -25,49 +25,13 @@ 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.25.0
|
||||
go-version: 1.25.1
|
||||
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:
|
||||
@@ -86,17 +50,15 @@ 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
|
||||
@@ -180,7 +142,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:
|
||||
@@ -259,7 +221,6 @@ jobs:
|
||||
|
||||
post-release:
|
||||
needs:
|
||||
- setup-variables
|
||||
- argocd-image
|
||||
- goreleaser
|
||||
- generate-sbom
|
||||
@@ -268,8 +229,6 @@ 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
|
||||
@@ -283,6 +242,27 @@ 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 }}
|
||||
|
||||
1
.github/workflows/renovate.yaml
vendored
1
.github/workflows/renovate.yaml
vendored
@@ -10,6 +10,7 @@ permissions:
|
||||
jobs:
|
||||
renovate:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'argoproj/argo-cd'
|
||||
steps:
|
||||
- name: Get token
|
||||
id: get_token
|
||||
|
||||
@@ -49,14 +49,13 @@ archives:
|
||||
- argocd-cli
|
||||
name_template: |-
|
||||
{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}
|
||||
formats: [binary]
|
||||
formats: [ binary ]
|
||||
|
||||
checksum:
|
||||
name_template: 'cli_checksums.txt'
|
||||
algorithm: sha256
|
||||
|
||||
release:
|
||||
make_latest: '{{ .Env.GORELEASER_MAKE_LATEST }}'
|
||||
prerelease: auto
|
||||
draft: false
|
||||
header: |
|
||||
|
||||
@@ -24,6 +24,7 @@ packages:
|
||||
Renderer: {}
|
||||
github.com/argoproj/argo-cd/v3/commitserver/apiclient:
|
||||
interfaces:
|
||||
Clientset: {}
|
||||
CommitServiceClient: {}
|
||||
github.com/argoproj/argo-cd/v3/commitserver/commit:
|
||||
interfaces:
|
||||
@@ -34,7 +35,6 @@ packages:
|
||||
github.com/argoproj/argo-cd/v3/controller/hydrator:
|
||||
interfaces:
|
||||
Dependencies: {}
|
||||
RepoGetter: {}
|
||||
github.com/argoproj/argo-cd/v3/pkg/apiclient/cluster:
|
||||
interfaces:
|
||||
ClusterServiceServer: {}
|
||||
|
||||
@@ -4,7 +4,7 @@ ARG BASE_IMAGE=docker.io/library/ubuntu:25.04@sha256:10bb10bb062de665d4dc3e0ea36
|
||||
# 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.25.0@sha256:9e56f0d0f043a68bb8c47c819e47dc29f6e8f5129b8885bed9d43f058f7f3ed6 AS builder
|
||||
FROM docker.io/library/golang:1.25.1@sha256:8305f5fa8ea63c7b5bc85bd223ccc62941f852318ebfbd22f53bbd0b358c07e1 AS builder
|
||||
|
||||
WORKDIR /tmp
|
||||
|
||||
@@ -85,7 +85,7 @@ WORKDIR /home/argocd
|
||||
####################################################################################################
|
||||
# Argo CD UI stage
|
||||
####################################################################################################
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/node:23.0.0@sha256:e643c0b70dca9704dff42e12b17f5b719dbe4f95e6392fc2dfa0c5f02ea8044d AS argocd-ui
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/node:23.11.1@sha256:9a25b5a6f9a90218b73a62205f111e71de5e4289aee952b4dd7e86f7498f2544 AS argocd-ui
|
||||
|
||||
WORKDIR /src
|
||||
COPY ["ui/package.json", "ui/yarn.lock", "./"]
|
||||
@@ -103,7 +103,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.25.0@sha256:9e56f0d0f043a68bb8c47c819e47dc29f6e8f5129b8885bed9d43f058f7f3ed6 AS argocd-build
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.25.1@sha256:8305f5fa8ea63c7b5bc85bd223ccc62941f852318ebfbd22f53bbd0b358c07e1 AS argocd-build
|
||||
|
||||
WORKDIR /go/src/github.com/argoproj/argo-cd
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM docker.io/library/golang:1.25.0@sha256:9e56f0d0f043a68bb8c47c819e47dc29f6e8f5129b8885bed9d43f058f7f3ed6
|
||||
FROM docker.io/library/golang:1.25.1@sha256:8305f5fa8ea63c7b5bc85bd223ccc62941f852318ebfbd22f53bbd0b358c07e1
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/retry"
|
||||
"k8s.io/utils/ptr"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
@@ -46,6 +47,8 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
|
||||
"github.com/argoproj/gitops-engine/pkg/health"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/controllers/template"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/generators"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/metrics"
|
||||
@@ -100,7 +103,6 @@ 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
|
||||
@@ -227,8 +229,6 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
return ctrl.Result{}, fmt.Errorf("failed to get update resources status for application set: %w", err)
|
||||
}
|
||||
|
||||
// appMap is a name->app collection of Applications in this ApplicationSet.
|
||||
appMap := map[string]argov1alpha1.Application{}
|
||||
// appSyncMap tracks which apps will be synced during this reconciliation.
|
||||
appSyncMap := map[string]bool{}
|
||||
|
||||
@@ -242,33 +242,11 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
return ctrl.Result{}, fmt.Errorf("failed to clear previous AppSet application statuses for %v: %w", applicationSetInfo.Name, err)
|
||||
}
|
||||
} else if isRollingSyncStrategy(&applicationSetInfo) {
|
||||
// The appset uses progressive sync with `RollingSync` strategy
|
||||
for _, app := range currentApplications {
|
||||
appMap[app.Name] = app
|
||||
}
|
||||
|
||||
appSyncMap, err = r.performProgressiveSyncs(ctx, logCtx, applicationSetInfo, currentApplications, generatedApplications, appMap)
|
||||
appSyncMap, err = r.performProgressiveSyncs(ctx, logCtx, applicationSetInfo, currentApplications, generatedApplications)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, fmt.Errorf("failed to perform progressive sync reconciliation for application set: %w", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Progressive Sync is disabled, clear any existing applicationStatus to prevent stale data
|
||||
if len(applicationSetInfo.Status.ApplicationStatus) > 0 {
|
||||
logCtx.Infof("Progressive Sync disabled, removing %v 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 AppSet application statuses when Progressive Sync is disabled for %v: %w", applicationSetInfo.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var validApps []argov1alpha1.Application
|
||||
for i := range generatedApplications {
|
||||
if validateErrors[generatedApplications[i].QualifiedName()] == nil {
|
||||
validApps = append(validApps, generatedApplications[i])
|
||||
}
|
||||
}
|
||||
|
||||
if len(validateErrors) > 0 {
|
||||
@@ -298,13 +276,25 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
)
|
||||
}
|
||||
|
||||
var validApps []argov1alpha1.Application
|
||||
for i := range generatedApplications {
|
||||
if validateErrors[generatedApplications[i].QualifiedName()] == nil {
|
||||
validApps = append(validApps, generatedApplications[i])
|
||||
}
|
||||
}
|
||||
|
||||
if r.EnableProgressiveSyncs {
|
||||
// trigger appropriate application syncs if RollingSync strategy is enabled
|
||||
if progressiveSyncsRollingSyncStrategyEnabled(&applicationSetInfo) {
|
||||
validApps = r.syncValidApplications(logCtx, &applicationSetInfo, appSyncMap, appMap, validApps)
|
||||
validApps = r.syncDesiredApplications(logCtx, &applicationSetInfo, appSyncMap, validApps)
|
||||
}
|
||||
}
|
||||
|
||||
// Sort apps by name so they are updated/created in the same order, and condition errors are the same
|
||||
sort.Slice(validApps, func(i, j int) bool {
|
||||
return validApps[i].Name < validApps[j].Name
|
||||
})
|
||||
|
||||
if utils.DefaultPolicy(applicationSetInfo.Spec.SyncPolicy, r.Policy, r.EnablePolicyOverride).AllowUpdate() {
|
||||
err = r.createOrUpdateInCluster(ctx, logCtx, applicationSetInfo, validApps)
|
||||
if err != nil {
|
||||
@@ -336,6 +326,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
}
|
||||
|
||||
if utils.DefaultPolicy(applicationSetInfo.Spec.SyncPolicy, r.Policy, r.EnablePolicyOverride).AllowDelete() {
|
||||
// Delete the generatedApplications instead of the validApps because we want to be able to delete applications in error/invalid state
|
||||
err = r.deleteInCluster(ctx, logCtx, applicationSetInfo, generatedApplications)
|
||||
if err != nil {
|
||||
_ = r.setApplicationSetStatusCondition(ctx,
|
||||
@@ -942,7 +933,7 @@ func (r *ApplicationSetReconciler) removeOwnerReferencesOnDeleteAppSet(ctx conte
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ApplicationSetReconciler) performProgressiveSyncs(ctx context.Context, logCtx *log.Entry, appset argov1alpha1.ApplicationSet, applications []argov1alpha1.Application, desiredApplications []argov1alpha1.Application, appMap map[string]argov1alpha1.Application) (map[string]bool, error) {
|
||||
func (r *ApplicationSetReconciler) performProgressiveSyncs(ctx context.Context, logCtx *log.Entry, appset argov1alpha1.ApplicationSet, applications []argov1alpha1.Application, desiredApplications []argov1alpha1.Application) (map[string]bool, error) {
|
||||
appDependencyList, appStepMap := r.buildAppDependencyList(logCtx, appset, desiredApplications)
|
||||
|
||||
_, err := r.updateApplicationSetApplicationStatus(ctx, logCtx, &appset, applications, appStepMap)
|
||||
@@ -951,21 +942,21 @@ func (r *ApplicationSetReconciler) performProgressiveSyncs(ctx context.Context,
|
||||
}
|
||||
|
||||
logCtx.Infof("ApplicationSet %v step list:", appset.Name)
|
||||
for i, step := range appDependencyList {
|
||||
logCtx.Infof("step %v: %+v", i+1, step)
|
||||
for stepIndex, applicationNames := range appDependencyList {
|
||||
logCtx.Infof("step %v: %+v", stepIndex+1, applicationNames)
|
||||
}
|
||||
|
||||
appSyncMap := r.buildAppSyncMap(appset, appDependencyList, appMap)
|
||||
logCtx.Infof("Application allowed to sync before maxUpdate?: %+v", appSyncMap)
|
||||
appsToSync := r.getAppsToSync(appset, appDependencyList, applications)
|
||||
logCtx.Infof("Application allowed to sync before maxUpdate?: %+v", appsToSync)
|
||||
|
||||
_, err = r.updateApplicationSetApplicationStatusProgress(ctx, logCtx, &appset, appSyncMap, appStepMap)
|
||||
_, err = r.updateApplicationSetApplicationStatusProgress(ctx, logCtx, &appset, appsToSync, appStepMap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update applicationset application status progress: %w", err)
|
||||
}
|
||||
|
||||
_ = r.updateApplicationSetApplicationStatusConditions(ctx, &appset)
|
||||
|
||||
return appSyncMap, nil
|
||||
return appsToSync, nil
|
||||
}
|
||||
|
||||
// this list tracks which Applications belong to each RollingUpdate step
|
||||
@@ -1039,55 +1030,53 @@ func labelMatchedExpression(logCtx *log.Entry, val string, matchExpression argov
|
||||
return valueMatched
|
||||
}
|
||||
|
||||
// this map is used to determine which stage of Applications are ready to be updated in the reconciler loop
|
||||
func (r *ApplicationSetReconciler) buildAppSyncMap(applicationSet argov1alpha1.ApplicationSet, appDependencyList [][]string, appMap map[string]argov1alpha1.Application) map[string]bool {
|
||||
// getAppsToSync returns a Map of Applications that should be synced in this progressive sync wave
|
||||
func (r *ApplicationSetReconciler) getAppsToSync(applicationSet argov1alpha1.ApplicationSet, appDependencyList [][]string, currentApplications []argov1alpha1.Application) map[string]bool {
|
||||
appSyncMap := map[string]bool{}
|
||||
syncEnabled := true
|
||||
currentAppsMap := map[string]bool{}
|
||||
|
||||
// healthy stages and the first non-healthy stage should have sync enabled
|
||||
// every stage after should have sync disabled
|
||||
for _, app := range currentApplications {
|
||||
currentAppsMap[app.Name] = true
|
||||
}
|
||||
|
||||
for i := range appDependencyList {
|
||||
for stepIndex := range appDependencyList {
|
||||
// set the syncEnabled boolean for every Application in the current step
|
||||
for _, appName := range appDependencyList[i] {
|
||||
appSyncMap[appName] = syncEnabled
|
||||
for _, appName := range appDependencyList[stepIndex] {
|
||||
appSyncMap[appName] = true
|
||||
}
|
||||
|
||||
// detect if we need to halt before progressing to the next step
|
||||
for _, appName := range appDependencyList[i] {
|
||||
// evaluate if we need to sync next waves
|
||||
syncNextWave := true
|
||||
for _, appName := range appDependencyList[stepIndex] {
|
||||
// Check if application is created and managed by this AppSet, if it is not created yet, we cannot progress
|
||||
if _, ok := currentAppsMap[appName]; !ok {
|
||||
syncNextWave = false
|
||||
break
|
||||
}
|
||||
|
||||
idx := findApplicationStatusIndex(applicationSet.Status.ApplicationStatus, appName)
|
||||
if idx == -1 {
|
||||
// no Application status found, likely because the Application is being newly created
|
||||
syncEnabled = false
|
||||
// No Application status found, likely because the Application is being newly created
|
||||
// This mean this wave is not yet completed
|
||||
syncNextWave = false
|
||||
break
|
||||
}
|
||||
|
||||
appStatus := applicationSet.Status.ApplicationStatus[idx]
|
||||
app, ok := appMap[appName]
|
||||
if !ok {
|
||||
// application name not found in the list of applications managed by this ApplicationSet, maybe because it's being deleted
|
||||
syncEnabled = false
|
||||
break
|
||||
}
|
||||
syncEnabled = appSyncEnabledForNextStep(&applicationSet, app, appStatus)
|
||||
if !syncEnabled {
|
||||
if appStatus.Status != argov1alpha1.ProgressiveSyncHealthy {
|
||||
// At least one application in this wave is not yet healthy. We cannot proceed to the next wave
|
||||
syncNextWave = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !syncNextWave {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return appSyncMap
|
||||
}
|
||||
|
||||
func appSyncEnabledForNextStep(appset *argov1alpha1.ApplicationSet, app argov1alpha1.Application, appStatus argov1alpha1.ApplicationSetApplicationStatus) bool {
|
||||
if progressiveSyncsRollingSyncStrategyEnabled(appset) {
|
||||
// we still need to complete the current step if the Application is not yet Healthy or there are still pending Application changes
|
||||
return isApplicationHealthy(app) && appStatus.Status == "Healthy"
|
||||
}
|
||||
|
||||
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
|
||||
@@ -1098,29 +1087,21 @@ func progressiveSyncsRollingSyncStrategyEnabled(appset *argov1alpha1.Application
|
||||
return isRollingSyncStrategy(appset) && len(appset.Spec.Strategy.RollingSync.Steps) > 0
|
||||
}
|
||||
|
||||
func isProgressiveSyncDeletionOrderReversed(appset *argov1alpha1.ApplicationSet) bool {
|
||||
// When progressive sync is enabled + deletionOrder is set to Reverse (case-insensitive)
|
||||
return progressiveSyncsRollingSyncStrategyEnabled(appset) && strings.EqualFold(appset.Spec.Strategy.DeletionOrder, ReverseDeletionOrder)
|
||||
}
|
||||
|
||||
func isApplicationHealthy(app argov1alpha1.Application) bool {
|
||||
healthStatusString, syncStatusString, operationPhaseString := statusStrings(app)
|
||||
|
||||
if healthStatusString == "Healthy" && syncStatusString != "OutOfSync" && (operationPhaseString == "Succeeded" || operationPhaseString == "") {
|
||||
return true
|
||||
func isApplicationWithError(app argov1alpha1.Application) bool {
|
||||
for _, condition := range app.Status.Conditions {
|
||||
if condition.Type == argov1alpha1.ApplicationConditionInvalidSpecError {
|
||||
return true
|
||||
}
|
||||
if condition.Type == argov1alpha1.ApplicationConditionUnknownError {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func statusStrings(app argov1alpha1.Application) (string, string, string) {
|
||||
healthStatusString := string(app.Status.Health.Status)
|
||||
syncStatusString := string(app.Status.Sync.Status)
|
||||
operationPhaseString := ""
|
||||
if app.Status.OperationState != nil {
|
||||
operationPhaseString = string(app.Status.OperationState.Phase)
|
||||
}
|
||||
|
||||
return healthStatusString, syncStatusString, operationPhaseString
|
||||
func isProgressiveSyncDeletionOrderReversed(appset *argov1alpha1.ApplicationSet) bool {
|
||||
// When progressive sync is enabled + deletionOrder is set to Reverse (case-insensitive)
|
||||
return progressiveSyncsRollingSyncStrategyEnabled(appset) && strings.EqualFold(appset.Spec.Strategy.DeletionOrder, ReverseDeletionOrder)
|
||||
}
|
||||
|
||||
func getAppStep(appName string, appStepMap map[string]int) int {
|
||||
@@ -1139,81 +1120,112 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
|
||||
appStatuses := make([]argov1alpha1.ApplicationSetApplicationStatus, 0, len(applications))
|
||||
|
||||
for _, app := range applications {
|
||||
healthStatusString, syncStatusString, operationPhaseString := statusStrings(app)
|
||||
|
||||
idx := findApplicationStatusIndex(applicationSet.Status.ApplicationStatus, app.Name)
|
||||
appHealthStatus := app.Status.Health.Status
|
||||
appSyncStatus := app.Status.Sync.Status
|
||||
|
||||
currentAppStatus := argov1alpha1.ApplicationSetApplicationStatus{}
|
||||
|
||||
idx := findApplicationStatusIndex(applicationSet.Status.ApplicationStatus, app.Name)
|
||||
if idx == -1 {
|
||||
// AppStatus not found, set default status of "Waiting"
|
||||
currentAppStatus = argov1alpha1.ApplicationSetApplicationStatus{
|
||||
Application: app.Name,
|
||||
TargetRevisions: app.Status.GetRevisions(),
|
||||
LastTransitionTime: &now,
|
||||
Message: "No Application status found, defaulting status to Waiting.",
|
||||
Status: "Waiting",
|
||||
Message: "No Application status found, defaulting status to Waiting",
|
||||
Status: argov1alpha1.ProgressiveSyncWaiting,
|
||||
Step: strconv.Itoa(getAppStep(app.Name, appStepMap)),
|
||||
}
|
||||
} else {
|
||||
// we have an existing AppStatus
|
||||
currentAppStatus = applicationSet.Status.ApplicationStatus[idx]
|
||||
if !reflect.DeepEqual(currentAppStatus.TargetRevisions, app.Status.GetRevisions()) {
|
||||
currentAppStatus.Message = "Application has pending changes, setting status to Waiting."
|
||||
}
|
||||
}
|
||||
|
||||
statusLogCtx := logCtx.WithFields(log.Fields{
|
||||
"app.name": currentAppStatus.Application,
|
||||
"app.health": appHealthStatus,
|
||||
"app.sync": appSyncStatus,
|
||||
"status.status": currentAppStatus.Status,
|
||||
"status.message": currentAppStatus.Message,
|
||||
"status.step": currentAppStatus.Step,
|
||||
"status.targetRevisions": strings.Join(currentAppStatus.TargetRevisions, ","),
|
||||
})
|
||||
|
||||
newAppStatus := currentAppStatus.DeepCopy()
|
||||
newAppStatus.Step = strconv.Itoa(getAppStep(newAppStatus.Application, appStepMap))
|
||||
|
||||
if !reflect.DeepEqual(currentAppStatus.TargetRevisions, app.Status.GetRevisions()) {
|
||||
currentAppStatus.TargetRevisions = app.Status.GetRevisions()
|
||||
currentAppStatus.Status = "Waiting"
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
// A new version is available in the application and we need to re-sync the application
|
||||
newAppStatus.TargetRevisions = app.Status.GetRevisions()
|
||||
newAppStatus.Message = "Application has pending changes, setting status to Waiting"
|
||||
newAppStatus.Status = argov1alpha1.ProgressiveSyncWaiting
|
||||
newAppStatus.LastTransitionTime = &now
|
||||
}
|
||||
|
||||
appOutdated := false
|
||||
if progressiveSyncsRollingSyncStrategyEnabled(applicationSet) {
|
||||
appOutdated = syncStatusString == "OutOfSync"
|
||||
}
|
||||
if newAppStatus.Status == argov1alpha1.ProgressiveSyncWaiting {
|
||||
// App has changed to waiting because the TargetRevisions changed or it is a new selected app
|
||||
// This does not mean we should always sync the app. The app may not be OutOfSync
|
||||
// and may not require a sync if it does not have differences.
|
||||
if appSyncStatus == argov1alpha1.SyncStatusCodeSynced {
|
||||
if app.Status.Health.Status == health.HealthStatusHealthy {
|
||||
newAppStatus.LastTransitionTime = &now
|
||||
newAppStatus.Status = argov1alpha1.ProgressiveSyncHealthy
|
||||
newAppStatus.Message = "Application resource has synced, updating status to Healthy"
|
||||
} else {
|
||||
newAppStatus.LastTransitionTime = &now
|
||||
newAppStatus.Status = argov1alpha1.ProgressiveSyncProgressing
|
||||
newAppStatus.Message = "Application resource has synced, updating status to Progressing"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The target revision is the same, so we need to evaluate the current revision progress
|
||||
if currentAppStatus.Status == argov1alpha1.ProgressiveSyncPending {
|
||||
// No need to evaluate status health further if the application did not change since our last transition
|
||||
if app.Status.ReconciledAt == nil || (newAppStatus.LastTransitionTime != nil && app.Status.ReconciledAt.After(newAppStatus.LastTransitionTime.Time)) {
|
||||
// Validate that at least one sync was trigerred after the pending transition time
|
||||
if app.Status.OperationState != nil && app.Status.OperationState.StartedAt.After(currentAppStatus.LastTransitionTime.Time) {
|
||||
statusLogCtx = statusLogCtx.WithField("app.operation", app.Status.OperationState.Phase)
|
||||
newAppStatus.LastTransitionTime = &now
|
||||
newAppStatus.Status = argov1alpha1.ProgressiveSyncProgressing
|
||||
|
||||
if appOutdated && currentAppStatus.Status != "Waiting" && currentAppStatus.Status != "Pending" {
|
||||
logCtx.Infof("Application %v is outdated, updating its ApplicationSet status to Waiting", app.Name)
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Status = "Waiting"
|
||||
currentAppStatus.Message = "Application has pending changes, setting status to Waiting."
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
}
|
||||
switch {
|
||||
case app.Status.OperationState.Phase.Successful():
|
||||
newAppStatus.Message = "Application resource completed a sync successfully, updating status from Pending to Progressing"
|
||||
case app.Status.OperationState.Phase.Completed():
|
||||
newAppStatus.Message = "Application resource completed a sync, updating status from Pending to Progressing"
|
||||
default:
|
||||
// If a sync fails or has errors, the Application should be configured with retry. It is not the appset's job to retry failed syncs
|
||||
newAppStatus.Message = "Application resource became Progressing, updating status from Pending to Progressing"
|
||||
}
|
||||
} else if isApplicationWithError(app) {
|
||||
// Validate if the application has errors preventing it to be reconciled and perform syncs
|
||||
// If it does, we move it to progressing.
|
||||
newAppStatus.LastTransitionTime = &now
|
||||
newAppStatus.Status = argov1alpha1.ProgressiveSyncProgressing
|
||||
newAppStatus.Message = "Application resource has error and cannot sync, updating status to Progressing"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if currentAppStatus.Status == "Pending" {
|
||||
if !appOutdated && operationPhaseString == "Succeeded" {
|
||||
logCtx.Infof("Application %v has completed a sync successfully, updating its ApplicationSet status to Progressing", app.Name)
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Status = "Progressing"
|
||||
currentAppStatus.Message = "Application resource completed a sync successfully, updating status from Pending to Progressing."
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
} else if operationPhaseString == "Running" || healthStatusString == "Progressing" {
|
||||
logCtx.Infof("Application %v has entered Progressing status, updating its ApplicationSet status to Progressing", app.Name)
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Status = "Progressing"
|
||||
currentAppStatus.Message = "Application resource became Progressing, updating status from Pending to Progressing."
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
if currentAppStatus.Status == argov1alpha1.ProgressiveSyncProgressing {
|
||||
// If the status has reached progressing, we know a sync has been triggered. No matter the result of that operation,
|
||||
// we want an the app to reach the Healthy state for the current revision.
|
||||
if appHealthStatus == health.HealthStatusHealthy && appSyncStatus == argov1alpha1.SyncStatusCodeSynced {
|
||||
newAppStatus.LastTransitionTime = &now
|
||||
newAppStatus.Status = argov1alpha1.ProgressiveSyncHealthy
|
||||
newAppStatus.Message = "Application resource became Healthy, updating status from Progressing to Healthy"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if currentAppStatus.Status == "Waiting" && isApplicationHealthy(app) {
|
||||
logCtx.Infof("Application %v is already synced and healthy, updating its ApplicationSet status to Healthy", app.Name)
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Status = healthStatusString
|
||||
currentAppStatus.Message = "Application resource is already Healthy, updating status from Waiting to Healthy."
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
if newAppStatus.LastTransitionTime == &now {
|
||||
statusLogCtx.WithFields(log.Fields{
|
||||
"new_status.status": newAppStatus.Status,
|
||||
"new_status.message": newAppStatus.Message,
|
||||
"new_status.step": newAppStatus.Step,
|
||||
"new_status.targetRevisions": strings.Join(newAppStatus.TargetRevisions, ","),
|
||||
}).Info("Progressive sync application changed status")
|
||||
}
|
||||
|
||||
if currentAppStatus.Status == "Progressing" && isApplicationHealthy(app) {
|
||||
logCtx.Infof("Application %v has completed Progressing status, updating its ApplicationSet status to Healthy", app.Name)
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Status = healthStatusString
|
||||
currentAppStatus.Message = "Application resource became Healthy, updating status from Progressing to Healthy."
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
}
|
||||
|
||||
appStatuses = append(appStatuses, currentAppStatus)
|
||||
appStatuses = append(appStatuses, *newAppStatus)
|
||||
}
|
||||
|
||||
err := r.setAppSetApplicationStatus(ctx, logCtx, applicationSet, appStatuses)
|
||||
@@ -1225,7 +1237,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
|
||||
}
|
||||
|
||||
// check Applications that are in Waiting status and promote them to Pending if needed
|
||||
func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress(ctx context.Context, logCtx *log.Entry, applicationSet *argov1alpha1.ApplicationSet, appSyncMap map[string]bool, appStepMap map[string]int) ([]argov1alpha1.ApplicationSetApplicationStatus, error) {
|
||||
func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress(ctx context.Context, logCtx *log.Entry, applicationSet *argov1alpha1.ApplicationSet, appsToSync map[string]bool, appStepMap map[string]int) ([]argov1alpha1.ApplicationSetApplicationStatus, error) {
|
||||
now := metav1.Now()
|
||||
|
||||
appStatuses := make([]argov1alpha1.ApplicationSetApplicationStatus, 0, len(applicationSet.Status.ApplicationStatus))
|
||||
@@ -1241,12 +1253,20 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress
|
||||
for _, appStatus := range applicationSet.Status.ApplicationStatus {
|
||||
totalCountMap[appStepMap[appStatus.Application]]++
|
||||
|
||||
if appStatus.Status == "Pending" || appStatus.Status == "Progressing" {
|
||||
if appStatus.Status == argov1alpha1.ProgressiveSyncPending || appStatus.Status == argov1alpha1.ProgressiveSyncProgressing {
|
||||
updateCountMap[appStepMap[appStatus.Application]]++
|
||||
}
|
||||
}
|
||||
|
||||
for _, appStatus := range applicationSet.Status.ApplicationStatus {
|
||||
statusLogCtx := logCtx.WithFields(log.Fields{
|
||||
"app.name": appStatus.Application,
|
||||
"status.status": appStatus.Status,
|
||||
"status.message": appStatus.Message,
|
||||
"status.step": appStatus.Step,
|
||||
"status.targetRevisions": strings.Join(appStatus.TargetRevisions, ","),
|
||||
})
|
||||
|
||||
maxUpdateAllowed := true
|
||||
maxUpdate := &intstr.IntOrString{}
|
||||
if progressiveSyncsRollingSyncStrategyEnabled(applicationSet) {
|
||||
@@ -1257,7 +1277,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress
|
||||
if maxUpdate != nil {
|
||||
maxUpdateVal, err := intstr.GetScaledValueFromIntOrPercent(maxUpdate, totalCountMap[appStepMap[appStatus.Application]], false)
|
||||
if err != nil {
|
||||
logCtx.Warnf("AppSet '%v' has a invalid maxUpdate value '%+v', ignoring maxUpdate logic for this step: %v", applicationSet.Name, maxUpdate, err)
|
||||
statusLogCtx.Warnf("AppSet has a invalid maxUpdate value '%+v', ignoring maxUpdate logic for this step: %v", maxUpdate, err)
|
||||
}
|
||||
|
||||
// ensure that percentage values greater than 0% always result in at least 1 Application being selected
|
||||
@@ -1267,16 +1287,21 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress
|
||||
|
||||
if updateCountMap[appStepMap[appStatus.Application]] >= maxUpdateVal {
|
||||
maxUpdateAllowed = false
|
||||
logCtx.Infof("Application %v is not allowed to update yet, %v/%v Applications already updating in step %v in AppSet %v", appStatus.Application, updateCountMap[appStepMap[appStatus.Application]], maxUpdateVal, getAppStep(appStatus.Application, appStepMap), applicationSet.Name)
|
||||
statusLogCtx.Infof("Application is not allowed to update yet, %v/%v Applications already updating in step %v", updateCountMap[appStepMap[appStatus.Application]], maxUpdateVal, getAppStep(appStatus.Application, appStepMap))
|
||||
}
|
||||
}
|
||||
|
||||
if appStatus.Status == "Waiting" && appSyncMap[appStatus.Application] && maxUpdateAllowed {
|
||||
logCtx.Infof("Application %v moved to Pending status, watching for the Application to start Progressing", appStatus.Application)
|
||||
if appStatus.Status == argov1alpha1.ProgressiveSyncWaiting && appsToSync[appStatus.Application] && maxUpdateAllowed {
|
||||
appStatus.LastTransitionTime = &now
|
||||
appStatus.Status = "Pending"
|
||||
appStatus.Message = "Application moved to Pending status, watching for the Application resource to start Progressing."
|
||||
appStatus.Step = strconv.Itoa(getAppStep(appStatus.Application, appStepMap))
|
||||
appStatus.Status = argov1alpha1.ProgressiveSyncPending
|
||||
appStatus.Message = "Application moved to Pending status, watching for the Application resource to start Progressing"
|
||||
|
||||
statusLogCtx.WithFields(log.Fields{
|
||||
"new_status.status": appStatus.Status,
|
||||
"new_status.message": appStatus.Message,
|
||||
"new_status.step": appStatus.Step,
|
||||
"new_status.targetRevisions": strings.Join(appStatus.TargetRevisions, ","),
|
||||
}).Info("Progressive sync application changed status")
|
||||
|
||||
updateCountMap[appStepMap[appStatus.Application]]++
|
||||
}
|
||||
@@ -1301,9 +1326,9 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusConditio
|
||||
completedWaves := map[string]bool{}
|
||||
for _, appStatus := range applicationSet.Status.ApplicationStatus {
|
||||
if v, ok := completedWaves[appStatus.Step]; !ok {
|
||||
completedWaves[appStatus.Step] = appStatus.Status == "Healthy"
|
||||
completedWaves[appStatus.Step] = appStatus.Status == argov1alpha1.ProgressiveSyncHealthy
|
||||
} else {
|
||||
completedWaves[appStatus.Step] = v && appStatus.Status == "Healthy"
|
||||
completedWaves[appStatus.Step] = v && appStatus.Status == argov1alpha1.ProgressiveSyncHealthy
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1409,13 +1434,7 @@ func (r *ApplicationSetReconciler) updateResourcesStatus(ctx context.Context, lo
|
||||
sort.Slice(statuses, func(i, j int) bool {
|
||||
return statuses[i].Name < statuses[j].Name
|
||||
})
|
||||
resourcesCount := int64(len(statuses))
|
||||
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
|
||||
appset.Status.ResourcesCount = resourcesCount
|
||||
// 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 {
|
||||
namespacedName := types.NamespacedName{Namespace: appset.Namespace, Name: appset.Name}
|
||||
@@ -1428,7 +1447,6 @@ func (r *ApplicationSetReconciler) updateResourcesStatus(ctx context.Context, lo
|
||||
}
|
||||
|
||||
updatedAppset.Status.Resources = appset.Status.Resources
|
||||
updatedAppset.Status.ResourcesCount = resourcesCount
|
||||
|
||||
// Update the newly fetched object with new status resources
|
||||
err := r.Client.Status().Update(ctx, updatedAppset)
|
||||
@@ -1525,30 +1543,31 @@ func (r *ApplicationSetReconciler) setAppSetApplicationStatus(ctx context.Contex
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ApplicationSetReconciler) syncValidApplications(logCtx *log.Entry, applicationSet *argov1alpha1.ApplicationSet, appSyncMap map[string]bool, appMap map[string]argov1alpha1.Application, validApps []argov1alpha1.Application) []argov1alpha1.Application {
|
||||
func (r *ApplicationSetReconciler) syncDesiredApplications(logCtx *log.Entry, applicationSet *argov1alpha1.ApplicationSet, appsToSync map[string]bool, desiredApplications []argov1alpha1.Application) []argov1alpha1.Application {
|
||||
rolloutApps := []argov1alpha1.Application{}
|
||||
for i := range validApps {
|
||||
for i := range desiredApplications {
|
||||
pruneEnabled := false
|
||||
|
||||
// ensure that Applications generated with RollingSync do not have an automated sync policy, since the AppSet controller will handle triggering the sync operation instead
|
||||
if validApps[i].Spec.SyncPolicy != nil && validApps[i].Spec.SyncPolicy.IsAutomatedSyncEnabled() {
|
||||
pruneEnabled = validApps[i].Spec.SyncPolicy.Automated.Prune
|
||||
validApps[i].Spec.SyncPolicy.Automated = nil
|
||||
if desiredApplications[i].Spec.SyncPolicy != nil && desiredApplications[i].Spec.SyncPolicy.IsAutomatedSyncEnabled() {
|
||||
pruneEnabled = desiredApplications[i].Spec.SyncPolicy.Automated.Prune
|
||||
desiredApplications[i].Spec.SyncPolicy.Automated.Enabled = ptr.To(false)
|
||||
}
|
||||
|
||||
appSetStatusPending := false
|
||||
idx := findApplicationStatusIndex(applicationSet.Status.ApplicationStatus, validApps[i].Name)
|
||||
if idx > -1 && applicationSet.Status.ApplicationStatus[idx].Status == "Pending" {
|
||||
idx := findApplicationStatusIndex(applicationSet.Status.ApplicationStatus, desiredApplications[i].Name)
|
||||
if idx > -1 && applicationSet.Status.ApplicationStatus[idx].Status == argov1alpha1.ProgressiveSyncPending {
|
||||
// only trigger a sync for Applications that are in Pending status, since this is governed by maxUpdate
|
||||
appSetStatusPending = true
|
||||
}
|
||||
|
||||
// check appSyncMap to determine which Applications are ready to be updated and which should be skipped
|
||||
if appSyncMap[validApps[i].Name] && appMap[validApps[i].Name].Status.Sync.Status == "OutOfSync" && appSetStatusPending {
|
||||
logCtx.Infof("triggering sync for application: %v, prune enabled: %v", validApps[i].Name, pruneEnabled)
|
||||
validApps[i] = syncApplication(validApps[i], pruneEnabled)
|
||||
// check appsToSync to determine which Applications are ready to be updated and which should be skipped
|
||||
if appsToSync[desiredApplications[i].Name] && appSetStatusPending {
|
||||
logCtx.Infof("triggering sync for application: %v, prune enabled: %v", desiredApplications[i].Name, pruneEnabled)
|
||||
desiredApplications[i] = syncApplication(desiredApplications[i], pruneEnabled)
|
||||
}
|
||||
rolloutApps = append(rolloutApps, validApps[i])
|
||||
|
||||
rolloutApps = append(rolloutApps, desiredApplications[i])
|
||||
}
|
||||
return rolloutApps
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,14 +26,10 @@ 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/v3/util/guard"
|
||||
)
|
||||
|
||||
const payloadQueueSize = 50000
|
||||
|
||||
const panicMsgAppSet = "panic while processing applicationset-controller webhook event"
|
||||
|
||||
type WebhookHandler struct {
|
||||
sync.WaitGroup // for testing
|
||||
github *github.Webhook
|
||||
@@ -106,7 +102,6 @@ func NewWebhookHandler(webhookParallelism int, argocdSettingsMgr *argosettings.S
|
||||
}
|
||||
|
||||
func (h *WebhookHandler) startWorkerPool(webhookParallelism int) {
|
||||
compLog := log.WithField("component", "applicationset-webhook")
|
||||
for i := 0; i < webhookParallelism; i++ {
|
||||
h.Add(1)
|
||||
go func() {
|
||||
@@ -116,7 +111,7 @@ func (h *WebhookHandler) startWorkerPool(webhookParallelism int) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
guard.RecoverAndLog(func() { h.HandleEvent(payload) }, compLog, panicMsgAppSet)
|
||||
h.HandleEvent(payload)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
11
assets/swagger.json
generated
11
assets/swagger.json
generated
@@ -7077,7 +7077,7 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"title": "Status contains the AppSet's perceived status of the managed Application resource: (Waiting, Pending, Progressing, Healthy)"
|
||||
"title": "Status contains the AppSet's perceived status of the managed Application resource"
|
||||
},
|
||||
"step": {
|
||||
"type": "string",
|
||||
@@ -7322,11 +7322,6 @@
|
||||
"items": {
|
||||
"$ref": "#/definitions/applicationv1alpha1ResourceStatus"
|
||||
}
|
||||
},
|
||||
"resourcesCount": {
|
||||
"description": "ResourcesCount is the total number of resources managed by this application set. The count may be higher than actual number of items in the Resources field when\nthe number of managed resources exceeds the limit imposed by the controller (to avoid making the status field too large).",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -10577,8 +10572,8 @@
|
||||
"type": "string"
|
||||
},
|
||||
"targetBranch": {
|
||||
"description": "TargetBranch is the branch from which hydrated manifests will be synced.\nIf HydrateTo is not set, this is also the branch to which hydrated manifests are committed.",
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"title": "TargetBranch is the branch to which hydrated manifests should be committed"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/reposerver/apiclient"
|
||||
logutils "github.com/argoproj/argo-cd/v3/util/log"
|
||||
"github.com/argoproj/argo-cd/v3/util/profile"
|
||||
"github.com/argoproj/argo-cd/v3/util/tls"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/controllers"
|
||||
@@ -80,7 +79,6 @@ func NewCommand() *cobra.Command {
|
||||
enableScmProviders bool
|
||||
webhookParallelism int
|
||||
tokenRefStrictMode bool
|
||||
maxResourcesStatusCount int
|
||||
)
|
||||
scheme := runtime.NewScheme()
|
||||
_ = clientgoscheme.AddToScheme(scheme)
|
||||
@@ -171,15 +169,6 @@ func NewCommand() *cobra.Command {
|
||||
log.Error(err, "unable to start manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
pprofMux := http.NewServeMux()
|
||||
profile.RegisterProfiler(pprofMux)
|
||||
// This looks a little strange. Eg, not using ctrl.Options PprofBindAddress and then adding the pprof mux
|
||||
// to the metrics server. However, it allows for the controller to dynamically expose the pprof endpoints
|
||||
// and use the existing metrics server, the same pattern that the application controller and api-server follow.
|
||||
if err = mgr.AddMetricsServerExtraHandler("/debug/pprof/", pprofMux); err != nil {
|
||||
log.Error(err, "failed to register pprof handlers")
|
||||
}
|
||||
dynamicClient, err := dynamic.NewForConfig(mgr.GetConfig())
|
||||
errors.CheckError(err)
|
||||
k8sClient, err := kubernetes.NewForConfig(mgr.GetConfig())
|
||||
@@ -242,7 +231,6 @@ 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)
|
||||
@@ -287,7 +275,6 @@ func NewCommand() *cobra.Command {
|
||||
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().BoolVar(&enableGitHubAPIMetrics, "enable-github-api-metrics", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_GITHUB_API_METRICS", false), "Enable GitHub API metrics for generators that use the GitHub API")
|
||||
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
|
||||
}
|
||||
|
||||
@@ -30,12 +30,11 @@ func NewNotificationsCommand() *cobra.Command {
|
||||
)
|
||||
|
||||
var argocdService service.Service
|
||||
|
||||
toolsCommand := cmd.NewToolsCommand(
|
||||
"notifications",
|
||||
"argocd admin notifications",
|
||||
applications,
|
||||
settings.GetFactorySettingsForCLI(func() service.Service { return argocdService }, "argocd-notifications-secret", "argocd-notifications-cm", false),
|
||||
settings.GetFactorySettingsForCLI(argocdService, "argocd-notifications-secret", "argocd-notifications-cm", false),
|
||||
func(clientConfig clientcmd.ClientConfig) {
|
||||
k8sCfg, err := clientConfig.ClientConfig()
|
||||
if err != nil {
|
||||
|
||||
97
commitserver/apiclient/mocks/Clientset.go
generated
97
commitserver/apiclient/mocks/Clientset.go
generated
@@ -1,14 +1,101 @@
|
||||
// Code generated by mockery; DO NOT EDIT.
|
||||
// github.com/vektra/mockery
|
||||
// template: testify
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"github.com/argoproj/argo-cd/v3/commitserver/apiclient"
|
||||
utilio "github.com/argoproj/argo-cd/v3/util/io"
|
||||
"github.com/argoproj/argo-cd/v3/util/io"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
type Clientset struct {
|
||||
CommitServiceClient apiclient.CommitServiceClient
|
||||
// NewClientset creates a new instance of Clientset. 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 NewClientset(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *Clientset {
|
||||
mock := &Clientset{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
|
||||
func (c *Clientset) NewCommitServerClient() (utilio.Closer, apiclient.CommitServiceClient, error) {
|
||||
return utilio.NopCloser, c.CommitServiceClient, nil
|
||||
// Clientset is an autogenerated mock type for the Clientset type
|
||||
type Clientset struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type Clientset_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *Clientset) EXPECT() *Clientset_Expecter {
|
||||
return &Clientset_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// NewCommitServerClient provides a mock function for the type Clientset
|
||||
func (_mock *Clientset) NewCommitServerClient() (io.Closer, apiclient.CommitServiceClient, error) {
|
||||
ret := _mock.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for NewCommitServerClient")
|
||||
}
|
||||
|
||||
var r0 io.Closer
|
||||
var r1 apiclient.CommitServiceClient
|
||||
var r2 error
|
||||
if returnFunc, ok := ret.Get(0).(func() (io.Closer, apiclient.CommitServiceClient, error)); ok {
|
||||
return returnFunc()
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func() io.Closer); ok {
|
||||
r0 = returnFunc()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(io.Closer)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func() apiclient.CommitServiceClient); ok {
|
||||
r1 = returnFunc()
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(apiclient.CommitServiceClient)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(2).(func() error); ok {
|
||||
r2 = returnFunc()
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// Clientset_NewCommitServerClient_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewCommitServerClient'
|
||||
type Clientset_NewCommitServerClient_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// NewCommitServerClient is a helper method to define mock.On call
|
||||
func (_e *Clientset_Expecter) NewCommitServerClient() *Clientset_NewCommitServerClient_Call {
|
||||
return &Clientset_NewCommitServerClient_Call{Call: _e.mock.On("NewCommitServerClient")}
|
||||
}
|
||||
|
||||
func (_c *Clientset_NewCommitServerClient_Call) Run(run func()) *Clientset_NewCommitServerClient_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Clientset_NewCommitServerClient_Call) Return(closer io.Closer, commitServiceClient apiclient.CommitServiceClient, err error) *Clientset_NewCommitServerClient_Call {
|
||||
_c.Call.Return(closer, commitServiceClient, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Clientset_NewCommitServerClient_Call) RunAndReturn(run func() (io.Closer, apiclient.CommitServiceClient, error)) *Clientset_NewCommitServerClient_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
@@ -1878,7 +1878,7 @@ func (ctrl *ApplicationController) processAppHydrateQueueItem() (processNext boo
|
||||
return
|
||||
}
|
||||
|
||||
ctrl.hydrator.ProcessAppHydrateQueueItem(origApp.DeepCopy())
|
||||
ctrl.hydrator.ProcessAppHydrateQueueItem(origApp)
|
||||
|
||||
log.WithFields(applog.GetAppLogFields(origApp)).Debug("Successfully processed app hydrate queue item")
|
||||
return
|
||||
|
||||
@@ -4,9 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -101,41 +99,47 @@ func NewHydrator(dependencies Dependencies, statusRefreshTimeout time.Duration,
|
||||
// It's likely that multiple applications will trigger hydration at the same time. The hydration queue key is meant to
|
||||
// dedupe these requests.
|
||||
func (h *Hydrator) ProcessAppHydrateQueueItem(origApp *appv1.Application) {
|
||||
origApp = origApp.DeepCopy()
|
||||
app := origApp.DeepCopy()
|
||||
|
||||
if app.Spec.SourceHydrator == nil {
|
||||
return
|
||||
}
|
||||
|
||||
logCtx := log.WithFields(applog.GetAppLogFields(app))
|
||||
|
||||
logCtx.Debug("Processing app hydrate queue item")
|
||||
|
||||
needsHydration, reason := appNeedsHydration(app)
|
||||
if needsHydration {
|
||||
app.Status.SourceHydrator.CurrentOperation = &appv1.HydrateOperation{
|
||||
StartedAt: metav1.Now(),
|
||||
FinishedAt: nil,
|
||||
Phase: appv1.HydrateOperationPhaseHydrating,
|
||||
SourceHydrator: *app.Spec.SourceHydrator,
|
||||
}
|
||||
h.dependencies.PersistAppHydratorStatus(origApp, &app.Status.SourceHydrator)
|
||||
// TODO: don't reuse statusRefreshTimeout. Create a new timeout for hydration.
|
||||
needsHydration, reason := appNeedsHydration(origApp, h.statusRefreshTimeout)
|
||||
if !needsHydration {
|
||||
return
|
||||
}
|
||||
|
||||
needsRefresh := app.Status.SourceHydrator.CurrentOperation.Phase == appv1.HydrateOperationPhaseHydrating && metav1.Now().Sub(app.Status.SourceHydrator.CurrentOperation.StartedAt.Time) > h.statusRefreshTimeout
|
||||
if needsHydration || needsRefresh {
|
||||
logCtx.WithField("reason", reason).Info("Hydrating app")
|
||||
h.dependencies.AddHydrationQueueItem(getHydrationQueueKey(app))
|
||||
} else {
|
||||
logCtx.WithField("reason", reason).Debug("Skipping hydration")
|
||||
logCtx.WithField("reason", reason).Info("Hydrating app")
|
||||
|
||||
app.Status.SourceHydrator.CurrentOperation = &appv1.HydrateOperation{
|
||||
StartedAt: metav1.Now(),
|
||||
FinishedAt: nil,
|
||||
Phase: appv1.HydrateOperationPhaseHydrating,
|
||||
SourceHydrator: *app.Spec.SourceHydrator,
|
||||
}
|
||||
h.dependencies.PersistAppHydratorStatus(origApp, &app.Status.SourceHydrator)
|
||||
origApp.Status.SourceHydrator = app.Status.SourceHydrator
|
||||
h.dependencies.AddHydrationQueueItem(getHydrationQueueKey(app))
|
||||
|
||||
logCtx.Debug("Successfully processed app hydrate queue item")
|
||||
}
|
||||
|
||||
func getHydrationQueueKey(app *appv1.Application) types.HydrationQueueKey {
|
||||
destinationBranch := app.Spec.SourceHydrator.SyncSource.TargetBranch
|
||||
if app.Spec.SourceHydrator.HydrateTo != nil {
|
||||
destinationBranch = app.Spec.SourceHydrator.HydrateTo.TargetBranch
|
||||
}
|
||||
key := types.HydrationQueueKey{
|
||||
SourceRepoURL: git.NormalizeGitURLAllowInvalid(app.Spec.SourceHydrator.DrySource.RepoURL),
|
||||
SourceTargetRevision: app.Spec.SourceHydrator.DrySource.TargetRevision,
|
||||
DestinationBranch: app.Spec.GetHydrateToSource().TargetRevision,
|
||||
DestinationBranch: destinationBranch,
|
||||
}
|
||||
return key
|
||||
}
|
||||
@@ -144,92 +148,43 @@ func getHydrationQueueKey(app *appv1.Application) types.HydrationQueueKey {
|
||||
// hydration key, hydrates their latest commit, and updates their status accordingly. If the hydration fails, it marks
|
||||
// the operation as failed and logs the error. If successful, it updates the operation to indicate that hydration was
|
||||
// successful and requests a refresh of the applications to pick up the new hydrated commit.
|
||||
func (h *Hydrator) ProcessHydrationQueueItem(hydrationKey types.HydrationQueueKey) {
|
||||
func (h *Hydrator) ProcessHydrationQueueItem(hydrationKey types.HydrationQueueKey) (processNext bool) {
|
||||
logCtx := log.WithFields(log.Fields{
|
||||
"sourceRepoURL": hydrationKey.SourceRepoURL,
|
||||
"sourceTargetRevision": hydrationKey.SourceTargetRevision,
|
||||
"destinationBranch": hydrationKey.DestinationBranch,
|
||||
})
|
||||
|
||||
// Get all applications sharing the same hydration key
|
||||
apps, err := h.getAppsForHydrationKey(hydrationKey)
|
||||
if err != nil {
|
||||
// If we get an error here, we cannot proceed with hydration and we do not know
|
||||
// which apps to update with the failure. The best we can do is log an error in
|
||||
// the controller and wait for statusRefreshTimeout to retry
|
||||
logCtx.WithError(err).Error("failed to get apps for hydration")
|
||||
relevantApps, drySHA, hydratedSHA, err := h.hydrateAppsLatestCommit(logCtx, hydrationKey)
|
||||
if len(relevantApps) == 0 {
|
||||
// return early if there are no relevant apps found to hydrate
|
||||
// otherwise you'll be stuck in hydrating
|
||||
logCtx.Info("Skipping hydration since there are no relevant apps found to hydrate")
|
||||
return
|
||||
}
|
||||
logCtx.WithField("appCount", len(apps))
|
||||
|
||||
// FIXME: we might end up in a race condition here where an HydrationQueueItem is processed
|
||||
// before all applications had their CurrentOperation set by ProcessAppHydrateQueueItem.
|
||||
// This would cause this method to update "old" CurrentOperation.
|
||||
// It should only start hydration if all apps are in the HydrateOperationPhaseHydrating phase.
|
||||
raceDetected := false
|
||||
for _, app := range apps {
|
||||
if app.Status.SourceHydrator.CurrentOperation == nil || app.Status.SourceHydrator.CurrentOperation.Phase != appv1.HydrateOperationPhaseHydrating {
|
||||
raceDetected = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if raceDetected {
|
||||
logCtx.Warn("race condition detected: not all apps are in HydrateOperationPhaseHydrating phase")
|
||||
}
|
||||
|
||||
// validate all the applications to make sure they are all correctly configured.
|
||||
// All applications sharing the same hydration key must succeed for the hydration to be processed.
|
||||
projects, validationErrors := h.validateApplications(apps)
|
||||
if len(validationErrors) > 0 {
|
||||
// For the applications that have an error, set the specific error in their status.
|
||||
// Applications without error will still fail with a generic error since the hydration cannot be partial
|
||||
genericError := genericHydrationError(validationErrors)
|
||||
for _, app := range apps {
|
||||
if err, ok := validationErrors[app.QualifiedName()]; ok {
|
||||
logCtx = logCtx.WithFields(applog.GetAppLogFields(app))
|
||||
logCtx.Errorf("failed to validate hydration app: %v", err)
|
||||
h.setAppHydratorError(app, err)
|
||||
} else {
|
||||
h.setAppHydratorError(app, genericError)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Hydrate all the apps
|
||||
drySHA, hydratedSHA, appErrors, err := h.hydrate(logCtx, apps, projects)
|
||||
if err != nil {
|
||||
// If there is a single error, it affects each applications
|
||||
for i := range apps {
|
||||
appErrors[apps[i].QualifiedName()] = err
|
||||
}
|
||||
}
|
||||
if drySHA != "" {
|
||||
logCtx = logCtx.WithField("drySHA", drySHA)
|
||||
}
|
||||
if len(appErrors) > 0 {
|
||||
// For the applications that have an error, set the specific error in their status.
|
||||
// Applications without error will still fail with a generic error since the hydration cannot be partial
|
||||
genericError := genericHydrationError(appErrors)
|
||||
for _, app := range apps {
|
||||
if drySHA != "" {
|
||||
// If we have a drySHA, we can set it on the app status
|
||||
app.Status.SourceHydrator.CurrentOperation.DrySHA = drySHA
|
||||
}
|
||||
if err, ok := appErrors[app.QualifiedName()]; ok {
|
||||
logCtx = logCtx.WithFields(applog.GetAppLogFields(app))
|
||||
logCtx.Errorf("failed to hydrate app: %v", err)
|
||||
h.setAppHydratorError(app, err)
|
||||
} else {
|
||||
h.setAppHydratorError(app, genericError)
|
||||
}
|
||||
if err != nil {
|
||||
logCtx.WithField("appCount", len(relevantApps)).WithError(err).Error("Failed to hydrate apps")
|
||||
for _, app := range relevantApps {
|
||||
origApp := app.DeepCopy()
|
||||
app.Status.SourceHydrator.CurrentOperation.Phase = appv1.HydrateOperationPhaseFailed
|
||||
failedAt := metav1.Now()
|
||||
app.Status.SourceHydrator.CurrentOperation.FinishedAt = &failedAt
|
||||
app.Status.SourceHydrator.CurrentOperation.Message = fmt.Sprintf("Failed to hydrate revision %q: %v", drySHA, err.Error())
|
||||
// We may or may not have gotten far enough in the hydration process to get a non-empty SHA, but set it just
|
||||
// in case we did.
|
||||
app.Status.SourceHydrator.CurrentOperation.DrySHA = drySHA
|
||||
h.dependencies.PersistAppHydratorStatus(origApp, &app.Status.SourceHydrator)
|
||||
logCtx = logCtx.WithFields(applog.GetAppLogFields(app))
|
||||
logCtx.Errorf("Failed to hydrate app: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
logCtx.Debug("Successfully hydrated apps")
|
||||
logCtx.WithField("appCount", len(relevantApps)).Debug("Successfully hydrated apps")
|
||||
finishedAt := metav1.Now()
|
||||
for _, app := range apps {
|
||||
for _, app := range relevantApps {
|
||||
origApp := app.DeepCopy()
|
||||
operation := &appv1.HydrateOperation{
|
||||
StartedAt: app.Status.SourceHydrator.CurrentOperation.StartedAt,
|
||||
@@ -247,123 +202,118 @@ func (h *Hydrator) ProcessHydrationQueueItem(hydrationKey types.HydrationQueueKe
|
||||
SourceHydrator: app.Status.SourceHydrator.CurrentOperation.SourceHydrator,
|
||||
}
|
||||
h.dependencies.PersistAppHydratorStatus(origApp, &app.Status.SourceHydrator)
|
||||
|
||||
// Request a refresh since we pushed a new commit.
|
||||
err := h.dependencies.RequestAppRefresh(app.Name, app.Namespace)
|
||||
if err != nil {
|
||||
logCtx.WithFields(applog.GetAppLogFields(app)).WithError(err).Error("Failed to request app refresh after hydration")
|
||||
logCtx.WithField("app", app.QualifiedName()).WithError(err).Error("Failed to request app refresh after hydration")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// setAppHydratorError updates the CurrentOperation with the error information.
|
||||
func (h *Hydrator) setAppHydratorError(app *appv1.Application, err error) {
|
||||
// if the operation is not in progress, we do not update the status
|
||||
if app.Status.SourceHydrator.CurrentOperation.Phase != appv1.HydrateOperationPhaseHydrating {
|
||||
return
|
||||
func (h *Hydrator) hydrateAppsLatestCommit(logCtx *log.Entry, hydrationKey types.HydrationQueueKey) ([]*appv1.Application, string, string, error) {
|
||||
relevantApps, projects, err := h.getRelevantAppsAndProjectsForHydration(logCtx, hydrationKey)
|
||||
if err != nil {
|
||||
return nil, "", "", fmt.Errorf("failed to get relevant apps for hydration: %w", err)
|
||||
}
|
||||
|
||||
origApp := app.DeepCopy()
|
||||
app.Status.SourceHydrator.CurrentOperation.Phase = appv1.HydrateOperationPhaseFailed
|
||||
failedAt := metav1.Now()
|
||||
app.Status.SourceHydrator.CurrentOperation.FinishedAt = &failedAt
|
||||
app.Status.SourceHydrator.CurrentOperation.Message = fmt.Sprintf("Failed to hydrate: %v", err.Error())
|
||||
h.dependencies.PersistAppHydratorStatus(origApp, &app.Status.SourceHydrator)
|
||||
dryRevision, hydratedRevision, err := h.hydrate(logCtx, relevantApps, projects)
|
||||
if err != nil {
|
||||
return relevantApps, dryRevision, "", fmt.Errorf("failed to hydrate apps: %w", err)
|
||||
}
|
||||
|
||||
return relevantApps, dryRevision, hydratedRevision, nil
|
||||
}
|
||||
|
||||
// getAppsForHydrationKey returns the applications matching the hydration key.
|
||||
func (h *Hydrator) getAppsForHydrationKey(hydrationKey types.HydrationQueueKey) ([]*appv1.Application, error) {
|
||||
func (h *Hydrator) getRelevantAppsAndProjectsForHydration(logCtx *log.Entry, hydrationKey types.HydrationQueueKey) ([]*appv1.Application, map[string]*appv1.AppProject, error) {
|
||||
// Get all apps
|
||||
apps, err := h.dependencies.GetProcessableApps()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list apps: %w", err)
|
||||
return nil, nil, fmt.Errorf("failed to list apps: %w", err)
|
||||
}
|
||||
|
||||
var relevantApps []*appv1.Application
|
||||
projects := make(map[string]*appv1.AppProject)
|
||||
uniquePaths := make(map[string]bool, len(apps.Items))
|
||||
for _, app := range apps.Items {
|
||||
if app.Spec.SourceHydrator == nil {
|
||||
continue
|
||||
}
|
||||
appKey := getHydrationQueueKey(&app)
|
||||
if appKey != hydrationKey {
|
||||
|
||||
if !git.SameURL(app.Spec.SourceHydrator.DrySource.RepoURL, hydrationKey.SourceRepoURL) ||
|
||||
app.Spec.SourceHydrator.DrySource.TargetRevision != hydrationKey.SourceTargetRevision {
|
||||
continue
|
||||
}
|
||||
relevantApps = append(relevantApps, &app)
|
||||
}
|
||||
return relevantApps, nil
|
||||
}
|
||||
|
||||
// validateApplications checks that all applications are valid for hydration.
|
||||
func (h *Hydrator) validateApplications(apps []*appv1.Application) (map[string]*appv1.AppProject, map[string]error) {
|
||||
projects := make(map[string]*appv1.AppProject)
|
||||
errors := make(map[string]error)
|
||||
uniquePaths := make(map[string]string, len(apps))
|
||||
|
||||
for _, app := range apps {
|
||||
// Get the project for the app and validate if the app is allowed to use the source.
|
||||
// We can't short-circuit this even if we have seen this project before, because we need to verify that this
|
||||
// particular app is allowed to use this project.
|
||||
proj, err := h.dependencies.GetProcessableAppProj(app)
|
||||
if err != nil {
|
||||
errors[app.QualifiedName()] = fmt.Errorf("failed to get project %q: %w", app.Spec.Project, err)
|
||||
destinationBranch := app.Spec.SourceHydrator.SyncSource.TargetBranch
|
||||
if app.Spec.SourceHydrator.HydrateTo != nil {
|
||||
destinationBranch = app.Spec.SourceHydrator.HydrateTo.TargetBranch
|
||||
}
|
||||
if destinationBranch != hydrationKey.DestinationBranch {
|
||||
continue
|
||||
}
|
||||
|
||||
path := app.Spec.SourceHydrator.SyncSource.Path
|
||||
// ensure that the path is always set to a path that doesn't resolve to the root of the repo
|
||||
if IsRootPath(path) {
|
||||
return nil, nil, fmt.Errorf("app %q has path %q which resolves to repository root", app.QualifiedName(), path)
|
||||
}
|
||||
|
||||
var proj *appv1.AppProject
|
||||
// We can't short-circuit this even if we have seen this project before, because we need to verify that this
|
||||
// particular app is allowed to use this project. That logic is in GetProcessableAppProj.
|
||||
proj, err = h.dependencies.GetProcessableAppProj(&app)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get project %q for app %q: %w", app.Spec.Project, app.QualifiedName(), err)
|
||||
}
|
||||
permitted := proj.IsSourcePermitted(app.Spec.GetSource())
|
||||
if !permitted {
|
||||
errors[app.QualifiedName()] = fmt.Errorf("application repo %s is not permitted in project '%s'", app.Spec.GetSource().RepoURL, proj.Name)
|
||||
// Log and skip. We don't want to fail the entire operation because of one app.
|
||||
logCtx.Warnf("App %q is not permitted to use source %q", app.QualifiedName(), app.Spec.Source.String())
|
||||
continue
|
||||
}
|
||||
projects[app.Spec.Project] = proj
|
||||
|
||||
// Disallow hydrating to the repository root.
|
||||
// Hydrating to root would overwrite or delete files at the top level of the repo,
|
||||
// which can break other applications or shared configuration.
|
||||
// Every hydrated app must write into a subdirectory instead.
|
||||
destPath := app.Spec.SourceHydrator.SyncSource.Path
|
||||
if IsRootPath(destPath) {
|
||||
errors[app.QualifiedName()] = fmt.Errorf("app is configured to hydrate to the repository root (branch %q, path %q) which is not allowed", app.Spec.GetHydrateToSource().TargetRevision, destPath)
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: test the dupe detection
|
||||
// TODO: normalize the path to avoid "path/.." from being treated as different from "."
|
||||
if appName, ok := uniquePaths[destPath]; ok {
|
||||
errors[app.QualifiedName()] = fmt.Errorf("app %s hydrator use the same destination: %v", appName, app.Spec.SourceHydrator.SyncSource.Path)
|
||||
errors[appName] = fmt.Errorf("app %s hydrator use the same destination: %v", app.QualifiedName(), app.Spec.SourceHydrator.SyncSource.Path)
|
||||
continue
|
||||
if _, ok := uniquePaths[path]; ok {
|
||||
return nil, nil, fmt.Errorf("multiple app hydrators use the same destination: %v", app.Spec.SourceHydrator.SyncSource.Path)
|
||||
}
|
||||
uniquePaths[destPath] = app.QualifiedName()
|
||||
}
|
||||
uniquePaths[path] = true
|
||||
|
||||
// If there are any errors, return nil for projects to avoid possible partial processing.
|
||||
if len(errors) > 0 {
|
||||
projects = nil
|
||||
relevantApps = append(relevantApps, &app)
|
||||
}
|
||||
|
||||
return projects, errors
|
||||
return relevantApps, projects, nil
|
||||
}
|
||||
|
||||
func (h *Hydrator) hydrate(logCtx *log.Entry, apps []*appv1.Application, projects map[string]*appv1.AppProject) (string, string, map[string]error, error) {
|
||||
errors := make(map[string]error)
|
||||
func (h *Hydrator) hydrate(logCtx *log.Entry, apps []*appv1.Application, projects map[string]*appv1.AppProject) (string, string, error) {
|
||||
if len(apps) == 0 {
|
||||
return "", "", nil, nil
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
// These values are the same for all apps being hydrated together, so just get them from the first app.
|
||||
repoURL := apps[0].Spec.GetHydrateToSource().RepoURL
|
||||
targetBranch := apps[0].Spec.GetHydrateToSource().TargetRevision
|
||||
// FIXME: As a convenience, the commit server will create the syncBranch if it does not exist. If the
|
||||
// targetBranch does not exist, it will create it based on the syncBranch. On the next line, we take
|
||||
// the `syncBranch` from the first app and assume that they're all configured the same. Instead, if any
|
||||
// app has a different syncBranch, we should send the commit server an empty string and allow it to
|
||||
// create the targetBranch as an orphan since we can't reliable determine a reasonable base.
|
||||
repoURL := apps[0].Spec.SourceHydrator.DrySource.RepoURL
|
||||
syncBranch := apps[0].Spec.SourceHydrator.SyncSource.TargetBranch
|
||||
targetBranch := apps[0].Spec.GetHydrateToSource().TargetRevision
|
||||
|
||||
// Disallow hydrating to the repository root.
|
||||
// Hydrating to root would overwrite or delete files at the top level of the repo,
|
||||
// which can break other applications or shared configuration.
|
||||
// Every hydrated app must write into a subdirectory instead.
|
||||
|
||||
for _, app := range apps {
|
||||
destPath := app.Spec.SourceHydrator.SyncSource.Path
|
||||
if IsRootPath(destPath) {
|
||||
return "", "", fmt.Errorf(
|
||||
"app %q is configured to hydrate to the repository root (branch %q, path %q) which is not allowed",
|
||||
app.QualifiedName(), targetBranch, destPath,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Get a static SHA revision from the first app so that all apps are hydrated from the same revision.
|
||||
targetRevision, pathDetails, err := h.getManifests(context.Background(), apps[0], "", projects[apps[0].Spec.Project])
|
||||
if err != nil {
|
||||
errors[apps[0].QualifiedName()] = fmt.Errorf("failed to get manifests: %w", err)
|
||||
return "", "", errors, nil
|
||||
return "", "", fmt.Errorf("failed to get manifests for app %q: %w", apps[0].QualifiedName(), err)
|
||||
}
|
||||
paths := []*commitclient.PathDetails{pathDetails}
|
||||
|
||||
@@ -374,18 +324,18 @@ func (h *Hydrator) hydrate(logCtx *log.Entry, apps []*appv1.Application, project
|
||||
app := app
|
||||
eg.Go(func() error {
|
||||
_, pathDetails, err = h.getManifests(ctx, app, targetRevision, projects[app.Spec.Project])
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if err != nil {
|
||||
errors[app.QualifiedName()] = fmt.Errorf("failed to get manifests: %w", err)
|
||||
return errors[app.QualifiedName()]
|
||||
return fmt.Errorf("failed to get manifests for app %q: %w", app.QualifiedName(), err)
|
||||
}
|
||||
mu.Lock()
|
||||
paths = append(paths, pathDetails)
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if err := eg.Wait(); err != nil {
|
||||
return targetRevision, "", errors, nil
|
||||
err = eg.Wait()
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to get manifests for apps: %w", err)
|
||||
}
|
||||
|
||||
// If all the apps are under the same project, use that project. Otherwise, use an empty string to indicate that we
|
||||
@@ -394,19 +344,18 @@ func (h *Hydrator) hydrate(logCtx *log.Entry, apps []*appv1.Application, project
|
||||
if len(projects) == 1 {
|
||||
for p := range projects {
|
||||
project = p
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Get the commit metadata for the target revision.
|
||||
revisionMetadata, err := h.getRevisionMetadata(context.Background(), repoURL, project, targetRevision)
|
||||
if err != nil {
|
||||
return targetRevision, "", errors, fmt.Errorf("failed to get revision metadata for %q: %w", targetRevision, err)
|
||||
return "", "", fmt.Errorf("failed to get revision metadata for %q: %w", targetRevision, err)
|
||||
}
|
||||
|
||||
repo, err := h.dependencies.GetWriteCredentials(context.Background(), repoURL, project)
|
||||
if err != nil {
|
||||
return targetRevision, "", errors, fmt.Errorf("failed to get hydrator credentials: %w", err)
|
||||
return "", "", fmt.Errorf("failed to get hydrator credentials: %w", err)
|
||||
}
|
||||
if repo == nil {
|
||||
// Try without credentials.
|
||||
@@ -418,11 +367,11 @@ func (h *Hydrator) hydrate(logCtx *log.Entry, apps []*appv1.Application, project
|
||||
// get the commit message template
|
||||
commitMessageTemplate, err := h.dependencies.GetHydratorCommitMessageTemplate()
|
||||
if err != nil {
|
||||
return targetRevision, "", errors, fmt.Errorf("failed to get hydrated commit message template: %w", err)
|
||||
return "", "", fmt.Errorf("failed to get hydrated commit message template: %w", err)
|
||||
}
|
||||
commitMessage, errMsg := getTemplatedCommitMessage(repoURL, targetRevision, commitMessageTemplate, revisionMetadata)
|
||||
if errMsg != nil {
|
||||
return targetRevision, "", errors, fmt.Errorf("failed to get hydrator commit templated message: %w", errMsg)
|
||||
return "", "", fmt.Errorf("failed to get hydrator commit templated message: %w", errMsg)
|
||||
}
|
||||
|
||||
manifestsRequest := commitclient.CommitHydratedManifestsRequest{
|
||||
@@ -437,14 +386,14 @@ func (h *Hydrator) hydrate(logCtx *log.Entry, apps []*appv1.Application, project
|
||||
|
||||
closer, commitService, err := h.commitClientset.NewCommitServerClient()
|
||||
if err != nil {
|
||||
return targetRevision, "", errors, fmt.Errorf("failed to create commit service: %w", err)
|
||||
return targetRevision, "", fmt.Errorf("failed to create commit service: %w", err)
|
||||
}
|
||||
defer utilio.Close(closer)
|
||||
resp, err := commitService.CommitHydratedManifests(context.Background(), &manifestsRequest)
|
||||
if err != nil {
|
||||
return targetRevision, "", errors, fmt.Errorf("failed to commit hydrated manifests: %w", err)
|
||||
return targetRevision, "", fmt.Errorf("failed to commit hydrated manifests: %w", err)
|
||||
}
|
||||
return targetRevision, resp.HydratedSha, errors, nil
|
||||
return targetRevision, resp.HydratedSha, nil
|
||||
}
|
||||
|
||||
// getManifests gets the manifests for the given application and target revision. It returns the resolved revision
|
||||
@@ -507,27 +456,34 @@ func (h *Hydrator) getRevisionMetadata(ctx context.Context, repoURL, project, re
|
||||
}
|
||||
|
||||
// appNeedsHydration answers if application needs manifests hydrated.
|
||||
func appNeedsHydration(app *appv1.Application) (needsHydration bool, reason string) {
|
||||
switch {
|
||||
case app.Spec.SourceHydrator == nil:
|
||||
func appNeedsHydration(app *appv1.Application, statusHydrateTimeout time.Duration) (needsHydration bool, reason string) {
|
||||
if app.Spec.SourceHydrator == nil {
|
||||
return false, "source hydrator not configured"
|
||||
case app.Status.SourceHydrator.CurrentOperation == nil:
|
||||
return true, "no previous hydrate operation"
|
||||
case app.Status.SourceHydrator.CurrentOperation.Phase == appv1.HydrateOperationPhaseHydrating:
|
||||
return false, "hydration operation already in progress"
|
||||
}
|
||||
|
||||
var hydratedAt *metav1.Time
|
||||
if app.Status.SourceHydrator.CurrentOperation != nil {
|
||||
hydratedAt = &app.Status.SourceHydrator.CurrentOperation.StartedAt
|
||||
}
|
||||
|
||||
switch {
|
||||
case app.IsHydrateRequested():
|
||||
return true, "hydrate requested"
|
||||
case app.Status.SourceHydrator.CurrentOperation == nil:
|
||||
return true, "no previous hydrate operation"
|
||||
case !app.Spec.SourceHydrator.DeepEquals(app.Status.SourceHydrator.CurrentOperation.SourceHydrator):
|
||||
return true, "spec.sourceHydrator differs"
|
||||
case app.Status.SourceHydrator.CurrentOperation.Phase == appv1.HydrateOperationPhaseFailed && metav1.Now().Sub(app.Status.SourceHydrator.CurrentOperation.FinishedAt.Time) > 2*time.Minute:
|
||||
return true, "previous hydrate operation failed more than 2 minutes ago"
|
||||
case hydratedAt == nil || hydratedAt.Add(statusHydrateTimeout).Before(time.Now().UTC()):
|
||||
return true, "hydration expired"
|
||||
}
|
||||
|
||||
return false, "hydration not needed"
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// getTemplatedCommitMessage gets the multi-line commit message based on the template defined in the configmap. It is a two step process:
|
||||
// 1. Get the metadata template engine would use to render the template
|
||||
// Gets the multi-line commit message based on the template defined in the configmap. It is a two step process:
|
||||
// 1. Get the metadata template engine would use to render the template
|
||||
// 2. Pass the output of Step 1 and Step 2 to template Render
|
||||
func getTemplatedCommitMessage(repoURL, revision, commitMessageTemplate string, dryCommitMetadata *appv1.RevisionMetadata) (string, error) {
|
||||
hydratorCommitMetadata, err := hydrator.GetCommitMetadata(repoURL, revision, dryCommitMetadata)
|
||||
@@ -541,20 +497,6 @@ func getTemplatedCommitMessage(repoURL, revision, commitMessageTemplate string,
|
||||
return templatedCommitMsg, nil
|
||||
}
|
||||
|
||||
// genericHydrationError returns an error that summarizes the hydration errors for all applications.
|
||||
func genericHydrationError(validationErrors map[string]error) error {
|
||||
if len(validationErrors) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
keys := slices.Sorted(maps.Keys(validationErrors))
|
||||
remainder := "has an error"
|
||||
if len(keys) > 1 {
|
||||
remainder = fmt.Sprintf("and %d more have errors", len(keys)-1)
|
||||
}
|
||||
return fmt.Errorf("cannot hydrate because application %s %s", keys[0], remainder)
|
||||
}
|
||||
|
||||
// IsRootPath returns whether the path references a root path
|
||||
func IsRootPath(path string) bool {
|
||||
clean := filepath.Clean(path)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
113
controller/hydrator/mocks/RepoGetter.go
generated
113
controller/hydrator/mocks/RepoGetter.go
generated
@@ -1,113 +0,0 @@
|
||||
// Code generated by mockery; DO NOT EDIT.
|
||||
// github.com/vektra/mockery
|
||||
// template: testify
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// NewRepoGetter creates a new instance of RepoGetter. 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 NewRepoGetter(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *RepoGetter {
|
||||
mock := &RepoGetter{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
|
||||
// RepoGetter is an autogenerated mock type for the RepoGetter type
|
||||
type RepoGetter struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type RepoGetter_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *RepoGetter) EXPECT() *RepoGetter_Expecter {
|
||||
return &RepoGetter_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// GetRepository provides a mock function for the type RepoGetter
|
||||
func (_mock *RepoGetter) GetRepository(ctx context.Context, repoURL string, project string) (*v1alpha1.Repository, error) {
|
||||
ret := _mock.Called(ctx, repoURL, project)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetRepository")
|
||||
}
|
||||
|
||||
var r0 *v1alpha1.Repository
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, string, string) (*v1alpha1.Repository, error)); ok {
|
||||
return returnFunc(ctx, repoURL, project)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, string, string) *v1alpha1.Repository); ok {
|
||||
r0 = returnFunc(ctx, repoURL, project)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.Repository)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
|
||||
r1 = returnFunc(ctx, repoURL, project)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RepoGetter_GetRepository_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRepository'
|
||||
type RepoGetter_GetRepository_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetRepository is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - repoURL string
|
||||
// - project string
|
||||
func (_e *RepoGetter_Expecter) GetRepository(ctx interface{}, repoURL interface{}, project interface{}) *RepoGetter_GetRepository_Call {
|
||||
return &RepoGetter_GetRepository_Call{Call: _e.mock.On("GetRepository", ctx, repoURL, project)}
|
||||
}
|
||||
|
||||
func (_c *RepoGetter_GetRepository_Call) Run(run func(ctx context.Context, repoURL string, project string)) *RepoGetter_GetRepository_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 context.Context
|
||||
if args[0] != nil {
|
||||
arg0 = args[0].(context.Context)
|
||||
}
|
||||
var arg1 string
|
||||
if args[1] != nil {
|
||||
arg1 = args[1].(string)
|
||||
}
|
||||
var arg2 string
|
||||
if args[2] != nil {
|
||||
arg2 = args[2].(string)
|
||||
}
|
||||
run(
|
||||
arg0,
|
||||
arg1,
|
||||
arg2,
|
||||
)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *RepoGetter_GetRepository_Call) Return(repository *v1alpha1.Repository, err error) *RepoGetter_GetRepository_Call {
|
||||
_c.Call.Return(repository, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *RepoGetter_GetRepository_Call) RunAndReturn(run func(ctx context.Context, repoURL string, project string) (*v1alpha1.Repository, error)) *RepoGetter_GetRepository_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
# Progressive Syncs
|
||||
|
||||
!!! warning "Alpha Feature (Since v2.6.0)"
|
||||
This is an experimental, [alpha-quality](https://github.com/argoproj/argoproj/blob/main/community/feature-status.md#alpha)
|
||||
feature that allows you to control the order in which the ApplicationSet controller will create or update the Applications
|
||||
|
||||
This is an experimental, [alpha-quality](https://github.com/argoproj/argoproj/blob/main/community/feature-status.md#alpha)
|
||||
feature that allows you to control the order in which the ApplicationSet controller will create or update the Applications
|
||||
owned by an ApplicationSet resource. It may be removed in future releases or modified in backwards-incompatible ways.
|
||||
|
||||
## Use Cases
|
||||
|
||||
The Progressive Syncs feature set is intended to be light and flexible. The feature only interacts with the health of managed Applications. It is not intended to support direct integrations with other Rollout controllers (such as the native ReplicaSet controller or Argo Rollouts).
|
||||
|
||||
* Progressive Syncs watch for the managed Application resources to become "Healthy" before proceeding to the next stage.
|
||||
* Deployments, DaemonSets, StatefulSets, and [Argo Rollouts](https://argoproj.github.io/argo-rollouts/) are all supported, because the Application enters a "Progressing" state while pods are being rolled out. In fact, any resource with a health check that can report a "Progressing" status is supported.
|
||||
* [Argo CD Resource Hooks](../../user-guide/resource_hooks.md) are supported. We recommend this approach for users that need advanced functionality when an Argo Rollout cannot be used, such as smoke testing after a DaemonSet change.
|
||||
- Progressive Syncs watch for the managed Application resources to become "Healthy" before proceeding to the next stage.
|
||||
- Deployments, DaemonSets, StatefulSets, and [Argo Rollouts](https://argoproj.github.io/argo-rollouts/) are all supported, because the Application enters a "Progressing" state while pods are being rolled out. In fact, any resource with a health check that can report a "Progressing" status is supported.
|
||||
- [Argo CD Resource Hooks](../../user-guide/resource_hooks.md) are supported. We recommend this approach for users that need advanced functionality when an Argo Rollout cannot be used, such as smoke testing after a DaemonSet change.
|
||||
|
||||
## Enabling Progressive Syncs
|
||||
|
||||
As an experimental feature, progressive syncs must be explicitly enabled, in one of these ways.
|
||||
|
||||
1. Pass `--enable-progressive-syncs` to the ApplicationSet controller args.
|
||||
@@ -23,17 +26,18 @@ As an experimental feature, progressive syncs must be explicitly enabled, in one
|
||||
|
||||
ApplicationSet strategies control both how applications are created (or updated) and deleted. These operations are configured using two separate fields:
|
||||
|
||||
* **Creation Strategy** (`type` field): Controls application creation and updates
|
||||
* **Deletion Strategy** (`deletionOrder` field): Controls application deletion order
|
||||
- **Creation Strategy** (`type` field): Controls application creation and updates
|
||||
- **Deletion Strategy** (`deletionOrder` field): Controls application deletion order
|
||||
|
||||
### Creation Strategies
|
||||
|
||||
The `type` field controls how applications are created and updated. Available values:
|
||||
|
||||
* **AllAtOnce** (default)
|
||||
* **RollingSync**
|
||||
- **AllAtOnce** (default)
|
||||
- **RollingSync**
|
||||
|
||||
#### AllAtOnce
|
||||
|
||||
This default Application update behavior is unchanged from the original ApplicationSet implementation.
|
||||
|
||||
All Applications managed by the ApplicationSet resource are updated simultaneously when the ApplicationSet is updated.
|
||||
@@ -41,25 +45,25 @@ All Applications managed by the ApplicationSet resource are updated simultaneous
|
||||
```yaml
|
||||
spec:
|
||||
strategy:
|
||||
type: AllAtOnce # explicit, but this is the default
|
||||
type: AllAtOnce # explicit, but this is the default
|
||||
```
|
||||
|
||||
#### RollingSync
|
||||
|
||||
This update strategy allows you to group Applications by labels present on the generated Application resources.
|
||||
When the ApplicationSet changes, the changes will be applied to each group of Application resources sequentially.
|
||||
|
||||
* Application groups are selected using their labels and `matchExpressions`.
|
||||
* All `matchExpressions` must be true for an Application to be selected (multiple expressions match with AND behavior).
|
||||
* The `In` and `NotIn` operators must match at least one value to be considered true (OR behavior).
|
||||
* The `NotIn` operator has priority in the event that both a `NotIn` and `In` operator produce a match.
|
||||
* All Applications in each group must become Healthy before the ApplicationSet controller will proceed to update the next group of Applications.
|
||||
* The number of simultaneous Application updates in a group will not exceed its `maxUpdate` parameter (default is 100%, unbounded).
|
||||
* RollingSync will capture external changes outside the ApplicationSet resource, since it relies on watching the OutOfSync status of the managed Applications.
|
||||
* RollingSync will force all generated Applications to have autosync disabled. Warnings are printed in the applicationset-controller logs for any Application specs with an automated syncPolicy enabled.
|
||||
* Sync operations are triggered the same way as if they were triggered by the UI or CLI (by directly setting the `operation` status field on the Application resource). This means that a RollingSync will respect sync windows just as if a user had clicked the "Sync" button in the Argo UI.
|
||||
* When a sync is triggered, the sync is performed with the same syncPolicy configured for the Application. For example, this preserves the Application's retry settings.
|
||||
* If an Application is considered "Pending" for `applicationsetcontroller.default.application.progressing.timeout` seconds, the Application is automatically moved to Healthy status (default 300).
|
||||
* If an Application is not selected in any step, it will be excluded from the rolling sync and needs to be manually synced through the CLI or UI.
|
||||
- Application groups are selected using their labels and `matchExpressions`.
|
||||
- All `matchExpressions` must be true for an Application to be selected (multiple expressions match with AND behavior).
|
||||
- The `In` and `NotIn` operators must match at least one value to be considered true (OR behavior).
|
||||
- The `NotIn` operator has priority in the event that both a `NotIn` and `In` operator produce a match.
|
||||
- All Applications in each group must become Healthy before the ApplicationSet controller will proceed to update the next group of Applications.
|
||||
- The number of simultaneous Application updates in a group will not exceed its `maxUpdate` parameter (default is 100%, unbounded).
|
||||
- RollingSync will capture external changes outside the ApplicationSet resource, since it relies on watching the OutOfSync status of the managed Applications.
|
||||
- RollingSync will force all generated Applications to have autosync disabled. Warnings are printed in the applicationset-controller logs for any Application specs with an automated syncPolicy enabled.
|
||||
- Sync operations are triggered the same way as if they were triggered by the UI or CLI (by directly setting the `operation` status field on the Application resource). This means that a RollingSync will respect sync windows just as if a user had clicked the "Sync" button in the Argo UI.
|
||||
- When a sync is triggered, the sync is performed with the same syncPolicy configured for the Application. For example, this preserves the Application's retry settings.
|
||||
- If an Application is not selected in any step, it will be excluded from the rolling sync and needs to be manually synced through the CLI or UI.
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
@@ -84,25 +88,28 @@ spec:
|
||||
|
||||
The `deletionOrder` field controls the order in which applications are deleted when they are removed from the ApplicationSet. Available values:
|
||||
|
||||
* **AllAtOnce** (default)
|
||||
* **Reverse**
|
||||
- **AllAtOnce** (default)
|
||||
- **Reverse**
|
||||
|
||||
#### AllAtOnce Deletion
|
||||
|
||||
This is the default behavior where all applications that need to be deleted are removed simultaneously. This works with both `AllAtOnce` and `RollingSync` creation strategies.
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
strategy:
|
||||
type: RollingSync # or AllAtOnce
|
||||
deletionOrder: AllAtOnce # explicit, but this is the default
|
||||
type: RollingSync # or AllAtOnce
|
||||
deletionOrder: AllAtOnce # explicit, but this is the default
|
||||
```
|
||||
|
||||
#### Reverse Deletion
|
||||
|
||||
When using `deletionOrder: Reverse` with RollingSync strategy, applications are deleted in reverse order of the steps defined in `rollingSync.steps`. This ensures that applications deployed in later steps are deleted before applications deployed in earlier steps.
|
||||
This strategy is particularly useful when you need to tear down dependent services in the particular sequence.
|
||||
|
||||
**Requirements for Reverse deletion:**
|
||||
- Must be used with `type: RollingSync`
|
||||
|
||||
- Must be used with `type: RollingSync`
|
||||
- Requires `rollingSync.steps` to be defined
|
||||
- Applications are deleted in reverse order of step sequence
|
||||
|
||||
@@ -119,28 +126,30 @@ spec:
|
||||
- key: envLabel
|
||||
operator: In
|
||||
values:
|
||||
- env-dev # Step 1: Created first, deleted last
|
||||
- env-dev # Step 1: Created first, deleted last
|
||||
- matchExpressions:
|
||||
- key: envLabel
|
||||
- key: envLabel
|
||||
operator: In
|
||||
values:
|
||||
- env-prod # Step 2: Created second, deleted first
|
||||
- env-prod # Step 2: Created second, deleted first
|
||||
```
|
||||
|
||||
In this example, when applications are deleted:
|
||||
|
||||
1. `env-prod` applications (Step 2) are deleted first
|
||||
2. `env-dev` applications (Step 1) are deleted second
|
||||
|
||||
This deletion order is useful for scenarios where you need to tear down dependent services in the correct sequence, such as deleting frontend services before backend dependencies.
|
||||
|
||||
#### Example
|
||||
|
||||
The following example illustrates how to stage a progressive sync over Applications with explicitly configured environment labels.
|
||||
|
||||
Once a change is pushed, the following will happen in order.
|
||||
|
||||
* All `env-dev` Applications will be updated simultaneously.
|
||||
* The rollout will wait for all `env-qa` Applications to be manually synced via the `argocd` CLI or by clicking the Sync button in the UI.
|
||||
* 10% of all `env-prod` Applications will be updated at a time until all `env-prod` Applications have been updated.
|
||||
- All `env-dev` Applications will be updated simultaneously.
|
||||
- The rollout will wait for all `env-qa` Applications to be manually synced via the `argocd` CLI or by clicking the Sync button in the UI.
|
||||
- 10% of all `env-prod` Applications will be updated at a time until all `env-prod` Applications have been updated.
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
@@ -149,20 +158,20 @@ metadata:
|
||||
name: guestbook
|
||||
spec:
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- cluster: engineering-dev
|
||||
url: https://1.2.3.4
|
||||
env: env-dev
|
||||
- cluster: engineering-qa
|
||||
url: https://2.4.6.8
|
||||
env: env-qa
|
||||
- cluster: engineering-prod
|
||||
url: https://9.8.7.6/
|
||||
env: env-prod
|
||||
- list:
|
||||
elements:
|
||||
- cluster: engineering-dev
|
||||
url: https://1.2.3.4
|
||||
env: env-dev
|
||||
- cluster: engineering-qa
|
||||
url: https://2.4.6.8
|
||||
env: env-qa
|
||||
- cluster: engineering-prod
|
||||
url: https://9.8.7.6/
|
||||
env: env-prod
|
||||
strategy:
|
||||
type: RollingSync
|
||||
deletionOrder: Reverse # Applications will be deleted in reverse order of steps
|
||||
deletionOrder: Reverse # Applications will be deleted in reverse order of steps
|
||||
rollingSync:
|
||||
steps:
|
||||
- matchExpressions:
|
||||
@@ -176,15 +185,15 @@ spec:
|
||||
operator: In
|
||||
values:
|
||||
- env-qa
|
||||
maxUpdate: 0 # if 0, no matched applications will be updated
|
||||
maxUpdate: 0 # if 0, no matched applications will be updated
|
||||
- matchExpressions:
|
||||
- key: envLabel
|
||||
operator: In
|
||||
values:
|
||||
- env-prod
|
||||
maxUpdate: 10% # maxUpdate supports both integer and percentage string values (rounds down, but floored at 1 Application for >0%)
|
||||
maxUpdate: 10% # maxUpdate supports both integer and percentage string values (rounds down, but floored at 1 Application for >0%)
|
||||
goTemplate: true
|
||||
goTemplateOptions: ["missingkey=error"]
|
||||
goTemplateOptions: ['missingkey=error']
|
||||
template:
|
||||
metadata:
|
||||
name: '{{.cluster}}-guestbook'
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
An example of an argocd-cmd-params-cm.yaml file:
|
||||
|
||||
```yaml
|
||||
{ !docs/operator-manual/argocd-cmd-params-cm.yaml! }
|
||||
```
|
||||
{!docs/operator-manual/argocd-cmd-params-cm.yaml!}
|
||||
```
|
||||
|
||||
@@ -292,10 +292,6 @@ data:
|
||||
applicationsetcontroller.global.preserved.labels: "acme.com/label1,acme.com/label2"
|
||||
# Enable GitHub API metrics for generators that use GitHub API
|
||||
applicationsetcontroller.enable.github.api.metrics: "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"
|
||||
# Enables profile endpoint on the internal metrics port
|
||||
applicationsetcontroller.profile.enabled: "false"
|
||||
|
||||
## Argo CD Notifications Controller Properties
|
||||
# Set the logging level. One of: debug|info|warn|error (default "info")
|
||||
|
||||
@@ -223,10 +223,10 @@ The following resources have Go-based health checks:
|
||||
|
||||
## Health Checks
|
||||
|
||||
An Argo CD App's health is inferred from the health of its immediate child resources (the resources represented in
|
||||
source control). The App health will be the worst health of its immediate child sources. The priority of most to least
|
||||
healthy statuses is: `Healthy`, `Suspended`, `Progressing`, `Missing`, `Degraded`, `Unknown`. So, for example, if an App
|
||||
has a `Missing` resource and a `Degraded` resource, the App's health will be `Missing`.
|
||||
Argo CD App health is inferred from the health of its immediate child resources as represented in the application source.
|
||||
The App health will be the **worst health of its immediate child resources**, based on the following priority (from most to least healthy):
|
||||
**Healthy, Suspended, Progressing, Missing, Degraded, Unknown.**
|
||||
For example, if an App has a Missing resource and a Degraded resource, the App's health will be **Degraded**.
|
||||
|
||||
But the health of a resource is not inherited from child resources - it is calculated using only information about the
|
||||
resource itself. A resource's status field may or may not contain information about the health of a child resource, and
|
||||
|
||||
@@ -398,16 +398,13 @@ Not all HTTP responses are eligible for retries. The following conditions will n
|
||||
|
||||
## CPU/Memory Profiling
|
||||
|
||||
Argo CD optionally exposes a profiling endpoint that can be used to profile the CPU and memory usage of the Argo CD
|
||||
component.
|
||||
The profiling endpoint is available on metrics port of each component. See [metrics](./metrics.md) for more information
|
||||
about the port.
|
||||
For security reasons, the profiling endpoint is disabled by default. The endpoint can be enabled by setting the
|
||||
`server.profile.enabled`, `applicationsetcontroller.profile.enabled`, or `controller.profile.enabled` key
|
||||
of [argocd-cmd-params-cm](argocd-cmd-params-cm.yaml) ConfigMap to `true`.
|
||||
Once the endpoint is enabled, you can use go profile tool to collect the CPU and memory profiles. Example:
|
||||
Argo CD optionally exposes a profiling endpoint that can be used to profile the CPU and memory usage of the Argo CD component.
|
||||
The profiling endpoint is available on metrics port of each component. See [metrics](./metrics.md) for more information about the port.
|
||||
For security reasons the profiling endpoint is disabled by default. The endpoint can be enabled by setting the `server.profile.enabled`
|
||||
or `controller.profile.enabled` key of [argocd-cmd-params-cm](argocd-cmd-params-cm.yaml) ConfigMap to `true`.
|
||||
Once the endpoint is enabled you can use go profile tool to collect the CPU and memory profiles. Example:
|
||||
|
||||
```bash
|
||||
$ kubectl port-forward svc/argocd-metrics 8082:8082
|
||||
$ go tool pprof http://localhost:8082/debug/pprof/heap
|
||||
```
|
||||
```
|
||||
|
||||
@@ -37,7 +37,6 @@ argocd-applicationset-controller [flags]
|
||||
--kubeconfig string Path to a kube config. Only required if out-of-cluster
|
||||
--logformat string Set the logging format. One of: json|text (default "json")
|
||||
--loglevel string Set the logging level. One of: debug|info|warn|error (default "info")
|
||||
--max-resources-status-count int Max number of resources stored in appset status.
|
||||
--metrics-addr string The address the metric endpoint binds to. (default ":8080")
|
||||
--metrics-applicationset-labels strings List of Application labels that will be added to the argocd_applicationset_labels metric
|
||||
-n, --namespace string If present, the namespace scope for this CLI request
|
||||
|
||||
@@ -1,5 +1,2 @@
|
||||
| Argo CD version | Kubernetes versions |
|
||||
|-----------------|---------------------|
|
||||
| 3.2 | v1.33, v1.32, v1.31, v1.30 |
|
||||
| 3.1 | v1.33, v1.32, v1.31, v1.30 |
|
||||
| 3.0 | v1.32, v1.31, v1.30, v1.29 |
|
||||
This page is populated for released Argo CD versions. Use the version selector to view this table for a specific
|
||||
version.
|
||||
|
||||
@@ -86,9 +86,3 @@ If you do not want your CronJob to affect the Application's aggregated Health, y
|
||||
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.
|
||||
|
||||
## ApplicationSet `resources` field of `status` resource is limited to 5000 elements by default
|
||||
|
||||
The `resources` field of the `status` resource of an ApplicationSet is now limited to 5000 elements by default. This is
|
||||
to prevent status bloat and exceeding etcd limits. The limit can be configured by setting the `applicationsetcontroller.status.max.resources.count`
|
||||
field in the `argocd-cmd-params-cm` ConfigMap.
|
||||
|
||||
@@ -5,5 +5,5 @@ mkdocs-material==7.1.8
|
||||
markdown_include==0.8.1
|
||||
pygments==2.19.2
|
||||
jinja2==3.1.6
|
||||
markdown==3.8.2
|
||||
markdown==3.9
|
||||
pymdown-extensions==10.16.1
|
||||
@@ -297,7 +297,6 @@ data:
|
||||
{{- if .metadata.author }}
|
||||
Co-authored-by: {{ .metadata.author }}
|
||||
{{- end }}
|
||||
```
|
||||
|
||||
### Credential Templates
|
||||
|
||||
|
||||
8
go.mod
8
go.mod
@@ -6,13 +6,13 @@ require (
|
||||
code.gitea.io/sdk/gitea v0.22.0
|
||||
dario.cat/mergo v1.0.2
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.11.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0
|
||||
github.com/Azure/kubelogin v0.2.10
|
||||
github.com/Masterminds/semver/v3 v3.4.0
|
||||
github.com/Masterminds/sprig/v3 v3.3.0
|
||||
github.com/TomOnTime/utfutil v1.0.0
|
||||
github.com/alicebob/miniredis/v2 v2.35.0
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20251006172252-b89b0871b414
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20250908182407-97ad5b59a627
|
||||
github.com/argoproj/notifications-engine v0.4.1-0.20250908182349-da04400446ff
|
||||
github.com/argoproj/pkg v0.13.6
|
||||
github.com/argoproj/pkg/v2 v2.0.1
|
||||
@@ -115,7 +115,7 @@ require (
|
||||
layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427
|
||||
oras.land/oras-go/v2 v2.6.0
|
||||
sigs.k8s.io/controller-runtime v0.21.0
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.1-0.20251003215857-446d8398e19c
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.0
|
||||
sigs.k8s.io/yaml v1.6.0
|
||||
)
|
||||
|
||||
@@ -134,7 +134,7 @@ require (
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
|
||||
15
go.sum
15
go.sum
@@ -46,8 +46,8 @@ github.com/42wim/httpsig v1.2.3 h1:xb0YyWhkYj57SPtfSttIobJUPJZB9as1nsfo7KWVcEs=
|
||||
github.com/42wim/httpsig v1.2.3/go.mod h1:nZq9OlYKDrUBhptd77IHx4/sZZD+IxTBADvAPI9G/EM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 h1:5YTBM8QDVIBN3sxBil89WfdAAqDZbyJTgh688DSxX5w=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.11.0 h1:MhRfI58HblXzCtWEZCO0feHs8LweePB3s90r7WaR1KU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.11.0/go.mod h1:okZ+ZURbArNdlJ+ptXoyHNuOETzOl1Oww19rm8I2WLA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0 h1:wL5IEG5zb7BVv1Kv0Xm92orq+5hB5Nipn3B5tn4Rqfk=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0/go.mod h1:J7MUC/wtRpfGVbQ5sIItY5/FuVWmvzlY21WAOfQnq/I=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=
|
||||
@@ -74,8 +74,8 @@ github.com/Azure/kubelogin v0.2.10 h1:6CBXJt/RtnTPI1R1E4cfEdL+BnCKMuywtglX//FZPD
|
||||
github.com/Azure/kubelogin v0.2.10/go.mod h1:JtR+7h3NHAwQPZ+CagUZ+F1Uk3/JU0eRFwpESSnRNGU=
|
||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
|
||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 h1:XkkQbfMyuH2jTSjQjSoihryI8GINRcs4xp8lNawg0FI=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo=
|
||||
@@ -113,8 +113,8 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFI
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/appscode/go v0.0.0-20191119085241-0887d8ec2ecc/go.mod h1:OawnOmAL4ZX3YaPdN+8HTNwBveT1jMsqP74moa9XUbE=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20251006172252-b89b0871b414 h1:2w1vd2VZja7Mlf/rblJkp6/Eq8fNDuM7p6pI4PTAJhg=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20251006172252-b89b0871b414/go.mod h1:2nqYZBhj8CfVZb3ATakZpi1KNb/yc7mpadIHslicTFI=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20250908182407-97ad5b59a627 h1:yntvA+uaFz62HRfWGGwlvs4ErdxoLQjCpDXufdEt2FI=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20250908182407-97ad5b59a627/go.mod h1:yJ3t/GRn9Gx2LEyMrh9X0roL7zzVlk3nvuJt6G1o6jI=
|
||||
github.com/argoproj/notifications-engine v0.4.1-0.20250908182349-da04400446ff h1:pGGAeHIktPuYCRl1Z540XdxPFnedqyUhJK4VgpyJZfY=
|
||||
github.com/argoproj/notifications-engine v0.4.1-0.20250908182349-da04400446ff/go.mod h1:d1RazGXWvKRFv9//rg4MRRR7rbvbE7XLgTSMT5fITTE=
|
||||
github.com/argoproj/pkg v0.13.6 h1:36WPD9MNYECHcO1/R1pj6teYspiK7uMQLCgLGft2abM=
|
||||
@@ -1461,9 +1461,8 @@ sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HR
|
||||
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.2.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.1-0.20251003215857-446d8398e19c h1:RCkxmWwPjOw2O1RiDgBgI6tfISvB07jAh+GEztp7TWk=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.1-0.20251003215857-446d8398e19c/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||
|
||||
@@ -10,7 +10,7 @@ PATH="${INSTALL_PATH}:${PATH}"
|
||||
[ -d "$INSTALL_PATH" ] || mkdir -p "$INSTALL_PATH"
|
||||
|
||||
# renovate: datasource=github-releases depName=gotestyourself/gotestsum packageName=gotestyourself/gotestsum
|
||||
GOTESTSUM_VERSION=1.12.3
|
||||
GOTESTSUM_VERSION=1.13.0
|
||||
|
||||
OS=$(go env GOOS)
|
||||
ARCH=$(go env GOARCH)
|
||||
|
||||
@@ -187,12 +187,6 @@ 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
|
||||
@@ -206,8 +200,6 @@ spec:
|
||||
name: tmp
|
||||
- name: argocd-repo-server-tls
|
||||
mountPath: /app/config/reposerver/tls
|
||||
- name: argocd-cmd-params-cm
|
||||
mountPath: /home/argocd/params
|
||||
securityContext:
|
||||
capabilities:
|
||||
drop:
|
||||
@@ -243,12 +235,5 @@ spec:
|
||||
path: tls.key
|
||||
- key: ca.crt
|
||||
path: ca.crt
|
||||
- name: argocd-cmd-params-cm
|
||||
configMap:
|
||||
optional: true
|
||||
name: argocd-cmd-params-cm
|
||||
items:
|
||||
- key: applicationsetcontroller.profile.enabled
|
||||
path: profiler.enabled
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
@@ -12,4 +12,4 @@ resources:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v3.2.0
|
||||
newTag: latest
|
||||
|
||||
@@ -5,7 +5,7 @@ kind: Kustomization
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v3.2.0
|
||||
newTag: latest
|
||||
resources:
|
||||
- ./application-controller
|
||||
- ./dex
|
||||
|
||||
@@ -40,7 +40,7 @@ spec:
|
||||
serviceAccountName: argocd-redis
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:8.2.2-alpine
|
||||
image: redis:8.2.1-alpine
|
||||
imagePullPolicy: Always
|
||||
args:
|
||||
- "--save"
|
||||
|
||||
47
manifests/core-install-with-hydrator.yaml
generated
47
manifests/core-install-with-hydrator.yaml
generated
@@ -1485,9 +1485,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4901,9 +4900,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4984,9 +4982,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -23740,9 +23737,6 @@ spec:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
resourcesCount:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
required:
|
||||
- metadata
|
||||
@@ -24844,13 +24838,7 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- 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:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -24880,8 +24868,6 @@ spec:
|
||||
name: tmp
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
- mountPath: /home/argocd/params
|
||||
name: argocd-cmd-params-cm
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
serviceAccountName: argocd-applicationset-controller
|
||||
@@ -24910,13 +24896,6 @@ spec:
|
||||
path: ca.crt
|
||||
optional: true
|
||||
secretName: argocd-repo-server-tls
|
||||
- configMap:
|
||||
items:
|
||||
- key: applicationsetcontroller.profile.enabled
|
||||
path: profiler.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
name: argocd-cmd-params-cm
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -24985,7 +24964,7 @@ spec:
|
||||
key: log.format.timestamp
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -25097,7 +25076,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -25113,7 +25092,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -25404,7 +25383,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -25456,7 +25435,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -25804,7 +25783,7 @@ spec:
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
45
manifests/core-install.yaml
generated
45
manifests/core-install.yaml
generated
@@ -1485,9 +1485,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4901,9 +4900,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4984,9 +4982,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -23740,9 +23737,6 @@ spec:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
resourcesCount:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
required:
|
||||
- metadata
|
||||
@@ -24812,13 +24806,7 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- 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:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -24848,8 +24836,6 @@ spec:
|
||||
name: tmp
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
- mountPath: /home/argocd/params
|
||||
name: argocd-cmd-params-cm
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
serviceAccountName: argocd-applicationset-controller
|
||||
@@ -24878,13 +24864,6 @@ spec:
|
||||
path: ca.crt
|
||||
optional: true
|
||||
secretName: argocd-repo-server-tls
|
||||
- configMap:
|
||||
items:
|
||||
- key: applicationsetcontroller.profile.enabled
|
||||
path: profiler.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
name: argocd-cmd-params-cm
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -24931,7 +24910,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -24947,7 +24926,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -25238,7 +25217,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -25290,7 +25269,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -25638,7 +25617,7 @@ spec:
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -12,4 +12,4 @@ resources:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v3.2.0
|
||||
newTag: latest
|
||||
|
||||
15
manifests/crds/application-crd.yaml
generated
15
manifests/crds/application-crd.yaml
generated
@@ -1484,9 +1484,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4900,9 +4899,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4983,9 +4981,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
|
||||
3
manifests/crds/applicationset-crd.yaml
generated
3
manifests/crds/applicationset-crd.yaml
generated
@@ -17823,9 +17823,6 @@ spec:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
resourcesCount:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
required:
|
||||
- metadata
|
||||
|
||||
@@ -12,7 +12,7 @@ patches:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v3.2.0
|
||||
newTag: latest
|
||||
resources:
|
||||
- ../../base/application-controller
|
||||
- ../../base/applicationset-controller
|
||||
|
||||
@@ -1270,7 +1270,7 @@ spec:
|
||||
automountServiceAccountToken: false
|
||||
initContainers:
|
||||
- name: config-init
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
{}
|
||||
@@ -1310,7 +1310,7 @@ spec:
|
||||
|
||||
containers:
|
||||
- name: redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- redis-server
|
||||
@@ -1384,7 +1384,7 @@ spec:
|
||||
- /bin/sh
|
||||
- /readonly-config/trigger-failover-if-master.sh
|
||||
- name: sentinel
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- redis-sentinel
|
||||
@@ -1457,7 +1457,7 @@ spec:
|
||||
- sleep 30; redis-cli -p 26379 sentinel reset argocd
|
||||
|
||||
- name: split-brain-fix
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- sh
|
||||
|
||||
@@ -27,7 +27,7 @@ redis-ha:
|
||||
serviceAccount:
|
||||
automountToken: true
|
||||
image:
|
||||
tag: 8.2.2-alpine
|
||||
tag: 8.2.1-alpine
|
||||
sentinel:
|
||||
bind: '0.0.0.0'
|
||||
lifecycle:
|
||||
|
||||
59
manifests/ha/install-with-hydrator.yaml
generated
59
manifests/ha/install-with-hydrator.yaml
generated
@@ -1485,9 +1485,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4901,9 +4900,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4984,9 +4982,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -23740,9 +23737,6 @@ spec:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
resourcesCount:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
required:
|
||||
- metadata
|
||||
@@ -26210,13 +26204,7 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- 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:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -26246,8 +26234,6 @@ spec:
|
||||
name: tmp
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
- mountPath: /home/argocd/params
|
||||
name: argocd-cmd-params-cm
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
serviceAccountName: argocd-applicationset-controller
|
||||
@@ -26276,13 +26262,6 @@ spec:
|
||||
path: ca.crt
|
||||
optional: true
|
||||
secretName: argocd-repo-server-tls
|
||||
- configMap:
|
||||
items:
|
||||
- key: applicationsetcontroller.profile.enabled
|
||||
path: profiler.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
name: argocd-cmd-params-cm
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -26351,7 +26330,7 @@ spec:
|
||||
key: log.format.timestamp
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -26502,7 +26481,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -26598,7 +26577,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -26722,7 +26701,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -27039,7 +27018,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -27091,7 +27070,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -27465,7 +27444,7 @@ spec:
|
||||
key: server.sync.replace.allowed
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -27849,7 +27828,7 @@ spec:
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
@@ -27947,7 +27926,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
preStop:
|
||||
@@ -28018,7 +27997,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
postStart:
|
||||
@@ -28093,7 +28072,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: split-brain-fix
|
||||
resources: {}
|
||||
@@ -28128,7 +28107,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
|
||||
57
manifests/ha/install.yaml
generated
57
manifests/ha/install.yaml
generated
@@ -1485,9 +1485,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4901,9 +4900,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4984,9 +4982,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -23740,9 +23737,6 @@ spec:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
resourcesCount:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
required:
|
||||
- metadata
|
||||
@@ -26180,13 +26174,7 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- 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:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -26216,8 +26204,6 @@ spec:
|
||||
name: tmp
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
- mountPath: /home/argocd/params
|
||||
name: argocd-cmd-params-cm
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
serviceAccountName: argocd-applicationset-controller
|
||||
@@ -26246,13 +26232,6 @@ spec:
|
||||
path: ca.crt
|
||||
optional: true
|
||||
secretName: argocd-repo-server-tls
|
||||
- configMap:
|
||||
items:
|
||||
- key: applicationsetcontroller.profile.enabled
|
||||
path: profiler.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
name: argocd-cmd-params-cm
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -26338,7 +26317,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -26434,7 +26413,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -26558,7 +26537,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -26875,7 +26854,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -26927,7 +26906,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -27301,7 +27280,7 @@ spec:
|
||||
key: server.sync.replace.allowed
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -27685,7 +27664,7 @@ spec:
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
@@ -27783,7 +27762,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
preStop:
|
||||
@@ -27854,7 +27833,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
postStart:
|
||||
@@ -27929,7 +27908,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: split-brain-fix
|
||||
resources: {}
|
||||
@@ -27964,7 +27943,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
|
||||
41
manifests/ha/namespace-install-with-hydrator.yaml
generated
41
manifests/ha/namespace-install-with-hydrator.yaml
generated
@@ -1891,13 +1891,7 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- 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:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -1927,8 +1921,6 @@ spec:
|
||||
name: tmp
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
- mountPath: /home/argocd/params
|
||||
name: argocd-cmd-params-cm
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
serviceAccountName: argocd-applicationset-controller
|
||||
@@ -1957,13 +1949,6 @@ spec:
|
||||
path: ca.crt
|
||||
optional: true
|
||||
secretName: argocd-repo-server-tls
|
||||
- configMap:
|
||||
items:
|
||||
- key: applicationsetcontroller.profile.enabled
|
||||
path: profiler.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
name: argocd-cmd-params-cm
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -2032,7 +2017,7 @@ spec:
|
||||
key: log.format.timestamp
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -2183,7 +2168,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -2279,7 +2264,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -2403,7 +2388,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -2720,7 +2705,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -2772,7 +2757,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -3146,7 +3131,7 @@ spec:
|
||||
key: server.sync.replace.allowed
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -3530,7 +3515,7 @@ spec:
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
@@ -3628,7 +3613,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
preStop:
|
||||
@@ -3699,7 +3684,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
postStart:
|
||||
@@ -3774,7 +3759,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: split-brain-fix
|
||||
resources: {}
|
||||
@@ -3809,7 +3794,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
|
||||
39
manifests/ha/namespace-install.yaml
generated
39
manifests/ha/namespace-install.yaml
generated
@@ -1861,13 +1861,7 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- 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:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -1897,8 +1891,6 @@ spec:
|
||||
name: tmp
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
- mountPath: /home/argocd/params
|
||||
name: argocd-cmd-params-cm
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
serviceAccountName: argocd-applicationset-controller
|
||||
@@ -1927,13 +1919,6 @@ spec:
|
||||
path: ca.crt
|
||||
optional: true
|
||||
secretName: argocd-repo-server-tls
|
||||
- configMap:
|
||||
items:
|
||||
- key: applicationsetcontroller.profile.enabled
|
||||
path: profiler.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
name: argocd-cmd-params-cm
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -2019,7 +2004,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -2115,7 +2100,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -2239,7 +2224,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -2556,7 +2541,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -2608,7 +2593,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -2982,7 +2967,7 @@ spec:
|
||||
key: server.sync.replace.allowed
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -3366,7 +3351,7 @@ spec:
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
@@ -3464,7 +3449,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
preStop:
|
||||
@@ -3535,7 +3520,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle:
|
||||
postStart:
|
||||
@@ -3610,7 +3595,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: split-brain-fix
|
||||
resources: {}
|
||||
@@ -3645,7 +3630,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
|
||||
53
manifests/install-with-hydrator.yaml
generated
53
manifests/install-with-hydrator.yaml
generated
@@ -1485,9 +1485,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4901,9 +4900,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4984,9 +4982,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -23740,9 +23737,6 @@ spec:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
resourcesCount:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
required:
|
||||
- metadata
|
||||
@@ -25288,13 +25282,7 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- 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:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -25324,8 +25312,6 @@ spec:
|
||||
name: tmp
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
- mountPath: /home/argocd/params
|
||||
name: argocd-cmd-params-cm
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
serviceAccountName: argocd-applicationset-controller
|
||||
@@ -25354,13 +25340,6 @@ spec:
|
||||
path: ca.crt
|
||||
optional: true
|
||||
secretName: argocd-repo-server-tls
|
||||
- configMap:
|
||||
items:
|
||||
- key: applicationsetcontroller.profile.enabled
|
||||
path: profiler.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
name: argocd-cmd-params-cm
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -25429,7 +25408,7 @@ spec:
|
||||
key: log.format.timestamp
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -25580,7 +25559,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -25676,7 +25655,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -25762,7 +25741,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -25778,7 +25757,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -26069,7 +26048,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -26121,7 +26100,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -26493,7 +26472,7 @@ spec:
|
||||
key: server.sync.replace.allowed
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -26877,7 +26856,7 @@ spec:
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
51
manifests/install.yaml
generated
51
manifests/install.yaml
generated
@@ -1485,9 +1485,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4901,9 +4900,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -4984,9 +4982,8 @@ spec:
|
||||
pattern: ^.{2,}|[^./]$
|
||||
type: string
|
||||
targetBranch:
|
||||
description: |-
|
||||
TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
description: TargetBranch is the branch to which hydrated
|
||||
manifests should be committed
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
@@ -23740,9 +23737,6 @@ spec:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
resourcesCount:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
required:
|
||||
- metadata
|
||||
@@ -25256,13 +25250,7 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- 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:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -25292,8 +25280,6 @@ spec:
|
||||
name: tmp
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
- mountPath: /home/argocd/params
|
||||
name: argocd-cmd-params-cm
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
serviceAccountName: argocd-applicationset-controller
|
||||
@@ -25322,13 +25308,6 @@ spec:
|
||||
path: ca.crt
|
||||
optional: true
|
||||
secretName: argocd-repo-server-tls
|
||||
- configMap:
|
||||
items:
|
||||
- key: applicationsetcontroller.profile.enabled
|
||||
path: profiler.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
name: argocd-cmd-params-cm
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -25414,7 +25393,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -25510,7 +25489,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -25596,7 +25575,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -25612,7 +25591,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -25903,7 +25882,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -25955,7 +25934,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -26327,7 +26306,7 @@ spec:
|
||||
key: server.sync.replace.allowed
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -26711,7 +26690,7 @@ spec:
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
35
manifests/namespace-install-with-hydrator.yaml
generated
35
manifests/namespace-install-with-hydrator.yaml
generated
@@ -969,13 +969,7 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- 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:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -1005,8 +999,6 @@ spec:
|
||||
name: tmp
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
- mountPath: /home/argocd/params
|
||||
name: argocd-cmd-params-cm
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
serviceAccountName: argocd-applicationset-controller
|
||||
@@ -1035,13 +1027,6 @@ spec:
|
||||
path: ca.crt
|
||||
optional: true
|
||||
secretName: argocd-repo-server-tls
|
||||
- configMap:
|
||||
items:
|
||||
- key: applicationsetcontroller.profile.enabled
|
||||
path: profiler.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
name: argocd-cmd-params-cm
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -1110,7 +1095,7 @@ spec:
|
||||
key: log.format.timestamp
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1261,7 +1246,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -1357,7 +1342,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -1443,7 +1428,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -1459,7 +1444,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -1750,7 +1735,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1802,7 +1787,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -2174,7 +2159,7 @@ spec:
|
||||
key: server.sync.replace.allowed
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2558,7 +2543,7 @@ spec:
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
33
manifests/namespace-install.yaml
generated
33
manifests/namespace-install.yaml
generated
@@ -937,13 +937,7 @@ spec:
|
||||
key: applicationsetcontroller.requeue.after
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- 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:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -973,8 +967,6 @@ spec:
|
||||
name: tmp
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
- mountPath: /home/argocd/params
|
||||
name: argocd-cmd-params-cm
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
serviceAccountName: argocd-applicationset-controller
|
||||
@@ -1003,13 +995,6 @@ spec:
|
||||
path: ca.crt
|
||||
optional: true
|
||||
secretName: argocd-repo-server-tls
|
||||
- configMap:
|
||||
items:
|
||||
- key: applicationsetcontroller.profile.enabled
|
||||
path: profiler.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
name: argocd-cmd-params-cm
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -1095,7 +1080,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -1191,7 +1176,7 @@ spec:
|
||||
key: notificationscontroller.repo.server.plaintext
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -1277,7 +1262,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: auth
|
||||
name: argocd-redis
|
||||
image: public.ecr.aws/docker/library/redis:8.2.2-alpine
|
||||
image: public.ecr.aws/docker/library/redis:8.2.1-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -1293,7 +1278,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -1584,7 +1569,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1636,7 +1621,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -2008,7 +1993,7 @@ spec:
|
||||
key: server.sync.replace.allowed
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2392,7 +2377,7 @@ spec:
|
||||
optional: true
|
||||
- name: KUBECACHEDIR
|
||||
value: /tmp/kubecache
|
||||
image: quay.io/argoproj/argocd:v3.2.0
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -805,9 +805,6 @@ type ApplicationSetStatus struct {
|
||||
ApplicationStatus []ApplicationSetApplicationStatus `json:"applicationStatus,omitempty" protobuf:"bytes,2,name=applicationStatus"`
|
||||
// Resources is a list of Applications resources managed by this application set.
|
||||
Resources []ResourceStatus `json:"resources,omitempty" protobuf:"bytes,3,opt,name=resources"`
|
||||
// ResourcesCount is the total number of resources managed by this application set. The count may be higher than actual number of items in the Resources field when
|
||||
// the number of managed resources exceeds the limit imposed by the controller (to avoid making the status field too large).
|
||||
ResourcesCount int64 `json:"resourcesCount,omitempty" protobuf:"varint,4,opt,name=resourcesCount"`
|
||||
}
|
||||
|
||||
// ApplicationSetCondition contains details about an applicationset condition, which is usually an error or warning
|
||||
@@ -870,6 +867,20 @@ const (
|
||||
ApplicationSetReasonSyncApplicationError = "SyncApplicationError"
|
||||
)
|
||||
|
||||
// Represents resource health status
|
||||
type ProgressiveSyncStatusCode string
|
||||
|
||||
const (
|
||||
// Indicates that an Application sync is waiting to be trigerred
|
||||
ProgressiveSyncWaiting ProgressiveSyncStatusCode = "Waiting"
|
||||
// Indicates that a sync has been trigerred, but the application did not report any status
|
||||
ProgressiveSyncPending ProgressiveSyncStatusCode = "Pending"
|
||||
// Indicates that the application has not yet reached an Healthy state in regards to the requested sync
|
||||
ProgressiveSyncProgressing ProgressiveSyncStatusCode = "Progressing"
|
||||
// Indicates that the application has reached an Healthy state in regards to the requested sync
|
||||
ProgressiveSyncHealthy ProgressiveSyncStatusCode = "Healthy"
|
||||
)
|
||||
|
||||
// ApplicationSetApplicationStatus contains details about each Application managed by the ApplicationSet
|
||||
type ApplicationSetApplicationStatus struct {
|
||||
// Application contains the name of the Application resource
|
||||
@@ -878,8 +889,8 @@ type ApplicationSetApplicationStatus struct {
|
||||
LastTransitionTime *metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,2,opt,name=lastTransitionTime"`
|
||||
// Message contains human-readable message indicating details about the status
|
||||
Message string `json:"message" protobuf:"bytes,3,opt,name=message"`
|
||||
// Status contains the AppSet's perceived status of the managed Application resource: (Waiting, Pending, Progressing, Healthy)
|
||||
Status string `json:"status" protobuf:"bytes,4,opt,name=status"`
|
||||
// Status contains the AppSet's perceived status of the managed Application resource
|
||||
Status ProgressiveSyncStatusCode `json:"status" protobuf:"bytes,4,opt,name=status"`
|
||||
// Step tracks which step this Application should be updated in
|
||||
Step string `json:"step" protobuf:"bytes,5,opt,name=step"`
|
||||
// TargetRevision tracks the desired revisions the Application should be synced to.
|
||||
|
||||
1575
pkg/apis/application/v1alpha1/generated.pb.go
generated
1575
pkg/apis/application/v1alpha1/generated.pb.go
generated
File diff suppressed because it is too large
Load Diff
@@ -222,7 +222,7 @@ message ApplicationSetApplicationStatus {
|
||||
// Message contains human-readable message indicating details about the status
|
||||
optional string message = 3;
|
||||
|
||||
// Status contains the AppSet's perceived status of the managed Application resource: (Waiting, Pending, Progressing, Healthy)
|
||||
// Status contains the AppSet's perceived status of the managed Application resource
|
||||
optional string status = 4;
|
||||
|
||||
// Step tracks which step this Application should be updated in
|
||||
@@ -369,10 +369,6 @@ message ApplicationSetStatus {
|
||||
|
||||
// Resources is a list of Applications resources managed by this application set.
|
||||
repeated ResourceStatus resources = 3;
|
||||
|
||||
// ResourcesCount is the total number of resources managed by this application set. The count may be higher than actual number of items in the Resources field when
|
||||
// the number of managed resources exceeds the limit imposed by the controller (to avoid making the status field too large).
|
||||
optional int64 resourcesCount = 4;
|
||||
}
|
||||
|
||||
// ApplicationSetStrategy configures how generated Applications are updated in sequence.
|
||||
@@ -2639,8 +2635,7 @@ message SyncPolicyAutomated {
|
||||
// SyncSource specifies a location from which hydrated manifests may be synced. RepoURL is assumed based on the
|
||||
// associated DrySource config in the SourceHydrator.
|
||||
message SyncSource {
|
||||
// TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
// If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
// TargetBranch is the branch to which hydrated manifests should be committed
|
||||
optional string targetBranch = 1;
|
||||
|
||||
// Path is a directory path within the git repository where hydrated manifests should be committed to and synced
|
||||
|
||||
@@ -443,8 +443,7 @@ type DrySource struct {
|
||||
// SyncSource specifies a location from which hydrated manifests may be synced. RepoURL is assumed based on the
|
||||
// associated DrySource config in the SourceHydrator.
|
||||
type SyncSource struct {
|
||||
// TargetBranch is the branch from which hydrated manifests will be synced.
|
||||
// If HydrateTo is not set, this is also the branch to which hydrated manifests are committed.
|
||||
// TargetBranch is the branch to which hydrated manifests should be committed
|
||||
TargetBranch string `json:"targetBranch" protobuf:"bytes,1,name=targetBranch"`
|
||||
// Path is a directory path within the git repository where hydrated manifests should be committed to and synced
|
||||
// from. The Path should never point to the root of the repo. If hydrateTo is set, this is just the path from which
|
||||
|
||||
3
renovate.json
Normal file
3
renovate.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
-- Health check copied from here: https://github.com/crossplane/docs/blob/709889c5dbe6e5a2ea3dffd66fe276cf465b47b5/content/master/guides/crossplane-with-argo-cd.md
|
||||
-- Health check copied from here: https://github.com/crossplane/docs/blob/bd701357e9d5eecf529a0b42f23a78850a6d1d87/content/master/guides/crossplane-with-argo-cd.md
|
||||
|
||||
health_status = {
|
||||
status = "Progressing",
|
||||
@@ -18,10 +18,9 @@ local has_no_status = {
|
||||
"Composition",
|
||||
"CompositionRevision",
|
||||
"DeploymentRuntimeConfig",
|
||||
"ClusterProviderConfig",
|
||||
"ControllerConfig",
|
||||
"ProviderConfig",
|
||||
"ProviderConfigUsage",
|
||||
"ControllerConfig" -- Added to ensure that healthcheck is backwards-compatible with Crossplane v1
|
||||
"ProviderConfigUsage"
|
||||
}
|
||||
if obj.status == nil or next(obj.status) == nil and contains(has_no_status, obj.kind) then
|
||||
health_status.status = "Healthy"
|
||||
@@ -30,7 +29,7 @@ if obj.status == nil or next(obj.status) == nil and contains(has_no_status, obj.
|
||||
end
|
||||
|
||||
if obj.status == nil or next(obj.status) == nil or obj.status.conditions == nil then
|
||||
if (obj.kind == "ProviderConfig" or obj.kind == "ClusterProviderConfig") and obj.status.users ~= nil then
|
||||
if obj.kind == "ProviderConfig" and obj.status.users ~= nil then
|
||||
health_status.status = "Healthy"
|
||||
health_status.message = "Resource is in use."
|
||||
return health_status
|
||||
@@ -55,7 +54,7 @@ for i, condition in ipairs(obj.status.conditions) do
|
||||
end
|
||||
end
|
||||
|
||||
if contains({"Ready", "Healthy", "Offered", "Established", "ValidPipeline", "RevisionHealthy"}, condition.type) then
|
||||
if contains({"Ready", "Healthy", "Offered", "Established"}, condition.type) then
|
||||
if condition.status == "True" then
|
||||
health_status.status = "Healthy"
|
||||
health_status.message = "Resource is up-to-date."
|
||||
|
||||
@@ -3,7 +3,3 @@ tests:
|
||||
status: Healthy
|
||||
message: "Resource is up-to-date."
|
||||
inputPath: testdata/composition_healthy.yaml
|
||||
- healthStatus:
|
||||
status: Healthy
|
||||
message: "Resource is up-to-date."
|
||||
inputPath: testdata/configurationrevision_healthy.yaml
|
||||
@@ -1,22 +0,0 @@
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: ConfigurationRevision
|
||||
metadata:
|
||||
annotations:
|
||||
meta.crossplane.io/license: Apache-2.0
|
||||
meta.crossplane.io/maintainer: Upbound <support@upbound.io>
|
||||
meta.crossplane.io/source: github.com/upbound/configuration-getting-started
|
||||
name: upbound-configuration-getting-started-869bca254eb1
|
||||
spec:
|
||||
desiredState: Active
|
||||
ignoreCrossplaneConstraints: false
|
||||
image: xpkg.upbound.io/upbound/configuration-getting-started:v0.3.0
|
||||
packagePullPolicy: IfNotPresent
|
||||
revision: 1
|
||||
skipDependencyResolution: false
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: "2025-09-29T18:06:40Z"
|
||||
observedGeneration: 1
|
||||
reason: HealthyPackageRevision
|
||||
status: "True"
|
||||
type: RevisionHealthy
|
||||
@@ -1,4 +1,4 @@
|
||||
-- Health check copied from here: https://github.com/crossplane/docs/blob/709889c5dbe6e5a2ea3dffd66fe276cf465b47b5/content/master/guides/crossplane-with-argo-cd.md
|
||||
-- Health check copied from here: https://github.com/crossplane/docs/blob/bd701357e9d5eecf529a0b42f23a78850a6d1d87/content/master/guides/crossplane-with-argo-cd.md
|
||||
|
||||
health_status = {
|
||||
status = "Progressing",
|
||||
@@ -15,7 +15,6 @@ local function contains (table, val)
|
||||
end
|
||||
|
||||
local has_no_status = {
|
||||
"ClusterProviderConfig",
|
||||
"ProviderConfig",
|
||||
"ProviderConfigUsage"
|
||||
}
|
||||
@@ -27,7 +26,7 @@ if obj.status == nil or next(obj.status) == nil and contains(has_no_status, obj.
|
||||
end
|
||||
|
||||
if obj.status == nil or next(obj.status) == nil or obj.status.conditions == nil then
|
||||
if (obj.kind == "ProviderConfig" or obj.kind == "ClusterProviderConfig") and obj.status.users ~= nil then
|
||||
if obj.kind == "ProviderConfig" and obj.status.users ~= nil then
|
||||
health_status.status = "Healthy"
|
||||
health_status.message = "Resource is in use."
|
||||
return health_status
|
||||
|
||||
@@ -7,6 +7,3 @@ discoveryTests:
|
||||
- inputPath: testdata/external-secret.yaml
|
||||
result:
|
||||
- name: "refresh"
|
||||
- inputPath: testdata/external-secret-refresh-policy.yaml
|
||||
result:
|
||||
- name: "refresh"
|
||||
|
||||
@@ -3,11 +3,10 @@ local actions = {}
|
||||
local disable_refresh = false
|
||||
local time_units = {"ns", "us", "µs", "ms", "s", "m", "h"}
|
||||
local digits = obj.spec.refreshInterval
|
||||
local policy = obj.spec.refreshPolicy
|
||||
if digits ~= nil then
|
||||
digits = tostring(digits)
|
||||
for _, time_unit in ipairs(time_units) do
|
||||
if (digits == "0" or digits == "0" .. time_unit) and policy ~= "OnChange" then
|
||||
if digits == "0" or digits == "0" .. time_unit then
|
||||
disable_refresh = true
|
||||
break
|
||||
end
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
apiVersion: external-secrets.io/v1alpha1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
creationTimestamp: '2021-11-16T21:59:33Z'
|
||||
generation: 1
|
||||
name: test-healthy
|
||||
namespace: argocd
|
||||
resourceVersion: '136487331'
|
||||
selfLink: /apis/external-secrets.io/v1alpha1/namespaces/argocd/externalsecrets/test-healthy
|
||||
uid: 1e754a7e-0781-4d57-932d-4651d5b19586
|
||||
spec:
|
||||
data:
|
||||
- remoteRef:
|
||||
key: secret/sa/example
|
||||
property: api.address
|
||||
secretKey: url
|
||||
- remoteRef:
|
||||
key: secret/sa/example
|
||||
property: ca.crt
|
||||
secretKey: ca
|
||||
- remoteRef:
|
||||
key: secret/sa/example
|
||||
property: token
|
||||
secretKey: token
|
||||
refreshInterval: 0
|
||||
refreshPolicy: OnChange
|
||||
secretStoreRef:
|
||||
kind: SecretStore
|
||||
name: example
|
||||
target:
|
||||
creationPolicy: Owner
|
||||
template:
|
||||
data:
|
||||
config: |
|
||||
{
|
||||
"bearerToken": "{{ .token | base64decode | toString }}",
|
||||
"tlsClientConfig": {
|
||||
"insecure": false,
|
||||
"caData": "{{ .ca | toString }}"
|
||||
}
|
||||
}
|
||||
name: cluster-test
|
||||
server: '{{ .url | toString }}'
|
||||
metadata:
|
||||
labels:
|
||||
argocd.argoproj.io/secret-type: cluster
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: '2021-11-16T21:59:34Z'
|
||||
message: Secret was synced
|
||||
reason: SecretSynced
|
||||
status: 'True'
|
||||
type: Ready
|
||||
refreshTime: '2021-11-29T18:32:24Z'
|
||||
syncedResourceVersion: 1-519a61da0dc68b2575b4f8efada70e42
|
||||
@@ -9,39 +9,10 @@ function checkConditions(conditions, conditionType)
|
||||
return true
|
||||
end
|
||||
|
||||
-- isParentGenerationObserved checks if a parent's conditions match the current resource generation
|
||||
-- For HTTPRoute, observedGeneration is stored in each condition within a parent
|
||||
function isParentGenerationObserved(obj, parent)
|
||||
if obj.metadata.generation == nil then
|
||||
-- If no generation is set, accept all conditions
|
||||
return true
|
||||
end
|
||||
|
||||
if parent.conditions == nil or #parent.conditions == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check if all conditions have observedGeneration matching current generation
|
||||
for _, condition in ipairs(parent.conditions) do
|
||||
if condition.observedGeneration ~= nil then
|
||||
if condition.observedGeneration ~= obj.metadata.generation then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if obj.status ~= nil then
|
||||
if obj.status.parents ~= nil then
|
||||
for _, parent in ipairs(obj.status.parents) do
|
||||
if parent.conditions ~= nil then
|
||||
-- Skip this parent if it's not from the current generation
|
||||
if not isParentGenerationObserved(obj, parent) then
|
||||
goto continue
|
||||
end
|
||||
|
||||
local resolvedRefsFalse, resolvedRefsMsg = checkConditions(parent.conditions, "ResolvedRefs")
|
||||
local acceptedFalse, acceptedMsg = checkConditions(parent.conditions, "Accepted")
|
||||
|
||||
@@ -73,20 +44,15 @@ if obj.status ~= nil then
|
||||
hs.message = "Parent " .. (parent.parentRef.name or "") .. ": " .. progressingMsg
|
||||
return hs
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
if #obj.status.parents > 0 then
|
||||
for _, parent in ipairs(obj.status.parents) do
|
||||
if parent.conditions ~= nil and #parent.conditions > 0 then
|
||||
-- Only mark as healthy if we found a parent from the current generation
|
||||
if isParentGenerationObserved(obj, parent) then
|
||||
hs.status = "Healthy"
|
||||
hs.message = "HTTPRoute is healthy"
|
||||
return hs
|
||||
end
|
||||
hs.status = "Healthy"
|
||||
hs.message = "HTTPRoute is healthy"
|
||||
return hs
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,8 +14,4 @@ tests:
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: "Parent example-gateway: Route is still being programmed"
|
||||
inputPath: testdata/progressing.yaml
|
||||
- healthStatus:
|
||||
status: Healthy
|
||||
message: HTTPRoute is healthy
|
||||
inputPath: testdata/healthy_multiple_generations.yaml
|
||||
inputPath: testdata/progressing.yaml
|
||||
@@ -1,59 +0,0 @@
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: example-httproute
|
||||
generation: 2
|
||||
spec:
|
||||
parentRefs:
|
||||
- kind: Gateway
|
||||
name: eg
|
||||
namespace: envoy-gateway-system
|
||||
sectionName: foo-nonexistent
|
||||
hostnames:
|
||||
- "example-httproute.example.com"
|
||||
rules:
|
||||
- backendRefs:
|
||||
- name: example-service
|
||||
port: 8080
|
||||
status:
|
||||
parents:
|
||||
- conditions:
|
||||
- lastTransitionTime: "2025-10-14T11:19:41Z"
|
||||
message: No listeners match this parent ref
|
||||
observedGeneration: 1
|
||||
reason: NoMatchingParent
|
||||
status: "False"
|
||||
type: Accepted
|
||||
- lastTransitionTime: "2025-10-14T11:19:41Z"
|
||||
message: Resolved all the Object references for the Route
|
||||
observedGeneration: 1
|
||||
reason: ResolvedRefs
|
||||
status: "True"
|
||||
type: ResolvedRefs
|
||||
controllerName: gateway.envoyproxy.io/gatewayclass-controller
|
||||
parentRef:
|
||||
group: gateway.networking.k8s.io
|
||||
kind: Gateway
|
||||
name: eg
|
||||
namespace: envoy-gateway-system
|
||||
sectionName: foo-nonexistent
|
||||
- conditions:
|
||||
- lastTransitionTime: "2025-10-14T11:25:18Z"
|
||||
message: Route is accepted
|
||||
observedGeneration: 2
|
||||
reason: Accepted
|
||||
status: "True"
|
||||
type: Accepted
|
||||
- lastTransitionTime: "2025-10-14T11:25:18Z"
|
||||
message: Resolved all the Object references for the Route
|
||||
observedGeneration: 2
|
||||
reason: ResolvedRefs
|
||||
status: "True"
|
||||
type: ResolvedRefs
|
||||
controllerName: gateway.envoyproxy.io/gatewayclass-controller
|
||||
parentRef:
|
||||
group: gateway.networking.k8s.io
|
||||
kind: Gateway
|
||||
name: eg
|
||||
namespace: envoy-gateway-system
|
||||
sectionName: https-net
|
||||
@@ -25,17 +25,9 @@ if obj.status.conditions then
|
||||
hs.message = "Waiting for Argo CD commit status spec update to be observed"
|
||||
return hs
|
||||
end
|
||||
-- Check for any False condition status
|
||||
if condition.status == "False" then
|
||||
if condition.status == "False" and condition.reason == "ReconciliationError" then
|
||||
hs.status = "Degraded"
|
||||
local msg = condition.message or "Unknown error"
|
||||
local reason = condition.reason or "Unknown"
|
||||
-- Don't include ReconciliationError in the message since it's redundant
|
||||
if reason == "ReconciliationError" then
|
||||
hs.message = "Argo CD commit status reconciliation failed: " .. msg
|
||||
else
|
||||
hs.message = "Argo CD commit status reconciliation failed (" .. reason .. "): " .. msg
|
||||
end
|
||||
hs.message = "Argo CD commit status reconciliation failed: " .. (condition.message or "Unknown error")
|
||||
return hs
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,10 +15,6 @@ tests:
|
||||
status: Degraded
|
||||
message: "Argo CD commit status reconciliation failed: Something went wrong"
|
||||
inputPath: testdata/reconcile-error.yaml
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: "Argo CD commit status reconciliation failed: Failed to query Argo CD applications: connection timeout"
|
||||
inputPath: testdata/non-reconciliation-error.yaml
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: Argo CD commit status is not ready yet
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
apiVersion: promoter.argoproj.io/v1alpha1
|
||||
kind: ArgoCDCommitStatus
|
||||
metadata:
|
||||
name: test-commit-status
|
||||
namespace: test
|
||||
generation: 1
|
||||
spec:
|
||||
applicationSelector:
|
||||
matchLabels:
|
||||
environment: production
|
||||
promotionStrategyRef:
|
||||
name: test
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: '2025-10-15T16:00:00Z'
|
||||
message: 'Failed to query Argo CD applications: connection timeout'
|
||||
observedGeneration: 1
|
||||
reason: ReconciliationError
|
||||
status: 'False'
|
||||
type: Ready
|
||||
|
||||
@@ -26,17 +26,9 @@ if obj.status.conditions then
|
||||
hs.message = "Waiting for change transfer policy spec update to be observed"
|
||||
return hs
|
||||
end
|
||||
-- Check for any False condition status
|
||||
if condition.status == "False" then
|
||||
if condition.status == "False" and condition.reason == "ReconciliationError" then
|
||||
hs.status = "Degraded"
|
||||
local msg = condition.message or "Unknown error"
|
||||
local reason = condition.reason or "Unknown"
|
||||
-- Don't include ReconciliationError in the message since it's redundant
|
||||
if reason == "ReconciliationError" then
|
||||
hs.message = "Change transfer policy reconciliation failed: " .. msg
|
||||
else
|
||||
hs.message = "Change transfer policy reconciliation failed (" .. reason .. "): " .. msg
|
||||
end
|
||||
hs.message = "Change transfer policy reconciliation failed: " .. (condition.message or "Unknown error")
|
||||
return hs
|
||||
end
|
||||
end
|
||||
|
||||
@@ -39,7 +39,3 @@ tests:
|
||||
status: Healthy
|
||||
message: "Environment is up-to-date, but there are non-successful active commit statuses: 1 pending, 0 successful, 0 failed. Pending commit statuses: argocd-health. "
|
||||
inputPath: testdata/non-successful-environments.yaml
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: "Change transfer policy reconciliation failed (PullRequestNotReady): PullRequest \"deployment-environments-qal-usw2-next-environments-qal-usw2-7a8e7b70\" is not Ready because \"ReconciliationError\": Reconciliation failed: failed to merge pull request: failed to merge pull request: failed to merge pull request: PUT https://github.example.com/api/v3/repos/org/deployment/pulls/3/merge: 405 At least 2 approving reviews are required by reviewers with write access. Required status check \"continuous-integration/jenkins/pr-head\" is expected. You're not authorized to push to this branch."
|
||||
inputPath: testdata/missing-sha-and-not-ready.yaml
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
apiVersion: promoter.argoproj.io/v1alpha1
|
||||
kind: ChangeTransferPolicy
|
||||
metadata:
|
||||
annotations:
|
||||
promoter.argoproj.io/reconcile-at: '2025-10-15T17:11:51.672763364Z'
|
||||
creationTimestamp: '2025-10-15T16:26:17Z'
|
||||
generation: 1
|
||||
labels:
|
||||
promoter.argoproj.io/environment: environments-qal-usw2
|
||||
promoter.argoproj.io/promotion-strategy: strategy
|
||||
name: strategy-environments-qal-usw2-27894e05
|
||||
namespace: test
|
||||
ownerReferences:
|
||||
- apiVersion: promoter.argoproj.io/v1alpha1
|
||||
blockOwnerDeletion: true
|
||||
controller: true
|
||||
kind: PromotionStrategy
|
||||
name: strategy
|
||||
uid: 146aaaba-72d5-4155-bf5b-b5fd03b8a6d0
|
||||
resourceVersion: '116412858'
|
||||
uid: 62e1ed12-d808-4c78-9217-f80822f930ae
|
||||
spec:
|
||||
activeBranch: environments/qal-usw2
|
||||
activeCommitStatuses:
|
||||
- key: argocd-health
|
||||
autoMerge: true
|
||||
gitRepositoryRef:
|
||||
name: repo
|
||||
proposedBranch: environments/qal-usw2-next
|
||||
status:
|
||||
active:
|
||||
commitStatuses:
|
||||
- key: argocd-health
|
||||
phase: pending
|
||||
dry: {}
|
||||
hydrated:
|
||||
author: ServiceAccount
|
||||
commitTime: '2025-10-15T15:38:20Z'
|
||||
sha: b060fc7f5079a5aa7364a3844cfe26ee3084e282
|
||||
subject: '[Changed] - infrastructure deployment'
|
||||
conditions:
|
||||
- lastTransitionTime: '2025-10-15T17:34:14Z'
|
||||
message: 'PullRequest "deployment-environments-qal-usw2-next-environments-qal-usw2-7a8e7b70" is not Ready because "ReconciliationError": Reconciliation failed: failed to merge pull request: failed to merge pull request: failed to merge pull request: PUT https://github.example.com/api/v3/repos/org/deployment/pulls/3/merge: 405 At least 2 approving reviews are required by reviewers with write access. Required status check "continuous-integration/jenkins/pr-head" is expected. You''re not authorized to push to this branch.'
|
||||
observedGeneration: 1
|
||||
reason: PullRequestNotReady
|
||||
status: 'False'
|
||||
type: Ready
|
||||
history:
|
||||
- active:
|
||||
dry: {}
|
||||
hydrated:
|
||||
author: ServiceAccount
|
||||
commitTime: '2025-10-15T15:38:20Z'
|
||||
sha: b060fc7f5079a5aa7364a3844cfe26ee3084e282
|
||||
subject: '[Changed] - infrastructure deployment'
|
||||
proposed:
|
||||
hydrated: {}
|
||||
pullRequest: {}
|
||||
- active:
|
||||
dry: {}
|
||||
hydrated:
|
||||
author: ServiceAccount
|
||||
commitTime: '2025-10-15T15:15:27Z'
|
||||
sha: bb607f8854d83de1724bcc5515f685adf9d8a704
|
||||
subject: Initial commit
|
||||
proposed:
|
||||
hydrated: {}
|
||||
pullRequest: {}
|
||||
proposed:
|
||||
dry:
|
||||
author: user <user@example.com>
|
||||
commitTime: '2025-10-15T16:24:35Z'
|
||||
repoURL: https://github.example.com/org/deployment.git
|
||||
sha: ac7866685e376f32aaf09dced3cf2d39dc1ba50e
|
||||
subject: Create promotion-strategy.yaml
|
||||
hydrated:
|
||||
author: Argo CD
|
||||
body: 'Co-authored-by: user <user@example.com>'
|
||||
commitTime: '2025-10-15T16:26:18Z'
|
||||
sha: 2e8097c049a97c05e6f787f46aabfe3cc2a8af21
|
||||
subject: 'ac78666: Create promotion-strategy.yaml'
|
||||
pullRequest:
|
||||
id: '3'
|
||||
prCreationTime: '2025-10-15T17:11:53Z'
|
||||
state: open
|
||||
url: https://github.example.com/org/deployment/pull/3
|
||||
|
||||
@@ -25,17 +25,9 @@ if obj.status.conditions then
|
||||
hs.message = "Waiting for commit status spec update to be observed"
|
||||
return hs
|
||||
end
|
||||
-- Check for any False condition status
|
||||
if condition.status == "False" then
|
||||
if condition.status == "False" and condition.reason == "ReconciliationError" then
|
||||
hs.status = "Degraded"
|
||||
local msg = condition.message or "Unknown error"
|
||||
local reason = condition.reason or "Unknown"
|
||||
-- Don't include ReconciliationError in the message since it's redundant
|
||||
if reason == "ReconciliationError" then
|
||||
hs.message = "Commit status reconciliation failed: " .. msg
|
||||
else
|
||||
hs.message = "Commit status reconciliation failed (" .. reason .. "): " .. msg
|
||||
end
|
||||
hs.message = "Commit status reconciliation failed: " .. (condition.message or "Unknown error")
|
||||
return hs
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,10 +15,6 @@ tests:
|
||||
status: Degraded
|
||||
message: "Commit status reconciliation failed: Something went wrong"
|
||||
inputPath: testdata/reconcile-error.yaml
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: "Commit status reconciliation failed: Failed to update commit status: API request failed"
|
||||
inputPath: testdata/non-reconciliation-error.yaml
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: Commit status is not ready yet
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
apiVersion: promoter.argoproj.io/v1alpha1
|
||||
kind: CommitStatus
|
||||
metadata:
|
||||
name: test-commit-status
|
||||
namespace: test
|
||||
generation: 1
|
||||
spec:
|
||||
sha: abc1234567890
|
||||
url: https://example.com/ci/test
|
||||
gitRepositoryRef:
|
||||
name: repo
|
||||
description: example
|
||||
name: example
|
||||
phase: success
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: '2025-10-15T16:00:00Z'
|
||||
message: 'Failed to update commit status: API request failed'
|
||||
observedGeneration: 1
|
||||
reason: ReconciliationError
|
||||
status: 'False'
|
||||
type: Ready
|
||||
id: "1"
|
||||
sha: abc1234567890
|
||||
|
||||
@@ -26,17 +26,9 @@ if obj.status.conditions then
|
||||
hs.message = "Waiting for promotion strategy spec update to be observed"
|
||||
return hs
|
||||
end
|
||||
-- Check for any False condition status
|
||||
if condition.status == "False" then
|
||||
if condition.status == "False" and condition.reason == "ReconciliationError" then
|
||||
hs.status = "Degraded"
|
||||
local msg = condition.message or "Unknown error"
|
||||
local reason = condition.reason or "Unknown"
|
||||
-- Don't include ReconciliationError in the message since it's redundant
|
||||
if reason == "ReconciliationError" then
|
||||
hs.message = "Promotion strategy reconciliation failed: " .. msg
|
||||
else
|
||||
hs.message = "Promotion strategy reconciliation failed (" .. reason .. "): " .. msg
|
||||
end
|
||||
hs.message = "Promotion strategy reconciliation failed: " .. (condition.message or "Unknown error")
|
||||
return hs
|
||||
end
|
||||
end
|
||||
@@ -76,7 +68,7 @@ local proposedSha = obj.status.environments[1].proposed.dry.sha -- Don't panic,
|
||||
for _, env in ipairs(obj.status.environments) do
|
||||
if env.proposed.dry.sha ~= proposedSha then
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Not all environments have the same proposed commit SHA. This likely means the hydrator has not run for all environments yet."
|
||||
hs.status = "Not all environments have the same proposed commit SHA. This likely means the hydrator has not run for all environments yet."
|
||||
return hs
|
||||
end
|
||||
end
|
||||
|
||||
@@ -39,11 +39,3 @@ tests:
|
||||
status: Healthy
|
||||
message: All environments are up-to-date on commit 'abc1234'.
|
||||
inputPath: testdata/all-healthy.yaml
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: Not all environments have the same proposed commit SHA. This likely means the hydrator has not run for all environments yet.
|
||||
inputPath: testdata/different-proposed-commits.yaml
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: "Promotion strategy reconciliation failed (ChangeTransferPolicyNotReady): ChangeTransferPolicy \"strategy-environments-qal-usw2-27894e05\" is not Ready because \"ReconciliationError\": Reconciliation failed: failed to calculate ChangeTransferPolicy status: failed to get SHAs for proposed branch \"environments/qal-usw2-next\": exit status 128: fatal: 'origin/environments/qal-usw2-next' is not a commit and a branch 'environments/qal-usw2-next' cannot be created from it"
|
||||
inputPath: testdata/missing-sha-and-not-ready.yaml
|
||||
|
||||
@@ -1,412 +0,0 @@
|
||||
apiVersion: promoter.argoproj.io/v1alpha1
|
||||
kind: PromotionStrategy
|
||||
metadata:
|
||||
name: promotion-strategy
|
||||
namespace: gitops-promoter
|
||||
spec:
|
||||
activeCommitStatuses:
|
||||
- key: argocd-health
|
||||
environments:
|
||||
- autoMerge: false
|
||||
branch: wave/0/west
|
||||
- autoMerge: false
|
||||
branch: wave/1/west
|
||||
- autoMerge: false
|
||||
branch: wave/2/west
|
||||
- autoMerge: false
|
||||
branch: wave/3/west
|
||||
- autoMerge: false
|
||||
branch: wave/4/west
|
||||
- autoMerge: false
|
||||
branch: wave/5/west
|
||||
gitRepositoryRef:
|
||||
name: cdp-deployments
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: '2025-08-02T06:43:44Z'
|
||||
message: Reconciliation succeeded
|
||||
observedGeneration: 6
|
||||
reason: ReconciliationSuccess
|
||||
status: 'True'
|
||||
type: Ready
|
||||
environments:
|
||||
- active:
|
||||
commitStatuses:
|
||||
- key: argocd-health
|
||||
phase: pending
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-24T14:13:27Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: f94c9d42993145d9f10bb2c404b74da14ee3f74e
|
||||
subject: 'chore: fake new commit message'
|
||||
hydrated:
|
||||
author: GitOps Promoter
|
||||
commitTime: '2025-09-24T14:14:21Z'
|
||||
sha: 6b1095752ea7bef9c5c4251cb0722ce33dfd68d1
|
||||
subject: >-
|
||||
This is a no-op commit merging from wave/0/west-next into
|
||||
wave/0/west
|
||||
branch: wave/0/west
|
||||
history:
|
||||
- active:
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-23T17:33:12Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: 28f351384c8b8e58624726c4c3713979d0143775
|
||||
subject: 'chore: fake old commit message'
|
||||
hydrated:
|
||||
author: argo-cd[bot]
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-23T17:36:40Z'
|
||||
sha: 3ebd45b702bc23619c8ae6724e81955afc644555
|
||||
subject: Promote 28f35 to `wave/0/west` (#2929)
|
||||
proposed:
|
||||
hydrated: {}
|
||||
pullRequest: {}
|
||||
- active:
|
||||
dry:
|
||||
author: asingh51 <fake@example.com>
|
||||
commitTime: '2025-09-22T21:04:40Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: 9dc9529ddba077fcdf8cffef716b7d20e1e8b844
|
||||
subject: >-
|
||||
Onboarding new cluster to argocd-genai on wave 5 [ARGO-2499]
|
||||
(#2921)
|
||||
hydrated:
|
||||
author: argo-cd[bot]
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-22T21:56:33Z'
|
||||
sha: 2fefa5165e46988666cbb1d2d4f39e21871fa671
|
||||
subject: Promote 9dc95 to `wave/0/west` (#2925)
|
||||
proposed:
|
||||
hydrated: {}
|
||||
pullRequest: {}
|
||||
- active:
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-22T19:29:53Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: 7f91282cc8146644d0721efde1b9069ccbd475a1
|
||||
subject: >-
|
||||
chore: temporarily disable server-side diff on argo-argo
|
||||
(ARGO-2528) (#2917)
|
||||
hydrated:
|
||||
author: argo-cd[bot]
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-22T19:32:09Z'
|
||||
sha: 6c6493caa0d5b7211bb09c93a7047c90db393cd6
|
||||
subject: Promote 7f912 to `wave/0/west` (#2922)
|
||||
proposed:
|
||||
hydrated: {}
|
||||
pullRequest: {}
|
||||
proposed:
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-24T14:13:27Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: f94c9d42993145d9f10bb2c404b74da14ee3f74e
|
||||
subject: 'chore: fake new commit message'
|
||||
hydrated:
|
||||
author: GitOps Promoter
|
||||
commitTime: '2025-09-24T14:14:16Z'
|
||||
sha: 9dfd6245b7b2e86660a13743ecc85d26bf3df04c
|
||||
subject: Merge branch 'wave/0/west' into wave/0/west-next
|
||||
- active:
|
||||
commitStatuses:
|
||||
- key: argocd-health
|
||||
phase: pending
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-24T14:13:27Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: f94c9d42993145d9f10bb2c404b74da14ee3f74e
|
||||
subject: 'chore: fake new commit message'
|
||||
hydrated:
|
||||
author: GitOps Promoter
|
||||
commitTime: '2025-09-24T14:14:01Z'
|
||||
sha: 580bbde2b775a8c6dc1484c4ba970426029e63b4
|
||||
subject: >-
|
||||
This is a no-op commit merging from wave/1/west-next into
|
||||
wave/1/west
|
||||
branch: wave/1/west
|
||||
history:
|
||||
- active:
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-23T17:33:12Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: 28f351384c8b8e58624726c4c3713979d0143775
|
||||
subject: 'chore: fake old commit message'
|
||||
hydrated:
|
||||
author: argo-cd[bot]
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-23T17:37:46Z'
|
||||
sha: c2b69cd2186df736ee4e27a6de5590135a3c5823
|
||||
subject: Promote 28f35 to `wave/1/west` (#2928)
|
||||
proposed:
|
||||
hydrated: {}
|
||||
pullRequest: {}
|
||||
- active:
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-22T19:29:53Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: 7f91282cc8146644d0721efde1b9069ccbd475a1
|
||||
subject: >-
|
||||
chore: temporarily disable server-side diff on argo-argo
|
||||
(ARGO-2528) (#2917)
|
||||
hydrated:
|
||||
author: argo-cd[bot]
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-22T20:15:13Z'
|
||||
sha: baf2f21f5085adaa7fe4720ca41d4f7ff918d4fd
|
||||
subject: Promote 7f912 to `wave/1/west` (#2883)
|
||||
proposed:
|
||||
hydrated: {}
|
||||
pullRequest: {}
|
||||
- active:
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-16T16:32:32Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: 789df516a84b1d3beb2f8ffe56e052b5b411aa74
|
||||
subject: >-
|
||||
chore: upgrade to 3.2.0-rc1, argo and team instances (ARGO-2412)
|
||||
(#2875)
|
||||
hydrated:
|
||||
author: argo-cd[bot]
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-16T16:45:40Z'
|
||||
sha: 728e1a237732a20281f986916301a5dca254e3a4
|
||||
subject: Promote 789df to `wave/1/west` (#2876)
|
||||
proposed:
|
||||
hydrated: {}
|
||||
pullRequest: {}
|
||||
proposed:
|
||||
commitStatuses:
|
||||
- key: promoter-previous-environment
|
||||
phase: pending
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-24T14:13:27Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: f94c9d42993145d9f10bb2c404b74da14ee3f74e
|
||||
subject: 'chore: fake new commit message'
|
||||
hydrated:
|
||||
author: GitOps Promoter
|
||||
commitTime: '2025-09-24T14:13:56Z'
|
||||
sha: 50b7c73718813b9b92a0e1e166798cbd55874bbd
|
||||
subject: Merge branch 'wave/1/west' into wave/1/west-next
|
||||
- active:
|
||||
commitStatuses:
|
||||
- key: argocd-health
|
||||
phase: pending
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-23T17:33:12Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: 28f351384c8b8e58624726c4c3713979d0143775
|
||||
subject: 'chore: fake old commit message'
|
||||
hydrated:
|
||||
author: GitOps Promoter
|
||||
commitTime: '2025-09-23T17:34:05Z'
|
||||
sha: 169626417d1863434901c9225ded78963b7bd691
|
||||
subject: >-
|
||||
This is a no-op commit merging from wave/2/west-next into
|
||||
wave/2/west
|
||||
branch: wave/2/west
|
||||
history:
|
||||
- active:
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-22T19:29:53Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: 7f91282cc8146644d0721efde1b9069ccbd475a1
|
||||
subject: >-
|
||||
chore: temporarily disable server-side diff on argo-argo
|
||||
(ARGO-2528) (#2917)
|
||||
hydrated:
|
||||
author: argo-cd[bot]
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-22T20:59:45Z'
|
||||
sha: 1bfe993b41fe27b298c0aab9a5f185b29a478178
|
||||
subject: Promote 7f912 to `wave/2/west` (#2884)
|
||||
proposed:
|
||||
hydrated: {}
|
||||
pullRequest: {}
|
||||
proposed:
|
||||
commitStatuses:
|
||||
- key: promoter-previous-environment
|
||||
phase: pending
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-23T17:33:12Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: 28f351384c8b8e58624726c4c3713979d0143775
|
||||
subject: 'chore: fake old commit message'
|
||||
hydrated:
|
||||
author: Argo CD
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-23T17:33:50Z'
|
||||
sha: 6e0e11f0102faa5779223159a2b16ccee63a8ac0
|
||||
subject: '28f3513: chore: fake old commit message'
|
||||
- active:
|
||||
commitStatuses:
|
||||
- key: argocd-health
|
||||
phase: pending
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-24T14:13:27Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: f94c9d42993145d9f10bb2c404b74da14ee3f74e
|
||||
subject: 'chore: fake new commit message'
|
||||
hydrated:
|
||||
author: GitOps Promoter
|
||||
commitTime: '2025-09-24T14:14:08Z'
|
||||
sha: 73cf41db84a6e97a74c967243e65ffce66dd4198
|
||||
subject: >-
|
||||
This is a no-op commit merging from wave/3/west-next into
|
||||
wave/3/west
|
||||
branch: wave/3/west
|
||||
history:
|
||||
- active:
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-22T19:29:53Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: 7f91282cc8146644d0721efde1b9069ccbd475a1
|
||||
subject: >-
|
||||
chore: fake super old commit message
|
||||
hydrated:
|
||||
author: argo-cd[bot]
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-22T21:00:07Z'
|
||||
sha: e7456f8ff4a5943ace3bb425e2d4e7dd43a53e46
|
||||
subject: Promote 7f912 to `wave/3/west` (#2887)
|
||||
proposed:
|
||||
hydrated: {}
|
||||
pullRequest: {}
|
||||
proposed:
|
||||
commitStatuses:
|
||||
- key: promoter-previous-environment
|
||||
phase: pending
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-24T14:13:27Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: f94c9d42993145d9f10bb2c404b74da14ee3f74e
|
||||
subject: 'chore: fake new commit message'
|
||||
hydrated:
|
||||
author: Argo CD
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-24T14:13:49Z'
|
||||
sha: daf0534e9db36334c82870cbb2e5d14cc687e0f5
|
||||
subject: 'f94c9d4: chore: fake new commit message'
|
||||
- active:
|
||||
commitStatuses:
|
||||
- key: argocd-health
|
||||
phase: pending
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-24T14:13:27Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: f94c9d42993145d9f10bb2c404b74da14ee3f74e
|
||||
subject: 'chore: fake new commit message'
|
||||
hydrated:
|
||||
author: GitOps Promoter
|
||||
commitTime: '2025-09-24T14:14:30Z'
|
||||
sha: 5abc8f1fd4056ad9f78723f3a83ac2291e87c821
|
||||
subject: >-
|
||||
This is a no-op commit merging from wave/4/west-next into
|
||||
wave/4/west
|
||||
branch: wave/4/west
|
||||
history:
|
||||
- active:
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-22T19:29:53Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: 7f91282cc8146644d0721efde1b9069ccbd475a1
|
||||
subject: >-
|
||||
chore: temporarily disable server-side diff on argo-argo
|
||||
(ARGO-2528) (#2917)
|
||||
hydrated:
|
||||
author: argo-cd[bot]
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-22T21:00:29Z'
|
||||
sha: 1d6e2b279108f6430825c889f6d2248fe4388aba
|
||||
subject: Promote 7f912 to `wave/4/west` (#2885)
|
||||
proposed:
|
||||
hydrated: {}
|
||||
pullRequest: {}
|
||||
proposed:
|
||||
commitStatuses:
|
||||
- key: promoter-previous-environment
|
||||
phase: pending
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-24T14:13:27Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: f94c9d42993145d9f10bb2c404b74da14ee3f74e
|
||||
subject: 'chore: fake new commit message'
|
||||
hydrated:
|
||||
author: Argo CD
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-24T14:14:09Z'
|
||||
sha: 91d942a1da3799d6027a7c407eee98b1f9cdcde0
|
||||
subject: 'f94c9d4: chore: fake new commit message'
|
||||
- active:
|
||||
commitStatuses:
|
||||
- key: argocd-health
|
||||
phase: pending
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-24T14:13:27Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: f94c9d42993145d9f10bb2c404b74da14ee3f74e
|
||||
subject: 'chore: fake new commit message'
|
||||
hydrated:
|
||||
author: GitOps Promoter
|
||||
commitTime: '2025-09-24T14:14:40Z'
|
||||
sha: 7bee0fcb985ac4ecccddf70a8b2d02cc0c41f231
|
||||
subject: >-
|
||||
This is a no-op commit merging from wave/5/west-next into
|
||||
wave/5/west
|
||||
branch: wave/5/west
|
||||
history:
|
||||
- active:
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-22T19:29:53Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: 7f91282cc8146644d0721efde1b9069ccbd475a1
|
||||
subject: >-
|
||||
chore: temporarily disable server-side diff on argo-argo
|
||||
(ARGO-2528) (#2917)
|
||||
hydrated:
|
||||
author: argo-cd[bot]
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-22T21:00:59Z'
|
||||
sha: a9d26ef79a1cc786a2a90446f7e8bbef2e5be653
|
||||
subject: Promote 7f912 to `wave/5/west` (#2888)
|
||||
proposed:
|
||||
hydrated: {}
|
||||
pullRequest: {}
|
||||
proposed:
|
||||
commitStatuses:
|
||||
- key: promoter-previous-environment
|
||||
phase: pending
|
||||
dry:
|
||||
author: Fake Person <fake@example.com>
|
||||
commitTime: '2025-09-24T14:13:27Z'
|
||||
repoURL: https://git.example.com/fake-org/fake-repo
|
||||
sha: f94c9d42993145d9f10bb2c404b74da14ee3f74e
|
||||
subject: 'chore: fake new commit message'
|
||||
hydrated:
|
||||
author: Argo CD
|
||||
body: "Fake commit message"
|
||||
commitTime: '2025-09-24T14:14:24Z'
|
||||
sha: 20c41602695addbf7760236eff562f5692e585aa
|
||||
subject: 'f94c9d4: chore: fake new commit message'
|
||||
@@ -1,38 +0,0 @@
|
||||
apiVersion: promoter.argoproj.io/v1alpha1
|
||||
kind: PromotionStrategy
|
||||
metadata:
|
||||
name: strategy
|
||||
namespace: test
|
||||
spec:
|
||||
activeCommitStatuses:
|
||||
- key: argocd-health
|
||||
environments:
|
||||
- autoMerge: true
|
||||
branch: environments/qal-usw2
|
||||
- autoMerge: true
|
||||
branch: environments/e2e-usw2
|
||||
gitRepositoryRef:
|
||||
name: repo
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: '2025-10-15T16:31:47Z'
|
||||
message: 'ChangeTransferPolicy "strategy-environments-qal-usw2-27894e05" is not Ready because "ReconciliationError": Reconciliation failed: failed to calculate ChangeTransferPolicy status: failed to get SHAs for proposed branch "environments/qal-usw2-next": exit status 128: fatal: ''origin/environments/qal-usw2-next'' is not a commit and a branch ''environments/qal-usw2-next'' cannot be created from it'
|
||||
observedGeneration: 1
|
||||
reason: ChangeTransferPolicyNotReady
|
||||
status: 'False'
|
||||
type: Ready
|
||||
environments:
|
||||
- active:
|
||||
dry: {}
|
||||
hydrated: {}
|
||||
branch: environments/qal-usw2
|
||||
proposed:
|
||||
dry: {}
|
||||
hydrated: {}
|
||||
- active:
|
||||
dry: {}
|
||||
hydrated: {}
|
||||
branch: environments/e2e-usw2
|
||||
proposed:
|
||||
dry: {}
|
||||
hydrated: {}
|
||||
@@ -26,16 +26,9 @@ if obj.status.conditions then
|
||||
hs.message = "Waiting for pull request spec update to be observed"
|
||||
return hs
|
||||
end
|
||||
if condition.status == "False" then
|
||||
if condition.status == "False" and (condition.reason == "ReconcileError" or condition.reason == "Failed") then
|
||||
hs.status = "Degraded"
|
||||
local msg = condition.message or "Unknown error"
|
||||
local reason = condition.reason or "Unknown"
|
||||
-- Don't include ReconciliationError in the message since it's redundant
|
||||
if reason == "ReconciliationError" then
|
||||
hs.message = "Pull request reconciliation failed: " .. msg
|
||||
else
|
||||
hs.message = "Pull request reconciliation failed (" .. reason .. "): " .. msg
|
||||
end
|
||||
hs.message = "Pull request reconciliation failed: " .. (condition.message or "Unknown error")
|
||||
return hs
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,11 +14,7 @@ tests:
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: "Pull request reconciliation failed: Something went wrong"
|
||||
inputPath: testdata/reconciliation-error.yaml
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: "Pull request reconciliation failed: Failed to create pull request: authentication failed"
|
||||
inputPath: testdata/non-reconciliation-error.yaml
|
||||
inputPath: testdata/reconcile-error.yaml
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: Pull request is not ready yet
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
apiVersion: promoter.argoproj.io/v1alpha1
|
||||
kind: PullRequest
|
||||
metadata:
|
||||
name: test-pr
|
||||
namespace: test
|
||||
generation: 1
|
||||
spec:
|
||||
sourceBranch: app-next
|
||||
targetBranch: app
|
||||
gitRepositoryRef:
|
||||
name: repo
|
||||
title: Test Pull Request
|
||||
state: open
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: '2025-10-15T16:00:00Z'
|
||||
message: 'Failed to create pull request: authentication failed'
|
||||
observedGeneration: 1
|
||||
reason: ReconciliationError
|
||||
status: 'False'
|
||||
type: Ready
|
||||
|
||||
@@ -7,7 +7,7 @@ status:
|
||||
conditions:
|
||||
- type: Ready
|
||||
status: "False"
|
||||
reason: ReconciliationError
|
||||
reason: ReconcileError
|
||||
message: Something went wrong
|
||||
observedGeneration: 2
|
||||
|
||||
@@ -774,8 +774,9 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*v1a
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.inferResourcesStatusHealth(a)
|
||||
|
||||
if q.Refresh == nil {
|
||||
s.inferResourcesStatusHealth(a)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
@@ -854,9 +855,7 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*v1a
|
||||
annotations = make(map[string]string)
|
||||
}
|
||||
if _, ok := annotations[v1alpha1.AnnotationKeyRefresh]; !ok {
|
||||
refreshedApp := event.Application.DeepCopy()
|
||||
s.inferResourcesStatusHealth(refreshedApp)
|
||||
return refreshedApp, nil
|
||||
return event.Application.DeepCopy(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2711,99 +2711,6 @@ func TestGetAppRefresh_HardRefresh(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetApp_HealthStatusPropagation(t *testing.T) {
|
||||
newServerWithTree := func(t *testing.T) (*Server, *v1alpha1.Application) {
|
||||
t.Helper()
|
||||
cacheClient := cache.NewCache(cache.NewInMemoryCache(1 * time.Hour))
|
||||
|
||||
testApp := newTestApp()
|
||||
testApp.Status.ResourceHealthSource = v1alpha1.ResourceHealthLocationAppTree
|
||||
testApp.Status.Resources = []v1alpha1.ResourceStatus{
|
||||
{
|
||||
Group: "apps",
|
||||
Kind: "Deployment",
|
||||
Name: "guestbook",
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
|
||||
appServer := newTestAppServer(t, testApp)
|
||||
|
||||
appStateCache := appstate.NewCache(cacheClient, time.Minute)
|
||||
appInstanceName := testApp.InstanceName(appServer.appNamespaceOrDefault(testApp.Namespace))
|
||||
err := appStateCache.SetAppResourcesTree(appInstanceName, &v1alpha1.ApplicationTree{
|
||||
Nodes: []v1alpha1.ResourceNode{{
|
||||
ResourceRef: v1alpha1.ResourceRef{
|
||||
Group: "apps",
|
||||
Kind: "Deployment",
|
||||
Name: "guestbook",
|
||||
Namespace: "default",
|
||||
},
|
||||
Health: &v1alpha1.HealthStatus{Status: health.HealthStatusDegraded},
|
||||
}},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
appServer.cache = servercache.NewCache(appStateCache, time.Minute, time.Minute)
|
||||
|
||||
return appServer, testApp
|
||||
}
|
||||
|
||||
t.Run("propagated health status on get with no refresh", func(t *testing.T) {
|
||||
appServer, testApp := newServerWithTree(t)
|
||||
fetchedApp, err := appServer.Get(t.Context(), &application.ApplicationQuery{
|
||||
Name: &testApp.Name,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, health.HealthStatusDegraded, fetchedApp.Status.Resources[0].Health.Status)
|
||||
})
|
||||
|
||||
t.Run("propagated health status on normal refresh", func(t *testing.T) {
|
||||
appServer, testApp := newServerWithTree(t)
|
||||
var patched int32
|
||||
ch := make(chan string, 1)
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
go refreshAnnotationRemover(t, ctx, &patched, appServer, testApp.Name, ch)
|
||||
|
||||
fetchedApp, err := appServer.Get(t.Context(), &application.ApplicationQuery{
|
||||
Name: &testApp.Name,
|
||||
Refresh: ptr.To(string(v1alpha1.RefreshTypeNormal)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
assert.Equal(t, int32(1), atomic.LoadInt32(&patched))
|
||||
case <-time.After(10 * time.Second):
|
||||
assert.Fail(t, "Out of time ( 10 seconds )")
|
||||
}
|
||||
assert.Equal(t, health.HealthStatusDegraded, fetchedApp.Status.Resources[0].Health.Status)
|
||||
})
|
||||
|
||||
t.Run("propagated health status on hard refresh", func(t *testing.T) {
|
||||
appServer, testApp := newServerWithTree(t)
|
||||
var patched int32
|
||||
ch := make(chan string, 1)
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
go refreshAnnotationRemover(t, ctx, &patched, appServer, testApp.Name, ch)
|
||||
|
||||
fetchedApp, err := appServer.Get(t.Context(), &application.ApplicationQuery{
|
||||
Name: &testApp.Name,
|
||||
Refresh: ptr.To(string(v1alpha1.RefreshTypeHard)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
assert.Equal(t, int32(1), atomic.LoadInt32(&patched))
|
||||
case <-time.After(10 * time.Second):
|
||||
assert.Fail(t, "Out of time ( 10 seconds )")
|
||||
}
|
||||
assert.Equal(t, health.HealthStatusDegraded, fetchedApp.Status.Resources[0].Health.Status)
|
||||
})
|
||||
}
|
||||
|
||||
func TestInferResourcesStatusHealth(t *testing.T) {
|
||||
cacheClient := cache.NewCache(cache.NewInMemoryCache(1 * time.Hour))
|
||||
|
||||
|
||||
@@ -1257,7 +1257,7 @@ func (server *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWeb
|
||||
|
||||
// Webhook handler for git events (Note: cache timeouts are hardcoded because API server does not write to cache and not really using them)
|
||||
argoDB := db.NewDB(server.Namespace, server.settingsMgr, server.KubeClientset)
|
||||
acdWebhookHandler := webhook.NewHandler(server.Namespace, server.ApplicationNamespaces, server.WebhookParallelism, server.AppClientset, server.appLister, server.settings, server.settingsMgr, server.RepoServerCache, server.Cache, argoDB, server.settingsMgr.GetMaxWebhookPayloadSize())
|
||||
acdWebhookHandler := webhook.NewHandler(server.Namespace, server.ApplicationNamespaces, server.WebhookParallelism, server.AppClientset, server.settings, server.settingsMgr, server.RepoServerCache, server.Cache, argoDB, server.settingsMgr.GetMaxWebhookPayloadSize())
|
||||
|
||||
mux.HandleFunc("/api/webhook", acdWebhookHandler.Handler)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM docker.io/library/node:23.0.0@sha256:e643c0b70dca9704dff42e12b17f5b719dbe4f95e6392fc2dfa0c5f02ea8044d as node
|
||||
FROM docker.io/library/node:23.11.1@sha256:9a25b5a6f9a90218b73a62205f111e71de5e4289aee952b4dd7e86f7498f2544 as node
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
software-properties-common
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
"resolutions": {
|
||||
"@types/react": "^16.9.3",
|
||||
"@types/react-dom": "^16.8.2",
|
||||
"normalize-url": "4.3.0",
|
||||
"normalize-url": "4.5.1",
|
||||
"rxjs": "6.6.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
&__conditions {
|
||||
display: flex;
|
||||
max-width: 250px;
|
||||
margin: auto;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
line-height: 1.5em;
|
||||
@@ -98,10 +97,6 @@
|
||||
@include responsive-widths();
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
@include themify($themes) {
|
||||
border-left: 1px solid themed('border');
|
||||
@@ -139,7 +134,7 @@
|
||||
|
||||
&__item-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: baseline;
|
||||
margin-bottom: 0.5em;
|
||||
font-weight: 500;
|
||||
padding: 2px 0px;
|
||||
|
||||
@@ -39,15 +39,19 @@ interface SectionInfo {
|
||||
}
|
||||
|
||||
const sectionLabel = (info: SectionInfo) => (
|
||||
<label style={{fontSize: '12px', fontWeight: 600, color: ARGO_GRAY6_COLOR}}>
|
||||
<label style={{display: 'flex', alignItems: 'flex-start', fontSize: '12px', fontWeight: 600, color: ARGO_GRAY6_COLOR, minHeight: '18px'}}>
|
||||
{info.title}
|
||||
{info.helpContent && <HelpIcon title={info.helpContent} />}
|
||||
{info.helpContent && (
|
||||
<span style={{marginLeft: '5px'}}>
|
||||
<HelpIcon title={info.helpContent} />
|
||||
</span>
|
||||
)}
|
||||
</label>
|
||||
);
|
||||
|
||||
const sectionHeader = (info: SectionInfo, onClick?: () => any) => {
|
||||
return (
|
||||
<div style={{display: 'flex', alignItems: 'center', marginBottom: '0.5em'}}>
|
||||
<div style={{display: 'flex', alignItems: 'center'}}>
|
||||
{sectionLabel(info)}
|
||||
{onClick && (
|
||||
<button className='argo-button application-status-panel__more-button' onClick={onClick}>
|
||||
@@ -58,12 +62,16 @@ const sectionHeader = (info: SectionInfo, onClick?: () => any) => {
|
||||
);
|
||||
};
|
||||
|
||||
const getApplicationSetOwnerRef = (application: models.Application) => {
|
||||
return application.metadata.ownerReferences?.find(ref => ref.kind === 'ApplicationSet');
|
||||
const hasRollingSyncEnabled = (application: models.Application): boolean => {
|
||||
return application.metadata.ownerReferences?.some(ref => ref.kind === 'ApplicationSet') || false;
|
||||
};
|
||||
|
||||
const ProgressiveSyncStatus = ({application}: {application: models.Application}) => {
|
||||
const appSetRef = getApplicationSetOwnerRef(application);
|
||||
if (!hasRollingSyncEnabled(application)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const appSetRef = application.metadata.ownerReferences.find(ref => ref.kind === 'ApplicationSet');
|
||||
if (!appSetRef) {
|
||||
return null;
|
||||
}
|
||||
@@ -71,39 +79,12 @@ const ProgressiveSyncStatus = ({application}: {application: models.Application})
|
||||
return (
|
||||
<DataLoader
|
||||
input={application}
|
||||
errorRenderer={() => {
|
||||
// For any errors, show a minimal error state
|
||||
return (
|
||||
<div className='application-status-panel__item'>
|
||||
{sectionHeader({
|
||||
title: 'PROGRESSIVE SYNC',
|
||||
helpContent: 'Shows the current status of progressive sync for applications managed by an ApplicationSet.'
|
||||
})}
|
||||
<div className='application-status-panel__item-value'>
|
||||
<i className='fa fa-exclamation-triangle' style={{color: COLORS.sync.unknown}} /> Error
|
||||
</div>
|
||||
<div className='application-status-panel__item-name'>Unable to load Progressive Sync status</div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
load={async () => {
|
||||
// Find ApplicationSet by searching all namespaces dynamically
|
||||
const appSetList = await services.applications.listApplicationSets();
|
||||
const appSet = appSetList.items?.find(item => item.metadata.name === appSetRef.name);
|
||||
|
||||
return {appSet};
|
||||
const appSet = await services.applications.getApplicationSet(appSetRef.name, application.metadata.namespace);
|
||||
return appSet?.spec?.strategy?.type === 'RollingSync' ? appSet : null;
|
||||
}}>
|
||||
{({appSet}: {appSet: models.ApplicationSet}) => {
|
||||
// Hide panel if: Progressive Sync disabled, no permission, or not RollingSync strategy
|
||||
if (!appSet || !appSet.status?.applicationStatus || appSet?.spec?.strategy?.type !== 'RollingSync') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the current application's status from the ApplicationSet applicationStatus
|
||||
const appResource = appSet.status?.applicationStatus?.find(status => status.application === application.metadata.name);
|
||||
|
||||
// If no application status is found, show a default status
|
||||
if (!appResource) {
|
||||
{(appSet: models.ApplicationSet) => {
|
||||
if (!appSet) {
|
||||
return (
|
||||
<div className='application-status-panel__item'>
|
||||
{sectionHeader({
|
||||
@@ -111,15 +92,14 @@ const ProgressiveSyncStatus = ({application}: {application: models.Application})
|
||||
helpContent: 'Shows the current status of progressive sync for applications managed by an ApplicationSet with RollingSync strategy.'
|
||||
})}
|
||||
<div className='application-status-panel__item-value'>
|
||||
<i className='fa fa-clock' style={{color: COLORS.sync.out_of_sync}} /> Waiting
|
||||
<i className='fa fa-question-circle' style={{color: COLORS.sync.unknown}} /> Unknown
|
||||
</div>
|
||||
<div className='application-status-panel__item-name'>Application status not yet available from ApplicationSet</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Get last transition time from application status
|
||||
const lastTransitionTime = appResource?.lastTransitionTime;
|
||||
// Get the current application's status from the ApplicationSet resources
|
||||
const appResource = appSet.status?.applicationStatus?.find(status => status.application === application.metadata.name);
|
||||
|
||||
return (
|
||||
<div className='application-status-panel__item'>
|
||||
@@ -130,14 +110,12 @@ const ProgressiveSyncStatus = ({application}: {application: models.Application})
|
||||
<div className='application-status-panel__item-value' style={{color: getProgressiveSyncStatusColor(appResource.status)}}>
|
||||
{getProgressiveSyncStatusIcon({status: appResource.status})} {appResource.status}
|
||||
</div>
|
||||
{appResource?.step && <div className='application-status-panel__item-value'>Wave: {appResource.step}</div>}
|
||||
{lastTransitionTime && (
|
||||
<div className='application-status-panel__item-name' style={{marginBottom: '0.5em'}}>
|
||||
Last Transition: <br />
|
||||
<Timestamp date={lastTransitionTime} />
|
||||
</div>
|
||||
)}
|
||||
{appResource?.message && <div className='application-status-panel__item-name'>{appResource.message}</div>}
|
||||
<div className='application-status-panel__item-value'>Wave: {appResource.step}</div>
|
||||
<div className='application-status-panel__item-name' style={{marginBottom: '0.5em'}}>
|
||||
Last Transition: <br />
|
||||
<Timestamp date={appResource.lastTransitionTime} />
|
||||
</div>
|
||||
{appResource.message && <div className='application-status-panel__item-name'>{appResource.message}</div>}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
@@ -149,9 +127,7 @@ export const ApplicationStatusPanel = ({application, showDiff, showOperation, sh
|
||||
const [showProgressiveSync, setShowProgressiveSync] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
// Only show Progressive Sync if the application has an ApplicationSet parent
|
||||
// The actual strategy validation will be done inside ProgressiveSyncStatus component
|
||||
setShowProgressiveSync(!!getApplicationSetOwnerRef(application));
|
||||
setShowProgressiveSync(hasRollingSyncEnabled(application));
|
||||
}, [application]);
|
||||
|
||||
const today = new Date();
|
||||
@@ -184,7 +160,7 @@ export const ApplicationStatusPanel = ({application, showDiff, showOperation, sh
|
||||
return (
|
||||
<div className='application-status-panel row'>
|
||||
<div className='application-status-panel__item'>
|
||||
<div style={{lineHeight: '19.5px', marginBottom: '0.3em'}}>{sectionLabel({title: 'APP HEALTH', helpContent: 'The health status of your app'})}</div>
|
||||
{sectionHeader({title: 'APP HEALTH', helpContent: 'The health status of your app'})}
|
||||
<div className='application-status-panel__item-value'>
|
||||
<HealthStatusIcon state={application.status.health} />
|
||||
|
||||
@@ -310,7 +286,7 @@ export const ApplicationStatusPanel = ({application, showDiff, showOperation, sh
|
||||
)}
|
||||
{application.status.conditions && (
|
||||
<div className={`application-status-panel__item`}>
|
||||
{sectionLabel({title: 'APP CONDITIONS'})}
|
||||
{sectionHeader({title: 'APP CONDITIONS'})}
|
||||
<div className='application-status-panel__item-value application-status-panel__conditions' onClick={() => showConditions && showConditions()}>
|
||||
{infos && (
|
||||
<a className='info'>
|
||||
|
||||
@@ -60,13 +60,3 @@ i.utils-health-status-icon {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.delete-dialog-icon {
|
||||
&.warning {
|
||||
color: #f4c030;
|
||||
}
|
||||
|
||||
&.info {
|
||||
color: #0DADEA;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,18 +65,8 @@ export const SpinningIcon = ({color, qeId}: {color: string; qeId: string}) => {
|
||||
);
|
||||
};
|
||||
|
||||
export async function deleteApplication(appName: string, appNamespace: string, apis: ContextApis, application?: appModels.Application): Promise<boolean> {
|
||||
export async function deleteApplication(appName: string, appNamespace: string, apis: ContextApis): Promise<boolean> {
|
||||
let confirmed = false;
|
||||
|
||||
// Use common child application detection logic if application object is provided
|
||||
const isChildApp = application ? isChildApplication(application) : false;
|
||||
const dialogTitle = isChildApp ? 'Delete child application' : 'Delete application';
|
||||
const appType = isChildApp ? 'child Application' : 'Application';
|
||||
const confirmLabel = isChildApp ? 'child application' : 'application';
|
||||
|
||||
// Check if this is being called from resource tree context
|
||||
const isFromResourceTree = application !== undefined;
|
||||
|
||||
const propagationPolicies: {name: string; message: string}[] = [
|
||||
{
|
||||
name: 'Foreground',
|
||||
@@ -92,27 +82,18 @@ export async function deleteApplication(appName: string, appNamespace: string, a
|
||||
}
|
||||
];
|
||||
await apis.popup.prompt(
|
||||
dialogTitle,
|
||||
'Delete application',
|
||||
api => (
|
||||
<div>
|
||||
<p>
|
||||
Are you sure you want to delete the <strong>{appType}</strong> <kbd>{appName}</kbd>?
|
||||
</p>
|
||||
{isFromResourceTree && (
|
||||
<p>
|
||||
<strong>
|
||||
<i className='fa fa-warning delete-dialog-icon warning' /> Note:
|
||||
</strong>{' '}
|
||||
You are about to delete an Application from the resource tree. This uses the same deletion behavior as the Applications list page.
|
||||
</p>
|
||||
)}
|
||||
<p>
|
||||
Are you sure you want to delete the <strong>Application</strong> <kbd>{appName}</kbd>?
|
||||
<span style={{display: 'block', marginBottom: '10px'}} />
|
||||
Deleting the application in <kbd>foreground</kbd> or <kbd>background</kbd> mode will delete all the application's managed resources, which can be{' '}
|
||||
<strong>dangerous</strong>. Be sure you understand the effects of deleting this resource before continuing. Consider asking someone to review the change first.
|
||||
</p>
|
||||
<div className='argo-form-row'>
|
||||
<FormField
|
||||
label={`Please type '${appName}' to confirm the deletion of the ${confirmLabel}`}
|
||||
label={`Please type '${appName}' to confirm the deletion of the resource`}
|
||||
formApi={api}
|
||||
field='applicationName'
|
||||
qeId='name-field-delete-confirmation'
|
||||
@@ -454,17 +435,6 @@ export const deleteSourceAction = (app: appModels.Application, source: appModels
|
||||
);
|
||||
};
|
||||
|
||||
// Detect if a resource is an Application
|
||||
const isApplicationResource = (resource: ResourceTreeNode): boolean => {
|
||||
return resource.kind === 'Application' && resource.group === 'argoproj.io';
|
||||
};
|
||||
|
||||
// Detect if an application is a child application
|
||||
const isChildApplication = (application: appModels.Application): boolean => {
|
||||
const partOfLabel = application.metadata.labels?.['app.kubernetes.io/part-of'];
|
||||
return partOfLabel && partOfLabel.trim() !== '';
|
||||
};
|
||||
|
||||
export const deletePopup = async (
|
||||
ctx: ContextApis,
|
||||
resource: ResourceTreeNode,
|
||||
@@ -473,17 +443,6 @@ export const deletePopup = async (
|
||||
childResources: appModels.ResourceNode[],
|
||||
appChanged?: BehaviorSubject<appModels.Application>
|
||||
) => {
|
||||
// Detect if this is an Application resource
|
||||
const isApplication = isApplicationResource(resource);
|
||||
|
||||
// Check if we're in a parent-child context (used for both Application and non-Application resources)
|
||||
const isInParentContext = isChildApplication(application);
|
||||
|
||||
// For Application resources, use the deleteApplication function with resource tree context
|
||||
if (isApplication) {
|
||||
return deleteApplication(resource.name, resource.namespace || '', ctx, application);
|
||||
}
|
||||
|
||||
const deleteOptions = {
|
||||
option: 'foreground'
|
||||
};
|
||||
@@ -495,31 +454,13 @@ export const deletePopup = async (
|
||||
return deletePodAction(ctx, resource, application);
|
||||
}
|
||||
|
||||
// Determine dialog title and add custom messaging
|
||||
const dialogTitle = 'Delete resource';
|
||||
let customMessage: React.ReactNode = null;
|
||||
|
||||
if (isInParentContext) {
|
||||
customMessage = (
|
||||
<div>
|
||||
<p>
|
||||
<strong>
|
||||
<i className='fa fa-exclamation-triangle delete-dialog-icon info' /> Note:
|
||||
</strong>{' '}
|
||||
You are about to delete a resource from a parent application's resource tree.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return ctx.popup.prompt(
|
||||
dialogTitle,
|
||||
'Delete resource',
|
||||
api => (
|
||||
<div>
|
||||
<p>
|
||||
Are you sure you want to delete <strong>{resource.kind}</strong> <kbd>{resource.name}</kbd>?
|
||||
</p>
|
||||
{customMessage}
|
||||
<p>
|
||||
Deleting resources can be <strong>dangerous</strong>. Be sure you understand the effects of deleting this resource before continuing. Consider asking someone to
|
||||
review the change first.
|
||||
@@ -1775,10 +1716,6 @@ export const getProgressiveSyncStatusIcon = ({status, isButton}: {status: string
|
||||
return {icon: 'fa-clock', color: COLORS.sync.out_of_sync};
|
||||
case 'Error':
|
||||
return {icon: 'fa-times-circle', color: COLORS.health.degraded};
|
||||
case 'Synced':
|
||||
return {icon: 'fa-check-circle', color: COLORS.sync.synced};
|
||||
case 'OutOfSync':
|
||||
return {icon: 'fa-exclamation-triangle', color: COLORS.sync.out_of_sync};
|
||||
default:
|
||||
return {icon: 'fa-question-circle', color: COLORS.sync.unknown};
|
||||
}
|
||||
@@ -1801,10 +1738,6 @@ export const getProgressiveSyncStatusColor = (status: string): string => {
|
||||
return COLORS.health.healthy;
|
||||
case 'Error':
|
||||
return COLORS.health.degraded;
|
||||
case 'Synced':
|
||||
return COLORS.sync.synced;
|
||||
case 'OutOfSync':
|
||||
return COLORS.sync.out_of_sync;
|
||||
default:
|
||||
return COLORS.sync.unknown;
|
||||
}
|
||||
|
||||
@@ -1134,8 +1134,3 @@ export interface ApplicationSet {
|
||||
resources?: ApplicationSetResource[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface ApplicationSetList {
|
||||
metadata: models.ListMeta;
|
||||
items: ApplicationSet[];
|
||||
}
|
||||
|
||||
@@ -550,8 +550,4 @@ export class ApplicationsService {
|
||||
.query({appsetNamespace: namespace})
|
||||
.then(res => res.body as models.ApplicationSet);
|
||||
}
|
||||
|
||||
public async listApplicationSets(): Promise<models.ApplicationSetList> {
|
||||
return requests.get(`/applicationsets`).then(res => res.body as models.ApplicationSetList);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6839,10 +6839,10 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
||||
|
||||
normalize-url@4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.3.0.tgz#9c49e10fc1876aeb76dba88bf1b2b5d9fa57b2ee"
|
||||
integrity sha512-0NLtR71o4k6GLP+mr6Ty34c5GA6CMoEsncKJxvQd8NzPxaHRJNnb5gZE8R1XF4CPIS7QPHLJ74IFszwtNVAHVQ==
|
||||
normalize-url@4.5.1:
|
||||
version "4.5.1"
|
||||
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a"
|
||||
integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==
|
||||
|
||||
npm-run-path@^4.0.1:
|
||||
version "4.0.1"
|
||||
|
||||
@@ -34,9 +34,9 @@ func (s *secretsRepositoryBackend) CreateRepository(ctx context.Context, reposit
|
||||
},
|
||||
}
|
||||
|
||||
updatedSecret := s.repositoryToSecret(repository, repositorySecret)
|
||||
s.repositoryToSecret(repository, repositorySecret)
|
||||
|
||||
_, err := s.db.createSecret(ctx, updatedSecret)
|
||||
_, err := s.db.createSecret(ctx, repositorySecret)
|
||||
if err != nil {
|
||||
if apierrors.IsAlreadyExists(err) {
|
||||
hasLabel, err := s.hasRepoTypeLabel(secName)
|
||||
@@ -142,9 +142,9 @@ func (s *secretsRepositoryBackend) UpdateRepository(ctx context.Context, reposit
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updatedSecret := s.repositoryToSecret(repository, repositorySecret)
|
||||
s.repositoryToSecret(repository, repositorySecret)
|
||||
|
||||
_, err = s.db.kubeclientset.CoreV1().Secrets(s.db.ns).Update(ctx, updatedSecret, metav1.UpdateOptions{})
|
||||
_, err = s.db.kubeclientset.CoreV1().Secrets(s.db.ns).Update(ctx, repositorySecret, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -187,9 +187,9 @@ func (s *secretsRepositoryBackend) CreateRepoCreds(ctx context.Context, repoCred
|
||||
},
|
||||
}
|
||||
|
||||
updatedSecret := s.repoCredsToSecret(repoCreds, repoCredsSecret)
|
||||
s.repoCredsToSecret(repoCreds, repoCredsSecret)
|
||||
|
||||
_, err := s.db.createSecret(ctx, updatedSecret)
|
||||
_, err := s.db.createSecret(ctx, repoCredsSecret)
|
||||
if err != nil {
|
||||
if apierrors.IsAlreadyExists(err) {
|
||||
return nil, status.Errorf(codes.AlreadyExists, "repository credentials %q already exists", repoCreds.URL)
|
||||
@@ -237,9 +237,9 @@ func (s *secretsRepositoryBackend) UpdateRepoCreds(ctx context.Context, repoCred
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updatedSecret := s.repoCredsToSecret(repoCreds, repoCredsSecret)
|
||||
s.repoCredsToSecret(repoCreds, repoCredsSecret)
|
||||
|
||||
repoCredsSecret, err = s.db.kubeclientset.CoreV1().Secrets(s.db.ns).Update(ctx, updatedSecret, metav1.UpdateOptions{})
|
||||
repoCredsSecret, err = s.db.kubeclientset.CoreV1().Secrets(s.db.ns).Update(ctx, repoCredsSecret, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -323,75 +323,73 @@ func (s *secretsRepositoryBackend) GetAllOCIRepoCreds(_ context.Context) ([]*app
|
||||
}
|
||||
|
||||
func secretToRepository(secret *corev1.Secret) (*appsv1.Repository, error) {
|
||||
secretCopy := secret.DeepCopy()
|
||||
|
||||
repository := &appsv1.Repository{
|
||||
Name: string(secretCopy.Data["name"]),
|
||||
Repo: string(secretCopy.Data["url"]),
|
||||
Username: string(secretCopy.Data["username"]),
|
||||
Password: string(secretCopy.Data["password"]),
|
||||
BearerToken: string(secretCopy.Data["bearerToken"]),
|
||||
SSHPrivateKey: string(secretCopy.Data["sshPrivateKey"]),
|
||||
TLSClientCertData: string(secretCopy.Data["tlsClientCertData"]),
|
||||
TLSClientCertKey: string(secretCopy.Data["tlsClientCertKey"]),
|
||||
Type: string(secretCopy.Data["type"]),
|
||||
GithubAppPrivateKey: string(secretCopy.Data["githubAppPrivateKey"]),
|
||||
GitHubAppEnterpriseBaseURL: string(secretCopy.Data["githubAppEnterpriseBaseUrl"]),
|
||||
Proxy: string(secretCopy.Data["proxy"]),
|
||||
NoProxy: string(secretCopy.Data["noProxy"]),
|
||||
Project: string(secretCopy.Data["project"]),
|
||||
GCPServiceAccountKey: string(secretCopy.Data["gcpServiceAccountKey"]),
|
||||
Name: string(secret.Data["name"]),
|
||||
Repo: string(secret.Data["url"]),
|
||||
Username: string(secret.Data["username"]),
|
||||
Password: string(secret.Data["password"]),
|
||||
BearerToken: string(secret.Data["bearerToken"]),
|
||||
SSHPrivateKey: string(secret.Data["sshPrivateKey"]),
|
||||
TLSClientCertData: string(secret.Data["tlsClientCertData"]),
|
||||
TLSClientCertKey: string(secret.Data["tlsClientCertKey"]),
|
||||
Type: string(secret.Data["type"]),
|
||||
GithubAppPrivateKey: string(secret.Data["githubAppPrivateKey"]),
|
||||
GitHubAppEnterpriseBaseURL: string(secret.Data["githubAppEnterpriseBaseUrl"]),
|
||||
Proxy: string(secret.Data["proxy"]),
|
||||
NoProxy: string(secret.Data["noProxy"]),
|
||||
Project: string(secret.Data["project"]),
|
||||
GCPServiceAccountKey: string(secret.Data["gcpServiceAccountKey"]),
|
||||
}
|
||||
|
||||
insecureIgnoreHostKey, err := boolOrFalse(secretCopy, "insecureIgnoreHostKey")
|
||||
insecureIgnoreHostKey, err := boolOrFalse(secret, "insecureIgnoreHostKey")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
repository.InsecureIgnoreHostKey = insecureIgnoreHostKey
|
||||
|
||||
insecure, err := boolOrFalse(secretCopy, "insecure")
|
||||
insecure, err := boolOrFalse(secret, "insecure")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
repository.Insecure = insecure
|
||||
|
||||
enableLfs, err := boolOrFalse(secretCopy, "enableLfs")
|
||||
enableLfs, err := boolOrFalse(secret, "enableLfs")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
repository.EnableLFS = enableLfs
|
||||
|
||||
enableOCI, err := boolOrFalse(secretCopy, "enableOCI")
|
||||
enableOCI, err := boolOrFalse(secret, "enableOCI")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
repository.EnableOCI = enableOCI
|
||||
|
||||
insecureOCIForceHTTP, err := boolOrFalse(secretCopy, "insecureOCIForceHttp")
|
||||
insecureOCIForceHTTP, err := boolOrFalse(secret, "insecureOCIForceHttp")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
repository.InsecureOCIForceHttp = insecureOCIForceHTTP
|
||||
|
||||
githubAppID, err := intOrZero(secretCopy, "githubAppID")
|
||||
githubAppID, err := intOrZero(secret, "githubAppID")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
repository.GithubAppId = githubAppID
|
||||
|
||||
githubAppInstallationID, err := intOrZero(secretCopy, "githubAppInstallationID")
|
||||
githubAppInstallationID, err := intOrZero(secret, "githubAppInstallationID")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
repository.GithubAppInstallationId = githubAppInstallationID
|
||||
|
||||
forceBasicAuth, err := boolOrFalse(secretCopy, "forceHttpBasicAuth")
|
||||
forceBasicAuth, err := boolOrFalse(secret, "forceHttpBasicAuth")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
repository.ForceHttpBasicAuth = forceBasicAuth
|
||||
|
||||
useAzureWorkloadIdentity, err := boolOrFalse(secretCopy, "useAzureWorkloadIdentity")
|
||||
useAzureWorkloadIdentity, err := boolOrFalse(secret, "useAzureWorkloadIdentity")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
@@ -400,92 +398,86 @@ func secretToRepository(secret *corev1.Secret) (*appsv1.Repository, error) {
|
||||
return repository, nil
|
||||
}
|
||||
|
||||
func (s *secretsRepositoryBackend) repositoryToSecret(repository *appsv1.Repository, secret *corev1.Secret) *corev1.Secret {
|
||||
secretCopy := secret.DeepCopy()
|
||||
|
||||
if secretCopy.Data == nil {
|
||||
secretCopy.Data = make(map[string][]byte)
|
||||
func (s *secretsRepositoryBackend) repositoryToSecret(repository *appsv1.Repository, secret *corev1.Secret) {
|
||||
if secret.Data == nil {
|
||||
secret.Data = make(map[string][]byte)
|
||||
}
|
||||
|
||||
updateSecretString(secretCopy, "name", repository.Name)
|
||||
updateSecretString(secretCopy, "project", repository.Project)
|
||||
updateSecretString(secretCopy, "url", repository.Repo)
|
||||
updateSecretString(secretCopy, "username", repository.Username)
|
||||
updateSecretString(secretCopy, "password", repository.Password)
|
||||
updateSecretString(secretCopy, "bearerToken", repository.BearerToken)
|
||||
updateSecretString(secretCopy, "sshPrivateKey", repository.SSHPrivateKey)
|
||||
updateSecretBool(secretCopy, "enableOCI", repository.EnableOCI)
|
||||
updateSecretBool(secretCopy, "insecureOCIForceHttp", repository.InsecureOCIForceHttp)
|
||||
updateSecretString(secretCopy, "tlsClientCertData", repository.TLSClientCertData)
|
||||
updateSecretString(secretCopy, "tlsClientCertKey", repository.TLSClientCertKey)
|
||||
updateSecretString(secretCopy, "type", repository.Type)
|
||||
updateSecretString(secretCopy, "githubAppPrivateKey", repository.GithubAppPrivateKey)
|
||||
updateSecretInt(secretCopy, "githubAppID", repository.GithubAppId)
|
||||
updateSecretInt(secretCopy, "githubAppInstallationID", repository.GithubAppInstallationId)
|
||||
updateSecretString(secretCopy, "githubAppEnterpriseBaseUrl", repository.GitHubAppEnterpriseBaseURL)
|
||||
updateSecretBool(secretCopy, "insecureIgnoreHostKey", repository.InsecureIgnoreHostKey)
|
||||
updateSecretBool(secretCopy, "insecure", repository.Insecure)
|
||||
updateSecretBool(secretCopy, "enableLfs", repository.EnableLFS)
|
||||
updateSecretString(secretCopy, "proxy", repository.Proxy)
|
||||
updateSecretString(secretCopy, "noProxy", repository.NoProxy)
|
||||
updateSecretString(secretCopy, "gcpServiceAccountKey", repository.GCPServiceAccountKey)
|
||||
updateSecretBool(secretCopy, "forceHttpBasicAuth", repository.ForceHttpBasicAuth)
|
||||
updateSecretBool(secretCopy, "useAzureWorkloadIdentity", repository.UseAzureWorkloadIdentity)
|
||||
addSecretMetadata(secretCopy, s.getSecretType())
|
||||
|
||||
return secretCopy
|
||||
updateSecretString(secret, "name", repository.Name)
|
||||
updateSecretString(secret, "project", repository.Project)
|
||||
updateSecretString(secret, "url", repository.Repo)
|
||||
updateSecretString(secret, "username", repository.Username)
|
||||
updateSecretString(secret, "password", repository.Password)
|
||||
updateSecretString(secret, "bearerToken", repository.BearerToken)
|
||||
updateSecretString(secret, "sshPrivateKey", repository.SSHPrivateKey)
|
||||
updateSecretBool(secret, "enableOCI", repository.EnableOCI)
|
||||
updateSecretBool(secret, "insecureOCIForceHttp", repository.InsecureOCIForceHttp)
|
||||
updateSecretString(secret, "tlsClientCertData", repository.TLSClientCertData)
|
||||
updateSecretString(secret, "tlsClientCertKey", repository.TLSClientCertKey)
|
||||
updateSecretString(secret, "type", repository.Type)
|
||||
updateSecretString(secret, "githubAppPrivateKey", repository.GithubAppPrivateKey)
|
||||
updateSecretInt(secret, "githubAppID", repository.GithubAppId)
|
||||
updateSecretInt(secret, "githubAppInstallationID", repository.GithubAppInstallationId)
|
||||
updateSecretString(secret, "githubAppEnterpriseBaseUrl", repository.GitHubAppEnterpriseBaseURL)
|
||||
updateSecretBool(secret, "insecureIgnoreHostKey", repository.InsecureIgnoreHostKey)
|
||||
updateSecretBool(secret, "insecure", repository.Insecure)
|
||||
updateSecretBool(secret, "enableLfs", repository.EnableLFS)
|
||||
updateSecretString(secret, "proxy", repository.Proxy)
|
||||
updateSecretString(secret, "noProxy", repository.NoProxy)
|
||||
updateSecretString(secret, "gcpServiceAccountKey", repository.GCPServiceAccountKey)
|
||||
updateSecretBool(secret, "forceHttpBasicAuth", repository.ForceHttpBasicAuth)
|
||||
updateSecretBool(secret, "useAzureWorkloadIdentity", repository.UseAzureWorkloadIdentity)
|
||||
addSecretMetadata(secret, s.getSecretType())
|
||||
}
|
||||
|
||||
func (s *secretsRepositoryBackend) secretToRepoCred(secret *corev1.Secret) (*appsv1.RepoCreds, error) {
|
||||
secretCopy := secret.DeepCopy()
|
||||
|
||||
repository := &appsv1.RepoCreds{
|
||||
URL: string(secretCopy.Data["url"]),
|
||||
Username: string(secretCopy.Data["username"]),
|
||||
Password: string(secretCopy.Data["password"]),
|
||||
BearerToken: string(secretCopy.Data["bearerToken"]),
|
||||
SSHPrivateKey: string(secretCopy.Data["sshPrivateKey"]),
|
||||
TLSClientCertData: string(secretCopy.Data["tlsClientCertData"]),
|
||||
TLSClientCertKey: string(secretCopy.Data["tlsClientCertKey"]),
|
||||
Type: string(secretCopy.Data["type"]),
|
||||
GithubAppPrivateKey: string(secretCopy.Data["githubAppPrivateKey"]),
|
||||
GitHubAppEnterpriseBaseURL: string(secretCopy.Data["githubAppEnterpriseBaseUrl"]),
|
||||
GCPServiceAccountKey: string(secretCopy.Data["gcpServiceAccountKey"]),
|
||||
Proxy: string(secretCopy.Data["proxy"]),
|
||||
NoProxy: string(secretCopy.Data["noProxy"]),
|
||||
URL: string(secret.Data["url"]),
|
||||
Username: string(secret.Data["username"]),
|
||||
Password: string(secret.Data["password"]),
|
||||
BearerToken: string(secret.Data["bearerToken"]),
|
||||
SSHPrivateKey: string(secret.Data["sshPrivateKey"]),
|
||||
TLSClientCertData: string(secret.Data["tlsClientCertData"]),
|
||||
TLSClientCertKey: string(secret.Data["tlsClientCertKey"]),
|
||||
Type: string(secret.Data["type"]),
|
||||
GithubAppPrivateKey: string(secret.Data["githubAppPrivateKey"]),
|
||||
GitHubAppEnterpriseBaseURL: string(secret.Data["githubAppEnterpriseBaseUrl"]),
|
||||
GCPServiceAccountKey: string(secret.Data["gcpServiceAccountKey"]),
|
||||
Proxy: string(secret.Data["proxy"]),
|
||||
NoProxy: string(secret.Data["noProxy"]),
|
||||
}
|
||||
|
||||
enableOCI, err := boolOrFalse(secretCopy, "enableOCI")
|
||||
enableOCI, err := boolOrFalse(secret, "enableOCI")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
repository.EnableOCI = enableOCI
|
||||
|
||||
insecureOCIForceHTTP, err := boolOrFalse(secretCopy, "insecureOCIForceHttp")
|
||||
insecureOCIForceHTTP, err := boolOrFalse(secret, "insecureOCIForceHttp")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
repository.InsecureOCIForceHttp = insecureOCIForceHTTP
|
||||
|
||||
githubAppID, err := intOrZero(secretCopy, "githubAppID")
|
||||
githubAppID, err := intOrZero(secret, "githubAppID")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
repository.GithubAppId = githubAppID
|
||||
|
||||
githubAppInstallationID, err := intOrZero(secretCopy, "githubAppInstallationID")
|
||||
githubAppInstallationID, err := intOrZero(secret, "githubAppInstallationID")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
repository.GithubAppInstallationId = githubAppInstallationID
|
||||
|
||||
forceBasicAuth, err := boolOrFalse(secretCopy, "forceHttpBasicAuth")
|
||||
forceBasicAuth, err := boolOrFalse(secret, "forceHttpBasicAuth")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
repository.ForceHttpBasicAuth = forceBasicAuth
|
||||
|
||||
useAzureWorkloadIdentity, err := boolOrFalse(secretCopy, "useAzureWorkloadIdentity")
|
||||
useAzureWorkloadIdentity, err := boolOrFalse(secret, "useAzureWorkloadIdentity")
|
||||
if err != nil {
|
||||
return repository, err
|
||||
}
|
||||
@@ -494,35 +486,31 @@ func (s *secretsRepositoryBackend) secretToRepoCred(secret *corev1.Secret) (*app
|
||||
return repository, nil
|
||||
}
|
||||
|
||||
func (s *secretsRepositoryBackend) repoCredsToSecret(repoCreds *appsv1.RepoCreds, secret *corev1.Secret) *corev1.Secret {
|
||||
secretCopy := secret.DeepCopy()
|
||||
|
||||
if secretCopy.Data == nil {
|
||||
secretCopy.Data = make(map[string][]byte)
|
||||
func (s *secretsRepositoryBackend) repoCredsToSecret(repoCreds *appsv1.RepoCreds, secret *corev1.Secret) {
|
||||
if secret.Data == nil {
|
||||
secret.Data = make(map[string][]byte)
|
||||
}
|
||||
|
||||
updateSecretString(secretCopy, "url", repoCreds.URL)
|
||||
updateSecretString(secretCopy, "username", repoCreds.Username)
|
||||
updateSecretString(secretCopy, "password", repoCreds.Password)
|
||||
updateSecretString(secretCopy, "bearerToken", repoCreds.BearerToken)
|
||||
updateSecretString(secretCopy, "sshPrivateKey", repoCreds.SSHPrivateKey)
|
||||
updateSecretBool(secretCopy, "enableOCI", repoCreds.EnableOCI)
|
||||
updateSecretBool(secretCopy, "insecureOCIForceHttp", repoCreds.InsecureOCIForceHttp)
|
||||
updateSecretString(secretCopy, "tlsClientCertData", repoCreds.TLSClientCertData)
|
||||
updateSecretString(secretCopy, "tlsClientCertKey", repoCreds.TLSClientCertKey)
|
||||
updateSecretString(secretCopy, "type", repoCreds.Type)
|
||||
updateSecretString(secretCopy, "githubAppPrivateKey", repoCreds.GithubAppPrivateKey)
|
||||
updateSecretInt(secretCopy, "githubAppID", repoCreds.GithubAppId)
|
||||
updateSecretInt(secretCopy, "githubAppInstallationID", repoCreds.GithubAppInstallationId)
|
||||
updateSecretString(secretCopy, "githubAppEnterpriseBaseUrl", repoCreds.GitHubAppEnterpriseBaseURL)
|
||||
updateSecretString(secretCopy, "gcpServiceAccountKey", repoCreds.GCPServiceAccountKey)
|
||||
updateSecretString(secretCopy, "proxy", repoCreds.Proxy)
|
||||
updateSecretString(secretCopy, "noProxy", repoCreds.NoProxy)
|
||||
updateSecretBool(secretCopy, "forceHttpBasicAuth", repoCreds.ForceHttpBasicAuth)
|
||||
updateSecretBool(secretCopy, "useAzureWorkloadIdentity", repoCreds.UseAzureWorkloadIdentity)
|
||||
addSecretMetadata(secretCopy, s.getRepoCredSecretType())
|
||||
|
||||
return secretCopy
|
||||
updateSecretString(secret, "url", repoCreds.URL)
|
||||
updateSecretString(secret, "username", repoCreds.Username)
|
||||
updateSecretString(secret, "password", repoCreds.Password)
|
||||
updateSecretString(secret, "bearerToken", repoCreds.BearerToken)
|
||||
updateSecretString(secret, "sshPrivateKey", repoCreds.SSHPrivateKey)
|
||||
updateSecretBool(secret, "enableOCI", repoCreds.EnableOCI)
|
||||
updateSecretBool(secret, "insecureOCIForceHttp", repoCreds.InsecureOCIForceHttp)
|
||||
updateSecretString(secret, "tlsClientCertData", repoCreds.TLSClientCertData)
|
||||
updateSecretString(secret, "tlsClientCertKey", repoCreds.TLSClientCertKey)
|
||||
updateSecretString(secret, "type", repoCreds.Type)
|
||||
updateSecretString(secret, "githubAppPrivateKey", repoCreds.GithubAppPrivateKey)
|
||||
updateSecretInt(secret, "githubAppID", repoCreds.GithubAppId)
|
||||
updateSecretInt(secret, "githubAppInstallationID", repoCreds.GithubAppInstallationId)
|
||||
updateSecretString(secret, "githubAppEnterpriseBaseUrl", repoCreds.GitHubAppEnterpriseBaseURL)
|
||||
updateSecretString(secret, "gcpServiceAccountKey", repoCreds.GCPServiceAccountKey)
|
||||
updateSecretString(secret, "proxy", repoCreds.Proxy)
|
||||
updateSecretString(secret, "noProxy", repoCreds.NoProxy)
|
||||
updateSecretBool(secret, "forceHttpBasicAuth", repoCreds.ForceHttpBasicAuth)
|
||||
updateSecretBool(secret, "useAzureWorkloadIdentity", repoCreds.UseAzureWorkloadIdentity)
|
||||
addSecretMetadata(secret, s.getRepoCredSecretType())
|
||||
}
|
||||
|
||||
func (s *secretsRepositoryBackend) getRepositorySecret(repoURL, project string, allowFallback bool) (*corev1.Secret, error) {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -87,9 +85,9 @@ func TestSecretsRepositoryBackend_CreateRepository(t *testing.T) {
|
||||
t.Parallel()
|
||||
secret := &corev1.Secret{}
|
||||
s := secretsRepositoryBackend{}
|
||||
updatedSecret := s.repositoryToSecret(repo, secret)
|
||||
delete(updatedSecret.Labels, common.LabelKeySecretType)
|
||||
f := setupWithK8sObjects(updatedSecret)
|
||||
s.repositoryToSecret(repo, secret)
|
||||
delete(secret.Labels, common.LabelKeySecretType)
|
||||
f := setupWithK8sObjects(secret)
|
||||
f.clientSet.ReactionChain = nil
|
||||
f.clientSet.AddReactor("create", "secrets", func(_ k8stesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
gr := schema.GroupResource{
|
||||
@@ -124,8 +122,8 @@ func TestSecretsRepositoryBackend_CreateRepository(t *testing.T) {
|
||||
},
|
||||
}
|
||||
s := secretsRepositoryBackend{}
|
||||
updatedSecret := s.repositoryToSecret(repo, secret)
|
||||
f := setupWithK8sObjects(updatedSecret)
|
||||
s.repositoryToSecret(repo, secret)
|
||||
f := setupWithK8sObjects(secret)
|
||||
f.clientSet.ReactionChain = nil
|
||||
f.clientSet.WatchReactionChain = nil
|
||||
f.clientSet.AddReactor("create", "secrets", func(_ k8stesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
@@ -136,7 +134,7 @@ func TestSecretsRepositoryBackend_CreateRepository(t *testing.T) {
|
||||
return true, nil, apierrors.NewAlreadyExists(gr, "already exists")
|
||||
})
|
||||
watcher := watch.NewFakeWithChanSize(1, true)
|
||||
watcher.Add(updatedSecret)
|
||||
watcher.Add(secret)
|
||||
f.clientSet.AddWatchReactor("secrets", func(_ k8stesting.Action) (handled bool, ret watch.Interface, err error) {
|
||||
return true, watcher, nil
|
||||
})
|
||||
@@ -954,9 +952,7 @@ func TestRepoCredsToSecret(t *testing.T) {
|
||||
GithubAppInstallationId: 456,
|
||||
GitHubAppEnterpriseBaseURL: "GitHubAppEnterpriseBaseURL",
|
||||
}
|
||||
|
||||
s = testee.repoCredsToSecret(creds, s)
|
||||
|
||||
testee.repoCredsToSecret(creds, s)
|
||||
assert.Equal(t, []byte(creds.URL), s.Data["url"])
|
||||
assert.Equal(t, []byte(creds.Username), s.Data["username"])
|
||||
assert.Equal(t, []byte(creds.Password), s.Data["password"])
|
||||
@@ -998,7 +994,7 @@ func TestRepoWriteCredsToSecret(t *testing.T) {
|
||||
GithubAppInstallationId: 456,
|
||||
GitHubAppEnterpriseBaseURL: "GitHubAppEnterpriseBaseURL",
|
||||
}
|
||||
s = testee.repoCredsToSecret(creds, s)
|
||||
testee.repoCredsToSecret(creds, s)
|
||||
assert.Equal(t, []byte(creds.URL), s.Data["url"])
|
||||
assert.Equal(t, []byte(creds.Username), s.Data["username"])
|
||||
assert.Equal(t, []byte(creds.Password), s.Data["password"])
|
||||
@@ -1014,169 +1010,3 @@ func TestRepoWriteCredsToSecret(t *testing.T) {
|
||||
assert.Equal(t, map[string]string{common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD}, s.Annotations)
|
||||
assert.Equal(t, map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepoCredsWrite}, s.Labels)
|
||||
}
|
||||
|
||||
func TestRaceConditionInRepoCredsOperations(t *testing.T) {
|
||||
// Create a single shared secret that will be accessed concurrently
|
||||
sharedSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: RepoURLToSecretName(repoSecretPrefix, "git@github.com:argoproj/argo-cd.git", ""),
|
||||
Namespace: testNamespace,
|
||||
Labels: map[string]string{
|
||||
common.LabelKeySecretType: common.LabelValueSecretTypeRepoCreds,
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"url": []byte("git@github.com:argoproj/argo-cd.git"),
|
||||
"username": []byte("test-user"),
|
||||
"password": []byte("test-pass"),
|
||||
},
|
||||
}
|
||||
|
||||
// Create test credentials that we'll use for conversion
|
||||
repoCreds := &appsv1.RepoCreds{
|
||||
URL: "git@github.com:argoproj/argo-cd.git",
|
||||
Username: "test-user",
|
||||
Password: "test-pass",
|
||||
}
|
||||
|
||||
backend := &secretsRepositoryBackend{}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
concurrentOps := 50
|
||||
errChan := make(chan error, concurrentOps*2) // Channel to collect errors
|
||||
|
||||
// Launch goroutines that perform concurrent operations
|
||||
for i := 0; i < concurrentOps; i++ {
|
||||
wg.Add(2)
|
||||
|
||||
// One goroutine converts from RepoCreds to Secret
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
errChan <- fmt.Errorf("panic in repoCredsToSecret: %v", r)
|
||||
}
|
||||
}()
|
||||
_ = backend.repoCredsToSecret(repoCreds, sharedSecret)
|
||||
}()
|
||||
|
||||
// Another goroutine converts from Secret to RepoCreds
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
errChan <- fmt.Errorf("panic in secretToRepoCred: %v", r)
|
||||
}
|
||||
}()
|
||||
creds, err := backend.secretToRepoCred(sharedSecret)
|
||||
if err != nil {
|
||||
errChan <- fmt.Errorf("error in secretToRepoCred: %w", err)
|
||||
return
|
||||
}
|
||||
// Verify data integrity
|
||||
if creds.URL != repoCreds.URL || creds.Username != repoCreds.Username || creds.Password != repoCreds.Password {
|
||||
errChan <- fmt.Errorf("data mismatch in conversion: expected %v, got %v", repoCreds, creds)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errChan)
|
||||
|
||||
// Check for any errors that occurred during concurrent operations
|
||||
for err := range errChan {
|
||||
t.Errorf("concurrent operation error: %v", err)
|
||||
}
|
||||
|
||||
// Verify final state
|
||||
finalCreds, err := backend.secretToRepoCred(sharedSecret)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, repoCreds.URL, finalCreds.URL)
|
||||
assert.Equal(t, repoCreds.Username, finalCreds.Username)
|
||||
assert.Equal(t, repoCreds.Password, finalCreds.Password)
|
||||
}
|
||||
|
||||
func TestRaceConditionInRepositoryOperations(t *testing.T) {
|
||||
// Create a single shared secret that will be accessed concurrently
|
||||
sharedSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: RepoURLToSecretName(repoSecretPrefix, "git@github.com:argoproj/argo-cd.git", ""),
|
||||
Namespace: testNamespace,
|
||||
Labels: map[string]string{
|
||||
common.LabelKeySecretType: common.LabelValueSecretTypeRepository,
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"url": []byte("git@github.com:argoproj/argo-cd.git"),
|
||||
"name": []byte("test-repo"),
|
||||
"username": []byte("test-user"),
|
||||
"password": []byte("test-pass"),
|
||||
},
|
||||
}
|
||||
|
||||
// Create test repository that we'll use for conversion
|
||||
repo := &appsv1.Repository{
|
||||
Name: "test-repo",
|
||||
Repo: "git@github.com:argoproj/argo-cd.git",
|
||||
Username: "test-user",
|
||||
Password: "test-pass",
|
||||
}
|
||||
|
||||
backend := &secretsRepositoryBackend{}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
concurrentOps := 50
|
||||
errChan := make(chan error, concurrentOps*2) // Channel to collect errors
|
||||
|
||||
// Launch goroutines that perform concurrent operations
|
||||
for i := 0; i < concurrentOps; i++ {
|
||||
wg.Add(2)
|
||||
|
||||
// One goroutine converts from Repository to Secret
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
errChan <- fmt.Errorf("panic in repositoryToSecret: %v", r)
|
||||
}
|
||||
}()
|
||||
_ = backend.repositoryToSecret(repo, sharedSecret)
|
||||
}()
|
||||
|
||||
// Another goroutine converts from Secret to Repository
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
errChan <- fmt.Errorf("panic in secretToRepository: %v", r)
|
||||
}
|
||||
}()
|
||||
repository, err := secretToRepository(sharedSecret)
|
||||
if err != nil {
|
||||
errChan <- fmt.Errorf("error in secretToRepository: %w", err)
|
||||
return
|
||||
}
|
||||
// Verify data integrity
|
||||
if repository.Name != repo.Name || repository.Repo != repo.Repo ||
|
||||
repository.Username != repo.Username || repository.Password != repo.Password {
|
||||
errChan <- fmt.Errorf("data mismatch in conversion: expected %v, got %v", repo, repository)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errChan)
|
||||
|
||||
// Check for any errors that occurred during concurrent operations
|
||||
for err := range errChan {
|
||||
t.Errorf("concurrent operation error: %v", err)
|
||||
}
|
||||
|
||||
// Verify final state
|
||||
finalRepo, err := secretToRepository(sharedSecret)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, repo.Name, finalRepo.Name)
|
||||
assert.Equal(t, repo.Repo, finalRepo.Repo)
|
||||
assert.Equal(t, repo.Username, finalRepo.Username)
|
||||
assert.Equal(t, repo.Password, finalRepo.Password)
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ func RunWithRedactor(cmd *exec.Cmd, redactor func(text string) string) (string,
|
||||
}
|
||||
|
||||
func RunWithExecRunOpts(cmd *exec.Cmd, opts ExecRunOpts) (string, error) {
|
||||
cmdOpts := CmdOpts{Timeout: timeout, FatalTimeout: fatalTimeout, Redactor: opts.Redactor, TimeoutBehavior: opts.TimeoutBehavior, SkipErrorLogging: opts.SkipErrorLogging, CaptureStderr: opts.CaptureStderr}
|
||||
cmdOpts := CmdOpts{Timeout: timeout, FatalTimeout: fatalTimeout, Redactor: opts.Redactor, TimeoutBehavior: opts.TimeoutBehavior, SkipErrorLogging: opts.SkipErrorLogging}
|
||||
span := tracing.NewLoggingTracer(log.NewLogrusLogger(log.NewWithCurrentConfig())).StartSpan(fmt.Sprintf("exec %v", cmd.Args[0]))
|
||||
span.SetBaggageItem("dir", cmd.Dir)
|
||||
if cmdOpts.Redactor != nil {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user