Compare commits

...

321 Commits

Author SHA1 Message Date
github-actions[bot]
3f344d54a4 Bump version to 2.11.3 (#18520)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <39732895+pasha-codefresh@users.noreply.github.com>
2024-06-06 11:36:25 +03:00
pasha-codefresh
e01bb5303a Merge pull request from GHSA-3cqf-953p-h5cp
* fix: prevent enumerating by cluster name, return exact error for case when cluster exists and not

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix: prevent cluster enumeration by name

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix: prevent cluster enumeration by name

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix linter and add unit test

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix linter and add unit test

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: pashakostohrys <pavel@codefresh.io>
2024-06-06 11:30:10 +03:00
Blake Pettersson
320abb8d64 Merge pull request from GHSA-87p9-x75h-p4j2
Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-06-06 11:25:55 +03:00
gcp-cherry-pick-bot[bot]
46342a9e82 fix: app names with non-alphanumeric characters in position 63 break syncs (issue #18237) (#18256) (#18439)
* Ensure truncated app label does not end in a special character



* Move regex to global variable and add out of bounds check



* Add test for out-of-bounds check



---------

Signed-off-by: Zack Robinson <robinsoz@arcesium.com>
Co-authored-by: Zack Robinson <zkislakrobinson@gmail.com>
2024-05-28 21:08:52 +03:00
gcp-cherry-pick-bot[bot]
cf17283ebe fix source ordering issue in manifest generation for multi-source app while using manifests and diff commands (#18395) (#18408) 2024-05-24 16:52:42 -04:00
github-actions[bot]
25f7504ecc Bump version to 2.11.2 (#18384)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <39732895+pasha-codefresh@users.noreply.github.com>
2024-05-23 16:29:33 +03:00
gcp-cherry-pick-bot[bot]
2b463d4103 fix: remove Egress NetworkPolicy for argocd-redis and argocd-redis-ha-haproxy (#18367) (#18372)
* fix: runing local failed



* fix: Redis egress removal



---------

Signed-off-by: xiaowu.zhu <xiaowu.zhu@daocloud.io>
Signed-off-by: May Zhang <may_zhang@intuit.com>
Co-authored-by: May Zhang <may_zhang@intuit.com>
Co-authored-by: yyzxw <1020938856@qq.com>
2024-05-22 19:48:08 -04:00
Michael Crenshaw
9d58e7e330 fix: revert registry change (#18328)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-05-21 13:52:51 -04:00
gcp-cherry-pick-bot[bot]
212a6ed05a fix(deps): upgrade otel dependency (#18285) (#18324)
Signed-off-by: Justin Marquis <justin@akuity.io>
Co-authored-by: Justin Marquis <76892343+34fathombelow@users.noreply.github.com>
Co-authored-by: Soumya Ghosh Dastidar <44349253+gdsoumya@users.noreply.github.com>
2024-05-21 10:48:11 -07:00
Michael Crenshaw
140ffdda4d docs: add v2.11 notes to upgrading page (#18333)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-05-21 07:27:01 -10:00
gcp-cherry-pick-bot[bot]
47e7470726 chore(ci): fix release notes (#18132) (#18330)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-05-21 12:53:13 -04:00
github-actions[bot]
9f40df0c29 Bump version to 2.11.1 (#18319)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <39732895+pasha-codefresh@users.noreply.github.com>
2024-05-21 16:44:13 +03:00
Leonardo Luz Almeida
6ef7b62a0f Merge pull request from GHSA-9766-5277-j5hr
* fix: Enable Redis authentication in the default installation

Signed-off-by: May Zhang <may_zhang@intuit.com>

* chore: fix git_test unit test

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>

---------

Signed-off-by: May Zhang <may_zhang@intuit.com>
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
Co-authored-by: May Zhang <may_zhang@intuit.com>
2024-05-21 16:23:09 +03:00
Leonardo Luz Almeida
f1a449e83e Merge pull request from GHSA-9766-5277-j5hr
* fix: Enable Redis authentication in the default installation

Signed-off-by: May Zhang <may_zhang@intuit.com>

* chore: fix git_test unit test

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>

---------

Signed-off-by: May Zhang <may_zhang@intuit.com>
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
Co-authored-by: May Zhang <may_zhang@intuit.com>
2024-05-21 16:22:43 +03:00
Keith Chong
6530c6fede fix: UI MultiSource - Helm Chart with values.yaml (#18188) (#18200)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2024-05-20 08:26:42 -04:00
gcp-cherry-pick-bot[bot]
786e141047 fix: copy visited map #11699 (#12667) (#18219)
This commit fixed an issue #11699 that caused a warning even if the cycle didn't exist.
Fix false cycle discovery by copying the visited resource map before recursively calling of getAppRecursive.

Fixes #11699

Signed-off-by: Arata Furukawa <old.river.new@gmail.com>
Co-authored-by: Arata Furukawa <old.river.new@gmail.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-05-20 13:28:17 +03:00
gcp-cherry-pick-bot[bot]
37dd289240 update resolveRevision to use the correct source for multi-source app (#18194) (#18202)
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-05-20 11:15:55 +03:00
gcp-cherry-pick-bot[bot]
eee5c06eff Fix logging hash with multiple sources (#18189) (#18193)
Signed-off-by: onee-only <kimww0306@gmail.com>
Co-authored-by: onee-only <kimww0306@gmail.com>
2024-05-20 11:14:34 +03:00
gcp-cherry-pick-bot[bot]
4621b3b528 chore(deps): upgrade helm to 3.14.4 (#18255) (#18286)
* chore(deps): upgrade helm to 3.14.4



* place checksums where they belong



---------

Signed-off-by: Justin Marquis <justin@akuity.io>
Co-authored-by: Justin Marquis <76892343+34fathombelow@users.noreply.github.com>
Co-authored-by: Dan Garfield <dan@codefresh.io>
2024-05-20 11:13:29 +03:00
Ishita Sequeira
faeede3dc3 chore(deps): cherry-pick bump protobuf #17788 (#18284)
Signed-off-by: ishitasequeira <ishiseq29@gmail.com>
2024-05-20 10:14:30 +03:00
pasha-codefresh
dd4ee83442 chore: update gitops engine for force sync option (#5882) - 2.11 (#18125)
Signed-off-by: pashakostohrys <pavel@codefresh.io>
Co-authored-by: Kota Kimura <86363983+kkk777-7@users.noreply.github.com>
2024-05-08 18:08:25 +03:00
github-actions[bot]
d3f33c0019 Bump version to 2.11.0 (#18112)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <39732895+pasha-codefresh@users.noreply.github.com>
2024-05-07 18:57:05 +03:00
gcp-cherry-pick-bot[bot]
8cd8305212 docs: fix 404 styling (#18094) (#18104)
* docs: fix 404 styling



* hack around custom tag destruction



---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-05-07 09:07:38 -04:00
gcp-cherry-pick-bot[bot]
da6c2e9c08 fix: status.sync.comparedTo should use replace patch strategy (#18061) (#18071)
* fix: status.sync.comparedTo should use replace patch strategy



* add e2e tests



---------

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2024-05-04 13:57:47 -07:00
gcp-cherry-pick-bot[bot]
66f4934ecb fix: enable sha256 and sha512 for git ssh (#18028) (#18034)
* fix: bumping the knownhosts to v1.2.2 since this contains a fix that allows for sha256 and sha512 algorithms when using git ssh




* chore: remove older version of module from go sum



---------

Signed-off-by: Marc Arndt <marc@marcarndt.com>
Signed-off-by: Marc Arndt <m.arndt@evana.de>
Co-authored-by: Marc Arndt <marc@marcarndt.com>
Co-authored-by: Marc Arndt <m.arndt@evana.de>
2024-04-30 12:47:06 -04:00
github-actions[bot]
20fd621aa2 Bump version to 2.11.0-rc3 (#18019)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <39732895+pasha-codefresh@users.noreply.github.com>
2024-04-29 22:56:02 +03:00
Ishita Sequeira
f875931992 feat(cli): add support for multiple sources to sync command (#18016)
* update sync command

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

use arrays instead of map to display ApplicationManifetQuery fields in swagger

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

rebase and update logic for sync command

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

update conditions

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

update displayRevisions on OperationState

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

remove rerunreport file

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

fix index 0 out of bounds error

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

Address comments

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

fix codegen

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

rename GetSourcePtrBySourceIndex to GetSourcePtrByIndex

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

rename GetSourcePtrBySourcePosition to GetSourcePtrByPosition

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

rebase with master and resolve conflicts

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

fix codegen

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

Address feedback and add tests

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

fix unit test

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* codegen post cherry-pick

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

---------

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>
2024-04-29 22:34:01 +03:00
pasha-codefresh
e1f890d176 feat: update notifications (#18017)
Signed-off-by: pashakostohrys <pavel@codefresh.io>
Co-authored-by: Lukas Aldershaab <lpjoergensen@gmail.com>
2024-04-29 11:42:19 -04:00
gcp-cherry-pick-bot[bot]
602f5445b1 Fix post-delete finalizer in appset (#18003) (#18005)
Signed-off-by: Joe Bowbeer <joe.bowbeer@gmail.com>
Co-authored-by: Joe Bowbeer <joe.bowbeer@gmail.com>
2024-04-26 16:47:48 -07:00
pasha-codefresh
617f8a414f fix: codegen after security fix (#17987)
Signed-off-by: pashakostohrys <pavel@codefresh.io>
2024-04-26 16:24:54 +03:00
pasha-codefresh
0460b9873e Merge pull request from GHSA-9m6p-x4h2-6frq
* feat: limit jq.Run with timeout

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* feat: ignore normalizer jq execution timeout as env variable

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* feat: customize error message and add doc section

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* feat: improve log and change a way how to get variable

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* chore: fix import`s order

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* chore: rename variable inside sts

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* chore: fix import order

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: pashakostohrys <pavel@codefresh.io>
2024-04-26 12:24:32 +03:00
pasha-codefresh
25c6653d8a Merge pull request from GHSA-9m6p-x4h2-6frq
* feat: limit jq.Run with timeout

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* feat: ignore normalizer jq execution timeout as env variable

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* feat: customize error message and add doc section

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* feat: improve log and change a way how to get variable

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* chore: fix import`s order

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* chore: rename variable inside sts

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* chore: fix import order

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: pashakostohrys <pavel@codefresh.io>
2024-04-26 12:24:02 +03:00
gcp-cherry-pick-bot[bot]
9f186dab30 fix: use cmp vs reflect.DeepEqual for comparing Applications (#17861) (#17940) (#17958)
* fix(compare): appset compare the child apps with cmp vs reflect



* remove debug lines



* remove debug lines



---------

Signed-off-by: rumstead <37445536+rumstead@users.noreply.github.com>
Co-authored-by: rumstead <37445536+rumstead@users.noreply.github.com>
2024-04-24 16:21:05 -04:00
gcp-cherry-pick-bot[bot]
fb573e0008 docs: Mention configmap to enable new git file globbing by name (#17936) (#17938)
Signed-off-by: Christian Ciach <christian.ciach@gmail.com>
Co-authored-by: ChristianCiach <christian.ciach@gmail.com>
2024-04-23 09:41:05 -04:00
gcp-cherry-pick-bot[bot]
35a2ebe428 docs(cli): remove docs for non-existing argocd admin commands (#17924) (#17925)
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-04-22 12:32:13 -04:00
gcp-cherry-pick-bot[bot]
3bb7ac92e8 remove mention of beta state from apps-in-any-namespace doc (#17896) (#17899)
Signed-off-by: ishitasequeira <ishiseq29@gmail.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-04-19 14:04:34 +03:00
Amit Lin
2ef8fe2246 fix: debian source typo in Dockerfile (#17886)
Signed-off-by: Amit Lin <amitlin.dev@gmail.com>
2024-04-18 10:19:28 -04:00
gcp-cherry-pick-bot[bot]
ce0e3bc7f0 fix: invalid revision in re-used manifest cache (#17874) (#17877)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2024-04-18 10:50:19 +03:00
gcp-cherry-pick-bot[bot]
29cdd31572 fix(api): respect all allowed audiences, regardless of check order (#17876) (#17878)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-04-17 21:12:13 -04:00
github-actions[bot]
24ef7775e7 Bump version to 2.11.0-rc2 (#17852)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: pasha-codefresh <pasha-codefresh@users.noreply.github.com>
2024-04-15 22:40:31 +03:00
pasha-codefresh
b71f0c8b54 fix: codegen and e2e tests (#17851)
Signed-off-by: pashakostohrys <pavel@codefresh.io>
2024-04-15 22:35:51 +03:00
pasha-codefresh
edcf167be8 Merge pull request from GHSA-2gvw-w6fj-7m3c
* sec: validate a project before execute an action

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* sec: validate a project before execute an action

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: pashakostohrys <pavel@codefresh.io>
2024-04-15 10:20:07 +03:00
gcp-cherry-pick-bot[bot]
be48990126 fix(api): use arrays instead of map to display ApplicationManifetQuery fields in swagger (#17804) (#17820)
* use arrays instead of map to display ApplicationManifetQuery fields in swagger



* fix equality conditions for souce-position check



---------

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-04-12 16:07:55 -04:00
gcp-cherry-pick-bot[bot]
9d5b17403f chore: rename source-indexes to source-positions (#17746) (#17753)
* chore: rename source-indexes to source-positions



* update documentation



---------

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-04-05 09:39:13 -04:00
github-actions[bot]
f491935eb9 Bump version to 2.11.0-rc1 (#17751)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: pasha-codefresh <pasha-codefresh@users.noreply.github.com>
2024-04-05 15:08:37 +03:00
Michael Crenshaw
040eb36740 fix(security): use Chainguard fork of git-urls (#17732)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-04-04 16:44:43 -04:00
AS
6523f251b8 chore(ui): improve the msg to user when deleteing the resource (#17734)
Signed-off-by: ashutosh16 <11219262+ashutosh16@users.noreply.github.com>
2024-04-04 16:06:50 -04:00
Alexy Mantha
4e46a5e8fa feat(controller): use manifest generate path during comparison (#14242) (#15636)
* squash commits

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* Update util/git/client.go

Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* fix error message

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* add git client options

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* Update generated code

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* run fmt

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* fix tests

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* failed gen

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* tweak logs and rename cache

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* validate revisions

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* fix tests

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* fix tests

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* fmt

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* fix linting

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* fixes from review

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* generate

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* fix

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

* use log context

Signed-off-by: Alexy Mantha <alexy@mantha.dev>

---------

Signed-off-by: Alexy Mantha <alexy@mantha.dev>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-04-04 16:01:11 -04:00
dependabot[bot]
618a4e914b chore(deps): bump library/busybox in /test/e2e/multiarch-container (#17664)
Bumps library/busybox from `650fd57` to `c3839dd`.

---
updated-dependencies:
- dependency-name: library/busybox
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-04-04 09:27:15 -04:00
dependabot[bot]
3654d7f941 chore(deps): bump library/golang from 1.21.3 to 1.21.9 (#17722)
Bumps library/golang from 1.21.3 to 1.21.9.

---
updated-dependencies:
- dependency-name: library/golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-04 09:26:23 -04:00
pasha-codefresh
c09e5b0003 chore: add v2.11 release cadence (#17727) 2024-04-04 12:24:42 +00:00
dependabot[bot]
a4b8c6645b chore(deps): bump library/golang in /test/container (#17721)
Bumps library/golang from 1.21.8 to 1.21.9.

---
updated-dependencies:
- dependency-name: library/golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-04 15:08:50 +03:00
Alexander Matyushentsev
44da2063c7 fix: fix calculating patch for respect ignore diff feature (#17693)
* test: unit test for respectIgnoreDifferences bug

Signed-off-by: Jesse Suen <jesse@akuity.io>

* test: simplify unit test

Signed-off-by: Jesse Suen <jesse@akuity.io>

* fix: fix calculating patch for respect ignore diff feature

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>

---------

Signed-off-by: Jesse Suen <jesse@akuity.io>
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Co-authored-by: Jesse Suen <jesse@akuity.io>
2024-04-03 22:56:59 +00:00
Ishita Sequeira
4b11524242 feat(cli): add support for multiple sources to app diff|manifests command with revisions flag (#17650)
* Add support for multiple source to manifests --revision command

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* Update GetManifests to support multiple sources

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* remove testing logs

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* update cli docs

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* add extra validation for diff command

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* fix lint

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* Empty-Commit

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* revert apimachinery version

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* Update docs based on comments

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

---------

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>
2024-04-03 18:26:56 +00:00
Petr Šťastný
c8d912f104 docs/user-guide/helm.md: fix typo valuesFile (#17716)
Signed-off-by: Petr Šťastný <petr@stastny.eu>
2024-04-03 14:08:25 -04:00
Lukasz
614f44c26c feat(server): Add maxPodLogsToRender setting (#14617)
Signed-off-by: lukasz <lukasz.luszczynski@getyourguide.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-04-03 13:06:12 -04:00
Philipp Trulson
affd1cb251 fix(ui): Fix color generation for pod name in logs viewer. Fixes #17704 (#17706)
* Fix color generation for pod name in logs viewer

Signed-off-by: Philipp Trulson <der-eismann@users.noreply.github.com>

* Add rebuy to users.md

Signed-off-by: Philipp Trulson <der-eismann@users.noreply.github.com>

---------

Signed-off-by: Philipp Trulson <der-eismann@users.noreply.github.com>
2024-04-02 16:12:06 -04:00
Kostis (Codefresh)
405949b127 docs: clarify multiple sources example (#17698)
Signed-off-by: Kostis (Codefresh) <39800303+kostis-codefresh@users.noreply.github.com>
2024-04-02 13:07:58 -04:00
suhas-chikkanna
f287daba0d chore: Update USERS.md (#17683)
Add Shield.com as one of the users in the USER.md file

Signed-off-by: suhas-chikkanna <162577490+suhas-chikkanna@users.noreply.github.com>
2024-04-01 11:08:38 -04:00
Suraj yadav
7deafc4014 feat(ui): metadata.annotations: too long message Improved (#17452)
* metadata.annotations: too long

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* added as a default case

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

---------

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>
2024-03-31 22:16:36 -04:00
Mangaal
766a6da2cd feat: Enhance ArgoCD CLI: Dynamic Repo Server Retrieval with --core and --refresh Flags (#17613)
* add const key value for ComponentRepoServer

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* update NewRepoServerClient() to look for service with  ComponentRepoServer labels , if the label exist construct label selector PortForward

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* add comment for the new constants

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* instead of passing nil which leads to  nil ptr referance error, pass empty ClusterSharding{}

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* check for operator install repo server name

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* handle empty nil ptr dereference error

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* handle  nil prt dereference

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* typo correction

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* run clidocsgen

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

---------

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>
2024-03-29 14:49:16 -04:00
Kostis (Codefresh)
b711c5b7d7 docs: added warning for multiple sources (#17670)
* docs: added warning for multiple sources

Signed-off-by: Kostis (Codefresh) <39800303+kostis-codefresh@users.noreply.github.com>

* docs: minor spelling

Signed-off-by: Kostis (Codefresh) <39800303+kostis-codefresh@users.noreply.github.com>

---------

Signed-off-by: Kostis (Codefresh) <39800303+kostis-codefresh@users.noreply.github.com>
2024-03-29 10:00:50 -04:00
Deniz Erdogan
e26f4fbdc1 docs: 2 link fixes + hint (#17657)
* Update security.md

fix RBAC link

Signed-off-by: Deniz Erdogan <91744937+deer-wmde@users.noreply.github.com>

* Update security.md

Signed-off-by: Deniz Erdogan <91744937+deer-wmde@users.noreply.github.com>

* Update security.md

fix link to application-controller role

Signed-off-by: Deniz Erdogan <91744937+deer-wmde@users.noreply.github.com>

* Update security.md

Signed-off-by: Deniz Erdogan <91744937+deer-wmde@users.noreply.github.com>

---------

Signed-off-by: Deniz Erdogan <91744937+deer-wmde@users.noreply.github.com>
2024-03-28 04:36:35 -10:00
Leonardo Luz Almeida
8631e7ef9b docs: fix contrib meeting time description (#17655)
Signed-off-by: Leonardo Luz Almeida <leoluz@users.noreply.github.com>
2024-03-28 09:57:32 -04:00
pasha-codefresh
ae29279cbe Merge pull request from GHSA-jhwx-mhww-rgc3
* sec: limit helm index max size

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* sec: limit helm index max size

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* feat: fix tests and linter

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: pashakostohrys <pavel@codefresh.io>
2024-03-28 14:38:03 +02:00
dependabot[bot]
53b08426bc chore(deps): bump express from 4.17.3 to 4.19.2 in /ui (#17648)
Bumps [express](https://github.com/expressjs/express) from 4.17.3 to 4.19.2.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.17.3...4.19.2)

---
updated-dependencies:
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-28 13:13:55 +02:00
olivier beyler
4b80393108 Update USERS.md (#17651)
Add arturia as users

Signed-off-by: olivier beyler <beyler_olivier@yahoo.fr>
2024-03-28 00:41:21 -04:00
dependabot[bot]
31aa4d9af9 chore(deps): bump follow-redirects from 1.15.5 to 1.15.6 in /ui-test (#17541)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.5 to 1.15.6.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.5...v1.15.6)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-27 15:56:27 -04:00
github-actions[bot]
e9547bce42 [Bot] docs: Update Snyk reports (#17601)
Signed-off-by: CI <ci@argoproj.com>
Co-authored-by: CI <ci@argoproj.com>
2024-03-27 18:16:25 +00:00
treble-snake
442dac12a7 docs(user-guide): fix a typo (#17642)
Signed-off-by: treble-snake <treble.snake@gmail.com>
2024-03-27 16:39:58 +02:00
danqixu
ad372cf716 wrap error for SyncKeyRingFromDirectory (#17633)
Signed-off-by: danqixu <yzxudanqi@gmail.com>
2024-03-27 09:22:21 -04:00
Michael Crenshaw
1bddee2e5d fix(cmp): pass env to plugin discovery (#13947)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
Co-authored-by: Jann Fischer <jann@mistrust.net>
2024-03-26 12:44:00 -04:00
Wout Scheepers
12ccb52498 docs(goTemplate): Fix bullet list (#17611)
Signed-off-by: Wout Scheepers <wscheep@users.noreply.github.com>
2024-03-26 09:38:26 -04:00
Charles Coupal-Jetté
295dff6a38 fix: Appcontroller respects sync windows (#16492)
* fix: Appcontroller keeps op running when denied by sync window

Signed-off-by: Charles Coupal-Jetté <charles.coupaljette@goto.com>

* fix: Update test name

Signed-off-by: Charles Coupal-Jetté <charles.coupaljette@goto.com>

---------

Signed-off-by: Charles Coupal-Jetté <charles.coupaljette@goto.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-03-26 08:45:35 -04:00
Justin Marquis
a5a499a2c6 chore: update and fix scorecard (#17617)
Signed-off-by: Justin Marquis <justin@akuity.io>
2024-03-25 19:18:09 +00:00
Jann Fischer
f87897c53c chore: Bump Golang to 1.21.8 (#17616)
Signed-off-by: jannfis <jann@mistrust.net>
2024-03-25 13:20:13 -04:00
Mangaal
8cf03812a1 fix: flaky test - app history command not printing source in consistent order (#17615)
* instead if ranging over the map varHistory to print the history, inroduced a string array varHistoryKeys

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* update unit test expectation, remove new line in the beginning

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

---------

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>
2024-03-25 16:58:56 +00:00
Mangaal
38d86a911e feat: Update command argocd app history to support multiple sources (#17530)
* update argocd app history command to print app history group by thier sources along with all the REVISIONS

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* upadte unit test to ahve both Source and Sources and update function to overlooked source if sources is persent

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* remove magic no 7 and introduc a variable MAX_ALLOWED_REVISIONS

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* remove extra unit test

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* remove extra unit test TestPrintApplicationHistoryTableForWhenBothSourcesAndSourceFiledsExist()

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

---------

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-03-25 11:29:03 -04:00
Nathan Romriell
c4fdc54195 fix(repo-server): excess git requests, add shared cache lock on revisions (Issue #14725) (#17109)
* fix(repo-server): excess git requests, cache lock on revisions

Signed-off-by: nromriell <nateromriell@gmail.com>

* fix: pr feedback, simplify, add configurable variable

Signed-off-by: nromriell <nateromriell@gmail.com>

* fix: codegen, lint

Signed-off-by: nromriell <nateromriell@gmail.com>

* fix: test print, no opts set, var type nit

Signed-off-by: nromriell <nateromriell@gmail.com>

* chore: add additional logging for unexpected cache error

Signed-off-by: nromriell <nateromriell@gmail.com>

---------

Signed-off-by: nromriell <nateromriell@gmail.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-03-25 11:26:14 -04:00
Vipin M S
37c5f4d8ee Adds count of resource on resource tile (#14904)
Signed-off-by: Vipin M S <vipinachar2016@gmail.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-03-24 01:56:54 +00:00
Alexandre Gaudreault
a49880e0a5 fix: invalid badge validation (#15507) (#17580)
* fix: invalid badge validation

Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>

* use util methods

Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>

* rfc accept both lower and upper

Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>

* fix unit test affecting each other with var modification

Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>

---------

Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
Co-authored-by: Jann Fischer <jann@mistrust.net>
2024-03-23 16:35:38 -04:00
dependabot[bot]
2b28683419 chore(deps): bump ip from 1.1.5 to 1.1.9 in /ui (#17256)
Bumps [ip](https://github.com/indutny/node-ip) from 1.1.5 to 1.1.9.
- [Commits](https://github.com/indutny/node-ip/compare/v1.1.5...v1.1.9)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-03-22 15:45:11 -04:00
dependabot[bot]
ec7b49d82d chore(deps): bump docker/login-action from 2.2.0 to 3.1.0 (#17524)
Bumps [docker/login-action](https://github.com/docker/login-action) from 2.2.0 to 3.1.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](465a07811f...e92390c5fb)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-22 19:08:38 +00:00
dependabot[bot]
f0490090cd chore(deps): bump follow-redirects from 1.15.5 to 1.15.6 in /ui (#17542)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.5 to 1.15.6.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.5...v1.15.6)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-22 14:22:20 -04:00
dependabot[bot]
427965c497 chore(deps-dev): bump postcss from 8.4.37 to 8.4.38 in /ui (#17582)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.37 to 8.4.38.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.37...8.4.38)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-22 14:21:51 -04:00
dependabot[bot]
7350a55e57 chore(deps): bump webpack-dev-middleware from 5.3.1 to 5.3.4 in /ui (#17598)
Bumps [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) from 5.3.1 to 5.3.4.
- [Release notes](https://github.com/webpack/webpack-dev-middleware/releases)
- [Changelog](https://github.com/webpack/webpack-dev-middleware/blob/v5.3.4/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-middleware/compare/v5.3.1...v5.3.4)

---
updated-dependencies:
- dependency-name: webpack-dev-middleware
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-22 14:21:14 -04:00
dependabot[bot]
3ec63b222c chore(deps): bump slsa-framework/slsa-github-generator (#17593)
Bumps [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) from 1.9.0 to 1.10.0.
- [Release notes](https://github.com/slsa-framework/slsa-github-generator/releases)
- [Changelog](https://github.com/slsa-framework/slsa-github-generator/blob/main/CHANGELOG.md)
- [Commits](https://github.com/slsa-framework/slsa-github-generator/compare/v1.9.0...v1.10.0)

---
updated-dependencies:
- dependency-name: slsa-framework/slsa-github-generator
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-22 13:11:54 -04:00
Jann Fischer
d11e146ab5 chore: Fix linter issue with session manager (#17597)
Signed-off-by: jannfis <jann@mistrust.net>
2024-03-22 15:05:18 +00:00
dependabot[bot]
1c938e2aea chore(deps-dev): bump postcss from 8.4.36 to 8.4.37 in /ui (#17573)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.36 to 8.4.37.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.36...8.4.37)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-20 07:29:58 -04:00
Suraj yadav
5ada5c2810 feat(UI): Added link for docs to add clusters (#17395)
* cluster-add-link

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* docs

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* docs-panel

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* added

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* fixed

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

---------

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>
2024-03-19 23:06:34 -04:00
Ishita Sequeira
ed0218f98e feat: add cli commands to create/set/unset/edit sources for multi-source application (#17425)
* "feat:add cli commands to create/set/unset/edit sources for multi-source app"

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* fixed the ci failure

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* update commands

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* error out if source-index not specified for multi-source applications

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* fixed the ci failure

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* fix tests

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* set 0 as default source index for app create

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* add index to ParameterOverrides function

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* do not allow overrides for applications with multiple sources

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* update tests

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* remove create with override example

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* address comments

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* update tests

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* update examples in docs

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* update logs

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* Add test and update docs

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

---------

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>
2024-03-18 11:15:08 -07:00
ario0
997688e94b docs: mention that the argocd diff command does not include secrets (#15950)
* doc(cli): update argocd_app_diff

Adding the fact that secrets are ignored by the diff (not really stated in the doc so far)

Signed-off-by: ario0 <118843430+ario0@users.noreply.github.com>

* doc: remove whitespace

Signed-off-by: ario0 <118843430+ario0@users.noreply.github.com>

---------

Signed-off-by: ario0 <118843430+ario0@users.noreply.github.com>
Signed-off-by: Alexis Renard <renard.alexis@hotmail.fr>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-03-18 10:47:47 -07:00
dependabot[bot]
09407a21be chore(deps): bump library/registry in /test/container (#17554)
Bumps library/registry from `f4e1b87` to `fb9c9ae`.

---
updated-dependencies:
- dependency-name: library/registry
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-18 19:04:55 +02:00
dependabot[bot]
16fc00841e chore(deps-dev): bump postcss from 8.4.35 to 8.4.36 in /ui (#17555)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.35 to 8.4.36.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.35...8.4.36)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-18 19:03:38 +02:00
jannfis
d69c61ae1a Merge pull request from GHSA-6v85-wr92-q4p7
* fix: Fix concurrency issue in session manager

Signed-off-by: jannfis <jann@mistrust.net>

* Add note that modification to the map must be done in a thread safe manner

* chore: fix linter issues

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: jannfis <jann@mistrust.net>
Signed-off-by: pashakostohrys <pavel@codefresh.io>
Co-authored-by: Dan Garfield <dan@codefresh.io>
Co-authored-by: pashakostohrys <pavel@codefresh.io>
2024-03-18 03:59:06 -04:00
pasha-codefresh
6596e088ac Merge pull request from GHSA-2vgg-9h6w-m454
* feat: pick random user and exclude admin user and current user from deletion candidates

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* feat: increase default max cache size

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* add nil protection

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* Update util/session/sessionmanager.go

Signed-off-by: Dan Garfield <dan@codefresh.io>

Signed-off-by: Dan Garfield <dan@codefresh.io>

* chore: fix linter issues

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: pashakostohrys <pavel@codefresh.io>
Signed-off-by: Dan Garfield <dan@codefresh.io>
Co-authored-by: Dan Garfield <dan@codefresh.io>
2024-03-18 03:58:18 -04:00
Mangaal
63a72ee1e7 docs: Update the status of the feature, app in any namespace, from beta to stable (#17529)
* Update the status of the feature, app in any namespace, from beta to stable

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* adding warning and removing **Current feature state**

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

---------

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>
2024-03-15 17:26:32 -04:00
AS
2f58d73612 fix(ui): add confirmation box in resource summary delete action (#17485)
Signed-off-by: ashutosh16 <11219262+ashutosh16@users.noreply.github.com>
2024-03-15 12:06:25 -04:00
dependabot[bot]
2b75efd24a chore(deps): bump docker/build-push-action from 5.2.0 to 5.3.0 (#17537)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5.2.0 to 5.3.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](af5a7ed5ba...2cdde995de)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-15 11:03:28 -04:00
David Bunn
aaabb050b2 chore(deps): upgrade helm to 3.14.3 (#17531)
* chore(deps): upgrade helm to 3.14.3

Signed-off-by: David Bunn <david.bunn@prodigygame.com>

* chore(deps): upgrade helm to 3.14.3

Signed-off-by: David Bunn <david.bunn@prodigygame.com>

---------

Signed-off-by: David Bunn <david.bunn@prodigygame.com>
2024-03-14 17:33:20 +00:00
danqixu
4a92ab782f chore: Add error messages to return statements in BlockingDial function (#17521)
* Add error messages to return statements in BlockingDial function

Signed-off-by: danqixu <yzxudanqi@gmail.com>

* amend error wrapping from %s to %w

Signed-off-by: danqixu <yzxudanqi@gmail.com>

---------

Signed-off-by: danqixu <yzxudanqi@gmail.com>
2024-03-14 03:33:40 +00:00
dependabot[bot]
739fa0c26e chore(deps): bump actions/checkout (#17493)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3df4ab11eba7bda6032a0b82a6bb43b11571feac to 8410ad0602e1e429cee44a835ae9f77f654a6694.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](3df4ab11eb...8410ad0602)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-13 23:27:04 -04:00
Alexander Matyushentsev
138b37bd6c fix: Argo CD unnecessary enforce sequential helm manifest generation for one chart (#17518)
* fix: Argo CD unnecessary enforce sequential helm manifest generation for one chart

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>

* Update docs/operator-manual/high_availability.md

Signed-off-by: Dan Garfield <dan@codefresh.io>

---------

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Signed-off-by: Dan Garfield <dan@codefresh.io>
Co-authored-by: Dan Garfield <dan@codefresh.io>
2024-03-13 23:39:39 +00:00
Andreas Hunkeler
77899cb285 docs: add attestation of SBOM to release assets in signed-release-assets.md (#17520)
Closes https://github.com/argoproj/argo-cd/issues/17200.

Signed-off-by: Andreas Hunkeler <karneades@protonmail.com>
2024-03-13 15:06:30 -06:00
Savely Kalinov
f0b03071fc feat: Add support to enable FullTimeStamp in logging (#15127)
* Add support to enable FullTimeStamp in logging
Signed-off-by: skalinov <skalinov@tradingview.com>

* fix: Fix go linter file exist issue
Signed-off-by: skalinov <skalinov@tradingview.com>

* fix: Remove --skip-pkg-cache
Signed-off-by: skalinov <skalinov@tradingview.com>

* Update util/log/logrus_test.go

Use custom set env for prevent linter to be failed

Signed-off-by: pasha-codefresh <pavel@codefresh.io>

* Update common/common.go

Signed-off-by: Dan Garfield <dan@codefresh.io>

* Update util/log/logrus_test.go

Signed-off-by: pasha-codefresh <pavel@codefresh.io>

* Update util/log/logrus_test.go

remove os import

Signed-off-by: pasha-codefresh <pavel@codefresh.io>

* Update util/log/logrus_test.go

sort dependencies

Signed-off-by: pasha-codefresh <pavel@codefresh.io>

* fix formatting

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: pasha-codefresh <pavel@codefresh.io>
Signed-off-by: Dan Garfield <dan@codefresh.io>
Signed-off-by: pashakostohrys <pavel@codefresh.io>
Co-authored-by: skalinov <skalinov@tradingview.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
Co-authored-by: Dan Garfield <dan@codefresh.io>
2024-03-13 20:19:26 +00:00
Michael Crenshaw
3b8f673f06 Merge pull request from GHSA-g623-jcgg-mhmm
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-03-13 14:28:43 -04:00
RyotaK
479b5544b5 Merge pull request from GHSA-jwv5-8mqv-g387
* fix: Validate external URLs for applicatins

Signed-off-by: Ry0taK <49341894+Ry0taK@users.noreply.github.com>

* fix(ui): remove invalid external-link

Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>

* linting

Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>

---------

Signed-off-by: Ry0taK <49341894+Ry0taK@users.noreply.github.com>
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
Co-authored-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2024-03-13 14:26:47 -04:00
Blake Pettersson
51cfd50dd9 fix: elements should be optional (#17424)
A bug was reported, where an applicationset with an empty elements
array, when created with `argocd appset create <filename>.yaml` gets a
`...list.elements: Required value` error.

My hypothesis is that when calling the K8s API, golang JSON marshalling
mangles the empty `elements` array to `nil`, rather than creating an
empty array when submitting the `POST`.

Still need to figure out why the same setup seemingly works fine when
the same appset is in an app-of-apps.

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-03-13 09:52:19 -07:00
Hoang Quoc Trung
85a2145401 Add documentation for google transitive groups (#9487)
Signed-off-by: Trung <trung.hoang@pricehubble.com>
Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-03-13 17:39:26 +02:00
Mario Adrián Domínguez González de Eiris
27c174384b docs: Add note in installation step 1 with argocd cli (#8030)
* Add note in installation stesps

Added notes in installation step 1: 
kubectl config set-context --current --namespace=argocd

* Updated doc

* Update docs/getting_started.md

Signed-off-by: Dan Garfield <dan@codefresh.io>

---------

Signed-off-by: Dan Garfield <dan@codefresh.io>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
Co-authored-by: Dan Garfield <dan@codefresh.io>
2024-03-13 17:26:50 +02:00
Harshvir Potpose
be69bcc010 docs: added all available fields for applicationset.yaml #16095 (#16104)
* adding all available filds for generators

Signed-off-by: Harshvir Potpose <hpotpose62@gmail.com>

* add remaining fields in applicationset.yml

Signed-off-by: Harshvir Potpose <hpotpose62@gmail.com>

* Update docs/operator-manual/applicationset.yaml

Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: Harshvir Potpose <122517264+akagami-harsh@users.noreply.github.com>

* Update docs/operator-manual/applicationset.yaml

Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: Harshvir Potpose <122517264+akagami-harsh@users.noreply.github.com>

* Update docs/operator-manual/applicationset.yaml

Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: Harshvir Potpose <122517264+akagami-harsh@users.noreply.github.com>

* Update docs/operator-manual/applicationset.yaml

Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: Harshvir Potpose <122517264+akagami-harsh@users.noreply.github.com>

* fix

Signed-off-by: Harshvir Potpose <hpotpose62@gmail.com>

---------

Signed-off-by: Harshvir Potpose <hpotpose62@gmail.com>
Signed-off-by: Harshvir Potpose <122517264+akagami-harsh@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-03-13 15:24:52 +00:00
Dan Garfield
f4bb860fb8 Make evergreen (#17507)
This example uses an old revision `v1.0.1` instead it should just use stable.

Signed-off-by: Dan Garfield <dan@codefresh.io>
2024-03-13 17:23:57 +02:00
dependabot[bot]
565aa8e1f5 chore(deps): bump library/node in /test/container (#17494)
Bumps library/node from `f358dfc` to `b9ccc4a`.

---
updated-dependencies:
- dependency-name: library/node
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-03-13 12:12:57 +02:00
dependabot[bot]
e4885db6ad chore(deps): bump library/redis in /test/container (#17496)
Bumps library/redis from `e647cfe` to `7dd7070`.

---
updated-dependencies:
- dependency-name: library/redis
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-03-13 10:49:02 +02:00
dependabot[bot]
0b5d9afd40 chore(deps): bump library/golang in /test/container (#17495)
Bumps library/golang from `34ce21a` to `0b55ab8`.

---
updated-dependencies:
- dependency-name: library/golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-13 09:51:49 +02:00
dependabot[bot]
2a747c65ed chore(deps): bump library/node from 21.7.0 to 21.7.1 in /ui-test (#17498)
Bumps library/node from 21.7.0 to 21.7.1.

---
updated-dependencies:
- dependency-name: library/node
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-13 09:49:43 +02:00
Xavier Krantz
5b77e8d448 docs(EKS): Fix ArgoCD management role AssumeRole policy for IRSA (#17455)
Signed-off-by: Xavier Krantz <xakraz@gmail.com>
2024-03-12 21:46:00 -04:00
similark
86369ca71d fix(appset): keep reconciling even when params error occurred (#17062)
* fix(appset): keep reconcile even when params error occurred

Signed-off-by: Or Koren <or.koren@similarweb.com>

* requeue on generator rendering error

Signed-off-by: Or Koren <or.koren@similarweb.com>

* test ignoring partial rendering errors

Signed-off-by: Or Koren <or.koren@similarweb.com>

* e2e test create app with param error

Signed-off-by: Or Koren <or.koren@similarweb.com>

---------

Signed-off-by: Or Koren <or.koren@similarweb.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-03-12 21:20:28 -04:00
jannfis
7cfb9d6e13 chore: Support running and testing locally using podman instead of docker (#17481)
* chore: Support rootless podman for run/test

Signed-off-by: jannfis <jann@mistrust.net>

* Note DOCKER env in docs

Signed-off-by: jannfis <jann@mistrust.net>

---------

Signed-off-by: jannfis <jann@mistrust.net>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-03-13 00:02:20 +00:00
Michael Crenshaw
ff055300a2 docs: remove configManagementPlugins from argocd-cm.yaml (#17486)
That field is no longer supported.

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-03-12 16:13:19 -04:00
dependabot[bot]
de44e14d90 chore(deps): bump docker/build-push-action from 5.1.0 to 5.2.0 (#17463)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5.1.0 to 5.2.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](4a13e500e5...af5a7ed5ba)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-03-12 13:33:37 -04:00
jannfis
e60996814e chore: Fix containerized toolchain (#17480)
Signed-off-by: jannfis <jann@mistrust.net>
2024-03-12 19:09:39 +02:00
Pablo Aguilar
57d6e6557b fix: registry argument to be only the host instead full URL (#17381)
Signed-off-by: Pablo Aguilar <pablo.aguilar@outlook.com.br>
2024-03-12 10:21:53 -04:00
pasha-codefresh
dd29300fc1 fix(notifications): Helm.GetParameterValueByName should take helm.parametes first (#17472)
* fix: Helm.GetParameterValueByName should take helm.parametes first

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix linters

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: pashakostohrys <pavel@codefresh.io>
2024-03-12 10:06:24 -04:00
dependabot[bot]
dc242da748 chore(deps): bump library/golang in /test/container (#17415)
Bumps library/golang from 1.21.3 to 1.22.1.

---
updated-dependencies:
- dependency-name: library/golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-12 10:40:54 +02:00
dependabot[bot]
76c64796cc chore(deps): bump library/node from 21.6.2 to 21.7.1 in /test/container (#17475)
Bumps library/node from 21.6.2 to 21.7.1.

---
updated-dependencies:
- dependency-name: library/node
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-12 10:39:43 +02:00
Jonas Bakken
6ca29a3c0b docs: fix kustomize example resources url (#17468)
Signed-off-by: Jonas Bakken <jonasbakken@protonmail.com>
2024-03-11 19:18:18 +02:00
github-actions[bot]
cc235e4a06 [Bot] docs: Update Snyk reports (#17458)
Signed-off-by: CI <ci@argoproj.com>
Co-authored-by: CI <ci@argoproj.com>
2024-03-11 15:57:49 +00:00
Anirudh Sudhir
05eea87162 feat: add option manual to the --sync-policy flag of the app create command (#17459)
* feat: add sync policy option 'manual' for app create command

Signed-off-by: Anirudh Sudhir <anirudh.sudhir1@gmail.com>

* chore: Update tests to reflect sync policy option changes

Signed-off-by: Anirudh Sudhir <anirudh.sudhir1@gmail.com>

---------

Signed-off-by: Anirudh Sudhir <anirudh.sudhir1@gmail.com>
2024-03-11 16:36:15 +02:00
avoidalone
085ed0f65a chore: remove repetitive words (#17464)
Signed-off-by: avoidalone <wuguangdong@outlook.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-03-11 14:27:46 +00:00
dependabot[bot]
9b965700b3 chore(deps): bump library/ubuntu in /test/container (#17414)
Bumps library/ubuntu from `f9d633f` to `77906da`.

---
updated-dependencies:
- dependency-name: library/ubuntu
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-11 16:24:24 +02:00
mamccorm
31776d49f4 make CGO_ENABLED configurable (#17462)
Signed-off-by: Mark McCormick <mark.mccormick@chainguard.dev>
2024-03-11 13:51:53 +02:00
dependabot[bot]
de4cac4165 chore(deps): bump library/node from 21.6.2 to 21.7.0 in /ui-test (#17444)
Bumps library/node from 21.6.2 to 21.7.0.

---
updated-dependencies:
- dependency-name: library/node
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-11 13:19:18 +02:00
dependabot[bot]
0fe1acb357 chore(deps): bump library/busybox in /test/e2e/multiarch-container (#17445)
Bumps library/busybox from `3fbc632` to `650fd57`.

---
updated-dependencies:
- dependency-name: library/busybox
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-11 13:17:13 +02:00
Joe Wingard
da49d3eed9 add Oncourse Home (#17457) 2024-03-11 10:50:40 +00:00
Ikko Eltociear Ashimine
542890f739 docs: Update site.md (#17454)
erros -> errors

Signed-off-by: Ikko Eltociear Ashimine <eltociear@gmail.com>
2024-03-09 08:12:48 -05:00
Aiman Ismail
fd3462e9c0 docs: dex google oidc: add note on dex connector type (#17453)
Signed-off-by: Aiman Ismail <m.aimanismail@gmail.com>
2024-03-08 18:58:03 -05:00
Justin Marquis
1901cb56bc chore: update slsa3 generate (#17451)
Signed-off-by: Justin Marquis <justin@akuity.io>
2024-03-08 18:44:19 +00:00
Justin Marquis
3fee8cbf81 chore: update cosign and version (#17441)
* chore: update cosign and version

Signed-off-by: Justin Marquis <justin@akuity.io>

* fix typo

Signed-off-by: Justin Marquis <justin@akuity.io>

---------

Signed-off-by: Justin Marquis <justin@akuity.io>
2024-03-08 07:09:02 -05:00
Nguyen Thai
98a888ed52 Fixed project parameter docs for Gitlab pull request generator (#17429)
Signed-off-by: Nguyen Thai <tknguyen@linagora.com>
2024-03-07 22:32:34 -05:00
Albin Björk
7bb92d7d61 docs: re-worded updated a link in release-process-and-cadance.md (#17438)
Signed-off-by: AlbinB97 <devalbinbjork@gmail.com>
2024-03-07 22:19:01 -05:00
Collin Walker
2b6b9bf93e chore: Fix Helm Installation Breaking on Mac (#17426)
* fix helm installation to work with mac

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* fix checksums

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* change install filename and makefile

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* change name to just helm - fix dockerfile

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

---------

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>
2024-03-07 20:35:37 -05:00
dependabot[bot]
2ad06a6308 chore(deps): bump github.com/go-jose/go-jose/v3 from 3.0.1 to 3.0.3 (#17442)
Bumps [github.com/go-jose/go-jose/v3](https://github.com/go-jose/go-jose) from 3.0.1 to 3.0.3.
- [Release notes](https://github.com/go-jose/go-jose/releases)
- [Changelog](https://github.com/go-jose/go-jose/blob/v3.0.3/CHANGELOG.md)
- [Commits](https://github.com/go-jose/go-jose/compare/v3.0.1...v3.0.3)

---
updated-dependencies:
- dependency-name: github.com/go-jose/go-jose/v3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-07 19:36:25 -05:00
Carlos Santana
edc6f5f39e feat: Allow mkdocs to livereload when using docker (#17383)
* feat: Allow mkdocs to livereload when using docker

Signed-off-by: Carlos Santana <csantana23@gmail.com>

* update the docs

Signed-off-by: Carlos Santana <csantana23@gmail.com>

---------

Signed-off-by: Carlos Santana <csantana23@gmail.com>
2024-03-07 15:03:26 -05:00
Alexander Matyushentsev
138a112172 docs: proposal to implement sync timeout and termination settings (#16630)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2024-03-07 16:46:02 +00:00
Caio Paiva
fda25d0b93 fix(ui): align resource nodegroup (#17427)
Signed-off-by: Caio Paiva <cclp94@gmail.com>
2024-03-07 09:52:54 -05:00
Pelen
d76976ff12 fix: add retry condition with kube-apiserver sent GOAWAY (#17422)
Signed-off-by: penglongli <pelenli@tencent.com>
2024-03-07 09:50:34 -05:00
Nate Douglas
8aa9625870 docs: Small edits to docs/user-guide/application-set.md (#17434)
* Update application-set.md

Signed-off-by: Nate Douglas <ndouglas@users.noreply.github.com>

* Make example code consistent with examples elsewhere.

Signed-off-by: Nathan Douglas <github@darkdell.net>

---------

Signed-off-by: Nate Douglas <ndouglas@users.noreply.github.com>
Signed-off-by: Nathan Douglas <github@darkdell.net>
2024-03-07 09:34:53 -05:00
Takahiro Suzuki
0c2934a339 docs: Clarify for valueFiles behaviour with path field (#17431)
This commit adds clarification by explaining that `valueFiles` must be a relative path to the root of sources, even if the `path` field is set.

Signed-off-by: Takahiro Suzuki <tkasuz.dev@gmail.com>
Signed-off-by: tkasuz <takahiro.suzuki@hennge.com>
2024-03-07 08:53:48 -05:00
Mangaal
0d020f0079 feat(cli): enable --app-namespace flag for argocd app subcommand (#17437)
* add --app-namespace flag for set/unset command

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* add --app-namespace flag for add-source/remove-source command

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* fix bug, handle array out of-bound when --source-index=len(source)

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* add documentation

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

---------

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>
2024-03-07 13:38:43 +00:00
John
d0331eefe4 docs: remove repetitive words (#17430)
Signed-off-by: hishope <csqiye@126.com>
2024-03-07 10:49:22 +01:00
Duncan
1b919879ab docs (aks cluster): update workloadidentity documentation (#17401)
Signed-off-by: duncan485 <bakkerduncan@gmail.com>
2024-03-06 13:18:59 -07:00
Nate Douglas
58993b1a01 docs: Fix some awkward phrasing in core.md (#17412)
Signed-off-by: Nate Douglas <ndouglas@users.noreply.github.com>
2024-03-06 21:06:16 +01:00
Bogay
4db89427a8 fix(grpcproxy): parse headers contain colon (#13274) (#14294)
* fix(grpcproxy): parse headers contain colon

Signed-off-by: bogay <pojay11523@gmail.com>

* test(apiclient): headers in wrong format

Signed-off-by: bogay <pojay11523@gmail.com>

---------

Signed-off-by: bogay <pojay11523@gmail.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-03-06 14:23:50 -05:00
Leonardo Luz Almeida
8786ec243a chore: add more unit tests around useDiffCache function (#17404)
* chore: add more unit tests around useDiffCache function

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>

* fix doc

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>

---------

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2024-03-05 19:19:09 -05:00
Suraj yadav
ee78d02a42 fix(ui): application-summary-help-icon fix (#17385)
* Update application-summary.tsx

revision-history icon fix

Signed-off-by: Suraj yadav <harrypotter1108@gmail.com>

* icons

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

---------

Signed-off-by: Suraj yadav <harrypotter1108@gmail.com>
Signed-off-by: Surajyadav <harrypotter1108@gmail.com>
2024-03-05 16:56:01 -05:00
Suraj yadav
24ac326384 fix(ui): Highlight failing containers in the UI (#17143)
* failing container icon added

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* lint-fix

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* ..

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* tried yarn lint-fix

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* margin

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* running

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

---------

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>
2024-03-04 18:15:30 -05:00
Collin Walker
839526e976 feat: Allow Kustomize common labels to not apply to selectors (#17329)
* modify crds

Signed-off-by: Collin <cwalker@ancestry.com>
Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* cmd opts and test

Signed-off-by: Collin <cwalker@ancestry.com>
Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* kustomize build and test

Signed-off-by: Collin <cwalker@ancestry.com>
Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* fix option order and add ancestry to users

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* fix users format

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* generated files

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* set flag value

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* modify crds

Signed-off-by: Collin <cwalker@ancestry.com>
Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* chore(deps): bump library/registry in /test/container (#17317)

Bumps library/registry from `b209a41` to `f4e1b87`.

---
updated-dependencies:
- dependency-name: library/registry
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Collin <cwalker@ancestry.com>
Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* generated files

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* add docs

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* fix doc

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* remove debug prints

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

* fix autogen docs

Signed-off-by: lets-call-n-walk <cw404@hotmail.com>

---------

Signed-off-by: Collin <cwalker@ancestry.com>
Signed-off-by: lets-call-n-walk <cw404@hotmail.com>
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Collin Walker <10523817+lets-call-n-walk@users.noreply.github.com>
Co-authored-by: Collin <cwalker@ancestry.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-04 18:13:34 -05:00
DongHo Jung
7eda6e01f4 docs: use service-name instead of service-id (#17389)
* use service-name instead of service-id

Signed-off-by: DongHo Jung <dongho971220@gmail.com>

* trigger CICD

Signed-off-by: DongHo Jung <dongho971220@gmail.com>

---------

Signed-off-by: DongHo Jung <dongho971220@gmail.com>
2024-03-04 10:48:28 -07:00
Soumya Ghosh Dastidar
88e4da625e fix: disable rate limiting sompletely by default (#17355)
Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
2024-03-04 10:46:55 -05:00
Eric Bissonnette
e2f87940e4 fix: preserve escape codes in repo url of git webhook payload (#17376)
Signed-off-by: Eric Bissonnette <ebisso.dev@gmail.com>
2024-03-04 11:03:19 +02:00
Mangaal
82e20a4fc9 feat: enable users to run commands related to Argo Applications in any namespace (#17360)
* enable --app-namespace falg for application get command

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* enable --app-namespace falg for application diff command

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* enable --app-namespace falg for application wait command

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* enable --app-namespace falg for application rollback command

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* enable --app-namespace falg for application patch command

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* enable --app-namespace falg for application edit command

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* enable --app-namespace falg for application history command

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* enable --app-namespace falg for application sync  command

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* enable --app-namespace falg for application delete  command

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

* cli doc generated

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>

---------

Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-03-01 17:35:31 -05:00
Ishita Sequeira
3cf54af2be feat: add cli commands to add/remove sources for multi-source applications (#17310)
* Initial commit

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* add cli commands to add/remove sources for multi-source app

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* add checks

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* add docs

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* refactor code and update tests

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* add removed additional switch case

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* fix suggested nits

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

---------

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>
2024-03-01 22:13:14 +00:00
Suraj yadav
e3ee9ee831 fix(ui): Dark-mode-enhancements (#17241)
* dark-mode-enhancements

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* monaco

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

---------

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>
Signed-off-by: Suraj yadav <harrypotter1108@gmail.com>
2024-03-01 15:56:09 -05:00
Michael Crenshaw
28112c65a4 chore(ci): free up disk space for goreleaser (#17373)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-03-01 20:39:31 +00:00
Blake Pettersson
99128c27f5 feat: add ability to auto label clusters from k8s clusterinfo (#17289)
* feat: add ability to auto label clusters

This gives the ability to automatically label cluster secrets on a cluster-by-cluster basis. If `enableClusterInfoLabels` is set on a cluster secret, the controller will (eventually) label the cluster secret with the current k8s version detected by the cluster info.

This needs documentation, e2e tests, as well as CLI/UI additions.

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>

* refactor: use labels instead of secret data

This is easier to work with, especially in the context where we need
this feature.

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>

* docs: add description on how to use dynamic labeling

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>

---------

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-03-01 15:18:19 -05:00
Raghavi
e9b1af5885 feat: add cli commands to add/delete sourceNamespaces from AppProject (#17337)
* Add cli to add/delete sourceNamespaces

Signed-off-by: Raghavi Shirur <rshirur@redhat.com>

* update command/comments

Signed-off-by: Raghavi Shirur <rshirur@redhat.com>

* update command/comments(1)

Signed-off-by: Raghavi Shirur <rshirur@redhat.com>

* update user-guide docs

Signed-off-by: Raghavi Shirur <rshirur@redhat.com>

* Retrigger CI pipeline

Signed-off-by: Raghavi Shirur <rshirur@redhat.com>

* add check for '*' & rename command to remove-source-namespace

Signed-off-by: Raghavi Shirur <rshirur@redhat.com>

* update command/comments(2)

Signed-off-by: Raghavi Shirur <rshirur@redhat.com>

* update command/comments(3)

Signed-off-by: Raghavi Shirur <rshirur@redhat.com>

* Retrigger CI pipeline

Signed-off-by: Raghavi Shirur <rshirur@redhat.com>

---------

Signed-off-by: Raghavi Shirur <rshirur@redhat.com>
2024-03-01 14:07:27 -05:00
Andrea Sannuto
f132628866 docs: Update USERS.md (#17371)
Hi, I added IABAI as using officially ArgoCD

Signed-off-by: Andrea Sannuto <andrea@iab.ai>
2024-03-01 13:58:02 -05:00
Enclavet
d73304ea1c feat: Add app data to sharding cache to allow sharding by apps (#17014)
* Adding app list to sharding cache

Signed-off-by: Andrew Lee <andrewkl@enclavenet.com>

* Add shard by apps test

Signed-off-by: Andrew Lee <andrewkl@enclavenet.com>

* Fix lint

Signed-off-by: Andrew Lee <andrewkl@enclavenet.com>

* Add coverage to test

Signed-off-by: Andrew Lee <andrewkl@enclavenet.com>

* Fix lint

Signed-off-by: Andrew Lee <andrewkl@enclavenet.com>

* Converted cluster/app accesors to private, add apps-in-any-namespace suport in shardingcache init, added read lock to GetAppDistribution

Signed-off-by: Andrew Lee <andrewkl@enclavenet.com>

* Fix tests

Signed-off-by: Andrew Lee <andrewkl@enclavenet.com>

---------

Signed-off-by: Andrew Lee <andrewkl@enclavenet.com>
2024-03-01 13:56:48 -05:00
Arthur Outhenin-Chalandre
62003f0152 feat: allow webhook settings to be referenced by external secret (#16262)
Signed-off-by: Arthur Outhenin-Chalandre <arthur.outhenin-chalandre@ledger.fr>
2024-02-29 13:58:38 +02:00
Michael Firestone
d4251ef7cf chore(notifications): remove unneeded operations from templates (#17307)
* chore(deps): bump library/ubuntu in /test/container (#13409)

Bumps library/ubuntu from `9a0bdde` to `67211c1`.

---
updated-dependencies:
- dependency-name: library/ubuntu
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Michael Firestone <mike.firestone@electriphi.ai>

* rm unneeded operations from templates

Signed-off-by: Michael Firestone <firestonem@gmail.com>
Signed-off-by: Michael Firestone <mike.firestone@electriphi.ai>

* rm more unneeded ops

Signed-off-by: Michael Firestone <mike.firestone@electriphi.ai>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Michael Firestone <mike.firestone@electriphi.ai>
Signed-off-by: Michael Firestone <firestonem@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Michael Firestone <mike.firestone@electriphi.ai>
2024-02-29 13:54:15 +02:00
Rafal
a4b5051538 fix(ui): The tiles in Applications List are too wide #17220 (#17340)
* fix(ui): The tiles in Applications List are too wide

Signed-off-by: Rafal Pelczar <rafal@akuity.io>

* change min width of app tiles

Signed-off-by: Rafal Pelczar <rafal@akuity.io>

---------

Signed-off-by: Rafal Pelczar <rafal@akuity.io>
2024-02-28 19:42:20 +00:00
Alexander Matyushentsev
bb4e47a12d fix: The argocd server api-content-type flag does not allow empty content-type header (#17331)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2024-02-28 09:45:44 -08:00
dependabot[bot]
c973f7013b chore(deps): bump library/node from 21.6.1 to 21.6.2 in /test/container (#17316)
Bumps library/node from 21.6.1 to 21.6.2.

---
updated-dependencies:
- dependency-name: library/node
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-28 11:47:58 +02:00
David Bunn
e492e1469c chore(deps): upgrade helm to 3.14.2 (#17330)
* chore(deps): upgrade helm to 3.14.2

Signed-off-by: David Bunn <david.bunn@prodigygame.com>

* Signing commit

Signed-off-by: David Bunn <david.bunn@prodigygame.com>

---------

Signed-off-by: David Bunn <david.bunn@prodigygame.com>
2024-02-27 20:48:41 -05:00
Keith Chong
48f4392b26 fix: multi-source app breaks application parameters UI (#16910) (#17033)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2024-02-27 20:15:50 -05:00
Suraj yadav
8b89722eee fix(ui): Added dashed line between collapsed sections in Compact-diff (#17173)
* dashed-line-breaker

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* dark-mode

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* dark-mode-text-fix

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

---------

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>
2024-02-27 16:39:47 -05:00
Juliusz Jaksa
5ffbca4cce docs: fixed name of environment variable and config map property enabling scm providers for applicationsets (#17326)
Signed-off-by: Juliusz <juliusz.jaksa@xylem.com>
Co-authored-by: Juliusz <juliusz.jaksa@xylem.com>
2024-02-27 16:36:07 -05:00
dependabot[bot]
d42004fa86 chore(deps): bump library/registry in /test/container (#17317)
Bumps library/registry from `b209a41` to `f4e1b87`.

---
updated-dependencies:
- dependency-name: library/registry
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-27 19:48:59 +02:00
Carlos Santana
891d089304 fix: use simple python image to build mkdocs (#17313)
* fix: use simple python image to build mkdocs

Signed-off-by: Carlos Santana <csantana23@gmail.com>

* use python 3.7

Signed-off-by: Carlos Santana <csantana23@gmail.com>

---------

Signed-off-by: Carlos Santana <csantana23@gmail.com>
2024-02-26 14:12:21 -05:00
dependabot[bot]
2ac96a55ba chore(deps): bump library/busybox in /test/e2e/multiarch-container (#14592)
Bumps library/busybox from `2376a0c` to `3fbc632`.

---
updated-dependencies:
- dependency-name: library/busybox
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-26 14:45:03 +02:00
dependabot[bot]
09798b5713 chore(deps): bump library/registry in /test/container (#13050)
Bumps library/registry from `41f413c` to `b209a41`.

---
updated-dependencies:
- dependency-name: library/registry
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-26 12:48:21 +02:00
dependabot[bot]
4d1eb5515f chore(deps): bump library/redis in /test/container (#17309)
Bumps library/redis from `11c3e41` to `e647cfe`.

---
updated-dependencies:
- dependency-name: library/redis
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:09:22 +02:00
dependabot[bot]
37eacec208 chore(deps): bump library/ubuntu in /test/container (#13409)
Bumps library/ubuntu from `9a0bdde` to `67211c1`.

---
updated-dependencies:
- dependency-name: library/ubuntu
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-25 19:07:58 +02:00
Debdut Chakraborty
8712d03e9e chore: add Rocket.Chat to users (#17306)
Signed-off-by: Debdut Chakraborty <debdutdeb@outlook.com>
2024-02-25 11:52:47 +01:00
dependabot[bot]
99723143b9 chore(deps): bump bitnami/kubectl in /test/container (#14220)
Bumps bitnami/kubectl from `670fe3f` to `14ab746`.

---
updated-dependencies:
- dependency-name: bitnami/kubectl
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-24 23:36:59 +02:00
dependabot[bot]
6de1037eb3 chore(deps): bump react-helmet and @types/react-helmet in /ui (#11556)
Bumps [react-helmet](https://github.com/nfl/react-helmet) and [@types/react-helmet](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-helmet). These dependencies needed to be updated together.

Updates `react-helmet` from 5.2.1 to 6.1.0
- [Release notes](https://github.com/nfl/react-helmet/releases)
- [Changelog](https://github.com/nfl/react-helmet/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nfl/react-helmet/commits/6.1.0)

Updates `@types/react-helmet` from 5.0.19 to 6.1.6
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-helmet)

---
updated-dependencies:
- dependency-name: react-helmet
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: "@types/react-helmet"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-24 22:44:42 +02:00
dependabot[bot]
e4c8568393 chore(deps): bump library/redis in /test/container (#17137)
Bumps library/redis from `cc8b0b8` to `11c3e41`.

---
updated-dependencies:
- dependency-name: library/redis
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-24 22:03:47 +02:00
dependabot[bot]
c435260f13 chore(deps-dev): bump postcss from 8.2.13 to 8.4.35 in /ui (#17140)
Bumps [postcss](https://github.com/postcss/postcss) from 8.2.13 to 8.4.35.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.2.13...8.4.35)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-24 15:44:12 +02:00
Carlos Santana
8bb41eda04 fix: Update test image ssl/crypto libs (#17303)
Signed-off-by: Carlos Santana <csantana23@gmail.com>
2024-02-24 14:52:09 +02:00
Sonam
7fe1263300 fix(ui): Include application name in status badge (#17126)
* Added application name to badge

Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com>

* Rever svg change

Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com>

* Doc for disabling application name

Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com>

* Flag to not display application name

Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com>

* Added tests

Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com>

* Make no app name the default

Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com>

* Have enable app name as a query parameter

Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com>

* Have enable app name as a query parameter

Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com>

* argocd to original

Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com>

* Update docs/user-guide/status-badge.md

Signed-off-by: Dan Garfield <dan@codefresh.io>

Signed-off-by: Dan Garfield <dan@codefresh.io>

---------

Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com>
Signed-off-by: Dan Garfield <dan@codefresh.io>
Co-authored-by: sshenoy6 <sonamkaup_shenoy@intuit.com>
Co-authored-by: Dan Garfield <dan@codefresh.io>
2024-02-24 14:04:30 +02:00
Blake Pettersson
5bc1850aa1 chore(ci): use changed files action (#17180)
`dorny/paths-filter` doesn't seem to handle (multiple) negations well.
Therefore, this PR switches to `tj-actions/changed-files`, since it is
already successfully used in argo-workflows.

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-02-23 10:51:09 -05:00
Muhammad Zain ul abidin
4dc91dcb9d docs for PR #9791 (#16021)
Signed-off-by: mzain <zainawan89@gmail.com>
2024-02-22 10:01:44 -07:00
Damon Edstrom
262d287645 docs: Added examples for alternate EKS cluster authentication methods (#17270)
* Added examples for alternate EKS cluster authentication methods
Signed-off-by: Damon Edstrom <dedstrom@venerated.io>

* Update docs/operator-manual/declarative-setup.md

Signed-off-by: Dan Garfield <dan@codefresh.io>

Signed-off-by: Dan Garfield <dan@codefresh.io>

---------

Signed-off-by: Dan Garfield <dan@codefresh.io>
Co-authored-by: Dan Garfield <dan@codefresh.io>
2024-02-22 16:10:11 +00:00
Oscar Wieman
df2b0e2711 fix typo (#17272)
Signed-off-by: Oscar Wieman <oscar@oscarr.nl>
2024-02-22 02:07:44 +00:00
Wilson Wang
5d4c0ecdee reduce unnecessary unmarshal (#17187)
Signed-off-by: Wilson Wang <wilson.wang@bytedance.com>
2024-02-21 20:56:06 -05:00
Dan Garfield
6aa79f283c Update contributors-quickstart.md (#17266)
Signed-off-by: Dan Garfield <dan@codefresh.io>
2024-02-21 09:14:02 -08:00
Adrian Moisey
17ef8b9579 docs: Fix typo in notifications example (#17250)
* Fix typo in notifications example

I'm not too sure what the example should look like, so I'm taking a guess here.

Signed-off-by: Adrian Moisey <adrian@changeover.za.net>

* Update docs/operator-manual/notifications/troubleshooting.md

Co-authored-by: Soumya Ghosh Dastidar <44349253+gdsoumya@users.noreply.github.com>
Signed-off-by: Adrian Moisey <adrian@changeover.za.net>

---------

Signed-off-by: Adrian Moisey <adrian@changeover.za.net>
Co-authored-by: Soumya Ghosh Dastidar <44349253+gdsoumya@users.noreply.github.com>
2024-02-21 20:21:01 +05:30
Gaston Festari
4761255608 docs(metrics): add release label to haproxy (#17264)
Add missing `release` label to `argocd-redis-haproxy-metrics`
ServiceMonitor example.

Signed-off-by: Gaston Festari <cilindrox@gmail.com>
2024-02-21 16:36:14 +02:00
itayvolo
d55e926a63 docs: Update USERS.md (#17248)
* Update USERS.md

Signed-off-by: itayvolo <72027444+itayvolo@users.noreply.github.com>

* Update USERS.md

Signed-off-by: itayvolo <72027444+itayvolo@users.noreply.github.com>

* Update USERS.md

Signed-off-by: itayvolo <72027444+itayvolo@users.noreply.github.com>

---------

Signed-off-by: itayvolo <72027444+itayvolo@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-21 14:34:43 +00:00
dependabot[bot]
3cc02779ca chore(deps): bump library/node from 50703e6 to 65998e3 (#17243)
Bumps library/node from `50703e6` to `65998e3`.

---
updated-dependencies:
- dependency-name: library/node
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-20 13:23:01 +02:00
Dong Wang
fa1ad0c375 Add AppName to the RepoServerAppDetailsQuery for notification-controller (#17233)
Signed-off-by: Dong Wang <wd@wdicc.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-20 12:24:32 +02:00
dependabot[bot]
b80015e27e chore(deps): bump library/golang in /test/remote (#17244)
Bumps library/golang from `ef61a20` to `7b297d9`.

---
updated-dependencies:
- dependency-name: library/golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-20 10:33:55 +02:00
dependabot[bot]
8a866492db chore(deps): bump library/node from 6fb1883 to 65998e3 in /ui-test (#17245)
Bumps library/node from `6fb1883` to `65998e3`.

---
updated-dependencies:
- dependency-name: library/node
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-20 10:33:31 +02:00
Luke
078eb6c56d feat(grafana-dashboard): Update example dashboard, add AppSet Telemetry (#17232)
Signed-off-by: lukepatrick <lukephilips@gmail.com>
2024-02-19 19:29:27 +02:00
dependabot[bot]
d9e0666795 chore(deps): bump library/golang in /test/remote (#17138)
Bumps library/golang from `094e47e` to `ef61a20`.

---
updated-dependencies:
- dependency-name: library/golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-19 18:42:02 +02:00
dependabot[bot]
47eddf169e chore(deps): bump library/node from 21.6.1 to 21.6.2 (#17223)
Bumps library/node from 21.6.1 to 21.6.2.

---
updated-dependencies:
- dependency-name: library/node
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-19 14:58:46 +02:00
dependabot[bot]
4e224ee878 chore(deps): bump library/node from 21.6.1 to 21.6.2 in /ui-test (#17226)
Bumps library/node from 21.6.1 to 21.6.2.

---
updated-dependencies:
- dependency-name: library/node
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-19 13:56:27 +02:00
Mikołaj Przybysz
50284f7c5c Count git checkout failures (#15657)
Signed-off-by: Mikołaj Przybysz <1093404+mikolajprzybysz@users.noreply.github.com>
Co-authored-by: Mikołaj Przybysz <1093404+mikolajprzybysz@users.noreply.github.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-02-19 12:44:44 +02:00
Keith Chong
c0e679a66c fix: Permission Denied error when calling GetAppDetails API (#17221) (#17229)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2024-02-16 12:20:08 -08:00
NextBasket-Petyo
d5a4f81b8e docs: Add Nextbasket to USERS.md (#17228)
Signed-off-by: NextBasket-Petyo <100193556+NextBasket-Petyo@users.noreply.github.com>
2024-02-16 17:55:40 +01:00
Matt Menzenski
d5b0a4f029 docs: Add PayIt to USERS.md (#17215)
* docs: Add PayIt to USERS.md

Signed-off-by: Matt Menzenski <matt@payitgov.com>

* docs: Add PayIt to USERS.md

Signed-off-by: Matt Menzenski <matt@payitgov.com>

---------

Signed-off-by: Matt Menzenski <matt@payitgov.com>
2024-02-15 17:56:40 -05:00
Alexandre Gaudreault
79e94b8fe0 chore(deps): upgrade helm to 3.14.1 (#17213)
* chore(deps): upgrade helm to 3.14.1

Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>

* move files to folder......

Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>

---------

Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2024-02-15 08:26:32 -07:00
Alexandre Gaudreault
ff7192bfc5 fix(controller): add missing workqueue metrics (#16315) (#17013)
* fix(controller): add missing kubernetes metrics

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* validate workqueue metrics are present

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* use newer metrics registry

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* fix duplicated

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* init runtime controller in test to have correct metrics

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* fix lint error

Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>

* update controller-runtime to remove metrics with high cardinality

Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>

---------

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2024-02-14 11:48:39 -05:00
Michael Morris
6d0ba1fad7 feat: wait until resources are deleted #6085 (#16733)
* feat: wait until resources are deleted

Signed-off-by: MichaelMorris <michael.morris@est.tech>

* Added unit and e2e test

Signed-off-by: MichaelMorris <michael.morris@est.tech>

---------

Signed-off-by: MichaelMorris <michael.morris@est.tech>
2024-02-14 15:01:34 +02:00
Lukas Wöhrl
5d6111b745 fix: infer correct shard in statefulset setup (#17124, #17016) (#17167)
* fix: infer correct shard in statefulset setup

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

* fix the case if only a single replica

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

* fix: resolving pointer on shard compare

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

* fix: add readlock for cluster accessor

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

* fix: use defer to protect access of 'shard'

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

* fix: revert locking in getclusteraccessor

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

* fix: handle nil shard case

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

* fix: handle any nil shard value as false

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

* fix: handle nil case and fix another missing pointer dereference 

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

* revert

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

* fix: added tests and fixed some behaviour bugs

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

* test: add test to validate that Shard value is not overriden

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

* fix: added tests and fixe the case when server is changed inside a secret

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

* tests: add test cases for infering the shard logic

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>

---------

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>
2024-02-13 11:51:41 -05:00
Suraj yadav
db34f98451 docs: Private-helm-repo section target added to helm.md (#16697)
* helm-repo

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>

* Update docs/user-guide/helm.md

Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
Signed-off-by: Suraj yadav <harrypotter1108@gmail.com>

---------

Signed-off-by: Surajyadav <harrypotter1108@gmail.com>
Signed-off-by: Suraj yadav <harrypotter1108@gmail.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-02-13 14:16:09 +01:00
Ajay Chidambaram
5406a1a5e8 docs: fixes Template.md targetRevision typo (#17190)
* Template.md targetRevision typo fixed

Signed-off-by: Ajay Chidambaram <105060495+chidambaram27@users.noreply.github.com>

* retrigger checks

Signed-off-by: Ajay Chidambaram <105060495+chidambaram27@users.noreply.github.com>

* sign off

Signed-off-by: chidambaram27 <chidambaramk.27@gmail.com>
Signed-off-by: Ajay Chidambaram <105060495+chidambaram27@users.noreply.github.com>

* sign off

Signed-off-by: Ajay Chidambaram <105060495+chidambaram27@users.noreply.github.com>

---------

Signed-off-by: Ajay Chidambaram <105060495+chidambaram27@users.noreply.github.com>
Signed-off-by: chidambaram27 <chidambaramk.27@gmail.com>
2024-02-13 13:03:16 +01:00
David Grizzanti
c082a0cca5 Update triggers doc to fix typo (#17185)
Signed-off-by: David Grizzanti <dgrizzanti@users.noreply.github.com>
2024-02-12 22:35:22 -05:00
Jan Schumann
82433ff1a8 feat: query escape function for notifications (#16343)
Signed-off-by: Jan Schumann <js@schumann-it.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-12 12:34:16 +02:00
Soumya Ghosh Dastidar
4458d5fa80 fix: stop initializing deployment informer if dynamic sharding is disabled (#17097)
* fix: stop initializing deployment informer if dynamic sharding is disabled

Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>

* feat: updated sharding cache getter func

Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>

---------

Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
2024-02-11 13:32:17 -05:00
shlomi tubul
adceae9ec8 feat: Add support for passing Redis Sentinel username(ACL) and password (#17168)
* Add support for passing Sentinel username and password

Signed-off-by: ShlomiTubul <shlomi.tubul@placer.ai>

* fix align with var naming

Signed-off-by: ShlomiTubul <shlomi.tubul@placer.ai>

* fix align with var naming

Signed-off-by: ShlomiTubul <shlomi.tubul@placer.ai>

---------

Signed-off-by: ShlomiTubul <shlomi.tubul@placer.ai>
Co-authored-by: ShlomiTubul <shlomi.tubul@placer.ai>
2024-02-11 00:48:15 -05:00
AS
bb1c1ed44d chore(dex): 2.37.0 to 2.38.0 (#17157)
Signed-off-by: asingh51 <ashutosh_singh@intuit.com>
Co-authored-by: asingh51 <ashutosh_singh@intuit.com>
2024-02-09 09:37:04 -05:00
Alexandre Gaudreault
d7da05f3aa docs: fix error in toolchain setup (#17154)
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2024-02-08 18:09:17 -08:00
Blake Pettersson
7e80f1e8e5 chore(ci): tweak backend filters (#17134)
The existing backend filters get triggered even on frontend-only or
docs-only changes, which should not be the case. The reason for this
seems to be the fact that each filter line is ORed rather than ANDed.
To remedy this, we put all the filters on the same line.

I tried the filter out in a REPL
(https://runkit.com/blakepettersson/65c3daba99653f0008c74eda). This is
a filter using picomatch (the same library `dorny/paths-filter` uses).

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-02-07 18:43:50 -05:00
Prune Sebastien THOMAS
f77cf94908 fix(kustomize): set build dir (#15057) #16229 #16652 (#16653)
* use repo root, not app path

Signed-off-by: Prune <prune@lecentre.net>

correct patch

Signed-off-by: Prune <prune@lecentre.net>

* use Getwd to find the root path for diff commands

Signed-off-by: Prune <prune@lecentre.net>

* set dot a default for argo app commands

Signed-off-by: Prune <prune@lecentre.net>

* revert default values

Signed-off-by: Prune <prune@lecentre.net>

* patch diff in TestNamespacedResourceDiffing

Signed-off-by: Prune <prune@lecentre.net>

* patching some diff and sync

Signed-off-by: Prune <prune@lecentre.net>

* patch remaining diff in error

Signed-off-by: Prune <prune@lecentre.net>

---------

Signed-off-by: Prune <prune@lecentre.net>
2024-02-07 14:00:00 -05:00
fsl
52ffd7df4d chore(deps): bump library/node from 20.7.0 to 21.6.1 (#17065)
Signed-off-by: fengshunli <1171313930@qq.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-07 16:21:00 +02:00
dependabot[bot]
3c9a2fbc59 chore(deps): bump library/node from 20.6.1 to 21.6.1 (#17053)
Bumps library/node from 20.6.1 to 21.6.1.

---
updated-dependencies:
- dependency-name: library/node
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-07 15:06:57 +02:00
Sorav Kumar Sharma
93a668ac09 fix the typo (#17116) 2024-02-07 18:32:07 +05:30
dependabot[bot]
98d5a2bf86 chore(deps-dev): bump yarn from 1.22.10 to 1.22.21 in /ui (#17096)
Bumps [yarn](https://github.com/yarnpkg/yarn) from 1.22.10 to 1.22.21.
- [Release notes](https://github.com/yarnpkg/yarn/releases)
- [Changelog](https://github.com/yarnpkg/yarn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yarnpkg/yarn/compare/1.22.10...v1.22.21)

---
updated-dependencies:
- dependency-name: yarn
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-07 14:11:05 +02:00
dependabot[bot]
7ce342fb88 chore(deps): bump library/redis from 7.0.11 to 7.2.4 in /test/container (#16806)
Bumps library/redis from 7.0.11 to 7.2.4.

---
updated-dependencies:
- dependency-name: library/redis
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-07 12:55:20 +02:00
dependabot[bot]
b23e71f578 chore(deps-dev): bump yarn from 1.22.10 to 1.22.13 in /ui-test (#17092)
Bumps [yarn](https://github.com/yarnpkg/yarn) from 1.22.10 to 1.22.13.
- [Release notes](https://github.com/yarnpkg/yarn/releases)
- [Changelog](https://github.com/yarnpkg/yarn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yarnpkg/yarn/compare/1.22.10...v1.22.13)

---
updated-dependencies:
- dependency-name: yarn
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-07 11:54:46 +02:00
dependabot[bot]
8ac7b6da38 chore(deps): bump library/golang from 1.21.3 to 1.22.0 in /test/remote (#17111)
Bumps library/golang from 1.21.3 to 1.22.0.

---
updated-dependencies:
- dependency-name: library/golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-07 10:53:43 +02:00
Soumya Ghosh Dastidar
d494d3a331 fix: ci failures (#17107)
Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
2024-02-07 00:56:14 +01:00
borisssmidtCET
b93874e741 Add a description for using contour httpproxy CRD (#14614)
Which allows you to reuse the same hostname.

Co-authored-by: Boris Smidt <boris.smidt@restore.eu>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
2024-02-06 23:56:30 +02:00
jcourteau
af20dae498 docs: Update Okta OIDC SSO docs (#13811)
* Update the Okta SSO docs

* fill out the OIDC section with step-by-step instructions on using Okta
  with custom authorization servers
* adjust outdated docs about updating the docs

Signed-off-by: Jonas Courteau <jonas.courteau@abcellera.com>

* Add the Okta version that these docs are written against

Signed-off-by: Jonas Courteau <jonas.courteau@abcellera.com>

---------

Signed-off-by: Jonas Courteau <jonas.courteau@abcellera.com>
Signed-off-by: Dan Garfield <dan@codefresh.io>
Co-authored-by: Dan Garfield <dan@codefresh.io>
2024-02-06 13:33:12 -07:00
Petr Studeny
4bf4629231 docs(webhook): use real cm name instead of placeholder (#17002)
The document says I should registed configMap named argocd-notifications-cm but then uses placeholder in examples.

Signed-off-by: Petr Studeny <studenyp@gmail.com>
2024-02-07 01:31:13 +05:30
Tal Yitzhak
c4a9df6570 Updated otelgrpc to remediate CVE found by JFrog Xray (#17084)
Signed-off-by: Tal Yitzhak <taly@lightrun.com>
Co-authored-by: Tal Yitzhak <taly@lightrun.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-02-07 00:04:54 +05:30
Adam Huganir
ca27c41bc2 typo registires -> registries (#17099)
Signed-off-by: Adam Huganir <adam@huganir.com>
2024-02-06 09:54:11 -07:00
Eshwar Hebbur Shivakumar
0b22a1198a fix(ui): Change path to "root" when path is root directory (#14949)
* change path to display root

Signed-off-by: Eshwar Hebbur Shivakumar <eshwar1011235@gmail.com>

* Fix inequality typo

Signed-off-by: Eshwar Hebbur Shivakumar <eshwar1011235@gmail.com>

* Fix lint issues

Signed-off-by: Eshwar Hebbur Shivakumar <eshwar1011235@gmail.com>

---------

Signed-off-by: Eshwar Hebbur Shivakumar <eshwar1011235@gmail.com>
2024-02-06 10:27:05 -05:00
Blake Pettersson
228eda5e1e chore(ci): run ci checks conditionally (#16982)
* chore(ci): run ci checks conditionally

This should prevent docs changes from having the need to run e2e tests
etc, and prevent backend changes from needing to run ui tests, and vice
versa.

This is similar to previous attempts (see #16706 and #13507), with the
difference here that we add the if checks on each _step_ rather than
each _job_ - the reason being that most of these jobs are required, and
if we skip whole jobs any PR which does this will be left hanging
indefinitely, so Github forces us to do this on a step level instead.

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>

* chore(ci): run ci checks conditionally

Try conditional jobs, according to https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>

* chore(ci): add composite test-e2e action

This is a workaround for the e2e tests which do not run yet report `pending` when they are actually skipped.

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>

---------

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
Co-authored-by: Remington Breeze <remington@breeze.software>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-02-06 10:26:38 -05:00
Anand Francis Joseph
555f6f42d2 docs(proposal): decoupling app sync from control plane user w/ impersonation (#14255)
* Proposal for decoupling application sync from control plane user using impersonation

Signed-off-by: Anand Francis Joseph <anjoseph@redhat.com>

* Moved the proposal document to the right directory

Signed-off-by: Anand Francis Joseph <anjoseph@redhat.com>

* Update docs/decouple-application-sync-user-using-impersonation

Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
Signed-off-by: Anand Francis Joseph <anandfrancis.joseph@gmail.com>

* Update docs/decouple-application-sync-user-using-impersonation

Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
Signed-off-by: Anand Francis Joseph <anandfrancis.joseph@gmail.com>

* Update docs/decouple-application-sync-user-using-impersonation

Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
Signed-off-by: Anand Francis Joseph <anandfrancis.joseph@gmail.com>

* Modified the proposal to have control in AppProjects alone instead of Application and AppProject

Signed-off-by: Anand Francis Joseph <anjoseph@redhat.com>

* Removed proposal placed in wrong directory and corrected examples

Signed-off-by: Anand Francis Joseph <anjoseph@redhat.com>

* Update docs/proposals/decouple-application-sync-user-using-impersonation

Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: Anand Francis Joseph <anandfrancis.joseph@gmail.com>

* Update docs/proposals/decouple-application-sync-user-using-impersonation

Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: Anand Francis Joseph <anandfrancis.joseph@gmail.com>

* Addressed review comments

Signed-off-by: Anand Francis Joseph <anjoseph@redhat.com>

* Additional corrections

Signed-off-by: anandf <anjoseph@redhat.com>

* Fixed alternative proposals section to include only AppProject based approach

Signed-off-by: anandf <anjoseph@redhat.com>

* Added information on impersonation and added related links

Signed-off-by: anandf <anjoseph@redhat.com>

* Added examples for remote cluster destination with the required RBAC access

Signed-off-by: anandf <anjoseph@redhat.com>

* Fixed clusterrole and clusterrolebinding creation commands

Signed-off-by: anandf <anjoseph@redhat.com>

* Addressed review comments from Akram

Signed-off-by: anandf <anjoseph@redhat.com>

* Corrected RBAC to include serviceaccounts that can be impersonated as swell

Signed-off-by: anandf <anjoseph@redhat.com>

* Address few more review comments from Ishita, Akram

Signed-off-by: anandf <anjoseph@redhat.com>

* Fixed a typo and updated the last updated date field

Signed-off-by: anandf <anjoseph@redhat.com>

* Added information of the sync hook behaviour and also corrected the namespace to match that of destination

Signed-off-by: Anand Francis Joseph <anjoseph@redhat.com>

* Changed proposal to meet the latest api design using destinationServiceAccounts

Signed-off-by: Anand Francis Joseph <anjoseph@redhat.com>

* Fixed proposal document to use destinationServiceAccounts struct

Signed-off-by: Anand Francis Joseph <anjoseph@redhat.com>

* Renamed proposal file to have .md extension

Signed-off-by: anandf <anjoseph@redhat.com>

* Using glob pattern instead of regex, and corrected the order of precedence when multiple matches are available

Signed-off-by: anandf <anjoseph@redhat.com>

---------

Signed-off-by: Anand Francis Joseph <anjoseph@redhat.com>
Signed-off-by: Anand Francis Joseph <anandfrancis.joseph@gmail.com>
Signed-off-by: anandf <anjoseph@redhat.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-02-06 10:18:00 -05:00
Thomas Decaux
5100726fd6 feat: add health-checks for eck elastic beat (#16563)
* feat: add health-checks for eck elastic beat

Signed-off-by: ebuildy <ebuildy@gmail.com>

* fix tests

Signed-off-by: ebuildy <ebuildy@gmail.com>

---------

Signed-off-by: ebuildy <ebuildy@gmail.com>
2024-02-06 03:01:04 +00:00
Michael Crenshaw
769836e6ea fix: log all token verification failures (#16625)
* fix: log all token verification failures

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

* better

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-02-06 02:56:39 +00:00
Linghao Su
2082a21121 fix(ui): prevent app name too long hide open icon (#16983)
* fix(ui): prevent app name too long hide open icon

Signed-off-by: linghaoSu <linghao.su@daocloud.io>

* fix(ui): fix app resource list lint

Signed-off-by: linghaoSu <linghao.su@daocloud.io>

---------

Signed-off-by: linghaoSu <linghao.su@daocloud.io>
2024-02-05 20:56:58 -05:00
Gustavo Esser
b1c6dc5742 DOC: add Fly Security and Telavita in USERS.md (#17076)
Signed-off-by: Gustavo Esser <esser1997@hotmail.com>
2024-02-06 02:26:17 +01:00
Bardia Heydari
5246429cad chore: improve error logs (#10592) (#17089)
Signed-off-by: Bardia Heydari <az.bardia13@gmail.com>
2024-02-05 16:42:20 -05:00
Ishita Sequeira
3fda27e8d9 fix(controller): fix application controller deployment crashing (#16984)
* fix application controller deployment crashing and update manifests

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* remove environment variable ARGOCD_ENABLE_DYNAMIC_CLUSTER_DISTRIBUTION

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* fix auto-generated docs

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

---------

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>
2024-02-05 21:09:35 +00:00
Michael Crenshaw
55713b3474 fix(ci): correct helm checksum path (#17081)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-02-02 20:03:12 +00:00
Leonardo Luz Almeida
dc1ccea568 feat: add prometheus metrics around proxy extension requests (#17012)
* feat: add prometheus metrics around proxy extension requests

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>

* update go.mod

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>

* fix metrics bugs

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>

* fix unit-test

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>

* Add unit suffix in the duration metric

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>

* update doc

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>

---------

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2024-02-02 16:56:48 +00:00
Michael Crenshaw
fa31c2323a chore(ci): bump k3s versions to latest patches (#17060)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-02-01 13:39:20 -05:00
Kerwood
b8aeb781a6 fix: removed pkce code challange check for WebUI (#16730)
Signed-off-by: Patrick Kerwood <patrick@kerwood.dk>
2024-02-01 08:27:30 -08:00
Carlos Santana
0c8bc1d61e chore(deps): Upgrade aws-sdk-go to support eks pod identity (#17063)
* chore: Upgrade aws-sdk-go to support eks pod identity

---------

Signed-off-by: Carlos Santana <carrlos@amazon.com>
Co-authored-by: Mathieu Bruneau <brunemat@amazon.com>

* add cogen for notifications

Signed-off-by: Carlos Santana <carrlos@amazon.com>

---------

Signed-off-by: Carlos Santana <carrlos@amazon.com>
Co-authored-by: Mathieu Bruneau <brunemat@amazon.com>
2024-01-31 21:30:32 -05:00
dependabot[bot]
28f362b886 chore(deps): bump github.com/evanphx/json-patch (#17021)
Bumps [github.com/evanphx/json-patch](https://github.com/evanphx/json-patch) from 5.6.0+incompatible to 5.9.0+incompatible.
- [Release notes](https://github.com/evanphx/json-patch/releases)
- [Commits](https://github.com/evanphx/json-patch/compare/v5.6.0...v5.9.0)

---
updated-dependencies:
- dependency-name: github.com/evanphx/json-patch
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-31 15:29:36 -05:00
Simon HEGE
f4019b7657 chore(deps): bump Helm to 3.14.0 (#17031) (#17032)
* bump helm to 3.14.0

Signed-off-by: Simon HEGE <simonhege@gmail.com>

* Add a note about helm bump in upgrade instructions

Signed-off-by: Simon HEGE <simonhege@gmail.com>

---------

Signed-off-by: Simon HEGE <simonhege@gmail.com>
2024-01-31 15:26:28 -05:00
Shyukri Shyukriev
291445f132 chore: use kubernetes 1.29.0 in CI (#17050)
Keeping 1.25 for now.

Signed-off-by: Shyukri Shyukriev <shukera@gmail.com>
2024-01-31 15:23:45 -05:00
Andrew Block
c691d366a5 Corrected certificate managment for OCI helm charts (#16656)
Signed-off-by: Andrew Block <andy.block@gmail.com>
Co-authored-by: Soumya Ghosh Dastidar <44349253+gdsoumya@users.noreply.github.com>
2024-01-30 21:45:11 -05:00
Nicholas Morey
7f749c62b8 docs(hooks): add postdelete to table (#17048)
Add `PostDelete` to the hooks table, and clean up wording and old availability statement (all the way back to v1, probably irrelevant).

Signed-off-by: Nicholas Morey <nicholas@morey.tech>
2024-01-30 20:51:25 -05:00
Nicholas Morey
55918abd77 docs(argocd-cm): add timeout.reconciliation.jitter example (#17044)
Signed-off-by: Nicholas Morey <nicholas@morey.tech>
2024-01-30 10:21:49 -08:00
Nicholas Morey
4d53d36268 docs(kustomize): add components yaml example (#17043)
Signed-off-by: Nicholas Morey <nicholas@morey.tech>
2024-01-30 10:21:29 -08:00
Nicholas Morey
981bceecb0 docs(applicationset): explain impact of empty spec in templatePatch (#17042)
* docs: explain impact of empty spec in templatePatch

Signed-off-by: Nicholas Morey <nicholas@morey.tech>

* fix: not conditional helm values

Signed-off-by: Nicholas Morey <nicholas@morey.tech>

---------

Signed-off-by: Nicholas Morey <nicholas@morey.tech>
2024-01-30 09:55:50 -08:00
Siddhesh Ghadi
e5c88c914b feat: Prune resources in reverse order of syncwave during sync (#15074) (#16748)
* Add e2e & doc for prune order during sync

Signed-off-by: Siddhesh Ghadi <sghadi1203@gmail.com>

* Point gitops-engine to fork with reverse prune changes

Signed-off-by: Siddhesh Ghadi <sghadi1203@gmail.com>

* Fix ci linting failures

Signed-off-by: Siddhesh Ghadi <sghadi1203@gmail.com>

* Update gitops-engine commit ref

Signed-off-by: Siddhesh Ghadi <sghadi1203@gmail.com>

---------

Signed-off-by: Siddhesh Ghadi <sghadi1203@gmail.com>
2024-01-30 10:08:59 -05:00
saeedhosseini
3c21242356 Fix typo in documentation (#17022)
Signed-off-by: saeedhosseini <saeedhosseini21@gmail.com>
2024-01-29 21:04:01 +05:30
Yudi A Phanama
be1f0eafb8 fix(redis): go-redis v9 regression missing metrics and reconnect hook (#13415) (#15275)
* fix(redis): go-redis v9 regression missing metrics and reconnect hook

Signed-off-by: phanama <yudiandreanp@gmail.com>

* fix: golangci lint return values not checked in tests

Signed-off-by: phanama <yudiandreanp@gmail.com>

* chore: move dnsError var locally into func

Signed-off-by: phanama <yudiandreanp@gmail.com>

---------

Signed-off-by: phanama <yudiandreanp@gmail.com>
2024-01-29 10:31:15 -05:00
Nicholas Morey
4e084ace8c docs(helm): fix yaml formatting on code block (#17001)
Signed-off-by: Nicholas Morey <nicholas@morey.tech>
2024-01-26 15:38:49 -05:00
Sonam
8c9abb27ef Badge for apps in any namespace (#16739)
Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com>
Co-authored-by: sshenoy6 <sonamkaup_shenoy@intuit.com>
2024-01-26 15:01:30 -05:00
Nicholas Morey
344f23b5e8 docs(helm): add example of public oci chart (#17000)
There doesn't appear to be an example of using an OCI helm chart repository, so this adds a simple declarative example. This is a common question from the community.

Signed-off-by: Nicholas Morey <nicholas@morey.tech>
2024-01-26 15:42:52 +00:00
Fish-pro
85009d941c Clean up repeated package import (#16987)
Signed-off-by: Zechun Chen <zechun.chen@daocloud.io>
2024-01-25 09:51:43 -05:00
Michael Crenshaw
8932036d53 fix(server): allow disabling content-type check (#16959)
* fix(server): allow disabling content-type check

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

* fix spacing

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-01-24 14:45:09 -05:00
fsl
6d0850749b chore(deps): rm go-jose Cxb6dee8d5-b814 high vuln (#16947)
Signed-off-by: fengshunli <1171313930@qq.com>
2024-01-24 09:42:42 -05:00
1102
666499f610 feat(health): support for resourcerecordsets aws.crossplane.io resource (#16823)
Signed-off-by: nueavv <nuguni@kakao.com>
2024-01-24 00:23:58 -05:00
Christian Hernandez
0012e787f3 docs: Added an example of downloading the latest stable version (#16968)
* added an example of downloading the latest stable version

Signed-off-by: Christian Hernandez <christian@chernand.io>

* Update docs/cli_installation.md

Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
Signed-off-by: Christian Hernandez <christianh814@users.noreply.github.com>

---------

Signed-off-by: Christian Hernandez <christian@chernand.io>
Signed-off-by: Christian Hernandez <christianh814@users.noreply.github.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-01-24 03:32:29 +00:00
Keith Chong
fec5708ea5 docs: Update argocd-cm.yaml bannerposition description (#16961) (#16962)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2024-01-23 18:32:52 -05:00
Anand Francis Joseph
97727cbb59 fix(appcontroller): Uptake fix in gitops engine which fixes application sync with auto create ns and server side apply (#16942)
* Uptake fix in gitops engine to fix auto create ns with server side apply

Signed-off-by: anandf <anjoseph@redhat.com>

* Moved the new e2e test to different location

Signed-off-by: anandf <anjoseph@redhat.com>

* Fix test name to be less than 63 char for creating ns

Signed-off-by: anandf <anjoseph@redhat.com>

* update gitops-engine with latest master

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>

---------

Signed-off-by: anandf <anjoseph@redhat.com>
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
Co-authored-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2024-01-23 12:55:30 -05:00
Linghao Su
b234264d79 fix(ui): fix display banner when not explicit set position (#16741)
Signed-off-by: linghaoSu <linghao.su@daocloud.io>
2024-01-23 12:09:00 -05:00
Ishita Sequeira
c29f6da00c separate application controller roles into a separate manifests directory (#16884)
Signed-off-by: ishitasequeira <ishiseq29@gmail.com>
2024-01-22 15:39:56 -05:00
Arnold
f7236d794b feat: Add PITS Globale Datenrettungsdienste to user list (#16765)
* Add PITS Globale Datenrettungsdienste to user list

Signed-off-by: Arnold <87698848+arnoldberlin@users.noreply.github.com>

* Update USERS.md

Signed-off-by: Arnold <87698848+arnoldberlin@users.noreply.github.com>

---------

Signed-off-by: Arnold <87698848+arnoldberlin@users.noreply.github.com>
Co-authored-by: Soumya Ghosh Dastidar <44349253+gdsoumya@users.noreply.github.com>
2024-01-22 15:26:26 +00:00
Blake Pettersson
9042f415b7 Revert "chore: Preventing runnings jobs when updating documentation (#16706)" (#16943)
This reverts commit 65869a3860.

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-01-22 08:49:50 -05:00
Sergey Lanzman
397063fea4 fix(action): Add validation for Kustomize Build Options white space (#16704)
Signed-off-by: Sergey Lanzman <sergeylanz@gmail.com>
2024-01-21 12:18:36 +05:30
Alexandre Gaudreault
7302a52ea1 feat(controller): add sync jitter(#14241) (#16820)
* feat(controller): add sync jitter

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* convert to duration for simplicity

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* docs

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* add config to manifests

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* fix tests

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

---------

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>
2024-01-21 11:52:32 +05:30
Michael Crenshaw
9ecc5aec2a fix(ui): set content-type for certain UI requests (#16923) (#16930)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-01-19 16:47:14 +00:00
1102
21c384f423 feat(health): support for distribution aws.crossplane.io resource (#16827)
Signed-off-by: nueavv <nuguni@kakao.com>
2024-01-19 11:20:10 -05:00
Siddhesh Ghadi
32e373829b Initialize & send forceHttpBasicAuth & enableOCI params correctly during repo update from UI (#16794) 2024-01-19 10:14:38 -05:00
Aymen Ben Tanfous
80683acb71 docs: Fixed Slugify doc in GoTemplate.md (#16685)
* docs: Fixed Slugify doc in  GoTemplate.md

Signed-off-by: Aymen Ben Tanfous <aymen.bentanfous@gmail.com>

* Update docs/operator-manual/applicationset/GoTemplate.md

Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
Signed-off-by: Aymen Ben Tanfous <aymen.bentanfous@gmail.com>

* Update docs/operator-manual/applicationset/GoTemplate.md

Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
Signed-off-by: Aymen Ben Tanfous <aymen.bentanfous@gmail.com>

---------

Signed-off-by: Aymen Ben Tanfous <aymen.bentanfous@gmail.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-01-19 15:12:22 +00:00
Sergiy Kulanov
8a0bf41863 fix(cli): add support for Application in any namespace for app delete cmd (#16898)
Use fully qualified application names when operate with Applications

Closes: #16896

Signed-off-by: Sergiy Kulanov <sergiy_kulanov@epam.com>
2024-01-18 10:57:16 -05:00
dependabot[bot]
f0cbf516fc chore(deps): bump github.com/go-git/go-git/v5 from 5.8.1 to 5.11.0 (#16711)
Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.8.1 to 5.11.0.
- [Release notes](https://github.com/go-git/go-git/releases)
- [Commits](https://github.com/go-git/go-git/compare/v5.8.1...v5.11.0)

---
updated-dependencies:
- dependency-name: github.com/go-git/go-git/v5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-18 10:25:06 -05:00
Aymen Ben Tanfous
65869a3860 chore: Preventing runnings jobs when updating documentation (#16706)
* Preventing runnings jobs when updating documentation

Signed-off-by: Aymen Ben Tanfous <aymen.bentanfous@cimpress.com>

* Empty line added to .md file

Signed-off-by: Aymen Ben Tanfous <aymen.bentanfous@cimpress.com>

---------

Signed-off-by: Aymen Ben Tanfous <aymen.bentanfous@cimpress.com>
Co-authored-by: Aymen Ben Tanfous <aymen.bentanfous@cimpress.com>
2024-01-18 10:27:14 +01:00
Ryan Flynn
2b95bc0d3e docs: Update Azure AD to Entra ID (#16869)
* Update Azure AD to Entra ID

https://learn.microsoft.com/en-us/entra/fundamentals/new-name

Signed-off-by: Ryan Flynn <mr.ryanflynn@gmail.com>

* Add formerly known as azuread

Signed-off-by: Ryan Flynn <mr.ryanflynn@gmail.com>

---------

Signed-off-by: Ryan Flynn <mr.ryanflynn@gmail.com>
2024-01-17 22:55:27 +00:00
Chetan Deshmukh
d5e119c251 Adding CNCF blog to readme file (#16893)
Signed-off-by: Chetan Deshmukh <cdeshmukh@infracloud.io>
2024-01-17 14:12:34 +00:00
Blake Pettersson
d367b727c8 chore: allow @approvers-docs to approve readme.md (#16897)
Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-01-17 09:09:43 -05:00
Regina Scott
3997dbef8e update follow-redirects to 1.15.5 (#16899)
Signed-off-by: Regina Scott <rescott@redhat.com>
2024-01-17 09:08:41 -05:00
Yuan Tang
c7bf0648e5 docs: Add LinkedIn badge to README.md (#16889)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2024-01-17 11:15:17 +05:30
Sergiy Kulanov
256c2ae5dc fix(cli): add support for Application in any namespace for app wait (argoproj#16812) (#16816)
Use fully qualified application names in ApplicationWaitCommand

Closes: #16812

Signed-off-by: Sergiy Kulanov <sergiy_kulanov@epam.com>
2024-01-16 22:51:54 -05:00
doxsch
180b99010e fix: added logging if repo credentials collide (#16833)
Signed-off-by: doxsch <28098153+doxsch@users.noreply.github.com>
2024-01-16 22:51:03 -05:00
Zubair Haque
15060e1d73 adding tests for githandlers (#16678)
Signed-off-by: zhaque44 <haque.zubair@gmail.com>
2024-01-16 22:27:20 -05:00
Alexander Matyushentsev
7ec9999b01 fix: enforce content type header for API requests (#16860)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2024-01-16 18:54:13 +00:00
Isaac Gaskin
d9df2525c5 feat: adding option to specify an aws profile to use by the argocd-server when adding a EKS cluster (#16767)
useful for argocd-servers which are not running in AWS and want to add multiple EKS clusters using
separate keys instead of assuming roles

#16766

Signed-off-by: Isaac Gaskin <isaac.gaskin@circle.com>
Co-authored-by: Soumya Ghosh Dastidar <44349253+gdsoumya@users.noreply.github.com>
2024-01-12 18:39:41 -05:00
eddimull
b12630c4be typo in comment (#16834)
Signed-off-by: eddimull <eddimull@gmail.com>
2024-01-11 18:08:42 +01:00
mugi
54de532940 fix(manifests): applicationset-controller dir is not added to cluster-rbac/kustomization.yaml. (#16810)
* fix(manifests): applicationset-controller dir is not added to cluster-rbac/kustomization.yaml.

Related PR: https://github.com/argoproj/argo-cd/pull/16699.

I missed adding a new folder(applicationset-controller) to kustomization.yaml.

So, i addressed it.

Signed-off-by: mugioka <okamugi0722@gmail.com>

* chore: exec `make manifests`.

Signed-off-by: mugioka <okamugi0722@gmail.com>

* chore: exec `make manifests`.

Signed-off-by: mugioka <okamugi0722@gmail.com>

---------

Signed-off-by: mugioka <okamugi0722@gmail.com>
2024-01-11 07:52:18 -05:00
Akram Ben Aissi
cd4fc97c9d fix: Use the cache for sharding (#15237)
* feat(sharding): use a cache

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* cluster cmd

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* - Assign shard 0 to in-cluster cluster and nil check updates
- Caching clusters while sharding: Fixing unit tests
- Update generated docs
- Debug e2e tests
- Default the shardNumber to the number of replicas if it is calculated to a higher value
- defered Unlock only when a lock is set
- Disabling temporarly other versions of k3s to check if e2e passes
- Do not fail if hostname format is not abc-n
- Fix unit test and skip some e2e
- Skip TestGitSubmoduleHTTPSSupport test
- Remove breaking defer c.lock.Unlock()
- Reverting testing all k3s version
- Default sharding fix
Signed-off-by: Akram Ben Aissi <akram.benaissi@gmail.com>

Signed-off-by: Akram Ben Aissi <akram.benaissi@gmail.com>

* fixes related to code review: renaming structure param, moving db initialisation

Signed-off-by: Akram Ben Aissi <akram.benaissi@gmail.com>

* Code review

Signed-off-by: Akram Ben Aissi <akram.benaissi@gmail.com>

* Set default shard to 0

Signed-off-by: Akram Ben Aissi <akram.benaissi@gmail.com>

* Set different default value for Sts and Deployment mode

Signed-off-by: Akram Ben Aissi <akram.benaissi@gmail.com>

* Expose ClusterShardingCache

Signed-off-by: Akram Ben Aissi <akram.benaissi@gmail.com>

* Removing use of argoDB.db for DistributionFunction

Signed-off-by: Akram Ben Aissi <akram.benaissi@gmail.com>

* Update generated documentation

Signed-off-by: Akram Ben Aissi <akram.benaissi@gmail.com>

* Fix comment about NoShardingDistributionFunction and NoShardingAlgorithm

Signed-off-by: Akram Ben Aissi <akram.benaissi@gmail.com>

---------

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>
Signed-off-by: Akram Ben Aissi <akram.benaissi@gmail.com>
Co-authored-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>
2024-01-11 01:32:11 -05:00
Alexandre Gaudreault
54f1572d46 fix: allow to run codegen outside GOPATH (#16511)
* fix: allow to run codegen outside GOPATH

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* clientgen

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* openapigen

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

* remove ensure-gopath

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>

---------

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>
2024-01-09 21:09:34 -05:00
Mahesh Kasbe
d6da9f2a15 Added Openkruise workload integration health check scripts (#16238)
Signed-off-by: Mahesh <maheshkasbe010@gmail.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-01-09 21:05:07 -05:00
Anand Francis Joseph
9b27aeb1a4 Added socks5 proxy support for ssh based git URL, upgraded go-git to 5.10.1 (#15864)
Signed-off-by: Anand Francis Joseph <anjoseph@redhat.com>
2024-01-09 09:41:12 -05:00
mugi
2024659696 chore(manifests): add ClsuterRole/ClusterRoleBinding for applicationset controller. (#16699)
Closes https://github.com/argoproj/argo-cd/issues/16698.

Signed-off-by: mugioka <okamugi0722@gmail.com>
2024-01-08 22:57:27 -05:00
Ishita Sequeira
8ebe1cd3c4 fix: add list permission deployments (#16785)
* add list permissions for deployments to application controller

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* revert redis-ha chart changes

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

* revert redis-ha chart changes

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>

---------

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>
2024-01-08 21:58:34 -05:00
Alexander Matyushentsev
c5b9c67073 fix: support specifying username/password for redis holding manifests in argocd-server (#16786)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2024-01-09 00:04:46 +00:00
Lie Ryan
40760eb852 Document restarting argocd after modifying argocd-cm (#12405)
Signed-off-by: Lie Ryan <lie.1296@gmail.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-01-07 17:48:54 +01:00
mfreeman451
ecbd24da10 docs: Update signed-release-assets.md (#16755)
Missing \ in example

Signed-off-by: mfreeman451 <mfreeman451@gmail.com>
2024-01-05 19:04:54 -05:00
Michael Crenshaw
c4ac5aaa97 docs: add context to configmap example (#16763)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-01-05 20:13:35 +00:00
Alexander Matyushentsev
4afddf71cc feat: webhook should use 'rename' to copy app manifests of previous commit (#16754)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2024-01-05 08:53:52 -08:00
Yi Cai
1372529d56 fix(ui):Fixed log horizontal scroll for issue #16411 (#16727)
* Fixed log horizontal scroll

Signed-off-by: Yi Cai <yicai@redhat.com>

* Updated log line-height

Signed-off-by: Yi Cai <yicai@redhat.com>

---------

Signed-off-by: Yi Cai <yicai@redhat.com>
2024-01-05 08:53:08 -08:00
Greg Werner
d5955508da Update USERS.md with IllumiDesk (#16742)
Signed-off-by: Greg Werner <werner.greg@gmail.com>
2024-01-04 11:05:33 +05:30
Nicholas Morey
1975074de5 docs: remove core install commands from getting started (#16735)
* docs: remove core install commands from getting started

I often accidentally run the core install commands when quickly copying and pasting commands from the getting started guide, which leads to confusion. I've also spent plenty of time helping newcomers to Argo CD who have done the same and are confused when they can't reach the UI.

Given that this is a "getting started" guide, it's ideal to provide only the commands required. I've removed the commands and left the link out to the core install page for those who are interested in going down that path.

Signed-off-by: Nicholas Morey <nicholas@morey.tech>

* fix: use link to install commands in core docs

Signed-off-by: Nicholas Morey <nicholas@morey.tech>

* fix: use tip and improve wording

Signed-off-by: Nicholas Morey <nicholas@morey.tech>

---------

Signed-off-by: Nicholas Morey <nicholas@morey.tech>
2024-01-03 17:58:26 +00:00
Michael Crenshaw
a40330f5c8 docs: configmap items are strings (#16737)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-01-03 17:08:24 +00:00
Noam Gal
80ca563909 fix broken link (#16722)
Signed-off-by: Noam Gal <noam.gal@codefresh.io>
2023-12-31 17:46:58 +01:00
Nenad Strainovic
f0f4a4e438 Multiple hook delete policies can be specified as a comma separated list (#16659)
Based on https://github.com/argoproj/gitops-engine/blob/master/pkg/sync/hook/delete_policy.go#L13 multiple hook delete policies are also allowed.

Signed-off-by: Nenad Strainovic <nenad.strainovic@asseco-see.rs>
2023-12-28 12:32:15 +01:00
Mark Estiller
20f7182489 Update contributors-quickstart.md to include a link to Go's installation guide (#16691)
Signed-off-by: Mark Estiller <markalestiller@gmail.com>
2023-12-28 11:17:00 +01:00
Sanchaai Mathiyarasan
7d1f6a1e94 Update contributors-quickstart.md to include minikube as local cluster alternative. (#16690)
Signed-off-by: Sanchaai Mathiyarasan <sanchaai.mathi@gmail.com>
2023-12-28 11:15:36 +01:00
Robin Lieb
0e67ed89ac feat: add initiated by in history and rollback view (#16654)
Signed-off-by: Robin Lieb <robin.j.lieb@gmail.com>
2023-12-22 16:50:33 +00:00
Abhishek Veeramalla
7847e7f393 chore: fix typo in application controller description (#16671)
Signed-off-by: iam-veeramalla <abhishek.veeramalla@gmail.com>
2023-12-21 08:34:06 +00:00
dependabot[bot]
3224102664 chore(deps): bump golang.org/x/crypto from 0.14.0 to 0.17.0 (#16645)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 00:25:22 +00:00
548 changed files with 62072 additions and 48877 deletions

View File

@@ -1,5 +1,5 @@
name: Integration tests
on:
on:
push:
branches:
- 'master'
@@ -23,12 +23,35 @@ permissions:
contents: read
jobs:
changes:
runs-on: ubuntu-latest
outputs:
backend: ${{ steps.filter.outputs.backend_any_changed }}
frontend: ${{ steps.filter.outputs.frontend_any_changed }}
steps:
- uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
- uses: tj-actions/changed-files@90a06d6ba9543371ab4df8eeca0be07ca6054959 # v42.0.2
id: filter
with:
# Any file which is not under docs/, ui/ or is not a markdown file is counted as a backend file
files_yaml: |
backend:
- '!ui/**'
- '!**.md'
- '!**/*.md'
- '!docs/**'
frontend:
- 'ui/**'
- Dockerfile
check-go:
name: Ensure Go modules synchronicity
if: ${{ needs.changes.outputs.backend == 'true' }}
runs-on: ubuntu-22.04
needs:
- changes
steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
- name: Setup Golang
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0
with:
@@ -36,17 +59,20 @@ jobs:
- name: Download all Go modules
run: |
go mod download
- name: Check for tidyness of go.mod and go.sum
- name: Check for tidiness of go.mod and go.sum
run: |
go mod tidy
git diff --exit-code -- .
build-go:
name: Build & cache Go code
if: ${{ needs.changes.outputs.backend == 'true' }}
runs-on: ubuntu-22.04
needs:
- changes
steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
- name: Setup Golang
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0
with:
@@ -67,10 +93,13 @@ jobs:
contents: read # for actions/checkout to fetch code
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
name: Lint Go code
if: ${{ needs.changes.outputs.backend == 'true' }}
runs-on: ubuntu-22.04
needs:
- changes
steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
- name: Setup Golang
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0
with:
@@ -83,17 +112,19 @@ jobs:
test-go:
name: Run unit tests for Go packages
if: ${{ needs.changes.outputs.backend == 'true' }}
runs-on: ubuntu-22.04
needs:
- build-go
- changes
env:
GITHUB_TOKEN: ${{ secrets.E2E_TEST_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
steps:
- name: Create checkout directory
run: mkdir -p ~/go/src/github.com/argoproj
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
- name: Create symlink in GOPATH
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
- name: Setup Golang
@@ -150,17 +181,19 @@ jobs:
test-go-race:
name: Run unit tests with -race for Go packages
if: ${{ needs.changes.outputs.backend == 'true' }}
runs-on: ubuntu-22.04
needs:
- build-go
- changes
env:
GITHUB_TOKEN: ${{ secrets.E2E_TEST_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
steps:
- name: Create checkout directory
run: mkdir -p ~/go/src/github.com/argoproj
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
- name: Create symlink in GOPATH
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
- name: Setup Golang
@@ -212,10 +245,13 @@ jobs:
codegen:
name: Check changes to generated code
if: ${{ needs.changes.outputs.backend == 'true' }}
runs-on: ubuntu-22.04
needs:
- changes
steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
- name: Setup Golang
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0
with:
@@ -260,14 +296,17 @@ jobs:
build-ui:
name: Build, test & lint UI code
if: ${{ needs.changes.outputs.frontend == 'true' }}
runs-on: ubuntu-22.04
needs:
- changes
steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
- name: Setup NodeJS
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
with:
node-version: '20.7.0'
node-version: '21.6.1'
- name: Restore node dependency cache
id: cache-dependencies
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
@@ -292,15 +331,17 @@ jobs:
analyze:
name: Process & analyze test artifacts
if: ${{ needs.changes.outputs.backend == 'true' || needs.changes.outputs.frontend == 'true' }}
runs-on: ubuntu-22.04
needs:
- test-go
- build-ui
- changes
env:
sonar_secret: ${{ secrets.SONAR_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
with:
fetch-depth: 0
- name: Restore node dependency cache
@@ -315,7 +356,7 @@ jobs:
- name: Create test-results directory
run: |
mkdir -p test-results
- name: Get code coverage artifiact
- name: Get code coverage artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: code-coverage
@@ -336,35 +377,37 @@ jobs:
SCANNER_PATH: /tmp/cache/scanner
OS: linux
run: |
# We do not use the provided action, because it does contain an old
# version of the scanner, and also takes time to build.
set -e
mkdir -p ${SCANNER_PATH}
export SONAR_USER_HOME=${SCANNER_PATH}/.sonar
if [[ ! -x "${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/bin/sonar-scanner" ]]; then
curl -Ol https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SCANNER_VERSION}-${OS}.zip
unzip -qq -o sonar-scanner-cli-${SCANNER_VERSION}-${OS}.zip -d ${SCANNER_PATH}
fi
chmod +x ${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/bin/sonar-scanner
chmod +x ${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/jre/bin/java
# Explicitly set NODE_MODULES
export NODE_MODULES=${PWD}/ui/node_modules
export NODE_PATH=${PWD}/ui/node_modules
${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/bin/sonar-scanner
# We do not use the provided action, because it does contain an old
# version of the scanner, and also takes time to build.
set -e
mkdir -p ${SCANNER_PATH}
export SONAR_USER_HOME=${SCANNER_PATH}/.sonar
if [[ ! -x "${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/bin/sonar-scanner" ]]; then
curl -Ol https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SCANNER_VERSION}-${OS}.zip
unzip -qq -o sonar-scanner-cli-${SCANNER_VERSION}-${OS}.zip -d ${SCANNER_PATH}
fi
chmod +x ${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/bin/sonar-scanner
chmod +x ${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/jre/bin/java
# Explicitly set NODE_MODULES
export NODE_MODULES=${PWD}/ui/node_modules
export NODE_PATH=${PWD}/ui/node_modules
${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/bin/sonar-scanner
if: env.sonar_secret != ''
test-e2e:
name: Run end-to-end tests
if: ${{ needs.changes.outputs.backend == 'true' }}
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
k3s-version: [v1.28.2, v1.27.6, v1.26.9, v1.25.14]
needs:
k3s-version: [v1.29.1, v1.28.6, v1.27.10, v1.26.13, v1.25.16]
needs:
- build-go
- changes
env:
GOPATH: /home/runner/go
ARGOCD_FAKE_IN_CLUSTER: "true"
@@ -377,10 +420,10 @@ jobs:
ARGOCD_APPLICATION_NAMESPACES: "argocd-e2e-external,argocd-e2e-external-2"
ARGOCD_SERVER: "127.0.0.1:8088"
GITHUB_TOKEN: ${{ secrets.E2E_TEST_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
- name: Setup Golang
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0
with:
@@ -427,7 +470,7 @@ jobs:
git config --global user.email "john.doe@example.com"
- name: Pull Docker image required for tests
run: |
docker pull ghcr.io/dexidp/dex:v2.37.0
docker pull ghcr.io/dexidp/dex:v2.38.0
docker pull argoproj/argo-cd-ci-builder:v1.0.0
docker pull redis:7.0.14-alpine
- name: Create target directory for binaries in the build-process
@@ -462,3 +505,26 @@ jobs:
name: e2e-server-k8s${{ matrix.k3s-version }}.log
path: /tmp/e2e-server.log
if: ${{ failure() }}
# workaround for status checks -- check this one job instead of each individual E2E job in the matrix
# this allows us to skip the entire matrix when it doesn't need to run while still having accurate status checks
# see:
# https://github.com/argoproj/argo-workflows/pull/12006
# https://github.com/orgs/community/discussions/9141#discussioncomment-2296809
# https://github.com/orgs/community/discussions/26822#discussioncomment-3305794
test-e2e-composite-result:
name: E2E Tests - Composite result
if: ${{ always() }}
needs:
- test-e2e
- changes
runs-on: ubuntu-22.04
steps:
- run: |
result="${{ needs.test-e2e.result }}"
# mark as successful even if skipped
if [[ $result == "success" || $result == "skipped" ]]; then
exit 0
else
exit 1
fi

View File

@@ -29,7 +29,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
# Use correct go version. https://github.com/github/codeql-action/issues/1842#issuecomment-1704398087
- name: Setup Golang

View File

@@ -58,14 +58,14 @@ jobs:
image-digest: ${{ steps.image.outputs.digest }}
steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
if: ${{ github.ref_type == 'tag'}}
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
if: ${{ github.ref_type != 'tag'}}
- name: Setup Golang
@@ -74,9 +74,7 @@ jobs:
go-version: ${{ inputs.go-version }}
- name: Install cosign
uses: sigstore/cosign-installer@1fc5bd396d372bee37d608f955b336615edf79c8 # v3.2.0
with:
cosign-release: 'v2.2.1'
uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 # v3.4.0
- uses: docker/setup-qemu-action@2b82ce82d56a2a04d2637cd93a637ae1b359c0a7 # v2.2.0
- uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
@@ -106,7 +104,7 @@ jobs:
echo 'EOF' >> $GITHUB_ENV
- name: Login to Quay.io
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2.2.0
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
with:
registry: quay.io
username: ${{ secrets.quay_username }}
@@ -114,7 +112,7 @@ jobs:
if: ${{ inputs.quay_image_name && inputs.push }}
- name: Login to GitHub Container Registry
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2.2.0
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
with:
registry: ghcr.io
username: ${{ secrets.ghcr_username }}
@@ -122,7 +120,7 @@ jobs:
if: ${{ inputs.ghcr_image_name && inputs.push }}
- name: Login to dockerhub Container Registry
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2.2.0
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
with:
username: ${{ secrets.docker_username }}
password: ${{ secrets.docker_password }}
@@ -145,7 +143,7 @@ jobs:
- name: Build and push container image
id: image
uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 #v5.1.0
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 #v5.3.0
with:
context: .
platforms: ${{ inputs.platforms }}

View File

@@ -25,7 +25,7 @@ jobs:
image-tag: ${{ steps.image.outputs.tag}}
platforms: ${{ steps.platforms.outputs.platforms }}
steps:
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
- uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
- name: Set image tag for ghcr
run: echo "tag=$(cat ./VERSION)-${GITHUB_SHA::8}" >> $GITHUB_OUTPUT
@@ -86,7 +86,7 @@ jobs:
packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues)
if: ${{ github.repository == 'argoproj/argo-cd' && github.event_name == 'push' }}
# Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.7.0
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.10.0
with:
image: ghcr.io/argoproj/argo-cd/argocd
digest: ${{ needs.build-and-publish.outputs.image-digest }}
@@ -104,7 +104,7 @@ jobs:
if: ${{ github.repository == 'argoproj/argo-cd' && github.event_name == 'push' }}
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
- uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
- run: git clone "https://$TOKEN@github.com/argoproj/argoproj-deployments"
env:
TOKEN: ${{ secrets.TOKEN }}

View File

@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -38,7 +38,7 @@ jobs:
packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues)
# Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
if: github.repository == 'argoproj/argo-cd'
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.9.0
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.10.0
with:
image: quay.io/argoproj/argocd
digest: ${{ needs.argocd-image.outputs.image-digest }}
@@ -59,7 +59,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
@@ -87,6 +87,14 @@ jobs:
echo "KUBECTL_VERSION=$(go list -m k8s.io/client-go | head -n 1 | rev | cut -d' ' -f1 | rev)" >> $GITHUB_ENV
echo "GIT_TREE_STATE=$(if [ -z "`git status --porcelain`" ]; then echo "clean" ; else echo "dirty"; fi)" >> $GITHUB_ENV
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@4d9e71b726748f254fe64fa44d273194bd18ec91
with:
large-packages: false
docker-images: false
swap-storage: false
tool-cache: false
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@7ec5c2b0c6cdda6e8bbb49444bc797dd33d74dd8 # v5.0.0
id: run-goreleaser
@@ -120,7 +128,7 @@ jobs:
contents: write # Needed for release uploads
if: github.repository == 'argoproj/argo-cd'
# Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.9.0
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.10.0
with:
base64-subjects: "${{ needs.goreleaser.outputs.hashes }}"
provenance-name: "argocd-cli.intoto.jsonl"
@@ -139,7 +147,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
@@ -204,7 +212,7 @@ jobs:
contents: write # Needed for release uploads
if: github.repository == 'argoproj/argo-cd'
# Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.9.0
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.10.0
with:
base64-subjects: "${{ needs.generate-sbom.outputs.hashes }}"
provenance-name: "argocd-sbom.intoto.jsonl"
@@ -222,7 +230,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -30,12 +30,12 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@08b4669551908b1024bb425080c797723083c031 # v2.2.0
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
with:
results_file: results.sarif
results_format: sarif
@@ -54,7 +54,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: SARIF file
path: results.sarif
@@ -62,6 +62,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@3ebbd71c74ef574dbc558c82f70e52732c8b44fe # v2.2.1
uses: github/codeql-action/upload-sarif@83a02f7883b12e0e4e1a146174f5e2292a01e601 # v2.16.4
with:
sarif_file: results.sarif

View File

@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Build reports

View File

@@ -114,7 +114,7 @@ changelog:
exclude:
- '^test:'
- '^.*?Bump(\([[:word:]]+\))?.+$'
- '^.*?[Bot](\([[:word:]]+\))?.+$'
- '^.*?\[Bot\](\([[:word:]]+\))?.+$'
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json

View File

@@ -2,9 +2,10 @@
** @argoproj/argocd-approvers
# Docs
/docs/** @argoproj/argocd-approvers @argoproj/argocd-approvers-docs
/USERS.md @argoproj/argocd-approvers @argoproj/argocd-approvers-docs
/mkdocs.yml @argoproj/argocd-approvers @argoproj/argocd-approvers-docs
/docs/** @argoproj/argocd-approvers @argoproj/argocd-approvers-docs
/USERS.md @argoproj/argocd-approvers @argoproj/argocd-approvers-docs
/README.md @argoproj/argocd-approvers @argoproj/argocd-approvers-docs
/mkdocs.yml @argoproj/argocd-approvers @argoproj/argocd-approvers-docs
# CI
/.github/** @argoproj/argocd-approvers @argoproj/argocd-approvers-ci

View File

@@ -4,9 +4,9 @@ ARG BASE_IMAGE=docker.io/library/ubuntu:22.04@sha256:0bced47fffa3361afa981854fca
# 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.21.3@sha256:02d7116222536a5cf0fcf631f90b507758b669648e0f20186d2dc94a9b419a9b AS builder
FROM docker.io/library/golang:1.21.9@sha256:7d0dcbe5807b1ad7272a598fbf9d7af15b5e2bed4fd6c4c2b5b3684df0b317dd AS builder
RUN echo 'deb http://deb.debian.org/debian buster-backports main' >> /etc/apt/sources.list
RUN echo 'deb http://archive.debian.org/debian buster-backports main' >> /etc/apt/sources.list
RUN apt-get update && apt-get install --no-install-recommends -y \
openssh-server \
@@ -28,7 +28,7 @@ WORKDIR /tmp
COPY hack/install.sh hack/tool-versions.sh ./
COPY hack/installers installers
RUN ./install.sh helm-linux && \
RUN ./install.sh helm && \
INSTALL_PATH=/usr/local/bin ./install.sh kustomize
####################################################################################################
@@ -51,7 +51,7 @@ RUN groupadd -g $ARGOCD_USER_ID argocd && \
apt-get update && \
apt-get dist-upgrade -y && \
apt-get install -y \
git git-lfs tini gpg tzdata && \
git git-lfs tini gpg tzdata connect-proxy && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
@@ -83,7 +83,7 @@ WORKDIR /home/argocd
####################################################################################################
# Argo CD UI stage
####################################################################################################
FROM --platform=$BUILDPLATFORM docker.io/library/node:20.6.1@sha256:14bd39208dbc0eb171cbfb26ccb9ac09fa1b2eba04ccd528ab5d12983fd9ee24 AS argocd-ui
FROM --platform=$BUILDPLATFORM docker.io/library/node:21.6.2@sha256:65998e325b06014d4f1417a8a6afb1540d1ac66521cca76f2221a6953947f9ee AS argocd-ui
WORKDIR /src
COPY ["ui/package.json", "ui/yarn.lock", "./"]
@@ -101,7 +101,7 @@ RUN HOST_ARCH=$TARGETARCH NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OP
####################################################################################################
# Argo CD Build stage which performs the actual build of Argo CD binaries
####################################################################################################
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.21.3@sha256:02d7116222536a5cf0fcf631f90b507758b669648e0f20186d2dc94a9b419a9b AS argocd-build
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.21.9@sha256:7d0dcbe5807b1ad7272a598fbf9d7af15b5e2bed4fd6c4c2b5b3684df0b317dd AS argocd-build
WORKDIR /go/src/github.com/argoproj/argo-cd

102
Makefile
View File

@@ -3,6 +3,7 @@ CURRENT_DIR=$(shell pwd)
DIST_DIR=${CURRENT_DIR}/dist
CLI_NAME=argocd
BIN_NAME=argocd
CGO_FLAG=0
GEN_RESOURCES_CLI_NAME=argocd-resources-gen
@@ -22,14 +23,21 @@ KUBECTL_VERSION=$(shell go list -m k8s.io/client-go | head -n 1 | rev | cut -d'
GOPATH?=$(shell if test -x `which go`; then go env GOPATH; else echo "$(HOME)/go"; fi)
GOCACHE?=$(HOME)/.cache/go-build
# Docker command to use
DOCKER?=docker
ifeq ($(DOCKER),podman)
PODMAN_ARGS=--userns keep-id
else
PODMAN_ARGS=
endif
DOCKER_SRCDIR?=$(GOPATH)/src
DOCKER_WORKDIR?=/go/src/github.com/argoproj/argo-cd
ARGOCD_PROCFILE?=Procfile
# Strict mode has been disabled in latest versions of mkdocs-material.
# Thus pointing to the older image of mkdocs-material matching the version used by argo-cd.
MKDOCS_DOCKER_IMAGE?=squidfunk/mkdocs-material:4.1.1
# pointing to python 3.7 to match https://github.com/argoproj/argo-cd/blob/master/.readthedocs.yml
MKDOCS_DOCKER_IMAGE?=python:3.7-alpine
MKDOCS_RUN_ARGS?=
# Configuration for building argocd-test-tools image
@@ -49,7 +57,7 @@ ARGOCD_E2E_DEX_PORT?=5556
ARGOCD_E2E_YARN_HOST?=localhost
ARGOCD_E2E_DISABLE_AUTH?=
ARGOCD_E2E_TEST_TIMEOUT?=60m
ARGOCD_E2E_TEST_TIMEOUT?=90m
ARGOCD_IN_CI?=false
ARGOCD_TEST_E2E?=true
@@ -76,7 +84,7 @@ SUDO?=
# Runs any command in the argocd-test-utils container in server mode
# Server mode container will start with uid 0 and drop privileges during runtime
define run-in-test-server
$(SUDO) docker run --rm -it \
$(SUDO) $(DOCKER) run --rm -it \
--name argocd-test-server \
-u $(CONTAINER_UID):$(CONTAINER_GID) \
-e USER_ID=$(CONTAINER_UID) \
@@ -101,13 +109,14 @@ define run-in-test-server
-p ${ARGOCD_E2E_APISERVER_PORT}:8080 \
-p 4000:4000 \
-p 5000:5000 \
$(PODMAN_ARGS) \
$(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE):$(TEST_TOOLS_TAG) \
bash -c "$(1)"
endef
# Runs any command in the argocd-test-utils container in client mode
define run-in-test-client
$(SUDO) docker run --rm -it \
$(SUDO) $(DOCKER) run --rm -it \
--name argocd-test-client \
-u $(CONTAINER_UID):$(CONTAINER_GID) \
-e HOME=/home/user \
@@ -122,13 +131,14 @@ define run-in-test-client
-v ${HOME}/.kube:/home/user/.kube${VOLUME_MOUNT} \
-v /tmp:/tmp${VOLUME_MOUNT} \
-w ${DOCKER_WORKDIR} \
$(PODMAN_ARGS) \
$(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE):$(TEST_TOOLS_TAG) \
bash -c "$(1)"
endef
#
define exec-in-test-server
$(SUDO) docker exec -it -u $(CONTAINER_UID):$(CONTAINER_GID) -e ARGOCD_E2E_RECORD=$(ARGOCD_E2E_RECORD) -e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) argocd-test-server $(1)
$(SUDO) $(DOCKER) exec -it -u $(CONTAINER_UID):$(CONTAINER_GID) -e ARGOCD_E2E_RECORD=$(ARGOCD_E2E_RECORD) -e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) argocd-test-server $(1)
endef
PATH:=$(PATH):$(PWD)/hack
@@ -175,29 +185,21 @@ endif
.PHONY: all
all: cli image
# We have some legacy requirements for being checked out within $GOPATH.
# The ensure-gopath target can be used as dependency to ensure we are running
# within these boundaries.
.PHONY: ensure-gopath
ensure-gopath:
ifneq ("$(PWD)","$(LEGACY_PATH)")
@echo "Due to legacy requirements for codegen, repository needs to be checked out within \$$GOPATH"
@echo "Location of this repo should be '$(LEGACY_PATH)' but is '$(PWD)'"
@exit 1
endif
.PHONY: gogen
gogen: ensure-gopath
gogen:
export GO111MODULE=off
go generate ./util/argo/...
.PHONY: protogen
protogen: ensure-gopath mod-vendor-local
protogen: mod-vendor-local protogen-fast
.PHONY: protogen-fast
protogen-fast:
export GO111MODULE=off
./hack/generate-proto.sh
.PHONY: openapigen
openapigen: ensure-gopath
openapigen:
export GO111MODULE=off
./hack/update-openapi.sh
@@ -212,19 +214,22 @@ notification-docs:
.PHONY: clientgen
clientgen: ensure-gopath
clientgen:
export GO111MODULE=off
./hack/update-codegen.sh
.PHONY: clidocsgen
clidocsgen: ensure-gopath
clidocsgen:
go run tools/cmd-docs/main.go
.PHONY: codegen-local
codegen-local: ensure-gopath mod-vendor-local gogen protogen clientgen openapigen clidocsgen manifests-local notification-docs notification-catalog
codegen-local: mod-vendor-local gogen protogen clientgen openapigen clidocsgen manifests-local notification-docs notification-catalog
rm -rf vendor/
.PHONY: codegen-local-fast
codegen-local-fast: gogen protogen-fast clientgen openapigen clidocsgen manifests-local notification-docs notification-catalog
.PHONY: codegen
codegen: test-tools-image
$(call run-in-test-client,make codegen-local)
@@ -235,11 +240,11 @@ cli: test-tools-image
.PHONY: cli-local
cli-local: clean-debug
CGO_ENABLED=0 GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${CLI_NAME} ./cmd
CGO_ENABLED=${CGO_FLAG} GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${CLI_NAME} ./cmd
.PHONY: gen-resources-cli-local
gen-resources-cli-local: clean-debug
CGO_ENABLED=0 GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${GEN_RESOURCES_CLI_NAME} ./hack/gen-resources/cmd
CGO_ENABLED=${CGO_FLAG} GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${GEN_RESOURCES_CLI_NAME} ./hack/gen-resources/cmd
.PHONY: release-cli
release-cli: clean-debug build-ui
@@ -254,8 +259,8 @@ release-cli: clean-debug build-ui
.PHONY: test-tools-image
test-tools-image:
ifndef SKIP_TEST_TOOLS_IMAGE
$(SUDO) docker build --build-arg UID=$(CONTAINER_UID) -t $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE) -f test/container/Dockerfile .
$(SUDO) docker tag $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE) $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE):$(TEST_TOOLS_TAG)
$(SUDO) $(DOCKER) build --build-arg UID=$(CONTAINER_UID) -t $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE) -f test/container/Dockerfile .
$(SUDO) $(DOCKER) tag $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE) $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE):$(TEST_TOOLS_TAG)
endif
.PHONY: manifests-local
@@ -269,25 +274,25 @@ manifests: test-tools-image
# consolidated binary for cli, util, server, repo-server, controller
.PHONY: argocd-all
argocd-all: clean-debug
CGO_ENABLED=0 GOOS=${GOOS} GOARCH=${GOARCH} GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${BIN_NAME} ./cmd
CGO_ENABLED=${CGO_FLAG} GOOS=${GOOS} GOARCH=${GOARCH} GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${BIN_NAME} ./cmd
.PHONY: server
server: clean-debug
CGO_ENABLED=0 GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-server ./cmd
CGO_ENABLED=${CGO_FLAG} GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-server ./cmd
.PHONY: repo-server
repo-server:
CGO_ENABLED=0 GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-repo-server ./cmd
CGO_ENABLED=${CGO_FLAG} GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-repo-server ./cmd
.PHONY: controller
controller:
CGO_ENABLED=0 GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-application-controller ./cmd
CGO_ENABLED=${CGO_FLAG} GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-application-controller ./cmd
.PHONY: build-ui
build-ui:
DOCKER_BUILDKIT=1 docker build -t argocd-ui --platform=$(TARGET_ARCH) --target argocd-ui .
DOCKER_BUILDKIT=1 $(DOCKER) build -t argocd-ui --platform=$(TARGET_ARCH) --target argocd-ui .
find ./ui/dist -type f -not -name gitkeep -delete
docker run -v ${CURRENT_DIR}/ui/dist/app:/tmp/app --rm -t argocd-ui sh -c 'cp -r ./dist/app/* /tmp/app/'
$(DOCKER) run -v ${CURRENT_DIR}/ui/dist/app:/tmp/app --rm -t argocd-ui sh -c 'cp -r ./dist/app/* /tmp/app/'
.PHONY: image
ifeq ($(DEV_IMAGE), true)
@@ -296,29 +301,29 @@ ifeq ($(DEV_IMAGE), true)
# the dist directory is under .dockerignore.
IMAGE_TAG="dev-$(shell git describe --always --dirty)"
image: build-ui
DOCKER_BUILDKIT=1 docker build --platform=$(TARGET_ARCH) -t argocd-base --target argocd-base .
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd ./cmd
DOCKER_BUILDKIT=1 $(DOCKER) build --platform=$(TARGET_ARCH) -t argocd-base --target argocd-base .
CGO_ENABLED=${CGO_FLAG} GOOS=linux GOARCH=amd64 GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd ./cmd
ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-server
ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-application-controller
ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-repo-server
ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-cmp-server
ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-dex
cp Dockerfile.dev dist
DOCKER_BUILDKIT=1 docker build --platform=$(TARGET_ARCH) -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) -f dist/Dockerfile.dev dist
DOCKER_BUILDKIT=1 $(DOCKER) build --platform=$(TARGET_ARCH) -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) -f dist/Dockerfile.dev dist
else
image:
DOCKER_BUILDKIT=1 docker build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) --platform=$(TARGET_ARCH) .
DOCKER_BUILDKIT=1 $(DOCKER) build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) --platform=$(TARGET_ARCH) .
endif
@if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) ; fi
@if [ "$(DOCKER_PUSH)" = "true" ] ; then $(DOCKER) push $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) ; fi
.PHONY: armimage
armimage:
docker build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG)-arm .
$(DOCKER) build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG)-arm .
.PHONY: builder-image
builder-image:
docker build -t $(IMAGE_PREFIX)argo-cd-ci-builder:$(IMAGE_TAG) --target builder .
@if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argo-cd-ci-builder:$(IMAGE_TAG) ; fi
$(DOCKER) build -t $(IMAGE_PREFIX)argo-cd-ci-builder:$(IMAGE_TAG) --target builder .
@if [ "$(DOCKER_PUSH)" = "true" ] ; then $(DOCKER) push $(IMAGE_PREFIX)argo-cd-ci-builder:$(IMAGE_TAG) ; fi
.PHONY: mod-download
mod-download: test-tools-image
@@ -429,7 +434,7 @@ debug-test-client: test-tools-image
# Starts e2e server in a container
.PHONY: start-e2e
start-e2e: test-tools-image
docker version
$(DOCKER) version
mkdir -p ${GOCACHE}
$(call run-in-test-server,make ARGOCD_PROCFILE=test/container/Procfile start-e2e-local)
@@ -476,7 +481,7 @@ clean: clean-debug
.PHONY: start
start: test-tools-image
docker version
$(DOCKER) version
$(call run-in-test-server,make ARGOCD_PROCFILE=test/container/Procfile start-local ARGOCD_START=${ARGOCD_START})
# Starts a local instance of ArgoCD
@@ -526,7 +531,7 @@ build-docs-local:
.PHONY: build-docs
build-docs:
docker run ${MKDOCS_RUN_ARGS} --rm -it -v ${CURRENT_DIR}:/docs --entrypoint "" ${MKDOCS_DOCKER_IMAGE} sh -c 'pip install -r docs/requirements.txt; mkdocs build'
$(DOCKER) run ${MKDOCS_RUN_ARGS} --rm -it -v ${CURRENT_DIR}:/docs -w /docs --entrypoint "" ${MKDOCS_DOCKER_IMAGE} sh -c 'pip install -r docs/requirements.txt; mkdocs build'
.PHONY: serve-docs-local
serve-docs-local:
@@ -534,8 +539,7 @@ serve-docs-local:
.PHONY: serve-docs
serve-docs:
docker run ${MKDOCS_RUN_ARGS} --rm -it -p 8000:8000 -v ${CURRENT_DIR}/site:/site -w /site --entrypoint "" ${MKDOCS_DOCKER_IMAGE} python3 -m http.server --bind 0.0.0.0 8000
$(DOCKER) run ${MKDOCS_RUN_ARGS} --rm -it -p 8000:8000 -v ${CURRENT_DIR}:/docs -w /docs --entrypoint "" ${MKDOCS_DOCKER_IMAGE} sh -c 'pip install -r docs/requirements.txt; mkdocs serve -a $$(ip route get 1 | awk '\''{print $$7}'\''):8000'
# Verify that kubectl can connect to your K8s cluster from Docker
.PHONY: verify-kube-connect
@@ -558,7 +562,7 @@ install-tools-local: install-test-tools-local install-codegen-tools-local instal
.PHONY: install-test-tools-local
install-test-tools-local:
./hack/install.sh kustomize
./hack/install.sh helm-linux
./hack/install.sh helm
./hack/install.sh gotestsum
# Installs all tools required for running codegen (Linux packages)
@@ -587,7 +591,7 @@ list:
.PHONY: applicationset-controller
applicationset-controller:
GODEBUG="tarinsecurepath=0,zipinsecurepath=0" CGO_ENABLED=0 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-applicationset-controller ./cmd
GODEBUG="tarinsecurepath=0,zipinsecurepath=0" CGO_ENABLED=${CGO_FLAG} go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-applicationset-controller ./cmd
.PHONY: checksums
checksums:

View File

@@ -1,4 +1,4 @@
controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''} --server-side-diff-enabled=${ARGOCD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF:-'false'}"
controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "HOSTNAME=testappcontroller-1 FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''} --server-side-diff-enabled=${ARGOCD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF:-'false'}"
api-server: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''}"
dex: sh -c "ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/v2/cmd gendexcfg -o `pwd`/dist/dex.yaml && (test -f dist/dex.yaml || { echo 'Failed to generate dex configuration'; exit 1; }) && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:$(grep "image: ghcr.io/dexidp/dex" manifests/base/dex/argocd-dex-server-deployment.yaml | cut -d':' -f3) dex serve /dex.yaml"
redis: bash -c "if [ \"$ARGOCD_REDIS_LOCAL\" = 'true' ]; then redis-server --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; else docker run --rm --name argocd-redis -i -p ${ARGOCD_E2E_REDIS_PORT:-6379}:${ARGOCD_E2E_REDIS_PORT:-6379} docker.io/library/redis:$(grep "image: redis" manifests/base/redis/argocd-redis-deployment.yaml | cut -d':' -f3) --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; fi"

View File

@@ -13,6 +13,7 @@
**Social:**
[![Twitter Follow](https://img.shields.io/twitter/follow/argoproj?style=social)](https://twitter.com/argoproj)
[![Slack](https://img.shields.io/badge/slack-argoproj-brightgreen.svg?logo=slack)](https://argoproj.github.io/community/join-slack)
[![LinkedIn](https://img.shields.io/badge/LinkedIn-argoproj-blue.svg?logo=linkedin)](https://www.linkedin.com/company/argoproj/)
# Argo CD - Declarative Continuous Delivery for Kubernetes
@@ -85,4 +86,5 @@ Participation in the Argo CD project is governed by the [CNCF Code of Conduct](h
1. [Getting Started with ArgoCD for GitOps Deployments](https://youtu.be/AvLuplh1skA)
1. [Using Argo CD & Datree for Stable Kubernetes CI/CD Deployments](https://youtu.be/17894DTru2Y)
1. [How to create Argo CD Applications Automatically using ApplicationSet? "Automation of GitOps"](https://amralaayassen.medium.com/how-to-create-argocd-applications-automatically-using-applicationset-automation-of-the-gitops-59455eaf4f72)
1. [Progressive Delivery with Service Mesh Argo Rollouts with Istio](https://www.cncf.io/blog/2022/12/16/progressive-delivery-with-service-mesh-argo-rollouts-with-istio/)

View File

@@ -20,10 +20,12 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Allianz Direct](https://www.allianzdirect.de/)
1. [Amadeus IT Group](https://amadeus.com/)
1. [Ambassador Labs](https://www.getambassador.io/)
1. [Ancestry](https://www.ancestry.com/)
1. [ANSTO - Australian Synchrotron](https://www.synchrotron.org.au/)
1. [Ant Group](https://www.antgroup.com/)
1. [AppDirect](https://www.appdirect.com)
1. [Arctiq Inc.](https://www.arctiq.ca)
2. [Arturia](https://www.arturia.com)
1. [ARZ Allgemeines Rechenzentrum GmbH](https://www.arz.at/)
1. [Autodesk](https://www.autodesk.com)
1. [Axians ACSP](https://www.axians.fr)
@@ -40,17 +42,18 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Boozt](https://www.booztgroup.com/)
1. [Boticario](https://www.boticario.com.br/)
1. [Bulder Bank](https://bulderbank.no)
1. [CAM](https://cam-inc.co.jp)
1. [Camptocamp](https://camptocamp.com)
1. [Candis](https://www.candis.io)
1. [Capital One](https://www.capitalone.com)
1. [CARFAX](https://www.carfax.com)
1. [CARFAX Europe](https://www.carfax.eu)
1. [CARFAX](https://www.carfax.com)
1. [Carrefour Group](https://www.carrefour.com)
1. [Casavo](https://casavo.com)
1. [Celonis](https://www.celonis.com/)
1. [CERN](https://home.cern/)
1. [Chargetrip](https://chargetrip.com)
1. [Chainnodes](https://chainnodes.org)
1. [Chargetrip](https://chargetrip.com)
1. [Chime](https://www.chime.com)
1. [Cisco ET&I](https://eti.cisco.com/)
1. [Cloud Posse](https://www.cloudposse.com/)
@@ -93,6 +96,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Fave](https://myfave.com)
1. [Flexport](https://www.flexport.com/)
1. [Flip](https://flip.id)
1. [Fly Security](https://www.flysecurity.com.br/)
1. [Fonoa](https://www.fonoa.com/)
1. [Fortra](https://www.fortra.com)
1. [freee](https://corp.freee.co.jp/en/company/)
@@ -111,8 +115,8 @@ Currently, the following organizations are **officially** using Argo CD:
1. [GlueOps](https://glueops.dev)
1. [GMETRI](https://gmetri.com/)
1. [Gojek](https://www.gojek.io/)
1. [GoTo](https://www.goto.com/)
1. [GoTo Financial](https://gotofinancial.com/)
1. [GoTo](https://www.goto.com/)
1. [Greenpass](https://www.greenpass.com.br/)
1. [Gridfuse](https://gridfuse.com/)
1. [Groww](https://groww.in)
@@ -125,9 +129,11 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Hiya](https://hiya.com)
1. [Honestbank](https://honestbank.com)
1. [Hostinger](https://www.hostinger.com)
1. [IABAI](https://www.iab.ai)
1. [IBM](https://www.ibm.com/)
1. [Ibotta](https://home.ibotta.com)
1. [IITS-Consulting](https://iits-consulting.de)
1. [IllumiDesk](https://www.illumidesk.com)
1. [imaware](https://imaware.health)
1. [Indeed](https://indeed.com)
1. [Index Exchange](https://www.indexexchange.com/)
@@ -185,6 +191,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Natura &Co](https://naturaeco.com/)
1. [Nethopper](https://nethopper.io)
1. [New Relic](https://newrelic.com/)
1. [Nextbasket](https://nextbasket.com)
1. [Nextdoor](https://nextdoor.com/)
1. [Nikkei](https://www.nikkei.co.jp/nikkeiinfo/en/)
1. [Nitro](https://gonitro.com)
@@ -195,6 +202,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Olfeo](https://www.olfeo.com/)
1. [omegaUp](https://omegaUp.com)
1. [Omni](https://omni.se/)
1. [Oncourse Home Solutions](https://oncoursehome.com/)
1. [openEuler](https://openeuler.org)
1. [openGauss](https://opengauss.org/)
1. [OpenGov](https://opengov.com)
@@ -211,6 +219,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [PagerDuty](https://www.pagerduty.com/)
1. [Pandosearch](https://www.pandosearch.com/en/home)
1. [Patreon](https://www.patreon.com/)
1. [PayIt](https://payitgov.com/)
1. [PayPay](https://paypay.ne.jp/)
1. [Peloton Interactive](https://www.onepeloton.com/)
1. [Percona](https://percona.com/)
@@ -218,6 +227,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Pigment](https://www.gopigment.com/)
1. [Pipefy](https://www.pipefy.com/)
1. [Pismo](https://pismo.io/)
1. [PITS Globale Datenrettungsdienste](https://www.pitsdatenrettung.de/)
1. [Platform9 Systems](https://platform9.com/)
1. [Polarpoint.io](https://polarpoint.io)
1. [PostFinance](https://github.com/postfinance)
@@ -233,15 +243,18 @@ Currently, the following organizations are **officially** using Argo CD:
1. [QuintoAndar](https://quintoandar.com.br)
1. [Quipper](https://www.quipper.com/)
1. [RapidAPI](https://www.rapidapi.com/)
1. [rebuy](https://www.rebuy.de/)
1. [Recreation.gov](https://www.recreation.gov/)
1. [Red Hat](https://www.redhat.com/)
1. [Redpill Linpro](https://www.redpill-linpro.com/)
1. [Reenigne Cloud](https://reenigne.ca)
1. [reev.com](https://www.reev.com/)
1. [RightRev](https://rightrev.com/)
1. [Rijkswaterstaat](https://www.rijkswaterstaat.nl/en)
1. [Rise](https://www.risecard.eu/)
1. [Riskified](https://www.riskified.com/)
1. [Robotinfra](https://www.robotinfra.com)
1. [Rocket.Chat](https://rocket.chat)
1. [Rubin Observatory](https://www.lsst.org)
1. [Saildrone](https://www.saildrone.com/)
1. [Salad Technologies](https://salad.com/)
@@ -252,6 +265,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [SCRM Lidl International Hub](https://scrm.lidl)
1. [SEEK](https://seek.com.au)
1. [Semgrep](https://semgrep.com)
1. [Shield](https://shield.com)
1. [SI Analytics](https://si-analytics.ai)
1. [Skit](https://skit.ai/)
1. [Skyscanner](https://www.skyscanner.net/)
@@ -267,6 +281,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Splunk](https://splunk.com/)
1. [Spores Labs](https://spores.app)
1. [Statsig](https://statsig.com)
1. [SternumIOT](https://sternumiot.com)
1. [StreamNative](https://streamnative.io)
1. [Stuart](https://stuart.com/)
1. [Sumo Logic](https://sumologic.com/)
@@ -280,6 +295,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Tamkeen Technologies](https://tamkeentech.sa/)
1. [Techcombank](https://www.techcombank.com.vn/trang-chu)
1. [Technacy](https://www.technacy.it/)
1. [Telavita](https://www.telavita.com.br/)
1. [Tesla](https://tesla.com/)
1. [The Scale Factory](https://www.scalefactory.com/)
1. [ThousandEyes](https://www.thousandeyes.com/)

View File

@@ -1 +1 @@
2.9.0
2.11.3

View File

@@ -17,9 +17,11 @@ package controllers
import (
"context"
"fmt"
"reflect"
"strings"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
log "github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
apierr "k8s.io/apimachinery/pkg/api/errors"
@@ -50,6 +52,7 @@ import (
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
argoutil "github.com/argoproj/argo-cd/v2/util/argo"
"github.com/argoproj/argo-cd/v2/util/argo/normalizers"
"github.com/argoproj/argo-cd/v2/pkg/apis/application"
)
@@ -124,18 +127,20 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
// Log a warning if there are unrecognized generators
_ = utils.CheckInvalidGenerators(&applicationSetInfo)
// desiredApplications is the main list of all expected Applications from all generators in this appset.
desiredApplications, applicationSetReason, err := r.generateApplications(logCtx, applicationSetInfo)
if err != nil {
desiredApplications, applicationSetReason, generatorsErr := r.generateApplications(logCtx, applicationSetInfo)
if generatorsErr != nil {
_ = r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
Message: err.Error(),
Message: generatorsErr.Error(),
Reason: string(applicationSetReason),
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
}, parametersGenerated,
)
return ctrl.Result{}, err
if len(desiredApplications) < 1 {
return ctrl.Result{}, generatorsErr
}
}
parametersGenerated = true
@@ -309,7 +314,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
requeueAfter := r.getMinRequeueAfter(&applicationSetInfo)
if len(validateErrors) == 0 {
if len(validateErrors) == 0 && generatorsErr == nil {
if err := r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
@@ -666,7 +671,7 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context,
},
}
action, err := utils.CreateOrUpdate(ctx, appLog, r.Client, applicationSet.Spec.IgnoreApplicationDifferences, found, func() error {
action, err := utils.CreateOrUpdate(ctx, appLog, r.Client, applicationSet.Spec.IgnoreApplicationDifferences, normalizers.IgnoreNormalizerOpts{}, found, func() error {
// Copy only the Application/ObjectMeta fields that are significant, from the generatedApp
found.Spec = generatedApp.Spec
@@ -714,6 +719,17 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context,
}
}
// Preserve post-delete finalizers:
// https://github.com/argoproj/argo-cd/issues/17181
for _, finalizer := range found.ObjectMeta.Finalizers {
if strings.HasPrefix(finalizer, argov1alpha1.PostDeleteFinalizerName) {
if generatedApp.Finalizers == nil {
generatedApp.Finalizers = []string{}
}
generatedApp.Finalizers = append(generatedApp.Finalizers, finalizer)
}
}
found.ObjectMeta.Annotations = generatedApp.Annotations
found.ObjectMeta.Finalizers = generatedApp.Finalizers
@@ -1526,10 +1542,14 @@ func shouldRequeueApplicationSet(appOld *argov1alpha1.Application, appNew *argov
}
// the applicationset controller owns the application spec, labels, annotations, and finalizers on the applications
if !reflect.DeepEqual(appOld.Spec, appNew.Spec) ||
!reflect.DeepEqual(appOld.ObjectMeta.GetAnnotations(), appNew.ObjectMeta.GetAnnotations()) ||
!reflect.DeepEqual(appOld.ObjectMeta.GetLabels(), appNew.ObjectMeta.GetLabels()) ||
!reflect.DeepEqual(appOld.ObjectMeta.GetFinalizers(), appNew.ObjectMeta.GetFinalizers()) {
// reflect.DeepEqual considers nil slices/maps not equal to empty slices/maps
// https://pkg.go.dev/reflect#DeepEqual
// ApplicationDestination has an unexported field so we can just use the == for comparsion
if !cmp.Equal(appOld.Spec, appNew.Spec, cmpopts.EquateEmpty(), cmpopts.EquateComparable(argov1alpha1.ApplicationDestination{})) ||
!cmp.Equal(appOld.ObjectMeta.GetAnnotations(), appNew.ObjectMeta.GetAnnotations(), cmpopts.EquateEmpty()) ||
!cmp.Equal(appOld.ObjectMeta.GetLabels(), appNew.ObjectMeta.GetLabels(), cmpopts.EquateEmpty()) ||
!cmp.Equal(appOld.ObjectMeta.GetFinalizers(), appNew.ObjectMeta.GetFinalizers(), cmpopts.EquateEmpty()) {
return true
}

View File

@@ -1281,6 +1281,71 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
},
},
},
}, {
name: "Ensure that argocd post-delete finalizers are preserved from an existing app",
appSet: v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: v1alpha1.ApplicationSetSpec{
Template: v1alpha1.ApplicationSetTemplate{
Spec: v1alpha1.ApplicationSpec{
Project: "project",
},
},
},
},
existingApps: []v1alpha1.Application{
{
TypeMeta: metav1.TypeMeta{
Kind: application.ApplicationKind,
APIVersion: "argoproj.io/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
ResourceVersion: "2",
Finalizers: []string{
v1alpha1.PostDeleteFinalizerName,
v1alpha1.PostDeleteFinalizerName + "/mystage",
},
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
},
},
},
desiredApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
},
},
},
expected: []v1alpha1.Application{
{
TypeMeta: metav1.TypeMeta{
Kind: application.ApplicationKind,
APIVersion: "argoproj.io/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
ResourceVersion: "2",
Finalizers: []string{
v1alpha1.PostDeleteFinalizerName,
v1alpha1.PostDeleteFinalizerName + "/mystage",
},
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
},
},
},
},
} {
@@ -2423,6 +2488,91 @@ func TestReconcilerValidationProjectErrorBehaviour(t *testing.T) {
assert.Error(t, err)
}
func TestReconcilerCreateAppsRecoveringRenderError(t *testing.T) {
scheme := runtime.NewScheme()
err := v1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = v1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
project := v1alpha1.AppProject{
ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "argocd"},
}
appSet := v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSetSpec{
GoTemplate: true,
Generators: []v1alpha1.ApplicationSetGenerator{
{
List: &v1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{{
Raw: []byte(`{"name": "very-good-app"}`),
}, {
Raw: []byte(`{"name": "bad-app"}`),
}},
},
},
},
Template: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "{{ index (splitList \"-\" .name ) 2 }}",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argocd-example-apps", Path: "guestbook"},
Project: "default",
Destination: v1alpha1.ApplicationDestination{Server: "https://kubernetes.default.svc"},
},
},
},
}
kubeclientset := kubefake.NewSimpleClientset()
argoDBMock := dbmocks.ArgoDB{}
argoObjs := []runtime.Object{&project}
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build()
r := ApplicationSetReconciler{
Client: client,
Scheme: scheme,
Renderer: &utils.Render{},
Recorder: record.NewFakeRecorder(1),
Cache: &fakeCache{},
Generators: map[string]generators.Generator{
"List": generators.NewListGenerator(),
},
ArgoDB: &argoDBMock,
ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...),
KubeClientset: kubeclientset,
Policy: v1alpha1.ApplicationsSyncPolicySync,
ArgoCDNamespace: "argocd",
}
req := ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: "argocd",
Name: "name",
},
}
// Verify that on generatorsError, no error is returned, but the object is requeued
res, err := r.Reconcile(context.Background(), req)
assert.Nil(t, err)
assert.True(t, res.RequeueAfter == ReconcileRequeueOnValidationError)
var app v1alpha1.Application
// make sure good app got created
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "app"}, &app)
assert.NoError(t, err)
assert.Equal(t, app.Name, "app")
}
func TestSetApplicationSetStatusCondition(t *testing.T) {
scheme := runtime.NewScheme()
err := v1alpha1.AddToScheme(scheme)
@@ -6087,14 +6237,70 @@ func TestOwnsHandler(t *testing.T) {
ObjectOld: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}}},
ObjectNew: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"bar": "foo"}}},
}}, want: true},
{name: "DifferentApplicationLabelsNil", args: args{e: event.UpdateEvent{
ObjectOld: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{}}},
ObjectNew: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Labels: nil}},
}}, want: false},
{name: "DifferentApplicationAnnotations", args: args{e: event.UpdateEvent{
ObjectOld: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"foo": "bar"}}},
ObjectNew: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"bar": "foo"}}},
}}, want: true},
{name: "DifferentApplicationAnnotationsNil", args: args{e: event.UpdateEvent{
ObjectOld: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}}},
ObjectNew: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Annotations: nil}},
}}, want: false},
{name: "DifferentApplicationFinalizers", args: args{e: event.UpdateEvent{
ObjectOld: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Finalizers: []string{"argo"}}},
ObjectNew: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Finalizers: []string{"none"}}},
}}, want: true},
{name: "DifferentApplicationFinalizersNil", args: args{e: event.UpdateEvent{
ObjectOld: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Finalizers: []string{}}},
ObjectNew: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Finalizers: nil}},
}}, want: false},
{name: "ApplicationDestinationSame", args: args{e: event.UpdateEvent{
ObjectOld: &v1alpha1.Application{
Spec: v1alpha1.ApplicationSpec{
Destination: v1alpha1.ApplicationDestination{
Server: "server",
Namespace: "ns",
Name: "name",
},
},
},
ObjectNew: &v1alpha1.Application{
Spec: v1alpha1.ApplicationSpec{
Destination: v1alpha1.ApplicationDestination{
Server: "server",
Namespace: "ns",
Name: "name",
},
},
},
},
enableProgressiveSyncs: true,
}, want: false},
{name: "ApplicationDestinationDiff", args: args{e: event.UpdateEvent{
ObjectOld: &v1alpha1.Application{
Spec: v1alpha1.ApplicationSpec{
Destination: v1alpha1.ApplicationDestination{
Server: "server",
Namespace: "ns",
Name: "name",
},
},
},
ObjectNew: &v1alpha1.Application{
Spec: v1alpha1.ApplicationSpec{
Destination: v1alpha1.ApplicationDestination{
Server: "notSameServer",
Namespace: "ns",
Name: "name",
},
},
},
},
enableProgressiveSyncs: true,
}, want: true},
{name: "NotAnAppOld", args: args{e: event.UpdateEvent{
ObjectOld: &v1alpha1.AppProject{},
ObjectNew: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"bar": "foo"}}},

View File

@@ -20,6 +20,7 @@ import (
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/argo"
argodiff "github.com/argoproj/argo-cd/v2/util/argo/diff"
"github.com/argoproj/argo-cd/v2/util/argo/normalizers"
)
// CreateOrUpdate overrides "sigs.k8s.io/controller-runtime" function
@@ -35,7 +36,7 @@ import (
// The MutateFn is called regardless of creating or updating an object.
//
// It returns the executed operation and an error.
func CreateOrUpdate(ctx context.Context, logCtx *log.Entry, c client.Client, ignoreAppDifferences argov1alpha1.ApplicationSetIgnoreDifferences, obj *argov1alpha1.Application, f controllerutil.MutateFn) (controllerutil.OperationResult, error) {
func CreateOrUpdate(ctx context.Context, logCtx *log.Entry, c client.Client, ignoreAppDifferences argov1alpha1.ApplicationSetIgnoreDifferences, ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts, obj *argov1alpha1.Application, f controllerutil.MutateFn) (controllerutil.OperationResult, error) {
key := client.ObjectKeyFromObject(obj)
if err := c.Get(ctx, key, obj); err != nil {
@@ -60,7 +61,7 @@ func CreateOrUpdate(ctx context.Context, logCtx *log.Entry, c client.Client, ign
// Apply ignoreApplicationDifferences rules to remove ignored fields from both the live and the desired state. This
// prevents those differences from appearing in the diff and therefore in the patch.
err := applyIgnoreDifferences(ignoreAppDifferences, normalizedLive, obj)
err := applyIgnoreDifferences(ignoreAppDifferences, normalizedLive, obj, ignoreNormalizerOpts)
if err != nil {
return controllerutil.OperationResultNone, fmt.Errorf("failed to apply ignore differences: %w", err)
}
@@ -134,14 +135,14 @@ func mutate(f controllerutil.MutateFn, key client.ObjectKey, obj client.Object)
}
// applyIgnoreDifferences applies the ignore differences rules to the found application. It modifies the applications in place.
func applyIgnoreDifferences(applicationSetIgnoreDifferences argov1alpha1.ApplicationSetIgnoreDifferences, found *argov1alpha1.Application, generatedApp *argov1alpha1.Application) error {
func applyIgnoreDifferences(applicationSetIgnoreDifferences argov1alpha1.ApplicationSetIgnoreDifferences, found *argov1alpha1.Application, generatedApp *argov1alpha1.Application, ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts) error {
if len(applicationSetIgnoreDifferences) == 0 {
return nil
}
generatedAppCopy := generatedApp.DeepCopy()
diffConfig, err := argodiff.NewDiffConfigBuilder().
WithDiffSettings(applicationSetIgnoreDifferences.ToApplicationIgnoreDifferences(), nil, false).
WithDiffSettings(applicationSetIgnoreDifferences.ToApplicationIgnoreDifferences(), nil, false, ignoreNormalizerOpts).
WithNoCache().
Build()
if err != nil {

View File

@@ -9,6 +9,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/argo/normalizers"
)
func Test_applyIgnoreDifferences(t *testing.T) {
@@ -222,7 +223,7 @@ spec:
generatedApp := v1alpha1.Application{TypeMeta: appMeta}
err = yaml.Unmarshal([]byte(tc.generatedApp), &generatedApp)
require.NoError(t, err, tc.generatedApp)
err = applyIgnoreDifferences(tc.ignoreDifferences, &foundApp, &generatedApp)
err = applyIgnoreDifferences(tc.ignoreDifferences, &foundApp, &generatedApp, normalizers.IgnoreNormalizerOpts{})
require.NoError(t, err)
yamlFound, err := yaml.Marshal(tc.foundApp)
require.NoError(t, err)

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -975,6 +975,25 @@
"type": "string",
"name": "project",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string",
"format": "int64"
},
"collectionFormat": "multi",
"name": "sourcePositions",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"name": "revisions",
"in": "query"
}
],
"responses": {
@@ -4219,6 +4238,19 @@
"revision": {
"type": "string"
},
"revisions": {
"type": "array",
"items": {
"type": "string"
}
},
"sourcePositions": {
"type": "array",
"items": {
"type": "string",
"format": "int64"
}
},
"strategy": {
"$ref": "#/definitions/v1alpha1SyncStrategy"
},
@@ -5664,6 +5696,10 @@
"type": "string",
"title": "ClusterName contains AWS cluster name"
},
"profile": {
"description": "Profile contains optional role ARN. If set then AWS IAM Authenticator uses the profile to perform cluster operations instead of the default AWS credential provider chain.",
"type": "string"
},
"roleARN": {
"description": "RoleARN contains optional role ARN. If set then AWS IAM Authenticator assume a role to perform cluster operations instead of the default AWS credential provider chain.",
"type": "string"
@@ -6420,6 +6456,10 @@
"type": "string"
}
},
"labelWithoutSelector": {
"type": "boolean",
"title": "LabelWithoutSelector specifies whether to apply common labels to resource selectors or not"
},
"namePrefix": {
"type": "string",
"title": "NamePrefix is a prefix appended to resources for Kustomize apps"
@@ -7405,6 +7445,7 @@
"properties": {
"elements": {
"type": "array",
"title": "+kubebuilder:validation:Optional",
"items": {
"$ref": "#/definitions/v1JSON"
}
@@ -8499,6 +8540,9 @@
"format": "int64",
"title": "ID is an auto incrementing identifier of the RevisionHistory"
},
"initiatedBy": {
"$ref": "#/definitions/v1alpha1OperationInitiator"
},
"revision": {
"type": "string",
"title": "Revision holds the revision the sync was performed against"

View File

@@ -6,7 +6,6 @@ import (
"math"
"time"
"github.com/argoproj/argo-cd/v2/pkg/ratelimiter"
"github.com/argoproj/pkg/stats"
"github.com/redis/go-redis/v9"
log "github.com/sirupsen/logrus"
@@ -20,19 +19,18 @@ import (
"github.com/argoproj/argo-cd/v2/controller/sharding"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
"github.com/argoproj/argo-cd/v2/pkg/ratelimiter"
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/util/argo/normalizers"
cacheutil "github.com/argoproj/argo-cd/v2/util/cache"
appstatecache "github.com/argoproj/argo-cd/v2/util/cache/appstate"
"github.com/argoproj/argo-cd/v2/util/cli"
"github.com/argoproj/argo-cd/v2/util/db"
"github.com/argoproj/argo-cd/v2/util/env"
"github.com/argoproj/argo-cd/v2/util/errors"
kubeutil "github.com/argoproj/argo-cd/v2/util/kube"
"github.com/argoproj/argo-cd/v2/util/settings"
"github.com/argoproj/argo-cd/v2/util/tls"
"github.com/argoproj/argo-cd/v2/util/trace"
kubeerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const (
@@ -50,6 +48,7 @@ func NewCommand() *cobra.Command {
clientConfig clientcmd.ClientConfig
appResyncPeriod int64
appHardResyncPeriod int64
appResyncJitter int64
repoErrorGracePeriod int64
repoServerAddress string
repoServerTimeoutSeconds int
@@ -74,6 +73,7 @@ func NewCommand() *cobra.Command {
shardingAlgorithm string
enableDynamicClusterDistribution bool
serverSideDiff bool
ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts
)
var command = cobra.Command{
Use: cliName,
@@ -146,7 +146,8 @@ func NewCommand() *cobra.Command {
appController.InvalidateProjectsCache()
}))
kubectl := kubeutil.NewKubectl()
clusterFilter := getClusterFilter(kubeClient, settingsMgr, shardingAlgorithm, enableDynamicClusterDistribution)
clusterSharding, err := sharding.GetClusterSharding(kubeClient, settingsMgr, shardingAlgorithm, enableDynamicClusterDistribution)
errors.CheckError(err)
appController, err = controller.NewApplicationController(
namespace,
settingsMgr,
@@ -157,6 +158,7 @@ func NewCommand() *cobra.Command {
kubectl,
resyncDuration,
hardResyncDuration,
time.Duration(appResyncJitter)*time.Second,
time.Duration(selfHealTimeoutSeconds)*time.Second,
time.Duration(repoErrorGracePeriod)*time.Second,
metricsPort,
@@ -164,10 +166,12 @@ func NewCommand() *cobra.Command {
metricsAplicationLabels,
kubectlParallelismLimit,
persistResourceHealth,
clusterFilter,
clusterSharding,
applicationNamespaces,
&workqueueRateLimit,
serverSideDiff,
enableDynamicClusterDistribution,
ignoreNormalizerOpts,
)
errors.CheckError(err)
cacheutil.CollectMetrics(redisClient, appController.GetMetricsServer())
@@ -194,6 +198,7 @@ func NewCommand() *cobra.Command {
clientConfig = cli.AddKubectlFlagsToCmd(&command)
command.Flags().Int64Var(&appResyncPeriod, "app-resync", int64(env.ParseDurationFromEnv("ARGOCD_RECONCILIATION_TIMEOUT", defaultAppResyncPeriod*time.Second, 0, math.MaxInt64).Seconds()), "Time period in seconds for application resync.")
command.Flags().Int64Var(&appHardResyncPeriod, "app-hard-resync", int64(env.ParseDurationFromEnv("ARGOCD_HARD_RECONCILIATION_TIMEOUT", defaultAppHardResyncPeriod*time.Second, 0, math.MaxInt64).Seconds()), "Time period in seconds for application hard resync.")
command.Flags().Int64Var(&appResyncJitter, "app-resync-jitter", int64(env.ParseDurationFromEnv("ARGOCD_RECONCILIATION_JITTER", 0*time.Second, 0, math.MaxInt64).Seconds()), "Maximum time period in seconds to add as a delay jitter for application resync.")
command.Flags().Int64Var(&repoErrorGracePeriod, "repo-error-grace-period-seconds", int64(env.ParseDurationFromEnv("ARGOCD_REPO_ERROR_GRACE_PERIOD_SECONDS", defaultAppResyncPeriod*time.Second, 0, math.MaxInt64).Seconds()), "Grace period in seconds for ignoring consecutive errors while communicating with repo server.")
command.Flags().StringVar(&repoServerAddress, "repo-server", env.StringFromEnv("ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER", common.DefaultRepoServerAddr), "Repo server address.")
command.Flags().IntVar(&repoServerTimeoutSeconds, "repo-server-timeout-seconds", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS", 60, 0, math.MaxInt64), "Repo server RPC call timeout seconds.")
@@ -218,7 +223,7 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&shardingAlgorithm, "sharding-method", env.StringFromEnv(common.EnvControllerShardingAlgorithm, common.DefaultShardingAlgorithm), "Enables choice of sharding method. Supported sharding methods are : [legacy, round-robin] ")
// global queue rate limit config
command.Flags().Int64Var(&workqueueRateLimit.BucketSize, "wq-bucket-size", env.ParseInt64FromEnv("WORKQUEUE_BUCKET_SIZE", 500, 1, math.MaxInt64), "Set Workqueue Rate Limiter Bucket Size, default 500")
command.Flags().Int64Var(&workqueueRateLimit.BucketQPS, "wq-bucket-qps", env.ParseInt64FromEnv("WORKQUEUE_BUCKET_QPS", 50, 1, math.MaxInt64), "Set Workqueue Rate Limiter Bucket QPS, default 50")
command.Flags().Float64Var(&workqueueRateLimit.BucketQPS, "wq-bucket-qps", env.ParseFloat64FromEnv("WORKQUEUE_BUCKET_QPS", math.MaxFloat64, 1, math.MaxFloat64), "Set Workqueue Rate Limiter Bucket QPS, default set to MaxFloat64 which disables the bucket limiter")
// individual item rate limit config
// when WORKQUEUE_FAILURE_COOLDOWN is 0 per item rate limiting is disabled(default)
command.Flags().DurationVar(&workqueueRateLimit.FailureCoolDown, "wq-cooldown-ns", time.Duration(env.ParseInt64FromEnv("WORKQUEUE_FAILURE_COOLDOWN_NS", 0, 0, (24*time.Hour).Nanoseconds())), "Set Workqueue Per Item Rate Limiter Cooldown duration in ns, default 0(per item rate limiter disabled)")
@@ -227,63 +232,11 @@ func NewCommand() *cobra.Command {
command.Flags().Float64Var(&workqueueRateLimit.BackoffFactor, "wq-backoff-factor", env.ParseFloat64FromEnv("WORKQUEUE_BACKOFF_FACTOR", 1.5, 0, math.MaxFloat64), "Set Workqueue Per Item Rate Limiter Backoff Factor, default is 1.5")
command.Flags().BoolVar(&enableDynamicClusterDistribution, "dynamic-cluster-distribution-enabled", env.ParseBoolFromEnv(common.EnvEnableDynamicClusterDistribution, false), "Enables dynamic cluster distribution.")
command.Flags().BoolVar(&serverSideDiff, "server-side-diff-enabled", env.ParseBoolFromEnv(common.EnvServerSideDiff, false), "Feature flag to enable ServerSide diff. Default (\"false\")")
cacheSource = appstatecache.AddCacheFlagsToCmd(&command, func(client *redis.Client) {
redisClient = client
command.Flags().DurationVar(&ignoreNormalizerOpts.JQExecutionTimeout, "ignore-normalizer-jq-execution-timeout-seconds", env.ParseDurationFromEnv("ARGOCD_IGNORE_NORMALIZER_JQ_TIMEOUT", 0*time.Second, 0, math.MaxInt64), "Set ignore normalizer JQ execution timeout")
cacheSource = appstatecache.AddCacheFlagsToCmd(&command, cacheutil.Options{
OnClientCreated: func(client *redis.Client) {
redisClient = client
},
})
return &command
}
func getClusterFilter(kubeClient *kubernetes.Clientset, settingsMgr *settings.SettingsManager, shardingAlgorithm string, enableDynamicClusterDistribution bool) sharding.ClusterFilterFunction {
var replicas int
shard := env.ParseNumFromEnv(common.EnvControllerShard, -1, -math.MaxInt32, math.MaxInt32)
applicationControllerName := env.StringFromEnv(common.EnvAppControllerName, common.DefaultApplicationControllerName)
appControllerDeployment, err := kubeClient.AppsV1().Deployments(settingsMgr.GetNamespace()).Get(context.Background(), applicationControllerName, metav1.GetOptions{})
// if the application controller deployment was not found, the Get() call returns an empty Deployment object. So, set the variable to nil explicitly
if err != nil && kubeerrors.IsNotFound(err) {
appControllerDeployment = nil
}
if enableDynamicClusterDistribution && appControllerDeployment != nil && appControllerDeployment.Spec.Replicas != nil {
replicas = int(*appControllerDeployment.Spec.Replicas)
} else {
replicas = env.ParseNumFromEnv(common.EnvControllerReplicas, 0, 0, math.MaxInt32)
}
var clusterFilter func(cluster *v1alpha1.Cluster) bool
if replicas > 1 {
// check for shard mapping using configmap if application-controller is a deployment
// else use existing logic to infer shard from pod name if application-controller is a statefulset
if enableDynamicClusterDistribution && appControllerDeployment != nil {
var err error
// retry 3 times if we find a conflict while updating shard mapping configMap.
// If we still see conflicts after the retries, wait for next iteration of heartbeat process.
for i := 0; i <= common.AppControllerHeartbeatUpdateRetryCount; i++ {
shard, err = sharding.GetOrUpdateShardFromConfigMap(kubeClient, settingsMgr, replicas, shard)
if !kubeerrors.IsConflict(err) {
err = fmt.Errorf("unable to get shard due to error updating the sharding config map: %s", err)
break
}
log.Warnf("conflict when getting shard from shard mapping configMap. Retrying (%d/3)", i)
}
errors.CheckError(err)
} else {
if shard < 0 {
var err error
shard, err = sharding.InferShard()
errors.CheckError(err)
}
}
log.Infof("Processing clusters from shard %d", shard)
db := db.NewDB(settingsMgr.GetNamespace(), settingsMgr, kubeClient)
log.Infof("Using filter function: %s", shardingAlgorithm)
distributionFunction := sharding.GetDistributionFunction(db, shardingAlgorithm)
clusterFilter = sharding.GetClusterFilter(db, distributionFunction, shard)
} else {
log.Info("Processing all cluster shards")
}
return clusterFilter
}

View File

@@ -37,13 +37,14 @@ func newAWSCommand() *cobra.Command {
var (
clusterName string
roleARN string
profile string
)
var command = &cobra.Command{
Use: "aws",
Run: func(c *cobra.Command, args []string) {
ctx := c.Context()
presignedURLString, err := getSignedRequestWithRetry(ctx, time.Minute, 5*time.Second, clusterName, roleARN, getSignedRequest)
presignedURLString, err := getSignedRequestWithRetry(ctx, time.Minute, 5*time.Second, clusterName, roleARN, profile, getSignedRequest)
errors.CheckError(err)
token := v1Prefix + base64.RawURLEncoding.EncodeToString([]byte(presignedURLString))
// Set token expiration to 1 minute before the presigned URL expires for some cushion
@@ -53,16 +54,17 @@ func newAWSCommand() *cobra.Command {
}
command.Flags().StringVar(&clusterName, "cluster-name", "", "AWS Cluster name")
command.Flags().StringVar(&roleARN, "role-arn", "", "AWS Role ARN")
command.Flags().StringVar(&profile, "profile", "", "AWS Profile")
return command
}
type getSignedRequestFunc func(clusterName, roleARN string) (string, error)
type getSignedRequestFunc func(clusterName, roleARN string, profile string) (string, error)
func getSignedRequestWithRetry(ctx context.Context, timeout, interval time.Duration, clusterName, roleARN string, fn getSignedRequestFunc) (string, error) {
func getSignedRequestWithRetry(ctx context.Context, timeout, interval time.Duration, clusterName, roleARN string, profile string, fn getSignedRequestFunc) (string, error) {
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
for {
signed, err := fn(clusterName, roleARN)
signed, err := fn(clusterName, roleARN, profile)
if err == nil {
return signed, nil
}
@@ -74,8 +76,10 @@ func getSignedRequestWithRetry(ctx context.Context, timeout, interval time.Durat
}
}
func getSignedRequest(clusterName, roleARN string) (string, error) {
sess, err := session.NewSession()
func getSignedRequest(clusterName, roleARN string, profile string) (string, error) {
sess, err := session.NewSessionWithOptions(session.Options{
Profile: profile,
})
if err != nil {
return "", fmt.Errorf("error creating new AWS session: %s", err)
}

View File

@@ -22,7 +22,7 @@ func TestGetSignedRequestWithRetry(t *testing.T) {
}
// when
signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", mock.getSignedRequestMock)
signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", "", mock.getSignedRequestMock)
// then
assert.NoError(t, err)
@@ -41,7 +41,7 @@ func TestGetSignedRequestWithRetry(t *testing.T) {
}
// when
signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", mock.getSignedRequestMock)
signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", "", mock.getSignedRequestMock)
// then
assert.NoError(t, err)
@@ -57,7 +57,7 @@ func TestGetSignedRequestWithRetry(t *testing.T) {
}
// when
signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", mock.getSignedRequestMock)
signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", "", mock.getSignedRequestMock)
// then
assert.Error(t, err)
@@ -70,7 +70,7 @@ type signedRequestMock struct {
returnFunc func(m *signedRequestMock) (string, error)
}
func (m *signedRequestMock) getSignedRequestMock(clusterName, roleARN string) (string, error) {
func (m *signedRequestMock) getSignedRequestMock(clusterName, roleARN string, profile string) (string, error) {
m.getSignedRequestCalls++
return m.returnFunc(m)
}

View File

@@ -68,6 +68,7 @@ func NewCommand() *cobra.Command {
streamedManifestMaxTarSize string
streamedManifestMaxExtractedSize string
helmManifestMaxExtractedSize string
helmRegistryMaxIndexSize string
disableManifestMaxExtractedSize bool
)
var command = cobra.Command{
@@ -110,6 +111,9 @@ func NewCommand() *cobra.Command {
helmManifestMaxExtractedSizeQuantity, err := resource.ParseQuantity(helmManifestMaxExtractedSize)
errors.CheckError(err)
helmRegistryMaxIndexSizeQuantity, err := resource.ParseQuantity(helmRegistryMaxIndexSize)
errors.CheckError(err)
askPassServer := askpass.NewServer()
metricsServer := metrics.NewMetricsServer()
cacheutil.CollectMetrics(redisClient, metricsServer)
@@ -125,6 +129,7 @@ func NewCommand() *cobra.Command {
StreamedManifestMaxExtractedSize: streamedManifestMaxExtractedSizeQuantity.ToDec().Value(),
StreamedManifestMaxTarSize: streamedManifestMaxTarSizeQuantity.ToDec().Value(),
HelmManifestMaxExtractedSize: helmManifestMaxExtractedSizeQuantity.ToDec().Value(),
HelmRegistryMaxIndexSize: helmRegistryMaxIndexSizeQuantity.ToDec().Value(),
}, askPassServer)
errors.CheckError(err)
@@ -208,10 +213,13 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&streamedManifestMaxTarSize, "streamed-manifest-max-tar-size", env.StringFromEnv("ARGOCD_REPO_SERVER_STREAMED_MANIFEST_MAX_TAR_SIZE", "100M"), "Maximum size of streamed manifest archives")
command.Flags().StringVar(&streamedManifestMaxExtractedSize, "streamed-manifest-max-extracted-size", env.StringFromEnv("ARGOCD_REPO_SERVER_STREAMED_MANIFEST_MAX_EXTRACTED_SIZE", "1G"), "Maximum size of streamed manifest archives when extracted")
command.Flags().StringVar(&helmManifestMaxExtractedSize, "helm-manifest-max-extracted-size", env.StringFromEnv("ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE", "1G"), "Maximum size of helm manifest archives when extracted")
command.Flags().StringVar(&helmRegistryMaxIndexSize, "helm-registry-max-index-size", env.StringFromEnv("ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_INDEX_SIZE", "1G"), "Maximum size of registry index file")
command.Flags().BoolVar(&disableManifestMaxExtractedSize, "disable-helm-manifest-max-extracted-size", env.ParseBoolFromEnv("ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE", false), "Disable maximum size of helm manifest archives when extracted")
tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(&command)
cacheSrc = reposervercache.AddCacheFlagsToCmd(&command, func(client *redis.Client) {
redisClient = client
cacheSrc = reposervercache.AddCacheFlagsToCmd(&command, cacheutil.Options{
OnClientCreated: func(client *redis.Client) {
redisClient = client
},
})
return &command
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"math"
"strings"
"time"
"github.com/argoproj/pkg/stats"
@@ -18,8 +19,10 @@ import (
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
reposervercache "github.com/argoproj/argo-cd/v2/reposerver/cache"
"github.com/argoproj/argo-cd/v2/server"
servercache "github.com/argoproj/argo-cd/v2/server/cache"
cacheutil "github.com/argoproj/argo-cd/v2/util/cache"
"github.com/argoproj/argo-cd/v2/util/cli"
"github.com/argoproj/argo-cd/v2/util/dex"
"github.com/argoproj/argo-cd/v2/util/env"
@@ -61,9 +64,11 @@ func NewCommand() *cobra.Command {
repoServerAddress string
dexServerAddress string
disableAuth bool
contentTypes string
enableGZip bool
tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error)
cacheSrc func() (*servercache.Cache, error)
repoServerCacheSrc func() (*reposervercache.Cache, error)
frameOptions string
contentSecurityPolicy string
repoServerPlaintext bool
@@ -105,6 +110,8 @@ func NewCommand() *cobra.Command {
errors.CheckError(err)
cache, err := cacheSrc()
errors.CheckError(err)
repoServerCache, err := repoServerCacheSrc()
errors.CheckError(err)
kubeclientset := kubernetes.NewForConfigOrDie(config)
@@ -165,6 +172,11 @@ func NewCommand() *cobra.Command {
baseHRef = rootPath
}
var contentTypesList []string
if contentTypes != "" {
contentTypesList = strings.Split(contentTypes, ";")
}
argoCDOpts := server.ArgoCDServerOpts{
Insecure: insecure,
ListenPort: listenPort,
@@ -180,9 +192,11 @@ func NewCommand() *cobra.Command {
DexServerAddr: dexServerAddress,
DexTLSConfig: dexTlsConfig,
DisableAuth: disableAuth,
ContentTypes: contentTypesList,
EnableGZip: enableGZip,
TLSConfigCustomizer: tlsConfigCustomizer,
Cache: cache,
RepoServerCache: repoServerCache,
XFrameOptions: frameOptions,
ContentSecurityPolicy: contentSecurityPolicy,
RedisClient: redisClient,
@@ -234,6 +248,7 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&repoServerAddress, "repo-server", env.StringFromEnv("ARGOCD_SERVER_REPO_SERVER", common.DefaultRepoServerAddr), "Repo server address")
command.Flags().StringVar(&dexServerAddress, "dex-server", env.StringFromEnv("ARGOCD_SERVER_DEX_SERVER", common.DefaultDexServerAddr), "Dex server address")
command.Flags().BoolVar(&disableAuth, "disable-auth", env.ParseBoolFromEnv("ARGOCD_SERVER_DISABLE_AUTH", false), "Disable client authentication")
command.Flags().StringVar(&contentTypes, "api-content-types", env.StringFromEnv("ARGOCD_API_CONTENT_TYPES", "application/json", env.StringFromEnvOpts{AllowEmpty: true}), "Semicolon separated list of allowed content types for non GET api requests. Any content type is allowed if empty.")
command.Flags().BoolVar(&enableGZip, "enable-gzip", env.ParseBoolFromEnv("ARGOCD_SERVER_ENABLE_GZIP", true), "Enable GZIP compression")
command.AddCommand(cli.NewVersionCmd(cliName))
command.Flags().StringVar(&listenHost, "address", env.StringFromEnv("ARGOCD_SERVER_LISTEN_ADDRESS", common.DefaultAddressAPIServer), "Listen on given address")
@@ -254,8 +269,11 @@ func NewCommand() *cobra.Command {
command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces where application resources can be managed in")
command.Flags().BoolVar(&enableProxyExtension, "enable-proxy-extension", env.ParseBoolFromEnv("ARGOCD_SERVER_ENABLE_PROXY_EXTENSION", false), "Enable Proxy Extension feature")
tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(command)
cacheSrc = servercache.AddCacheFlagsToCmd(command, func(client *redis.Client) {
redisClient = client
cacheSrc = servercache.AddCacheFlagsToCmd(command, cacheutil.Options{
OnClientCreated: func(client *redis.Client) {
redisClient = client
},
})
repoServerCacheSrc = reposervercache.AddCacheFlagsToCmd(command, cacheutil.Options{FlagPrefix: "repo-server-"})
return command
}

View File

@@ -48,84 +48,9 @@ func NewAdminCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
Run: func(c *cobra.Command, args []string) {
c.HelpFunc()(c, args)
},
Example: `# List all clusters
$ argocd admin cluster list
# Add a new cluster
$ argocd admin cluster add my-cluster --name my-cluster --in-cluster-context
# Remove a cluster
argocd admin cluster remove my-cluster
# List all projects
$ argocd admin project list
# Create a new project
$argocd admin project create my-project --src-namespace my-source-namespace --dest-namespace my-dest-namespace
# Update a project
$ argocd admin project update my-project --src-namespace my-updated-source-namespace --dest-namespace my-updated-dest-namespace
# Delete a project
$ argocd admin project delete my-project
# List all settings
$ argocd admin settings list
# Get the current settings
$ argocd admin settings get
# Update settings
$ argocd admin settings update --repository.resync --value 15
# List all applications
$ argocd admin app list
# Get application details
$ argocd admin app get my-app
# Sync an application
$ argocd admin app sync my-app
# Pause an application
$ argocd admin app pause my-app
# Resume an application
$ argocd admin app resume my-app
# List all repositories
$ argocd admin repo list
# Add a repository
$ argocd admin repo add https://github.com/argoproj/my-repo.git
# Remove a repository
$ argocd admin repo remove https://github.com/argoproj/my-repo.git
# Import an application from a YAML file
$ argocd admin app import -f my-app.yaml
# Export an application to a YAML file
$ argocd admin app export my-app -o my-exported-app.yaml
# Access the Argo CD web UI
Example: `# Access the Argo CD web UI
$ argocd admin dashboard
# List notifications
$ argocd admin notification list
# Get notification details
$ argocd admin notification get my-notification
# Create a new notification
$ argocd admin notification create my-notification -f notification-config.yaml
# Update a notification
$ argocd admin notification update my-notification -f updated-notification-config.yaml
# Delete a notification
$ argocd admin notification delete my-notification
# Reset the initial admin password
$ argocd admin initial-password reset
`,
@@ -141,6 +66,7 @@ $ argocd admin initial-password reset
command.AddCommand(NewDashboardCommand(clientOpts))
command.AddCommand(NewNotificationsCommand())
command.AddCommand(NewInitialPasswordCommand())
command.AddCommand(NewRedisInitialPasswordCommand())
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", "text", "Set the logging format. One of: text|json")
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")

View File

@@ -24,12 +24,14 @@ import (
"github.com/argoproj/argo-cd/v2/controller"
"github.com/argoproj/argo-cd/v2/controller/cache"
"github.com/argoproj/argo-cd/v2/controller/metrics"
"github.com/argoproj/argo-cd/v2/controller/sharding"
argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
appinformers "github.com/argoproj/argo-cd/v2/pkg/client/informers/externalversions"
reposerverclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/util/argo"
"github.com/argoproj/argo-cd/v2/util/argo/normalizers"
cacheutil "github.com/argoproj/argo-cd/v2/util/cache"
appstatecache "github.com/argoproj/argo-cd/v2/util/cache/appstate"
"github.com/argoproj/argo-cd/v2/util/cli"
@@ -238,12 +240,13 @@ func diffReconcileResults(res1 reconcileResults, res2 reconcileResults) error {
func NewReconcileCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
clientConfig clientcmd.ClientConfig
selector string
repoServerAddress string
outputFormat string
refresh bool
serverSideDiff bool
clientConfig clientcmd.ClientConfig
selector string
repoServerAddress string
outputFormat string
refresh bool
serverSideDiff bool
ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts
)
var command = &cobra.Command{
@@ -269,19 +272,27 @@ func NewReconcileCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
var result []appReconcileResult
if refresh {
appClientset := appclientset.NewForConfigOrDie(cfg)
kubeClientset := kubernetes.NewForConfigOrDie(cfg)
if repoServerAddress == "" {
printLine("Repo server is not provided, trying to port-forward to argocd-repo-server pod.")
overrides := clientcmd.ConfigOverrides{}
repoServerPodLabelSelector := common.LabelKeyAppName + "=" + clientOpts.RepoServerName
repoServerName := clientOpts.RepoServerName
repoServerServiceLabelSelector := common.LabelKeyComponentRepoServer + "=" + common.LabelValueComponentRepoServer
repoServerServices, err := kubeClientset.CoreV1().Services(namespace).List(context.Background(), v1.ListOptions{LabelSelector: repoServerServiceLabelSelector})
errors.CheckError(err)
if len(repoServerServices.Items) > 0 {
if repoServerServicelabel, ok := repoServerServices.Items[0].Labels[common.LabelKeyAppName]; ok && repoServerServicelabel != "" {
repoServerName = repoServerServicelabel
}
}
repoServerPodLabelSelector := common.LabelKeyAppName + "=" + repoServerName
repoServerPort, err := kubeutil.PortForward(8081, namespace, &overrides, repoServerPodLabelSelector)
errors.CheckError(err)
repoServerAddress = fmt.Sprintf("localhost:%d", repoServerPort)
}
repoServerClient := reposerverclient.NewRepoServerClientset(repoServerAddress, 60, reposerverclient.TLSConfiguration{DisableTLS: false, StrictValidation: false})
appClientset := appclientset.NewForConfigOrDie(cfg)
kubeClientset := kubernetes.NewForConfigOrDie(cfg)
result, err = reconcileApplications(ctx, kubeClientset, appClientset, namespace, repoServerClient, selector, newLiveStateCache, serverSideDiff)
result, err = reconcileApplications(ctx, kubeClientset, appClientset, namespace, repoServerClient, selector, newLiveStateCache, serverSideDiff, ignoreNormalizerOpts)
errors.CheckError(err)
} else {
appClientset := appclientset.NewForConfigOrDie(cfg)
@@ -297,7 +308,7 @@ func NewReconcileCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
command.Flags().StringVar(&outputFormat, "o", "yaml", "Output format (yaml|json)")
command.Flags().BoolVar(&refresh, "refresh", false, "If set to true then recalculates apps reconciliation")
command.Flags().BoolVar(&serverSideDiff, "server-side-diff", false, "If set to \"true\" will use server-side diff while comparing resources. Default (\"false\")")
command.Flags().DurationVar(&ignoreNormalizerOpts.JQExecutionTimeout, "ignore-normalizer-jq-execution-timeout", normalizers.DefaultJQExecutionTimeout, "Set ignore normalizer JQ execution timeout")
return command
}
@@ -347,6 +358,7 @@ func reconcileApplications(
selector string,
createLiveStateCache func(argoDB db.ArgoDB, appInformer kubecache.SharedIndexInformer, settingsMgr *settings.SettingsManager, server *metrics.MetricsServer) cache.LiveStateCache,
serverSideDiff bool,
ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts,
) ([]appReconcileResult, error) {
settingsMgr := settings.NewSettingsManager(ctx, kubeClientset, namespace)
argoDB := db.NewDB(namespace, settingsMgr, kubeClientset)
@@ -387,7 +399,7 @@ func reconcileApplications(
)
appStateManager := controller.NewAppStateManager(
argoDB, appClientset, repoServerClient, namespace, kubeutil.NewKubectl(), settingsMgr, stateCache, projInformer, server, cache, time.Second, argo.NewResourceTracking(), false, 0, serverSideDiff)
argoDB, appClientset, repoServerClient, namespace, kubeutil.NewKubectl(), settingsMgr, stateCache, projInformer, server, cache, time.Second, argo.NewResourceTracking(), false, 0, serverSideDiff, ignoreNormalizerOpts)
appsList, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(ctx, v1.ListOptions{LabelSelector: selector})
if err != nil {
@@ -437,5 +449,5 @@ func reconcileApplications(
}
func newLiveStateCache(argoDB db.ArgoDB, appInformer kubecache.SharedIndexInformer, settingsMgr *settings.SettingsManager, server *metrics.MetricsServer) cache.LiveStateCache {
return cache.NewLiveStateCache(argoDB, appInformer, settingsMgr, kubeutil.NewKubectl(), server, func(managedByApp map[string]bool, ref apiv1.ObjectReference) {}, nil, argo.NewResourceTracking())
return cache.NewLiveStateCache(argoDB, appInformer, settingsMgr, kubeutil.NewKubectl(), server, func(managedByApp map[string]bool, ref apiv1.ObjectReference) {}, &sharding.ClusterSharding{}, argo.NewResourceTracking())
}

View File

@@ -23,6 +23,7 @@ import (
argocdclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/reposerver/apiclient/mocks"
"github.com/argoproj/argo-cd/v2/test"
"github.com/argoproj/argo-cd/v2/util/argo/normalizers"
"github.com/argoproj/argo-cd/v2/util/db"
"github.com/argoproj/argo-cd/v2/util/settings"
)
@@ -114,6 +115,7 @@ func TestGetReconcileResults_Refresh(t *testing.T) {
return &liveStateCache
},
false,
normalizers.IgnoreNormalizerOpts{},
)
if !assert.NoError(t, err) {

View File

@@ -25,7 +25,7 @@ import (
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/controller/sharding"
argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient"
argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
"github.com/argoproj/argo-cd/v2/util/argo"
cacheutil "github.com/argoproj/argo-cd/v2/util/cache"
@@ -71,14 +71,14 @@ argocd admin cluster namespaces my-cluster `,
}
type ClusterWithInfo struct {
argoappv1.Cluster
v1alpha1.Cluster
// Shard holds controller shard number that handles the cluster
Shard int
// Namespaces holds list of namespaces managed by Argo CD in the cluster
Namespaces []string
}
func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClient *versioned.Clientset, replicas int, namespace string, portForwardRedis bool, cacheSrc func() (*appstatecache.Cache, error), shard int, redisName string, redisHaProxyName string, redisCompressionStr string) ([]ClusterWithInfo, error) {
func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClient *versioned.Clientset, replicas int, shardingAlgorithm string, namespace string, portForwardRedis bool, cacheSrc func() (*appstatecache.Cache, error), shard int, redisName string, redisHaProxyName string, redisCompressionStr string) ([]ClusterWithInfo, error) {
settingsMgr := settings.NewSettingsManager(ctx, kubeClient, namespace)
argoDB := db.NewDB(namespace, settingsMgr, kubeClient)
@@ -86,6 +86,14 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie
if err != nil {
return nil, err
}
appItems, err := appClient.ArgoprojV1alpha1().Applications(namespace).List(ctx, v1.ListOptions{})
if err != nil {
return nil, err
}
clusterShardingCache := sharding.NewClusterSharding(argoDB, shard, replicas, shardingAlgorithm)
clusterShardingCache.Init(clustersList, appItems)
clusterShards := clusterShardingCache.GetDistribution()
var cache *appstatecache.Cache
if portForwardRedis {
overrides := clientcmd.ConfigOverrides{}
@@ -109,10 +117,6 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie
}
}
appItems, err := appClient.ArgoprojV1alpha1().Applications(namespace).List(ctx, v1.ListOptions{})
if err != nil {
return nil, err
}
apps := appItems.Items
for i, app := range apps {
err := argo.ValidateDestination(ctx, &app.Spec.Destination, argoDB)
@@ -122,6 +126,7 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie
apps[i] = app
}
clusters := make([]ClusterWithInfo, len(clustersList.Items))
batchSize := 10
batchesCount := int(math.Ceil(float64(len(clusters)) / float64(batchSize)))
for batchNum := 0; batchNum < batchesCount; batchNum++ {
@@ -135,12 +140,10 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie
clusterShard := 0
cluster := batch[i]
if replicas > 0 {
distributionFunction := sharding.GetDistributionFunction(argoDB, common.DefaultShardingAlgorithm)
distributionFunction(&cluster)
clusterShard = clusterShards[cluster.Server]
cluster.Shard = pointer.Int64(int64(clusterShard))
log.Infof("Cluster with uid: %s will be processed by shard %d", cluster.ID, clusterShard)
}
if shard != -1 && clusterShard != shard {
return nil
}
@@ -176,6 +179,7 @@ func NewClusterShardsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm
var (
shard int
replicas int
shardingAlgorithm string
clientConfig clientcmd.ClientConfig
cacheSrc func() (*appstatecache.Cache, error)
portForwardRedis bool
@@ -183,7 +187,7 @@ func NewClusterShardsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm
)
var command = cobra.Command{
Use: "shards",
Short: "Print information about each controller shard and portion of Kubernetes resources it is responsible for.",
Short: "Print information about each controller shard and the estimated portion of Kubernetes resources it is responsible for.",
Run: func(cmd *cobra.Command, args []string) {
ctx := cmd.Context()
@@ -203,8 +207,7 @@ func NewClusterShardsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm
if replicas == 0 {
return
}
clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, redisCompressionStr)
clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, shardingAlgorithm, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, redisCompressionStr)
errors.CheckError(err)
if len(clusters) == 0 {
return
@@ -216,7 +219,9 @@ func NewClusterShardsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm
clientConfig = cli.AddKubectlFlagsToCmd(&command)
command.Flags().IntVar(&shard, "shard", -1, "Cluster shard filter")
command.Flags().IntVar(&replicas, "replicas", 0, "Application controller replicas count. Inferred from number of running controller pods if not specified")
command.Flags().StringVar(&shardingAlgorithm, "sharding-method", common.DefaultShardingAlgorithm, "Sharding method. Defaults: legacy. Supported sharding methods are : [legacy, round-robin] ")
command.Flags().BoolVar(&portForwardRedis, "port-forward-redis", true, "Automatically port-forward ha proxy redis from current namespace?")
cacheSrc = appstatecache.AddCacheFlagsToCmd(&command)
// parse all added flags so far to get the redis-compression flag that was added by AddCacheFlagsToCmd() above
@@ -461,6 +466,7 @@ func NewClusterStatsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comma
var (
shard int
replicas int
shardingAlgorithm string
clientConfig clientcmd.ClientConfig
cacheSrc func() (*appstatecache.Cache, error)
portForwardRedis bool
@@ -494,7 +500,7 @@ argocd admin cluster stats target-cluster`,
replicas, err = getControllerReplicas(ctx, kubeClient, namespace, clientOpts.AppControllerName)
errors.CheckError(err)
}
clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, redisCompressionStr)
clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, shardingAlgorithm, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, redisCompressionStr)
errors.CheckError(err)
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
@@ -508,6 +514,7 @@ argocd admin cluster stats target-cluster`,
clientConfig = cli.AddKubectlFlagsToCmd(&command)
command.Flags().IntVar(&shard, "shard", -1, "Cluster shard filter")
command.Flags().IntVar(&replicas, "replicas", 0, "Application controller replicas count. Inferred from number of running controller pods if not specified")
command.Flags().StringVar(&shardingAlgorithm, "sharding-method", common.DefaultShardingAlgorithm, "Sharding method. Defaults: legacy. Supported sharding methods are : [legacy, round-robin] ")
command.Flags().BoolVar(&portForwardRedis, "port-forward-redis", true, "Automatically port-forward ha proxy redis from current namespace?")
cacheSrc = appstatecache.AddCacheFlagsToCmd(&command)
@@ -610,15 +617,16 @@ func NewGenClusterConfigCommand(pathOpts *clientcmd.PathOptions) *cobra.Command
errors.CheckError(err)
kubeClientset := fake.NewSimpleClientset()
var awsAuthConf *argoappv1.AWSAuthConfig
var execProviderConf *argoappv1.ExecProviderConfig
var awsAuthConf *v1alpha1.AWSAuthConfig
var execProviderConf *v1alpha1.ExecProviderConfig
if clusterOpts.AwsClusterName != "" {
awsAuthConf = &argoappv1.AWSAuthConfig{
awsAuthConf = &v1alpha1.AWSAuthConfig{
ClusterName: clusterOpts.AwsClusterName,
RoleARN: clusterOpts.AwsRoleArn,
Profile: clusterOpts.AwsProfile,
}
} else if clusterOpts.ExecProviderCommand != "" {
execProviderConf = &argoappv1.ExecProviderConfig{
execProviderConf = &v1alpha1.ExecProviderConfig{
Command: clusterOpts.ExecProviderCommand,
Args: clusterOpts.ExecProviderArgs,
Env: clusterOpts.ExecProviderEnv,
@@ -642,7 +650,7 @@ func NewGenClusterConfigCommand(pathOpts *clientcmd.PathOptions) *cobra.Command
clst := cmdutil.NewCluster(contextName, clusterOpts.Namespaces, clusterOpts.ClusterResources, conf, bearerToken, awsAuthConf, execProviderConf, labelsMap, annotationsMap)
if clusterOpts.InClusterEndpoint() {
clst.Server = argoappv1.KubernetesInternalAPIServerAddr
clst.Server = v1alpha1.KubernetesInternalAPIServerAddr
}
if clusterOpts.ClusterEndpoint == string(cmdutil.KubePublicEndpoint) {
// Ignore `kube-public` cluster endpoints, since this command is intended to run without invoking any network connections.

View File

@@ -0,0 +1,98 @@
package admin
import (
"context"
"crypto/rand"
"fmt"
"math/big"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/cli"
apierr "k8s.io/apimachinery/pkg/api/errors"
"github.com/argoproj/argo-cd/v2/util/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
)
const defaulRedisInitialPasswordSecretName = "argocd-redis"
const defaultResisInitialPasswordKey = "auth"
func generateRandomPassword() (string, error) {
const initialPasswordLength = 16
const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"
randBytes := make([]byte, initialPasswordLength)
for i := 0; i < initialPasswordLength; i++ {
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
if err != nil {
return "", err
}
randBytes[i] = letters[num.Int64()]
}
initialPassword := string(randBytes)
return initialPassword, nil
}
// NewRedisInitialPasswordCommand defines a new command to ensure Argo CD Redis password secret exists.
func NewRedisInitialPasswordCommand() *cobra.Command {
var (
clientConfig clientcmd.ClientConfig
)
var command = cobra.Command{
Use: "redis-initial-password",
Short: "Ensure the Redis password exists, creating a new one if necessary.",
Run: func(c *cobra.Command, args []string) {
namespace, _, err := clientConfig.Namespace()
errors.CheckError(err)
redisInitialPasswordSecretName := defaulRedisInitialPasswordSecretName
redisInitialPasswordKey := defaultResisInitialPasswordKey
fmt.Printf("Checking for initial Redis password in secret %s/%s at key %s. \n", namespace, redisInitialPasswordSecretName, redisInitialPasswordKey)
config, err := clientConfig.ClientConfig()
errors.CheckError(err)
errors.CheckError(v1alpha1.SetK8SConfigDefaults(config))
kubeClientset := kubernetes.NewForConfigOrDie(config)
randomPassword, err := generateRandomPassword()
errors.CheckError(err)
data := map[string][]byte{
redisInitialPasswordKey: []byte(randomPassword),
}
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: redisInitialPasswordSecretName,
Namespace: namespace,
},
Data: data,
Type: corev1.SecretTypeOpaque,
}
_, err = kubeClientset.CoreV1().Secrets(namespace).Create(context.Background(), secret, metav1.CreateOptions{})
if err != nil && !apierr.IsAlreadyExists(err) {
errors.CheckError(err)
}
fmt.Println("Argo CD Redis secret state confirmed: secret name argocd-redis.")
secret, err = kubeClientset.CoreV1().Secrets(namespace).Get(context.Background(), redisInitialPasswordSecretName, v1.GetOptions{})
errors.CheckError(err)
if _, ok := secret.Data[redisInitialPasswordKey]; ok {
fmt.Println("Password secret is configured properly.")
} else {
err := fmt.Errorf("key %s doesn't exist in secret %s. \n", redisInitialPasswordKey, redisInitialPasswordSecretName)
errors.CheckError(err)
}
},
}
clientConfig = cli.AddKubectlFlagsToCmd(&command)
return &command
}

View File

@@ -428,7 +428,7 @@ argocd admin settings resource-overrides ignore-differences ./deploy.yaml --argo
// configurations. This requires access to live resources which is not the
// purpose of this command. This will just apply jsonPointers and
// jqPathExpressions configurations.
normalizer, err := normalizers.NewIgnoreNormalizer(nil, overrides)
normalizer, err := normalizers.NewIgnoreNormalizer(nil, overrides, normalizers.IgnoreNormalizerOpts{})
errors.CheckError(err)
normalizedRes := res.DeepCopy()
@@ -453,6 +453,9 @@ argocd admin settings resource-overrides ignore-differences ./deploy.yaml --argo
}
func NewResourceIgnoreResourceUpdatesCommand(cmdCtx commandContext) *cobra.Command {
var (
ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts
)
var command = &cobra.Command{
Use: "ignore-resource-updates RESOURCE_YAML_PATH",
Short: "Renders fields excluded from resource updates",
@@ -474,7 +477,7 @@ argocd admin settings resource-overrides ignore-resource-updates ./deploy.yaml -
return
}
normalizer, err := normalizers.NewIgnoreNormalizer(nil, overrides)
normalizer, err := normalizers.NewIgnoreNormalizer(nil, overrides, ignoreNormalizerOpts)
errors.CheckError(err)
normalizedRes := res.DeepCopy()
@@ -495,6 +498,7 @@ argocd admin settings resource-overrides ignore-resource-updates ./deploy.yaml -
})
},
}
command.Flags().DurationVar(&ignoreNormalizerOpts.JQExecutionTimeout, "ignore-normalizer-jq-execution-timeout", normalizers.DefaultJQExecutionTimeout, "Set ignore normalizer JQ execution timeout")
return command
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +1,43 @@
package commands
import (
"context"
"fmt"
"io"
"net/http"
"os"
"testing"
"time"
argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient"
accountpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/account"
applicationpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/application"
applicationsetpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/applicationset"
certificatepkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/certificate"
clusterpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster"
gpgkeypkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/gpgkey"
notificationpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/notification"
projectpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/project"
repocredspkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/repocreds"
repositorypkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/repository"
sessionpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/session"
settingspkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/settings"
versionpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/version"
"github.com/argoproj/argo-cd/v2/pkg/apis/application"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/gitops-engine/pkg/health"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/stretchr/testify/assert"
"golang.org/x/oauth2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
k8swatch "k8s.io/apimachinery/pkg/watch"
)
func Test_getInfos(t *testing.T) {
@@ -402,8 +422,8 @@ func TestFormatSyncPolicy(t *testing.T) {
policy := formatSyncPolicy(app)
if policy != "<none>" {
t.Fatalf("Incorrect policy %q, should be <none>", policy)
if policy != "Manual" {
t.Fatalf("Incorrect policy %q, should be Manual", policy)
}
})
@@ -537,18 +557,21 @@ func TestPrintApplicationHistoryTable(t *testing.T) {
ID: 1,
Source: v1alpha1.ApplicationSource{
TargetRevision: "1",
RepoURL: "test",
},
},
{
ID: 2,
Source: v1alpha1.ApplicationSource{
TargetRevision: "2",
RepoURL: "test",
},
},
{
ID: 3,
Source: v1alpha1.ApplicationSource{
TargetRevision: "3",
RepoURL: "test",
},
},
}
@@ -558,7 +581,86 @@ func TestPrintApplicationHistoryTable(t *testing.T) {
return nil
})
expectation := "ID DATE REVISION\n1 0001-01-01 00:00:00 +0000 UTC 1\n2 0001-01-01 00:00:00 +0000 UTC 2\n3 0001-01-01 00:00:00 +0000 UTC 3\n"
expectation := "SOURCE test\nID DATE REVISION\n1 0001-01-01 00:00:00 +0000 UTC 1\n2 0001-01-01 00:00:00 +0000 UTC 2\n3 0001-01-01 00:00:00 +0000 UTC 3\n"
if output != expectation {
t.Fatalf("Incorrect print operation output %q, should be %q", output, expectation)
}
}
func TestPrintApplicationHistoryTableWithMultipleSources(t *testing.T) {
histories := []v1alpha1.RevisionHistory{
{
ID: 0,
Source: v1alpha1.ApplicationSource{
TargetRevision: "0",
RepoURL: "test",
},
},
{
ID: 1,
Revisions: []string{
"1a",
"1b",
},
//added Source just for testing the fuction
Source: v1alpha1.ApplicationSource{
TargetRevision: "-1",
RepoURL: "ignore",
},
Sources: v1alpha1.ApplicationSources{
v1alpha1.ApplicationSource{
RepoURL: "test-1",
TargetRevision: "1a",
},
v1alpha1.ApplicationSource{
RepoURL: "test-2",
TargetRevision: "1b",
},
},
},
{
ID: 2,
Revisions: []string{
"2a",
"2b",
},
Sources: v1alpha1.ApplicationSources{
v1alpha1.ApplicationSource{
RepoURL: "test-1",
TargetRevision: "2a",
},
v1alpha1.ApplicationSource{
RepoURL: "test-2",
TargetRevision: "2b",
},
},
},
{
ID: 3,
Revisions: []string{
"3a",
"3b",
},
Sources: v1alpha1.ApplicationSources{
v1alpha1.ApplicationSource{
RepoURL: "test-1",
TargetRevision: "3a",
},
v1alpha1.ApplicationSource{
RepoURL: "test-2",
TargetRevision: "3b",
},
},
},
}
output, _ := captureOutput(func() error {
printApplicationHistoryTable(histories)
return nil
})
expectation := "SOURCE test\nID DATE REVISION\n0 0001-01-01 00:00:00 +0000 UTC 0\n\nSOURCE test-1\nID DATE REVISION\n1 0001-01-01 00:00:00 +0000 UTC 1a\n2 0001-01-01 00:00:00 +0000 UTC 2a\n3 0001-01-01 00:00:00 +0000 UTC 3a\n\nSOURCE test-2\nID DATE REVISION\n1 0001-01-01 00:00:00 +0000 UTC 1b\n2 0001-01-01 00:00:00 +0000 UTC 2b\n3 0001-01-01 00:00:00 +0000 UTC 3b\n"
if output != expectation {
t.Fatalf("Incorrect print operation output %q, should be %q", output, expectation)
@@ -639,11 +741,110 @@ Project: default
Server: local
Namespace: argocd
URL: url
Repo: test
Target: master
Path: /test
Helm Values: path1,path2
Name Prefix: prefix
Source:
- Repo: test
Target: master
Path: /test
Helm Values: path1,path2
Name Prefix: prefix
SyncWindow: Sync Denied
Assigned Windows: allow:0 0 * * *:24h,deny:0 0 * * *:24h,allow:0 0 * * *:24h
Sync Policy: Automated (Prune)
Sync Status: OutOfSync from master
Health Status: Progressing (health-message)
`
assert.Equalf(t, expectation, output, "Incorrect print app summary output %q, should be %q", output, expectation)
}
func TestPrintAppSummaryTable_MultipleSources(t *testing.T) {
output, _ := captureOutput(func() error {
app := &v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSpec{
SyncPolicy: &v1alpha1.SyncPolicy{
Automated: &v1alpha1.SyncPolicyAutomated{
Prune: true,
},
},
Project: "default",
Destination: v1alpha1.ApplicationDestination{Server: "local", Namespace: "argocd"},
Sources: v1alpha1.ApplicationSources{
{
RepoURL: "test",
TargetRevision: "master",
Path: "/test",
Helm: &v1alpha1.ApplicationSourceHelm{
ValueFiles: []string{"path1", "path2"},
},
Kustomize: &v1alpha1.ApplicationSourceKustomize{NamePrefix: "prefix"},
}, {
RepoURL: "test2",
TargetRevision: "master2",
Path: "/test2",
},
},
},
Status: v1alpha1.ApplicationStatus{
Sync: v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
},
Health: v1alpha1.HealthStatus{
Status: health.HealthStatusProgressing,
Message: "health-message",
},
},
}
windows := &v1alpha1.SyncWindows{
{
Kind: "allow",
Schedule: "0 0 * * *",
Duration: "24h",
Applications: []string{
"*-prod",
},
ManualSync: true,
},
{
Kind: "deny",
Schedule: "0 0 * * *",
Duration: "24h",
Namespaces: []string{
"default",
},
},
{
Kind: "allow",
Schedule: "0 0 * * *",
Duration: "24h",
Clusters: []string{
"in-cluster",
"cluster1",
},
},
}
printAppSummaryTable(app, "url", windows)
return nil
})
expectation := `Name: argocd/test
Project: default
Server: local
Namespace: argocd
URL: url
Sources:
- Repo: test
Target: master
Path: /test
Helm Values: path1,path2
Name Prefix: prefix
- Repo: test2
Target: master2
Path: /test2
SyncWindow: Sync Denied
Assigned Windows: allow:0 0 * * *:24h,deny:0 0 * * *:24h,allow:0 0 * * *:24h
Sync Policy: Automated (Prune)
@@ -806,6 +1007,14 @@ func TestTargetObjects_invalid(t *testing.T) {
assert.Error(t, err)
}
func TestCheckForDeleteEvent(t *testing.T) {
ctx := context.Background()
fakeClient := new(fakeAcdClient)
checkForDeleteEvent(ctx, fakeClient, "testApp")
}
func TestPrintApplicationNames(t *testing.T) {
output, _ := captureOutput(func() error {
app := &v1alpha1.Application{
@@ -1301,7 +1510,7 @@ func TestPrintApplicationTableNotWide(t *testing.T) {
return nil
})
assert.NoError(t, err)
expectation := "NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS\napp-name http://localhost:8080 default prj OutOfSync Healthy <none> <none>\napp-name http://localhost:8080 default prj OutOfSync Healthy <none> <none>\n"
expectation := "NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS\napp-name http://localhost:8080 default prj OutOfSync Healthy Manual <none>\napp-name http://localhost:8080 default prj OutOfSync Healthy Manual <none>\n"
assert.Equal(t, output, expectation)
}
@@ -1337,7 +1546,7 @@ func TestPrintApplicationTableWide(t *testing.T) {
return nil
})
assert.NoError(t, err)
expectation := "NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET\napp-name http://localhost:8080 default prj OutOfSync Healthy <none> <none> https://github.com/argoproj/argocd-example-apps guestbook 123\napp-name http://localhost:8080 default prj OutOfSync Healthy <none> <none> https://github.com/argoproj/argocd-example-apps guestbook 123\n"
expectation := "NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET\napp-name http://localhost:8080 default prj OutOfSync Healthy Manual <none> https://github.com/argoproj/argocd-example-apps guestbook 123\napp-name http://localhost:8080 default prj OutOfSync Healthy Manual <none> https://github.com/argoproj/argocd-example-apps guestbook 123\n"
assert.Equal(t, output, expectation)
}
@@ -1599,3 +1808,104 @@ func testApp(name, project string, labels map[string]string, annotations map[str
},
}
}
type fakeAcdClient struct{}
func (c *fakeAcdClient) ClientOptions() argocdclient.ClientOptions {
return argocdclient.ClientOptions{}
}
func (c *fakeAcdClient) HTTPClient() (*http.Client, error) { return nil, nil }
func (c *fakeAcdClient) OIDCConfig(context.Context, *settingspkg.Settings) (*oauth2.Config, *oidc.Provider, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewRepoClient() (io.Closer, repositorypkg.RepositoryServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewRepoClientOrDie() (io.Closer, repositorypkg.RepositoryServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewRepoCredsClient() (io.Closer, repocredspkg.RepoCredsServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewRepoCredsClientOrDie() (io.Closer, repocredspkg.RepoCredsServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewCertClient() (io.Closer, certificatepkg.CertificateServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewCertClientOrDie() (io.Closer, certificatepkg.CertificateServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewClusterClient() (io.Closer, clusterpkg.ClusterServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewClusterClientOrDie() (io.Closer, clusterpkg.ClusterServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewGPGKeyClient() (io.Closer, gpgkeypkg.GPGKeyServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewGPGKeyClientOrDie() (io.Closer, gpgkeypkg.GPGKeyServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewApplicationClient() (io.Closer, applicationpkg.ApplicationServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewApplicationSetClient() (io.Closer, applicationsetpkg.ApplicationSetServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewApplicationClientOrDie() (io.Closer, applicationpkg.ApplicationServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewApplicationSetClientOrDie() (io.Closer, applicationsetpkg.ApplicationSetServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewNotificationClient() (io.Closer, notificationpkg.NotificationServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewNotificationClientOrDie() (io.Closer, notificationpkg.NotificationServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewSessionClient() (io.Closer, sessionpkg.SessionServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewSessionClientOrDie() (io.Closer, sessionpkg.SessionServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewSettingsClient() (io.Closer, settingspkg.SettingsServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewSettingsClientOrDie() (io.Closer, settingspkg.SettingsServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewVersionClient() (io.Closer, versionpkg.VersionServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewVersionClientOrDie() (io.Closer, versionpkg.VersionServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewProjectClient() (io.Closer, projectpkg.ProjectServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewProjectClientOrDie() (io.Closer, projectpkg.ProjectServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewAccountClient() (io.Closer, accountpkg.AccountServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewAccountClientOrDie() (io.Closer, accountpkg.AccountServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) WatchApplicationWithRetry(ctx context.Context, appName string, revision string) chan *v1alpha1.ApplicationWatchEvent {
appEventsCh := make(chan *v1alpha1.ApplicationWatchEvent)
go func() {
modifiedEvent := new(v1alpha1.ApplicationWatchEvent)
modifiedEvent.Type = k8swatch.Modified
appEventsCh <- modifiedEvent
deletedEvent := new(v1alpha1.ApplicationWatchEvent)
deletedEvent.Type = k8swatch.Deleted
appEventsCh <- deletedEvent
}()
return appEventsCh
}

View File

@@ -350,9 +350,11 @@ func printAppSetSummaryTable(appSet *arogappsetv1.ApplicationSet) {
fmt.Printf(printOpFmtStr, "Project:", appSet.Spec.Template.Spec.GetProject())
fmt.Printf(printOpFmtStr, "Server:", getServerForAppSet(appSet))
fmt.Printf(printOpFmtStr, "Namespace:", appSet.Spec.Template.Spec.Destination.Namespace)
fmt.Printf(printOpFmtStr, "Repo:", source.RepoURL)
fmt.Printf(printOpFmtStr, "Target:", source.TargetRevision)
fmt.Printf(printOpFmtStr, "Path:", source.Path)
if !appSet.Spec.Template.Spec.HasMultipleSources() {
fmt.Println("Source:")
} else {
fmt.Println("Sources:")
}
printAppSourceDetails(&source)
var (

View File

@@ -180,9 +180,9 @@ func TestPrintAppSetSummaryTable(t *testing.T) {
Project: default
Server:
Namespace:
Repo:
Target:
Path:
Source:
- Repo:
Target:
SyncPolicy: <none>
`,
},
@@ -193,9 +193,9 @@ SyncPolicy: <none>
Project: default
Server:
Namespace:
Repo:
Target:
Path:
Source:
- Repo:
Target:
SyncPolicy: Automated
`,
},
@@ -206,9 +206,9 @@ SyncPolicy: Automated
Project: default
Server:
Namespace:
Repo:
Target:
Path:
Source:
- Repo:
Target:
SyncPolicy: Automated
`,
},

View File

@@ -111,6 +111,7 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
awsAuthConf = &argoappv1.AWSAuthConfig{
ClusterName: clusterOpts.AwsClusterName,
RoleARN: clusterOpts.AwsRoleArn,
Profile: clusterOpts.AwsProfile,
}
} else if clusterOpts.ExecProviderCommand != "" {
execProviderConf = &argoappv1.ExecProviderConfig{

View File

@@ -18,6 +18,7 @@ import (
"github.com/redis/go-redis/v9"
log "github.com/sirupsen/logrus"
"github.com/spf13/pflag"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes"
cache2 "k8s.io/client-go/tools/cache"
@@ -78,6 +79,12 @@ func (c *forwardCacheClient) Set(item *cache.Item) error {
})
}
func (c *forwardCacheClient) Rename(oldKey string, newKey string, expiration time.Duration) error {
return c.doLazy(func(client cache.CacheClient) error {
return client.Rename(oldKey, newKey, expiration)
})
}
func (c *forwardCacheClient) Get(key string, obj interface{}) error {
return c.doLazy(func(client cache.CacheClient) error {
return client.Get(key, obj)
@@ -109,6 +116,7 @@ type forwardRepoClientset struct {
repoClientset repoapiclient.Clientset
err error
repoServerName string
kubeClientset kubernetes.Interface
}
func (c *forwardRepoClientset) NewRepoServerClient() (io.Closer, repoapiclient.RepoServerServiceClient, error) {
@@ -116,7 +124,19 @@ func (c *forwardRepoClientset) NewRepoServerClient() (io.Closer, repoapiclient.R
overrides := clientcmd.ConfigOverrides{
CurrentContext: c.context,
}
repoServerPodLabelSelector := common.LabelKeyAppName + "=" + c.repoServerName
repoServerName := c.repoServerName
repoServererviceLabelSelector := common.LabelKeyComponentRepoServer + "=" + common.LabelValueComponentRepoServer
repoServerServices, err := c.kubeClientset.CoreV1().Services(c.namespace).List(context.Background(), v1.ListOptions{LabelSelector: repoServererviceLabelSelector})
if err != nil {
c.err = err
return
}
if len(repoServerServices.Items) > 0 {
if repoServerServicelabel, ok := repoServerServices.Items[0].Labels[common.LabelKeyAppName]; ok && repoServerServicelabel != "" {
repoServerName = repoServerServicelabel
}
}
repoServerPodLabelSelector := common.LabelKeyAppName + "=" + repoServerName
repoServerPort, err := kubeutil.PortForward(8081, c.namespace, &overrides, repoServerPodLabelSelector)
if err != nil {
c.err = err
@@ -231,7 +251,7 @@ func MaybeStartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOpti
KubeClientset: kubeClientset,
Insecure: true,
ListenHost: *address,
RepoClientset: &forwardRepoClientset{namespace: namespace, context: ctxStr, repoServerName: clientOpts.RepoServerName},
RepoClientset: &forwardRepoClientset{namespace: namespace, context: ctxStr, repoServerName: clientOpts.RepoServerName, kubeClientset: kubeClientset},
EnableProxyExtension: false,
})
srv.Init(ctx)

View File

@@ -78,6 +78,8 @@ func NewProjectCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
command.AddCommand(NewProjectWindowsCommand(clientOpts))
command.AddCommand(NewProjectAddOrphanedIgnoreCommand(clientOpts))
command.AddCommand(NewProjectRemoveOrphanedIgnoreCommand(clientOpts))
command.AddCommand(NewProjectAddSourceNamespace(clientOpts))
command.AddCommand(NewProjectRemoveSourceNamespace(clientOpts))
return command
}
@@ -509,6 +511,88 @@ func NewProjectAddSourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
return command
}
// NewProjectAddSourceNamespace returns a new instance of an `argocd proj add-source-namespace` command
func NewProjectAddSourceNamespace(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var command = &cobra.Command{
Use: "add-source-namespace PROJECT NAMESPACE",
Short: "Add source namespace to the AppProject",
Example: templates.Examples(`
# Add Kubernetes namespace as source namespace to the AppProject where application resources are allowed to be created in.
argocd proj add-source-namespace PROJECT NAMESPACE
`),
Run: func(c *cobra.Command, args []string) {
ctx := c.Context()
if len(args) != 2 {
c.HelpFunc()(c, args)
os.Exit(1)
}
projName := args[0]
srcNamespace := args[1]
conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie()
defer argoio.Close(conn)
proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName})
errors.CheckError(err)
for _, item := range proj.Spec.SourceNamespaces {
if item == "*" || item == srcNamespace {
fmt.Printf("Source namespace '*' already allowed in project\n")
return
}
}
proj.Spec.SourceNamespaces = append(proj.Spec.SourceNamespaces, srcNamespace)
_, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj})
errors.CheckError(err)
},
}
return command
}
// NewProjectRemoveSourceNamespace returns a new instance of an `argocd proj remove-source-namespace` command
func NewProjectRemoveSourceNamespace(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var command = &cobra.Command{
Use: "remove-source-namespace PROJECT NAMESPACE",
Short: "Removes the source namespace from the AppProject",
Example: templates.Examples(`
# Remove source NAMESPACE in PROJECT
argocd proj remove-source-namespace PROJECT NAMESPACE
`),
Run: func(c *cobra.Command, args []string) {
ctx := c.Context()
if len(args) != 2 {
c.HelpFunc()(c, args)
os.Exit(1)
}
projName := args[0]
srcNamespace := args[1]
conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie()
defer argoio.Close(conn)
proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName})
errors.CheckError(err)
index := -1
for i, item := range proj.Spec.SourceNamespaces {
if item == srcNamespace && item != "*" {
index = i
break
}
}
if index == -1 {
fmt.Printf("Source namespace '%s' does not exist in project or cannot be removed\n", srcNamespace)
} else {
proj.Spec.SourceNamespaces = append(proj.Spec.SourceNamespaces[:index], proj.Spec.SourceNamespaces[index+1:]...)
_, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj})
errors.CheckError(err)
}
},
}
return command
}
func modifyResourcesList(list *[]metav1.GroupKind, add bool, listDesc string, group string, kind string) bool {
if add {
for _, item := range *list {

View File

@@ -64,6 +64,12 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
# Add a Git repository via SSH on a non-default port - need to use ssh:// style URLs here
argocd repo add ssh://git@git.example.com:2222/repos/repo --ssh-private-key-path ~/id_rsa
# Add a Git repository via SSH using socks5 proxy with no proxy credentials
argocd repo add ssh://git@github.com/argoproj/argocd-example-apps --ssh-private-key-path ~/id_rsa --proxy socks5://your.proxy.server.ip:1080
# Add a Git repository via SSH using socks5 proxy with proxy credentials
argocd repo add ssh://git@github.com/argoproj/argocd-example-apps --ssh-private-key-path ~/id_rsa --proxy socks5://username:password@your.proxy.server.ip:1080
# Add a private Git repository via HTTPS using username/password and TLS client certificates:
argocd repo add https://git.example.com/repos/repo --username git --password secret --tls-client-cert-path ~/mycert.crt --tls-client-cert-key-path ~/mycert.key

View File

@@ -68,6 +68,7 @@ type AppOptions struct {
kustomizeVersion string
kustomizeCommonLabels []string
kustomizeCommonAnnotations []string
kustomizeLabelWithoutSelector bool
kustomizeForceCommonLabels bool
kustomizeForceCommonAnnotations bool
kustomizeNamespace string
@@ -79,6 +80,7 @@ type AppOptions struct {
retryBackoffDuration time.Duration
retryBackoffMaxDuration time.Duration
retryBackoffFactor int64
ref string
}
func AddAppFlags(command *cobra.Command, opts *AppOptions) {
@@ -103,7 +105,7 @@ func AddAppFlags(command *cobra.Command, opts *AppOptions) {
command.Flags().StringArrayVar(&opts.helmSetFiles, "helm-set-file", []string{}, "Helm set values from respective files specified via the command line (can be repeated to set several values: --helm-set-file key1=path1 --helm-set-file key2=path2)")
command.Flags().BoolVar(&opts.helmSkipCrds, "helm-skip-crds", false, "Skip helm crd installation step")
command.Flags().StringVar(&opts.project, "project", "", "Application project name")
command.Flags().StringVar(&opts.syncPolicy, "sync-policy", "", "Set the sync policy (one of: none, automated (aliases of automated: auto, automatic))")
command.Flags().StringVar(&opts.syncPolicy, "sync-policy", "", "Set the sync policy (one of: manual (aliases of manual: none), automated (aliases of automated: auto, automatic))")
command.Flags().StringArrayVar(&opts.syncOptions, "sync-option", []string{}, "Add or remove a sync option, e.g add `Prune=false`. Remove using `!` prefix, e.g. `!Prune=false`")
command.Flags().BoolVar(&opts.autoPrune, "auto-prune", false, "Set automatic pruning when sync is automated")
command.Flags().BoolVar(&opts.selfHeal, "self-heal", false, "Set self healing when sync is automated")
@@ -124,6 +126,7 @@ func AddAppFlags(command *cobra.Command, opts *AppOptions) {
command.Flags().BoolVar(&opts.Validate, "validate", true, "Validation of repo and cluster")
command.Flags().StringArrayVar(&opts.kustomizeCommonLabels, "kustomize-common-label", []string{}, "Set common labels in Kustomize")
command.Flags().StringArrayVar(&opts.kustomizeCommonAnnotations, "kustomize-common-annotation", []string{}, "Set common labels in Kustomize")
command.Flags().BoolVar(&opts.kustomizeLabelWithoutSelector, "kustomize-label-without-selector", false, "Do not apply common label to selectors or templates")
command.Flags().BoolVar(&opts.kustomizeForceCommonLabels, "kustomize-force-common-label", false, "Force common labels in Kustomize")
command.Flags().BoolVar(&opts.kustomizeForceCommonAnnotations, "kustomize-force-common-annotation", false, "Force common annotations in Kustomize")
command.Flags().StringVar(&opts.kustomizeNamespace, "kustomize-namespace", "", "Kustomize namespace")
@@ -133,81 +136,37 @@ func AddAppFlags(command *cobra.Command, opts *AppOptions) {
command.Flags().DurationVar(&opts.retryBackoffDuration, "sync-retry-backoff-duration", argoappv1.DefaultSyncRetryDuration, "Sync retry backoff base duration. Input needs to be a duration (e.g. 2m, 1h)")
command.Flags().DurationVar(&opts.retryBackoffMaxDuration, "sync-retry-backoff-max-duration", argoappv1.DefaultSyncRetryMaxDuration, "Max sync retry backoff duration. Input needs to be a duration (e.g. 2m, 1h)")
command.Flags().Int64Var(&opts.retryBackoffFactor, "sync-retry-backoff-factor", argoappv1.DefaultSyncRetryFactor, "Factor multiplies the base duration after each failed sync retry")
command.Flags().StringVar(&opts.ref, "ref", "", "Ref is reference to another source within sources field")
}
func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, appOpts *AppOptions) int {
func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, appOpts *AppOptions, sourcePosition int) int {
visited := 0
if flags == nil {
return visited
}
source := spec.GetSourcePtrByPosition(sourcePosition)
if source == nil {
source = &argoappv1.ApplicationSource{}
}
source, visited = ConstructSource(source, *appOpts, flags)
if spec.HasMultipleSources() {
if sourcePosition == 0 {
spec.Sources[sourcePosition] = *source
} else if sourcePosition > 0 {
spec.Sources[sourcePosition-1] = *source
} else {
spec.Sources = append(spec.Sources, *source)
}
} else {
spec.Source = source
}
flags.Visit(func(f *pflag.Flag) {
visited++
source := spec.GetSourcePtr()
if source == nil {
source = &argoappv1.ApplicationSource{}
}
switch f.Name {
case "repo":
source.RepoURL = appOpts.repoURL
case "path":
source.Path = appOpts.appPath
case "helm-chart":
source.Chart = appOpts.chart
case "revision":
source.TargetRevision = appOpts.revision
case "revision-history-limit":
i := int64(appOpts.revisionHistoryLimit)
spec.RevisionHistoryLimit = &i
case "values":
setHelmOpt(source, helmOpts{valueFiles: appOpts.valuesFiles})
case "ignore-missing-value-files":
setHelmOpt(source, helmOpts{ignoreMissingValueFiles: appOpts.ignoreMissingValueFiles})
case "values-literal-file":
var data []byte
// read uri
parsedURL, err := url.ParseRequestURI(appOpts.values)
if err != nil || !(parsedURL.Scheme == "http" || parsedURL.Scheme == "https") {
data, err = os.ReadFile(appOpts.values)
} else {
data, err = config.ReadRemoteFile(appOpts.values)
}
errors.CheckError(err)
setHelmOpt(source, helmOpts{values: string(data)})
case "release-name":
setHelmOpt(source, helmOpts{releaseName: appOpts.releaseName})
case "helm-version":
setHelmOpt(source, helmOpts{version: appOpts.helmVersion})
case "helm-pass-credentials":
setHelmOpt(source, helmOpts{passCredentials: appOpts.helmPassCredentials})
case "helm-set":
setHelmOpt(source, helmOpts{helmSets: appOpts.helmSets})
case "helm-set-string":
setHelmOpt(source, helmOpts{helmSetStrings: appOpts.helmSetStrings})
case "helm-set-file":
setHelmOpt(source, helmOpts{helmSetFiles: appOpts.helmSetFiles})
case "helm-skip-crds":
setHelmOpt(source, helmOpts{skipCrds: appOpts.helmSkipCrds})
case "directory-recurse":
if source.Directory != nil {
source.Directory.Recurse = appOpts.directoryRecurse
} else {
source.Directory = &argoappv1.ApplicationSourceDirectory{Recurse: appOpts.directoryRecurse}
}
case "directory-exclude":
if source.Directory != nil {
source.Directory.Exclude = appOpts.directoryExclude
} else {
source.Directory = &argoappv1.ApplicationSourceDirectory{Exclude: appOpts.directoryExclude}
}
case "directory-include":
if source.Directory != nil {
source.Directory.Include = appOpts.directoryInclude
} else {
source.Directory = &argoappv1.ApplicationSourceDirectory{Include: appOpts.directoryInclude}
}
case "config-management-plugin":
source.Plugin = &argoappv1.ApplicationSourcePlugin{Name: appOpts.configManagementPlugin}
case "dest-name":
spec.Destination.Name = appOpts.destName
case "dest-server":
@@ -216,45 +175,9 @@ func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap
spec.Destination.Namespace = appOpts.destNamespace
case "project":
spec.Project = appOpts.project
case "nameprefix":
setKustomizeOpt(source, kustomizeOpts{namePrefix: appOpts.namePrefix})
case "namesuffix":
setKustomizeOpt(source, kustomizeOpts{nameSuffix: appOpts.nameSuffix})
case "kustomize-image":
setKustomizeOpt(source, kustomizeOpts{images: appOpts.kustomizeImages})
case "kustomize-replica":
setKustomizeOpt(source, kustomizeOpts{replicas: appOpts.kustomizeReplicas})
case "kustomize-version":
setKustomizeOpt(source, kustomizeOpts{version: appOpts.kustomizeVersion})
case "kustomize-namespace":
setKustomizeOpt(source, kustomizeOpts{namespace: appOpts.kustomizeNamespace})
case "kustomize-common-label":
parsedLabels, err := label.Parse(appOpts.kustomizeCommonLabels)
errors.CheckError(err)
setKustomizeOpt(source, kustomizeOpts{commonLabels: parsedLabels})
case "kustomize-common-annotation":
parsedAnnotations, err := label.Parse(appOpts.kustomizeCommonAnnotations)
errors.CheckError(err)
setKustomizeOpt(source, kustomizeOpts{commonAnnotations: parsedAnnotations})
case "kustomize-force-common-label":
setKustomizeOpt(source, kustomizeOpts{forceCommonLabels: appOpts.kustomizeForceCommonLabels})
case "kustomize-force-common-annotation":
setKustomizeOpt(source, kustomizeOpts{forceCommonAnnotations: appOpts.kustomizeForceCommonAnnotations})
case "jsonnet-tla-str":
setJsonnetOpt(source, appOpts.jsonnetTlaStr, false)
case "jsonnet-tla-code":
setJsonnetOpt(source, appOpts.jsonnetTlaCode, true)
case "jsonnet-ext-var-str":
setJsonnetOptExtVar(source, appOpts.jsonnetExtVarStr, false)
case "jsonnet-ext-var-code":
setJsonnetOptExtVar(source, appOpts.jsonnetExtVarCode, true)
case "jsonnet-libs":
setJsonnetOptLibs(source, appOpts.jsonnetLibs)
case "plugin-env":
setPluginOptEnvs(source, appOpts.pluginEnvs)
case "sync-policy":
switch appOpts.syncPolicy {
case "none":
case "none", "manual":
if spec.SyncPolicy != nil {
spec.SyncPolicy.Automated = nil
}
@@ -308,7 +231,6 @@ func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap
log.Fatalf("Invalid sync-retry-limit [%d]", appOpts.retryLimit)
}
}
spec.Source = source
})
if flags.Changed("auto-prune") {
if spec.SyncPolicy == nil || spec.SyncPolicy.Automated == nil {
@@ -340,6 +262,7 @@ type kustomizeOpts struct {
version string
commonLabels map[string]string
commonAnnotations map[string]string
labelWithoutSelector bool
forceCommonLabels bool
forceCommonAnnotations bool
namespace string
@@ -367,6 +290,9 @@ func setKustomizeOpt(src *argoappv1.ApplicationSource, opts kustomizeOpts) {
if opts.commonAnnotations != nil {
src.Kustomize.CommonAnnotations = opts.commonAnnotations
}
if opts.labelWithoutSelector {
src.Kustomize.LabelWithoutSelector = opts.labelWithoutSelector
}
if opts.forceCommonLabels {
src.Kustomize.ForceCommonLabels = opts.forceCommonLabels
}
@@ -498,11 +424,11 @@ func setJsonnetOptLibs(src *argoappv1.ApplicationSource, libs []string) {
// SetParameterOverrides updates an existing or appends a new parameter override in the application
// The app is assumed to be a helm app and is expected to be in the form:
// param=value
func SetParameterOverrides(app *argoappv1.Application, parameters []string) {
func SetParameterOverrides(app *argoappv1.Application, parameters []string, index int) {
if len(parameters) == 0 {
return
}
source := app.Spec.GetSource()
source := app.Spec.GetSourcePtrByIndex(index)
var sourceType argoappv1.ApplicationSourceType
if st, _ := source.ExplicitType(); st != nil {
sourceType = *st
@@ -614,8 +540,8 @@ func constructAppsBaseOnName(appName string, labels, annotations, args []string,
Source: &argoappv1.ApplicationSource{},
},
}
SetAppSpecOptions(flags, &app.Spec, &appOpts)
SetParameterOverrides(app, appOpts.Parameters)
SetAppSpecOptions(flags, &app.Spec, &appOpts, 0)
SetParameterOverrides(app, appOpts.Parameters, 0)
mergeLabels(app, labels)
setAnnotations(app, annotations)
return []*argoappv1.Application{
@@ -640,10 +566,15 @@ func constructAppsFromFileUrl(fileURL, appName string, labels, annotations, args
if app.Name == "" {
return nil, fmt.Errorf("app.Name is empty. --name argument can be used to provide app.Name")
}
SetAppSpecOptions(flags, &app.Spec, &appOpts)
SetParameterOverrides(app, appOpts.Parameters)
mergeLabels(app, labels)
setAnnotations(app, annotations)
// do not allow overrides for applications with multiple sources
if !app.Spec.HasMultipleSources() {
SetAppSpecOptions(flags, &app.Spec, &appOpts, 0)
SetParameterOverrides(app, appOpts.Parameters, 0)
}
}
return apps, nil
}
@@ -654,9 +585,117 @@ func ConstructApps(fileURL, appName string, labels, annotations, args []string,
} else if fileURL != "" {
return constructAppsFromFileUrl(fileURL, appName, labels, annotations, args, appOpts, flags)
}
return constructAppsBaseOnName(appName, labels, annotations, args, appOpts, flags)
}
func ConstructSource(source *argoappv1.ApplicationSource, appOpts AppOptions, flags *pflag.FlagSet) (*argoappv1.ApplicationSource, int) {
visited := 0
flags.Visit(func(f *pflag.Flag) {
visited++
switch f.Name {
case "repo":
source.RepoURL = appOpts.repoURL
case "path":
source.Path = appOpts.appPath
case "helm-chart":
source.Chart = appOpts.chart
case "revision":
source.TargetRevision = appOpts.revision
case "values":
setHelmOpt(source, helmOpts{valueFiles: appOpts.valuesFiles})
case "ignore-missing-value-files":
setHelmOpt(source, helmOpts{ignoreMissingValueFiles: appOpts.ignoreMissingValueFiles})
case "values-literal-file":
var data []byte
// read uri
parsedURL, err := url.ParseRequestURI(appOpts.values)
if err != nil || !(parsedURL.Scheme == "http" || parsedURL.Scheme == "https") {
data, err = os.ReadFile(appOpts.values)
} else {
data, err = config.ReadRemoteFile(appOpts.values)
}
errors.CheckError(err)
setHelmOpt(source, helmOpts{values: string(data)})
case "release-name":
setHelmOpt(source, helmOpts{releaseName: appOpts.releaseName})
case "helm-version":
setHelmOpt(source, helmOpts{version: appOpts.helmVersion})
case "helm-pass-credentials":
setHelmOpt(source, helmOpts{passCredentials: appOpts.helmPassCredentials})
case "helm-set":
setHelmOpt(source, helmOpts{helmSets: appOpts.helmSets})
case "helm-set-string":
setHelmOpt(source, helmOpts{helmSetStrings: appOpts.helmSetStrings})
case "helm-set-file":
setHelmOpt(source, helmOpts{helmSetFiles: appOpts.helmSetFiles})
case "helm-skip-crds":
setHelmOpt(source, helmOpts{skipCrds: appOpts.helmSkipCrds})
case "directory-recurse":
if source.Directory != nil {
source.Directory.Recurse = appOpts.directoryRecurse
} else {
source.Directory = &argoappv1.ApplicationSourceDirectory{Recurse: appOpts.directoryRecurse}
}
case "directory-exclude":
if source.Directory != nil {
source.Directory.Exclude = appOpts.directoryExclude
} else {
source.Directory = &argoappv1.ApplicationSourceDirectory{Exclude: appOpts.directoryExclude}
}
case "directory-include":
if source.Directory != nil {
source.Directory.Include = appOpts.directoryInclude
} else {
source.Directory = &argoappv1.ApplicationSourceDirectory{Include: appOpts.directoryInclude}
}
case "config-management-plugin":
source.Plugin = &argoappv1.ApplicationSourcePlugin{Name: appOpts.configManagementPlugin}
case "nameprefix":
setKustomizeOpt(source, kustomizeOpts{namePrefix: appOpts.namePrefix})
case "namesuffix":
setKustomizeOpt(source, kustomizeOpts{nameSuffix: appOpts.nameSuffix})
case "kustomize-image":
setKustomizeOpt(source, kustomizeOpts{images: appOpts.kustomizeImages})
case "kustomize-replica":
setKustomizeOpt(source, kustomizeOpts{replicas: appOpts.kustomizeReplicas})
case "kustomize-version":
setKustomizeOpt(source, kustomizeOpts{version: appOpts.kustomizeVersion})
case "kustomize-namespace":
setKustomizeOpt(source, kustomizeOpts{namespace: appOpts.kustomizeNamespace})
case "kustomize-common-label":
parsedLabels, err := label.Parse(appOpts.kustomizeCommonLabels)
errors.CheckError(err)
setKustomizeOpt(source, kustomizeOpts{commonLabels: parsedLabels})
case "kustomize-common-annotation":
parsedAnnotations, err := label.Parse(appOpts.kustomizeCommonAnnotations)
errors.CheckError(err)
setKustomizeOpt(source, kustomizeOpts{commonAnnotations: parsedAnnotations})
case "kustomize-label-without-selector":
setKustomizeOpt(source, kustomizeOpts{labelWithoutSelector: appOpts.kustomizeLabelWithoutSelector})
case "kustomize-force-common-label":
setKustomizeOpt(source, kustomizeOpts{forceCommonLabels: appOpts.kustomizeForceCommonLabels})
case "kustomize-force-common-annotation":
setKustomizeOpt(source, kustomizeOpts{forceCommonAnnotations: appOpts.kustomizeForceCommonAnnotations})
case "jsonnet-tla-str":
setJsonnetOpt(source, appOpts.jsonnetTlaStr, false)
case "jsonnet-tla-code":
setJsonnetOpt(source, appOpts.jsonnetTlaCode, true)
case "jsonnet-ext-var-str":
setJsonnetOptExtVar(source, appOpts.jsonnetExtVarStr, false)
case "jsonnet-ext-var-code":
setJsonnetOptExtVar(source, appOpts.jsonnetExtVarCode, true)
case "jsonnet-libs":
setJsonnetOptLibs(source, appOpts.jsonnetLibs)
case "plugin-env":
setPluginOptEnvs(source, appOpts.pluginEnvs)
case "ref":
source.Ref = appOpts.ref
}
})
return source, visited
}
func mergeLabels(app *argoappv1.Application, labels []string) {
mapLabels, err := label.Parse(labels)
errors.CheckError(err)

View File

@@ -123,6 +123,11 @@ func Test_setKustomizeOpt(t *testing.T) {
setKustomizeOpt(&src, kustomizeOpts{commonAnnotations: map[string]string{"foo1": "bar1", "foo2": "bar2"}})
assert.Equal(t, &v1alpha1.ApplicationSourceKustomize{CommonAnnotations: map[string]string{"foo1": "bar1", "foo2": "bar2"}}, src.Kustomize)
})
t.Run("Label Without Selector", func(t *testing.T) {
src := v1alpha1.ApplicationSource{}
setKustomizeOpt(&src, kustomizeOpts{commonLabels: map[string]string{"foo1": "bar1", "foo2": "bar2"}, labelWithoutSelector: true})
assert.Equal(t, &v1alpha1.ApplicationSourceKustomize{CommonLabels: map[string]string{"foo1": "bar1", "foo2": "bar2"}, LabelWithoutSelector: true}, src.Kustomize)
})
}
func Test_setJsonnetOpt(t *testing.T) {
@@ -165,7 +170,16 @@ func (f *appOptionsFixture) SetFlag(key, value string) error {
if err != nil {
return err
}
_ = SetAppSpecOptions(f.command.Flags(), f.spec, f.options)
_ = SetAppSpecOptions(f.command.Flags(), f.spec, f.options, 0)
return err
}
func (f *appOptionsFixture) SetFlagWithSourcePosition(key, value string, sourcePosition int) error {
err := f.command.Flags().Set(key, value)
if err != nil {
return err
}
_ = SetAppSpecOptions(f.command.Flags(), f.spec, f.options, sourcePosition)
return err
}
@@ -220,6 +234,54 @@ func Test_setAppSpecOptions(t *testing.T) {
})
}
func newMultiSourceAppOptionsFixture() *appOptionsFixture {
fixture := &appOptionsFixture{
spec: &v1alpha1.ApplicationSpec{
Sources: v1alpha1.ApplicationSources{
v1alpha1.ApplicationSource{},
v1alpha1.ApplicationSource{},
},
},
command: &cobra.Command{},
options: &AppOptions{},
}
AddAppFlags(fixture.command, fixture.options)
return fixture
}
func Test_setAppSpecOptionsMultiSourceApp(t *testing.T) {
f := newMultiSourceAppOptionsFixture()
sourcePosition := 0
sourcePosition1 := 1
sourcePosition2 := 2
t.Run("SyncPolicy", func(t *testing.T) {
assert.NoError(t, f.SetFlagWithSourcePosition("sync-policy", "automated", sourcePosition1))
assert.NotNil(t, f.spec.SyncPolicy.Automated)
f.spec.SyncPolicy = nil
assert.NoError(t, f.SetFlagWithSourcePosition("sync-policy", "automatic", sourcePosition1))
assert.NotNil(t, f.spec.SyncPolicy.Automated)
})
t.Run("Helm - SourcePosition 0", func(t *testing.T) {
assert.NoError(t, f.SetFlagWithSourcePosition("helm-version", "v2", sourcePosition))
assert.Equal(t, len(f.spec.GetSources()), 2)
assert.Equal(t, f.spec.GetSources()[sourcePosition].Helm.Version, "v2")
})
t.Run("Kustomize", func(t *testing.T) {
assert.NoError(t, f.SetFlagWithSourcePosition("kustomize-replica", "my-deployment=2", sourcePosition1))
assert.Equal(t, f.spec.Sources[sourcePosition1-1].Kustomize.Replicas, v1alpha1.KustomizeReplicas{{Name: "my-deployment", Count: intstr.FromInt(2)}})
assert.NoError(t, f.SetFlagWithSourcePosition("kustomize-replica", "my-deployment=4", sourcePosition2))
assert.Equal(t, f.spec.Sources[sourcePosition2-1].Kustomize.Replicas, v1alpha1.KustomizeReplicas{{Name: "my-deployment", Count: intstr.FromInt(4)}})
})
t.Run("Helm", func(t *testing.T) {
assert.NoError(t, f.SetFlagWithSourcePosition("helm-version", "v2", sourcePosition1))
assert.NoError(t, f.SetFlagWithSourcePosition("helm-version", "v3", sourcePosition2))
assert.Equal(t, len(f.spec.GetSources()), 2)
assert.Equal(t, f.spec.GetSources()[sourcePosition1-1].Helm.Version, "v2")
assert.Equal(t, f.spec.GetSources()[sourcePosition2-1].Helm.Version, "v3")
})
}
func Test_setAnnotations(t *testing.T) {
t.Run("Annotations", func(t *testing.T) {
app := v1alpha1.Application{}

View File

@@ -144,6 +144,7 @@ type ClusterOptions struct {
Upsert bool
ServiceAccount string
AwsRoleArn string
AwsProfile string
AwsClusterName string
SystemNamespace string
Namespaces []string
@@ -169,6 +170,7 @@ func AddClusterFlags(command *cobra.Command, opts *ClusterOptions) {
command.Flags().BoolVar(&opts.InCluster, "in-cluster", false, "Indicates Argo CD resides inside this cluster and should connect using the internal k8s hostname (kubernetes.default.svc)")
command.Flags().StringVar(&opts.AwsClusterName, "aws-cluster-name", "", "AWS Cluster name if set then aws cli eks token command will be used to access cluster")
command.Flags().StringVar(&opts.AwsRoleArn, "aws-role-arn", "", "Optional AWS role arn. If set then AWS IAM Authenticator assumes a role to perform cluster operations instead of the default AWS credential provider chain.")
command.Flags().StringVar(&opts.AwsProfile, "aws-profile", "", "Optional AWS profile. If set then AWS IAM Authenticator uses this profile to perform cluster operations instead of the default AWS credential provider chain.")
command.Flags().StringArrayVar(&opts.Namespaces, "namespace", nil, "List of namespaces which are allowed to manage")
command.Flags().BoolVar(&opts.ClusterResources, "cluster-resources", false, "Indicates if cluster level resources should be managed. The setting is used only if list of managed namespaces is not empty.")
command.Flags().StringVar(&opts.Name, "name", "", "Overwrite the cluster name")

View File

@@ -46,13 +46,13 @@ func NewServer(initConstants plugin.CMPServerInitConstants) (*ArgoCDCMPServer, e
serverLog := log.NewEntry(log.StandardLogger())
streamInterceptors := []grpc.StreamServerInterceptor{
otelgrpc.StreamServerInterceptor(),
otelgrpc.StreamServerInterceptor(), //nolint:staticcheck // TODO: ignore SA1019 for depreciation: see https://github.com/argoproj/argo-cd/issues/18258
grpc_logrus.StreamServerInterceptor(serverLog),
grpc_prometheus.StreamServerInterceptor,
grpc_util.PanicLoggerStreamServerInterceptor(serverLog),
}
unaryInterceptors := []grpc.UnaryServerInterceptor{
otelgrpc.UnaryServerInterceptor(),
otelgrpc.UnaryServerInterceptor(), //nolint:staticcheck // TODO: ignore SA1019 for depreciation: see https://github.com/argoproj/argo-cd/issues/18258
grpc_logrus.UnaryServerInterceptor(serverLog),
grpc_prometheus.UnaryServerInterceptor,
grpc_util.PanicLoggerUnaryServerInterceptor(serverLog),

View File

@@ -115,9 +115,9 @@ const (
LegacyShardingAlgorithm = "legacy"
// RoundRobinShardingAlgorithm is a flag value that can be opted for Sharding Algorithm it uses an equal distribution accross all shards
RoundRobinShardingAlgorithm = "round-robin"
DefaultShardingAlgorithm = LegacyShardingAlgorithm
// AppControllerHeartbeatUpdateRetryCount is the retry count for updating the Shard Mapping to the Shard Mapping ConfigMap used by Application Controller
AppControllerHeartbeatUpdateRetryCount = 3
DefaultShardingAlgorithm = LegacyShardingAlgorithm
)
// Dex related constants
@@ -149,10 +149,14 @@ const (
LabelKeyAppInstance = "app.kubernetes.io/instance"
// LabelKeyAppName is the label key to use to uniquely identify the name of the Kubernetes application
LabelKeyAppName = "app.kubernetes.io/name"
// LabelKeyAutoLabelClusterInfo if set to true will automatically add extra labels from the cluster info (currently it only adds a k8s version label)
LabelKeyAutoLabelClusterInfo = "argocd.argoproj.io/auto-label-cluster-info"
// LabelKeyLegacyApplicationName is the legacy label (v0.10 and below) and is superseded by 'app.kubernetes.io/instance'
LabelKeyLegacyApplicationName = "applications.argoproj.io/app-name"
// LabelKeySecretType contains the type of argocd secret (currently: 'cluster', 'repository', 'repo-config' or 'repo-creds')
LabelKeySecretType = "argocd.argoproj.io/secret-type"
// LabelKeyClusterKubernetesVersion contains the kubernetes version of the cluster secret if it has been enabled
LabelKeyClusterKubernetesVersion = "argocd.argoproj.io/kubernetes-version"
// LabelValueSecretTypeCluster indicates a secret type of cluster
LabelValueSecretTypeCluster = "cluster"
// LabelValueSecretTypeRepository indicates a secret type of repository
@@ -184,6 +188,10 @@ const (
// AnnotationKeyAppSkipReconcile tells the Application to skip the Application controller reconcile.
// Skip reconcile when the value is "true" or any other string values that can be strconv.ParseBool() to be true.
AnnotationKeyAppSkipReconcile = "argocd.argoproj.io/skip-reconcile"
// LabelKeyComponentRepoServer is the label key to identify the component as repo-server
LabelKeyComponentRepoServer = "app.kubernetes.io/component"
// LabelValueComponentRepoServer is the label value for the repo-server component
LabelValueComponentRepoServer = "repo-server"
)
// Environment variables for tuning and debugging Argo CD
@@ -238,6 +246,8 @@ const (
EnvLogFormat = "ARGOCD_LOG_FORMAT"
// EnvLogLevel log level that is defined by `--loglevel` option
EnvLogLevel = "ARGOCD_LOG_LEVEL"
// EnvLogFormatEnableFullTimestamp enables the FullTimestamp option in logs
EnvLogFormatEnableFullTimestamp = "ARGOCD_LOG_FORMAT_ENABLE_FULL_TIMESTAMP"
// EnvMaxCookieNumber max number of chunks a cookie can be broken into
EnvMaxCookieNumber = "ARGOCD_MAX_COOKIE_NUMBER"
// EnvPluginSockFilePath allows to override the pluginSockFilePath for repo server and cmp server

View File

@@ -6,6 +6,7 @@ import (
goerrors "errors"
"fmt"
"math"
"math/rand"
"net/http"
"reflect"
"runtime/debug"
@@ -47,13 +48,13 @@ import (
"github.com/argoproj/argo-cd/v2/controller/sharding"
"github.com/argoproj/argo-cd/v2/pkg/apis/application"
appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argov1alpha "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
"github.com/argoproj/argo-cd/v2/pkg/client/informers/externalversions/application/v1alpha1"
applisters "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/util/argo"
argodiff "github.com/argoproj/argo-cd/v2/util/argo/diff"
"github.com/argoproj/argo-cd/v2/util/argo/normalizers"
"github.com/argoproj/argo-cd/v2/util/env"
kubeerrors "k8s.io/apimachinery/pkg/api/errors"
@@ -113,11 +114,11 @@ type ApplicationController struct {
appInformer cache.SharedIndexInformer
appLister applisters.ApplicationLister
projInformer cache.SharedIndexInformer
deploymentInformer informerv1.DeploymentInformer
appStateManager AppStateManager
stateCache statecache.LiveStateCache
statusRefreshTimeout time.Duration
statusHardRefreshTimeout time.Duration
statusRefreshJitter time.Duration
selfHealTimeout time.Duration
repoClientset apiclient.Clientset
db db.ArgoDB
@@ -126,9 +127,14 @@ type ApplicationController struct {
refreshRequestedAppsMutex *sync.Mutex
metricsServer *metrics.MetricsServer
kubectlSemaphore *semaphore.Weighted
clusterFilter func(cluster *appv1.Cluster) bool
clusterSharding sharding.ClusterShardingCache
projByNameCache sync.Map
applicationNamespaces []string
ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts
// dynamicClusterDistributionEnabled if disabled deploymentInformer is never initialized
dynamicClusterDistributionEnabled bool
deploymentInformer informerv1.DeploymentInformer
}
// NewApplicationController creates new instance of ApplicationController.
@@ -142,6 +148,7 @@ func NewApplicationController(
kubectl kube.Kubectl,
appResyncPeriod time.Duration,
appHardResyncPeriod time.Duration,
appResyncJitter time.Duration,
selfHealTimeout time.Duration,
repoErrorGracePeriod time.Duration,
metricsPort int,
@@ -149,39 +156,44 @@ func NewApplicationController(
metricsApplicationLabels []string,
kubectlParallelismLimit int64,
persistResourceHealth bool,
clusterFilter func(cluster *appv1.Cluster) bool,
clusterSharding sharding.ClusterShardingCache,
applicationNamespaces []string,
rateLimiterConfig *ratelimiter.AppControllerRateLimiterConfig,
serverSideDiff bool,
dynamicClusterDistributionEnabled bool,
ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts,
) (*ApplicationController, error) {
log.Infof("appResyncPeriod=%v, appHardResyncPeriod=%v", appResyncPeriod, appHardResyncPeriod)
log.Infof("appResyncPeriod=%v, appHardResyncPeriod=%v, appResyncJitter=%v", appResyncPeriod, appHardResyncPeriod, appResyncJitter)
db := db.NewDB(namespace, settingsMgr, kubeClientset)
if rateLimiterConfig == nil {
rateLimiterConfig = ratelimiter.GetDefaultAppRateLimiterConfig()
log.Info("Using default workqueue rate limiter config")
}
ctrl := ApplicationController{
cache: argoCache,
namespace: namespace,
kubeClientset: kubeClientset,
kubectl: kubectl,
applicationClientset: applicationClientset,
repoClientset: repoClientset,
appRefreshQueue: workqueue.NewNamedRateLimitingQueue(ratelimiter.NewCustomAppControllerRateLimiter(rateLimiterConfig), "app_reconciliation_queue"),
appOperationQueue: workqueue.NewNamedRateLimitingQueue(ratelimiter.NewCustomAppControllerRateLimiter(rateLimiterConfig), "app_operation_processing_queue"),
projectRefreshQueue: workqueue.NewNamedRateLimitingQueue(ratelimiter.NewCustomAppControllerRateLimiter(rateLimiterConfig), "project_reconciliation_queue"),
appComparisonTypeRefreshQueue: workqueue.NewRateLimitingQueue(ratelimiter.NewCustomAppControllerRateLimiter(rateLimiterConfig)),
db: db,
statusRefreshTimeout: appResyncPeriod,
statusHardRefreshTimeout: appHardResyncPeriod,
refreshRequestedApps: make(map[string]CompareWith),
refreshRequestedAppsMutex: &sync.Mutex{},
auditLogger: argo.NewAuditLogger(namespace, kubeClientset, common.ApplicationController),
settingsMgr: settingsMgr,
selfHealTimeout: selfHealTimeout,
clusterFilter: clusterFilter,
projByNameCache: sync.Map{},
applicationNamespaces: applicationNamespaces,
cache: argoCache,
namespace: namespace,
kubeClientset: kubeClientset,
kubectl: kubectl,
applicationClientset: applicationClientset,
repoClientset: repoClientset,
appRefreshQueue: workqueue.NewNamedRateLimitingQueue(ratelimiter.NewCustomAppControllerRateLimiter(rateLimiterConfig), "app_reconciliation_queue"),
appOperationQueue: workqueue.NewNamedRateLimitingQueue(ratelimiter.NewCustomAppControllerRateLimiter(rateLimiterConfig), "app_operation_processing_queue"),
projectRefreshQueue: workqueue.NewNamedRateLimitingQueue(ratelimiter.NewCustomAppControllerRateLimiter(rateLimiterConfig), "project_reconciliation_queue"),
appComparisonTypeRefreshQueue: workqueue.NewRateLimitingQueue(ratelimiter.NewCustomAppControllerRateLimiter(rateLimiterConfig)),
db: db,
statusRefreshTimeout: appResyncPeriod,
statusHardRefreshTimeout: appHardResyncPeriod,
statusRefreshJitter: appResyncJitter,
refreshRequestedApps: make(map[string]CompareWith),
refreshRequestedAppsMutex: &sync.Mutex{},
auditLogger: argo.NewAuditLogger(namespace, kubeClientset, common.ApplicationController),
settingsMgr: settingsMgr,
selfHealTimeout: selfHealTimeout,
clusterSharding: clusterSharding,
projByNameCache: sync.Map{},
applicationNamespaces: applicationNamespaces,
dynamicClusterDistributionEnabled: dynamicClusterDistributionEnabled,
ignoreNormalizerOpts: ignoreNormalizerOpts,
}
if kubectlParallelismLimit > 0 {
ctrl.kubectlSemaphore = semaphore.NewWeighted(kubectlParallelismLimit)
@@ -224,25 +236,33 @@ func NewApplicationController(
}
factory := informers.NewSharedInformerFactoryWithOptions(ctrl.kubeClientset, defaultDeploymentInformerResyncDuration, informers.WithNamespace(settingsMgr.GetNamespace()))
deploymentInformer := factory.Apps().V1().Deployments()
var deploymentInformer informerv1.DeploymentInformer
// only initialize deployment informer if dynamic distribution is enabled
if dynamicClusterDistributionEnabled {
deploymentInformer = factory.Apps().V1().Deployments()
}
readinessHealthCheck := func(r *http.Request) error {
applicationControllerName := env.StringFromEnv(common.EnvAppControllerName, common.DefaultApplicationControllerName)
appControllerDeployment, err := deploymentInformer.Lister().Deployments(settingsMgr.GetNamespace()).Get(applicationControllerName)
if err != nil {
if kubeerrors.IsNotFound(err) {
appControllerDeployment = nil
} else {
return fmt.Errorf("error retrieving Application Controller Deployment: %s", err)
if dynamicClusterDistributionEnabled {
applicationControllerName := env.StringFromEnv(common.EnvAppControllerName, common.DefaultApplicationControllerName)
appControllerDeployment, err := deploymentInformer.Lister().Deployments(settingsMgr.GetNamespace()).Get(applicationControllerName)
if err != nil {
if kubeerrors.IsNotFound(err) {
appControllerDeployment = nil
} else {
return fmt.Errorf("error retrieving Application Controller Deployment: %s", err)
}
}
}
if appControllerDeployment != nil {
if appControllerDeployment.Spec.Replicas != nil && int(*appControllerDeployment.Spec.Replicas) <= 0 {
return fmt.Errorf("application controller deployment replicas is not set or is less than 0, replicas: %d", appControllerDeployment.Spec.Replicas)
}
shard := env.ParseNumFromEnv(common.EnvControllerShard, -1, -math.MaxInt32, math.MaxInt32)
if _, err := sharding.GetOrUpdateShardFromConfigMap(kubeClientset.(*kubernetes.Clientset), settingsMgr, int(*appControllerDeployment.Spec.Replicas), shard); err != nil {
return fmt.Errorf("error while updating the heartbeat for to the Shard Mapping ConfigMap: %s", err)
if appControllerDeployment != nil {
if appControllerDeployment.Spec.Replicas != nil && int(*appControllerDeployment.Spec.Replicas) <= 0 {
return fmt.Errorf("application controller deployment replicas is not set or is less than 0, replicas: %d", appControllerDeployment.Spec.Replicas)
}
shard := env.ParseNumFromEnv(common.EnvControllerShard, -1, -math.MaxInt32, math.MaxInt32)
if _, err := sharding.GetOrUpdateShardFromConfigMap(kubeClientset.(*kubernetes.Clientset), settingsMgr, int(*appControllerDeployment.Spec.Replicas), shard); err != nil {
return fmt.Errorf("error while updating the heartbeat for to the Shard Mapping ConfigMap: %s", err)
}
}
}
return nil
@@ -260,8 +280,8 @@ func NewApplicationController(
return nil, err
}
}
stateCache := statecache.NewLiveStateCache(db, appInformer, ctrl.settingsMgr, kubectl, ctrl.metricsServer, ctrl.handleObjectUpdated, clusterFilter, argo.NewResourceTracking())
appStateManager := NewAppStateManager(db, applicationClientset, repoClientset, namespace, kubectl, ctrl.settingsMgr, stateCache, projInformer, ctrl.metricsServer, argoCache, ctrl.statusRefreshTimeout, argo.NewResourceTracking(), persistResourceHealth, repoErrorGracePeriod, serverSideDiff)
stateCache := statecache.NewLiveStateCache(db, appInformer, ctrl.settingsMgr, kubectl, ctrl.metricsServer, ctrl.handleObjectUpdated, clusterSharding, argo.NewResourceTracking())
appStateManager := NewAppStateManager(db, applicationClientset, repoClientset, namespace, kubectl, ctrl.settingsMgr, stateCache, projInformer, ctrl.metricsServer, argoCache, ctrl.statusRefreshTimeout, argo.NewResourceTracking(), persistResourceHealth, repoErrorGracePeriod, serverSideDiff, ignoreNormalizerOpts)
ctrl.appInformer = appInformer
ctrl.appLister = appLister
ctrl.projInformer = projInformer
@@ -494,13 +514,13 @@ func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managed
if err != nil {
return nil, fmt.Errorf("failed to unmarshal live state of managed resources: %w", err)
}
var target = &unstructured.Unstructured{}
err = json.Unmarshal([]byte(managedResource.TargetState), &target)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal target state of managed resources: %w", err)
}
if live == nil {
var target = &unstructured.Unstructured{}
err = json.Unmarshal([]byte(managedResource.TargetState), &target)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal target state of managed resources: %w", err)
}
nodes = append(nodes, appv1.ResourceNode{
ResourceRef: appv1.ResourceRef{
Version: target.GroupVersionKind().Version,
@@ -712,7 +732,7 @@ func (ctrl *ApplicationController) hideSecretData(app *appv1.Application, compar
return nil, fmt.Errorf("error getting cluster cache: %s", err)
}
diffConfig, err := argodiff.NewDiffConfigBuilder().
WithDiffSettings(app.Spec.IgnoreDifferences, resourceOverrides, compareOptions.IgnoreAggregatedRoles).
WithDiffSettings(app.Spec.IgnoreDifferences, resourceOverrides, compareOptions.IgnoreAggregatedRoles, ctrl.ignoreNormalizerOpts).
WithTracking(appLabelKey, trackingMethod).
WithNoCache().
WithLogger(logutils.NewLogrusLogger(logutils.NewWithCurrentConfig())).
@@ -770,7 +790,24 @@ func (ctrl *ApplicationController) Run(ctx context.Context, statusProcessors int
go ctrl.appInformer.Run(ctx.Done())
go ctrl.projInformer.Run(ctx.Done())
go ctrl.deploymentInformer.Informer().Run(ctx.Done())
if ctrl.dynamicClusterDistributionEnabled {
// only start deployment informer if dynamic distribution is enabled
go ctrl.deploymentInformer.Informer().Run(ctx.Done())
}
clusters, err := ctrl.db.ListClusters(ctx)
if err != nil {
log.Warnf("Cannot init sharding. Error while querying clusters list from database: %v", err)
} else {
appItems, err := ctrl.getAppList(metav1.ListOptions{})
if err != nil {
log.Warnf("Cannot init sharding. Error while querying application list from database: %v", err)
} else {
ctrl.clusterSharding.Init(clusters, appItems)
}
}
errors.CheckError(ctrl.stateCache.Init())
@@ -1023,7 +1060,7 @@ func (ctrl *ApplicationController) getPermittedAppLiveObjects(app *appv1.Applica
return objsMap, nil
}
func (ctrl *ApplicationController) isValidDestination(app *appv1.Application) (bool, *argov1alpha.Cluster) {
func (ctrl *ApplicationController) isValidDestination(app *appv1.Application) (bool, *appv1.Cluster) {
// Validate the cluster using the Application destination's `name` field, if applicable,
// and set the Server field, if needed.
if err := argo.ValidateDestination(context.Background(), &app.Spec.Destination, ctrl.db); err != nil {
@@ -1636,6 +1673,7 @@ func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application,
var reason string
compareWith := CompareWithLatest
refreshType := appv1.RefreshTypeNormal
softExpired := app.Status.ReconciledAt == nil || app.Status.ReconciledAt.Add(statusRefreshTimeout).Before(time.Now().UTC())
hardExpired := (app.Status.ReconciledAt == nil || app.Status.ReconciledAt.Add(statusHardRefreshTimeout).Before(time.Now().UTC())) && statusHardRefreshTimeout.Seconds() != 0
@@ -1885,7 +1923,15 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
} else {
ctrl.writeBackToInformer(updatedApp)
}
message := fmt.Sprintf("Initiated automated sync to '%s'", desiredCommitSHA)
var target string
if updatedApp.Spec.HasMultipleSources() {
target = strings.Join(desiredCommitSHAsMS, ", ")
} else {
target = desiredCommitSHA
}
message := fmt.Sprintf("Initiated automated sync to '%s'", target)
ctrl.auditLogger.LogAppEvent(app, argo.EventInfo{Reason: argo.EventReasonOperationStarted, Type: v1.EventTypeNormal}, message, "")
logCtx.Info(message)
return nil, setOpTime
@@ -1976,15 +2022,11 @@ func (ctrl *ApplicationController) canProcessApp(obj interface{}) bool {
}
}
if ctrl.clusterFilter != nil {
cluster, err := ctrl.db.GetCluster(context.Background(), app.Spec.Destination.Server)
if err != nil {
return ctrl.clusterFilter(nil)
}
return ctrl.clusterFilter(cluster)
cluster, err := ctrl.db.GetCluster(context.Background(), app.Spec.Destination.Server)
if err != nil {
return ctrl.clusterSharding.IsManagedCluster(nil)
}
return true
return ctrl.clusterSharding.IsManagedCluster(cluster)
}
func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.SharedIndexInformer, applisters.ApplicationLister) {
@@ -2082,6 +2124,10 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar
ctrl.appRefreshQueue.AddRateLimited(key)
ctrl.appOperationQueue.AddRateLimited(key)
}
newApp, newOK := obj.(*appv1.Application)
if err == nil && newOK {
ctrl.clusterSharding.AddApp(newApp)
}
},
UpdateFunc: func(old, new interface{}) {
if !ctrl.canProcessApp(new) {
@@ -2092,15 +2138,27 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar
if err != nil {
return
}
var compareWith *CompareWith
var delay *time.Duration
oldApp, oldOK := old.(*appv1.Application)
newApp, newOK := new.(*appv1.Application)
if oldOK && newOK && automatedSyncEnabled(oldApp, newApp) {
log.WithField("application", newApp.QualifiedName()).Info("Enabled automated sync")
compareWith = CompareWithLatest.Pointer()
if oldOK && newOK {
if automatedSyncEnabled(oldApp, newApp) {
log.WithField("application", newApp.QualifiedName()).Info("Enabled automated sync")
compareWith = CompareWithLatest.Pointer()
}
if ctrl.statusRefreshJitter != 0 && oldApp.ResourceVersion == newApp.ResourceVersion {
// Handler is refreshing the apps, add a random jitter to spread the load and avoid spikes
jitter := time.Duration(float64(ctrl.statusRefreshJitter) * rand.Float64())
delay = &jitter
}
}
ctrl.requestAppRefresh(newApp.QualifiedName(), compareWith, nil)
ctrl.requestAppRefresh(newApp.QualifiedName(), compareWith, delay)
ctrl.appOperationQueue.AddRateLimited(key)
ctrl.clusterSharding.UpdateApp(newApp)
},
DeleteFunc: func(obj interface{}) {
if !ctrl.canProcessApp(obj) {
@@ -2113,6 +2171,10 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar
// for deletes, we immediately add to the refresh queue
ctrl.appRefreshQueue.Add(key)
}
delApp, delOK := obj.(*appv1.Application)
if err == nil && delOK {
ctrl.clusterSharding.DeleteApp(delApp)
}
},
},
)
@@ -2136,7 +2198,7 @@ func (ctrl *ApplicationController) projectErrorToCondition(err error, app *appv1
}
func (ctrl *ApplicationController) RegisterClusterSecretUpdater(ctx context.Context) {
updater := NewClusterInfoUpdater(ctrl.stateCache, ctrl.db, ctrl.appLister.Applications(""), ctrl.cache, ctrl.clusterFilter, ctrl.getAppProj, ctrl.namespace)
updater := NewClusterInfoUpdater(ctrl.stateCache, ctrl.db, ctrl.appLister.Applications(""), ctrl.cache, ctrl.clusterSharding.IsManagedCluster, ctrl.getAppProj, ctrl.namespace)
go updater.Run(ctx)
}
@@ -2188,4 +2250,26 @@ func (ctrl *ApplicationController) toAppQualifiedName(appName, appNamespace stri
return fmt.Sprintf("%s/%s", appNamespace, appName)
}
type ClusterFilterFunction func(c *argov1alpha.Cluster, distributionFunction sharding.DistributionFunction) bool
func (ctrl *ApplicationController) getAppList(options metav1.ListOptions) (*appv1.ApplicationList, error) {
watchNamespace := ctrl.namespace
// If we have at least one additional namespace configured, we need to
// watch on them all.
if len(ctrl.applicationNamespaces) > 0 {
watchNamespace = ""
}
appList, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(watchNamespace).List(context.TODO(), options)
if err != nil {
return nil, err
}
newItems := []appv1.Application{}
for _, app := range appList.Items {
if ctrl.isAppNamespaceAllowed(&app) {
newItems = append(newItems, app)
}
}
appList.Items = newItems
return appList, nil
}
type ClusterFilterFunction func(c *appv1.Cluster, distributionFunction sharding.DistributionFunction) bool

View File

@@ -17,7 +17,9 @@ import (
"github.com/argoproj/argo-cd/v2/common"
statecache "github.com/argoproj/argo-cd/v2/controller/cache"
"github.com/argoproj/argo-cd/v2/controller/sharding"
dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks"
"github.com/argoproj/gitops-engine/pkg/cache/mocks"
synccommon "github.com/argoproj/gitops-engine/pkg/sync/common"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
@@ -40,6 +42,7 @@ import (
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
mockrepoclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient/mocks"
"github.com/argoproj/argo-cd/v2/test"
"github.com/argoproj/argo-cd/v2/util/argo/normalizers"
cacheutil "github.com/argoproj/argo-cd/v2/util/cache"
appstatecache "github.com/argoproj/argo-cd/v2/util/cache/appstate"
"github.com/argoproj/argo-cd/v2/util/settings"
@@ -51,14 +54,15 @@ type namespacedResource struct {
}
type fakeData struct {
apps []runtime.Object
manifestResponse *apiclient.ManifestResponse
manifestResponses []*apiclient.ManifestResponse
managedLiveObjs map[kube.ResourceKey]*unstructured.Unstructured
namespacedResources map[kube.ResourceKey]namespacedResource
configMapData map[string]string
metricsCacheExpiration time.Duration
applicationNamespaces []string
apps []runtime.Object
manifestResponse *apiclient.ManifestResponse
manifestResponses []*apiclient.ManifestResponse
managedLiveObjs map[kube.ResourceKey]*unstructured.Unstructured
namespacedResources map[kube.ResourceKey]namespacedResource
configMapData map[string]string
metricsCacheExpiration time.Duration
applicationNamespaces []string
updateRevisionForPathsResponse *apiclient.UpdateRevisionForPathsResponse
}
type MockKubectl struct {
@@ -104,6 +108,8 @@ func newFakeController(data *fakeData, repoErr error) *ApplicationController {
}
}
mockRepoClient.On("UpdateRevisionForPaths", mock.Anything, mock.Anything).Return(data.updateRevisionForPathsResponse, nil)
mockRepoClientset := mockrepoclient.Clientset{RepoServerServiceClient: &mockRepoClient}
secret := corev1.Secret{
@@ -142,6 +148,7 @@ func newFakeController(data *fakeData, repoErr error) *ApplicationController {
kubectl,
time.Minute,
time.Hour,
time.Second,
time.Minute,
time.Second*10,
common.DefaultPortArgoCDMetrics,
@@ -153,7 +160,13 @@ func newFakeController(data *fakeData, repoErr error) *ApplicationController {
data.applicationNamespaces,
nil,
false,
false,
normalizers.IgnoreNormalizerOpts{},
)
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
// Setting a default sharding algorithm for the tests where we cannot set it.
ctrl.clusterSharding = sharding.NewClusterSharding(db, 0, 1, common.DefaultShardingAlgorithm)
if err != nil {
panic(err)
}
@@ -686,7 +699,6 @@ func TestFinalizeAppDeletion(t *testing.T) {
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}, managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{
kube.GetResourceKey(appObj): appObj,
}}, nil)
patched := false
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
defaultReactor := fakeAppCs.ReactionChain[0]
@@ -977,7 +989,7 @@ func TestNormalizeApplication(t *testing.T) {
normalized := false
fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
if patchAction, ok := action.(kubetesting.PatchAction); ok {
if string(patchAction.GetPatch()) == `{"spec":{"project":"default"}}` {
if string(patchAction.GetPatch()) == `{"spec":{"project":"default"},"status":{"sync":{"comparedTo":{"destination":{},"source":{"repoURL":""}}}}}` {
normalized = true
}
}
@@ -999,7 +1011,7 @@ func TestNormalizeApplication(t *testing.T) {
normalized := false
fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
if patchAction, ok := action.(kubetesting.PatchAction); ok {
if string(patchAction.GetPatch()) == `{"spec":{"project":"default"}}` {
if string(patchAction.GetPatch()) == `{"spec":{"project":"default"},"status":{"sync":{"comparedTo":{"destination":{},"source":{"repoURL":""}}}}}` {
normalized = true
}
}
@@ -1809,13 +1821,11 @@ func Test_canProcessApp(t *testing.T) {
})
t.Run("with cluster filter, good namespace", func(t *testing.T) {
app.Namespace = "good"
ctrl.clusterFilter = func(_ *v1alpha1.Cluster) bool { return true }
canProcess := ctrl.canProcessApp(app)
assert.True(t, canProcess)
})
t.Run("with cluster filter, bad namespace", func(t *testing.T) {
app.Namespace = "bad"
ctrl.clusterFilter = func(_ *v1alpha1.Cluster) bool { return true }
canProcess := ctrl.canProcessApp(app)
assert.False(t, canProcess)
})

View File

@@ -29,9 +29,11 @@ import (
"k8s.io/client-go/tools/cache"
"github.com/argoproj/argo-cd/v2/controller/metrics"
"github.com/argoproj/argo-cd/v2/controller/sharding"
"github.com/argoproj/argo-cd/v2/pkg/apis/application"
appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/argo"
"github.com/argoproj/argo-cd/v2/util/argo/normalizers"
"github.com/argoproj/argo-cd/v2/util/db"
"github.com/argoproj/argo-cd/v2/util/env"
logutils "github.com/argoproj/argo-cd/v2/util/log"
@@ -168,7 +170,7 @@ func NewLiveStateCache(
kubectl kube.Kubectl,
metricsServer *metrics.MetricsServer,
onObjectUpdated ObjectUpdatedHandler,
clusterFilter func(cluster *appv1.Cluster) bool,
clusterSharding sharding.ClusterShardingCache,
resourceTracking argo.ResourceTracking) LiveStateCache {
return &liveStateCache{
@@ -179,7 +181,7 @@ func NewLiveStateCache(
kubectl: kubectl,
settingsMgr: settingsMgr,
metricsServer: metricsServer,
clusterFilter: clusterFilter,
clusterSharding: clusterSharding,
resourceTracking: resourceTracking,
}
}
@@ -196,14 +198,15 @@ type cacheSettings struct {
}
type liveStateCache struct {
db db.ArgoDB
appInformer cache.SharedIndexInformer
onObjectUpdated ObjectUpdatedHandler
kubectl kube.Kubectl
settingsMgr *settings.SettingsManager
metricsServer *metrics.MetricsServer
clusterFilter func(cluster *appv1.Cluster) bool
resourceTracking argo.ResourceTracking
db db.ArgoDB
appInformer cache.SharedIndexInformer
onObjectUpdated ObjectUpdatedHandler
kubectl kube.Kubectl
settingsMgr *settings.SettingsManager
metricsServer *metrics.MetricsServer
clusterSharding sharding.ClusterShardingCache
resourceTracking argo.ResourceTracking
ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts
clusters map[string]clustercache.ClusterCache
cacheSettings cacheSettings
@@ -287,7 +290,8 @@ func isRootAppNode(r *clustercache.Resource) bool {
}
func getApp(r *clustercache.Resource, ns map[kube.ResourceKey]*clustercache.Resource) string {
return getAppRecursive(r, ns, map[kube.ResourceKey]bool{})
name, _ := getAppRecursive(r, ns, map[kube.ResourceKey]bool{})
return name
}
func ownerRefGV(ownerRef metav1.OwnerReference) schema.GroupVersion {
@@ -298,27 +302,31 @@ func ownerRefGV(ownerRef metav1.OwnerReference) schema.GroupVersion {
return gv
}
func getAppRecursive(r *clustercache.Resource, ns map[kube.ResourceKey]*clustercache.Resource, visited map[kube.ResourceKey]bool) string {
func getAppRecursive(r *clustercache.Resource, ns map[kube.ResourceKey]*clustercache.Resource, visited map[kube.ResourceKey]bool) (string, bool) {
if !visited[r.ResourceKey()] {
visited[r.ResourceKey()] = true
} else {
log.Warnf("Circular dependency detected: %v.", visited)
return resInfo(r).AppName
return resInfo(r).AppName, false
}
if resInfo(r).AppName != "" {
return resInfo(r).AppName
return resInfo(r).AppName, true
}
for _, ownerRef := range r.OwnerRefs {
gv := ownerRefGV(ownerRef)
if parent, ok := ns[kube.NewResourceKey(gv.Group, ownerRef.Kind, r.Ref.Namespace, ownerRef.Name)]; ok {
app := getAppRecursive(parent, ns, visited)
if app != "" {
return app
visited_branch := make(map[kube.ResourceKey]bool, len(visited))
for k, v := range visited {
visited_branch[k] = v
}
app, ok := getAppRecursive(parent, ns, visited_branch)
if app != "" || !ok {
return app, ok
}
}
}
return ""
return "", true
}
var (
@@ -371,9 +379,14 @@ func isRetryableError(err error) bool {
isResourceQuotaConflictErr(err) ||
isTransientNetworkErr(err) ||
isExceededQuotaErr(err) ||
isHTTP2GoawayErr(err) ||
errors.Is(err, syscall.ECONNRESET)
}
func isHTTP2GoawayErr(err error) bool {
return strings.Contains(err.Error(), "http2: server sent GOAWAY and closed the connection")
}
func isExceededQuotaErr(err error) bool {
return kerrors.IsForbidden(err) && strings.Contains(err.Error(), "exceeded quota")
}
@@ -431,6 +444,10 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
return nil, fmt.Errorf("error getting cluster: %w", err)
}
if c.clusterSharding == nil {
return nil, fmt.Errorf("unable to handle cluster %s: cluster sharding is not configured", cluster.Server)
}
if !c.canHandleCluster(cluster) {
return nil, fmt.Errorf("controller is configured to ignore cluster %s", cluster.Server)
}
@@ -486,7 +503,7 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
gvk := un.GroupVersionKind()
if cacheSettings.ignoreResourceUpdatesEnabled && shouldHashManifest(appName, gvk) {
hash, err := generateManifestHash(un, nil, cacheSettings.resourceOverrides)
hash, err := generateManifestHash(un, nil, cacheSettings.resourceOverrides, c.ignoreNormalizerOpts)
if err != nil {
log.Errorf("Failed to generate manifest hash: %v", err)
} else {
@@ -722,22 +739,24 @@ func (c *liveStateCache) Run(ctx context.Context) error {
}
func (c *liveStateCache) canHandleCluster(cluster *appv1.Cluster) bool {
if c.clusterFilter == nil {
return true
}
return c.clusterFilter(cluster)
return c.clusterSharding.IsManagedCluster(cluster)
}
func (c *liveStateCache) handleAddEvent(cluster *appv1.Cluster) {
c.clusterSharding.Add(cluster)
if !c.canHandleCluster(cluster) {
log.Infof("Ignoring cluster %s", cluster.Server)
return
}
c.lock.Lock()
_, ok := c.clusters[cluster.Server]
c.lock.Unlock()
if !ok {
log.Debugf("Checking if cache %v / cluster %v has appInformer %v", c, cluster, c.appInformer)
if c.appInformer == nil {
log.Warn("Cannot get a cluster appInformer. Cache may not be started this time")
return
}
if c.isClusterHasApps(c.appInformer.GetStore().List(), cluster) {
go func() {
// warm up cache for cluster with apps
@@ -748,6 +767,7 @@ func (c *liveStateCache) handleAddEvent(cluster *appv1.Cluster) {
}
func (c *liveStateCache) handleModEvent(oldCluster *appv1.Cluster, newCluster *appv1.Cluster) {
c.clusterSharding.Update(oldCluster, newCluster)
c.lock.Lock()
cluster, ok := c.clusters[newCluster.Server]
c.lock.Unlock()
@@ -790,6 +810,7 @@ func (c *liveStateCache) handleModEvent(oldCluster *appv1.Cluster, newCluster *a
func (c *liveStateCache) handleDeleteEvent(clusterServer string) {
c.lock.RLock()
c.clusterSharding.Delete(clusterServer)
cluster, ok := c.clusters[clusterServer]
c.lock.RUnlock()
if ok {

View File

@@ -18,10 +18,15 @@ import (
"github.com/argoproj/gitops-engine/pkg/cache"
"github.com/argoproj/gitops-engine/pkg/cache/mocks"
"github.com/argoproj/gitops-engine/pkg/health"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/stretchr/testify/mock"
"k8s.io/client-go/kubernetes/fake"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/controller/metrics"
"github.com/argoproj/argo-cd/v2/controller/sharding"
appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks"
argosettings "github.com/argoproj/argo-cd/v2/util/settings"
)
@@ -35,11 +40,13 @@ func TestHandleModEvent_HasChanges(t *testing.T) {
clusterCache := &mocks.ClusterCache{}
clusterCache.On("Invalidate", mock.Anything, mock.Anything).Return(nil).Once()
clusterCache.On("EnsureSynced").Return(nil).Once()
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
clustersCache := liveStateCache{
clusters: map[string]cache.ClusterCache{
"https://mycluster": clusterCache,
},
clusterSharding: sharding.NewClusterSharding(db, 0, 1, common.DefaultShardingAlgorithm),
}
clustersCache.handleModEvent(&appv1.Cluster{
@@ -56,14 +63,22 @@ func TestHandleModEvent_ClusterExcluded(t *testing.T) {
clusterCache := &mocks.ClusterCache{}
clusterCache.On("Invalidate", mock.Anything, mock.Anything).Return(nil).Once()
clusterCache.On("EnsureSynced").Return(nil).Once()
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
clustersCache := liveStateCache{
clusters: map[string]cache.ClusterCache{
"https://mycluster": clusterCache,
},
clusterFilter: func(cluster *appv1.Cluster) bool {
return false
db: nil,
appInformer: nil,
onObjectUpdated: func(managedByApp map[string]bool, ref v1.ObjectReference) {
},
kubectl: nil,
settingsMgr: &argosettings.SettingsManager{},
metricsServer: &metrics.MetricsServer{},
// returns a shard that never process any cluster
clusterSharding: sharding.NewClusterSharding(db, 0, 1, common.DefaultShardingAlgorithm),
resourceTracking: nil,
clusters: map[string]cache.ClusterCache{"https://mycluster": clusterCache},
cacheSettings: cacheSettings{},
lock: sync.RWMutex{},
}
clustersCache.handleModEvent(&appv1.Cluster{
@@ -75,18 +90,20 @@ func TestHandleModEvent_ClusterExcluded(t *testing.T) {
Namespaces: []string{"default"},
})
assert.Len(t, clustersCache.clusters, 0)
assert.Len(t, clustersCache.clusters, 1)
}
func TestHandleModEvent_NoChanges(t *testing.T) {
clusterCache := &mocks.ClusterCache{}
clusterCache.On("Invalidate", mock.Anything).Panic("should not invalidate")
clusterCache.On("EnsureSynced").Return(nil).Panic("should not re-sync")
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
clustersCache := liveStateCache{
clusters: map[string]cache.ClusterCache{
"https://mycluster": clusterCache,
},
clusterSharding: sharding.NewClusterSharding(db, 0, 1, common.DefaultShardingAlgorithm),
}
clustersCache.handleModEvent(&appv1.Cluster{
@@ -99,11 +116,11 @@ func TestHandleModEvent_NoChanges(t *testing.T) {
}
func TestHandleAddEvent_ClusterExcluded(t *testing.T) {
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
clustersCache := liveStateCache{
clusters: map[string]cache.ClusterCache{},
clusterFilter: func(cluster *appv1.Cluster) bool {
return false
},
clusters: map[string]cache.ClusterCache{},
clusterSharding: sharding.NewClusterSharding(db, 0, 2, common.DefaultShardingAlgorithm),
}
clustersCache.handleAddEvent(&appv1.Cluster{
Server: "https://mycluster",
@@ -118,6 +135,8 @@ func TestHandleDeleteEvent_CacheDeadlock(t *testing.T) {
Server: "https://mycluster",
Config: appv1.ClusterConfig{Username: "bar"},
}
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
fakeClient := fake.NewSimpleClientset()
settingsMgr := argosettings.NewSettingsManager(context.TODO(), fakeClient, "argocd")
liveStateCacheLock := sync.RWMutex{}
@@ -126,10 +145,8 @@ func TestHandleDeleteEvent_CacheDeadlock(t *testing.T) {
clusters: map[string]cache.ClusterCache{
testCluster.Server: gitopsEngineClusterCache,
},
clusterFilter: func(cluster *appv1.Cluster) bool {
return true
},
settingsMgr: settingsMgr,
clusterSharding: sharding.NewClusterSharding(db, 0, 1, common.DefaultShardingAlgorithm),
settingsMgr: settingsMgr,
// Set the lock here so we can reference it later
// nolint We need to overwrite here to have access to the lock
lock: liveStateCacheLock,
@@ -303,6 +320,216 @@ func Test_asResourceNode_owner_refs(t *testing.T) {
assert.Equal(t, expected, resNode)
}
func Test_getAppRecursive(t *testing.T) {
for _, tt := range []struct {
name string
r *cache.Resource
ns map[kube.ResourceKey]*cache.Resource
wantName string
wantOK assert.BoolAssertionFunc
}{
{
name: "ok: cm1->app1",
r: &cache.Resource{
Ref: v1.ObjectReference{
Name: "cm1",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "app1"},
},
},
ns: map[kube.ResourceKey]*cache.Resource{
kube.NewResourceKey("", "", "", "app1"): {
Info: &ResourceInfo{
AppName: "app1",
},
},
},
wantName: "app1",
wantOK: assert.True,
},
{
name: "ok: cm1->cm2->app1",
r: &cache.Resource{
Ref: v1.ObjectReference{
Name: "cm1",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "cm2"},
},
},
ns: map[kube.ResourceKey]*cache.Resource{
kube.NewResourceKey("", "", "", "cm2"): {
Ref: v1.ObjectReference{
Name: "cm2",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "app1"},
},
},
kube.NewResourceKey("", "", "", "app1"): {
Info: &ResourceInfo{
AppName: "app1",
},
},
},
wantName: "app1",
wantOK: assert.True,
},
{
name: "cm1->cm2->app1 & cm1->cm3->app1",
r: &cache.Resource{
Ref: v1.ObjectReference{
Name: "cm1",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "cm2"},
{Name: "cm3"},
},
},
ns: map[kube.ResourceKey]*cache.Resource{
kube.NewResourceKey("", "", "", "cm2"): {
Ref: v1.ObjectReference{
Name: "cm2",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "app1"},
},
},
kube.NewResourceKey("", "", "", "cm3"): {
Ref: v1.ObjectReference{
Name: "cm3",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "app1"},
},
},
kube.NewResourceKey("", "", "", "app1"): {
Info: &ResourceInfo{
AppName: "app1",
},
},
},
wantName: "app1",
wantOK: assert.True,
},
{
// Nothing cycle.
// Issue #11699, fixed #12667.
name: "ok: cm1->cm2 & cm1->cm3->cm2 & cm1->cm3->app1",
r: &cache.Resource{
Ref: v1.ObjectReference{
Name: "cm1",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "cm2"},
{Name: "cm3"},
},
},
ns: map[kube.ResourceKey]*cache.Resource{
kube.NewResourceKey("", "", "", "cm2"): {
Ref: v1.ObjectReference{
Name: "cm2",
},
},
kube.NewResourceKey("", "", "", "cm3"): {
Ref: v1.ObjectReference{
Name: "cm3",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "cm2"},
{Name: "app1"},
},
},
kube.NewResourceKey("", "", "", "app1"): {
Info: &ResourceInfo{
AppName: "app1",
},
},
},
wantName: "app1",
wantOK: assert.True,
},
{
name: "cycle: cm1<->cm2",
r: &cache.Resource{
Ref: v1.ObjectReference{
Name: "cm1",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "cm2"},
},
},
ns: map[kube.ResourceKey]*cache.Resource{
kube.NewResourceKey("", "", "", "cm1"): {
Ref: v1.ObjectReference{
Name: "cm1",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "cm2"},
},
},
kube.NewResourceKey("", "", "", "cm2"): {
Ref: v1.ObjectReference{
Name: "cm2",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "cm1"},
},
},
},
wantName: "",
wantOK: assert.False,
},
{
name: "cycle: cm1->cm2->cm3->cm1",
r: &cache.Resource{
Ref: v1.ObjectReference{
Name: "cm1",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "cm2"},
},
},
ns: map[kube.ResourceKey]*cache.Resource{
kube.NewResourceKey("", "", "", "cm1"): {
Ref: v1.ObjectReference{
Name: "cm1",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "cm2"},
},
},
kube.NewResourceKey("", "", "", "cm2"): {
Ref: v1.ObjectReference{
Name: "cm2",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "cm3"},
},
},
kube.NewResourceKey("", "", "", "cm3"): {
Ref: v1.ObjectReference{
Name: "cm3",
},
OwnerRefs: []metav1.OwnerReference{
{Name: "cm1"},
},
},
},
wantName: "",
wantOK: assert.False,
},
} {
t.Run(tt.name, func(t *testing.T) {
visited := map[kube.ResourceKey]bool{}
got, ok := getAppRecursive(tt.r, tt.ns, visited)
assert.Equal(t, tt.wantName, got)
tt.wantOK(t, ok)
})
}
}
func TestSkipResourceUpdate(t *testing.T) {
var (
hash1_x string = "x"

View File

@@ -408,8 +408,8 @@ func populateHostNodeInfo(un *unstructured.Unstructured, res *ResourceInfo) {
}
}
func generateManifestHash(un *unstructured.Unstructured, ignores []v1alpha1.ResourceIgnoreDifferences, overrides map[string]v1alpha1.ResourceOverride) (string, error) {
normalizer, err := normalizers.NewIgnoreNormalizer(ignores, overrides)
func generateManifestHash(un *unstructured.Unstructured, ignores []v1alpha1.ResourceIgnoreDifferences, overrides map[string]v1alpha1.ResourceOverride, opts normalizers.IgnoreNormalizerOpts) (string, error) {
normalizer, err := normalizers.NewIgnoreNormalizer(ignores, overrides, opts)
if err != nil {
return "", fmt.Errorf("error creating normalizer: %w", err)
}

View File

@@ -16,6 +16,7 @@ import (
"sigs.k8s.io/yaml"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/argo/normalizers"
)
func strToUnstructured(jsonStr string) *unstructured.Unstructured {
@@ -749,7 +750,7 @@ func TestManifestHash(t *testing.T) {
expected := hash(data)
hash, err := generateManifestHash(manifest, ignores, nil)
hash, err := generateManifestHash(manifest, ignores, nil, normalizers.IgnoreNormalizerOpts{})
assert.Equal(t, expected, hash)
assert.Nil(t, err)
}

View File

@@ -3,6 +3,7 @@ package controller
import (
"context"
"fmt"
"github.com/argoproj/argo-cd/v2/common"
"time"
"github.com/argoproj/argo-cd/v2/util/env"
@@ -101,8 +102,11 @@ func (c *clusterInfoUpdater) updateClusters() {
}
_ = kube.RunAllAsync(len(clustersFiltered), func(i int) error {
cluster := clustersFiltered[i]
if err := c.updateClusterInfo(ctx, cluster, infoByServer[cluster.Server]); err != nil {
log.Warnf("Failed to save clusters info: %v", err)
clusterInfo := infoByServer[cluster.Server]
if err := c.updateClusterInfo(ctx, cluster, clusterInfo); err != nil {
log.Warnf("Failed to save cluster info: %v", err)
} else if err := updateClusterLabels(ctx, clusterInfo, cluster, c.db.UpdateCluster); err != nil {
log.Warnf("Failed to update cluster labels: %v", err)
}
return nil
})
@@ -114,6 +118,12 @@ func (c *clusterInfoUpdater) updateClusterInfo(ctx context.Context, cluster appv
if err != nil {
return fmt.Errorf("error while fetching the apps list: %w", err)
}
updated := c.getUpdatedClusterInfo(ctx, apps, cluster, info, metav1.Now())
return c.cache.SetClusterInfo(cluster.Server, &updated)
}
func (c *clusterInfoUpdater) getUpdatedClusterInfo(ctx context.Context, apps []*appv1.Application, cluster appv1.Cluster, info *cache.ClusterInfo, now metav1.Time) appv1.ClusterInfo {
var appCount int64
for _, a := range apps {
if c.projGetter != nil {
@@ -129,7 +139,6 @@ func (c *clusterInfoUpdater) updateClusterInfo(ctx context.Context, cluster appv
appCount += 1
}
}
now := metav1.Now()
clusterInfo := appv1.ClusterInfo{
ConnectionState: appv1.ConnectionState{ModifiedAt: &now},
ApplicationsCount: appCount,
@@ -156,5 +165,15 @@ func (c *clusterInfoUpdater) updateClusterInfo(ctx context.Context, cluster appv
}
}
return c.cache.SetClusterInfo(cluster.Server, &clusterInfo)
return clusterInfo
}
func updateClusterLabels(ctx context.Context, clusterInfo *cache.ClusterInfo, cluster appv1.Cluster, updateCluster func(context.Context, *appv1.Cluster) (*appv1.Cluster, error)) error {
if clusterInfo != nil && cluster.Labels[common.LabelKeyAutoLabelClusterInfo] == "true" && cluster.Labels[common.LabelKeyClusterKubernetesVersion] != clusterInfo.K8SVersion {
cluster.Labels[common.LabelKeyClusterKubernetesVersion] = clusterInfo.K8SVersion
_, err := updateCluster(ctx, &cluster)
return err
}
return nil
}

View File

@@ -2,6 +2,7 @@ package controller
import (
"context"
"errors"
"fmt"
"testing"
"time"
@@ -98,3 +99,92 @@ func TestClusterSecretUpdater(t *testing.T) {
assert.Equal(t, test.ExpectedStatus, clusterInfo.ConnectionState.Status)
}
}
func TestUpdateClusterLabels(t *testing.T) {
shouldNotBeInvoked := func(ctx context.Context, cluster *v1alpha1.Cluster) (*v1alpha1.Cluster, error) {
shouldNotHappen := errors.New("if an error happens here, something's wrong")
assert.NoError(t, shouldNotHappen)
return nil, shouldNotHappen
}
tests := []struct {
name string
clusterInfo *clustercache.ClusterInfo
cluster v1alpha1.Cluster
updateCluster func(context.Context, *v1alpha1.Cluster) (*v1alpha1.Cluster, error)
wantErr assert.ErrorAssertionFunc
}{
{
"enableClusterInfoLabels = false",
&clustercache.ClusterInfo{
Server: "kubernetes.svc.local",
K8SVersion: "1.28",
},
v1alpha1.Cluster{
Server: "kubernetes.svc.local",
Labels: nil,
},
shouldNotBeInvoked,
assert.NoError,
},
{
"clusterInfo = nil",
nil,
v1alpha1.Cluster{
Server: "kubernetes.svc.local",
Labels: map[string]string{"argocd.argoproj.io/auto-label-cluster-info": "true"},
},
shouldNotBeInvoked,
assert.NoError,
},
{
"clusterInfo.k8sversion == cluster k8s label",
&clustercache.ClusterInfo{
Server: "kubernetes.svc.local",
K8SVersion: "1.28",
},
v1alpha1.Cluster{
Server: "kubernetes.svc.local",
Labels: map[string]string{"argocd.argoproj.io/kubernetes-version": "1.28", "argocd.argoproj.io/auto-label-cluster-info": "true"},
},
shouldNotBeInvoked,
assert.NoError,
},
{
"clusterInfo.k8sversion != cluster k8s label, no error",
&clustercache.ClusterInfo{
Server: "kubernetes.svc.local",
K8SVersion: "1.28",
},
v1alpha1.Cluster{
Server: "kubernetes.svc.local",
Labels: map[string]string{"argocd.argoproj.io/kubernetes-version": "1.27", "argocd.argoproj.io/auto-label-cluster-info": "true"},
},
func(ctx context.Context, cluster *v1alpha1.Cluster) (*v1alpha1.Cluster, error) {
assert.Equal(t, cluster.Labels["argocd.argoproj.io/kubernetes-version"], "1.28")
return nil, nil
},
assert.NoError,
},
{
"clusterInfo.k8sversion != cluster k8s label, some error",
&clustercache.ClusterInfo{
Server: "kubernetes.svc.local",
K8SVersion: "1.28",
},
v1alpha1.Cluster{
Server: "kubernetes.svc.local",
Labels: map[string]string{"argocd.argoproj.io/kubernetes-version": "1.27", "argocd.argoproj.io/auto-label-cluster-info": "true"},
},
func(ctx context.Context, cluster *v1alpha1.Cluster) (*v1alpha1.Cluster, error) {
assert.Equal(t, cluster.Labels["argocd.argoproj.io/kubernetes-version"], "1.28")
return nil, errors.New("some error happened while saving")
},
assert.Error,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.wantErr(t, updateClusterLabels(context.Background(), tt.clusterInfo, tt.cluster, tt.updateCluster), fmt.Sprintf("updateClusterLabels(%v, %v, %v)", context.Background(), tt.clusterInfo, tt.cluster))
})
}
}

View File

@@ -23,6 +23,8 @@ import (
"github.com/argoproj/argo-cd/v2/util/git"
"github.com/argoproj/argo-cd/v2/util/healthz"
"github.com/argoproj/argo-cd/v2/util/profile"
ctrl_metrics "sigs.k8s.io/controller-runtime/pkg/metrics"
)
type MetricsServer struct {
@@ -160,12 +162,12 @@ func NewMetricsServer(addr string, appLister applister.ApplicationLister, appFil
mux := http.NewServeMux()
registry := NewAppRegistry(appLister, appFilter, appLabels)
registry.MustRegister(depth, adds, latency, workDuration, unfinished, longestRunningProcessor, retries)
mux.Handle(MetricsPath, promhttp.HandlerFor(prometheus.Gatherers{
// contains app controller specific metrics
registry,
// contains process, golang and controller workqueues metrics
prometheus.DefaultGatherer,
// contains workqueue metrics, process and golang metrics
ctrl_metrics.Registry,
}, promhttp.HandlerOpts{}))
profile.RegisterProfiler(mux)
healthz.ServeHealthCheck(mux, healthCheck)

View File

@@ -2,6 +2,7 @@ package metrics
import (
"context"
"fmt"
"log"
"net/http"
"net/http/httptest"
@@ -15,12 +16,15 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
"sigs.k8s.io/yaml"
argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/fake"
appinformer "github.com/argoproj/argo-cd/v2/pkg/client/informers/externalversions"
applister "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
"sigs.k8s.io/controller-runtime/pkg/controller"
)
const fakeApp = `
@@ -140,6 +144,12 @@ var appFilter = func(obj interface{}) bool {
return true
}
func init() {
// Create a fake controller so we initialize the internal controller metrics.
// https://github.com/kubernetes-sigs/controller-runtime/blob/4000e996a202917ad7d40f02ed8a2079a9ce25e9/pkg/internal/controller/metrics/metrics.go
_, _ = controller.New("test-controller", nil, controller.Options{})
}
func newFakeApp(fakeAppYAML string) *argoappv1.Application {
var app argoappv1.Application
err := yaml.Unmarshal([]byte(fakeAppYAML), &app)
@@ -360,7 +370,7 @@ func assertMetricsPrinted(t *testing.T, expectedLines, body string) {
if line == "" {
continue
}
assert.Contains(t, body, line, "expected metrics mismatch")
assert.Contains(t, body, line, fmt.Sprintf("expected metrics mismatch for line: %s", line))
}
}
@@ -443,3 +453,70 @@ argocd_app_sync_total{dest_server="https://localhost:6443",name="my-app",namespa
err = metricsServ.SetExpiration(time.Second)
assert.Error(t, err)
}
func TestWorkqueueMetrics(t *testing.T) {
cancel, appLister := newFakeLister()
defer cancel()
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{})
assert.NoError(t, err)
expectedMetrics := `
# TYPE workqueue_adds_total counter
workqueue_adds_total{name="test"}
# TYPE workqueue_depth gauge
workqueue_depth{name="test"}
# TYPE workqueue_longest_running_processor_seconds gauge
workqueue_longest_running_processor_seconds{name="test"}
# TYPE workqueue_queue_duration_seconds histogram
# TYPE workqueue_unfinished_work_seconds gauge
workqueue_unfinished_work_seconds{name="test"}
# TYPE workqueue_work_duration_seconds histogram
`
workqueue.NewNamed("test")
req, err := http.NewRequest(http.MethodGet, "/metrics", nil)
assert.NoError(t, err)
rr := httptest.NewRecorder()
metricsServ.Handler.ServeHTTP(rr, req)
assert.Equal(t, rr.Code, http.StatusOK)
body := rr.Body.String()
log.Println(body)
assertMetricsPrinted(t, expectedMetrics, body)
}
func TestGoMetrics(t *testing.T) {
cancel, appLister := newFakeLister()
defer cancel()
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{})
assert.NoError(t, err)
expectedMetrics := `
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds_sum
go_gc_duration_seconds_count
# TYPE go_goroutines gauge
go_goroutines
# TYPE go_info gauge
go_info
# TYPE go_memstats_alloc_bytes gauge
go_memstats_alloc_bytes
# TYPE go_memstats_sys_bytes gauge
go_memstats_sys_bytes
# TYPE go_threads gauge
go_threads
`
req, err := http.NewRequest(http.MethodGet, "/metrics", nil)
assert.NoError(t, err)
rr := httptest.NewRecorder()
metricsServ.Handler.ServeHTTP(rr, req)
assert.Equal(t, rr.Code, http.StatusOK)
body := rr.Body.String()
log.Println(body)
assertMetricsPrinted(t, expectedMetrics, body)
}

View File

@@ -1,101 +0,0 @@
package metrics
import (
"github.com/prometheus/client_golang/prometheus"
"k8s.io/client-go/util/workqueue"
)
const (
WorkQueueSubsystem = "workqueue"
DepthKey = "depth"
AddsKey = "adds_total"
QueueLatencyKey = "queue_duration_seconds"
WorkDurationKey = "work_duration_seconds"
UnfinishedWorkKey = "unfinished_work_seconds"
LongestRunningProcessorKey = "longest_running_processor_seconds"
RetriesKey = "retries_total"
)
var (
depth = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Subsystem: WorkQueueSubsystem,
Name: DepthKey,
Help: "Current depth of workqueue",
}, []string{"name"})
adds = prometheus.NewCounterVec(prometheus.CounterOpts{
Subsystem: WorkQueueSubsystem,
Name: AddsKey,
Help: "Total number of adds handled by workqueue",
}, []string{"name"})
latency = prometheus.NewHistogramVec(prometheus.HistogramOpts{
Subsystem: WorkQueueSubsystem,
Name: QueueLatencyKey,
Help: "How long in seconds an item stays in workqueue before being requested",
Buckets: []float64{1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1, 5, 10, 15, 30, 60, 120, 180},
}, []string{"name"})
workDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
Subsystem: WorkQueueSubsystem,
Name: WorkDurationKey,
Help: "How long in seconds processing an item from workqueue takes.",
Buckets: []float64{1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1, 5, 10, 15, 30, 60, 120, 180},
}, []string{"name"})
unfinished = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Subsystem: WorkQueueSubsystem,
Name: UnfinishedWorkKey,
Help: "How many seconds of work has been done that " +
"is in progress and hasn't been observed by work_duration. Large " +
"values indicate stuck threads. One can deduce the number of stuck " +
"threads by observing the rate at which this increases.",
}, []string{"name"})
longestRunningProcessor = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Subsystem: WorkQueueSubsystem,
Name: LongestRunningProcessorKey,
Help: "How many seconds has the longest running " +
"processor for workqueue been running.",
}, []string{"name"})
retries = prometheus.NewCounterVec(prometheus.CounterOpts{
Subsystem: WorkQueueSubsystem,
Name: RetriesKey,
Help: "Total number of retries handled by workqueue",
}, []string{"name"})
)
func init() {
workqueue.SetProvider(workqueueMetricsProvider{})
}
type workqueueMetricsProvider struct{}
func (workqueueMetricsProvider) NewDepthMetric(name string) workqueue.GaugeMetric {
return depth.WithLabelValues(name)
}
func (workqueueMetricsProvider) NewAddsMetric(name string) workqueue.CounterMetric {
return adds.WithLabelValues(name)
}
func (workqueueMetricsProvider) NewLatencyMetric(name string) workqueue.HistogramMetric {
return latency.WithLabelValues(name)
}
func (workqueueMetricsProvider) NewWorkDurationMetric(name string) workqueue.HistogramMetric {
return workDuration.WithLabelValues(name)
}
func (workqueueMetricsProvider) NewUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric {
return unfinished.WithLabelValues(name)
}
func (workqueueMetricsProvider) NewLongestRunningProcessorSecondsMetric(name string) workqueue.SettableGaugeMetric {
return longestRunningProcessor.WithLabelValues(name)
}
func (workqueueMetricsProvider) NewRetriesMetric(name string) workqueue.CounterMetric {
return retries.WithLabelValues(name)
}

View File

@@ -0,0 +1,264 @@
package sharding
import (
"sync"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/db"
log "github.com/sirupsen/logrus"
)
type ClusterShardingCache interface {
Init(clusters *v1alpha1.ClusterList, apps *v1alpha1.ApplicationList)
Add(c *v1alpha1.Cluster)
Delete(clusterServer string)
Update(oldCluster *v1alpha1.Cluster, newCluster *v1alpha1.Cluster)
AddApp(a *v1alpha1.Application)
DeleteApp(a *v1alpha1.Application)
UpdateApp(a *v1alpha1.Application)
IsManagedCluster(c *v1alpha1.Cluster) bool
GetDistribution() map[string]int
GetAppDistribution() map[string]int
}
type ClusterSharding struct {
Shard int
Replicas int
Shards map[string]int
Clusters map[string]*v1alpha1.Cluster
Apps map[string]*v1alpha1.Application
lock sync.RWMutex
getClusterShard DistributionFunction
}
func NewClusterSharding(_ db.ArgoDB, shard, replicas int, shardingAlgorithm string) ClusterShardingCache {
log.Debugf("Processing clusters from shard %d: Using filter function: %s", shard, shardingAlgorithm)
clusterSharding := &ClusterSharding{
Shard: shard,
Replicas: replicas,
Shards: make(map[string]int),
Clusters: make(map[string]*v1alpha1.Cluster),
Apps: make(map[string]*v1alpha1.Application),
}
distributionFunction := NoShardingDistributionFunction()
if replicas > 1 {
log.Debugf("Processing clusters from shard %d: Using filter function: %s", shard, shardingAlgorithm)
distributionFunction = GetDistributionFunction(clusterSharding.getClusterAccessor(), clusterSharding.getAppAccessor(), shardingAlgorithm, replicas)
} else {
log.Info("Processing all cluster shards")
}
clusterSharding.getClusterShard = distributionFunction
return clusterSharding
}
// IsManagedCluster returns wheter or not the cluster should be processed by a given shard.
func (s *ClusterSharding) IsManagedCluster(c *v1alpha1.Cluster) bool {
s.lock.RLock()
defer s.lock.RUnlock()
if c == nil { // nil cluster (in-cluster) is always managed by current clusterShard
return true
}
clusterShard := 0
if shard, ok := s.Shards[c.Server]; ok {
clusterShard = shard
} else {
log.Warnf("The cluster %s has no assigned shard.", c.Server)
}
log.Debugf("Checking if cluster %s with clusterShard %d should be processed by shard %d", c.Server, clusterShard, s.Shard)
return clusterShard == s.Shard
}
func (sharding *ClusterSharding) Init(clusters *v1alpha1.ClusterList, apps *v1alpha1.ApplicationList) {
sharding.lock.Lock()
defer sharding.lock.Unlock()
newClusters := make(map[string]*v1alpha1.Cluster, len(clusters.Items))
for _, c := range clusters.Items {
cluster := c
newClusters[c.Server] = &cluster
}
sharding.Clusters = newClusters
newApps := make(map[string]*v1alpha1.Application, len(apps.Items))
for i := range apps.Items {
app := apps.Items[i]
newApps[app.Name] = &app
}
sharding.Apps = newApps
sharding.updateDistribution()
}
func (sharding *ClusterSharding) Add(c *v1alpha1.Cluster) {
sharding.lock.Lock()
defer sharding.lock.Unlock()
old, ok := sharding.Clusters[c.Server]
sharding.Clusters[c.Server] = c
if !ok || hasShardingUpdates(old, c) {
sharding.updateDistribution()
} else {
log.Debugf("Skipping sharding distribution update. Cluster already added")
}
}
func (sharding *ClusterSharding) Delete(clusterServer string) {
sharding.lock.Lock()
defer sharding.lock.Unlock()
if _, ok := sharding.Clusters[clusterServer]; ok {
delete(sharding.Clusters, clusterServer)
delete(sharding.Shards, clusterServer)
sharding.updateDistribution()
}
}
func (sharding *ClusterSharding) Update(oldCluster *v1alpha1.Cluster, newCluster *v1alpha1.Cluster) {
sharding.lock.Lock()
defer sharding.lock.Unlock()
if _, ok := sharding.Clusters[oldCluster.Server]; ok && oldCluster.Server != newCluster.Server {
delete(sharding.Clusters, oldCluster.Server)
delete(sharding.Shards, oldCluster.Server)
}
sharding.Clusters[newCluster.Server] = newCluster
if hasShardingUpdates(oldCluster, newCluster) {
sharding.updateDistribution()
} else {
log.Debugf("Skipping sharding distribution update. No relevant changes")
}
}
func (sharding *ClusterSharding) GetDistribution() map[string]int {
sharding.lock.RLock()
defer sharding.lock.RUnlock()
shards := sharding.Shards
distribution := make(map[string]int, len(shards))
for k, v := range shards {
distribution[k] = v
}
return distribution
}
func (sharding *ClusterSharding) updateDistribution() {
for k, c := range sharding.Clusters {
shard := 0
if c.Shard != nil {
requestedShard := int(*c.Shard)
if requestedShard < sharding.Replicas {
shard = requestedShard
} else {
log.Warnf("Specified cluster shard (%d) for cluster: %s is greater than the number of available shard (%d). Using shard 0.", requestedShard, c.Server, sharding.Replicas)
}
} else {
shard = sharding.getClusterShard(c)
}
existingShard, ok := sharding.Shards[k]
if ok && existingShard != shard {
log.Infof("Cluster %s has changed shard from %d to %d", k, existingShard, shard)
} else if !ok {
log.Infof("Cluster %s has been assigned to shard %d", k, shard)
} else {
log.Debugf("Cluster %s has not changed shard", k)
}
sharding.Shards[k] = shard
}
}
// hasShardingUpdates returns true if the sharding distribution has explicitly changed
func hasShardingUpdates(old, new *v1alpha1.Cluster) bool {
if old == nil || new == nil {
return false
}
// returns true if the cluster id has changed because some sharding algorithms depend on it.
if old.ID != new.ID {
return true
}
if old.Server != new.Server {
return true
}
// return false if the shard field has not been modified
if old.Shard == nil && new.Shard == nil {
return false
}
return old.Shard == nil || new.Shard == nil || int64(*old.Shard) != int64(*new.Shard)
}
// A read lock should be acquired before calling getClusterAccessor.
func (d *ClusterSharding) getClusterAccessor() clusterAccessor {
return func() []*v1alpha1.Cluster {
// no need to lock, as this is only called from the updateDistribution function
clusters := make([]*v1alpha1.Cluster, 0, len(d.Clusters))
for _, c := range d.Clusters {
clusters = append(clusters, c)
}
return clusters
}
}
// A read lock should be acquired before calling getAppAccessor.
func (d *ClusterSharding) getAppAccessor() appAccessor {
return func() []*v1alpha1.Application {
apps := make([]*v1alpha1.Application, 0, len(d.Apps))
for _, a := range d.Apps {
apps = append(apps, a)
}
return apps
}
}
func (sharding *ClusterSharding) AddApp(a *v1alpha1.Application) {
sharding.lock.Lock()
defer sharding.lock.Unlock()
_, ok := sharding.Apps[a.Name]
sharding.Apps[a.Name] = a
if !ok {
sharding.updateDistribution()
} else {
log.Debugf("Skipping sharding distribution update. App already added")
}
}
func (sharding *ClusterSharding) DeleteApp(a *v1alpha1.Application) {
sharding.lock.Lock()
defer sharding.lock.Unlock()
if _, ok := sharding.Apps[a.Name]; ok {
delete(sharding.Apps, a.Name)
sharding.updateDistribution()
}
}
func (sharding *ClusterSharding) UpdateApp(a *v1alpha1.Application) {
sharding.lock.Lock()
defer sharding.lock.Unlock()
_, ok := sharding.Apps[a.Name]
sharding.Apps[a.Name] = a
if !ok {
sharding.updateDistribution()
} else {
log.Debugf("Skipping sharding distribution update. No relevant changes")
}
}
// GetAppDistribution should be not be called from a DestributionFunction because
// it could cause a deadlock when updateDistribution is called.
func (sharding *ClusterSharding) GetAppDistribution() map[string]int {
sharding.lock.RLock()
clusters := sharding.Clusters
apps := sharding.Apps
sharding.lock.RUnlock()
appDistribution := make(map[string]int, len(clusters))
for _, a := range apps {
if _, ok := appDistribution[a.Spec.Destination.Server]; !ok {
appDistribution[a.Spec.Destination.Server] = 0
}
appDistribution[a.Spec.Destination.Server]++
}
return appDistribution
}

View File

@@ -0,0 +1,511 @@
package sharding
import (
"testing"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks"
"github.com/stretchr/testify/assert"
)
func setupTestSharding(shard int, replicas int) *ClusterSharding {
shardingAlgorithm := "legacy" // we are using the legacy algorithm as it is deterministic based on the cluster id which is easier to test
db := &dbmocks.ArgoDB{}
return NewClusterSharding(db, shard, replicas, shardingAlgorithm).(*ClusterSharding)
}
func TestNewClusterSharding(t *testing.T) {
shard := 1
replicas := 2
sharding := setupTestSharding(shard, replicas)
assert.NotNil(t, sharding)
assert.Equal(t, shard, sharding.Shard)
assert.Equal(t, replicas, sharding.Replicas)
assert.NotNil(t, sharding.Shards)
assert.NotNil(t, sharding.Clusters)
}
func TestClusterSharding_Add(t *testing.T) {
shard := 1
replicas := 2
sharding := setupTestSharding(shard, replicas)
clusterA := &v1alpha1.Cluster{
ID: "2",
Server: "https://127.0.0.1:6443",
}
sharding.Add(clusterA)
clusterB := v1alpha1.Cluster{
ID: "1",
Server: "https://kubernetes.default.svc",
}
sharding.Add(&clusterB)
distribution := sharding.GetDistribution()
assert.Contains(t, sharding.Clusters, clusterA.Server)
assert.Contains(t, sharding.Clusters, clusterB.Server)
clusterDistribution, ok := distribution[clusterA.Server]
assert.True(t, ok)
assert.Equal(t, 1, clusterDistribution)
myClusterDistribution, ok := distribution[clusterB.Server]
assert.True(t, ok)
assert.Equal(t, 0, myClusterDistribution)
assert.Equal(t, 2, len(distribution))
}
func TestClusterSharding_AddRoundRobin_Redistributes(t *testing.T) {
shard := 1
replicas := 2
db := &dbmocks.ArgoDB{}
sharding := NewClusterSharding(db, shard, replicas, "round-robin").(*ClusterSharding)
clusterA := &v1alpha1.Cluster{
ID: "1",
Server: "https://127.0.0.1:6443",
}
sharding.Add(clusterA)
clusterB := v1alpha1.Cluster{
ID: "3",
Server: "https://kubernetes.default.svc",
}
sharding.Add(&clusterB)
distributionBefore := sharding.GetDistribution()
assert.Contains(t, sharding.Clusters, clusterA.Server)
assert.Contains(t, sharding.Clusters, clusterB.Server)
clusterDistributionA, ok := distributionBefore[clusterA.Server]
assert.True(t, ok)
assert.Equal(t, 0, clusterDistributionA)
clusterDistributionB, ok := distributionBefore[clusterB.Server]
assert.True(t, ok)
assert.Equal(t, 1, clusterDistributionB)
assert.Equal(t, 2, len(distributionBefore))
clusterC := v1alpha1.Cluster{
ID: "2",
Server: "https://1.1.1.1",
}
sharding.Add(&clusterC)
distributionAfter := sharding.GetDistribution()
assert.Contains(t, sharding.Clusters, clusterA.Server)
assert.Contains(t, sharding.Clusters, clusterB.Server)
assert.Contains(t, sharding.Clusters, clusterC.Server)
clusterDistributionA, ok = distributionAfter[clusterA.Server]
assert.True(t, ok)
assert.Equal(t, 0, clusterDistributionA)
clusterDistributionC, ok := distributionAfter[clusterC.Server]
assert.True(t, ok)
assert.Equal(t, 1, clusterDistributionC) // will be assigned to shard 1 because the .ID is smaller then the "B" cluster
clusterDistributionB, ok = distributionAfter[clusterB.Server]
assert.True(t, ok)
assert.Equal(t, 0, clusterDistributionB) // will be reassigned to shard 0 because the .ID is bigger then the "C" cluster
}
func TestClusterSharding_Delete(t *testing.T) {
shard := 1
replicas := 2
sharding := setupTestSharding(shard, replicas)
sharding.Init(
&v1alpha1.ClusterList{
Items: []v1alpha1.Cluster{
{
ID: "2",
Server: "https://127.0.0.1:6443",
},
{
ID: "1",
Server: "https://kubernetes.default.svc",
},
},
},
&v1alpha1.ApplicationList{
Items: []v1alpha1.Application{
createApp("app2", "https://127.0.0.1:6443"),
createApp("app1", "https://kubernetes.default.svc"),
},
},
)
sharding.Delete("https://kubernetes.default.svc")
distribution := sharding.GetDistribution()
assert.Equal(t, 1, len(distribution))
}
func TestClusterSharding_Update(t *testing.T) {
shard := 1
replicas := 2
sharding := setupTestSharding(shard, replicas)
sharding.Init(
&v1alpha1.ClusterList{
Items: []v1alpha1.Cluster{
{
ID: "2",
Server: "https://127.0.0.1:6443",
},
{
ID: "1",
Server: "https://kubernetes.default.svc",
},
},
},
&v1alpha1.ApplicationList{
Items: []v1alpha1.Application{
createApp("app2", "https://127.0.0.1:6443"),
createApp("app1", "https://kubernetes.default.svc"),
},
},
)
distributionBefore := sharding.GetDistribution()
assert.Equal(t, 2, len(distributionBefore))
distributionA, ok := distributionBefore["https://kubernetes.default.svc"]
assert.True(t, ok)
assert.Equal(t, 0, distributionA)
sharding.Update(&v1alpha1.Cluster{
ID: "1",
Server: "https://kubernetes.default.svc",
}, &v1alpha1.Cluster{
ID: "4",
Server: "https://kubernetes.default.svc",
})
distributionAfter := sharding.GetDistribution()
assert.Equal(t, 2, len(distributionAfter))
distributionA, ok = distributionAfter["https://kubernetes.default.svc"]
assert.True(t, ok)
assert.Equal(t, 1, distributionA)
}
func TestClusterSharding_UpdateServerName(t *testing.T) {
shard := 1
replicas := 2
sharding := setupTestSharding(shard, replicas)
sharding.Init(
&v1alpha1.ClusterList{
Items: []v1alpha1.Cluster{
{
ID: "2",
Server: "https://127.0.0.1:6443",
},
{
ID: "1",
Server: "https://kubernetes.default.svc",
},
},
},
&v1alpha1.ApplicationList{
Items: []v1alpha1.Application{
createApp("app2", "https://127.0.0.1:6443"),
createApp("app1", "https://kubernetes.default.svc"),
},
},
)
distributionBefore := sharding.GetDistribution()
assert.Equal(t, 2, len(distributionBefore))
distributionA, ok := distributionBefore["https://kubernetes.default.svc"]
assert.True(t, ok)
assert.Equal(t, 0, distributionA)
sharding.Update(&v1alpha1.Cluster{
ID: "1",
Server: "https://kubernetes.default.svc",
}, &v1alpha1.Cluster{
ID: "1",
Server: "https://server2",
})
distributionAfter := sharding.GetDistribution()
assert.Equal(t, 2, len(distributionAfter))
_, ok = distributionAfter["https://kubernetes.default.svc"]
assert.False(t, ok) // the old server name should not be present anymore
_, ok = distributionAfter["https://server2"]
assert.True(t, ok) // the new server name should be present
}
func TestClusterSharding_IsManagedCluster(t *testing.T) {
replicas := 2
sharding0 := setupTestSharding(0, replicas)
sharding0.Init(
&v1alpha1.ClusterList{
Items: []v1alpha1.Cluster{
{
ID: "1",
Server: "https://kubernetes.default.svc",
},
{
ID: "2",
Server: "https://127.0.0.1:6443",
},
},
},
&v1alpha1.ApplicationList{
Items: []v1alpha1.Application{
createApp("app2", "https://127.0.0.1:6443"),
createApp("app1", "https://kubernetes.default.svc"),
},
},
)
assert.True(t, sharding0.IsManagedCluster(&v1alpha1.Cluster{
ID: "1",
Server: "https://kubernetes.default.svc",
}))
assert.False(t, sharding0.IsManagedCluster(&v1alpha1.Cluster{
ID: "2",
Server: "https://127.0.0.1:6443",
}))
sharding1 := setupTestSharding(1, replicas)
sharding1.Init(
&v1alpha1.ClusterList{
Items: []v1alpha1.Cluster{
{
ID: "2",
Server: "https://127.0.0.1:6443",
},
{
ID: "1",
Server: "https://kubernetes.default.svc",
},
},
},
&v1alpha1.ApplicationList{
Items: []v1alpha1.Application{
createApp("app2", "https://127.0.0.1:6443"),
createApp("app1", "https://kubernetes.default.svc"),
},
},
)
assert.False(t, sharding1.IsManagedCluster(&v1alpha1.Cluster{
ID: "1",
Server: "https://kubernetes.default.svc",
}))
assert.True(t, sharding1.IsManagedCluster(&v1alpha1.Cluster{
ID: "2",
Server: "https://127.0.0.1:6443",
}))
}
func TestClusterSharding_ClusterShardOfResourceShouldNotBeChanged(t *testing.T) {
shard := 1
replicas := 2
sharding := setupTestSharding(shard, replicas)
Int64Ptr := func(i int64) *int64 {
return &i
}
clusterWithNil := &v1alpha1.Cluster{
ID: "2",
Server: "https://127.0.0.1:6443",
Shard: nil,
}
clusterWithValue := &v1alpha1.Cluster{
ID: "1",
Server: "https://kubernetes.default.svc",
Shard: Int64Ptr(1),
}
clusterWithToBigValue := &v1alpha1.Cluster{
ID: "3",
Server: "https://1.1.1.1",
Shard: Int64Ptr(999), // shard value is explicitly bigger than the number of replicas
}
sharding.Init(
&v1alpha1.ClusterList{
Items: []v1alpha1.Cluster{
*clusterWithNil,
*clusterWithValue,
*clusterWithToBigValue,
},
},
&v1alpha1.ApplicationList{
Items: []v1alpha1.Application{
createApp("app2", "https://127.0.0.1:6443"),
createApp("app1", "https://kubernetes.default.svc"),
},
},
)
distribution := sharding.GetDistribution()
assert.Equal(t, 3, len(distribution))
assert.Nil(t, sharding.Clusters[clusterWithNil.Server].Shard)
assert.NotNil(t, sharding.Clusters[clusterWithValue.Server].Shard)
assert.Equal(t, int64(1), *sharding.Clusters[clusterWithValue.Server].Shard)
assert.Equal(t, 1, distribution[clusterWithValue.Server])
assert.NotNil(t, sharding.Clusters[clusterWithToBigValue.Server].Shard)
assert.Equal(t, int64(999), *sharding.Clusters[clusterWithToBigValue.Server].Shard)
assert.Equal(t, 0, distribution[clusterWithToBigValue.Server]) // will be assigned to shard 0 because the value is bigger than the number of replicas
}
func TestHasShardingUpdates(t *testing.T) {
Int64Ptr := func(i int64) *int64 {
return &i
}
testCases := []struct {
name string
old *v1alpha1.Cluster
new *v1alpha1.Cluster
expected bool
}{
{
name: "No updates",
old: &v1alpha1.Cluster{
Server: "https://kubernetes.default.svc",
Shard: Int64Ptr(1),
},
new: &v1alpha1.Cluster{
Server: "https://kubernetes.default.svc",
Shard: Int64Ptr(1),
},
expected: false,
},
{
name: "Updates",
old: &v1alpha1.Cluster{
Server: "https://kubernetes.default.svc",
Shard: Int64Ptr(1),
},
new: &v1alpha1.Cluster{
Server: "https://kubernetes.default.svc",
Shard: Int64Ptr(2),
},
expected: true,
},
{
name: "Old is nil",
old: nil,
new: &v1alpha1.Cluster{
Server: "https://kubernetes.default.svc",
Shard: Int64Ptr(2),
},
expected: false,
},
{
name: "New is nil",
old: &v1alpha1.Cluster{
Server: "https://kubernetes.default.svc",
Shard: Int64Ptr(2),
},
new: nil,
expected: false,
},
{
name: "Both are nil",
old: nil,
new: nil,
expected: false,
},
{
name: "Both shards are nil",
old: &v1alpha1.Cluster{
Server: "https://kubernetes.default.svc",
Shard: nil,
},
new: &v1alpha1.Cluster{
Server: "https://kubernetes.default.svc",
Shard: nil,
},
expected: false,
},
{
name: "Old shard is nil",
old: &v1alpha1.Cluster{
Server: "https://kubernetes.default.svc",
Shard: nil,
},
new: &v1alpha1.Cluster{
Server: "https://kubernetes.default.svc",
Shard: Int64Ptr(2),
},
expected: true,
},
{
name: "New shard is nil",
old: &v1alpha1.Cluster{
Server: "https://kubernetes.default.svc",
Shard: Int64Ptr(2),
},
new: &v1alpha1.Cluster{
Server: "https://kubernetes.default.svc",
Shard: nil,
},
expected: true,
},
{
name: "Cluster ID has changed",
old: &v1alpha1.Cluster{
ID: "1",
Server: "https://kubernetes.default.svc",
Shard: Int64Ptr(2),
},
new: &v1alpha1.Cluster{
ID: "2",
Server: "https://kubernetes.default.svc",
Shard: Int64Ptr(2),
},
expected: true,
},
{
name: "Server has changed",
old: &v1alpha1.Cluster{
ID: "1",
Server: "https://server1",
Shard: Int64Ptr(2),
},
new: &v1alpha1.Cluster{
ID: "1",
Server: "https://server2",
Shard: Int64Ptr(2),
},
expected: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
assert.Equal(t, tc.expected, hasShardingUpdates(tc.old, tc.new))
})
}
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"hash/fnv"
"math"
"os"
"sort"
"strconv"
@@ -20,6 +21,7 @@ import (
"github.com/argoproj/argo-cd/v2/util/db"
"github.com/argoproj/argo-cd/v2/util/env"
"github.com/argoproj/argo-cd/v2/util/errors"
"github.com/argoproj/argo-cd/v2/util/settings"
log "github.com/sirupsen/logrus"
kubeerrors "k8s.io/apimachinery/pkg/api/errors"
@@ -40,6 +42,8 @@ const ShardControllerMappingKey = "shardControllerMapping"
type DistributionFunction func(c *v1alpha1.Cluster) int
type ClusterFilterFunction func(c *v1alpha1.Cluster) bool
type clusterAccessor func() []*v1alpha1.Cluster
type appAccessor func() []*v1alpha1.Application
// shardApplicationControllerMapping stores the mapping of Shard Number to Application Controller in ConfigMap.
// It also stores the heartbeat of last synced time of the application controller.
@@ -53,8 +57,7 @@ type shardApplicationControllerMapping struct {
// and returns wheter or not the cluster should be processed by a given shard. It calls the distributionFunction
// to determine which shard will process the cluster, and if the given shard is equal to the calculated shard
// the function will return true.
func GetClusterFilter(db db.ArgoDB, distributionFunction DistributionFunction, shard int) ClusterFilterFunction {
replicas := db.GetApplicationControllerReplicas()
func GetClusterFilter(db db.ArgoDB, distributionFunction DistributionFunction, replicas, shard int) ClusterFilterFunction {
return func(c *v1alpha1.Cluster) bool {
clusterShard := 0
if c != nil && c.Shard != nil {
@@ -73,14 +76,14 @@ func GetClusterFilter(db db.ArgoDB, distributionFunction DistributionFunction, s
// GetDistributionFunction returns which DistributionFunction should be used based on the passed algorithm and
// the current datas.
func GetDistributionFunction(db db.ArgoDB, shardingAlgorithm string) DistributionFunction {
log.Infof("Using filter function: %s", shardingAlgorithm)
distributionFunction := LegacyDistributionFunction(db)
func GetDistributionFunction(clusters clusterAccessor, apps appAccessor, shardingAlgorithm string, replicasCount int) DistributionFunction {
log.Debugf("Using filter function: %s", shardingAlgorithm)
distributionFunction := LegacyDistributionFunction(replicasCount)
switch shardingAlgorithm {
case common.RoundRobinShardingAlgorithm:
distributionFunction = RoundRobinDistributionFunction(db)
distributionFunction = RoundRobinDistributionFunction(clusters, replicasCount)
case common.LegacyShardingAlgorithm:
distributionFunction = LegacyDistributionFunction(db)
distributionFunction = LegacyDistributionFunction(replicasCount)
default:
log.Warnf("distribution type %s is not supported, defaulting to %s", shardingAlgorithm, common.DefaultShardingAlgorithm)
}
@@ -92,15 +95,21 @@ func GetDistributionFunction(db db.ArgoDB, shardingAlgorithm string) Distributio
// is lightweight and can be distributed easily, however, it does not ensure an homogenous distribution as
// some shards may get assigned more clusters than others. It is the legacy function distribution that is
// kept for compatibility reasons
func LegacyDistributionFunction(db db.ArgoDB) DistributionFunction {
replicas := db.GetApplicationControllerReplicas()
func LegacyDistributionFunction(replicas int) DistributionFunction {
return func(c *v1alpha1.Cluster) int {
if replicas == 0 {
log.Debugf("Replicas count is : %d, returning -1", replicas)
return -1
}
if c == nil {
log.Debug("In-cluster: returning 0")
return 0
}
// if Shard is manually set and the assigned value is lower than the number of replicas,
// then its value is returned otherwise it is the default calculated value
if c.Shard != nil && int(*c.Shard) < replicas {
return int(*c.Shard)
}
id := c.ID
log.Debugf("Calculating cluster shard for cluster id: %s", id)
if id == "" {
@@ -121,14 +130,19 @@ func LegacyDistributionFunction(db db.ArgoDB) DistributionFunction {
// This function ensures an homogenous distribution: each shards got assigned the same number of
// clusters +/-1 , but with the drawback of a reshuffling of clusters accross shards in case of some changes
// in the cluster list
func RoundRobinDistributionFunction(db db.ArgoDB) DistributionFunction {
replicas := db.GetApplicationControllerReplicas()
func RoundRobinDistributionFunction(clusters clusterAccessor, replicas int) DistributionFunction {
return func(c *v1alpha1.Cluster) int {
if replicas > 0 {
if c == nil { // in-cluster does not necessarly have a secret assigned. So we are receiving a nil cluster here.
return 0
}
// if Shard is manually set and the assigned value is lower than the number of replicas,
// then its value is returned otherwise it is the default calculated value
if c.Shard != nil && int(*c.Shard) < replicas {
return int(*c.Shard)
} else {
clusterIndexdByClusterIdMap := createClusterIndexByClusterIdMap(db)
clusterIndexdByClusterIdMap := createClusterIndexByClusterIdMap(clusters)
clusterIndex, ok := clusterIndexdByClusterIdMap[c.ID]
if !ok {
log.Warnf("Cluster with id=%s not found in cluster map.", c.ID)
@@ -144,6 +158,12 @@ func RoundRobinDistributionFunction(db db.ArgoDB) DistributionFunction {
}
}
// NoShardingDistributionFunction returns a DistributionFunction that will process all cluster by shard 0
// the function is created for API compatibility purposes and is not supposed to be activated.
func NoShardingDistributionFunction() DistributionFunction {
return func(c *v1alpha1.Cluster) int { return 0 }
}
// InferShard extracts the shard index based on its hostname.
func InferShard() (int, error) {
hostname, err := osHostnameFunction()
@@ -152,33 +172,29 @@ func InferShard() (int, error) {
}
parts := strings.Split(hostname, "-")
if len(parts) == 0 {
return 0, fmt.Errorf("hostname should ends with shard number separated by '-' but got: %s", hostname)
log.Warnf("hostname should end with shard number separated by '-' but got: %s", hostname)
return 0, nil
}
shard, err := strconv.Atoi(parts[len(parts)-1])
if err != nil {
return 0, fmt.Errorf("hostname should ends with shard number separated by '-' but got: %s", hostname)
log.Warnf("hostname should end with shard number separated by '-' but got: %s", hostname)
return 0, nil
}
return int(shard), nil
}
func getSortedClustersList(db db.ArgoDB) []v1alpha1.Cluster {
ctx := context.Background()
clustersList, dbErr := db.ListClusters(ctx)
if dbErr != nil {
log.Warnf("Error while querying clusters list from database: %v", dbErr)
return []v1alpha1.Cluster{}
}
clusters := clustersList.Items
func getSortedClustersList(getCluster clusterAccessor) []*v1alpha1.Cluster {
clusters := getCluster()
sort.Slice(clusters, func(i, j int) bool {
return clusters[i].ID < clusters[j].ID
})
return clusters
}
func createClusterIndexByClusterIdMap(db db.ArgoDB) map[string]int {
clusters := getSortedClustersList(db)
func createClusterIndexByClusterIdMap(getCluster clusterAccessor) map[string]int {
clusters := getSortedClustersList(getCluster)
log.Debugf("ClustersList has %d items", len(clusters))
clusterById := make(map[string]v1alpha1.Cluster)
clusterById := make(map[string]*v1alpha1.Cluster)
clusterIndexedByClusterId := make(map[string]int)
for i, cluster := range clusters {
log.Debugf("Adding cluster with id=%s and name=%s to cluster's map", cluster.ID, cluster.Name)
@@ -193,8 +209,7 @@ func createClusterIndexByClusterIdMap(db db.ArgoDB) map[string]int {
// The function takes the shard number from the environment variable (default value -1, if not set) and passes it to this function.
// If the shard value passed to this function is -1, that is, the shard was not set as an environment variable,
// we default the shard number to 0 for computing the default config map.
func GetOrUpdateShardFromConfigMap(kubeClient *kubernetes.Clientset, settingsMgr *settings.SettingsManager, replicas, shard int) (int, error) {
func GetOrUpdateShardFromConfigMap(kubeClient kubernetes.Interface, settingsMgr *settings.SettingsManager, replicas, shard int) (int, error) {
hostname, err := osHostnameFunction()
if err != nil {
return -1, err
@@ -351,3 +366,59 @@ func getDefaultShardMappingData(replicas int) []shardApplicationControllerMappin
}
return shardMappingData
}
func GetClusterSharding(kubeClient kubernetes.Interface, settingsMgr *settings.SettingsManager, shardingAlgorithm string, enableDynamicClusterDistribution bool) (ClusterShardingCache, error) {
var replicasCount int
if enableDynamicClusterDistribution {
applicationControllerName := env.StringFromEnv(common.EnvAppControllerName, common.DefaultApplicationControllerName)
appControllerDeployment, err := kubeClient.AppsV1().Deployments(settingsMgr.GetNamespace()).Get(context.Background(), applicationControllerName, metav1.GetOptions{})
// if app controller deployment is not found when dynamic cluster distribution is enabled error out
if err != nil {
return nil, fmt.Errorf("(dynamic cluster distribution) failed to get app controller deployment: %v", err)
}
if appControllerDeployment != nil && appControllerDeployment.Spec.Replicas != nil {
replicasCount = int(*appControllerDeployment.Spec.Replicas)
} else {
return nil, fmt.Errorf("(dynamic cluster distribution) failed to get app controller deployment replica count")
}
} else {
replicasCount = env.ParseNumFromEnv(common.EnvControllerReplicas, 0, 0, math.MaxInt32)
}
shardNumber := env.ParseNumFromEnv(common.EnvControllerShard, -1, -math.MaxInt32, math.MaxInt32)
if replicasCount > 1 {
// check for shard mapping using configmap if application-controller is a deployment
// else use existing logic to infer shard from pod name if application-controller is a statefulset
if enableDynamicClusterDistribution {
var err error
// retry 3 times if we find a conflict while updating shard mapping configMap.
// If we still see conflicts after the retries, wait for next iteration of heartbeat process.
for i := 0; i <= common.AppControllerHeartbeatUpdateRetryCount; i++ {
shardNumber, err = GetOrUpdateShardFromConfigMap(kubeClient, settingsMgr, replicasCount, shardNumber)
if err != nil && !kubeerrors.IsConflict(err) {
err = fmt.Errorf("unable to get shard due to error updating the sharding config map: %s", err)
break
}
log.Warnf("conflict when getting shard from shard mapping configMap. Retrying (%d/3)", i)
}
errors.CheckError(err)
} else {
if shardNumber < 0 {
var err error
shardNumber, err = InferShard()
errors.CheckError(err)
}
if shardNumber > replicasCount {
log.Warnf("Calculated shard number %d is greated than the number of replicas count. Defaulting to 0", shardNumber)
shardNumber = 0
}
}
} else {
log.Info("Processing all cluster shards")
shardNumber = 0
}
db := db.NewDB(settingsMgr.GetNamespace(), settingsMgr, kubeClient)
return NewClusterSharding(db, shardNumber, replicasCount, shardingAlgorithm), nil
}

View File

@@ -1,36 +1,45 @@
package sharding
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"strconv"
"testing"
"time"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks"
"github.com/argoproj/argo-cd/v2/util/settings"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
kubefake "k8s.io/client-go/kubernetes/fake"
"sigs.k8s.io/yaml"
)
func TestGetShardByID_NotEmptyID(t *testing.T) {
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
assert.Equal(t, 0, LegacyDistributionFunction(db)(&v1alpha1.Cluster{ID: "1"}))
assert.Equal(t, 0, LegacyDistributionFunction(db)(&v1alpha1.Cluster{ID: "2"}))
assert.Equal(t, 0, LegacyDistributionFunction(db)(&v1alpha1.Cluster{ID: "3"}))
assert.Equal(t, 0, LegacyDistributionFunction(db)(&v1alpha1.Cluster{ID: "4"}))
replicasCount := 1
db.On("GetApplicationControllerReplicas").Return(replicasCount)
assert.Equal(t, 0, LegacyDistributionFunction(replicasCount)(&v1alpha1.Cluster{ID: "1"}))
assert.Equal(t, 0, LegacyDistributionFunction(replicasCount)(&v1alpha1.Cluster{ID: "2"}))
assert.Equal(t, 0, LegacyDistributionFunction(replicasCount)(&v1alpha1.Cluster{ID: "3"}))
assert.Equal(t, 0, LegacyDistributionFunction(replicasCount)(&v1alpha1.Cluster{ID: "4"}))
}
func TestGetShardByID_EmptyID(t *testing.T) {
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
replicasCount := 1
db.On("GetApplicationControllerReplicas").Return(replicasCount)
distributionFunction := LegacyDistributionFunction
shard := distributionFunction(db)(&v1alpha1.Cluster{})
shard := distributionFunction(replicasCount)(&v1alpha1.Cluster{})
assert.Equal(t, 0, shard)
}
@@ -38,7 +47,7 @@ func TestGetShardByID_NoReplicas(t *testing.T) {
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(0)
distributionFunction := LegacyDistributionFunction
shard := distributionFunction(db)(&v1alpha1.Cluster{})
shard := distributionFunction(0)(&v1alpha1.Cluster{})
assert.Equal(t, -1, shard)
}
@@ -46,16 +55,16 @@ func TestGetShardByID_NoReplicasUsingHashDistributionFunction(t *testing.T) {
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(0)
distributionFunction := LegacyDistributionFunction
shard := distributionFunction(db)(&v1alpha1.Cluster{})
shard := distributionFunction(0)(&v1alpha1.Cluster{})
assert.Equal(t, -1, shard)
}
func TestGetShardByID_NoReplicasUsingHashDistributionFunctionWithClusters(t *testing.T) {
db, cluster1, cluster2, cluster3, cluster4, cluster5 := createTestClusters()
clusters, db, cluster1, cluster2, cluster3, cluster4, cluster5 := createTestClusters()
// Test with replicas set to 0
db.On("GetApplicationControllerReplicas").Return(0)
t.Setenv(common.EnvControllerShardingAlgorithm, common.RoundRobinShardingAlgorithm)
distributionFunction := RoundRobinDistributionFunction(db)
distributionFunction := RoundRobinDistributionFunction(clusters, 0)
assert.Equal(t, -1, distributionFunction(nil))
assert.Equal(t, -1, distributionFunction(&cluster1))
assert.Equal(t, -1, distributionFunction(&cluster2))
@@ -65,137 +74,115 @@ func TestGetShardByID_NoReplicasUsingHashDistributionFunctionWithClusters(t *tes
}
func TestGetClusterFilterDefault(t *testing.T) {
shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...)
//shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...)
clusterAccessor, _, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters()
os.Unsetenv(common.EnvControllerShardingAlgorithm)
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(2)
filter := GetClusterFilter(db, GetDistributionFunction(db, common.DefaultShardingAlgorithm), shardIndex)
assert.False(t, filter(&v1alpha1.Cluster{ID: "1"}))
assert.True(t, filter(&v1alpha1.Cluster{ID: "2"}))
assert.False(t, filter(&v1alpha1.Cluster{ID: "3"}))
assert.True(t, filter(&v1alpha1.Cluster{ID: "4"}))
replicasCount := 2
distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
assert.Equal(t, 0, distributionFunction(&cluster1))
assert.Equal(t, 1, distributionFunction(&cluster2))
assert.Equal(t, 0, distributionFunction(&cluster3))
assert.Equal(t, 1, distributionFunction(&cluster4))
}
func TestGetClusterFilterLegacy(t *testing.T) {
shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...)
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(2)
//shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...)
clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters()
replicasCount := 2
db.On("GetApplicationControllerReplicas").Return(replicasCount)
t.Setenv(common.EnvControllerShardingAlgorithm, common.LegacyShardingAlgorithm)
filter := GetClusterFilter(db, GetDistributionFunction(db, common.LegacyShardingAlgorithm), shardIndex)
assert.False(t, filter(&v1alpha1.Cluster{ID: "1"}))
assert.True(t, filter(&v1alpha1.Cluster{ID: "2"}))
assert.False(t, filter(&v1alpha1.Cluster{ID: "3"}))
assert.True(t, filter(&v1alpha1.Cluster{ID: "4"}))
distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
assert.Equal(t, 0, distributionFunction(&cluster1))
assert.Equal(t, 1, distributionFunction(&cluster2))
assert.Equal(t, 0, distributionFunction(&cluster3))
assert.Equal(t, 1, distributionFunction(&cluster4))
}
func TestGetClusterFilterUnknown(t *testing.T) {
shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...)
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(2)
clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters()
appAccessor, _, _, _, _, _ := createTestApps()
// Test with replicas set to 0
t.Setenv(common.EnvControllerReplicas, "2")
os.Unsetenv(common.EnvControllerShardingAlgorithm)
t.Setenv(common.EnvControllerShardingAlgorithm, "unknown")
filter := GetClusterFilter(db, GetDistributionFunction(db, "unknown"), shardIndex)
assert.False(t, filter(&v1alpha1.Cluster{ID: "1"}))
assert.True(t, filter(&v1alpha1.Cluster{ID: "2"}))
assert.False(t, filter(&v1alpha1.Cluster{ID: "3"}))
assert.True(t, filter(&v1alpha1.Cluster{ID: "4"}))
replicasCount := 2
db.On("GetApplicationControllerReplicas").Return(replicasCount)
distributionFunction := GetDistributionFunction(clusterAccessor, appAccessor, "unknown", replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
assert.Equal(t, 0, distributionFunction(&cluster1))
assert.Equal(t, 1, distributionFunction(&cluster2))
assert.Equal(t, 0, distributionFunction(&cluster3))
assert.Equal(t, 1, distributionFunction(&cluster4))
}
func TestLegacyGetClusterFilterWithFixedShard(t *testing.T) {
shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...)
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(2)
filter := GetClusterFilter(db, GetDistributionFunction(db, common.DefaultShardingAlgorithm), shardIndex)
assert.False(t, filter(nil))
assert.False(t, filter(&v1alpha1.Cluster{ID: "1"}))
assert.True(t, filter(&v1alpha1.Cluster{ID: "2"}))
assert.False(t, filter(&v1alpha1.Cluster{ID: "3"}))
assert.True(t, filter(&v1alpha1.Cluster{ID: "4"}))
//shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...)
t.Setenv(common.EnvControllerReplicas, "5")
clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters()
appAccessor, _, _, _, _, _ := createTestApps()
replicasCount := 5
db.On("GetApplicationControllerReplicas").Return(replicasCount)
filter := GetDistributionFunction(clusterAccessor, appAccessor, common.DefaultShardingAlgorithm, replicasCount)
assert.Equal(t, 0, filter(nil))
assert.Equal(t, 4, filter(&cluster1))
assert.Equal(t, 1, filter(&cluster2))
assert.Equal(t, 2, filter(&cluster3))
assert.Equal(t, 2, filter(&cluster4))
var fixedShard int64 = 4
filter = GetClusterFilter(db, GetDistributionFunction(db, common.DefaultShardingAlgorithm), int(fixedShard))
assert.False(t, filter(&v1alpha1.Cluster{ID: "4", Shard: &fixedShard}))
cluster5 := &v1alpha1.Cluster{ID: "5", Shard: &fixedShard}
clusterAccessor = getClusterAccessor([]v1alpha1.Cluster{cluster1, cluster2, cluster2, cluster4, *cluster5})
filter = GetDistributionFunction(clusterAccessor, appAccessor, common.DefaultShardingAlgorithm, replicasCount)
assert.Equal(t, int(fixedShard), filter(cluster5))
fixedShard = 1
filter = GetClusterFilter(db, GetDistributionFunction(db, common.DefaultShardingAlgorithm), int(fixedShard))
assert.True(t, filter(&v1alpha1.Cluster{Name: "cluster4", ID: "4", Shard: &fixedShard}))
cluster5.Shard = &fixedShard
clusterAccessor = getClusterAccessor([]v1alpha1.Cluster{cluster1, cluster2, cluster2, cluster4, *cluster5})
filter = GetDistributionFunction(clusterAccessor, appAccessor, common.DefaultShardingAlgorithm, replicasCount)
assert.Equal(t, int(fixedShard), filter(&v1alpha1.Cluster{ID: "4", Shard: &fixedShard}))
}
func TestRoundRobinGetClusterFilterWithFixedShard(t *testing.T) {
shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...)
db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters()
db.On("GetApplicationControllerReplicas").Return(2)
filter := GetClusterFilter(db, GetDistributionFunction(db, common.RoundRobinShardingAlgorithm), shardIndex)
assert.False(t, filter(nil))
assert.False(t, filter(&cluster1))
assert.True(t, filter(&cluster2))
assert.False(t, filter(&cluster3))
assert.True(t, filter(&cluster4))
//shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...)
t.Setenv(common.EnvControllerReplicas, "4")
clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters()
appAccessor, _, _, _, _, _ := createTestApps()
replicasCount := 4
db.On("GetApplicationControllerReplicas").Return(replicasCount)
filter := GetDistributionFunction(clusterAccessor, appAccessor, common.RoundRobinShardingAlgorithm, replicasCount)
assert.Equal(t, filter(nil), 0)
assert.Equal(t, filter(&cluster1), 0)
assert.Equal(t, filter(&cluster2), 1)
assert.Equal(t, filter(&cluster3), 2)
assert.Equal(t, filter(&cluster4), 3)
// a cluster with a fixed shard should be processed by the specified exact
// same shard unless the specified shard index is greater than the number of replicas.
var fixedShard int64 = 4
filter = GetClusterFilter(db, GetDistributionFunction(db, common.RoundRobinShardingAlgorithm), int(fixedShard))
assert.False(t, filter(&v1alpha1.Cluster{Name: "cluster4", ID: "4", Shard: &fixedShard}))
var fixedShard int64 = 1
cluster5 := v1alpha1.Cluster{Name: "cluster5", ID: "5", Shard: &fixedShard}
clusters := []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5}
clusterAccessor = getClusterAccessor(clusters)
filter = GetDistributionFunction(clusterAccessor, appAccessor, common.RoundRobinShardingAlgorithm, replicasCount)
assert.Equal(t, int(fixedShard), filter(&cluster5))
fixedShard = 1
filter = GetClusterFilter(db, GetDistributionFunction(db, common.RoundRobinShardingAlgorithm), int(fixedShard))
assert.True(t, filter(&v1alpha1.Cluster{Name: "cluster4", ID: "4", Shard: &fixedShard}))
}
func TestGetClusterFilterLegacyHash(t *testing.T) {
shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...)
t.Setenv(common.EnvControllerShardingAlgorithm, "hash")
db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters()
db.On("GetApplicationControllerReplicas").Return(2)
filter := GetClusterFilter(db, GetDistributionFunction(db, common.LegacyShardingAlgorithm), shardIndex)
assert.False(t, filter(&cluster1))
assert.True(t, filter(&cluster2))
assert.False(t, filter(&cluster3))
assert.True(t, filter(&cluster4))
// a cluster with a fixed shard should be processed by the specified exact
// same shard unless the specified shard index is greater than the number of replicas.
var fixedShard int64 = 4
filter = GetClusterFilter(db, GetDistributionFunction(db, common.LegacyShardingAlgorithm), int(fixedShard))
assert.False(t, filter(&v1alpha1.Cluster{Name: "cluster4", ID: "4", Shard: &fixedShard}))
fixedShard = 1
filter = GetClusterFilter(db, GetDistributionFunction(db, common.LegacyShardingAlgorithm), int(fixedShard))
assert.True(t, filter(&v1alpha1.Cluster{Name: "cluster4", ID: "4", Shard: &fixedShard}))
}
func TestGetClusterFilterWithEnvControllerShardingAlgorithms(t *testing.T) {
db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters()
shardIndex := 1
db.On("GetApplicationControllerReplicas").Return(2)
t.Run("legacy", func(t *testing.T) {
t.Setenv(common.EnvControllerShardingAlgorithm, common.LegacyShardingAlgorithm)
shardShouldProcessCluster := GetClusterFilter(db, GetDistributionFunction(db, common.LegacyShardingAlgorithm), shardIndex)
assert.False(t, shardShouldProcessCluster(&cluster1))
assert.True(t, shardShouldProcessCluster(&cluster2))
assert.False(t, shardShouldProcessCluster(&cluster3))
assert.True(t, shardShouldProcessCluster(&cluster4))
assert.False(t, shardShouldProcessCluster(nil))
})
t.Run("roundrobin", func(t *testing.T) {
t.Setenv(common.EnvControllerShardingAlgorithm, common.RoundRobinShardingAlgorithm)
shardShouldProcessCluster := GetClusterFilter(db, GetDistributionFunction(db, common.LegacyShardingAlgorithm), shardIndex)
assert.False(t, shardShouldProcessCluster(&cluster1))
assert.True(t, shardShouldProcessCluster(&cluster2))
assert.False(t, shardShouldProcessCluster(&cluster3))
assert.True(t, shardShouldProcessCluster(&cluster4))
assert.False(t, shardShouldProcessCluster(nil))
})
cluster5 = v1alpha1.Cluster{Name: "cluster5", ID: "5", Shard: &fixedShard}
clusters = []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5}
clusterAccessor = getClusterAccessor(clusters)
filter = GetDistributionFunction(clusterAccessor, appAccessor, common.RoundRobinShardingAlgorithm, replicasCount)
assert.Equal(t, int(fixedShard), filter(&v1alpha1.Cluster{Name: "cluster4", ID: "4", Shard: &fixedShard}))
}
func TestGetShardByIndexModuloReplicasCountDistributionFunction2(t *testing.T) {
db, cluster1, cluster2, cluster3, cluster4, cluster5 := createTestClusters()
clusters, db, cluster1, cluster2, cluster3, cluster4, cluster5 := createTestClusters()
t.Run("replicas set to 1", func(t *testing.T) {
db.On("GetApplicationControllerReplicas").Return(1).Once()
distributionFunction := RoundRobinDistributionFunction(db)
replicasCount := 1
db.On("GetApplicationControllerReplicas").Return(replicasCount).Once()
distributionFunction := RoundRobinDistributionFunction(clusters, replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
assert.Equal(t, 0, distributionFunction(&cluster1))
assert.Equal(t, 0, distributionFunction(&cluster2))
@@ -205,8 +192,9 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunction2(t *testing.T) {
})
t.Run("replicas set to 2", func(t *testing.T) {
db.On("GetApplicationControllerReplicas").Return(2).Once()
distributionFunction := RoundRobinDistributionFunction(db)
replicasCount := 2
db.On("GetApplicationControllerReplicas").Return(replicasCount).Once()
distributionFunction := RoundRobinDistributionFunction(clusters, replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
assert.Equal(t, 0, distributionFunction(&cluster1))
assert.Equal(t, 1, distributionFunction(&cluster2))
@@ -216,8 +204,9 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunction2(t *testing.T) {
})
t.Run("replicas set to 3", func(t *testing.T) {
db.On("GetApplicationControllerReplicas").Return(3).Once()
distributionFunction := RoundRobinDistributionFunction(db)
replicasCount := 3
db.On("GetApplicationControllerReplicas").Return(replicasCount).Once()
distributionFunction := RoundRobinDistributionFunction(clusters, replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
assert.Equal(t, 0, distributionFunction(&cluster1))
assert.Equal(t, 1, distributionFunction(&cluster2))
@@ -233,17 +222,19 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunctionWhenClusterNumber
// Initial tests where showing that under 1024 clusters, execution time was around 400ms
// and for 4096 clusters, execution time was under 9s
// The other implementation was giving almost linear time of 400ms up to 10'000 clusters
db := dbmocks.ArgoDB{}
clusterList := &v1alpha1.ClusterList{Items: []v1alpha1.Cluster{}}
clusterPointers := []*v1alpha1.Cluster{}
for i := 0; i < 2048; i++ {
cluster := createCluster(fmt.Sprintf("cluster-%d", i), fmt.Sprintf("%d", i))
clusterList.Items = append(clusterList.Items, cluster)
clusterPointers = append(clusterPointers, &cluster)
}
db.On("ListClusters", mock.Anything).Return(clusterList, nil)
db.On("GetApplicationControllerReplicas").Return(2)
distributionFunction := RoundRobinDistributionFunction(&db)
for i, c := range clusterList.Items {
assert.Equal(t, i%2, distributionFunction(&c))
replicasCount := 2
t.Setenv(common.EnvControllerReplicas, strconv.Itoa(replicasCount))
_, db, _, _, _, _, _ := createTestClusters()
clusterAccessor := func() []*v1alpha1.Cluster { return clusterPointers }
db.On("GetApplicationControllerReplicas").Return(replicasCount)
distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount)
for i, c := range clusterPointers {
assert.Equal(t, i%2, distributionFunction(c))
}
}
@@ -256,12 +247,15 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunctionWhenClusterIsAdde
cluster5 := createCluster("cluster5", "5")
cluster6 := createCluster("cluster6", "6")
clusters := []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5}
clusterAccessor := getClusterAccessor(clusters)
clusterList := &v1alpha1.ClusterList{Items: []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5}}
db.On("ListClusters", mock.Anything).Return(clusterList, nil)
// Test with replicas set to 2
db.On("GetApplicationControllerReplicas").Return(2)
distributionFunction := RoundRobinDistributionFunction(&db)
replicasCount := 2
db.On("GetApplicationControllerReplicas").Return(replicasCount)
distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
assert.Equal(t, 0, distributionFunction(&cluster1))
assert.Equal(t, 1, distributionFunction(&cluster2))
@@ -272,17 +266,20 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunctionWhenClusterIsAdde
// Now, the database knows cluster6. Shard should be assigned a proper shard
clusterList.Items = append(clusterList.Items, cluster6)
distributionFunction = RoundRobinDistributionFunction(getClusterAccessor(clusterList.Items), replicasCount)
assert.Equal(t, 1, distributionFunction(&cluster6))
// Now, we remove the last added cluster, it should be unassigned as well
clusterList.Items = clusterList.Items[:len(clusterList.Items)-1]
distributionFunction = RoundRobinDistributionFunction(getClusterAccessor(clusterList.Items), replicasCount)
assert.Equal(t, -1, distributionFunction(&cluster6))
}
func TestGetShardByIndexModuloReplicasCountDistributionFunction(t *testing.T) {
db, cluster1, cluster2, _, _, _ := createTestClusters()
db.On("GetApplicationControllerReplicas").Return(2)
distributionFunction := RoundRobinDistributionFunction(db)
clusters, db, cluster1, cluster2, _, _, _ := createTestClusters()
replicasCount := 2
db.On("GetApplicationControllerReplicas").Return(replicasCount)
distributionFunction := RoundRobinDistributionFunction(clusters, replicasCount)
// Test that the function returns the correct shard for cluster1 and cluster2
expectedShardForCluster1 := 0
@@ -315,14 +312,14 @@ func TestInferShard(t *testing.T) {
osHostnameFunction = func() (string, error) { return "exampleshard", nil }
_, err = InferShard()
assert.NotNil(t, err)
assert.Nil(t, err)
osHostnameFunction = func() (string, error) { return "example-shard", nil }
_, err = InferShard()
assert.NotNil(t, err)
assert.Nil(t, err)
}
func createTestClusters() (*dbmocks.ArgoDB, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster) {
func createTestClusters() (clusterAccessor, *dbmocks.ArgoDB, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster) {
db := dbmocks.ArgoDB{}
cluster1 := createCluster("cluster1", "1")
cluster2 := createCluster("cluster2", "2")
@@ -330,10 +327,27 @@ func createTestClusters() (*dbmocks.ArgoDB, v1alpha1.Cluster, v1alpha1.Cluster,
cluster4 := createCluster("cluster4", "4")
cluster5 := createCluster("cluster5", "5")
clusters := []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5}
db.On("ListClusters", mock.Anything).Return(&v1alpha1.ClusterList{Items: []v1alpha1.Cluster{
cluster1, cluster2, cluster3, cluster4, cluster5,
}}, nil)
return &db, cluster1, cluster2, cluster3, cluster4, cluster5
return getClusterAccessor(clusters), &db, cluster1, cluster2, cluster3, cluster4, cluster5
}
func getClusterAccessor(clusters []v1alpha1.Cluster) clusterAccessor {
// Convert the array to a slice of pointers
clusterPointers := getClusterPointers(clusters)
clusterAccessor := func() []*v1alpha1.Cluster { return clusterPointers }
return clusterAccessor
}
func getClusterPointers(clusters []v1alpha1.Cluster) []*v1alpha1.Cluster {
var clusterPointers []*v1alpha1.Cluster
for i := range clusters {
clusterPointers = append(clusterPointers, &clusters[i])
}
return clusterPointers
}
func createCluster(name string, id string) v1alpha1.Cluster {
@@ -676,3 +690,265 @@ func Test_getOrUpdateShardNumberForController(t *testing.T) {
})
}
}
func TestGetClusterSharding(t *testing.T) {
IntPtr := func(i int32) *int32 {
return &i
}
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: common.DefaultApplicationControllerName,
Namespace: "argocd",
},
Spec: appsv1.DeploymentSpec{
Replicas: IntPtr(1),
},
}
deploymentMultiReplicas := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "argocd-application-controller-multi-replicas",
Namespace: "argocd",
},
Spec: appsv1.DeploymentSpec{
Replicas: IntPtr(3),
},
}
objects := append([]runtime.Object{}, deployment, deploymentMultiReplicas)
kubeclientset := kubefake.NewSimpleClientset(objects...)
settingsMgr := settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd", settings.WithRepoOrClusterChangedHandler(func() {
}))
testCases := []struct {
name string
useDynamicSharding bool
envsSetter func(t *testing.T)
cleanup func()
expectedShard int
expectedReplicas int
expectedErr error
}{
{
name: "Default sharding with statefulset",
envsSetter: func(t *testing.T) {
t.Setenv(common.EnvControllerReplicas, "1")
},
cleanup: func() {},
useDynamicSharding: false,
expectedShard: 0,
expectedReplicas: 1,
expectedErr: nil,
},
{
name: "Default sharding with deployment",
envsSetter: func(t *testing.T) {
t.Setenv(common.EnvAppControllerName, common.DefaultApplicationControllerName)
},
cleanup: func() {},
useDynamicSharding: true,
expectedShard: 0,
expectedReplicas: 1,
expectedErr: nil,
},
{
name: "Default sharding with deployment and multiple replicas",
envsSetter: func(t *testing.T) {
t.Setenv(common.EnvAppControllerName, "argocd-application-controller-multi-replicas")
},
cleanup: func() {},
useDynamicSharding: true,
expectedShard: 0,
expectedReplicas: 3,
expectedErr: nil,
},
{
name: "Statefulset multiple replicas",
envsSetter: func(t *testing.T) {
t.Setenv(common.EnvControllerReplicas, "3")
osHostnameFunction = func() (string, error) { return "example-shard-3", nil }
},
cleanup: func() {
osHostnameFunction = os.Hostname
},
useDynamicSharding: false,
expectedShard: 3,
expectedReplicas: 3,
expectedErr: nil,
},
{
name: "Explicit shard with statefulset and 1 replica",
envsSetter: func(t *testing.T) {
t.Setenv(common.EnvControllerReplicas, "1")
t.Setenv(common.EnvControllerShard, "3")
},
cleanup: func() {},
useDynamicSharding: false,
expectedShard: 0,
expectedReplicas: 1,
expectedErr: nil,
},
{
name: "Explicit shard with statefulset and 2 replica - and to high shard",
envsSetter: func(t *testing.T) {
t.Setenv(common.EnvControllerReplicas, "2")
t.Setenv(common.EnvControllerShard, "3")
},
cleanup: func() {},
useDynamicSharding: false,
expectedShard: 0,
expectedReplicas: 2,
expectedErr: nil,
},
{
name: "Explicit shard with statefulset and 2 replica",
envsSetter: func(t *testing.T) {
t.Setenv(common.EnvControllerReplicas, "2")
t.Setenv(common.EnvControllerShard, "1")
},
cleanup: func() {},
useDynamicSharding: false,
expectedShard: 1,
expectedReplicas: 2,
expectedErr: nil,
},
{
name: "Explicit shard with deployment",
envsSetter: func(t *testing.T) {
t.Setenv(common.EnvControllerShard, "3")
},
cleanup: func() {},
useDynamicSharding: true,
expectedShard: 0,
expectedReplicas: 1,
expectedErr: nil,
},
{
name: "Explicit shard with deployment and multiple replicas will read from configmap",
envsSetter: func(t *testing.T) {
t.Setenv(common.EnvAppControllerName, "argocd-application-controller-multi-replicas")
t.Setenv(common.EnvControllerShard, "3")
},
cleanup: func() {},
useDynamicSharding: true,
expectedShard: 0,
expectedReplicas: 3,
expectedErr: nil,
},
{
name: "Dynamic sharding but missing deployment",
envsSetter: func(t *testing.T) {
t.Setenv(common.EnvAppControllerName, "missing-deployment")
},
cleanup: func() {},
useDynamicSharding: true,
expectedShard: 0,
expectedReplicas: 1,
expectedErr: fmt.Errorf("(dynamic cluster distribution) failed to get app controller deployment: deployments.apps \"missing-deployment\" not found"),
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
tc.envsSetter(t)
defer tc.cleanup()
shardingCache, err := GetClusterSharding(kubeclientset, settingsMgr, "round-robin", tc.useDynamicSharding)
if shardingCache != nil {
clusterSharding := shardingCache.(*ClusterSharding)
assert.Equal(t, tc.expectedShard, clusterSharding.Shard)
assert.Equal(t, tc.expectedReplicas, clusterSharding.Replicas)
}
if tc.expectedErr != nil {
if err != nil {
assert.Equal(t, tc.expectedErr.Error(), err.Error())
} else {
t.Errorf("Expected error %v but got nil", tc.expectedErr)
}
} else {
assert.Nil(t, err)
}
})
}
}
func TestAppAwareCache(t *testing.T) {
_, db, cluster1, cluster2, cluster3, cluster4, cluster5 := createTestClusters()
_, app1, app2, app3, app4, app5 := createTestApps()
clusterSharding := NewClusterSharding(db, 0, 1, "legacy")
clusterList := &v1alpha1.ClusterList{Items: []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5}}
appList := &v1alpha1.ApplicationList{Items: []v1alpha1.Application{app1, app2, app3, app4, app5}}
clusterSharding.Init(clusterList, appList)
appDistribution := clusterSharding.GetAppDistribution()
assert.Equal(t, 2, appDistribution["cluster1"])
assert.Equal(t, 2, appDistribution["cluster2"])
assert.Equal(t, 1, appDistribution["cluster3"])
app6 := createApp("app6", "cluster4")
clusterSharding.AddApp(&app6)
app1Update := createApp("app1", "cluster2")
clusterSharding.UpdateApp(&app1Update)
clusterSharding.DeleteApp(&app3)
appDistribution = clusterSharding.GetAppDistribution()
assert.Equal(t, 1, appDistribution["cluster1"])
assert.Equal(t, 2, appDistribution["cluster2"])
assert.Equal(t, 1, appDistribution["cluster3"])
assert.Equal(t, 1, appDistribution["cluster4"])
}
func createTestApps() (appAccessor, v1alpha1.Application, v1alpha1.Application, v1alpha1.Application, v1alpha1.Application, v1alpha1.Application) {
app1 := createApp("app1", "cluster1")
app2 := createApp("app2", "cluster1")
app3 := createApp("app3", "cluster2")
app4 := createApp("app4", "cluster2")
app5 := createApp("app5", "cluster3")
apps := []v1alpha1.Application{app1, app2, app3, app4, app5}
return getAppAccessor(apps), app1, app2, app3, app4, app5
}
func getAppAccessor(apps []v1alpha1.Application) appAccessor {
// Convert the array to a slice of pointers
appPointers := getAppPointers(apps)
appAccessor := func() []*v1alpha1.Application { return appPointers }
return appAccessor
}
func getAppPointers(apps []v1alpha1.Application) []*v1alpha1.Application {
var appPointers []*v1alpha1.Application
for i := range apps {
appPointers = append(appPointers, &apps[i])
}
return appPointers
}
func createApp(name string, server string) v1alpha1.Application {
var testApp = `
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: ` + name + `
spec:
destination:
server: ` + server + `
`
var app v1alpha1.Application
err := yaml.Unmarshal([]byte(testApp), &app)
if err != nil {
panic(err)
}
return app
}

View File

@@ -3,6 +3,7 @@ package sharding
import (
"fmt"
"math"
"strconv"
"testing"
"github.com/argoproj/argo-cd/v2/common"
@@ -22,9 +23,11 @@ func TestLargeShuffle(t *testing.T) {
clusterList.Items = append(clusterList.Items, cluster)
}
db.On("ListClusters", mock.Anything).Return(clusterList, nil)
clusterAccessor := getClusterAccessor(clusterList.Items)
// Test with replicas set to 256
t.Setenv(common.EnvControllerReplicas, "256")
distributionFunction := RoundRobinDistributionFunction(&db)
replicasCount := 256
t.Setenv(common.EnvControllerReplicas, strconv.Itoa(replicasCount))
distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount)
for i, c := range clusterList.Items {
assert.Equal(t, i%2567, distributionFunction(&c))
}
@@ -44,10 +47,11 @@ func TestShuffle(t *testing.T) {
clusterList := &v1alpha1.ClusterList{Items: []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5, cluster6}}
db.On("ListClusters", mock.Anything).Return(clusterList, nil)
clusterAccessor := getClusterAccessor(clusterList.Items)
// Test with replicas set to 3
t.Setenv(common.EnvControllerReplicas, "3")
distributionFunction := RoundRobinDistributionFunction(&db)
replicasCount := 3
distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
assert.Equal(t, 0, distributionFunction(&cluster1))
assert.Equal(t, 1, distributionFunction(&cluster2))

View File

@@ -33,8 +33,10 @@ import (
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/util/app/path"
"github.com/argoproj/argo-cd/v2/util/argo"
argodiff "github.com/argoproj/argo-cd/v2/util/argo/diff"
"github.com/argoproj/argo-cd/v2/util/argo/normalizers"
appstatecache "github.com/argoproj/argo-cd/v2/util/cache/appstate"
"github.com/argoproj/argo-cd/v2/util/db"
"github.com/argoproj/argo-cd/v2/util/gpg"
@@ -117,6 +119,7 @@ type appStateManager struct {
repoErrorCache goSync.Map
repoErrorGracePeriod time.Duration
serverSideDiff bool
ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts
}
// GetRepoObjs will generate the manifests for the given application delegating the
@@ -194,6 +197,38 @@ func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alp
return nil, nil, fmt.Errorf("failed to get Kustomize options for source %d of %d: %w", i+1, len(sources), err)
}
syncedRevision := app.Status.Sync.Revision
if app.Spec.HasMultipleSources() {
if i < len(app.Status.Sync.Revisions) {
syncedRevision = app.Status.Sync.Revisions[i]
} else {
syncedRevision = ""
}
}
val, ok := app.Annotations[v1alpha1.AnnotationKeyManifestGeneratePaths]
if !source.IsHelm() && syncedRevision != "" && ok && val != "" {
// Validate the manifest-generate-path annotation to avoid generating manifests if it has not changed.
_, err = repoClient.UpdateRevisionForPaths(context.Background(), &apiclient.UpdateRevisionForPathsRequest{
Repo: repo,
Revision: revisions[i],
SyncedRevision: syncedRevision,
Paths: path.GetAppRefreshPaths(app),
AppLabelKey: appLabelKey,
AppName: app.InstanceName(m.namespace),
Namespace: app.Spec.Destination.Namespace,
ApplicationSource: &source,
KubeVersion: serverVersion,
ApiVersions: argo.APIResourcesToStrings(apiResources, true),
TrackingMethod: string(argo.GetTrackingMethod(m.settingsMgr)),
RefSources: refSources,
HasMultipleSources: app.Spec.HasMultipleSources(),
})
if err != nil {
return nil, nil, fmt.Errorf("failed to compare revisions for source %d of %d: %w", i+1, len(sources), err)
}
}
ts.AddCheckpoint("version_ms")
log.Debugf("Generating Manifest for source %s revision %s", source, revisions[i])
manifestInfo, err := repoClient.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
@@ -605,7 +640,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1
useDiffCache := useDiffCache(noCache, manifestInfos, sources, app, manifestRevisions, m.statusRefreshTimeout, serverSideDiff, logCtx)
diffConfigBuilder := argodiff.NewDiffConfigBuilder().
WithDiffSettings(app.Spec.IgnoreDifferences, resourceOverrides, compareOptions.IgnoreAggregatedRoles).
WithDiffSettings(app.Spec.IgnoreDifferences, resourceOverrides, compareOptions.IgnoreAggregatedRoles, m.ignoreNormalizerOpts).
WithTracking(appLabelKey, string(trackingMethod))
if useDiffCache {
@@ -880,7 +915,16 @@ func useDiffCache(noCache bool, manifestInfos []*apiclient.ManifestResponse, sou
return true
}
func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, revisions []string, sources []v1alpha1.ApplicationSource, hasMultipleSources bool, startedAt metav1.Time) error {
func (m *appStateManager) persistRevisionHistory(
app *v1alpha1.Application,
revision string,
source v1alpha1.ApplicationSource,
revisions []string,
sources []v1alpha1.ApplicationSource,
hasMultipleSources bool,
startedAt metav1.Time,
initiatedBy v1alpha1.OperationInitiator,
) error {
var nextID int64
if len(app.Status.History) > 0 {
nextID = app.Status.History.LastRevisionHistory().ID + 1
@@ -893,6 +937,7 @@ func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revi
ID: nextID,
Sources: sources,
Revisions: revisions,
InitiatedBy: initiatedBy,
})
} else {
app.Status.History = append(app.Status.History, v1alpha1.RevisionHistory{
@@ -901,6 +946,7 @@ func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revi
DeployStartedAt: &startedAt,
ID: nextID,
Source: source,
InitiatedBy: initiatedBy,
})
}
@@ -935,6 +981,7 @@ func NewAppStateManager(
persistResourceHealth bool,
repoErrorGracePeriod time.Duration,
serverSideDiff bool,
ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts,
) AppStateManager {
return &appStateManager{
liveStateCache: liveStateCache,
@@ -952,6 +999,7 @@ func NewAppStateManager(
persistResourceHealth: persistResourceHealth,
repoErrorGracePeriod: repoErrorGracePeriod,
serverSideDiff: serverSideDiff,
ignoreNormalizerOpts: ignoreNormalizerOpts,
}
}

View File

@@ -23,8 +23,11 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/controller/testdata"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
mockrepoclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient/mocks"
"github.com/argoproj/argo-cd/v2/test"
"github.com/argoproj/argo-cd/v2/util/argo"
)
@@ -649,6 +652,37 @@ var defaultProj = argoappv1.AppProject{
},
}
// TestCompareAppStateWithManifestGeneratePath tests that it compares revisions when the manifest-generate-path annotation is set.
func TestCompareAppStateWithManifestGeneratePath(t *testing.T) {
app := newFakeApp()
app.SetAnnotations(map[string]string{argoappv1.AnnotationKeyManifestGeneratePaths: "."})
app.Status.Sync = argoappv1.SyncStatus{
Revision: "abc123",
Status: argoappv1.SyncStatusCodeSynced,
}
data := fakeData{
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{},
Namespace: test.FakeDestNamespace,
Server: test.FakeClusterURL,
Revision: "abc123",
},
updateRevisionForPathsResponse: &apiclient.UpdateRevisionForPathsResponse{},
}
ctrl := newFakeController(&data, nil)
revisions := make([]string, 0)
revisions = append(revisions, "abc123")
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, false)
assert.Nil(t, err)
assert.NotNil(t, compRes)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
assert.Equal(t, "abc123", compRes.syncStatus.Revision)
ctrl.repoClientset.(*mockrepoclient.Clientset).RepoServerServiceClient.(*mockrepoclient.RepoServerServiceClient).AssertNumberOfCalls(t, "UpdateRevisionForPaths", 1)
}
func TestSetHealth(t *testing.T) {
app := newFakeApp()
deployment := kube.MustToUnstructured(&v1.Deployment{
@@ -838,7 +872,7 @@ func Test_appStateManager_persistRevisionHistory(t *testing.T) {
app.Spec.RevisionHistoryLimit = &i
}
addHistory := func() {
err := manager.persistRevisionHistory(app, "my-revision", argoappv1.ApplicationSource{}, []string{}, []argoappv1.ApplicationSource{}, false, metav1.Time{})
err := manager.persistRevisionHistory(app, "my-revision", argoappv1.ApplicationSource{}, []string{}, []argoappv1.ApplicationSource{}, false, metav1.Time{}, v1alpha1.OperationInitiator{})
assert.NoError(t, err)
}
addHistory()
@@ -874,7 +908,7 @@ func Test_appStateManager_persistRevisionHistory(t *testing.T) {
assert.Len(t, app.Status.History, 9)
metav1NowTime := metav1.NewTime(time.Now())
err := manager.persistRevisionHistory(app, "my-revision", argoappv1.ApplicationSource{}, []string{}, []argoappv1.ApplicationSource{}, false, metav1NowTime)
err := manager.persistRevisionHistory(app, "my-revision", argoappv1.ApplicationSource{}, []string{}, []argoappv1.ApplicationSource{}, false, metav1NowTime, v1alpha1.OperationInitiator{})
assert.NoError(t, err)
assert.Equal(t, app.Status.History.LastRevisionHistory().DeployStartedAt, &metav1NowTime)
}
@@ -1508,6 +1542,17 @@ func TestUseDiffCache(t *testing.T) {
expectedUseCache: true,
serverSideDiff: false,
},
{
testName: "will use diff cache with sync policy",
noCache: false,
manifestInfos: manifestInfos("rev1"),
sources: sources(),
app: test.YamlToApplication(testdata.DiffCacheYaml),
manifestRevisions: []string{"rev1"},
statusRefreshTimeout: time.Hour * 24,
expectedUseCache: true,
serverSideDiff: true,
},
{
testName: "will use diff cache for multisource",
noCache: false,

View File

@@ -2,7 +2,6 @@ package controller
import (
"context"
"encoding/json"
goerrors "errors"
"fmt"
"os"
@@ -11,6 +10,7 @@ import (
"time"
cdcommon "github.com/argoproj/argo-cd/v2/common"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"github.com/argoproj/gitops-engine/pkg/sync"
"github.com/argoproj/gitops-engine/pkg/sync/common"
@@ -21,6 +21,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/managedfields"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/kubectl/pkg/util/openapi"
"github.com/argoproj/argo-cd/v2/controller/metrics"
@@ -103,7 +104,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
if syncOp.SyncOptions.HasOption("FailOnSharedResource=true") &&
hasSharedResource {
state.Phase = common.OperationFailed
state.Message = fmt.Sprintf("Shared resouce found: %s", sharedResourceMessage)
state.Message = fmt.Sprintf("Shared resource found: %s", sharedResourceMessage)
return
}
@@ -161,6 +162,12 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
state.Phase = common.OperationError
state.Message = fmt.Sprintf("Failed to load application project: %v", err)
return
} else if syncWindowPreventsSync(app, proj) {
// If the operation is currently running, simply let the user know the sync is blocked by a current sync window
if state.Phase == common.OperationRunning {
state.Message = "Sync operation blocked by sync window"
}
return
}
if app.Spec.HasMultipleSources() {
@@ -391,7 +398,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
logEntry.WithField("duration", time.Since(start)).Info("sync/terminate complete")
if !syncOp.DryRun && len(syncOp.Resources) == 0 && state.Phase.Successful() {
err := m.persistRevisionHistory(app, compareResult.syncStatus.Revision, source, compareResult.syncStatus.Revisions, compareResult.syncStatus.ComparedTo.Sources, app.Spec.HasMultipleSources(), state.StartedAt)
err := m.persistRevisionHistory(app, compareResult.syncStatus.Revision, source, compareResult.syncStatus.Revisions, compareResult.syncStatus.ComparedTo.Sources, app.Spec.HasMultipleSources(), state.StartedAt, state.Operation.InitiatedBy)
if err != nil {
state.Phase = common.OperationError
state.Message = fmt.Sprintf("failed to record sync to history: %v", err)
@@ -399,11 +406,10 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
}
}
// normalizeTargetResources will apply the diff normalization in all live and target resources.
// Then it calculates the merge patch between the normalized live and the current live resources.
// Finally it applies the merge patch in the normalized target resources. This is done to ensure
// that target resources have the same ignored diff fields values from live ones to avoid them to
// be applied in the cluster. Returns the list of normalized target resources.
// normalizeTargetResources modifies target resources to ensure ignored fields are not touched during synchronization:
// - applies normalization to the target resources based on the live resources
// - copies ignored fields from the matching live resources: apply normalizer to the live resource,
// calculates the patch performed by normalizer and applies the patch to the target resource
func normalizeTargetResources(cr *comparisonResult) ([]*unstructured.Unstructured, error) {
// normalize live and target resources
normalized, err := diff.Normalize(cr.reconciliationResult.Live, cr.reconciliationResult.Target, cr.diffConfig)
@@ -422,94 +428,35 @@ func normalizeTargetResources(cr *comparisonResult) ([]*unstructured.Unstructure
patchedTargets = append(patchedTargets, originalTarget)
continue
}
// calculate targetPatch between normalized and target resource
targetPatch, err := getMergePatch(normalizedTarget, originalTarget)
var lookupPatchMeta *strategicpatch.PatchMetaFromStruct
versionedObject, err := scheme.Scheme.New(normalizedTarget.GroupVersionKind())
if err == nil {
meta, err := strategicpatch.NewPatchMetaFromStruct(versionedObject)
if err != nil {
return nil, err
}
lookupPatchMeta = &meta
}
livePatch, err := getMergePatch(normalized.Lives[idx], live, lookupPatchMeta)
if err != nil {
return nil, err
}
// check if there is a patch to apply. An empty patch is identified by a '{}' string.
if len(targetPatch) > 2 {
livePatch, err := getMergePatch(normalized.Lives[idx], live)
if err != nil {
return nil, err
}
// generate a minimal patch that uses the fields from targetPatch (template)
// with livePatch values
patch, err := compilePatch(targetPatch, livePatch)
if err != nil {
return nil, err
}
normalizedTarget, err = applyMergePatch(normalizedTarget, patch)
if err != nil {
return nil, err
}
} else {
// if there is no patch just use the original target
normalizedTarget = originalTarget
normalizedTarget, err = applyMergePatch(normalizedTarget, livePatch, versionedObject)
if err != nil {
return nil, err
}
patchedTargets = append(patchedTargets, normalizedTarget)
}
return patchedTargets, nil
}
// compilePatch will generate a patch using the fields from templatePatch with
// the values from valuePatch.
func compilePatch(templatePatch, valuePatch []byte) ([]byte, error) {
templateMap := make(map[string]interface{})
err := json.Unmarshal(templatePatch, &templateMap)
if err != nil {
return nil, err
}
valueMap := make(map[string]interface{})
err = json.Unmarshal(valuePatch, &valueMap)
if err != nil {
return nil, err
}
resultMap := intersectMap(templateMap, valueMap)
return json.Marshal(resultMap)
}
// intersectMap will return map with the fields intersection from the 2 provided
// maps populated with the valueMap values.
func intersectMap(templateMap, valueMap map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{})
for k, v := range templateMap {
if innerTMap, ok := v.(map[string]interface{}); ok {
if innerVMap, ok := valueMap[k].(map[string]interface{}); ok {
result[k] = intersectMap(innerTMap, innerVMap)
}
} else if innerTSlice, ok := v.([]interface{}); ok {
if innerVSlice, ok := valueMap[k].([]interface{}); ok {
items := []interface{}{}
for idx, innerTSliceValue := range innerTSlice {
if idx < len(innerVSlice) {
if tSliceValueMap, ok := innerTSliceValue.(map[string]interface{}); ok {
if vSliceValueMap, ok := innerVSlice[idx].(map[string]interface{}); ok {
item := intersectMap(tSliceValueMap, vSliceValueMap)
items = append(items, item)
}
} else {
items = append(items, innerVSlice[idx])
}
}
}
if len(items) > 0 {
result[k] = items
}
}
} else {
if _, ok := valueMap[k]; ok {
result[k] = valueMap[k]
}
}
}
return result
}
// getMergePatch calculates and returns the patch between the original and the
// modified unstructures.
func getMergePatch(original, modified *unstructured.Unstructured) ([]byte, error) {
func getMergePatch(original, modified *unstructured.Unstructured, lookupPatchMeta *strategicpatch.PatchMetaFromStruct) ([]byte, error) {
originalJSON, err := original.MarshalJSON()
if err != nil {
return nil, err
@@ -518,20 +465,30 @@ func getMergePatch(original, modified *unstructured.Unstructured) ([]byte, error
if err != nil {
return nil, err
}
if lookupPatchMeta != nil {
return strategicpatch.CreateThreeWayMergePatch(modifiedJSON, modifiedJSON, originalJSON, lookupPatchMeta, true)
}
return jsonpatch.CreateMergePatch(originalJSON, modifiedJSON)
}
// applyMergePatch will apply the given patch in the obj and return the patched
// unstructure.
func applyMergePatch(obj *unstructured.Unstructured, patch []byte) (*unstructured.Unstructured, error) {
func applyMergePatch(obj *unstructured.Unstructured, patch []byte, versionedObject interface{}) (*unstructured.Unstructured, error) {
originalJSON, err := obj.MarshalJSON()
if err != nil {
return nil, err
}
patchedJSON, err := jsonpatch.MergePatch(originalJSON, patch)
var patchedJSON []byte
if versionedObject == nil {
patchedJSON, err = jsonpatch.MergePatch(originalJSON, patch)
} else {
patchedJSON, err = strategicpatch.StrategicMergePatch(originalJSON, patch, versionedObject)
}
if err != nil {
return nil, err
}
patchedObj := &unstructured.Unstructured{}
_, _, err = unstructured.UnstructuredJSONScheme.Decode(patchedJSON, nil, patchedObj)
if err != nil {
@@ -573,3 +530,12 @@ func delayBetweenSyncWaves(phase common.SyncPhase, wave int, finalWave bool) err
}
return nil
}
func syncWindowPreventsSync(app *v1alpha1.Application, proj *v1alpha1.AppProject) bool {
window := proj.Spec.SyncWindows.Matches(app)
isManual := false
if app.Status.OperationState != nil {
isManual = !app.Status.OperationState.Operation.InitiatedBy.Automated
}
return !window.CanSync(isManual)
}

View File

@@ -18,6 +18,7 @@ import (
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/test"
"github.com/argoproj/argo-cd/v2/util/argo/diff"
"github.com/argoproj/argo-cd/v2/util/argo/normalizers"
)
func TestPersistRevisionHistory(t *testing.T) {
@@ -254,6 +255,75 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
})
}
func TestSyncWindowDeniesSync(t *testing.T) {
type fixture struct {
project *v1alpha1.AppProject
application *v1alpha1.Application
controller *ApplicationController
}
setup := func() *fixture {
app := newFakeApp()
app.Status.OperationState = nil
app.Status.History = nil
project := &v1alpha1.AppProject{
ObjectMeta: v1.ObjectMeta{
Namespace: test.FakeArgoCDNamespace,
Name: "default",
},
Spec: v1alpha1.AppProjectSpec{
SyncWindows: v1alpha1.SyncWindows{{
Kind: "deny",
Schedule: "0 0 * * *",
Duration: "24h",
Clusters: []string{"*"},
Namespaces: []string{"*"},
Applications: []string{"*"},
}},
},
}
data := fakeData{
apps: []runtime.Object{app, project},
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{},
Namespace: test.FakeDestNamespace,
Server: test.FakeClusterURL,
Revision: "abc123",
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
return &fixture{
project: project,
application: app,
controller: ctrl,
}
}
t.Run("will keep the sync progressing if a sync window prevents the sync", func(t *testing.T) {
// given a project with an active deny sync window and an operation in progress
t.Parallel()
f := setup()
opMessage := "Sync operation blocked by sync window"
opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{
Sync: &v1alpha1.SyncOperation{
Source: &v1alpha1.ApplicationSource{},
}},
Phase: common.OperationRunning,
}
// when
f.controller.appStateManager.SyncAppState(f.application, opState)
//then
assert.Equal(t, common.OperationRunning, opState.Phase)
assert.Contains(t, opState.Message, opMessage)
})
}
func TestNormalizeTargetResources(t *testing.T) {
type fixture struct {
comparisonResult *comparisonResult
@@ -261,7 +331,7 @@ func TestNormalizeTargetResources(t *testing.T) {
setup := func(t *testing.T, ignores []v1alpha1.ResourceIgnoreDifferences) *fixture {
t.Helper()
dc, err := diff.NewDiffConfigBuilder().
WithDiffSettings(ignores, nil, true).
WithDiffSettings(ignores, nil, true, normalizers.IgnoreNormalizerOpts{}).
WithNoCache().
Build()
require.NoError(t, err)
@@ -386,3 +456,207 @@ func TestNormalizeTargetResources(t *testing.T) {
assert.Equal(t, 2, len(containers))
})
}
func TestNormalizeTargetResourcesWithList(t *testing.T) {
type fixture struct {
comparisonResult *comparisonResult
}
setupHttpProxy := func(t *testing.T, ignores []v1alpha1.ResourceIgnoreDifferences) *fixture {
t.Helper()
dc, err := diff.NewDiffConfigBuilder().
WithDiffSettings(ignores, nil, true, normalizers.IgnoreNormalizerOpts{}).
WithNoCache().
Build()
require.NoError(t, err)
live := test.YamlToUnstructured(testdata.LiveHTTPProxy)
target := test.YamlToUnstructured(testdata.TargetHTTPProxy)
return &fixture{
&comparisonResult{
reconciliationResult: sync.ReconciliationResult{
Live: []*unstructured.Unstructured{live},
Target: []*unstructured.Unstructured{target},
},
diffConfig: dc,
},
}
}
t.Run("will properly ignore nested fields within arrays", func(t *testing.T) {
// given
ignores := []v1alpha1.ResourceIgnoreDifferences{
{
Group: "projectcontour.io",
Kind: "HTTPProxy",
JQPathExpressions: []string{".spec.routes[]"},
//JSONPointers: []string{"/spec/routes"},
},
}
f := setupHttpProxy(t, ignores)
target := test.YamlToUnstructured(testdata.TargetHTTPProxy)
f.comparisonResult.reconciliationResult.Target = []*unstructured.Unstructured{target}
// when
patchedTargets, err := normalizeTargetResources(f.comparisonResult)
// then
require.NoError(t, err)
require.Equal(t, 1, len(f.comparisonResult.reconciliationResult.Live))
require.Equal(t, 1, len(f.comparisonResult.reconciliationResult.Target))
require.Equal(t, 1, len(patchedTargets))
// live should have 1 entry
require.Equal(t, 1, len(dig[[]any](f.comparisonResult.reconciliationResult.Live[0].Object, []interface{}{"spec", "routes", 0, "rateLimitPolicy", "global", "descriptors"})))
// assert some arbitrary field to show `entries[0]` is not an empty object
require.Equal(t, "sample-header", dig[string](f.comparisonResult.reconciliationResult.Live[0].Object, []interface{}{"spec", "routes", 0, "rateLimitPolicy", "global", "descriptors", 0, "entries", 0, "requestHeader", "headerName"}))
// target has 2 entries
require.Equal(t, 2, len(dig[[]any](f.comparisonResult.reconciliationResult.Target[0].Object, []interface{}{"spec", "routes", 0, "rateLimitPolicy", "global", "descriptors", 0, "entries"})))
// assert some arbitrary field to show `entries[0]` is not an empty object
require.Equal(t, "sample-header", dig[string](f.comparisonResult.reconciliationResult.Target[0].Object, []interface{}{"spec", "routes", 0, "rateLimitPolicy", "global", "descriptors", 0, "entries", 0, "requestHeaderValueMatch", "headers", 0, "name"}))
// It should be *1* entries in the array
require.Equal(t, 1, len(dig[[]any](patchedTargets[0].Object, []interface{}{"spec", "routes", 0, "rateLimitPolicy", "global", "descriptors"})))
// and it should NOT equal an empty object
require.Len(t, dig[any](patchedTargets[0].Object, []interface{}{"spec", "routes", 0, "rateLimitPolicy", "global", "descriptors", 0, "entries", 0}), 1)
})
t.Run("will correctly set array entries if new entries have been added", func(t *testing.T) {
// given
ignores := []v1alpha1.ResourceIgnoreDifferences{
{
Group: "apps",
Kind: "Deployment",
JQPathExpressions: []string{".spec.template.spec.containers[].env[] | select(.name == \"SOME_ENV_VAR\")"},
},
}
f := setupHttpProxy(t, ignores)
live := test.YamlToUnstructured(testdata.LiveDeploymentEnvVarsYaml)
target := test.YamlToUnstructured(testdata.TargetDeploymentEnvVarsYaml)
f.comparisonResult.reconciliationResult.Live = []*unstructured.Unstructured{live}
f.comparisonResult.reconciliationResult.Target = []*unstructured.Unstructured{target}
// when
targets, err := normalizeTargetResources(f.comparisonResult)
// then
require.NoError(t, err)
require.Equal(t, 1, len(targets))
containers, ok, err := unstructured.NestedSlice(targets[0].Object, "spec", "template", "spec", "containers")
require.NoError(t, err)
require.True(t, ok)
assert.Equal(t, 1, len(containers))
ports := containers[0].(map[string]interface{})["ports"].([]interface{})
assert.Equal(t, 1, len(ports))
env := containers[0].(map[string]interface{})["env"].([]interface{})
assert.Equal(t, 3, len(env))
first := env[0]
second := env[1]
third := env[2]
// Currently the defined order at this time is the insertion order of the target manifest.
assert.Equal(t, "SOME_ENV_VAR", first.(map[string]interface{})["name"])
assert.Equal(t, "some_value", first.(map[string]interface{})["value"])
assert.Equal(t, "SOME_OTHER_ENV_VAR", second.(map[string]interface{})["name"])
assert.Equal(t, "some_other_value", second.(map[string]interface{})["value"])
assert.Equal(t, "YET_ANOTHER_ENV_VAR", third.(map[string]interface{})["name"])
assert.Equal(t, "yet_another_value", third.(map[string]interface{})["value"])
})
t.Run("ignore-deployment-image-replicas-changes-additive", func(t *testing.T) {
// given
ignores := []v1alpha1.ResourceIgnoreDifferences{
{
Group: "apps",
Kind: "Deployment",
JSONPointers: []string{"/spec/replicas"},
}, {
Group: "apps",
Kind: "Deployment",
JQPathExpressions: []string{".spec.template.spec.containers[].image"},
},
}
f := setupHttpProxy(t, ignores)
live := test.YamlToUnstructured(testdata.MinimalImageReplicaDeploymentYaml)
target := test.YamlToUnstructured(testdata.AdditionalImageReplicaDeploymentYaml)
f.comparisonResult.reconciliationResult.Live = []*unstructured.Unstructured{live}
f.comparisonResult.reconciliationResult.Target = []*unstructured.Unstructured{target}
// when
targets, err := normalizeTargetResources(f.comparisonResult)
// then
require.NoError(t, err)
require.Equal(t, 1, len(targets))
metadata, ok, err := unstructured.NestedMap(targets[0].Object, "metadata")
require.NoError(t, err)
require.True(t, ok)
labels, ok := metadata["labels"].(map[string]interface{})
require.True(t, ok)
assert.Equal(t, 2, len(labels))
assert.Equal(t, "web", labels["appProcess"])
spec, ok, err := unstructured.NestedMap(targets[0].Object, "spec")
require.NoError(t, err)
require.True(t, ok)
assert.Equal(t, int64(1), spec["replicas"])
template, ok := spec["template"].(map[string]interface{})
require.True(t, ok)
tMetadata, ok := template["metadata"].(map[string]interface{})
require.True(t, ok)
tLabels, ok := tMetadata["labels"].(map[string]interface{})
require.True(t, ok)
assert.Equal(t, 2, len(tLabels))
assert.Equal(t, "web", tLabels["appProcess"])
tSpec, ok := template["spec"].(map[string]interface{})
require.True(t, ok)
containers, ok, err := unstructured.NestedSlice(tSpec, "containers")
require.NoError(t, err)
require.True(t, ok)
assert.Equal(t, 1, len(containers))
first := containers[0].(map[string]interface{})
assert.Equal(t, "alpine:3", first["image"])
resources, ok := first["resources"].(map[string]interface{})
require.True(t, ok)
requests, ok := resources["requests"].(map[string]interface{})
require.True(t, ok)
assert.Equal(t, "400m", requests["cpu"])
env, ok, err := unstructured.NestedSlice(first, "env")
require.NoError(t, err)
require.True(t, ok)
assert.Equal(t, 1, len(env))
env0 := env[0].(map[string]interface{})
assert.Equal(t, "EV", env0["name"])
assert.Equal(t, "here", env0["value"])
})
}
func dig[T any](obj interface{}, path []interface{}) T {
i := obj
for _, segment := range path {
switch segment.(type) {
case int:
i = i.([]interface{})[segment.(int)]
case string:
i = i.(map[string]interface{})[segment.(string)]
default:
panic("invalid path for object")
}
}
return i.(T)
}

View File

@@ -0,0 +1,28 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: client
appProcess: web
name: client
spec:
replicas: 2
selector:
matchLabels:
app: client
strategy: {}
template:
metadata:
labels:
app: client
appProcess: web
spec:
containers:
- image: alpine:2
name: alpine
resources:
requests:
cpu: 400m
env:
- name: EV
value: here

View File

@@ -11,4 +11,25 @@ var (
//go:embed target-deployment-new-entries.yaml
TargetDeploymentNewEntries string
//go:embed diff-cache.yaml
DiffCacheYaml string
//go:embed live-httpproxy.yaml
LiveHTTPProxy string
//go:embed target-httpproxy.yaml
TargetHTTPProxy string
//go:embed live-deployment-env-vars.yaml
LiveDeploymentEnvVarsYaml string
//go:embed target-deployment-env-vars.yaml
TargetDeploymentEnvVarsYaml string
//go:embed minimal-image-replicas-deployment.yaml
MinimalImageReplicaDeploymentYaml string
//go:embed additional-image-replicas-deployment.yaml
AdditionalImageReplicaDeploymentYaml string
)

498
controller/testdata/diff-cache.yaml vendored Normal file
View File

@@ -0,0 +1,498 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
argocd-image-updater.argoproj.io/allow-tags: any
argocd-image-updater.argoproj.io/ignore-tags: ""
argocd-image-updater.argoproj.io/image-list-disabled-hack: ""
argocd-image-updater.argoproj.io/update-strategy: semver
argocd-image-updater.argoproj.io/write-back-method: git
argocd-image-updater.argoproj.io/write-back-target: kustomization
argocd-notif-onDeployed.slack-disabled: ""
argocd-notif-onHealthDegraded.slack-disabled: ""
argocd-notif-onSyncFailed.slack-disabled: ""
argocd-notif-onSyncRunning.slack-disabled: ""
argocd-notif-onSyncStatusUnknown.slack-disabled: ""
argocd-notif-onSyncSucceeded.slack-disabled: ""
argocd.argoproj.io/compare-options: ServerSideDiff=true
argocd.argoproj.io/manifest-generate-paths: .;/chart
creationTimestamp: "2024-03-04T21:30:33Z"
finalizers:
- resources-finalizer.argocd.argoproj.io
generation: 263
labels:
cloud_provider: gcp
cluster_name: gke-alpha-01-europe-west1
foo: bar
preview: "true"
project: sre
service_class: alpha
stack: gke-v2
name: velero-test
namespace: argo-cd
ownerReferences:
- apiVersion: argoproj.io/v1alpha1
blockOwnerDeletion: true
controller: true
kind: ApplicationSet
name: velero
uid: 86cdfba4-8697-47b3-8489-71fab7f4a805
resourceVersion: "722811357"
uid: 94978696-4fd4-40b3-a1de-38d9df9e9316
spec:
destination:
name: gke-alpha-01-europe-west1
namespace: test-lla
project: sre
source:
path: instances/test
plugin:
env:
- name: RELEASE_NAME
value: test-lla
- name: CHART_REPOSITORY
value: oci://europe-west1-docker.pkg.dev/platform-89be/charts
- name: CHART_NAME
value: velero
- name: PREVIEW
value: "false"
- name: HELM_VALUES
value: |
global:
app:
cluster_name: gke-alpha-01-europe-west1
service_class: alpha
cloud_provider: gcp
cluster_stack: gke-v2
- name: HELM_ARGS
value: ""
name: cmp-helm-v2
repoURL: https://github.com/mirakl/manifests-velero.git
targetRevision: test-lla
syncPolicy:
retry:
backoff:
duration: 5s
factor: 2
maxDuration: 3m
limit: 10
syncOptions:
- CreateNamespace=true
- ApplyOutOfSyncOnly=true
- RespectIgnoreDifferences=false
- ServerSideApply=true
- Validate=true
status:
controllerNamespace: argo-cd
health:
status: Healthy
history:
- deployStartedAt: "2024-03-04T22:00:05Z"
deployedAt: "2024-03-04T22:00:06Z"
id: 14
revision: ea8759964626a583667a2bfd08f334ec2070040a
source:
path: instances/test
plugin:
env:
- name: RELEASE_NAME
value: test-lla
- name: CHART_REPOSITORY
value: oci://europe-west1-docker.pkg.dev/platform-89be/charts
- name: CHART_NAME
value: velero
- name: PREVIEW
value: "false"
- name: HELM_VALUES
value: |
global:
app:
cluster_name: gke-alpha-01-europe-west1
service_class: alpha
cloud_provider: gcp
cluster_stack: gke-v2
- name: HELM_ARGS
value: ""
name: cmp-helm-v2
repoURL: https://github.com/mirakl/manifests-velero.git
targetRevision: test-lla
- deployStartedAt: "2024-03-04T22:08:29Z"
deployedAt: "2024-03-04T22:08:30Z"
id: 15
revision: ea8759964626a583667a2bfd08f334ec2070040a
source:
path: instances/test
plugin:
env:
- name: RELEASE_NAME
value: test-lla
- name: CHART_REPOSITORY
value: oci://europe-west1-docker.pkg.dev/platform-89be/charts
- name: CHART_NAME
value: velero
- name: PREVIEW
value: "false"
- name: HELM_VALUES
value: |
global:
app:
cluster_name: gke-alpha-01-europe-west1
service_class: alpha
cloud_provider: gcp
cluster_stack: gke-v2
- name: HELM_ARGS
value: ""
name: cmp-helm-v2
repoURL: https://github.com/mirakl/manifests-velero.git
targetRevision: test-lla
- deployStartedAt: "2024-03-04T22:09:16Z"
deployedAt: "2024-03-04T22:09:16Z"
id: 16
revision: ea8759964626a583667a2bfd08f334ec2070040a
source:
path: instances/test
plugin:
env:
- name: RELEASE_NAME
value: test-lla
- name: CHART_REPOSITORY
value: oci://europe-west1-docker.pkg.dev/platform-89be/charts
- name: CHART_NAME
value: velero
- name: PREVIEW
value: "false"
- name: HELM_VALUES
value: |
global:
app:
cluster_name: gke-alpha-01-europe-west1
service_class: alpha
cloud_provider: gcp
cluster_stack: gke-v2
- name: HELM_ARGS
value: ""
name: cmp-helm-v2
repoURL: https://github.com/mirakl/manifests-velero.git
targetRevision: test-lla
- deployStartedAt: "2024-03-04T22:11:41Z"
deployedAt: "2024-03-04T22:11:41Z"
id: 17
revision: ea8759964626a583667a2bfd08f334ec2070040a
source:
path: instances/test
plugin:
env:
- name: RELEASE_NAME
value: test-lla
- name: CHART_REPOSITORY
value: oci://europe-west1-docker.pkg.dev/platform-89be/charts
- name: CHART_NAME
value: velero
- name: PREVIEW
value: "false"
- name: HELM_VALUES
value: |
global:
app:
cluster_name: gke-alpha-01-europe-west1
service_class: alpha
cloud_provider: gcp
cluster_stack: gke-v2
- name: HELM_ARGS
value: ""
name: cmp-helm-v2
repoURL: https://github.com/mirakl/manifests-velero.git
targetRevision: test-lla
- deployStartedAt: "2024-03-04T22:50:55Z"
deployedAt: "2024-03-04T22:50:55Z"
id: 18
revision: ea8759964626a583667a2bfd08f334ec2070040a
source:
path: instances/test
plugin:
env:
- name: RELEASE_NAME
value: test-lla
- name: CHART_REPOSITORY
value: oci://europe-west1-docker.pkg.dev/platform-89be/charts
- name: CHART_NAME
value: velero
- name: PREVIEW
value: "false"
- name: HELM_VALUES
value: |
global:
app:
cluster_name: gke-alpha-01-europe-west1
service_class: alpha
cloud_provider: gcp
cluster_stack: gke-v2
- name: HELM_ARGS
value: ""
name: cmp-helm-v2
repoURL: https://github.com/mirakl/manifests-velero.git
targetRevision: test-lla
- deployStartedAt: "2024-03-04T22:52:56Z"
deployedAt: "2024-03-04T22:52:56Z"
id: 19
revision: ea8759964626a583667a2bfd08f334ec2070040a
source:
path: instances/test
plugin:
env:
- name: RELEASE_NAME
value: test-lla
- name: CHART_REPOSITORY
value: oci://europe-west1-docker.pkg.dev/platform-89be/charts
- name: CHART_NAME
value: velero
- name: PREVIEW
value: "false"
- name: HELM_VALUES
value: |
global:
app:
cluster_name: gke-alpha-01-europe-west1
service_class: alpha
cloud_provider: gcp
cluster_stack: gke-v2
- name: HELM_ARGS
value: ""
name: cmp-helm-v2
repoURL: https://github.com/mirakl/manifests-velero.git
targetRevision: test-lla
- deployStartedAt: "2024-03-04T22:56:15Z"
deployedAt: "2024-03-04T22:56:15Z"
id: 20
revision: ea8759964626a583667a2bfd08f334ec2070040a
source:
path: instances/test
plugin:
env:
- name: RELEASE_NAME
value: test-lla
- name: CHART_REPOSITORY
value: oci://europe-west1-docker.pkg.dev/platform-89be/charts
- name: CHART_NAME
value: velero
- name: PREVIEW
value: "false"
- name: HELM_VALUES
value: |
global:
app:
cluster_name: gke-alpha-01-europe-west1
service_class: alpha
cloud_provider: gcp
cluster_stack: gke-v2
- name: HELM_ARGS
value: ""
name: cmp-helm-v2
repoURL: https://github.com/mirakl/manifests-velero.git
targetRevision: test-lla
- deployStartedAt: "2024-03-05T07:31:56Z"
deployedAt: "2024-03-05T07:31:57Z"
id: 21
revision: ea8759964626a583667a2bfd08f334ec2070040a
source:
path: instances/test
plugin:
env:
- name: RELEASE_NAME
value: test-lla
- name: CHART_REPOSITORY
value: oci://europe-west1-docker.pkg.dev/platform-89be/charts
- name: CHART_NAME
value: velero
- name: PREVIEW
value: "false"
- name: HELM_VALUES
value: |
global:
app:
cluster_name: gke-alpha-01-europe-west1
service_class: alpha
cloud_provider: gcp
cluster_stack: gke-v2
- name: HELM_ARGS
value: ""
name: cmp-helm-v2
repoURL: https://github.com/mirakl/manifests-velero.git
targetRevision: test-lla
- deployStartedAt: "2024-03-05T07:32:44Z"
deployedAt: "2024-03-05T07:32:44Z"
id: 22
revision: ea8759964626a583667a2bfd08f334ec2070040a
source:
path: instances/test
plugin:
env:
- name: RELEASE_NAME
value: test-lla
- name: CHART_REPOSITORY
value: oci://europe-west1-docker.pkg.dev/platform-89be/charts
- name: CHART_NAME
value: velero
- name: PREVIEW
value: "false"
- name: HELM_VALUES
value: |
global:
app:
cluster_name: gke-alpha-01-europe-west1
service_class: alpha
cloud_provider: gcp
cluster_stack: gke-v2
- name: HELM_ARGS
value: ""
name: cmp-helm-v2
repoURL: https://github.com/mirakl/manifests-velero.git
targetRevision: test-lla
- deployStartedAt: "2024-03-05T07:33:03Z"
deployedAt: "2024-03-05T07:33:04Z"
id: 23
revision: ea8759964626a583667a2bfd08f334ec2070040a
source:
path: instances/test
plugin:
env:
- name: RELEASE_NAME
value: test-lla
- name: CHART_REPOSITORY
value: oci://europe-west1-docker.pkg.dev/platform-89be/charts
- name: CHART_NAME
value: velero
- name: PREVIEW
value: "false"
- name: HELM_VALUES
value: |
global:
app:
cluster_name: gke-alpha-01-europe-west1
service_class: alpha
cloud_provider: gcp
cluster_stack: gke-v2
- name: HELM_ARGS
value: ""
name: cmp-helm-v2
repoURL: https://github.com/mirakl/manifests-velero.git
targetRevision: test-lla
operationState:
finishedAt: "2024-03-05T07:33:04Z"
message: successfully synced (all tasks run)
operation:
initiatedBy:
username: laurent.lavaud@mirakl.com
retry:
backoff:
duration: 5s
factor: 2
maxDuration: 3m
limit: 10
sync:
revision: ea8759964626a583667a2bfd08f334ec2070040a
syncOptions:
- ServerSideApply=true
syncStrategy:
hook: {}
phase: Succeeded
startedAt: "2024-03-05T07:33:03Z"
syncResult:
resources:
- group: ""
hookPhase: Running
kind: Service
message: service/test-lla serverside-applied
name: test-lla
namespace: test-lla
status: Synced
syncPhase: Sync
version: v1
- group: apps
hookPhase: Running
kind: Deployment
message: deployment.apps/test-lla serverside-applied
name: test-lla
namespace: test-lla
status: Synced
syncPhase: Sync
version: v1
revision: ea8759964626a583667a2bfd08f334ec2070040a
source:
path: instances/test
plugin:
env:
- name: RELEASE_NAME
value: test-lla
- name: CHART_REPOSITORY
value: oci://europe-west1-docker.pkg.dev/platform-89be/charts
- name: CHART_NAME
value: velero
- name: PREVIEW
value: "false"
- name: HELM_VALUES
value: |
global:
app:
cluster_name: gke-alpha-01-europe-west1
service_class: alpha
cloud_provider: gcp
cluster_stack: gke-v2
- name: HELM_ARGS
value: ""
name: cmp-helm-v2
repoURL: https://github.com/mirakl/manifests-velero.git
targetRevision: test-lla
reconciledAt: "2024-03-05T07:33:04Z"
resources:
- health:
status: Healthy
kind: Service
name: test-lla
namespace: test-lla
status: Synced
version: v1
- group: apps
health:
status: Healthy
kind: Deployment
name: test-lla
namespace: test-lla
status: Synced
version: v1
sourceType: Plugin
summary:
images:
- nginx:latest
sync:
comparedTo:
destination:
name: gke-alpha-01-europe-west1
namespace: test-lla
source:
path: instances/test
plugin:
env:
- name: RELEASE_NAME
value: test-lla
- name: CHART_REPOSITORY
value: oci://europe-west1-docker.pkg.dev/platform-89be/charts
- name: CHART_NAME
value: velero
- name: PREVIEW
value: "false"
- name: HELM_VALUES
value: |
global:
app:
cluster_name: gke-alpha-01-europe-west1
service_class: alpha
cloud_provider: gcp
cluster_stack: gke-v2
- name: HELM_ARGS
value: ""
name: cmp-helm-v2
repoURL: https://github.com/mirakl/manifests-velero.git
targetRevision: test-lla
revision: rev1
status: Synced

View File

@@ -0,0 +1,177 @@
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
argocd.argoproj.io/tracking-id: 'guestbook:apps/Deployment:default/kustomize-guestbook-ui'
deployment.kubernetes.io/revision: '9'
iksm-version: '2.0'
kubectl.kubernetes.io/last-applied-configuration: >
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{"argocd.argoproj.io/tracking-id":"guestbook:apps/Deployment:default/kustomize-guestbook-ui","iksm-version":"2.0"},"name":"kustomize-guestbook-ui","namespace":"default"},"spec":{"replicas":4,"revisionHistoryLimit":3,"selector":{"matchLabels":{"app":"guestbook-ui"}},"template":{"metadata":{"labels":{"app":"guestbook-ui"}},"spec":{"containers":[{"env":[{"name":"SOME_ENV_VAR","value":"some_value"}],"image":"gcr.io/heptio-images/ks-guestbook-demo:0.1","name":"guestbook-ui","ports":[{"containerPort":80}],"resources":{"requests":{"cpu":"50m","memory":"100Mi"}}}]}}}}
creationTimestamp: '2022-01-05T15:45:21Z'
generation: 119
managedFields:
- apiVersion: apps/v1
fieldsType: FieldsV1
fieldsV1:
'f:metadata':
'f:annotations':
'f:iksm-version': {}
manager: janitor
operation: Apply
time: '2022-01-06T18:21:04Z'
- apiVersion: apps/v1
fieldsType: FieldsV1
fieldsV1:
'f:metadata':
'f:annotations':
.: {}
'f:argocd.argoproj.io/tracking-id': {}
'f:kubectl.kubernetes.io/last-applied-configuration': {}
'f:spec':
'f:progressDeadlineSeconds': {}
'f:replicas': {}
'f:revisionHistoryLimit': {}
'f:selector': {}
'f:strategy':
'f:rollingUpdate':
.: {}
'f:maxSurge': {}
'f:maxUnavailable': {}
'f:type': {}
'f:template':
'f:metadata':
'f:labels':
.: {}
'f:app': {}
'f:spec':
'f:containers':
'k:{"name":"guestbook-ui"}':
.: {}
'f:env':
.: {}
'k:{"name":"SOME_ENV_VAR"}':
.: {}
'f:name': {}
'f:value': {}
'f:image': {}
'f:imagePullPolicy': {}
'f:name': {}
'f:ports':
.: {}
'k:{"containerPort":80,"protocol":"TCP"}':
.: {}
'f:containerPort': {}
'f:protocol': {}
'f:resources':
.: {}
'f:requests':
.: {}
'f:cpu': {}
'f:memory': {}
'f:terminationMessagePath': {}
'f:terminationMessagePolicy': {}
'f:dnsPolicy': {}
'f:restartPolicy': {}
'f:schedulerName': {}
'f:securityContext': {}
'f:terminationGracePeriodSeconds': {}
manager: argocd
operation: Update
time: '2022-01-06T15:04:15Z'
- apiVersion: apps/v1
fieldsType: FieldsV1
fieldsV1:
'f:metadata':
'f:annotations':
'f:deployment.kubernetes.io/revision': {}
'f:status':
'f:availableReplicas': {}
'f:conditions':
.: {}
'k:{"type":"Available"}':
.: {}
'f:lastTransitionTime': {}
'f:lastUpdateTime': {}
'f:message': {}
'f:reason': {}
'f:status': {}
'f:type': {}
'k:{"type":"Progressing"}':
.: {}
'f:lastTransitionTime': {}
'f:lastUpdateTime': {}
'f:message': {}
'f:reason': {}
'f:status': {}
'f:type': {}
'f:observedGeneration': {}
'f:readyReplicas': {}
'f:replicas': {}
'f:updatedReplicas': {}
manager: kube-controller-manager
operation: Update
time: '2022-01-06T18:15:14Z'
name: kustomize-guestbook-ui
namespace: default
resourceVersion: '8289211'
uid: ef253575-ce44-4c5e-84ad-16e81d0df6eb
spec:
progressDeadlineSeconds: 600
replicas: 4
revisionHistoryLimit: 3
selector:
matchLabels:
app: guestbook-ui
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: guestbook-ui
spec:
containers:
- env:
- name: SOME_ENV_VAR
value: some_value
image: 'gcr.io/heptio-images/ks-guestbook-demo:0.1'
imagePullPolicy: IfNotPresent
name: guestbook-ui
ports:
- containerPort: 80
protocol: TCP
resources:
requests:
cpu: 50m
memory: 100Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
status:
availableReplicas: 4
conditions:
- lastTransitionTime: '2022-01-05T22:20:37Z'
lastUpdateTime: '2022-01-05T22:43:47Z'
message: >-
ReplicaSet "kustomize-guestbook-ui-6549d54677" has successfully
progressed.
reason: NewReplicaSetAvailable
status: 'True'
type: Progressing
- lastTransitionTime: '2022-01-06T18:15:14Z'
lastUpdateTime: '2022-01-06T18:15:14Z'
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: 'True'
type: Available
observedGeneration: 119
readyReplicas: 4
replicas: 4
updatedReplicas: 4

14
controller/testdata/live-httpproxy.yaml vendored Normal file
View File

@@ -0,0 +1,14 @@
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: my-http-proxy
namespace: default
spec:
routes:
- rateLimitPolicy:
global:
descriptors:
- entries:
- requestHeader:
descriptorKey: sample-key
headerName: sample-header

View File

@@ -0,0 +1,21 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: client
name: client
spec:
replicas: 1
selector:
matchLabels:
app: client
strategy: {}
template:
metadata:
labels:
app: client
spec:
containers:
- image: alpine:3
name: alpine
resources: {}

View File

@@ -0,0 +1,35 @@
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
argocd.argoproj.io/tracking-id: 'guestbook:apps/Deployment:default/kustomize-guestbook-ui'
iksm-version: '1.0'
name: kustomize-guestbook-ui
namespace: default
spec:
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app: guestbook-ui
template:
metadata:
labels:
app: guestbook-ui
spec:
containers:
- env:
- name: SOME_OTHER_ENV_VAR
value: some_other_value
- name: YET_ANOTHER_ENV_VAR
value: yet_another_value
- name: SOME_ENV_VAR
value: different_value!
image: 'gcr.io/heptio-images/ks-guestbook-demo:0.1'
name: guestbook-ui
ports:
- containerPort: 80
resources:
requests:
cpu: 50m
memory: 100Mi

View File

@@ -0,0 +1,23 @@
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: my-http-proxy
namespace: default
spec:
routes:
- rateLimitPolicy:
global:
descriptors:
- entries:
- requestHeaderValueMatch:
headers:
- contains: sample-key
name: sample-header
value: third
- requestHeader:
descriptorKey: sample-key
headerName: sample-header
- entries:
- requestHeader:
descriptorKey: sample-key
headerName: sample-header

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

BIN
docs/assets/okta-app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

View File

@@ -37,6 +37,17 @@ sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
rm argocd-linux-amd64
```
#### Download latest stable version
You can download the latest stable release by executing below steps:
```bash
VERSION=$(curl -L -s https://raw.githubusercontent.com/argoproj/argo-cd/stable/VERSION)
curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/download/v$VERSION/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
rm argocd-linux-amd64
```
You should now be able to run `argocd` commands.

View File

@@ -71,7 +71,7 @@ and the CLI functionalities.
### Application Controller
The Application Controller is responsible for reconciling the
Application resource in Kubernetes syncronizing the desired
Application resource in Kubernetes synchronizing the desired
application state (provided in Git) with the live state (in
Kubernetes). The Application Controller is also responsible for
reconciling the Project resource.

View File

@@ -103,10 +103,12 @@ Design documents are usually submitted as PR and use [this template](https://git
Our community regularly meets virtually to discuss issues, ideas and enhancements around Argo CD. We do invite you to join this virtual meetings if you want to bring up certain things (including your enhancement proposals), participate in our triaging or just want to get to know other contributors.
The current cadence of our meetings is weekly, every Thursday at 4:15pm UTC (8:15am Pacific, 11:15am Eastern, 5:15pm Central European, 9:45pm Indian). We use Zoom to conduct these meetings.
The current cadence of our meetings is weekly, every Thursday at 8:15AM Pacific Time ([click here to check in your current timezone][1]). We use Zoom to conduct these meetings.
* [Agenda document (Google Docs, includes Zoom link)](https://docs.google.com/document/d/1xkoFkVviB70YBzSEa4bDnu-rUZ1sIFtwKKG1Uw8XsY8)
If you want to discuss something, we kindly ask you to put your item on the
[agenda](https://docs.google.com/document/d/1xkoFkVviB70YBzSEa4bDnu-rUZ1sIFtwKKG1Uw8XsY8)
for one of the upcoming meetings so that we can plan in the time for discussing it.
for one of the upcoming meetings so that we can plan in the time for discussing it.
[1]: https://www.timebie.com/std/pacific.php?q=081500

View File

@@ -9,7 +9,9 @@ and the [toolchain guide](toolchain-guide.md).
### Install Go
Install version 1.18 or newer (Verify version by running `go version`)
<https://go.dev/doc/install/>
Install Go with a version equal to or greater than the version listed in `go.mod` (verify go version with `go version`).
### Clone the Argo CD repo
@@ -23,16 +25,29 @@ git clone https://github.com/argoproj/argo-cd.git
<https://docs.docker.com/engine/install/>
### Install or Upgrade `kind` (Optional - Should work with any local cluster)
### Install or Upgrade a Tool for Running Local Clusters (e.g. kind or minikube)
#### Installation guide for kind:
<https://kind.sigs.k8s.io/docs/user/quick-start/>
#### Installation guide for minikube:
<https://minikube.sigs.k8s.io/docs/start/>
### Start Your Local Cluster
For example, if you are using kind:
```shell
kind create cluster
```
Or, if you are using minikube:
```shell
minikube start
```
### Install Argo CD
```shell

View File

@@ -15,7 +15,7 @@ requests before forwarding to the backend service.
As proxy extension is in [Alpha][1] phase, the feature is disabled by
default. To enable it, it is necessary to configure the feature flag
in Argo CD command parameters. The easiest way to to properly enable
in Argo CD command parameters. The easiest way to properly enable
this feature flag is by adding the `server.enable.proxy.extension` key
in the existing `argocd-cmd-params-cm`. For example:

View File

@@ -13,7 +13,7 @@ These are the upcoming releases dates:
| v2.8 | Monday, Jun. 26, 2023 | Monday, Aug. 7, 2023 | [Keith Chong](https://github.com/keithchong) | [Keith Chong](https://github.com/keithchong) | [checklist](https://github.com/argoproj/argo-cd/issues/13742) |
| v2.9 | Monday, Sep. 18, 2023 | Monday, Nov. 6, 2023 | [Leonardo Almeida](https://github.com/leoluz) | [Leonardo Almeida](https://github.com/leoluz) | [checklist](https://github.com/argoproj/argo-cd/issues/14078) |
| v2.10 | Monday, Dec. 18, 2023 | Monday, Feb. 5, 2024 | [Katie Lamkin](https://github.com/kmlamkin9) | | [checklist](https://github.com/argoproj/argo-cd/issues/16339) |
| v2.11 | Monday, Mar. 18, 2024 | Monday, May 6, 2024 |
| v2.11 | Friday, Apr. 5, 2024 | Monday, May 6, 2024 | [Pavel Kostohrys](https://github.com/pasha-codefresh) | [Pavel Kostohrys](https://github.com/pasha-codefresh) | [checklist](https://github.com/argoproj/argo-cd/issues/17726) |
| v2.12 | Monday, Jun. 17, 2024 | Monday, Aug. 5, 2024 |
Actual release dates might differ from the plan by a few days.
@@ -71,7 +71,7 @@ that minor release. It will have to wait for the next minor release.
### Security Patch Policy
CVEs in Argo CD code will be patched for all [supported versions](../operator-manual/installation.md#supported-versions).
CVEs in Argo CD code will be patched for all supported versions. Read more about supported versions in the [security policy for Argo CD](https://github.com/argoproj/argo-cd/security/policy#supported-versions).
### Dependencies Lifecycle Policy

View File

@@ -2,20 +2,19 @@
## Developing And Testing
The website is built using `mkdocs` and `mkdocs-material`.
The website is built using `mkdocs` and `mkdocs-material`.
To test:
```bash
make serve-docs
```
Once running, you can view your locally built documentation at [http://0.0.0.0:8000/](http://0.0.0.0:8000/).
Make a change to documentation and the website will rebuild and refresh the view.
Once running, you can view your locally built documentation at [http://0.0.0.0:8000/](http://0.0.0.0:8000/).
## Deploying
Before submitting a PR build the website, to verify that there are no errors building the site
```bash
make publish-docs
make build-docs
```
## Analytics
@@ -23,4 +22,4 @@ make publish-docs
!!! tip
Don't forget to disable your ad-blocker when testing.
We collect [Google Analytics](https://analytics.google.com/analytics/web/#/report-home/a105170809w198079555p192782995).
We collect [Google Analytics](https://analytics.google.com/analytics/web/#/report-home/a105170809w198079555p192782995).

View File

@@ -138,6 +138,14 @@ The following steps are required no matter whether you chose to use a virtualize
export SUDO=sudo
```
If you have podman installed, you can also leverage its rootless mode. In
order to use podman for running and testing Argo CD locally, set the
`DOCKER` environment variable to `podman` before you run `make`, e.g.
```
DOCKER=podman make start
```
### Clone the Argo CD repository from your personal fork on GitHub
* `mkdir -p ~/go/src/github.com/argoproj`
@@ -304,7 +312,7 @@ For installing the tools required to build and test Argo CD on your local system
You can change the target location by setting the `BIN` environment before running the installer scripts. For example, you can install the binaries into `~/go/bin` (which should then be the first component in your `PATH` environment, i.e. `export PATH=~/go/bin:$PATH`):
```shell
make BIN=~/go/bin install-tools-local
BIN=~/go/bin make install-tools-local
```
Additionally, you have to install at least the following tools via your OS's package manager (this list might not be always up-to-date):

View File

@@ -36,7 +36,7 @@ which might cause health check to return `Progressing` state instead of `Healthy
As workaround Argo CD allows providing [health check](operator-manual/health.md) customization which overrides default
behavior.
If you are using Traefik for your Ingress, you can update the Traefik config to publish the loadBalancer IP using [publishedservice](https://doc.traefik.io/traefik/providers/kubernetes-ingress/#publishedservice), which will resolve this issue.
If you are using Traefik for your Ingress, you can update the Traefik config to publish the loadBalancer IP using [publishedservice](https://doc.traefik.io/traefik/providers/kubernetes-ingress/#publishedservice), which will resolve this issue.
```yaml
providers:
@@ -97,7 +97,7 @@ data:
## After deploying my Helm application with Argo CD I cannot see it with `helm ls` and other Helm commands
When deploying a Helm application Argo CD is using Helm
When deploying a Helm application Argo CD is using Helm
only as a template mechanism. It runs `helm template` and
then deploys the resulting manifests on the cluster instead of doing `helm install`. This means that you cannot use any Helm command
to view/verify the application. It is fully managed by Argo CD.
@@ -140,15 +140,15 @@ Argo CD automatically sets the `app.kubernetes.io/instance` label and uses it to
If the tool does this too, this causes confusion. You can change this label by setting
the `application.instanceLabelKey` value in the `argocd-cm`. We recommend that you use `argocd.argoproj.io/instance`.
!!! note
!!! note
When you make this change your applications will become out of sync and will need re-syncing.
See [#1482](https://github.com/argoproj/argo-cd/issues/1482).
## How often does Argo CD check for changes to my Git or Helm repository ?
The default polling interval is 3 minutes (180 seconds).
You can change the setting by updating the `timeout.reconciliation` value in the [argocd-cm](https://github.com/argoproj/argo-cd/blob/2d6ce088acd4fb29271ffb6f6023dbb27594d59b/docs/operator-manual/argocd-cm.yaml#L279-L282) config map. If there are any Git changes, Argo CD will only update applications with the [auto-sync setting](user-guide/auto_sync.md) enabled. If you set it to `0` then Argo CD will stop polling Git repositories automatically and you can only use alternative methods such as [webhooks](operator-manual/webhook.md) and/or manual syncs for deploying applications.
The default polling interval is 3 minutes (180 seconds) with a configurable jitter.
You can change the setting by updating the `timeout.reconciliation` value and the `timeout.reconciliation.jitter` in the [argocd-cm](https://github.com/argoproj/argo-cd/blob/2d6ce088acd4fb29271ffb6f6023dbb27594d59b/docs/operator-manual/argocd-cm.yaml#L279-L282) config map. If there are any Git changes, Argo CD will only update applications with the [auto-sync setting](user-guide/auto_sync.md) enabled. If you set it to `0` then Argo CD will stop polling Git repositories automatically and you can only use alternative methods such as [webhooks](operator-manual/webhook.md) and/or manual syncs for deploying applications.
## Why Are My Resource Limits `Out Of Sync`?
@@ -250,7 +250,7 @@ There are two parts to the message:
> map[name:**KEY_BC** value:150] map[name:**KEY_BC** value:500] map[name:**KEY_BD** value:250] map[name:**KEY_BD** value:500] map[name:KEY_BI value:something]
You'll want to identify the keys that are duplicated -- you can focus on the first part, as each duplicated key will appear, once for each of its value with its value in the first list. The second list is really just
You'll want to identify the keys that are duplicated -- you can focus on the first part, as each duplicated key will appear, once for each of its value with its value in the first list. The second list is really just
`]`
@@ -259,7 +259,7 @@ There are two parts to the message:
This includes all of the keys. It's included for debugging purposes -- you don't need to pay much attention to it. It will give you a hint about the precise location in the list for the duplicated keys:
> map[name:KEY_AA] map[name:KEY_AB] map[name:KEY_AC] map[name:KEY_AD] map[name:KEY_AE] map[name:KEY_AF] map[name:KEY_AG] map[name:KEY_AH] map[name:KEY_AI] map[name:KEY_AJ] map[name:KEY_AK] map[name:KEY_AL] map[name:KEY_AM] map[name:KEY_AN] map[name:KEY_AO] map[name:KEY_AP] map[name:KEY_AQ] map[name:KEY_AR] map[name:KEY_AS] map[name:KEY_AT] map[name:KEY_AU] map[name:KEY_AV] map[name:KEY_AW] map[name:KEY_AX] map[name:KEY_AY] map[name:KEY_AZ] map[name:KEY_BA] map[name:KEY_BB] map[name:**KEY_BC**] map[name:**KEY_BD**] map[name:KEY_BE] map[name:KEY_BF] map[name:KEY_BG] map[name:KEY_BH] map[name:KEY_BI] map[name:**KEY_BC**] map[name:**KEY_BD**]
`]`
In this case, the duplicated keys have been **emphasized** to help you identify the problematic keys. Many editors have the ability to highlight all instances of a string, using such an editor can help with such problems.
@@ -268,3 +268,45 @@ The most common instance of this error is with `env:` fields for `containers`.
!!! note "Dynamic applications"
It's possible that your application is being generated by a tool in which case the duplication might not be evident within the scope of a single file. If you have trouble debugging this problem, consider filing a ticket to the owner of the generator tool asking them to improve its validation and error reporting.
## How to rotate Redis secret?
* Delete `argocd-redis` secret in the namespace where Argo CD is installed.
```bash
kubectl delete secret argocd-redis -n <argocd namesapce>
```
* If you are running Redis in HA mode, restart Redis in HA.
```bash
kubectl rollout restart deployment argocd-redis-ha-haproxy
kubectl rollout restart statefulset argocd-redis-ha-server
```
* If you are running Redis in non-HA mode, restart Redis.
```bash
kubectl rollout restart deployment argocd-redis
```
* Restart other components.
```bash
kubectl rollout restart deployment argocd-server argocd-repo-server
kubectl rollout restart statefulset argocd-application-controller
```
## How to turn off Redis auth if users really want to?
Argo CD default installation is now configured automatically enable Redis authentication.
If for some reason authenticated Redis does not work for you and you want to use non-authenticated Redis, here are the steps:
* You need to have your own Redis installation.
* Configure Argo CD to use your own Redis instance. See this [doc](https://argo-cd.readthedocs.io/en/stable/operator-manual/argocd-cmd-params-cm-yaml/) for the Argo CD configuration.
* If you already installed Redis shipped with Argo CD, you also need to clean up the existing components:
* When HA Redis is used:
* kubectl delete deployment argocd-redis-ha-haproxy
* kubectl delete statefulset argocd-redis-ha-server
* When non-HA Redis is used:
* kubectl delete deployment argocd-redis
* Remove environment variable `REDIS_PASSWORD` from the following manifests
* Deployment: argocd-repo-server:
* Deployment: argocd-server
* StatefulSet: argocd-application-controller
## How do I provide my own Redis credentials?
The Redis password is stored in Kubernetes secret `argocd-redis` with key `auth` in the namespace where Argo CD is installed.
You can config your secret provider to generate Kubernetes secret accordingly.

View File

@@ -22,12 +22,8 @@ This will create a new namespace, `argocd`, where Argo CD services and applicati
The installation manifests include `ClusterRoleBinding` resources that reference `argocd` namespace. If you are installing Argo CD into a different
namespace then make sure to update the namespace reference.
If you are not interested in UI, SSO, multi-cluster features then you can install [core](operator-manual/installation.md#core) Argo CD components only:
```bash
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/core-install.yaml
```
!!! tip
If you are not interested in UI, SSO, and multi-cluster features, then you can install only the [core](operator-manual/core/#installing) Argo CD components.
This default installation will have a self-signed certificate and cannot be accessed without a bit of extra work.
Do one of:
@@ -36,8 +32,17 @@ Do one of:
* Configure the client OS to trust the self signed certificate.
* Use the --insecure flag on all Argo CD CLI operations in this guide.
!!! note
Default namespace for `kubectl` config must be set to `argocd`.
This is only needed for the following commands since the previous commands have -n argocd already:
`kubectl config set-context --current --namespace=argocd`
Use `argocd login --core` to [configure](./user-guide/commands/argocd_login.md) CLI access and skip steps 3-5.
!!! note
This default installation for Redis is using password authentication. The Redis password is stored in Kubernetes secret `argocd-redis` with key `auth` in the namespace where Argo CD is installed.
## 2. Download Argo CD CLI
Download the latest Argo CD version from [https://github.com/argoproj/argo-cd/releases/latest](https://github.com/argoproj/argo-cd/releases/latest). More detailed installation instructions can be found via the [CLI installation documentation](cli_installation.md).

View File

@@ -1,7 +1,5 @@
# Applications in any namespace
**Current feature state**: Beta
!!! warning
Please read this documentation carefully before you enable this feature. Misconfiguration could lead to potential security issues.
@@ -13,10 +11,6 @@ Argo CD administrators can define a certain set of namespaces where `Application
Some manual steps will need to be performed by the Argo CD administrator in order to enable this feature.
!!! note
This feature is considered beta as of now. Some of the implementation details may change over the course of time until it is promoted to a stable status. We will be happy if early adopters use this feature and provide us with bug reports and feedback.
One additional advantage of adopting applications in any namespace is to allow end-users to configure notifications for their Argo CD application in the namespace where Argo CD application is running in. See notifications [namespace based configuration](notifications/index.md#namespace-based-configuration) page for more information.
## Prerequisites

View File

@@ -119,7 +119,7 @@ spec:
extVars:
- name: foo
value: bar
# You can use "code to determine if the value is either string (false, the default) or Jsonnet code (if code is true).
# You can use "code" to determine if the value is either string (false, the default) or Jsonnet code (if code is true).
- code: true
name: baz
value: "true"

View File

@@ -3,32 +3,217 @@ kind: ApplicationSet
metadata:
name: test-hello-world-appset
namespace: argocd
# To preserve this annotation and label we can use the preservedFields property
preservedFields:
# This annotation and label exists only on this Application, and not in
# the parent ApplicationSet template:
# ignoreApplicationDifferences is the preferred way to accomplish this now.
annotations:
my-custom-annotation: some-value
labels:
my-custom-label: some-value
spec:
# See docs for available generators and their specs.
generators:
- list:
elements:
- cluster: https://kubernetes.default.svc
# Using a generator plugin without combining it with Matrix or Merge
# Plugins allow you to provide your own generator
- plugin:
# Specify the configMap where the plugin configuration is located.
configMapRef:
name: my-plugin
# You can pass arbitrary parameters to the plugin. `input.parameters` is a map, but values may be any type.
# These parameters will also be available on the generator's output under the `generator.input.parameters` key.
input:
parameters:
key1: "value1"
key2: "value2"
list: ["list", "of", "values"]
boolean: true
map:
key1: "value1"
key2: "value2"
key3: "value3"
# You can also attach arbitrary values to the generator's output under the `values` key. These values will be
# available in templates under the `values` key.
values:
value1: something
# When using a Plugin generator, the ApplicationSet controller polls every `requeueAfterSeconds` interval (defaulting to every 30 minutes) to detect changes.
requeueAfterSeconds: 30
# to automatically discover repositories within an organization
- scmProvider:
# Which protocol to clone using.
cloneProtocol: ssh
# The GitHub mode uses the GitHub API to scan an organization in either github.com or GitHub Enterprise
github:
# The GitHub organization to scan.
organization: myorg
# For GitHub Enterprise:
api: https://git.example.com/
# If true, scan every branch of every repository. If false, scan only the default branch. Defaults to false.
allBranches: true
# Reference to a Secret containing an access token. (optional)
tokenRef:
secretName: github-token
key: token
# (optional) use a GitHub App to access the API instead of a PAT.
appSecretName: gh-app-repo-creds
#Pass additional key-value pairs via values field
values:
name: "{{organization}}-{{repository}}"
#The GitLab mode uses the GitLab API to scan and organization in either gitlab.com or self-hosted GitLab.
gitlab:
#The Gitea mode uses the Gitea API to scan organizations in your instance
gitea:
#Use the Bitbucket Server API (1.0) to scan repos in a project.
bitbucketServer:
#Uses the Azure DevOps API to look up eligible repositories
azureDevOps:
# The Bitbucket mode uses the Bitbucket API V2 to scan a workspace in bitbucket.org
bitbucket:
#Uses AWS ResourceGroupsTagging and AWS CodeCommit APIs to scan repos across AWS accounts and regionsz
awsCodeCommit:
#Filters allow selecting which repositories to generate for.
filters:
# Include any repository starting with "myapp" AND including a Kustomize config AND labeled with "deploy-ok" ...
- repositoryMatch: ^myapp
pathsExist: [kubernetes/kustomization.yaml]
labelMatch: deploy-ok
# ... OR include any repository starting with "otherapp" AND a Helm folder and doesn't have file disabledrepo.txt.
- repositoryMatch: ^otherapp
pathsExist: [helm]
pathsDoNotExist: [disabledrepo.txt]
# matrix 'parent' generator
- matrix:
generators:
# any of the top-level generators may be used here instead.
# merge 'parent' generator
# Use the selector set by both child generators to combine them.
- merge:
mergeKeys:
- server
# Note that this would not work with goTemplate enabled,
# nested merge keys are not supported there.
- values.selector
generators:
- clusters:
values:
kafka: 'true'
redis: 'false'
# For clusters with a specific label, enable Kafka.
- clusters:
selector:
matchLabels:
use-kafka: 'false'
values:
kafka: 'false'
# For a specific cluster, enable Redis.
- list:
elements:
- server: https://2.4.6.8
values.redis: 'true'
# Determines whether go templating will be used in the `template` field below.
goTemplate: false
goTemplate: true
# Optional list of go templating options, see https://pkg.go.dev/text/template#Template.Option
# This is only relevant if `goTemplate` is true
goTemplateOptions: ["missingkey="]
goTemplateOptions: ["missingkey=error"]
# These fields are identical to the Application spec.
# The generator's template field takes precedence over the spec's template fields
template:
metadata:
name: test-hello-world-app
spec:
project: my-project
syncPolicy:
automated:
selfHeal: true
syncOptions:
- CreateNamespace=true
# defines from which Git repository to extract the desired Application manifests
source:
- chart: '{{.chart}}'
# developers may customize app details using JSON files from above repo URL
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
# Path within the repository where Kubernetes manifests are located
path: applicationset/examples/list-generator/guestbook/{{cluster}}
helm:
useCredentials: "{{.useCredentials}}" # This field may NOT be templated, because it is a boolean field
parameters:
- name: "image.tag"
value: "pull-{{head_sha}}"
- name: "{{.name}}"
value: "{{.value}}"
- name: throw-away
value: "{{end}}"
destination:
# Only one of name or server may be specified: if both are specified, an error is returned.
# Name of the cluster (within Argo CD) to deploy to
name: production-cluster # cluster is restricted
# API Server URL for the cluster
server: '{{.url}}'
# Target namespace in which to deploy the manifests from source
namespace: dev-team-one # namespace is restricted
# This sync policy pertains to the ApplicationSet, not to the Applications it creates.
syncPolicy:
# Determines whether the controller will delete Applications when an ApplicationSet is deleted.
preserveResourcesOnDeletion: false
# Alpha feature to determine the order in which ApplicationSet applies changes.
# Prevents ApplicationSet controller from modifying or deleting Applications
applicationsSync: create-only
# Prevents ApplicationSet controller from deleting Applications. Update is allowed
# applicationsSync: create-update
# Prevents ApplicationSet controller from modifying Applications. Delete is allowed.
# applicationsSync: create-delete
syncOptions:
- CreateNamespace=true
# Prevent an Application's child resources from being deleted, when the parent Application is deleted
preserveResourcesOnDeletion: true
# which fields of the ApplicationSet should be ignored when comparing Applications.
ignoreApplicationDifferences:
- jsonPointers:
- /spec/source/targetRevision
- name: some-app
jqExpressions:
- .spec.source.helm.values
strategy:
# This field lets you define fields which should be ignored when applying Application resources. This is helpful if you
# want to use ApplicationSets to create apps, but also want to allow users to modify those apps without having their
# changes overwritten by the ApplicationSet.
# This update strategy allows you to group Applications by labels present on the generated Application resources
type: RollingSync
rollingSync:
steps:
# Application groups are selected using their labels and matchExpressions
- matchExpressions:
- key: envLabel
operator: In
values:
- env-dev
# maxUpdate: 100% # if undefined, all applications matched are updated together (default is 100%)
- matchExpressions:
- key: envLabel
operator: In
values:
- env-qa
maxUpdate: 0 # if 0, no matched applications will be synced unless they're synced manually
- 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%)
ignoreApplicationDifferences:
- jsonPointers:
- /spec/source/targetRevision
@@ -36,3 +221,94 @@ spec:
jqPathExpressions:
- .spec.source.helm.values
# Cluster-decision-resource-based ApplicationSet generator
- clusterDecisionResource:
# ConfigMap with GVK information for the duck type resource
configMapRef: my-configmap
name: quak # Choose either "name" of the resource or "labelSelector"
labelSelector:
matchLabels: # OPTIONAL
duck: spotted
matchExpressions: # OPTIONAL
- key: duck
operator: In
values:
- "spotted"
- "canvasback"
# OPTIONAL: Checks for changes every 60sec (default 3min)
requeueAfterSeconds: 60
# The Pull Request generator uses the API of an SCMaaS provider to automatically discover open pull requests within a repository
- pullRequest:
# When using a Pull Request generator, the ApplicationSet controller polls every `requeueAfterSeconds` interval (defaulting to every 30 minutes) to detect changes.
requeueAfterSeconds: 1800
# See below for provider specific options.
# Specify the repository from which to fetch the GitHub Pull requests.
github:
# The GitHub organization or user.
owner: myorg
# The Github repository
repo: myrepository
# For GitHub Enterprise (optional)
api: https://git.example.com/
# Reference to a Secret containing an access token. (optional)
tokenRef:
secretName: github-token
key: token
# (optional) use a GitHub App to access the API instead of a PAT.
appSecretName: github-app-repo-creds
# Labels is used to filter the PRs that you want to target. (optional)
labels:
- preview
# Filters allow selecting which pull requests to generate for
# Include any pull request ending with "argocd". (optional)
filters:
- branchMatch: ".*-argocd"
# Specify the project from which to fetch the GitLab merge requests.
gitlab:
# Specify the repository from which to fetch the Gitea Pull requests.
gitea:
# Fetch pull requests from a repo hosted on a Bitbucket Server (not the same as Bitbucket Cloud).
bitbucketServer:
# Fetch pull requests from a repo hosted on a Bitbucket Cloud.
bitbucket:
# Specify the organization, project and repository from which you want to fetch pull requests.
azuredevops:
# Fetch pull requests from AWS CodeCommit repositories.
awsCodeCommit:
# The list generator generates a set of two application which then filter by the key value to only select the env with value staging
- list:
elements:
- cluster: engineering-dev
url: https://kubernetes.default.svc
env: staging
- cluster: engineering-prod
url: https://kubernetes.default.svc
env: prod
# The generator's template field takes precedence over the spec's template fields
template:
metadata: {}
spec:
project: "default"
source:
revision: HEAD
repoURL: https://github.com/argoproj/argo-cd.git
# New path value is generated here:
path: 'applicationset/examples/template-override/{{cluster}}-override'
destination: {}
selector:
matchLabels:
env: staging
# It is also possible to use matchExpressions for more powerful selectors
- clusters: {}
selector:
matchExpressions:
- key: server
operator: In
values:
- https://kubernetes.default.svc
- https://some-other-cluster

View File

@@ -72,7 +72,7 @@ data:
The allow-list only applies to SCM providers for which the user may configure a custom `api`. Where an SCM or PR
generator does not accept a custom API URL, the provider is implicitly allowed.
If you do not intend to allow users to use the SCM or PR generators, you can disable them entirely by setting the environment variable `ARGOCD_APPLICATIONSET_CONTROLLER_ALLOW_SCM_PROVIDERS` to argocd-cmd-params-cm `applicationsetcontroller.allow.scm.providers` to `false`.
If you do not intend to allow users to use the SCM or PR generators, you can disable them entirely by setting the environment variable `ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS` to argocd-cmd-params-cm `applicationsetcontroller.enable.scm.providers` to `false`.
### Overview

View File

@@ -136,6 +136,29 @@ However, if you do wish to target both local and non-local clusters, while also
These steps might seem counterintuitive, but the act of changing one of the default values for the local cluster causes the Argo CD Web UI to create a new secret for this cluster. In the Argo CD namespace, you should now see a Secret resource named `cluster-(cluster suffix)` with label `argocd.argoproj.io/secret-type": "cluster"`. You may also create a local [cluster secret declaratively](../../declarative-setup/#clusters), or with the CLI using `argocd cluster add "(context name)" --in-cluster`, rather than through the Web UI.
### Fetch clusters based on their K8s version
There is also the possibility to fetch clusters based upon their Kubernetes version. To do this, the label `argocd.argoproj.io/auto-label-cluster-info` needs to be set to `true` on the cluster secret.
Once that has been set, the controller will dynamically label the cluster secret with the Kubernetes version it is running on. To retrieve that value, you need to use the
`argocd.argoproj.io/kubernetes-version`, as the example below demonstrates:
```yaml
spec:
goTemplate: true
generators:
- clusters:
selector:
matchLabels:
argocd.argoproj.io/kubernetes-version: 1.28
# matchExpressions are also supported.
#matchExpressions:
# - key: argocd.argoproj.io/kubernetes-version
# operator: In
# values:
# - "1.27"
# - "1.28"
```
### Pass additional key-value pairs via `values` field
You may pass additional, arbitrary string key-value pairs via the `values` field of the cluster generator. Values added via the `values` field are added as `values.(field)`

View File

@@ -53,7 +53,7 @@ It can be enabled in any of these ways:
1. Pass `--enable-new-git-file-globbing` to the ApplicationSet controller args.
1. Set `ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING=true` in the ApplicationSet controller environment variables.
1. Set `applicationsetcontroller.enable.new.git.file.globbing: true` in the Argo CD ConfigMap.
1. Set `applicationsetcontroller.enable.new.git.file.globbing: "true"` in the `argocd-cmd-params-cm` ConfigMap.
Note that the default may change in the future.

View File

@@ -84,8 +84,8 @@ spec:
generators:
- pullRequest:
gitlab:
# The GitLab project.
project: myproject
# The GitLab project ID.
project: "12341234"
# For self-hosted GitLab (optional)
api: https://git.example.com/
# Reference to a Secret containing an access token. (optional)
@@ -104,7 +104,7 @@ spec:
# ...
```
* `project`: Required name of the GitLab project.
* `project`: Required project ID of the GitLab project.
* `api`: If using self-hosted GitLab, the URL to access it. (Optional)
* `tokenRef`: A `Secret` name and key containing the GitLab access token to use for requests. If not specified, will make anonymous requests which have a lower rate limit and can only see public repositories. (Optional)
* `labels`: Labels is used to filter the MRs that you want to target. (Optional)

Some files were not shown because too many files have changed in this diff Show More