Compare commits

..

153 Commits

Author SHA1 Message Date
argo-bot
903db5fe46 Bump version to 2.1.16 2022-06-21 16:19:26 +00:00
argo-bot
1d26f44f53 Bump version to 2.1.16 2022-06-21 16:19:15 +00:00
Michael Crenshaw
e577e25405 chore: fix docs gen
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-21 10:49:34 -04:00
Michael Crenshaw
a92a153a49 Merge pull request from GHSA-jhqp-vf4w-rpwq
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

defer instead of multiple close calls

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

oops

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

don't count jsonnet against max

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

fix codegen

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

add caveat about 300x ratio

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

fix versions

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

fix tests/lint

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-21 09:40:36 -04:00
Michael Crenshaw
45ddd05cef Merge pull request from GHSA-q4w5-4gq2-98vm
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-21 09:39:56 -04:00
Michael Crenshaw
947bdd9efb Merge pull request from GHSA-2m7h-86qq-fp4v
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

fix references

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

use long enough state param for oauth2

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

typo

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

more entropy

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

fix tests/lint

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-21 09:39:01 -04:00
Michael Crenshaw
4fd50ce8bd Merge pull request from GHSA-h4w9-6x78-8vrj
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-21 09:36:37 -04:00
Michael Crenshaw
3fab7def3e fix: missing Helm params (#9565) (#9566)
* fix: missing Helm params

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

* use absolute paths, fix tests

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

* fix race in test

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-14 22:32:42 -04:00
Michael Crenshaw
5e6b788da9 test: directory app manifest generation (#9503)
* test: directory app manifest generation

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

* git doesn't support empty dirs

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

fix bad cherry-pick

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-14 16:27:40 -04:00
Michael Crenshaw
26ac321f03 test: fix erroneous test change
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-14 15:36:34 -04:00
Michael Crenshaw
ea79ca4029 chore: eliminate go-mpatch dependency (#9045)
* chore: eliminate go-mpatch dependency

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

* chore: abstract out resource list function

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

* chore: don't exit the program in anything but the main function

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

* chore: better error messages

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

* chore: better error messages

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-14 15:34:32 -04:00
jannfis
e7ca57b361 chore: Make unit tests run on platforms other than amd64 (#8995)
Signed-off-by: jannfis <jann@mistrust.net>

Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-14 15:33:25 -04:00
Alexander Matyushentsev
f3e7fbada8 chore: remove obsolete repo-server unit test (#9559)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-06-14 15:33:07 -04:00
Michael Crenshaw
01f069c1da chore: remove unnecessary import
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-14 15:32:01 -04:00
Tommaso Sardelli
4c8ca4f41e chore: upgrade golangci-lint to v1.46.2 (#9448)
* chore: upgrade golangci-lint to v1.46.2

Because:

* Installation of golangci-lint v1.45.2 is currently broken and fails
  silently due to a redacted dependency
  (https://github.com/blizzy78/varnamelen/issues/13)

This commit:

* Upgrades golangci-lint to v1.46.2

Signed-off-by: Tommaso Sardelli <lacapannadelloziotom@gmail.com>

* fix: lint

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

* fix: lint

Signed-off-by: Tommaso Sardelli <lacapannadelloziotom@gmail.com>

Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-14 15:31:01 -04:00
Michael Crenshaw
e19c351f10 chore: update golangci-lint (#8988)
* chore: update golangci-lint

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-14 15:30:16 -04:00
Michael Crenshaw
0d74b6859d test: fix ErrorContains (#9445)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-14 14:41:00 -04:00
argo-bot
52f917a181 Bump version to 2.1.15 2022-05-18 12:34:22 +00:00
argo-bot
f4c22f5958 Bump version to 2.1.15 2022-05-18 12:34:11 +00:00
jannfis
10491767cf Merge pull request from GHSA-r642-gv9p-2wjj
Signed-off-by: jannfis <jann@mistrust.net>

Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>

Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-18 13:16:21 +02:00
Michael Crenshaw
7357cfdb58 Merge pull request from GHSA-6gcg-hp2x-q54h
* fix: do not allow symlinks from directory-type applications

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

* chore: fix merge

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

* chore: lint

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

* chore: use t.TempDir for simpler tests

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

* address comments

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-18 13:13:41 +02:00
jannfis
2fe88150d6 Merge pull request from GHSA-xmg8-99r8-jc2j
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-18 13:06:31 +02:00
argo-bot
836cde06ba Bump version to 2.1.14 2022-03-23 00:09:36 +00:00
argo-bot
db00e40b16 Bump version to 2.1.14 2022-03-23 00:09:23 +00:00
argo-bot
4803dfac1d Bump version to 2.1.13 2022-03-22 22:48:03 +00:00
argo-bot
5dbdaa4fe2 Bump version to 2.1.13 2022-03-22 22:47:48 +00:00
Alexander Matyushentsev
e13e887de8 fix: fix broken e2e test (#8861)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-03-22 14:59:38 -07:00
Alexander Matyushentsev
b043629979 Merge pull request from GHSA-2f5v-8r3f-8pww
* fix: application resource APIs must enforce project restrictions

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

* Fix unit tests

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

Co-authored-by: jannfis <jann@mistrust.net>
2022-03-22 10:57:31 -07:00
argo-bot
273a952e6c Bump version to 2.1.12 2022-03-09 00:45:50 +00:00
argo-bot
2600f52a66 Bump version to 2.1.12 2022-03-09 00:45:37 +00:00
Alexander Matyushentsev
2cefc00855 fix: correct jsonnet paths resolution (#8721)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-03-08 16:03:03 -08:00
argo-bot
e25d3b5435 Bump version to 2.1.11 2022-03-06 05:30:33 +00:00
argo-bot
b921433112 Bump version to 2.1.11 2022-03-06 05:30:19 +00:00
Alexander Matyushentsev
96f63c3e2b fix: prevent file traversal using helm file values param and application details api (#8606)
* fix: prevent file traversal using helm file values param and application details api

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

* apply reviewer notes: move resolve.go into separate package; use uuid to generate random file

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-03-03 21:22:16 -08:00
Jesse Suen
d04dc9baed fix!: enforce app create/update privileges when getting repo details (#8558)
Signed-off-by: Jesse Suen <jesse@akuity.io>
2022-03-03 20:39:29 -08:00
Alexander Matyushentsev
0ef556e0f5 feat: support custom helm values file schemes (#8535)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-03-03 17:13:28 -08:00
Jesse Suen
d54361937b docs: add security documentation related to git repositories (#8463)
Signed-off-by: Jesse Suen <jesse@akuity.io>
2022-02-11 15:53:02 -08:00
argo-bot
de6735c386 Bump version to 2.1.10 2022-02-05 01:10:59 +00:00
argo-bot
df2149bbac Bump version to 2.1.10 2022-02-05 01:10:46 +00:00
jannfis
09529ee1ae fix: Resolve symlinked value files correctly (#8387)
* fix: Resolve symlinked value files correctly

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

* fix: Resolve symlinked value files correctly

Signed-off-by: jannfis <jann@mistrust.net>
2022-02-04 15:12:32 -08:00
argo-bot
5c51d5dae0 Bump version to 2.1.9 2022-02-03 20:22:27 +00:00
argo-bot
ec9b6f1689 Bump version to 2.1.9 2022-02-03 20:22:14 +00:00
jannfis
b7d9f0071b Merge pull request from GHSA-63qx-x74g-jcr7
Signed-off-by: jannfis <jann@mistrust.net>
2022-02-03 20:37:46 +01:00
argo-bot
2fdaf7a9ad Bump version to 2.1.8 2021-12-13 23:10:19 +00:00
argo-bot
5e64458c6b Bump version to 2.1.8 2021-12-13 23:10:03 +00:00
pasha-codefresh
2475403af7 fix: issue with keepalive (#7861)
* fix issue with keepalive

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

* empty commit

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-12-11 11:18:48 -08:00
jomenxiao
a1e14d48ab fix nil point (#7905)
Signed-off-by: jomenxiao <jomenxiao@gmail.com>
2021-12-10 21:24:31 -08:00
Jesse Suen
425d35c477 fix: env vars to tune cluster cache were broken (#7779)
Signed-off-by: Jesse Suen <jesse@akuity.io>
2021-11-24 18:19:19 -08:00
Alexander Matyushentsev
0d7c4cbe83 fix: upgraded gitops engine to v0.4.2 (fixes #7561)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-19 13:07:41 -08:00
argo-bot
a408e299ff Bump version to 2.1.7 2021-11-17 22:02:58 +00:00
argo-bot
1acd1af8ef Bump version to 2.1.7 2021-11-17 22:02:45 +00:00
Mark Sarcevicz
5679e4060e Fix: Kuberenetes manifest to have new Github.com ssh known host keys for ArgoCD deployments (#7722)
* Kuberenetes manifest to have new ssh known host keys for ArgoCD deployments

https://github.blog/2021-09-01-improving-git-protocol-security-github/
Signed-off-by: smark88 <msarcevicz@influxdata.com>

* added to docs

Signed-off-by: smark88 <msarcevicz@influxdata.com>

* fix: regenerate manifests using 'make manifests'

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

Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-17 13:33:59 -08:00
argo-bot
a346cf933e Bump version to 2.1.6 2021-10-28 19:51:48 +00:00
argo-bot
f249d530b5 Bump version to 2.1.6 2021-10-28 19:51:34 +00:00
Alexander Matyushentsev
46c1ef7a16 fix: don't use revision caching during app creation (#7508)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-20 20:40:18 -07:00
Mohammad Yosefpor
b4565fd7b2 fix: supporting OCI dependencies. Fixes #6062 (#6994)
* fix: supporting OCI dependencies

Signed-off-by: Mohammad Yosefpor <myusefpur@gmail.com>

* chore: add org to USERS.md

Signed-off-by: Mohammad Yosefpor <myusefpur@gmail.com>

* fix(tests): remove invalid TestRepoPermission e2e test

Signed-off-by: Mohammad Yosefpor <myusefpur@gmail.com>
2021-10-20 18:43:03 -07:00
argo-bot
a8a6fc8dda Bump version to 2.1.5 2021-10-20 15:09:22 +00:00
argo-bot
81024f8a89 Bump version to 2.1.5 2021-10-20 15:09:12 +00:00
Alexander Matyushentsev
f0201c3a99 fix: Invalid memory address or nil pointer dereference in processRequestedAppOperation (#7501)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-20 08:04:38 -07:00
argo-bot
d5c6608827 Bump version to 2.1.4 2021-10-20 00:27:32 +00:00
argo-bot
0564de77e6 Bump version to 2.1.4 2021-10-20 00:27:18 +00:00
Alexander Matyushentsev
e1eec8a9dc fix: Operation has completed with phase: Running (#7482)
* fix: Operation has completed with phase: Running

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-19 17:17:34 -07:00
Alexander Matyushentsev
3d8d03f0a4 fix: Application status panel shows Syncing instead of Deleting (#7486)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-19 10:36:23 -07:00
pasha-codefresh
64f5c6aa85 fix: remove not existing repo (#7280)
* remove not existing repo

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

* fix test

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-12 09:59:51 -07:00
Alexander Matyushentsev
f9e2fc9210 docs: update v2.3+ roadmap (#7353)
* docs: update v2.3+ roadmap

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

* Address reviewer notes: Add 'Merge Argo CD Image Updater into Argo CD' and 'Multi-tenancy improvements'

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-12 08:55:51 -07:00
Jan-Otto Kröpke
f9eac82928 docs: Kustomize load_restrictor -> load-restrictor (#7358)
Signed-off-by: Jan-Otto Kröpke <joe@adorsys.de>
2021-10-12 08:55:32 -07:00
Remington Breeze
bfbc19a583 fix(ui): Add Error Boundary around Extensions and comply with new Extensions API (#7215)
* fix: Add error boundary around Extensions and change path where UI looks for extensions

Signed-off-by: Remington Breeze <remington@breeze.software>

* Add error message to error boundary

Signed-off-by: Remington Breeze <remington@breeze.software>
2021-10-04 17:38:06 -07:00
argo-bot
d855831540 Bump version to 2.1.3 2021-09-29 21:44:26 +00:00
argo-bot
6536fd9fb4 Bump version to 2.1.3 2021-09-29 21:44:11 +00:00
Alexander Matyushentsev
053bfbe845 fix: core-install.yaml always refers to latest argocd image (#7321)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-29 14:05:46 -07:00
Chetan Banavikalmutt
7b771061e1 fix: handle applicationset backup forbidden error (#7306)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2021-09-29 12:35:01 -07:00
Alexander Matyushentsev
f8c6bcba65 fix: Argo CD should not use cached git/helm revision during app creation/update validation (#7244)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-16 18:35:52 -07:00
Remington Breeze
6e9b18ea4b fix(ui): More tab was displayed for resources that did not have extensions installed (#7209)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-09-14 08:47:49 -07:00
jannfis
7a72b6f2d2 chore: Update haproxy for redis-ha to 2.0.25 (#7194)
Signed-off-by: jannfis <jann@mistrust.net>
2021-09-10 09:14:23 -07:00
Thomas
51db9bdf79 fix: use selected helm-values (#7166)
Signed-off-by: Thomas Münzl <thomasmuenzl@icloud.com>
2021-09-09 21:13:18 -07:00
irizzant
b2c5f5b63c 7144 fix: add custom volume as Helm working dir (#7162)
Signed-off-by: irizzant <i.rizzante@gmail.com>
2021-09-09 21:12:49 -07:00
argo-bot
7af9dfb352 Bump version to 2.1.2 2021-09-02 17:58:03 +00:00
argo-bot
8a39759eb3 Bump version to 2.1.2 2021-09-02 17:57:49 +00:00
Alexander Matyushentsev
3981432899 fix: cluster filter popping out of box (#7135)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-02 10:55:50 -07:00
Alexander Matyushentsev
af2e16fcaf fix: gracefully shutdown metrics server when dex config changes (#7138)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-01 18:58:30 -07:00
Alexander Matyushentsev
d34bf2cf14 fix: upgrade gitops engine version to v0.4.1 (#7088)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-01 16:57:50 -07:00
May Zhang
194b2894ef fix: repository name already exists when multiple helm dependencies f… (#7096)
* fix: repository name already exists when multiple helm dependencies from same private repo server

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

* fix: add test cases

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

* fix: clean up

Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-09-01 14:56:38 -07:00
argo-bot
aab9542f8b Bump version to 2.1.1 2021-08-25 15:05:12 +00:00
argo-bot
a85ab6586d Bump version to 2.1.1 2021-08-25 15:04:57 +00:00
May Zhang
57abbf95ed fix: password reset requirements (#7071)
* fix: password reset meet requirement

Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-08-24 23:22:23 -07:00
Alexander Matyushentsev
6a69d737da fix: Custom Styles feature is broken (#7067)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-24 15:11:52 -07:00
Remington Breeze
7c98813bb8 fix(ui): Add State to props passed to Extensions (#7045)
Signed-off-by: Remington Breeze <remington@breeze.software>
Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-24 15:11:43 -07:00
Alexander Matyushentsev
6868bd4213 fix: fix building remote container (#7062)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-24 15:11:32 -07:00
pasha-codefresh
c7c08426ac fix: make codegen (#7059)
fix: make codegen

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-08-24 15:11:24 -07:00
Alexander Matyushentsev
86d21721a8 fix: keep uid_entrypoint.sh for backward compatibility (#7047)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-23 06:45:35 +00:00
argo-bot
d0b2d55e3f Bump version to 2.1.0 2021-08-20 05:22:27 +00:00
argo-bot
6f03da218f Bump version to 2.1.0 2021-08-20 05:22:12 +00:00
Alexander Matyushentsev
5b5182f83a fix: reload extension when selected resource node changes (#7034)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-19 22:18:14 -07:00
Remington Breeze
d6c2cdf4a7 fix(ui): Resource details crashed due to extensions (#7025)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-19 21:13:12 -07:00
Alexander Matyushentsev
aeb9e9b383 feat: support loading extensions in Argo CD UI (#7019)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-19 21:13:05 -07:00
Philipp Dallig
cd470736f6 fix: Running on Openshift 4.x with readOnlyRootFilesystem (#6998)
Signed-off-by: Philipp Dallig <philipp.dallig@gmail.com>
2021-08-18 14:42:16 +00:00
Alexander Matyushentsev
7470dc3359 fix: resouce health filter should include node if node or node's root health matches filter (#7002)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-17 14:35:00 -07:00
Alexander Matyushentsev
6d3688ddd9 fix: upgrade argo-ui version (#7010)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-17 12:51:15 -07:00
Yuan Tang
20b3d56ba1 docs: Fix links to subsections in roadmap (#6986)
* docs: Fix links to completed subsections in roadmap

Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>

* One more link

Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-08-17 12:26:30 -07:00
Alexander Matyushentsev
d10778f431 docs: update roadmap and release checklist (#6980)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-17 12:26:24 -07:00
Alexander Matyushentsev
9d81d36a2c docs: update obsolete resource customization docs (#7000)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-17 12:26:12 -07:00
Remington Breeze
03bf5051e6 chore(ui): Relocate CheckboxRow component to Filters instead of argo-ui (#6990)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-17 12:25:42 -07:00
Remington Breeze
a502982d2d fix(ui): Migrate to keyhook helpers in argo-ui, update keybindings accordingly (#6953)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-17 12:25:34 -07:00
David Collom
fb3fe6ed42 fix: Disable generating of CA Certificates (#6987)
Signed-off-by: David Collom <david.collom@jetstack.io>
2021-08-16 06:43:23 +00:00
Alexander Matyushentsev
f3e28d3131 fix: argocd core commands should not drop existing persistent flags (#6981)
* fix: argocd core commands should not drop existing persistent flags

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

* run cli codegen

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-12 23:11:29 -07:00
pasha-codefresh
491ab32214 feat(ui): add top value for large breakpoint Closes #6944 (#6975)
feat(ui): add `top` value for `large` breakpoint Closes #6944 (#6975)

Signed-off-by: andrii-codefresh <andrii@codefresh.io>
2021-08-12 12:40:46 -07:00
Jesse Suen
f4331324cc fix: rollout v1.0 'Paused' status.phase should map to Argo CD 'Suspended' (#6967)
Signed-off-by: Jesse Suen <jessesuen@gmail.com>
2021-08-12 11:38:06 -07:00
Alexander Matyushentsev
a8e61cc13c fix: basehref not set correctly (#6962)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-11 15:23:06 -07:00
argo-bot
5700faf0d1 Bump version to 2.1.0-rc3 2021-08-11 19:36:11 +00:00
argo-bot
829f0285b9 Bump version to 2.1.0-rc3 2021-08-11 19:35:56 +00:00
Alexander Matyushentsev
d6bb869468 fix: update deprecated helm2 installation URL (#6960)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-11 12:35:01 -07:00
Alexander Matyushentsev
b3abdb1323 fix: make sure repo server discard cached empty response (#6948)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-11 08:54:33 -07:00
Alexander Matyushentsev
e2bca9f9ef fix: applications/resources filter improvement and bug fixes (#6931)
* fix: applications/resources filter improvement and bug fixes

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-11 08:54:26 -07:00
May Zhang
bdc53c804b fix: use secure way to generate initial password (#6938)
* fix: use secure way to generate initial password

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

* fix: use secure way to generate initial password

Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-08-10 15:01:15 -07:00
Daisuke Taniwaki
13e10a7c2b fix: Set header to OIDC requests (#6869)
Signed-off-by: Daisuke Taniwaki <daisuketaniwaki@gmail.com>
2021-08-10 15:01:05 -07:00
jannfis
f77d35a3d2 docs: Update contributor docs (#6615)
* Sync

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

* docs: Update contributor docs

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

* New paragraph about code submission

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

* Update

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

* Update code submissions before triage paragraph

Signed-off-by: jannfis <jann@mistrust.net>
2021-08-09 10:41:53 +00:00
jannfis
0818a48348 docs: Update security considerations (#6930)
* docs: Update security considerations

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

* docs: Update security considerations

Signed-off-by: jannfis <jann@mistrust.net>
2021-08-09 10:41:33 +00:00
Alexander Matyushentsev
faf7bff322 fix: application sync panel crashes if app has no sync options (#6914)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-04 16:57:09 -07:00
Yi Cai
96fba7c67b fix: Reword Generate new token dialog (#6913)
Signed-off-by: ciiay <yicai@redhat.com>
2021-08-04 16:57:05 -07:00
Alexander Matyushentsev
8020261a7d fix: assume ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS, ARGOCD_SERVER_REPO_SERVER_TIMEOUT_SECONDS env vars have seconds (#6912)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-04 13:52:37 -07:00
Yi Cai
e7e93b2e7a fix: UI 6337 cluster filter improvement for issue #6337 (#6856)
* fix: when cluster field is bge-dev1, the applications with cluster dev1 is selected #6337

Signed-off-by: ciiay <yicai@redhat.com>
2021-08-04 13:52:34 -07:00
Noam Gal
8d78f0a604 fixed max to use MaxInt64 value (#6911)
Signed-off-by: Noam Gal <noam.gal@codefresh.io>
2021-08-04 11:21:57 -07:00
Chetan Banavikalmutt
27e9f6398c fix: unset command should remove env vars when there's no error (#6908)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2021-08-04 11:21:54 -07:00
pasha-codefresh
455d0f1be1 feat: rollback should work without id passed #6825. (#6877)
feat: rollback should work without id passed #6825. (#6877)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-08-04 11:21:50 -07:00
Remington Breeze
a87660adee fix: Add https prefix to ingress URLs if hosts field is present (#6901)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-04 11:21:47 -07:00
woshicai
31093cd359 fix: client input arguments with equal sign (#6885)
Signed-off-by: Charles Cai <charles.cai@sap.com>

Co-authored-by: Charles Cai <charles.cai@sap.com>
2021-08-04 11:21:41 -07:00
Bob Claerhout
cad6016ac6 docs: Add replace description on individual resource level (#6905)
Signed-off-by: Bob Claerhout <claerhout.bob@gmail.com>
2021-08-04 11:21:34 -07:00
May Zhang
a2f1993c06 fix: logout redirect URL (#6903)
Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-08-03 17:07:37 -07:00
Alexander Matyushentsev
9118e7a7ec refactor: update resources install order according to helm implementation (#6902)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-03 17:07:33 -07:00
Alexander Matyushentsev
cd10754574 fix: controller should not create orphaned resources warning by default (#6898)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-03 17:07:28 -07:00
Alexander Matyushentsev
f0b91cccf3 feat: Improve Replace sync option description in UI (#6899)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-03 17:07:23 -07:00
dependabot[bot]
1354538269 chore(deps): bump tar from 6.1.0 to 6.1.3 in /ui (#6900)
Bumps [tar](https://github.com/npm/node-tar) from 6.1.0 to 6.1.3.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v6.1.0...v6.1.3)

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

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-03 17:07:20 -07:00
Yi Cai
5c408cc5d5 fix: menu for application loses text when title area buttons collapse #6474 (#6887)
Signed-off-by: ciiay <yicai@redhat.com>
2021-08-03 17:07:10 -07:00
argo-bot
b067879892 Bump version to 2.1.0-rc2 2021-08-03 17:00:32 +00:00
argo-bot
ab2bbc2201 Bump version to 2.1.0-rc2 2021-08-03 17:00:06 +00:00
Remington Breeze
a93649419b fix(ui): Bump argo-ui to hide filter suggestions on enter and show on typing (#6891)
* fix(ui): Bump argo-ui to hide filter suggestions on enter and show on typing

Signed-off-by: Remington Breeze <remington@breeze.software>

* remove unneccessary yarn.lock changes

Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-03 09:45:26 -07:00
Remington Breeze
15c361e525 fix(ui): Add View Details option to resource actions menu (#6893)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-03 09:45:21 -07:00
Jan-Otto Kröpke
a5ba98ff61 fix: upgrade to kustomize 4.2.0 (#6861)
Signed-off-by: Jan-Otto Kröpke <joe@adorsys.de>
2021-08-03 09:45:16 -07:00
May Zhang
18ddf1f839 fix: add documentation for using argocd repocreds with --enable-coi and --type helm (#6890)
Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-08-03 09:45:12 -07:00
Jun
4e8b9b85b8 feat: Rollback command support omit history id (#6863)
Signed-off-by: junnplus <junnplus@gmail.com>
2021-08-03 09:45:03 -07:00
Remington Breeze
34b3139309 fix(ui): Incorrect path for non-namespaced resources (#6895)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-03 09:44:58 -07:00
Remington Breeze
4410803b11 fix(ui): Page navigation no longer visible with status bar (#6888)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-03 09:44:50 -07:00
Alexander Matyushentsev
83b272e125 fix: make sure orphaned filter checkbox is clickable (#6886)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-03 09:44:44 -07:00
woshicai
4f967eaa5a fix: docs about custom image user #6851 (#6872)
* fix: docs about custom image user, change it from argocd to 999

Signed-off-by: Charles Cai <charles.cai@sap.com>

* update: docs for upgrading version

Signed-off-by: Charles Cai <charles.cai@sap.com>

Co-authored-by: Charles Cai <charles.cai@sap.com>
2021-08-03 09:44:38 -07:00
Joe Bowbeer
13cdf01506 docs: installation.md (#6860)
Signed-off-by: Joe Bowbeer <joe.bowbeer@gmail.com>
2021-08-03 09:44:32 -07:00
Yi Cai
d84822ea88 fix: Project filter selector does not get unset upon clear filters #6750 (#6866)
Signed-off-by: ciiay <yicai@redhat.com>
2021-08-03 09:44:25 -07:00
Remington Breeze
a524a3b4d9 fix(ui): Prevent UI crash if app status or resources is empty (#6858) 2021-07-30 10:03:55 -07:00
Alexander Matyushentsev
9419c11c1d fix: util.cli.SetLogLevel should update global log level (#6852)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-07-29 13:02:07 -07:00
Alexander Matyushentsev
12a4475176 fix: include cluster level RBAC into argocd-core manifests (#6854)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-07-29 12:49:53 -07:00
Klaus Dorninger
662567b8fd fix: #6844 multiple global projects can be configured (#6845)
Signed-off-by: Klaus Dorninger <github@dornimaug.org>
2021-07-29 11:08:01 -07:00
Alexander Matyushentsev
6b14f909e9 fix: core installation must include CRD definitions (#6841)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-07-28 16:30:42 -07:00
argo-bot
a92c24094e Bump version to 2.1.0-rc1 2021-07-28 22:24:09 +00:00
argo-bot
307de9555d Bump version to 2.1.0-rc1 2021-07-28 22:23:55 +00:00
507 changed files with 4013 additions and 25146 deletions

View File

@@ -13,14 +13,7 @@ on:
env:
# Golang version to use across CI steps
GOLANG_VERSION: '1.16.11'
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
GOLANG_VERSION: '1.16.5'
jobs:
build-docker:
@@ -38,9 +31,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Download all Go modules
@@ -56,13 +49,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Restore go build cache
uses: actions/cache@v3
uses: actions/cache@v1
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -73,14 +66,11 @@ jobs:
run: make build-local
lint-go:
permissions:
contents: read # for actions/checkout to fetch code
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
name: Lint Go code
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3
with:
@@ -96,11 +86,11 @@ jobs:
- name: Create checkout directory
run: mkdir -p ~/go/src/github.com/argoproj
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Create symlink in GOPATH
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Install required packages
@@ -120,7 +110,7 @@ jobs:
run: |
echo "/usr/local/bin" >> $GITHUB_PATH
- name: Restore go build cache
uses: actions/cache@v3
uses: actions/cache@v1
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -156,11 +146,11 @@ jobs:
- name: Create checkout directory
run: mkdir -p ~/go/src/github.com/argoproj
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Create symlink in GOPATH
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Install required packages
@@ -180,7 +170,7 @@ jobs:
run: |
echo "/usr/local/bin" >> $GITHUB_PATH
- name: Restore go build cache
uses: actions/cache@v3
uses: actions/cache@v1
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -207,9 +197,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Create symlink in GOPATH
@@ -254,14 +244,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup NodeJS
uses: actions/setup-node@v1
with:
node-version: '12.18.4'
- name: Restore node dependency cache
id: cache-dependencies
uses: actions/cache@v3
uses: actions/cache@v1
with:
path: ui/node_modules
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
@@ -290,12 +280,12 @@ jobs:
sonar_secret: ${{ secrets.SONAR_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Restore node dependency cache
id: cache-dependencies
uses: actions/cache@v3
uses: actions/cache@v1
with:
path: ui/node_modules
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
@@ -351,7 +341,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
k3s-version: [v1.21.2, v1.20.2, v1.19.2]
k3s-version: [v1.21.2, v1.20.2, v1.19.2, v1.18.9, v1.17.11]
needs:
- build-go
env:
@@ -366,9 +356,9 @@ jobs:
ARGOCD_SERVER: "127.0.0.1:8088"
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: GH actions workaround - Kill XSP4 process
@@ -386,7 +376,7 @@ jobs:
sudo chown runner $HOME/.kube/config
kubectl version
- name: Restore go build cache
uses: actions/cache@v3
uses: actions/cache@v1
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -409,9 +399,9 @@ 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.35.3-distroless
docker pull quay.io/dexidp/dex:v2.25.0
docker pull argoproj/argo-cd-ci-builder:v1.0.0
docker pull redis:6.2.7-alpine
docker pull redis:6.2.4-alpine
- name: Create target directory for binaries in the build-process
run: |
mkdir -p dist

View File

@@ -6,27 +6,15 @@ on:
schedule:
- cron: '0 19 * * 0'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
CodeQL-Build:
permissions:
actions: read # for github/codeql-action/init to get workflow details
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/autobuild to send a status report
if: github.repository == 'argoproj/argo-cd'
# CodeQL runs on ubuntu-latest and windows-latest
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
@@ -36,7 +24,7 @@ jobs:
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1

View File

@@ -16,7 +16,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v1
with:
python-version: 3.9.8
python-version: 3.x
- name: build
run: |
pip install -r docs/requirements.txt

View File

@@ -6,25 +6,15 @@ on:
- master
env:
GOLANG_VERSION: '1.16.11'
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
GOLANG_VERSION: '1.16.5'
jobs:
publish:
permissions:
contents: write # for git to push upgrade commit if not already deployed
if: github.repository == 'argoproj/argo-cd'
runs-on: ubuntu-latest
env:
GOPATH: /home/runner/work/argo-cd/argo-cd
steps:
- uses: actions/setup-go@v3
- uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- uses: actions/checkout@master
@@ -56,28 +46,12 @@ jobs:
DOCKER_USERNAME: ${{ secrets.RELEASE_DOCKERHUB_USERNAME }}
DOCKER_TOKEN: ${{ secrets.RELEASE_DOCKERHUB_TOKEN }}
# sign container images
- name: Install cosign
uses: sigstore/cosign-installer@main
with:
cosign-release: 'v1.13.0'
- name: Sign Argo CD latest image
run: |
cosign sign --key env://COSIGN_PRIVATE_KEY quay.io/argoproj/argocd:latest
# Displays the public key to share.
cosign public-key --key env://COSIGN_PRIVATE_KEY
env:
COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}}
COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}}
if: ${{ github.event_name == 'push' }}
# deploy
- run: git clone "https://$TOKEN@github.com/argoproj/argoproj-deployments"
env:
TOKEN: ${{ secrets.TOKEN }}
- run: |
docker run -u $(id -u):$(id -g) -v $(pwd):/src -w /src --rm -t ghcr.io/argoproj/argocd:${{ steps.image.outputs.tag }} kustomize edit set image quay.io/argoproj/argocd=ghcr.io/argoproj/argocd:${{ steps.image.outputs.tag }}
docker run -v $(pwd):/src -w /src --rm -t lyft/kustomizer:v3.3.0 kustomize edit set image quay.io/argoproj/argocd=ghcr.io/argoproj/argocd:${{ steps.image.outputs.tag }}
git config --global user.email 'ci@argoproj.com'
git config --global user.name 'CI'
git diff --exit-code && echo 'Already deployed' || (git commit -am 'Upgrade argocd to ${{ steps.image.outputs.tag }}' && git push)

View File

@@ -12,15 +12,10 @@ on:
- '!release-v0*'
env:
GOLANG_VERSION: '1.16.11'
permissions:
contents: read
GOLANG_VERSION: '1.16.5'
jobs:
prepare-release:
permissions:
contents: write # To push changes to release branch
name: Perform automatic release on trigger ${{ github.ref }}
runs-on: ubuntu-latest
env:
@@ -42,7 +37,7 @@ jobs:
GIT_EMAIL: argoproj@gmail.com
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
@@ -99,7 +94,7 @@ jobs:
echo "=========== BEGIN COMMIT MESSAGE ============="
git show ${SOURCE_TAG}
echo "============ END COMMIT MESSAGE =============="
# Quite dirty hack to get the release notes from the annotated tag
# into a temporary file.
RELEASE_NOTES=$(mktemp -p /tmp release-notes.XXXXXX)
@@ -146,7 +141,7 @@ jobs:
echo "RELEASE_NOTES=${RELEASE_NOTES}" >> $GITHUB_ENV
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
@@ -212,32 +207,12 @@ jobs:
docker login --username "${DOCKER_USERNAME}" --password "${DOCKER_TOKEN}"
docker tag ${IMAGE_NAMESPACE}/argocd:v${TARGET_VERSION} argoproj/argocd:v${TARGET_VERSION}
docker push argoproj/argocd:v${TARGET_VERSION}
make release-cli
make checksums
chmod +x ./dist/argocd-linux-amd64
./dist/argocd-linux-amd64 version --client
if: ${{ env.DRY_RUN != 'true' }}
- name: Install cosign
uses: sigstore/cosign-installer@main
with:
cosign-release: 'v1.13.0'
- name: Sign Argo CD container images and assets
run: |
cosign sign --key env://COSIGN_PRIVATE_KEY ${IMAGE_NAMESPACE}/argocd:v${TARGET_VERSION}
cosign sign-blob --key env://COSIGN_PRIVATE_KEY ./dist/argocd-${TARGET_VERSION}-checksums.txt > ./dist/argocd-${TARGET_VERSION}-checksums.sig
# Retrieves the public key to release as an asset
cosign public-key --key env://COSIGN_PRIVATE_KEY > ./dist/argocd-cosign.pub
env:
COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}}
COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}}
if: ${{ env.DRY_RUN != 'true' }}
- name: Read release notes file
id: release-notes
uses: juliangruber/read-file-action@v1
with:
with:
path: ${{ env.RELEASE_NOTES }}
- name: Push changes to release branch
@@ -246,7 +221,7 @@ jobs:
git push origin ${TARGET_BRANCH}
git push origin ${RELEASE_TAG}
- name: Dry run GitHub release
- name: Create GitHub release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -257,61 +232,38 @@ jobs:
draft: ${{ env.DRAFT_RELEASE }}
prerelease: ${{ env.PRE_RELEASE }}
body: ${{ steps.release-notes.outputs.content }}
if: ${{ env.DRY_RUN == 'true' }}
- name: Generate SBOM (spdx)
id: spdx-builder
env:
# defines the spdx/spdx-sbom-generator version to use.
SPDX_GEN_VERSION: v0.0.13
# defines the sigs.k8s.io/bom version to use.
SIGS_BOM_VERSION: v0.2.1
# comma delimited list of project relative folders to inspect for package
# managers (gomod, yarn, npm).
PROJECT_FOLDERS: ".,./ui"
# full qualified name of the docker image to be inspected
DOCKER_IMAGE: ${{env.IMAGE_NAMESPACE}}/argocd:v${{env.TARGET_VERSION}}
run: |
yarn install --cwd ./ui
go install github.com/spdx/spdx-sbom-generator/cmd/generator@$SPDX_GEN_VERSION
go install sigs.k8s.io/bom/cmd/bom@$SIGS_BOM_VERSION
# Generate SPDX for project dependencies analyzing package managers
for folder in $(echo $PROJECT_FOLDERS | sed "s/,/ /g")
do
generator -p $folder -o /tmp
done
# Generate SPDX for binaries analyzing the docker image
if [[ ! -z $DOCKER_IMAGE ]]; then
bom generate -o /tmp/bom-docker-image.spdx -i $DOCKER_IMAGE
fi
cd /tmp && tar -zcf sbom.tar.gz *.spdx
if: ${{ env.DRY_RUN != 'true' }}
- name: Sign sbom
run: |
cosign sign-blob --key env://COSIGN_PRIVATE_KEY /tmp/sbom.tar.gz > /tmp/sbom.tar.gz.sig
env:
COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}}
COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}}
if: ${{ env.DRY_RUN != 'true' }}
- name: Create GitHub release
uses: softprops/action-gh-release@v1
- name: Upload argocd-linux-amd64 binary to release assets
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
name: ${{ env.RELEASE_TAG }}
tag_name: ${{ env.RELEASE_TAG }}
draft: ${{ env.DRAFT_RELEASE }}
prerelease: ${{ env.PRE_RELEASE }}
body: ${{ steps.release-notes.outputs.content }}
files: |
dist/argocd-*
/tmp/sbom.tar.gz
/tmp/sbom.tar.gz.sig
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./dist/argocd-linux-amd64
asset_name: argocd-linux-amd64
asset_content_type: application/octet-stream
if: ${{ env.DRY_RUN != 'true' }}
- name: Upload argocd-darwin-amd64 binary to release assets
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./dist/argocd-darwin-amd64
asset_name: argocd-darwin-amd64
asset_content_type: application/octet-stream
if: ${{ env.DRY_RUN != 'true' }}
- name: Upload argocd-windows-amd64 binary to release assets
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./dist/argocd-windows-amd64.exe
asset_name: argocd-windows-amd64.exe
asset_content_type: application/octet-stream
if: ${{ env.DRY_RUN != 'true' }}
- name: Update homebrew formula
@@ -328,4 +280,3 @@ jobs:
set -ue
git push --delete origin ${SOURCE_TAG}
if: ${{ always() }}

View File

@@ -1,15 +1,6 @@
# Changelog
## v2.1.1 (2021-08-25)
### Bug Fixes
- fix: password reset requirements (#7071)
- fix: Custom Styles feature is broken (#7067)
- fix(ui): Add State to props passed to Extensions (#7045)
- fix: keep uid_entrypoint.sh for backward compatibility (#7047)
## v2.1.0 (2021-08-20)
## v2.1.0 (Unreleased)
> [Upgrade instructions](./docs/operator-manual/upgrading/2.0-2.1.md)

View File

@@ -1,10 +1,10 @@
ARG BASE_IMAGE=docker.io/library/ubuntu:22.04
ARG BASE_IMAGE=docker.io/library/ubuntu:21.04
####################################################################################################
# Builder image
# 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.16.11 as builder
FROM docker.io/library/golang:1.16.5 as builder
RUN echo 'deb http://deb.debian.org/debian buster-backports main' >> /etc/apt/sources.list
@@ -101,7 +101,7 @@ RUN NODE_ENV='production' NODE_ONLINE_ENV='online' yarn build
####################################################################################################
# Argo CD Build stage which performs the actual build of Argo CD binaries
####################################################################################################
FROM docker.io/library/golang:1.16.11 as argocd-build
FROM golang:1.16.5 as argocd-build
WORKDIR /go/src/github.com/argoproj/argo-cd
@@ -130,7 +130,6 @@ COPY --from=argocd-build /go/src/github.com/argoproj/argo-cd/dist/argocd* /usr/l
USER root
RUN ln -s /usr/local/bin/argocd /usr/local/bin/argocd-server
RUN ln -s /usr/local/bin/argocd /usr/local/bin/argocd-repo-server
RUN ln -s /usr/local/bin/argocd /usr/local/bin/argocd-cmp-server
RUN ln -s /usr/local/bin/argocd /usr/local/bin/argocd-application-controller
RUN ln -s /usr/local/bin/argocd /usr/local/bin/argocd-dex

View File

@@ -23,7 +23,7 @@ DOCKER_WORKDIR?=/go/src/github.com/argoproj/argo-cd
ARGOCD_PROCFILE?=Procfile
# Strict mode has been disabled in latest versions of mkdocs-material.
# 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
MKDOCS_RUN_ARGS?=
@@ -111,7 +111,7 @@ define run-in-test-client
bash -c "$(1)"
endef
#
#
define exec-in-test-server
docker exec -it -u $(shell id -u):$(shell id -g) -e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) argocd-test-server $(1)
endef
@@ -193,7 +193,7 @@ clientgen: ensure-gopath
.PHONY: clidocsgen
clidocsgen: ensure-gopath
go run tools/cmd-docs/main.go
go run tools/cmd-docs/main.go
.PHONY: codegen-local
codegen-local: ensure-gopath mod-vendor-local gogen protogen clientgen openapigen clidocsgen manifests-local
@@ -266,7 +266,6 @@ image:
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 build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) -f dist/Dockerfile.dev dist
@@ -410,14 +409,12 @@ start-e2e-local:
if test -d /tmp/argo-e2e/app/config/gpg; then rm -rf /tmp/argo-e2e/app/config/gpg/*; fi
mkdir -p /tmp/argo-e2e/app/config/gpg/keys && chmod 0700 /tmp/argo-e2e/app/config/gpg/keys
mkdir -p /tmp/argo-e2e/app/config/gpg/source && chmod 0700 /tmp/argo-e2e/app/config/gpg/source
mkdir -p /tmp/argo-e2e/app/config/plugin && chmod 0700 /tmp/argo-e2e/app/config/plugin
# set paths for locally managed ssh known hosts and tls certs data
ARGOCD_SSH_DATA_PATH=/tmp/argo-e2e/app/config/ssh \
ARGOCD_TLS_DATA_PATH=/tmp/argo-e2e/app/config/tls \
ARGOCD_GPG_DATA_PATH=/tmp/argo-e2e/app/config/gpg/source \
ARGOCD_GNUPGHOME=/tmp/argo-e2e/app/config/gpg/keys \
ARGOCD_GPG_ENABLED=$(ARGOCD_GPG_ENABLED) \
ARGOCD_PLUGINCONFIGFILEPATH=/tmp/argo-e2e/app/config/plugin \
ARGOCD_E2E_DISABLE_AUTH=false \
ARGOCD_ZJWT_FEATURE_FLAG=always \
ARGOCD_IN_CI=$(ARGOCD_IN_CI) \
@@ -454,12 +451,6 @@ start-local: mod-vendor-local dep-ui-local
ARGOCD_E2E_TEST=false \
goreman -f $(ARGOCD_PROCFILE) start ${ARGOCD_START}
# Run goreman start with exclude option , provide exclude env variable with list of services
.PHONY: run
run:
bash ./hack/goreman-start.sh
# Runs pre-commit validation with the virtualized toolchain
.PHONY: pre-commit
pre-commit: codegen build lint test
@@ -542,6 +533,3 @@ dep-ui-local:
start-test-k8s:
go run ./hack/k8s
checksums:
sha256sum ./dist/$(BIN_NAME)-* | awk -F './dist/' '{print $$1 $$2}' > ./dist/$(BIN_NAME)-$(TARGET_VERSION)-checksums.txt

3
OWNERS
View File

@@ -9,7 +9,6 @@ approvers:
- jessesuen
- jgwest
- mayzhang2000
- rbreeze
reviewers:
- dthomson25
@@ -19,5 +18,3 @@ reviewers:
- reginapizza
- hblixt
- chetan-rns
- wanghong230
- pasha-codefresh

View File

@@ -1,8 +1,8 @@
controller: 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 go run ./cmd/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
api-server: 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 go run ./cmd/main.go --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} "
dex: sh -c "ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/v2/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:v2.30.2 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} redis:6.2.7-alpine --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; fi"
repo-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-/tmp/argo-e2e/app/config/plugin} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} 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-repo-server ARGOCD_GPG_ENABLED=${ARGOCD_GPG_ENABLED:-false} go run ./cmd/main.go --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}"
dex: sh -c "ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/v2/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:v2.27.0 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} redis:6.2.4-alpine --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; fi"
repo-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} 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-repo-server go run ./cmd/main.go --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}"
ui: sh -c 'cd ui && ${ARGOCD_E2E_YARN_CMD:-yarn} start'
git-server: test/fixture/testrepos/start-git.sh
helm-registry: test/fixture/testrepos/start-helm-registry.sh

View File

@@ -45,8 +45,6 @@ Participation in the Argo CD project is governed by the [CNCF Code of Conduct](h
### Blogs and Presentations
1. [Awesome-Argo: A Curated List of Awesome Projects and Resources Related to Argo](https://github.com/terrytangyuan/awesome-argo)
1. [GitOps Without Pipelines With ArgoCD Image Updater](https://youtu.be/avPUQin9kzU)
1. [Combining Argo CD (GitOps), Crossplane (Control Plane), And KubeVela (OAM)](https://youtu.be/eEcgn_gU3SM)
1. [How to Apply GitOps to Everything - Combining Argo CD and Crossplane](https://youtu.be/yrj4lmScKHQ)
1. [Couchbase - How To Run a Database Cluster in Kubernetes Using Argo CD](https://youtu.be/nkPoPaVzExY)
@@ -71,4 +69,3 @@ Participation in the Argo CD project is governed by the [CNCF Code of Conduct](h
1. [Applied GitOps with Argo CD](https://thenewstack.io/applied-gitops-with-argocd/)
1. [Solving configuration drift using GitOps with Argo CD](https://www.cncf.io/blog/2020/12/17/solving-configuration-drift-using-gitops-with-argo-cd/)
1. [Decentralized GitOps over environments](https://blogs.sap.com/2021/05/06/decentralized-gitops-over-environments/)
1. [How GitOps and Operators mark the rise of Infrastructure-As-Software](https://paytmlabs.com/blog/2021/10/how-to-improve-operational-work-with-operators-and-gitops/)

View File

@@ -1,6 +1,6 @@
# Security Policy for Argo CD
Version: **v1.2 (2020-08-07)**
Version: **v1.1 (2020-06-29)**
## Preface
@@ -56,11 +56,13 @@ We will do our best to react quickly on your inquiry, and to coordinate a fix
and disclosure with you. Sometimes, it might take a little longer for us to
react (e.g. out of office conditions), so please bear with us in these cases.
We will publish security advisiories using the
[Git Hub Security Advisories](https://github.com/argoproj/argo-cd/security/advisories)
feature to keep our community well informed, and will credit you for your
findings (unless you prefer to stay anonymous, of course).
We will publish security advisiories using the Git Hub SA feature to keep our
community well informed, and will credit you for your findings (unless you
prefer to stay anonymous, of course).
Please report vulnerabilities by e-mail to the following address:
Please report vulnerabilities by e-mail to all of the following people:
* cncf-argo-security@lists.cncf.io
* jfischer@redhat.com
* Jesse_Suen@intuit.com
* Alexander_Matyushentsev@intuit.com
* Edward_Lee@intuit.com

View File

@@ -9,7 +9,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [7shifts](https://www.7shifts.com/)
1. [Adevinta](https://www.adevinta.com/)
1. [Adventure](https://jp.adventurekk.com/)
1. [Akuity](https://akuity.io/)
1. [Alibaba Group](https://www.alibabagroup.com/)
1. [Ambassador Labs](https://www.getambassador.io/)
1. [Ant Group](https://www.antgroup.com/)
@@ -23,17 +22,15 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Beat](https://thebeat.co/en/)
1. [Beez Innovation Labs](https://www.beezlabs.com/)
1. [BioBox Analytics](https://biobox.io)
1. [BigPanda](https://bigpanda.io)
1. [BMW Group](https://www.bmwgroup.com/)
1. [Camptocamp](https://camptocamp.com)
1. [Capital One](https://www.capitalone.com)
1. [CARFAX](https://www.carfax.com)
1. [Celonis](https://www.celonis.com/)
1. [Chime](https://www.chime.com)
1. [Codefresh](https://www.codefresh.io/)
1. [Codility](https://www.codility.com/)
1. [Commonbond](https://commonbond.co/)
1. [Crédit Agricole CIB](https://www.ca-cib.com)
1. [Crédit Agricole](https://www.ca-cib.com)
1. [CROZ d.o.o.](https://croz.net/)
1. [CyberAgent](https://www.cyberagent.co.jp/en/)
1. [Cybozu](https://cybozu-global.com)
@@ -51,7 +48,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Garner](https://www.garnercorp.com)
1. [G DATA CyberDefense AG](https://www.gdata-software.com/)
1. [Generali Deutschland AG](https://www.generali.de/)
1. [Gitpod](https://www.gitpod.io)
1. [Glovo](https://www.glovoapp.com)
1. [GMETRI](https://gmetri.com/)
1. [Gojek](https://www.gojek.io/)
@@ -62,14 +58,12 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Hiya](https://hiya.com)
1. [Honestbank](https://honestbank.com)
1. [IBM](https://www.ibm.com/)
1. [IITS-Consulting](https://iits-consulting.de)
1. [Index Exchange](https://www.indexexchange.com/)
1. [InsideBoard](https://www.insideboard.com)
1. [Intuit](https://www.intuit.com/)
1. [Joblift](https://joblift.com/)
1. [JovianX](https://www.jovianx.com/)
1. [Karrot](https://www.daangn.com/)
1. [KarrotPay](https://www.daangnpay.com/)
1. [Kasa](https://kasa.co.kr/)
1. [Keptn](https://keptn.sh)
1. [Kinguin](https://www.kinguin.net/)
@@ -80,11 +74,9 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Lytt](https://www.lytt.co/)
1. [Major League Baseball](https://mlb.com)
1. [Mambu](https://www.mambu.com/)
1. [Mattermost](https://www.mattermost.com)
1. [Max Kelsen](https://www.maxkelsen.com/)
1. [MindSpore](https://mindspore.cn)
1. [Mirantis](https://mirantis.com/)
1. [mixi Group](https://mixi.co.jp/)
1. [Moengage](https://www.moengage.com/)
1. [Money Forward](https://corp.moneyforward.com/en/)
1. [MOO Print](https://www.moo.com/)
@@ -101,7 +93,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Opensurvey](https://www.opensurvey.co.kr/)
1. [Optoro](https://www.optoro.com/)
1. [Orbital Insight](https://orbitalinsight.com/)
1. [Packlink](https://www.packlink.com/)
1. [PayPay](https://paypay.ne.jp/)
1. [Peloton Interactive](https://www.onepeloton.com/)
1. [Pipefy](https://www.pipefy.com/)
@@ -119,11 +110,9 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Saildrone](https://www.saildrone.com/)
1. [Saloodo! GmbH](https://www.saloodo.com)
1. [Schwarz IT](https://jobs.schwarz/it-mission)
1. [Snyk](https://snyk.io/)
1. [Speee](https://speee.jp/)
1. [Spendesk](https://spendesk.com/)
1. [Sumo Logic](https://sumologic.com/)
1. [Sutpc](http://www.sutpc.com/)
1. [Swisscom](https://www.swisscom.ch)
1. [Swissquote](https://github.com/swissquote)
1. [Syncier](https://syncier.com/)
@@ -133,12 +122,10 @@ Currently, the following organizations are **officially** using Argo CD:
1. [ThousandEyes](https://www.thousandeyes.com/)
1. [Ticketmaster](https://ticketmaster.com)
1. [Tiger Analytics](https://www.tigeranalytics.com/)
1. [Tigera](https://www.tigera.io/)
1. [Toss](https://toss.im/en)
1. [tru.ID](https://tru.id)
1. [Twilio SendGrid](https://sendgrid.com)
1. [tZERO](https://www.tzero.com/)
1. [ungleich.ch](https://ungleich.ch/)
1. [UBIO](https://ub.io/)
1. [UFirstGroup](https://www.ufirstgroup.com/en/)
1. [Universidad Mesoamericana](https://www.umes.edu.gt/)
@@ -148,7 +135,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Volvo Cars](https://www.volvocars.com/)
1. [VSHN - The DevOps Company](https://vshn.ch/)
1. [Walkbase](https://www.walkbase.com/)
1. [Wehkamp](https://www.wehkamp.nl/)
1. [WeMo Scooter](https://www.wemoscooter.com/)
1. [Webstores](https://www.webstores.nl)
1. [Whitehat Berlin](https://whitehat.berlin) by Guido Maria Serra +Fenaroli
@@ -168,13 +154,4 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Beleza Na Web](https://www.belezanaweb.com.br/)
1. [MariaDB](https://mariadb.com)
1. [Lightricks](https://www.lightricks.com/)
1. [RightRev](https://rightrev.com/)
1. [MeDirect](https://medirect.com.mt/)
1. [Snapp](https://snapp.ir/)
1. [Technacy](https://www.technacy.it/)
1. [freee](https://corp.freee.co.jp/en/company/)
1. [Youverify](https://youverify.co/)
1. [Keeeb](https://www.keeeb.com/)
1. [p3r](https://www.p3r.one/)
1. [Faro](https://www.faro.com/)
1. [Rise](https://www.risecard.eu/)
1. [Snapp](https://snapp.ir/)

View File

@@ -1 +1 @@
2.2.16
2.1.16

View File

@@ -11,4 +11,4 @@ g = _, _
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
[matchers]
m = g(r.sub, p.sub) && globOrRegexMatch(r.res, p.res) && globOrRegexMatch(r.act, p.act) && globOrRegexMatch(r.obj, p.obj)
m = g(r.sub, p.sub) && globMatch(r.res, p.res) && globMatch(r.act, p.act) && globMatch(r.obj, p.obj)

View File

@@ -753,11 +753,6 @@
"type": "string",
"name": "resourceName",
"in": "query"
},
{
"type": "boolean",
"name": "previous",
"in": "query"
}
],
"responses": {
@@ -937,11 +932,6 @@
"type": "string",
"name": "resourceName",
"in": "query"
},
{
"type": "boolean",
"name": "previous",
"in": "query"
}
],
"responses": {
@@ -2091,37 +2081,6 @@
}
}
},
"/api/v1/projects/{name}/detailed": {
"get": {
"tags": [
"ProjectService"
],
"summary": "GetDetailedProject returns a project that include project, global project and scoped resources by name",
"operationId": "ProjectService_GetDetailedProject",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/projectDetailedProjectsResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
}
}
},
"/api/v1/projects/{name}/events": {
"get": {
"tags": [
@@ -2914,12 +2873,6 @@
"description": "HTTP/HTTPS proxy to access the repository.",
"name": "proxy",
"in": "query"
},
{
"type": "string",
"description": "Reference between project and repository that allow you automatically to be added as item inside SourceRepos project entity.",
"name": "project",
"in": "query"
}
],
"responses": {
@@ -3680,18 +3633,9 @@
"statusBadgeEnabled": {
"type": "boolean"
},
"trackingMethod": {
"type": "string"
},
"uiBannerContent": {
"type": "string"
},
"uiBannerPermanent": {
"type": "boolean"
},
"uiBannerPosition": {
"type": "string"
},
"uiBannerURL": {
"type": "string"
},
@@ -3743,32 +3687,6 @@
}
}
},
"projectDetailedProjectsResponse": {
"type": "object",
"properties": {
"clusters": {
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1Cluster"
}
},
"globalProjects": {
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1AppProject"
}
},
"project": {
"$ref": "#/definitions/v1alpha1AppProject"
},
"repositories": {
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1Repository"
}
}
}
},
"projectEmptyResponse": {
"type": "object"
},
@@ -4381,10 +4299,6 @@
"description": "Operation is the type of operation which lead to this ManagedFieldsEntry being created.\nThe only valid values for this field are 'Apply' and 'Update'.",
"type": "string"
},
"subresource": {
"description": "Subresource is the name of the subresource used to update that object, or\nempty string if the object was updated through the main resource. The\nvalue of this field is used to distinguish between managers, even if they\nshare the same name. For example, a status update will be distinct from a\nregular update using the same manager name.\nNote that the APIVersion field is not related to the Subresource field and\nit always corresponds to the version of the main resource.",
"type": "string"
},
"time": {
"$ref": "#/definitions/v1Time"
}
@@ -4539,7 +4453,7 @@
},
"v1ObjectReference": {
"type": "object",
"title": "ObjectReference contains enough information to let you inspect or modify the referred object.\n---\nNew uses of this type are discouraged because of difficulty describing its usage when embedded in APIs.\n 1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage.\n 2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular\n restrictions like, \"must refer only to types A and B\" or \"UID not honored\" or \"name must be restricted\".\n Those cannot be well described when embedded.\n 3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen.\n 4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity\n during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple\n and the version of the actual struct is irrelevant.\n 5. We cannot easily change it. Because this type is embedded in many locations, updates to this type\n will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.\nInstead of using this type, create a locally provided and used type that is well-focused on your reference.\nFor example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .\n+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object\n+structType=atomic",
"title": "ObjectReference contains enough information to let you inspect or modify the referred object.\n---\nNew uses of this type are discouraged because of difficulty describing its usage when embedded in APIs.\n 1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage.\n 2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular\n restrictions like, \"must refer only to types A and B\" or \"UID not honored\" or \"name must be restricted\".\n Those cannot be well described when embedded.\n 3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen.\n 4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity\n during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple\n and the version of the actual struct is irrelevant.\n 5. We cannot easily change it. Because this type is embedded in many locations, updates to this type\n will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.\nInstead of using this type, create a locally provided and used type that is well-focused on your reference.\nFor example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .\n+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object",
"properties": {
"apiVersion": {
"type": "string",
@@ -4572,8 +4486,8 @@
}
},
"v1OwnerReference": {
"description": "OwnerReference contains enough information to let you identify an owning\nobject. An owning object must be in the same namespace as the dependent, or\nbe cluster-scoped, so there is no namespace field.",
"type": "object",
"title": "OwnerReference contains enough information to let you identify an owning\nobject. An owning object must be in the same namespace as the dependent, or\nbe cluster-scoped, so there is no namespace field.\n+structType=atomic",
"properties": {
"apiVersion": {
"description": "API version of the referent.",
@@ -4912,10 +4826,6 @@
"$ref": "#/definitions/v1alpha1HelmParameter"
}
},
"passCredentials": {
"type": "boolean",
"title": "PassCredentials pass credentials to all domains (Helm's --pass-credentials)"
},
"releaseName": {
"type": "string",
"title": "ReleaseName is the Helm release name to use. If omitted it will use the application name"
@@ -5212,13 +5122,6 @@
"type": "object",
"title": "Cluster is the definition of a cluster resource",
"properties": {
"annotations": {
"type": "object",
"title": "Annotations for cluster secret metadata",
"additionalProperties": {
"type": "string"
}
},
"clusterResources": {
"description": "Indicates if cluster level resources should be managed. This setting is used only if cluster is connected in a namespaced mode.",
"type": "boolean"
@@ -5232,13 +5135,6 @@
"info": {
"$ref": "#/definitions/v1alpha1ClusterInfo"
},
"labels": {
"type": "object",
"title": "Labels for cluster secret metadata",
"additionalProperties": {
"type": "string"
}
},
"name": {
"type": "string",
"title": "Name of the cluster. If omitted, will use the server address"
@@ -5250,10 +5146,6 @@
"type": "string"
}
},
"project": {
"type": "string",
"title": "Reference between project and cluster that allow you automatically to be added as item inside Destinations project entity"
},
"refreshRequestedAt": {
"$ref": "#/definitions/v1Time"
},
@@ -5400,9 +5292,6 @@
"init": {
"$ref": "#/definitions/v1alpha1Command"
},
"lockRepo": {
"type": "boolean"
},
"name": {
"type": "string"
}
@@ -5973,10 +5862,6 @@
"type": "string",
"title": "Password contains the password or PAT used for authenticating at the remote repository"
},
"project": {
"type": "string",
"title": "Reference between project and repository that allow you automatically to be added as item inside SourceRepos project entity"
},
"proxy": {
"type": "string",
"title": "Proxy specifies the HTTP/HTTPS proxy used to access the repo"
@@ -6665,10 +6550,6 @@
"schedule": {
"type": "string",
"title": "Schedule is the time the window will begin, specified in cron format"
},
"timeZone": {
"type": "string",
"title": "TimeZone of the sync that will be applied to the schedule"
}
}
},

View File

@@ -49,7 +49,6 @@ func NewCommand() *cobra.Command {
glogLevel int
metricsPort int
metricsCacheExpiration time.Duration
metricsAplicationLabels []string
kubectlParallelismLimit int64
cacheSrc func() (*appstatecache.Cache, error)
redisClient *redis.Client
@@ -111,14 +110,10 @@ func NewCommand() *cobra.Command {
errors.CheckError(err)
cache.Cache.SetClient(cacheutil.NewTwoLevelClient(cache.Cache.GetClient(), 10*time.Minute))
var appController *controller.ApplicationController
settingsMgr := settings.NewSettingsManager(ctx, kubeClient, namespace, settings.WithRepoOrClusterChangedHandler(func() {
appController.InvalidateProjectsCache()
}))
settingsMgr := settings.NewSettingsManager(ctx, kubeClient, namespace)
kubectl := kubeutil.NewKubectl()
clusterFilter := getClusterFilter()
appController, err = controller.NewApplicationController(
appController, err := controller.NewApplicationController(
namespace,
settingsMgr,
kubeClient,
@@ -130,7 +125,6 @@ func NewCommand() *cobra.Command {
time.Duration(selfHealTimeoutSeconds)*time.Second,
metricsPort,
metricsCacheExpiration,
metricsAplicationLabels,
kubectlParallelismLimit,
clusterFilter)
errors.CheckError(err)
@@ -164,7 +158,6 @@ func NewCommand() *cobra.Command {
command.Flags().Int64Var(&kubectlParallelismLimit, "kubectl-parallelism-limit", 20, "Number of allowed concurrent kubectl fork/execs. Any value less the 1 means no limit.")
command.Flags().BoolVar(&repoServerPlaintext, "repo-server-plaintext", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_PLAINTEXT", false), "Disable TLS on connections to repo server")
command.Flags().BoolVar(&repoServerStrictTLS, "repo-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_STRICT_TLS", false), "Whether to use strict validation of the TLS cert presented by the repo server")
command.Flags().StringSliceVar(&metricsAplicationLabels, "metrics-application-labels", []string{}, "List of Application labels that will be added to the argocd_application_labels metric")
cacheSrc = appstatecache.AddCacheFlagsToCmd(&command, func(client *redis.Client) {
redisClient = client
})

View File

@@ -1,58 +0,0 @@
package commands
import (
"time"
"github.com/argoproj/pkg/stats"
"github.com/spf13/cobra"
cmdutil "github.com/argoproj/argo-cd/v2/cmd/util"
"github.com/argoproj/argo-cd/v2/cmpserver"
"github.com/argoproj/argo-cd/v2/cmpserver/plugin"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/util/cli"
"github.com/argoproj/argo-cd/v2/util/errors"
)
const (
// CLIName is the name of the CLI
cliName = "argocd-cmp-server"
)
func NewCommand() *cobra.Command {
var (
configFilePath string
)
var command = cobra.Command{
Use: cliName,
Short: "Run ArgoCD ConfigManagementPlugin Server",
Long: "ArgoCD ConfigManagementPlugin Server is an internal service which runs as sidecar container in reposerver deployment. It can be configured by following options.",
DisableAutoGenTag: true,
RunE: func(c *cobra.Command, args []string) error {
cli.SetLogFormat(cmdutil.LogFormat)
cli.SetLogLevel(cmdutil.LogLevel)
config, err := plugin.ReadPluginConfig(configFilePath)
errors.CheckError(err)
server, err := cmpserver.NewServer(plugin.CMPServerInitConstants{
PluginConfig: *config,
})
errors.CheckError(err)
// register dumper
stats.RegisterStackDumper()
stats.StartStatsTicker(10 * time.Minute)
stats.RegisterHeapDumper("memprofile")
// run argocd-cmp-server server
server.Run()
return nil
},
}
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")
command.Flags().StringVar(&configFilePath, "config-dir-path", common.DefaultPluginConfigFilePath, "Config management plugin configuration file location, Default is '/home/argocd/cmp-server/config/'")
return &command
}

View File

@@ -54,19 +54,7 @@ func NewAccountUpdatePasswordCommand(clientOpts *argocdclient.ClientOptions) *co
)
var command = &cobra.Command{
Use: "update-password",
Short: "Update an account's password",
Long: `
This command can be used to update the password of the currently logged on
user, or an arbitrary local user account when the currently logged on user
has appropriate RBAC permissions to change other accounts.
`,
Example: `
# Update the current user's password
argocd account update-password
# Update the password for user foobar
argocd account update-password --account foobar
`,
Short: "Update password",
Run: func(c *cobra.Command, args []string) {
if len(args) != 0 {
c.HelpFunc()(c, args)
@@ -79,20 +67,16 @@ has appropriate RBAC permissions to change other accounts.
userInfo := getCurrentAccount(acdClient)
if userInfo.Iss == sessionutil.SessionManagerClaimsIssuer && currentPassword == "" {
fmt.Printf("*** Enter password of currently logged in user (%s): ", userInfo.Username)
fmt.Print("*** Enter current password: ")
password, err := term.ReadPassword(int(os.Stdin.Fd()))
errors.CheckError(err)
currentPassword = string(password)
fmt.Print("\n")
}
if account == "" {
account = userInfo.Username
}
if newPassword == "" {
var err error
newPassword, err = cli.ReadAndConfirmPassword(account)
newPassword, err = cli.ReadAndConfirmPassword()
errors.CheckError(err)
}
@@ -127,7 +111,7 @@ has appropriate RBAC permissions to change other accounts.
},
}
command.Flags().StringVar(&currentPassword, "current-password", "", "password of the currently logged on user")
command.Flags().StringVar(&currentPassword, "current-password", "", "current password you wish to change")
command.Flags().StringVar(&newPassword, "new-password", "", "new password you want to update to")
command.Flags().StringVar(&account, "account", "", "an account name that should be updated. Defaults to current user account")
return command

View File

@@ -10,8 +10,6 @@ import (
"sort"
"time"
"github.com/argoproj/argo-cd/v2/util/argo"
"github.com/ghodss/yaml"
"github.com/spf13/cobra"
apiv1 "k8s.io/api/core/v1"
@@ -90,12 +88,9 @@ func NewGenAppSpecCommand() *cobra.Command {
argocd admin app generate-spec ksane --repo https://github.com/argoproj/argocd-example-apps.git --path plugins/kasane --dest-namespace default --dest-server https://kubernetes.default.svc --config-management-plugin kasane
`,
Run: func(c *cobra.Command, args []string) {
apps, err := cmdutil.ConstructApps(fileURL, appName, labels, annotations, args, appOpts, c.Flags())
app, err := cmdutil.ConstructApp(fileURL, appName, labels, annotations, args, appOpts, c.Flags())
errors.CheckError(err)
if len(apps) > 1 {
errors.CheckError(fmt.Errorf("failed to generate spec, more than one application is not supported"))
}
app := apps[0]
if app.Name == "" {
c.HelpFunc()(c, args)
os.Exit(1)
@@ -334,11 +329,11 @@ func reconcileApplications(
settingsMgr := settings.NewSettingsManager(context.Background(), kubeClientset, namespace)
argoDB := db.NewDB(namespace, settingsMgr, kubeClientset)
appInformerFactory := appinformers.NewSharedInformerFactoryWithOptions(
appInformerFactory := appinformers.NewFilteredSharedInformerFactory(
appClientset,
1*time.Hour,
appinformers.WithNamespace(namespace),
appinformers.WithTweakListOptions(func(options *v1.ListOptions) {}),
namespace,
func(options *v1.ListOptions) {},
)
appInformer := appInformerFactory.Argoproj().V1alpha1().Applications().Informer()
@@ -355,7 +350,7 @@ func reconcileApplications(
return true
}, func(r *http.Request) error {
return nil
}, []string{})
})
if err != nil {
return nil, err
@@ -371,7 +366,7 @@ func reconcileApplications(
)
appStateManager := controller.NewAppStateManager(
argoDB, appClientset, repoServerClient, namespace, kubeutil.NewKubectl(), settingsMgr, stateCache, projInformer, server, cache, time.Second, argo.NewResourceTracking())
argoDB, appClientset, repoServerClient, namespace, kubeutil.NewKubectl(), settingsMgr, stateCache, projInformer, server, cache, time.Second)
appsList, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(context.Background(), v1.ListOptions{LabelSelector: selector})
if err != nil {
@@ -413,5 +408,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) {}, nil)
}

View File

@@ -35,7 +35,6 @@ import (
"github.com/argoproj/argo-cd/v2/util/glob"
kubeutil "github.com/argoproj/argo-cd/v2/util/kube"
"github.com/argoproj/argo-cd/v2/util/settings"
"github.com/argoproj/argo-cd/v2/util/text/label"
)
func NewClusterCommand(pathOpts *clientcmd.PathOptions) *cobra.Command {
@@ -509,8 +508,6 @@ func NewGenClusterConfigCommand(pathOpts *clientcmd.PathOptions) *cobra.Command
bearerToken string
generateToken bool
outputFormat string
labels []string
annotations []string
)
var command = &cobra.Command{
Use: "generate-spec CONTEXT",
@@ -564,13 +561,7 @@ func NewGenClusterConfigCommand(pathOpts *clientcmd.PathOptions) *cobra.Command
if clusterOpts.Name != "" {
contextName = clusterOpts.Name
}
labelsMap, err := label.Parse(labels)
errors.CheckError(err)
annotationsMap, err := label.Parse(annotations)
errors.CheckError(err)
clst := cmdutil.NewCluster(contextName, clusterOpts.Namespaces, clusterOpts.ClusterResources, conf, bearerToken, awsAuthConf, execProviderConf, labelsMap, annotationsMap)
clst := cmdutil.NewCluster(contextName, clusterOpts.Namespaces, clusterOpts.ClusterResources, conf, bearerToken, awsAuthConf, execProviderConf)
if clusterOpts.InCluster {
clst.Server = argoappv1.KubernetesInternalAPIServerAddr
}
@@ -599,8 +590,6 @@ func NewGenClusterConfigCommand(pathOpts *clientcmd.PathOptions) *cobra.Command
command.Flags().StringVar(&clusterOpts.ServiceAccount, "service-account", "argocd-manager", fmt.Sprintf("System namespace service account to use for kubernetes resource management. If not set then default \"%s\" SA will be used", clusterauth.ArgoCDManagerServiceAccount))
command.Flags().StringVar(&clusterOpts.SystemNamespace, "system-namespace", common.DefaultSystemNamespace, "Use different system namespace")
command.Flags().StringVarP(&outputFormat, "output", "o", "yaml", "Output format. One of: json|yaml")
command.Flags().StringArrayVar(&labels, "label", nil, "Set metadata labels (e.g. --label key=value)")
command.Flags().StringArrayVar(&annotations, "annotation", nil, "Set metadata annotations (e.g. --annotation key=value)")
cmdutil.AddClusterFlags(command, &clusterOpts)
return command
}
@@ -609,7 +598,7 @@ func GenerateToken(clusterOpts cmdutil.ClusterOptions, conf *rest.Config) (strin
clientset, err := kubernetes.NewForConfig(conf)
errors.CheckError(err)
bearerToken, err := clusterauth.GetServiceAccountBearerToken(clientset, clusterOpts.SystemNamespace, clusterOpts.ServiceAccount, common.BearerTokenTimeout)
bearerToken, err := clusterauth.GetServiceAccountBearerToken(clientset, clusterOpts.SystemNamespace, clusterOpts.ServiceAccount)
if err != nil {
return "", err
}

View File

@@ -401,7 +401,7 @@ argocd admin settings resource-overrides ignore-differences ./deploy.yaml --argo
executeResourceOverrideCommand(cmdCtx, args, func(res unstructured.Unstructured, override v1alpha1.ResourceOverride, overrides map[string]v1alpha1.ResourceOverride) {
gvk := res.GroupVersionKind()
if len(override.IgnoreDifferences.JSONPointers) == 0 && len(override.IgnoreDifferences.JQPathExpressions) == 0 {
if len(override.IgnoreDifferences.JSONPointers) == 0 {
_, _ = fmt.Printf("Ignore differences are not configured for '%s/%s'\n", gvk.Group, gvk.Kind)
return
}

View File

@@ -14,8 +14,6 @@ import (
"time"
"unicode/utf8"
"github.com/argoproj/gitops-engine/pkg/sync/common"
"github.com/argoproj/gitops-engine/pkg/diff"
"github.com/argoproj/gitops-engine/pkg/health"
"github.com/argoproj/gitops-engine/pkg/sync/hook"
@@ -51,6 +49,7 @@ import (
"github.com/argoproj/argo-cd/v2/util/errors"
"github.com/argoproj/argo-cd/v2/util/git"
argoio "github.com/argoproj/argo-cd/v2/util/io"
argokube "github.com/argoproj/argo-cd/v2/util/kube"
"github.com/argoproj/argo-cd/v2/util/templates"
"github.com/argoproj/argo-cd/v2/util/text/label"
)
@@ -94,7 +93,6 @@ func NewApplicationCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comman
command.AddCommand(NewApplicationEditCommand(clientOpts))
command.AddCommand(NewApplicationPatchCommand(clientOpts))
command.AddCommand(NewApplicationPatchResourceCommand(clientOpts))
command.AddCommand(NewApplicationDeleteResourceCommand(clientOpts))
command.AddCommand(NewApplicationResourceActionsCommand(clientOpts))
command.AddCommand(NewApplicationListResourcesCommand(clientOpts))
command.AddCommand(NewApplicationLogsCommand(clientOpts))
@@ -136,27 +134,24 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
Run: func(c *cobra.Command, args []string) {
argocdClient := argocdclient.NewClientOrDie(clientOpts)
apps, err := cmdutil.ConstructApps(fileURL, appName, labels, annotations, args, appOpts, c.Flags())
app, err := cmdutil.ConstructApp(fileURL, appName, labels, annotations, args, appOpts, c.Flags())
errors.CheckError(err)
for _, app := range apps {
if app.Name == "" {
c.HelpFunc()(c, args)
os.Exit(1)
}
conn, appIf := argocdClient.NewApplicationClientOrDie()
defer argoio.Close(conn)
appCreateRequest := applicationpkg.ApplicationCreateRequest{
Application: *app,
Upsert: &upsert,
Validate: &appOpts.Validate,
}
created, err := appIf.Create(context.Background(), &appCreateRequest)
errors.CheckError(err)
fmt.Printf("application '%s' created\n", created.ObjectMeta.Name)
if app.Name == "" {
c.HelpFunc()(c, args)
os.Exit(1)
}
conn, appIf := argocdClient.NewApplicationClientOrDie()
defer argoio.Close(conn)
appCreateRequest := applicationpkg.ApplicationCreateRequest{
Application: *app,
Upsert: &upsert,
Validate: &appOpts.Validate,
}
created, err := appIf.Create(context.Background(), &appCreateRequest)
errors.CheckError(err)
fmt.Printf("application '%s' created\n", created.ObjectMeta.Name)
},
}
command.Flags().StringVar(&appName, "name", "", "A name for the app, ignored if a file is set (DEPRECATED)")
@@ -672,10 +667,6 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
}
}
}
if app.Spec.Source.Helm.PassCredentials {
app.Spec.Source.Helm.PassCredentials = false
updated = true
}
}
if app.Spec.Source.Plugin != nil {
@@ -742,8 +733,8 @@ func liveObjects(resources []*argoappv1.ResourceDiff) ([]*unstructured.Unstructu
}
func getLocalObjects(app *argoappv1.Application, local, localRepoRoot, appLabelKey, kubeVersion string, kustomizeOptions *argoappv1.KustomizeOptions,
configManagementPlugins []*argoappv1.ConfigManagementPlugin, trackingMethod string) []*unstructured.Unstructured {
manifestStrings := getLocalObjectsString(app, local, localRepoRoot, appLabelKey, kubeVersion, kustomizeOptions, configManagementPlugins, trackingMethod)
configManagementPlugins []*argoappv1.ConfigManagementPlugin) []*unstructured.Unstructured {
manifestStrings := getLocalObjectsString(app, local, localRepoRoot, appLabelKey, kubeVersion, kustomizeOptions, configManagementPlugins)
objs := make([]*unstructured.Unstructured, len(manifestStrings))
for i := range manifestStrings {
obj := unstructured.Unstructured{}
@@ -755,7 +746,7 @@ func getLocalObjects(app *argoappv1.Application, local, localRepoRoot, appLabelK
}
func getLocalObjectsString(app *argoappv1.Application, local, localRepoRoot, appLabelKey, kubeVersion string, kustomizeOptions *argoappv1.KustomizeOptions,
configManagementPlugins []*argoappv1.ConfigManagementPlugin, trackingMethod string) []string {
configManagementPlugins []*argoappv1.ConfigManagementPlugin) []string {
res, err := repository.GenerateManifests(local, localRepoRoot, app.Spec.Source.TargetRevision, &repoapiclient.ManifestRequest{
Repo: &argoappv1.Repository{Repo: app.Spec.Source.RepoURL},
@@ -766,7 +757,6 @@ func getLocalObjectsString(app *argoappv1.Application, local, localRepoRoot, app
KustomizeOptions: kustomizeOptions,
KubeVersion: kubeVersion,
Plugins: configManagementPlugins,
TrackingMethod: trackingMethod,
}, true, resource.MustParse("0"))
errors.CheckError(err)
@@ -852,7 +842,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
defer argoio.Close(conn)
cluster, err := clusterIf.Get(context.Background(), &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server})
errors.CheckError(err)
localObjs := groupObjsByKey(getLocalObjects(app, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod), liveObjs, app.Spec.Destination.Namespace)
localObjs := groupObjsByKey(getLocalObjects(app, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins), liveObjs, app.Spec.Destination.Namespace)
items = groupObjsForDiff(resources, localObjs, items, argoSettings, appName)
} else if revision != "" {
var unstructureds []*unstructured.Unstructured
@@ -934,7 +924,6 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
}
func groupObjsForDiff(resources *application.ManagedResourcesResponse, objs map[kube.ResourceKey]*unstructured.Unstructured, items []objKeyLiveTarget, argoSettings *settings.Settings, appName string) []objKeyLiveTarget {
resourceTracking := argo.NewResourceTracking()
for _, res := range resources.Items {
var live = &unstructured.Unstructured{}
err := json.Unmarshal([]byte(res.NormalizedLiveState), &live)
@@ -948,7 +937,7 @@ func groupObjsForDiff(resources *application.ManagedResourcesResponse, objs map[
}
if local, ok := objs[key]; ok || live != nil {
if local != nil && !kube.IsCRD(local) {
err = resourceTracking.SetAppInstance(local, argoSettings.AppLabelKey, appName, "", argoappv1.TrackingMethod(argoSettings.GetTrackingMethod()))
err = argokube.SetAppInstanceLabel(local, argoSettings.AppLabelKey, appName)
errors.CheckError(err)
}
@@ -1281,7 +1270,6 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
timeout uint
strategy string
force bool
replace bool
async bool
retryLimit int64
retryBackoffDuration time.Duration
@@ -1389,35 +1377,18 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
cluster, err := clusterIf.Get(context.Background(), &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server})
errors.CheckError(err)
argoio.Close(conn)
localObjsStrings = getLocalObjectsString(app, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod)
}
syncOptionsFactory := func() *applicationpkg.SyncOptions {
syncOptions := applicationpkg.SyncOptions{}
items := make([]string, 0)
if replace {
items = append(items, common.SyncOptionReplace)
}
if len(items) == 0 {
// for prevent send even empty array if not need
return nil
}
syncOptions.Items = items
return &syncOptions
localObjsStrings = getLocalObjectsString(app, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins)
}
syncReq := applicationpkg.ApplicationSyncRequest{
Name: &appName,
DryRun: dryRun,
Revision: revision,
Resources: selectedResources,
Prune: prune,
Manifests: localObjsStrings,
Infos: getInfos(infos),
SyncOptions: syncOptionsFactory(),
Name: &appName,
DryRun: dryRun,
Revision: revision,
Resources: selectedResources,
Prune: prune,
Manifests: localObjsStrings,
Infos: getInfos(infos),
}
switch strategy {
case "apply":
syncReq.Strategy = &argoappv1.SyncStrategy{Apply: &argoappv1.SyncStrategyApply{}}
@@ -1474,7 +1445,6 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
command.Flags().Int64Var(&retryBackoffFactor, "retry-backoff-factor", argoappv1.DefaultSyncRetryFactor, "Factor multiplies the base duration after each failed retry")
command.Flags().StringVar(&strategy, "strategy", "", "Sync strategy (one of: apply|hook)")
command.Flags().BoolVar(&force, "force", false, "Use a force apply")
command.Flags().BoolVar(&replace, "replace", false, "Use a kubectl create/replace instead apply")
command.Flags().BoolVar(&async, "async", false, "Do not wait for application to sync before continuing")
command.Flags().StringVar(&local, "local", "", "Path to a local directory. When this flag is present no git queries will be made")
command.Flags().StringVar(&localRepoRoot, "local-repo-root", "/", "Path to the repository root. Used together with --local allows setting the repository root")
@@ -2233,59 +2203,3 @@ func NewApplicationPatchResourceCommand(clientOpts *argocdclient.ClientOptions)
return command
}
func NewApplicationDeleteResourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var resourceName string
var namespace string
var kind string
var group string
var force bool
var orphan bool
var all bool
command := &cobra.Command{
Use: "delete-resource APPNAME",
Short: "Delete resource in an application",
}
command.Flags().StringVar(&resourceName, "resource-name", "", "Name of resource")
command.Flags().StringVar(&kind, "kind", "", "Kind")
err := command.MarkFlagRequired("kind")
errors.CheckError(err)
command.Flags().StringVar(&group, "group", "", "Group")
command.Flags().StringVar(&namespace, "namespace", "", "Namespace")
command.Flags().BoolVar(&force, "force", false, "Indicates whether to orphan the dependents of the deleted resource")
command.Flags().BoolVar(&orphan, "orphan", false, "Indicates whether to force delete the resource")
command.Flags().BoolVar(&all, "all", false, "Indicates whether to patch multiple matching of resources")
command.Run = func(c *cobra.Command, args []string) {
if len(args) != 1 {
c.HelpFunc()(c, args)
os.Exit(1)
}
appName := args[0]
conn, appIf := argocdclient.NewClientOrDie(clientOpts).NewApplicationClientOrDie()
defer argoio.Close(conn)
ctx := context.Background()
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{ApplicationName: &appName})
errors.CheckError(err)
objectsToDelete := filterResources(command, resources.Items, group, kind, namespace, resourceName, all)
for i := range objectsToDelete {
obj := objectsToDelete[i]
gvk := obj.GroupVersionKind()
_, err = appIf.DeleteResource(ctx, &applicationpkg.ApplicationResourceDeleteRequest{
Name: &appName,
Namespace: obj.GetNamespace(),
ResourceName: obj.GetName(),
Version: gvk.Version,
Group: gvk.Group,
Kind: gvk.Kind,
Force: &force,
Orphan: &orphan,
})
errors.CheckError(err)
log.Infof("Resource '%s' deleted", obj.GetName())
}
}
return command
}

View File

@@ -4,18 +4,13 @@ import (
"context"
"fmt"
"os"
"regexp"
"strings"
"text/tabwriter"
"github.com/mattn/go-isatty"
"k8s.io/client-go/kubernetes"
"github.com/argoproj/argo-cd/v2/util/cli"
"github.com/argoproj/argo-cd/v2/util/text/label"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
cmdutil "github.com/argoproj/argo-cd/v2/cmd/util"
@@ -23,6 +18,7 @@ import (
argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient"
clusterpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster"
argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/cli"
"github.com/argoproj/argo-cd/v2/util/clusterauth"
"github.com/argoproj/argo-cd/v2/util/errors"
"github.com/argoproj/argo-cd/v2/util/io"
@@ -64,8 +60,6 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
var (
clusterOpts cmdutil.ClusterOptions
skipConfirmation bool
labels []string
annotations []string
)
var command = &cobra.Command{
Use: "add CONTEXT",
@@ -122,41 +116,24 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
clientset, err := kubernetes.NewForConfig(conf)
errors.CheckError(err)
if clusterOpts.ServiceAccount != "" {
managerBearerToken, err = clusterauth.GetServiceAccountBearerToken(clientset, clusterOpts.SystemNamespace, clusterOpts.ServiceAccount, common.BearerTokenTimeout)
managerBearerToken, err = clusterauth.GetServiceAccountBearerToken(clientset, clusterOpts.SystemNamespace, clusterOpts.ServiceAccount)
} else {
isTerminal := isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd())
if isTerminal && !skipConfirmation {
message := fmt.Sprintf("WARNING: This will create a service account `argocd-manager` on the cluster referenced by context `%s` with full cluster level admin privileges. Do you want to continue [y/N]? ", contextName)
if !cli.AskToProceed(message) {
os.Exit(1)
}
}
managerBearerToken, err = clusterauth.InstallClusterManagerRBAC(clientset, clusterOpts.SystemNamespace, clusterOpts.Namespaces, common.BearerTokenTimeout)
managerBearerToken, err = clusterauth.InstallClusterManagerRBAC(clientset, clusterOpts.SystemNamespace, clusterOpts.Namespaces)
}
errors.CheckError(err)
}
labelsMap, err := label.Parse(labels)
errors.CheckError(err)
annotationsMap, err := label.Parse(annotations)
errors.CheckError(err)
conn, clusterIf := argocdclient.NewClientOrDie(clientOpts).NewClusterClientOrDie()
defer io.Close(conn)
if clusterOpts.Name != "" {
contextName = clusterOpts.Name
}
clst := cmdutil.NewCluster(contextName, clusterOpts.Namespaces, clusterOpts.ClusterResources, conf, managerBearerToken, awsAuthConf, execProviderConf, labelsMap, annotationsMap)
clst := cmdutil.NewCluster(contextName, clusterOpts.Namespaces, clusterOpts.ClusterResources, conf, managerBearerToken, awsAuthConf, execProviderConf)
if clusterOpts.InCluster {
clst.Server = argoappv1.KubernetesInternalAPIServerAddr
}
if clusterOpts.Shard >= 0 {
clst.Shard = &clusterOpts.Shard
}
if clusterOpts.Project != "" {
clst.Project = clusterOpts.Project
}
clstCreateReq := clusterpkg.ClusterCreateRequest{
Cluster: clst,
Upsert: clusterOpts.Upsert,
@@ -171,8 +148,6 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
command.Flags().StringVar(&clusterOpts.ServiceAccount, "service-account", "", fmt.Sprintf("System namespace service account to use for kubernetes resource management. If not set then default \"%s\" SA will be created", clusterauth.ArgoCDManagerServiceAccount))
command.Flags().StringVar(&clusterOpts.SystemNamespace, "system-namespace", common.DefaultSystemNamespace, "Use different system namespace")
command.Flags().BoolVarP(&skipConfirmation, "yes", "y", false, "Skip explicit confirmation")
command.Flags().StringArrayVar(&labels, "label", nil, "Set metadata labels (e.g. --label key=value)")
command.Flags().StringArrayVar(&annotations, "annotation", nil, "Set metadata annotations (e.g. --annotation key=value)")
cmdutil.AddClusterFlags(command, &clusterOpts)
return command
}
@@ -183,10 +158,9 @@ func NewClusterGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
output string
)
var command = &cobra.Command{
Use: "get SERVER/NAME",
Short: "Get cluster information",
Example: `argocd cluster get https://12.34.567.89
argocd cluster get in-cluster`,
Use: "get SERVER",
Short: "Get cluster information",
Example: `argocd cluster get https://12.34.567.89`,
Run: func(c *cobra.Command, args []string) {
if len(args) == 0 {
c.HelpFunc()(c, args)
@@ -195,8 +169,8 @@ argocd cluster get in-cluster`,
conn, clusterIf := argocdclient.NewClientOrDie(clientOpts).NewClusterClientOrDie()
defer io.Close(conn)
clusters := make([]argoappv1.Cluster, 0)
for _, clusterSelector := range args {
clst, err := clusterIf.Get(context.Background(), getQueryBySelector(clusterSelector))
for _, clusterName := range args {
clst, err := clusterIf.Get(context.Background(), &clusterpkg.ClusterQuery{Server: clusterName})
errors.CheckError(err)
clusters = append(clusters, *clst)
}
@@ -283,29 +257,17 @@ func NewClusterRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm
// Print table of cluster information
func printClusterTable(clusters []argoappv1.Cluster) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
_, _ = fmt.Fprintf(w, "SERVER\tNAME\tVERSION\tSTATUS\tMESSAGE\tPROJECT\n")
_, _ = fmt.Fprintf(w, "SERVER\tNAME\tVERSION\tSTATUS\tMESSAGE\n")
for _, c := range clusters {
server := c.Server
if len(c.Namespaces) > 0 {
server = fmt.Sprintf("%s (%d namespaces)", c.Server, len(c.Namespaces))
}
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\n", server, c.Name, c.ServerVersion, c.ConnectionState.Status, c.ConnectionState.Message, c.Project)
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", server, c.Name, c.ServerVersion, c.ConnectionState.Status, c.ConnectionState.Message)
}
_ = w.Flush()
}
// Returns cluster query for getting cluster depending on the cluster selector
func getQueryBySelector(clusterSelector string) *clusterpkg.ClusterQuery {
var query clusterpkg.ClusterQuery
isServer, err := regexp.MatchString(`^https?://`, clusterSelector)
if isServer || err != nil {
query.Server = clusterSelector
} else {
query.Name = clusterSelector
}
return &query
}
// Print list of cluster servers
func printClusterServers(clusters []argoappv1.Cluster) {
for _, c := range clusters {

View File

@@ -6,24 +6,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/stretchr/testify/assert"
)
func Test_getQueryBySelector(t *testing.T) {
query := getQueryBySelector("my-cluster")
assert.Equal(t, query.Name, "my-cluster")
assert.Equal(t, query.Server, "")
query = getQueryBySelector("http://my-server")
assert.Equal(t, query.Name, "")
assert.Equal(t, query.Server, "http://my-server")
query = getQueryBySelector("https://my-server")
assert.Equal(t, query.Name, "")
assert.Equal(t, query.Server, "https://my-server")
}
func Test_printClusterTable(t *testing.T) {
printClusterTable([]v1alpha1.Cluster{
{

View File

@@ -18,7 +18,6 @@ import (
type forwardCacheClient struct {
namespace string
context string
init sync.Once
client cache.CacheClient
err error
@@ -26,9 +25,7 @@ type forwardCacheClient struct {
func (c *forwardCacheClient) doLazy(action func(client cache.CacheClient) error) error {
c.init.Do(func() {
overrides := clientcmd.ConfigOverrides{
CurrentContext: c.context,
}
overrides := clientcmd.ConfigOverrides{}
redisPort, err := kubeutil.PortForward(6379, c.namespace, &overrides,
"app.kubernetes.io/name=argocd-redis-ha-haproxy", "app.kubernetes.io/name=argocd-redis")
if err != nil {
@@ -77,7 +74,6 @@ func (c *forwardCacheClient) NotifyUpdated(key string) error {
type forwardRepoClientset struct {
namespace string
context string
init sync.Once
repoClientset repoapiclient.Clientset
err error
@@ -85,9 +81,7 @@ type forwardRepoClientset struct {
func (c *forwardRepoClientset) NewRepoServerClient() (io.Closer, repoapiclient.RepoServerServiceClient, error) {
c.init.Do(func() {
overrides := clientcmd.ConfigOverrides{
CurrentContext: c.context,
}
overrides := clientcmd.ConfigOverrides{}
repoServerPort, err := kubeutil.PortForward(8081, c.namespace, &overrides, "app.kubernetes.io/name=argocd-repo-server")
if err != nil {
c.err = err

View File

@@ -12,10 +12,10 @@ import (
"github.com/golang/protobuf/ptypes/empty"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
argoapi "github.com/argoproj/argo-cd/v2/pkg/apiclient"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
@@ -27,8 +27,6 @@ import (
"github.com/argoproj/argo-cd/v2/util/cli"
"github.com/argoproj/argo-cd/v2/util/io"
"github.com/argoproj/argo-cd/v2/util/localconfig"
flag "github.com/spf13/pflag"
)
func testAPI(clientOpts *argoapi.ClientOptions) error {
@@ -45,27 +43,21 @@ func testAPI(clientOpts *argoapi.ClientOptions) error {
return err
}
func retrieveContextIfChanged(contextFlag *flag.Flag) string {
if contextFlag != nil && contextFlag.Changed {
return contextFlag.Value.String()
}
return ""
func addKubectlFlagsToCmd(cmd *cobra.Command) clientcmd.ClientConfig {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
overrides := clientcmd.ConfigOverrides{}
kflags := clientcmd.RecommendedConfigOverrideFlags("")
cmd.Flags().StringVar(&loadingRules.ExplicitPath, "kubeconfig", "", "Path to a kube config. Only required if out-of-cluster")
clientcmd.BindOverrideFlags(&overrides, cmd.Flags(), kflags)
return clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, &overrides, os.Stdin)
}
// InitCommand allows executing command in a headless mode: on the fly starts Argo CD API server and
// changes provided client options to use started API server port
func InitCommand(cmd *cobra.Command, clientOpts *argoapi.ClientOptions, port *int) *cobra.Command {
ctx, cancel := context.WithCancel(context.Background())
flags := pflag.NewFlagSet("tmp", pflag.ContinueOnError)
clientConfig := cli.AddKubectlFlagsToSet(flags)
// copy k8s persistent flags into argocd command flags
flags.VisitAll(func(flag *pflag.Flag) {
// skip Kubernetes server flags since argocd has it's own server flag
if flag.Name == "server" {
return
}
cmd.Flags().AddFlag(flag)
})
clientConfig := addKubectlFlagsToCmd(cmd)
cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
startInProcessAPI := clientOpts.Core
if !startInProcessAPI {
@@ -117,14 +109,12 @@ func InitCommand(cmd *cobra.Command, clientOpts *argoapi.ClientOptions, port *in
return err
}
context := retrieveContextIfChanged(cmd.Flag("context"))
mr, err := miniredis.Run()
if err != nil {
return err
}
appstateCache := appstatecache.NewCache(cacheutil.NewCache(&forwardCacheClient{namespace: namespace, context: context}), time.Hour)
appstateCache := appstatecache.NewCache(cacheutil.NewCache(&forwardCacheClient{namespace: namespace}), time.Hour)
srv := server.NewServer(ctx, server.ArgoCDServerOpts{
EnableGZip: false,
Namespace: namespace,
@@ -136,7 +126,7 @@ func InitCommand(cmd *cobra.Command, clientOpts *argoapi.ClientOptions, port *in
KubeClientset: kubeClientset,
Insecure: true,
ListenHost: "localhost",
RepoClientset: &forwardRepoClientset{namespace: namespace, context: context},
RepoClientset: &forwardRepoClientset{namespace: namespace},
})
go srv.Run(ctx, *port, 0)

View File

@@ -1,80 +0,0 @@
package headless
import (
"testing"
flag "github.com/spf13/pflag"
"github.com/stretchr/testify/assert"
)
type StringFlag struct {
// The exact value provided on the flag
value string
}
func (f StringFlag) String() string {
return f.value
}
func (f *StringFlag) Set(value string) error {
f.value = value
return nil
}
func (f *StringFlag) Type() string {
return "string"
}
func Test_FlagContextNotChanged(t *testing.T) {
res := retrieveContextIfChanged(&flag.Flag{
Name: "",
Shorthand: "",
Usage: "",
Value: &StringFlag{value: "test"},
DefValue: "",
Changed: false,
NoOptDefVal: "",
Deprecated: "",
Hidden: false,
ShorthandDeprecated: "",
Annotations: nil,
})
assert.Equal(t, "", res)
}
func Test_FlagContextChanged(t *testing.T) {
res := retrieveContextIfChanged(&flag.Flag{
Name: "",
Shorthand: "",
Usage: "",
Value: &StringFlag{value: "test"},
DefValue: "",
Changed: true,
NoOptDefVal: "",
Deprecated: "",
Hidden: false,
ShorthandDeprecated: "",
Annotations: nil,
})
assert.Equal(t, "test", res)
}
func Test_FlagContextNil(t *testing.T) {
res := retrieveContextIfChanged(&flag.Flag{
Name: "",
Shorthand: "",
Usage: "",
Value: nil,
DefValue: "",
Changed: false,
NoOptDefVal: "",
Deprecated: "",
Hidden: false,
ShorthandDeprecated: "",
Annotations: nil,
})
assert.Equal(t, "", res)
}

View File

@@ -90,8 +90,6 @@ argocd login cd.argoproj.io --core`,
ServerAddr: server,
Insecure: globalClientOpts.Insecure,
PlainText: globalClientOpts.PlainText,
ClientCertFile: globalClientOpts.ClientCertFile,
ClientCertKeyFile: globalClientOpts.ClientCertKeyFile,
GRPCWeb: globalClientOpts.GRPCWeb,
GRPCWebRootPath: globalClientOpts.GRPCWebRootPath,
PortForward: globalClientOpts.PortForward,

View File

@@ -219,17 +219,8 @@ func NewProjectRemoveSignatureKeyCommand(clientOpts *argocdclient.ClientOptions)
// NewProjectAddDestinationCommand returns a new instance of an `argocd proj add-destination` command
func NewProjectAddDestinationCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var nameInsteadServer bool
buildApplicationDestination := func(destination string, namespace string, nameInsteadServer bool) v1alpha1.ApplicationDestination {
if nameInsteadServer {
return v1alpha1.ApplicationDestination{Name: destination, Namespace: namespace}
}
return v1alpha1.ApplicationDestination{Server: destination, Namespace: namespace}
}
var command = &cobra.Command{
Use: "add-destination PROJECT SERVER/NAME NAMESPACE",
Use: "add-destination PROJECT SERVER NAMESPACE",
Short: "Add project destination",
Run: func(c *cobra.Command, args []string) {
if len(args) != 3 {
@@ -237,8 +228,8 @@ func NewProjectAddDestinationCommand(clientOpts *argocdclient.ClientOptions) *co
os.Exit(1)
}
projName := args[0]
server := args[1]
namespace := args[2]
destination := buildApplicationDestination(args[1], namespace, nameInsteadServer)
conn, projIf := argocdclient.NewClientOrDie(clientOpts).NewProjectClientOrDie()
defer argoio.Close(conn)
@@ -246,18 +237,15 @@ func NewProjectAddDestinationCommand(clientOpts *argocdclient.ClientOptions) *co
errors.CheckError(err)
for _, dest := range proj.Spec.Destinations {
dstServerExist := destination.Server != "" && dest.Server == destination.Server
dstNameExist := destination.Name != "" && dest.Name == destination.Name
if dest.Namespace == namespace && (dstServerExist || dstNameExist) {
if dest.Namespace == namespace && dest.Server == server {
log.Fatal("Specified destination is already defined in project")
}
}
proj.Spec.Destinations = append(proj.Spec.Destinations, destination)
proj.Spec.Destinations = append(proj.Spec.Destinations, v1alpha1.ApplicationDestination{Server: server, Namespace: namespace})
_, err = projIf.Update(context.Background(), &projectpkg.ProjectUpdateRequest{Project: proj})
errors.CheckError(err)
},
}
command.Flags().BoolVar(&nameInsteadServer, "name", false, "Use name as destination instead server")
return command
}

View File

@@ -116,7 +116,6 @@ func NewProjectWindowsAddWindowCommand(clientOpts *argocdclient.ClientOptions) *
namespaces []string
clusters []string
manualSync bool
timeZone string
)
var command = &cobra.Command{
Use: "add PROJECT",
@@ -133,7 +132,7 @@ func NewProjectWindowsAddWindowCommand(clientOpts *argocdclient.ClientOptions) *
proj, err := projIf.Get(context.Background(), &projectpkg.ProjectQuery{Name: projName})
errors.CheckError(err)
err = proj.Spec.AddWindow(kind, schedule, duration, applications, namespaces, clusters, manualSync, timeZone)
err = proj.Spec.AddWindow(kind, schedule, duration, applications, namespaces, clusters, manualSync)
errors.CheckError(err)
_, err = projIf.Update(context.Background(), &projectpkg.ProjectUpdateRequest{Project: proj})
@@ -147,7 +146,6 @@ func NewProjectWindowsAddWindowCommand(clientOpts *argocdclient.ClientOptions) *
command.Flags().StringSliceVar(&namespaces, "namespaces", []string{}, "Namespaces that the schedule will be applied to. Comma separated, wildcards supported (e.g. --namespaces default,\\*-prod)")
command.Flags().StringSliceVar(&clusters, "clusters", []string{}, "Clusters that the schedule will be applied to. Comma separated, wildcards supported (e.g. --clusters prod,staging)")
command.Flags().BoolVar(&manualSync, "manual-sync", false, "Allow manual syncs for both deny and allow windows")
command.Flags().StringVar(&timeZone, "time-zone", "UTC", "Time zone of the sync window")
return command
}
@@ -191,7 +189,6 @@ func NewProjectWindowsUpdateCommand(clientOpts *argocdclient.ClientOptions) *cob
applications []string
namespaces []string
clusters []string
timeZone string
)
var command = &cobra.Command{
Use: "update PROJECT ID",
@@ -215,7 +212,7 @@ func NewProjectWindowsUpdateCommand(clientOpts *argocdclient.ClientOptions) *cob
for i, window := range proj.Spec.SyncWindows {
if id == i {
err := window.Update(schedule, duration, applications, namespaces, clusters, timeZone)
err := window.Update(schedule, duration, applications, namespaces, clusters)
if err != nil {
errors.CheckError(err)
}
@@ -231,7 +228,6 @@ func NewProjectWindowsUpdateCommand(clientOpts *argocdclient.ClientOptions) *cob
command.Flags().StringSliceVar(&applications, "applications", []string{}, "Applications that the schedule will be applied to. Comma separated, wildcards supported (e.g. --applications prod-\\*,website)")
command.Flags().StringSliceVar(&namespaces, "namespaces", []string{}, "Namespaces that the schedule will be applied to. Comma separated, wildcards supported (e.g. --namespaces default,\\*-prod)")
command.Flags().StringSliceVar(&clusters, "clusters", []string{}, "Clusters that the schedule will be applied to. Comma separated, wildcards supported (e.g. --clusters prod,staging)")
command.Flags().StringVar(&timeZone, "time-zone", "UTC", "Time zone of the sync window. (e.g. --time-zone \"America/New_York\")")
return command
}

View File

@@ -43,15 +43,13 @@ func NewReloginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Comm
var tokenString string
var refreshToken string
clientOpts := argocdclient.ClientOptions{
ConfigPath: "",
ServerAddr: configCtx.Server.Server,
Insecure: configCtx.Server.Insecure,
ClientCertFile: globalClientOpts.ClientCertFile,
ClientCertKeyFile: globalClientOpts.ClientCertKeyFile,
GRPCWeb: globalClientOpts.GRPCWeb,
GRPCWebRootPath: globalClientOpts.GRPCWebRootPath,
PlainText: configCtx.Server.PlainText,
Headers: globalClientOpts.Headers,
ConfigPath: "",
ServerAddr: configCtx.Server.Server,
Insecure: configCtx.Server.Insecure,
GRPCWeb: globalClientOpts.GRPCWeb,
GRPCWebRootPath: globalClientOpts.GRPCWebRootPath,
PlainText: configCtx.Server.PlainText,
Headers: globalClientOpts.Headers,
}
acdClient := argocdclient.NewClientOrDie(&clientOpts)
claims, err := configCtx.User.Claims()

View File

@@ -182,7 +182,6 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
GithubAppInstallationID: repoOpts.Repo.GithubAppInstallationId,
GithubAppEnterpriseBaseUrl: repoOpts.Repo.GitHubAppEnterpriseBaseURL,
Proxy: repoOpts.Proxy,
Project: repoOpts.Repo.Project,
}
_, err := repoIf.ValidateAccess(context.Background(), &repoAccessReq)
errors.CheckError(err)
@@ -227,7 +226,7 @@ func NewRepoRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
// Print table of repo info
func printRepoTable(repos appsv1.Repositories) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
_, _ = fmt.Fprintf(w, "TYPE\tNAME\tREPO\tINSECURE\tOCI\tLFS\tCREDS\tSTATUS\tMESSAGE\tPROJECT\n")
_, _ = fmt.Fprintf(w, "TYPE\tNAME\tREPO\tINSECURE\tOCI\tLFS\tCREDS\tSTATUS\tMESSAGE\n")
for _, r := range repos {
var hasCreds string
if !r.HasCredentials() {
@@ -239,7 +238,7 @@ func printRepoTable(repos appsv1.Repositories) {
hasCreds = "true"
}
}
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%v\t%v\t%v\t%s\t%s\t%s\t%s\n", r.Type, r.Name, r.Repo, r.IsInsecure(), r.EnableOCI, r.EnableLFS, hasCreds, r.ConnectionState.Status, r.ConnectionState.Message, r.Project)
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%v\t%v\t%v\t%s\t%s\t%s\n", r.Type, r.Name, r.Repo, r.IsInsecure(), r.EnableOCI, r.EnableLFS, hasCreds, r.ConnectionState.Status, r.ConnectionState.Message)
}
_ = w.Flush()
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/spf13/cobra"
appcontroller "github.com/argoproj/argo-cd/v2/cmd/argocd-application-controller/commands"
cmpserver "github.com/argoproj/argo-cd/v2/cmd/argocd-cmp-server/commands"
dex "github.com/argoproj/argo-cd/v2/cmd/argocd-dex/commands"
reposerver "github.com/argoproj/argo-cd/v2/cmd/argocd-repo-server/commands"
apiserver "github.com/argoproj/argo-cd/v2/cmd/argocd-server/commands"
@@ -35,8 +34,6 @@ func main() {
command = appcontroller.NewCommand()
case "argocd-repo-server":
command = reposerver.NewCommand()
case "argocd-cmp-server":
command = cmpserver.NewCommand()
case "argocd-dex":
command = dex.NewCommand()
default:

View File

@@ -9,8 +9,6 @@ import (
"strings"
"time"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@@ -42,7 +40,6 @@ type AppOptions struct {
helmSetStrings []string
helmSetFiles []string
helmVersion string
helmPassCredentials bool
project string
syncPolicy string
syncOptions []string
@@ -89,7 +86,6 @@ func AddAppFlags(command *cobra.Command, opts *AppOptions) {
command.Flags().StringVar(&opts.values, "values-literal-file", "", "Filename or URL to import as a literal Helm values block")
command.Flags().StringVar(&opts.releaseName, "release-name", "", "Helm release-name")
command.Flags().StringVar(&opts.helmVersion, "helm-version", "", "Helm version")
command.Flags().BoolVar(&opts.helmPassCredentials, "helm-pass-credentials", false, "Pass credentials to all domain")
command.Flags().StringArrayVar(&opts.helmSets, "helm-set", []string{}, "Helm set values on the command line (can be repeated to set several values: --helm-set key1=val1 --helm-set key2=val2)")
command.Flags().StringArrayVar(&opts.helmSetStrings, "helm-set-string", []string{}, "Helm set STRING values on the command line (can be repeated to set several values: --helm-set-string key1=val1 --helm-set-string key2=val2)")
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)")
@@ -126,9 +122,6 @@ func AddAppFlags(command *cobra.Command, opts *AppOptions) {
func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, appOpts *AppOptions) int {
visited := 0
if flags == nil {
return visited
}
flags.Visit(func(f *pflag.Flag) {
visited++
switch f.Name {
@@ -163,8 +156,6 @@ func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap
setHelmOpt(&spec.Source, helmOpts{releaseName: appOpts.releaseName})
case "helm-version":
setHelmOpt(&spec.Source, helmOpts{version: appOpts.helmVersion})
case "helm-pass-credentials":
setHelmOpt(&spec.Source, helmOpts{passCredentials: appOpts.helmPassCredentials})
case "helm-set":
setHelmOpt(&spec.Source, helmOpts{helmSets: appOpts.helmSets})
case "helm-set-string":
@@ -381,14 +372,13 @@ func setPluginOptEnvs(src *argoappv1.ApplicationSource, envs []string) {
}
type helmOpts struct {
valueFiles []string
values string
releaseName string
version string
helmSets []string
helmSetStrings []string
helmSetFiles []string
passCredentials bool
valueFiles []string
values string
releaseName string
version string
helmSets []string
helmSetStrings []string
helmSetFiles []string
}
func setHelmOpt(src *argoappv1.ApplicationSource, opts helmOpts) {
@@ -407,9 +397,6 @@ func setHelmOpt(src *argoappv1.ApplicationSource, opts helmOpts) {
if opts.version != "" {
src.Helm.Version = opts.version
}
if opts.passCredentials {
src.Helm.PassCredentials = opts.passCredentials
}
for _, text := range opts.helmSets {
p, err := argoappv1.NewHelmParameter(text, false)
if err != nil {
@@ -531,99 +518,39 @@ func SetParameterOverrides(app *argoappv1.Application, parameters []string) {
}
}
func readApps(yml []byte, apps *[]*argoappv1.Application) error {
yamls, _ := kube.SplitYAMLToString(yml)
var err error
for _, yml := range yamls {
var app argoappv1.Application
err = config.Unmarshal([]byte(yml), &app)
*apps = append(*apps, &app)
if err != nil {
return err
}
}
return err
}
func readAppsFromStdin(apps *[]*argoappv1.Application) error {
func readAppFromStdin(app *argoappv1.Application) error {
reader := bufio.NewReader(os.Stdin)
data, err := ioutil.ReadAll(reader)
if err != nil {
return err
}
err = readApps(data, apps)
err := config.UnmarshalReader(reader, &app)
if err != nil {
return fmt.Errorf("unable to read manifest from stdin: %v", err)
}
return nil
}
func readAppsFromURI(fileURL string, apps *[]*argoappv1.Application) error {
func readAppFromURI(fileURL string, app *argoappv1.Application) error {
parsedURL, err := url.ParseRequestURI(fileURL)
if err != nil || !(parsedURL.Scheme == "http" || parsedURL.Scheme == "https") {
err = config.UnmarshalLocalFile(fileURL, &app)
} else {
err = config.UnmarshalRemoteFile(fileURL, &app)
}
return err
}
readFilePayload := func() ([]byte, error) {
parsedURL, err := url.ParseRequestURI(fileURL)
if err != nil || !(parsedURL.Scheme == "http" || parsedURL.Scheme == "https") {
return ioutil.ReadFile(fileURL)
func ConstructApp(fileURL, appName string, labels, annotations, args []string, appOpts AppOptions, flags *pflag.FlagSet) (*argoappv1.Application, error) {
var app argoappv1.Application
if fileURL == "-" {
// read stdin
err := readAppFromStdin(&app)
if err != nil {
return nil, err
}
return config.ReadRemoteFile(fileURL)
}
yml, err := readFilePayload()
if err != nil {
return err
}
return readApps(yml, apps)
}
func constructAppsFromStdin() ([]*argoappv1.Application, error) {
apps := make([]*argoappv1.Application, 0)
// read stdin
err := readAppsFromStdin(&apps)
if err != nil {
return nil, err
}
return apps, nil
}
func constructAppsBaseOnName(appName string, labels, annotations, args []string, appOpts AppOptions, flags *pflag.FlagSet) ([]*argoappv1.Application, error) {
var app *argoappv1.Application
// read arguments
if len(args) == 1 {
if appName != "" && appName != args[0] {
return nil, fmt.Errorf("--name argument '%s' does not match app name %s", appName, args[0])
} else if fileURL != "" {
// read uri
err := readAppFromURI(fileURL, &app)
if err != nil {
return nil, err
}
appName = args[0]
}
app = &argoappv1.Application{
TypeMeta: v1.TypeMeta{
Kind: application.ApplicationKind,
APIVersion: application.Group + "/v1alpha1",
},
ObjectMeta: v1.ObjectMeta{
Name: appName,
},
}
SetAppSpecOptions(flags, &app.Spec, &appOpts)
SetParameterOverrides(app, appOpts.Parameters)
mergeLabels(app, labels)
setAnnotations(app, annotations)
return []*argoappv1.Application{
app,
}, nil
}
func constructAppsFromFileUrl(fileURL, appName string, labels, annotations, args []string, appOpts AppOptions, flags *pflag.FlagSet) ([]*argoappv1.Application, error) {
apps := make([]*argoappv1.Application, 0)
// read uri
err := readAppsFromURI(fileURL, &apps)
if err != nil {
return nil, err
}
for _, app := range apps {
if len(args) == 1 && args[0] != app.Name {
return nil, fmt.Errorf("app name '%s' does not match app spec metadata.name '%s'", args[0], app.Name)
}
@@ -634,20 +561,32 @@ func constructAppsFromFileUrl(fileURL, appName string, labels, annotations, args
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)
SetParameterOverrides(&app, appOpts.Parameters)
mergeLabels(&app, labels)
setAnnotations(&app, annotations)
} else {
// read arguments
if len(args) == 1 {
if appName != "" && appName != args[0] {
return nil, fmt.Errorf("--name argument '%s' does not match app name %s", appName, args[0])
}
appName = args[0]
}
app = argoappv1.Application{
TypeMeta: v1.TypeMeta{
Kind: application.ApplicationKind,
APIVersion: application.Group + "/v1alpha1",
},
ObjectMeta: v1.ObjectMeta{
Name: appName,
},
}
SetAppSpecOptions(flags, &app.Spec, &appOpts)
SetParameterOverrides(&app, appOpts.Parameters)
mergeLabels(&app, labels)
setAnnotations(&app, annotations)
}
return apps, nil
}
func ConstructApps(fileURL, appName string, labels, annotations, args []string, appOpts AppOptions, flags *pflag.FlagSet) ([]*argoappv1.Application, error) {
if fileURL == "-" {
return constructAppsFromStdin()
} else if fileURL != "" {
return constructAppsFromFileUrl(fileURL, appName, labels, annotations, args, appOpts, flags)
}
return constructAppsBaseOnName(appName, labels, annotations, args, appOpts, flags)
return &app, nil
}
func mergeLabels(app *argoappv1.Application, labels []string) {

View File

@@ -1,16 +1,12 @@
package util
import (
"io/ioutil"
"os"
"testing"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
)
func Test_setHelmOpt(t *testing.T) {
@@ -49,11 +45,6 @@ func Test_setHelmOpt(t *testing.T) {
setHelmOpt(&src, helmOpts{version: "v3"})
assert.Equal(t, "v3", src.Helm.Version)
})
t.Run("HelmPassCredentials", func(t *testing.T) {
src := v1alpha1.ApplicationSource{}
setHelmOpt(&src, helmOpts{passCredentials: true})
assert.Equal(t, true, src.Helm.PassCredentials)
})
}
func Test_setKustomizeOpt(t *testing.T) {
@@ -199,106 +190,3 @@ func Test_setAnnotations(t *testing.T) {
assert.Equal(t, map[string]string{"hoge": ""}, app.Annotations)
})
}
const appsYaml = `---
# Source: apps/templates/helm.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: sth1
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
destination:
namespace: sth
server: 'https://kubernetes.default.svc'
project: default
source:
repoURL: 'https://github.com/pasha-codefresh/argocd-example-apps'
targetRevision: HEAD
path: apps
helm:
valueFiles:
- values.yaml
---
# Source: apps/templates/helm.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: sth2
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
destination:
namespace: sth
server: 'https://kubernetes.default.svc'
project: default
source:
repoURL: 'https://github.com/pasha-codefresh/argocd-example-apps'
targetRevision: HEAD
path: apps
helm:
valueFiles:
- values.yaml`
func TestReadAppsFromURI(t *testing.T) {
file, err := ioutil.TempFile(os.TempDir(), "")
if err != nil {
panic(err)
}
defer func() {
_ = os.Remove(file.Name())
}()
_, _ = file.WriteString(appsYaml)
_ = file.Sync()
apps := make([]*argoappv1.Application, 0)
err = readAppsFromURI(file.Name(), &apps)
assert.NoError(t, err)
assert.Equal(t, 2, len(apps))
assert.Equal(t, "sth1", apps[0].Name)
assert.Equal(t, "sth2", apps[1].Name)
}
func TestConstructAppFromStdin(t *testing.T) {
file, err := ioutil.TempFile(os.TempDir(), "")
if err != nil {
panic(err)
}
defer func() {
_ = os.Remove(file.Name())
}()
_, _ = file.WriteString(appsYaml)
_ = file.Sync()
if _, err := file.Seek(0, 0); err != nil {
log.Fatal(err)
}
os.Stdin = file
apps, err := ConstructApps("-", "test", []string{}, []string{}, []string{}, AppOptions{}, nil)
if err := file.Close(); err != nil {
log.Fatal(err)
}
assert.NoError(t, err)
assert.Equal(t, 2, len(apps))
assert.Equal(t, "sth1", apps[0].Name)
assert.Equal(t, "sth2", apps[1].Name)
}
func TestConstructBasedOnName(t *testing.T) {
apps, err := ConstructApps("", "test", []string{}, []string{}, []string{}, AppOptions{}, nil)
assert.NoError(t, err)
assert.Equal(t, 1, len(apps))
assert.Equal(t, "test", apps[0].Name)
}

View File

@@ -55,7 +55,7 @@ func PrintKubeContexts(ca clientcmd.ConfigAccess) {
}
}
func NewCluster(name string, namespaces []string, clusterResources bool, conf *rest.Config, managerBearerToken string, awsAuthConf *argoappv1.AWSAuthConfig, execProviderConf *argoappv1.ExecProviderConfig, labels, annotations map[string]string) *argoappv1.Cluster {
func NewCluster(name string, namespaces []string, clusterResources bool, conf *rest.Config, managerBearerToken string, awsAuthConf *argoappv1.AWSAuthConfig, execProviderConf *argoappv1.ExecProviderConfig) *argoappv1.Cluster {
tlsClientConfig := argoappv1.TLSClientConfig{
Insecure: conf.TLSClientConfig.Insecure,
ServerName: conf.TLSClientConfig.ServerName,
@@ -89,8 +89,6 @@ func NewCluster(name string, namespaces []string, clusterResources bool, conf *r
AWSAuthConfig: awsAuthConf,
ExecProviderConfig: execProviderConf,
},
Labels: labels,
Annotations: annotations,
}
// Bearer token will preferentially be used for auth if present,
@@ -113,7 +111,6 @@ type ClusterOptions struct {
Namespaces []string
ClusterResources bool
Name string
Project string
Shard int64
ExecProviderCommand string
ExecProviderArgs []string
@@ -129,7 +126,6 @@ func AddClusterFlags(command *cobra.Command, opts *ClusterOptions) {
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")
command.Flags().StringVar(&opts.Project, "project", "", "project of the cluster")
command.Flags().Int64Var(&opts.Shard, "shard", -1, "Cluster shard number; inferred from hostname if not set")
command.Flags().StringVar(&opts.ExecProviderCommand, "exec-command", "", "Command to run to provide client credentials to the cluster. You may need to build a custom ArgoCD image to ensure the command is available at runtime.")
command.Flags().StringArrayVar(&opts.ExecProviderArgs, "exec-command-args", nil, "Arguments to supply to the --exec-command executable")

View File

@@ -11,8 +11,6 @@ import (
)
func Test_newCluster(t *testing.T) {
labels := map[string]string{"key1": "val1"}
annotations := map[string]string{"key2": "val2"}
clusterWithData := NewCluster("test-cluster", []string{"test-namespace"}, false, &rest.Config{
TLSClientConfig: rest.TLSClientConfig{
Insecure: false,
@@ -25,13 +23,11 @@ func Test_newCluster(t *testing.T) {
},
"test-bearer-token",
&v1alpha1.AWSAuthConfig{},
&v1alpha1.ExecProviderConfig{}, labels, annotations)
&v1alpha1.ExecProviderConfig{})
assert.Equal(t, "test-cert-data", string(clusterWithData.Config.CertData))
assert.Equal(t, "test-key-data", string(clusterWithData.Config.KeyData))
assert.Equal(t, "", clusterWithData.Config.BearerToken)
assert.Equal(t, labels, clusterWithData.Labels)
assert.Equal(t, annotations, clusterWithData.Annotations)
clusterWithFiles := NewCluster("test-cluster", []string{"test-namespace"}, false, &rest.Config{
TLSClientConfig: rest.TLSClientConfig{
@@ -45,13 +41,11 @@ func Test_newCluster(t *testing.T) {
},
"test-bearer-token",
&v1alpha1.AWSAuthConfig{},
&v1alpha1.ExecProviderConfig{}, labels, nil)
&v1alpha1.ExecProviderConfig{})
assert.True(t, strings.Contains(string(clusterWithFiles.Config.CertData), "test-cert-data"))
assert.True(t, strings.Contains(string(clusterWithFiles.Config.KeyData), "test-key-data"))
assert.Equal(t, "", clusterWithFiles.Config.BearerToken)
assert.Equal(t, labels, clusterWithFiles.Labels)
assert.Nil(t, clusterWithFiles.Annotations)
clusterWithBearerToken := NewCluster("test-cluster", []string{"test-namespace"}, false, &rest.Config{
TLSClientConfig: rest.TLSClientConfig{
@@ -63,9 +57,7 @@ func Test_newCluster(t *testing.T) {
},
"test-bearer-token",
&v1alpha1.AWSAuthConfig{},
&v1alpha1.ExecProviderConfig{}, nil, nil)
&v1alpha1.ExecProviderConfig{})
assert.Equal(t, "test-bearer-token", clusterWithBearerToken.Config.BearerToken)
assert.Nil(t, clusterWithBearerToken.Labels)
assert.Nil(t, clusterWithBearerToken.Annotations)
}

View File

@@ -27,7 +27,6 @@ type RepoOptions struct {
func AddRepoFlags(command *cobra.Command, opts *RepoOptions) {
command.Flags().StringVar(&opts.Repo.Type, "type", common.DefaultRepoType, "type of the repository, \"git\" or \"helm\"")
command.Flags().StringVar(&opts.Repo.Name, "name", "", "name of the repository, mandatory for repositories of type helm")
command.Flags().StringVar(&opts.Repo.Project, "project", "", "project of the repository")
command.Flags().StringVar(&opts.Repo.Username, "username", "", "username to the repository")
command.Flags().StringVar(&opts.Repo.Password, "password", "", "password to the repository")
command.Flags().StringVar(&opts.SshPrivateKeyPath, "ssh-private-key-path", "", "path to the private ssh key (e.g. ~/.ssh/id_rsa)")

View File

@@ -1,66 +0,0 @@
package apiclient
import (
"context"
"time"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
grpc_util "github.com/argoproj/argo-cd/v2/util/grpc"
"github.com/argoproj/argo-cd/v2/util/io"
)
const (
// MaxGRPCMessageSize contains max grpc message size
MaxGRPCMessageSize = 100 * 1024 * 1024
)
// Clientset represents config management plugin server api clients
type Clientset interface {
NewConfigManagementPluginClient() (io.Closer, ConfigManagementPluginServiceClient, error)
}
type clientSet struct {
address string
timeoutSeconds int
}
func (c *clientSet) NewConfigManagementPluginClient() (io.Closer, ConfigManagementPluginServiceClient, error) {
conn, err := NewConnection(c.address, c.timeoutSeconds)
if err != nil {
return nil, nil, err
}
return conn, NewConfigManagementPluginServiceClient(conn), nil
}
func NewConnection(address string, timeoutSeconds int) (*grpc.ClientConn, error) {
retryOpts := []grpc_retry.CallOption{
grpc_retry.WithMax(3),
grpc_retry.WithBackoff(grpc_retry.BackoffLinear(1000 * time.Millisecond)),
}
unaryInterceptors := []grpc.UnaryClientInterceptor{grpc_retry.UnaryClientInterceptor(retryOpts...)}
if timeoutSeconds > 0 {
unaryInterceptors = append(unaryInterceptors, grpc_util.WithTimeout(time.Duration(timeoutSeconds)*time.Second))
}
dialOpts := []grpc.DialOption{
grpc.WithStreamInterceptor(grpc_retry.StreamClientInterceptor(retryOpts...)),
grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(unaryInterceptors...)),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(MaxGRPCMessageSize), grpc.MaxCallSendMsgSize(MaxGRPCMessageSize)),
}
dialOpts = append(dialOpts, grpc.WithInsecure())
conn, err := grpc_util.BlockingDial(context.Background(), "unix", address, nil, dialOpts...)
if err != nil {
log.Errorf("Unable to connect to config management plugin service with address %s", address)
return nil, err
}
return conn, nil
}
// NewCMPServerClientset creates new instance of config management plugin server Clientset
func NewConfigManagementPluginClientSet(address string, timeoutSeconds int) Clientset {
return &clientSet{address: address, timeoutSeconds: timeoutSeconds}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,91 +0,0 @@
package plugin
import (
"fmt"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/argoproj/argo-cd/v2/common"
configUtil "github.com/argoproj/argo-cd/v2/util/config"
)
const (
ConfigManagementPluginKind string = "ConfigManagementPlugin"
)
type PluginConfig struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ObjectMeta `json:"metadata"`
Spec PluginConfigSpec `json:"spec"`
}
type PluginConfigSpec struct {
Version string `json:"version"`
Init Command `json:"init,omitempty"`
Generate Command `json:"generate"`
Discover Discover `json:"discover"`
AllowConcurrency bool `json:"allowConcurrency"`
LockRepo bool `json:"lockRepo"`
}
//Discover holds find and fileName
type Discover struct {
Find Find `json:"find"`
FileName string `json:"fileName"`
}
// Command holds binary path and arguments list
type Command struct {
Command []string `json:"command,omitempty"`
Args []string `json:"args,omitempty"`
}
// Find holds find command or glob pattern
type Find struct {
Command
Glob string `json:"glob"`
}
func ReadPluginConfig(filePath string) (*PluginConfig, error) {
path := fmt.Sprintf("%s/%s", strings.TrimRight(filePath, "/"), common.PluginConfigFileName)
var config PluginConfig
err := configUtil.UnmarshalLocalFile(path, &config)
if err != nil {
return nil, err
}
if err = ValidatePluginConfig(config); err != nil {
return nil, err
}
return &config, nil
}
func ValidatePluginConfig(config PluginConfig) error {
if config.Metadata.Name == "" {
return fmt.Errorf("invalid plugin configuration file. metadata.name should be non-empty.")
}
if config.TypeMeta.Kind != ConfigManagementPluginKind {
return fmt.Errorf("invalid plugin configuration file. kind should be %s, found %s", ConfigManagementPluginKind, config.TypeMeta.Kind)
}
if len(config.Spec.Generate.Command) == 0 {
return fmt.Errorf("invalid plugin configuration file. spec.generate command should be non-empty")
}
if config.Spec.Discover.Find.Glob == "" && len(config.Spec.Discover.Find.Command.Command) == 0 && config.Spec.Discover.FileName == "" {
return fmt.Errorf("invalid plugin configuration file. atleast one of discover.find.command or discover.find.glob or discover.fineName should be non-empty")
}
return nil
}
func (cfg *PluginConfig) Address() string {
var address string
pluginSockFilePath := common.GetPluginSockFilePath()
if cfg.Spec.Version != "" {
address = fmt.Sprintf("%s/%s-%s.sock", pluginSockFilePath, cfg.Metadata.Name, cfg.Spec.Version)
} else {
address = fmt.Sprintf("%s/%s.sock", pluginSockFilePath, cfg.Metadata.Name)
}
return address
}

View File

@@ -1,137 +0,0 @@
package plugin
import (
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/mattn/go-zglob"
log "github.com/sirupsen/logrus"
"github.com/argoproj/argo-cd/v2/cmpserver/apiclient"
executil "github.com/argoproj/argo-cd/v2/util/exec"
)
// Service implements ConfigManagementPluginService interface
type Service struct {
initConstants CMPServerInitConstants
}
type CMPServerInitConstants struct {
PluginConfig PluginConfig
}
// NewService returns a new instance of the ConfigManagementPluginService
func NewService(initConstants CMPServerInitConstants) *Service {
return &Service{
initConstants: initConstants,
}
}
func runCommand(command Command, path string, env []string) (string, error) {
if len(command.Command) == 0 {
return "", fmt.Errorf("Command is empty")
}
cmd := exec.Command(command.Command[0], append(command.Command[1:], command.Args...)...)
cmd.Env = env
cmd.Dir = path
return executil.Run(cmd)
}
// Environ returns a list of environment variables in name=value format from a list of variables
func environ(envVars []*apiclient.EnvEntry) []string {
var environ []string
for _, item := range envVars {
if item != nil && item.Name != "" && item.Value != "" {
environ = append(environ, fmt.Sprintf("%s=%s", item.Name, item.Value))
}
}
return environ
}
// GenerateManifest runs generate command from plugin config file and returns generated manifest files
func (s *Service) GenerateManifest(ctx context.Context, q *apiclient.ManifestRequest) (*apiclient.ManifestResponse, error) {
config := s.initConstants.PluginConfig
env := append(os.Environ(), environ(q.Env)...)
if len(config.Spec.Init.Command) > 0 {
_, err := runCommand(config.Spec.Init, q.AppPath, env)
if err != nil {
return &apiclient.ManifestResponse{}, err
}
}
out, err := runCommand(config.Spec.Generate, q.AppPath, env)
if err != nil {
return &apiclient.ManifestResponse{}, err
}
manifests, err := kube.SplitYAMLToString([]byte(out))
if err != nil {
return &apiclient.ManifestResponse{}, err
}
return &apiclient.ManifestResponse{
Manifests: manifests,
}, err
}
// MatchRepository checks whether the application repository type is supported by config management plugin server
func (s *Service) MatchRepository(ctx context.Context, q *apiclient.RepositoryRequest) (*apiclient.RepositoryResponse, error) {
var repoResponse apiclient.RepositoryResponse
config := s.initConstants.PluginConfig
if config.Spec.Discover.FileName != "" {
log.Debugf("config.Spec.Discover.FileName is provided")
pattern := strings.TrimSuffix(q.Path, "/") + "/" + strings.TrimPrefix(config.Spec.Discover.FileName, "/")
matches, err := filepath.Glob(pattern)
if err != nil || len(matches) == 0 {
log.Debugf("Could not find match for pattern %s. Error is %v.", pattern, err)
return &repoResponse, err
} else if len(matches) > 0 {
repoResponse.IsSupported = true
return &repoResponse, nil
}
}
if config.Spec.Discover.Find.Glob != "" {
log.Debugf("config.Spec.Discover.Find.Glob is provided")
pattern := strings.TrimSuffix(q.Path, "/") + "/" + strings.TrimPrefix(config.Spec.Discover.Find.Glob, "/")
// filepath.Glob doesn't have '**' support hence selecting third-party lib
// https://github.com/golang/go/issues/11862
matches, err := zglob.Glob(pattern)
if err != nil || len(matches) == 0 {
log.Debugf("Could not find match for pattern %s. Error is %v.", pattern, err)
return &repoResponse, err
} else if len(matches) > 0 {
repoResponse.IsSupported = true
return &repoResponse, nil
}
}
log.Debugf("Going to try runCommand.")
find, err := runCommand(config.Spec.Discover.Find.Command, q.Path, os.Environ())
if err != nil {
return &repoResponse, err
}
var isSupported bool
if find != "" {
isSupported = true
}
return &apiclient.RepositoryResponse{
IsSupported: isSupported,
}, nil
}
// GetPluginConfig returns plugin config
func (s *Service) GetPluginConfig(ctx context.Context, q *apiclient.ConfigRequest) (*apiclient.ConfigResponse, error) {
config := s.initConstants.PluginConfig
return &apiclient.ConfigResponse{
AllowConcurrency: config.Spec.AllowConcurrency,
LockRepo: config.Spec.LockRepo,
}, nil
}

View File

@@ -1,61 +0,0 @@
syntax = "proto3";
option go_package = "github.com/argoproj/argo-cd/v2/cmpserver/apiclient";
package plugin;
import "k8s.io/api/core/v1/generated.proto";
// ManifestRequest is a query for manifest generation.
message ManifestRequest {
// Name of the application for which the request is triggered
string appName = 1;
string appPath = 2;
string repoPath = 3;
bool noCache = 4;
repeated EnvEntry env = 5;
}
// EnvEntry represents an entry in the application's environment
message EnvEntry {
// Name is the name of the variable, usually expressed in uppercase
string name = 1;
// Value is the value of the variable
string value = 2;
}
message ManifestResponse {
repeated string manifests = 1;
string sourceType = 2;
}
message RepositoryRequest {
string path = 1;
repeated EnvEntry env = 2;
}
message RepositoryResponse {
bool isSupported = 1;
}
message ConfigRequest {
}
message ConfigResponse {
bool allowConcurrency = 1;
bool lockRepo = 2;
}
// ConfigManagementPlugin Service
service ConfigManagementPluginService {
// GenerateManifest generates manifest for application in specified repo name and revision
rpc GenerateManifest(ManifestRequest) returns (ManifestResponse) {
}
// MatchRepository returns whether or not the given path is supported by the plugin
rpc MatchRepository(RepositoryRequest) returns (RepositoryResponse) {
}
// Get configuration of the plugin
rpc GetPluginConfig(ConfigRequest) returns (ConfigResponse) {
}
}

View File

@@ -1,65 +0,0 @@
package plugin
import (
"context"
"os"
"testing"
"github.com/stretchr/testify/require"
"github.com/argoproj/argo-cd/v2/cmpserver/apiclient"
)
func newService(configFilePath string) (*Service, error) {
config, err := ReadPluginConfig(configFilePath)
if err != nil {
return nil, err
}
initConstants := CMPServerInitConstants{
PluginConfig: *config,
}
service := &Service{
initConstants: initConstants,
}
return service, nil
}
func TestMatchRepository(t *testing.T) {
configFilePath := "./testdata/ksonnet/config"
service, err := newService(configFilePath)
require.NoError(t, err)
q := apiclient.RepositoryRequest{}
path, err := os.Getwd()
require.NoError(t, err)
q.Path = path
res1, err := service.MatchRepository(context.Background(), &q)
require.NoError(t, err)
require.True(t, res1.IsSupported)
}
func Test_Negative_ConfigFile_DoesnotExist(t *testing.T) {
configFilePath := "./testdata/kustomize-neg/config"
service, err := newService(configFilePath)
require.Error(t, err)
require.Nil(t, service)
}
func TestGenerateManifest(t *testing.T) {
configFilePath := "./testdata/kustomize/config"
service, err := newService(configFilePath)
require.NoError(t, err)
q := apiclient.ManifestRequest{}
res1, err := service.GenerateManifest(context.Background(), &q)
require.NoError(t, err)
require.NotNil(t, res1)
expectedOutput := "{\"apiVersion\":\"v1\",\"data\":{\"foo\":\"bar\"},\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"my-map\"}}"
if res1 != nil {
require.Equal(t, expectedOutput, res1.Manifests[0])
}
}

View File

@@ -1,15 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ConfigManagementPlugin
metadata:
name: ksonnet
spec:
version: v1.0
init:
command: [ks, version]
generate:
command: [sh, -c, "ks show $ARGOCD_APP_ENV"]
discover:
find:
glob: "**/*/main.jsonnet"
allowConcurrency: false
lockRepo: false

View File

@@ -1,16 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ConfigManagementPlugin
metadata:
name: kustomize
spec:
version: v1.0
init:
command: [kustomize, version]
generate:
command: [sh, -c, "cd testdata/kustomize && kustomize build"]
discover:
find:
command: [sh, -c, find . -name kustomization.yaml]
glob: "**/*/kustomization.yaml"
allowConcurrency: true
lockRepo: false

View File

@@ -1,6 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: my-map
data:
foo: bar

View File

@@ -1,16 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ConfigManagementPlugin
metadata:
name: kustomize
spec:
version: v1.0
init:
command: [kustomize, version]
generate:
command: [sh, -c, "cd testdata/kustomize && kustomize build"]
discover:
find:
command: [sh, -c, find . -name kustomization.yaml]
glob: "**/*/kustomization.yaml"
allowConcurrency: true
lockRepo: false

View File

@@ -1,5 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./cm.yaml

View File

@@ -1,107 +0,0 @@
package cmpserver
import (
"net"
"os"
"os/signal"
"syscall"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/health"
"google.golang.org/grpc/health/grpc_health_v1"
"google.golang.org/grpc/reflection"
"github.com/argoproj/argo-cd/v2/cmpserver/apiclient"
"github.com/argoproj/argo-cd/v2/cmpserver/plugin"
"github.com/argoproj/argo-cd/v2/common"
versionpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/version"
"github.com/argoproj/argo-cd/v2/server/version"
"github.com/argoproj/argo-cd/v2/util/errors"
grpc_util "github.com/argoproj/argo-cd/v2/util/grpc"
)
// ArgoCDCMPServer is the config management plugin server implementation
type ArgoCDCMPServer struct {
log *log.Entry
opts []grpc.ServerOption
initConstants plugin.CMPServerInitConstants
stopCh chan os.Signal
doneCh chan interface{}
sig os.Signal
}
// NewServer returns a new instance of the Argo CD config management plugin server
func NewServer(initConstants plugin.CMPServerInitConstants) (*ArgoCDCMPServer, error) {
if os.Getenv(common.EnvEnableGRPCTimeHistogramEnv) == "true" {
grpc_prometheus.EnableHandlingTimeHistogram()
}
serverLog := log.NewEntry(log.StandardLogger())
streamInterceptors := []grpc.StreamServerInterceptor{grpc_logrus.StreamServerInterceptor(serverLog), grpc_prometheus.StreamServerInterceptor, grpc_util.PanicLoggerStreamServerInterceptor(serverLog)}
unaryInterceptors := []grpc.UnaryServerInterceptor{grpc_logrus.UnaryServerInterceptor(serverLog), grpc_prometheus.UnaryServerInterceptor, grpc_util.PanicLoggerUnaryServerInterceptor(serverLog)}
serverOpts := []grpc.ServerOption{
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(unaryInterceptors...)),
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(streamInterceptors...)),
grpc.MaxRecvMsgSize(apiclient.MaxGRPCMessageSize),
grpc.MaxSendMsgSize(apiclient.MaxGRPCMessageSize),
}
return &ArgoCDCMPServer{
log: serverLog,
opts: serverOpts,
stopCh: make(chan os.Signal),
doneCh: make(chan interface{}),
initConstants: initConstants,
}, nil
}
func (a *ArgoCDCMPServer) Run() {
config := a.initConstants.PluginConfig
// Listen on the socket address
_ = os.Remove(config.Address())
listener, err := net.Listen("unix", config.Address())
errors.CheckError(err)
log.Infof("argocd-cmp-server %s serving on %s", common.GetVersion(), listener.Addr())
signal.Notify(a.stopCh, syscall.SIGINT, syscall.SIGTERM)
go a.Shutdown(config.Address())
grpcServer := a.CreateGRPC()
err = grpcServer.Serve(listener)
errors.CheckError(err)
if a.sig != nil {
<-a.doneCh
}
}
// CreateGRPC creates new configured grpc server
func (a *ArgoCDCMPServer) CreateGRPC() *grpc.Server {
server := grpc.NewServer(a.opts...)
versionpkg.RegisterVersionServiceServer(server, version.NewServer(nil, func() (bool, error) {
return true, nil
}))
pluginService := plugin.NewService(a.initConstants)
apiclient.RegisterConfigManagementPluginServiceServer(server, pluginService)
healthService := health.NewServer()
grpc_health_v1.RegisterHealthServer(server, healthService)
// Register reflection service on gRPC server.
reflection.Register(server)
return server
}
func (a *ArgoCDCMPServer) Shutdown(address string) {
defer signal.Stop(a.stopCh)
a.sig = <-a.stopCh
_ = os.Remove(address)
close(a.doneCh)
}

View File

@@ -54,12 +54,6 @@ const (
DefaultGnuPgHomePath = "/app/config/gpg/keys"
// Default path to repo server TLS endpoint config
DefaultAppConfigPath = "/app/config"
// Default path to cmp server plugin socket file
DefaultPluginSockFilePath = "/home/argocd/cmp-server/plugins"
// Default path to cmp server plugin configuration file
DefaultPluginConfigFilePath = "/home/argocd/cmp-server/config"
// Plugin Config File is a ConfigManagementPlugin manifest located inside the plugin container
PluginConfigFileName = "plugin.yaml"
)
// Argo CD application related constants
@@ -119,9 +113,6 @@ const (
// LabelValueSecretTypeRepoCreds indicates a secret type of repository credentials
LabelValueSecretTypeRepoCreds = "repo-creds"
// The Argo CD application name is used as the instance name
AnnotationKeyAppInstance = "argocd.argoproj.io/tracking-id"
// AnnotationCompareOptions is a comma-separated list of options for comparison
AnnotationCompareOptions = "argocd.argoproj.io/compare-options"
@@ -153,12 +144,6 @@ const (
EnvVarTLSDataPath = "ARGOCD_TLS_DATA_PATH"
// Specifies number of git remote operations attempts count
EnvGitAttemptsCount = "ARGOCD_GIT_ATTEMPTS_COUNT"
// Specifices max duration of git remote operation retry
EnvGitRetryMaxDuration = "ARGOCD_GIT_RETRY_MAX_DURATION"
// Specifies duration of git remote operation retry
EnvGitRetryDuration = "ARGOCD_GIT_RETRY_DURATION"
// Specifies fator of git remote operation retry
EnvGitRetryFactor = "ARGOCD_GIT_RETRY_FACTOR"
// Overrides git submodule support, true by default
EnvGitSubmoduleEnabled = "ARGOCD_GIT_MODULES_ENABLED"
// EnvGnuPGHome is the path to ArgoCD's GnuPG keyring for signature verification
@@ -187,10 +172,6 @@ const (
EnvLogFormat = "ARGOCD_LOG_FORMAT"
// EnvLogLevel log level that is defined by `--loglevel` option
EnvLogLevel = "ARGOCD_LOG_LEVEL"
// 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
EnvPluginSockFilePath = "ARGOCD_PLUGINSOCKFILEPATH"
)
const (
@@ -203,18 +184,6 @@ const (
CacheVersion = "1.8.3"
)
// Constants used by util/clusterauth package
const (
ClusterAuthRequestTimeout = 10 * time.Second
BearerTokenTimeout = 30 * time.Second
)
const (
DefaultGitRetryMaxDuration time.Duration = time.Second * 5 // 5s
DefaultGitRetryDuration time.Duration = time.Millisecond * 250 // 0.25s
DefaultGitRetryFactor = int64(2)
)
// GetGnuPGHomePath retrieves the path to use for GnuPG home directory, which is either taken from GNUPGHOME environment or a default value
func GetGnuPGHomePath() string {
if gnuPgHome := os.Getenv(EnvGnuPGHome); gnuPgHome == "" {
@@ -223,12 +192,3 @@ func GetGnuPGHomePath() string {
return gnuPgHome
}
}
// GetPluginSockFilePath retrieves the path of plugin sock file, which is either taken from PluginSockFilePath environment or a default value
func GetPluginSockFilePath() string {
if pluginSockFilePath := os.Getenv(EnvPluginSockFilePath); pluginSockFilePath == "" {
return DefaultPluginSockFilePath
} else {
return pluginSockFilePath
}
}

View File

@@ -113,7 +113,6 @@ type ApplicationController struct {
metricsServer *metrics.MetricsServer
kubectlSemaphore *semaphore.Weighted
clusterFilter func(cluster *appv1.Cluster) bool
projByNameCache sync.Map
}
// NewApplicationController creates new instance of ApplicationController.
@@ -129,7 +128,6 @@ func NewApplicationController(
selfHealTimeout time.Duration,
metricsPort int,
metricsCacheExpiration time.Duration,
metricsApplicationLabels []string,
kubectlParallelismLimit int64,
clusterFilter func(cluster *appv1.Cluster) bool,
) (*ApplicationController, error) {
@@ -154,7 +152,6 @@ func NewApplicationController(
settingsMgr: settingsMgr,
selfHealTimeout: selfHealTimeout,
clusterFilter: clusterFilter,
projByNameCache: sync.Map{},
}
if kubectlParallelismLimit > 0 {
ctrl.kubectlSemaphore = semaphore.NewWeighted(kubectlParallelismLimit)
@@ -167,26 +164,16 @@ func NewApplicationController(
AddFunc: func(obj interface{}) {
if key, err := cache.MetaNamespaceKeyFunc(obj); err == nil {
ctrl.projectRefreshQueue.Add(key)
if projMeta, ok := obj.(metav1.Object); ok {
ctrl.InvalidateProjectsCache(projMeta.GetName())
}
}
},
UpdateFunc: func(old, new interface{}) {
if key, err := cache.MetaNamespaceKeyFunc(new); err == nil {
ctrl.projectRefreshQueue.Add(key)
if projMeta, ok := new.(metav1.Object); ok {
ctrl.InvalidateProjectsCache(projMeta.GetName())
}
}
},
DeleteFunc: func(obj interface{}) {
if key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj); err == nil {
ctrl.projectRefreshQueue.Add(key)
if projMeta, ok := obj.(metav1.Object); ok {
ctrl.InvalidateProjectsCache(projMeta.GetName())
}
}
},
})
@@ -194,7 +181,7 @@ func NewApplicationController(
var err error
ctrl.metricsServer, err = metrics.NewMetricsServer(metricsAddr, appLister, ctrl.canProcessApp, func(r *http.Request) error {
return nil
}, metricsApplicationLabels)
})
if err != nil {
return nil, err
}
@@ -204,8 +191,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())
stateCache := statecache.NewLiveStateCache(db, appInformer, ctrl.settingsMgr, kubectl, ctrl.metricsServer, ctrl.handleObjectUpdated, clusterFilter)
appStateManager := NewAppStateManager(db, applicationClientset, repoClientset, namespace, kubectl, ctrl.settingsMgr, stateCache, projInformer, ctrl.metricsServer, argoCache, ctrl.statusRefreshTimeout)
ctrl.appInformer = appInformer
ctrl.appLister = appLister
ctrl.projInformer = projInformer
@@ -215,19 +202,6 @@ func NewApplicationController(
return &ctrl, nil
}
func (ctrl *ApplicationController) InvalidateProjectsCache(names ...string) {
if len(names) > 0 {
for _, name := range names {
ctrl.projByNameCache.Delete(name)
}
} else {
ctrl.projByNameCache.Range(func(key, _ interface{}) bool {
ctrl.projByNameCache.Delete(key)
return true
})
}
}
func (ctrl *ApplicationController) GetMetricsServer() *metrics.MetricsServer {
return ctrl.metricsServer
}
@@ -257,35 +231,8 @@ func isSelfReferencedApp(app *appv1.Application, ref v1.ObjectReference) bool {
gvk.Kind == application.ApplicationKind
}
func (ctrl *ApplicationController) newAppProjCache(name string) *appProjCache {
return &appProjCache{name: name, ctrl: ctrl}
}
type appProjCache struct {
name string
ctrl *ApplicationController
lock sync.Mutex
appProj *appv1.AppProject
}
func (projCache *appProjCache) GetAppProject(ctx context.Context) (*appv1.AppProject, error) {
projCache.lock.Lock()
defer projCache.lock.Unlock()
if projCache.appProj != nil {
return projCache.appProj, nil
}
proj, err := argo.GetAppProjectByName(projCache.name, applisters.NewAppProjectLister(projCache.ctrl.projInformer.GetIndexer()), projCache.ctrl.namespace, projCache.ctrl.settingsMgr, projCache.ctrl.db, ctx)
if err != nil {
return nil, err
}
projCache.appProj = proj
return projCache.appProj, nil
}
func (ctrl *ApplicationController) getAppProj(app *appv1.Application) (*appv1.AppProject, error) {
projCache, _ := ctrl.projByNameCache.LoadOrStore(app.Spec.GetProject(), ctrl.newAppProjCache(app.Spec.GetProject()))
return projCache.(*appProjCache).GetAppProject(context.TODO())
return argo.GetAppProject(&app.Spec, applisters.NewAppProjectLister(ctrl.projInformer.GetIndexer()), ctrl.namespace, ctrl.settingsMgr)
}
func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]bool, ref v1.ObjectReference) {
@@ -298,8 +245,12 @@ func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]b
if !ok {
continue
}
// exclude resource unless it is permitted in the app project. If project is not permitted then it is not controlled by the user and there is no point showing the warning.
if proj, err := ctrl.getAppProj(app); err == nil && proj.IsGroupKindPermitted(ref.GroupVersionKind().GroupKind(), true) &&
!isKnownOrphanedResourceExclusion(kube.NewResourceKey(ref.GroupVersionKind().Group, ref.GroupVersionKind().Kind, ref.Namespace, ref.Name), proj) {
managedByApp[app.Name] = true
managedByApp[app.Name] = false
}
}
}
}
@@ -326,21 +277,17 @@ func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]b
func (ctrl *ApplicationController) setAppManagedResources(a *appv1.Application, comparisonResult *comparisonResult) (*appv1.ApplicationTree, error) {
managedResources, err := ctrl.managedResources(comparisonResult)
if err != nil {
return nil, fmt.Errorf("error getting managed resources: %s", err)
return nil, err
}
tree, err := ctrl.getResourceTree(a, managedResources)
if err != nil {
return nil, fmt.Errorf("error getting resource tree: %s", err)
return nil, err
}
err = ctrl.cache.SetAppResourcesTree(a.Name, tree)
if err != nil {
return nil, fmt.Errorf("error setting app resource tree: %s", err)
return nil, err
}
err = ctrl.cache.SetAppManagedResources(a.Name, managedResources)
if err != nil {
return nil, fmt.Errorf("error setting app managed resources: %s", err)
}
return tree, nil
return tree, ctrl.cache.SetAppManagedResources(a.Name, managedResources)
}
// returns true of given resources exist in the namespace by default and not managed by the user
@@ -370,7 +317,7 @@ func isKnownOrphanedResourceExclusion(key kube.ResourceKey, proj *appv1.AppProje
func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managedResources []*appv1.ResourceDiff) (*appv1.ApplicationTree, error) {
nodes := make([]appv1.ResourceNode, 0)
proj, err := ctrl.getAppProj(a)
proj, err := argo.GetAppProject(&a.Spec, applisters.NewAppProjectLister(ctrl.projInformer.GetIndexer()), ctrl.namespace, ctrl.settingsMgr)
if err != nil {
return nil, err
}
@@ -570,18 +517,18 @@ func (ctrl *ApplicationController) managedResources(comparisonResult *comparison
var err error
target, live, err = diff.HideSecretData(res.Target, res.Live)
if err != nil {
return nil, fmt.Errorf("error hiding secret data: %s", err)
return nil, err
}
compareOptions, err := ctrl.settingsMgr.GetResourceCompareOptions()
if err != nil {
return nil, fmt.Errorf("error getting resource compare options: %s", err)
return nil, err
}
resDiffPtr, err := diff.Diff(target, live,
diff.WithNormalizer(comparisonResult.diffNormalizer),
diff.WithLogr(logutils.NewLogrusLogger(logutils.NewWithCurrentConfig())),
diff.IgnoreAggregatedRoles(compareOptions.IgnoreAggregatedRoles))
if err != nil {
return nil, fmt.Errorf("error applying diff: %s", err)
return nil, err
}
resDiff = *resDiffPtr
}
@@ -589,7 +536,7 @@ func (ctrl *ApplicationController) managedResources(comparisonResult *comparison
if live != nil {
data, err := json.Marshal(live)
if err != nil {
return nil, fmt.Errorf("error marshaling live json: %s", err)
return nil, err
}
item.LiveState = string(data)
} else {
@@ -599,7 +546,7 @@ func (ctrl *ApplicationController) managedResources(comparisonResult *comparison
if target != nil {
data, err := json.Marshal(target)
if err != nil {
return nil, fmt.Errorf("error marshaling target json: %s", err)
return nil, err
}
item.TargetState = string(data)
} else {
@@ -861,7 +808,7 @@ func (ctrl *ApplicationController) getPermittedAppLiveObjects(app *appv1.Applica
}
// Don't delete live resources which are not permitted in the app project
for k, v := range objsMap {
if !proj.IsLiveResourcePermitted(v, app.Spec.Destination.Server, app.Spec.Destination.Name) {
if !proj.IsLiveResourcePermitted(v, app.Spec.Destination.Server) {
delete(objsMap, k)
}
}
@@ -1661,7 +1608,7 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar
return nil, nil
}
proj, err := applisters.NewAppProjectLister(ctrl.projInformer.GetIndexer()).AppProjects(ctrl.namespace).Get(app.Spec.GetProject())
proj, err := ctrl.getAppProj(app)
if err != nil {
return nil, nil
}

View File

@@ -106,7 +106,6 @@ func newFakeController(data *fakeData) *ApplicationController {
time.Minute,
common.DefaultPortArgoCDMetrics,
data.metricsCacheExpiration,
[]string{},
0,
nil,
)
@@ -785,11 +784,11 @@ func TestHandleOrphanedResourceUpdated(t *testing.T) {
isRequested, level := ctrl.isRefreshRequested(app1.Name)
assert.True(t, isRequested)
assert.Equal(t, CompareWithRecent, level)
assert.Equal(t, ComparisonWithNothing, level)
isRequested, level = ctrl.isRefreshRequested(app2.Name)
assert.True(t, isRequested)
assert.Equal(t, CompareWithRecent, level)
assert.Equal(t, ComparisonWithNothing, level)
}
func TestGetResourceTree_HasOrphanedResources(t *testing.T) {

View File

@@ -3,7 +3,7 @@ package cache
import (
"context"
"fmt"
"math"
"os"
"reflect"
"sync"
"time"
@@ -24,7 +24,6 @@ import (
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/db"
"github.com/argoproj/argo-cd/v2/util/env"
logutils "github.com/argoproj/argo-cd/v2/util/log"
"github.com/argoproj/argo-cd/v2/util/lua"
"github.com/argoproj/argo-cd/v2/util/settings"
@@ -33,47 +32,25 @@ import (
const (
// EnvClusterCacheResyncDuration is the env variable that holds cluster cache re-sync duration
EnvClusterCacheResyncDuration = "ARGOCD_CLUSTER_CACHE_RESYNC_DURATION"
// EnvClusterCacheWatchResyncDuration is the env variable that holds cluster cache watch re-sync duration
EnvClusterCacheWatchResyncDuration = "ARGOCD_CLUSTER_CACHE_WATCH_RESYNC_DURATION"
// EnvClusterCacheListPageSize is the env variable to control size of the list page size when making K8s queries
EnvClusterCacheListPageSize = "ARGOCD_CLUSTER_CACHE_LIST_PAGE_SIZE"
// EnvClusterCacheListSemaphore is the env variable to control size of the list semaphore
// This is used to limit the number of concurrent memory consuming operations on the
// k8s list queries results across all clusters to avoid memory spikes during cache initialization.
EnvClusterCacheListSemaphore = "ARGOCD_CLUSTER_CACHE_LIST_SEMAPHORE"
)
// GitOps engine cluster cache tuning options
var (
// clusterCacheResyncDuration controls the duration of cluster cache refresh.
// NOTE: this differs from gitops-engine default of 24h
clusterCacheResyncDuration = 12 * time.Hour
// clusterCacheWatchResyncDuration controls the maximum duration that group/kind watches are allowed to run
// for before relisting & restarting the watch
clusterCacheWatchResyncDuration = 10 * time.Minute
// The default limit of 50 is chosen based on experiments.
clusterCacheListSemaphoreSize int64 = 50
// clusterCacheListPageSize is the page size when performing K8s list requests.
// 500 is equal to kubectl's size
clusterCacheListPageSize int64 = 500
// K8SClusterResyncDuration controls the duration of cluster cache refresh
K8SClusterResyncDuration = 12 * time.Hour
)
func init() {
clusterCacheResyncDuration = env.ParseDurationFromEnv(EnvClusterCacheResyncDuration, clusterCacheResyncDuration, 0, math.MaxInt64)
clusterCacheWatchResyncDuration = env.ParseDurationFromEnv(EnvClusterCacheWatchResyncDuration, clusterCacheWatchResyncDuration, 0, math.MaxInt64)
clusterCacheListPageSize = env.ParseInt64FromEnv(EnvClusterCacheListPageSize, clusterCacheListPageSize, 0, math.MaxInt64)
clusterCacheListSemaphoreSize = env.ParseInt64FromEnv(EnvClusterCacheListSemaphore, clusterCacheListSemaphoreSize, 0, math.MaxInt64)
if clusterResyncDurationStr := os.Getenv(EnvClusterCacheResyncDuration); clusterResyncDurationStr != "" {
if duration, err := time.ParseDuration(clusterResyncDurationStr); err == nil {
K8SClusterResyncDuration = duration
}
}
}
type LiveStateCache interface {
// Returns k8s server version
GetVersionsInfo(serverURL string) (string, []kube.APIResourceInfo, error)
GetVersionsInfo(serverURL string) (string, []metav1.APIGroup, error)
// Returns true of given group kind is a namespaced resource
IsNamespaced(server string, gk schema.GroupKind) (bool, error)
// Returns synced cluster cache
@@ -128,19 +105,19 @@ func NewLiveStateCache(
kubectl kube.Kubectl,
metricsServer *metrics.MetricsServer,
onObjectUpdated ObjectUpdatedHandler,
clusterFilter func(cluster *appv1.Cluster) bool,
resourceTracking argo.ResourceTracking) LiveStateCache {
clusterFilter func(cluster *appv1.Cluster) bool) LiveStateCache {
return &liveStateCache{
appInformer: appInformer,
db: db,
clusters: make(map[string]clustercache.ClusterCache),
onObjectUpdated: onObjectUpdated,
kubectl: kubectl,
settingsMgr: settingsMgr,
metricsServer: metricsServer,
clusterFilter: clusterFilter,
resourceTracking: resourceTracking,
appInformer: appInformer,
db: db,
clusters: make(map[string]clustercache.ClusterCache),
onObjectUpdated: onObjectUpdated,
kubectl: kubectl,
settingsMgr: settingsMgr,
metricsServer: metricsServer,
// The default limit of 50 is chosen based on experiments.
listSemaphore: semaphore.NewWeighted(50),
clusterFilter: clusterFilter,
}
}
@@ -150,14 +127,17 @@ 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
clusterFilter func(cluster *appv1.Cluster) bool
// listSemaphore is used to limit the number of concurrent memory consuming operations on the
// k8s list queries results across all clusters to avoid memory spikes during cache initialization.
listSemaphore *semaphore.Weighted
clusters map[string]clustercache.ClusterCache
cacheSettings cacheSettings
@@ -305,12 +285,9 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
return nil, fmt.Errorf("controller is configured to ignore cluster %s", cluster.Server)
}
trackingMethod := argo.GetTrackingMethod(c.settingsMgr)
clusterCacheOpts := []clustercache.UpdateSettingsFunc{
clustercache.SetListSemaphore(semaphore.NewWeighted(clusterCacheListSemaphoreSize)),
clustercache.SetListPageSize(clusterCacheListPageSize),
clustercache.SetWatchResyncTimeout(clusterCacheWatchResyncDuration),
clustercache.SetResyncTimeout(clusterCacheResyncDuration),
clusterCache = clustercache.NewClusterCache(cluster.RESTConfig(),
clustercache.SetListSemaphore(c.listSemaphore),
clustercache.SetResyncTimeout(K8SClusterResyncDuration),
clustercache.SetSettings(cacheSettings.clusterSettings),
clustercache.SetNamespaces(cluster.Namespaces),
clustercache.SetClusterResources(cluster.ClusterResources),
@@ -318,8 +295,7 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
res := &ResourceInfo{}
populateNodeInfo(un, res)
res.Health, _ = health.GetResourceHealth(un, cacheSettings.clusterSettings.ResourceHealthOverride)
appName := c.resourceTracking.GetAppName(un, cacheSettings.appInstanceLabelKey, trackingMethod)
appName := kube.GetAppInstanceLabel(un, cacheSettings.appInstanceLabelKey)
if isRoot && appName != "" {
res.AppName = appName
}
@@ -330,9 +306,7 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
return res, res.AppName != "" || gvk.Kind == kube.CustomResourceDefinitionKind
}),
clustercache.SetLogr(logutils.NewLogrusLogger(log.WithField("server", cluster.Server))),
}
clusterCache = clustercache.NewClusterCache(cluster.RESTConfig(), clusterCacheOpts...)
)
_ = clusterCache.OnResourceUpdated(func(newRes *clustercache.Resource, oldRes *clustercache.Resource, namespaceResources map[kube.ResourceKey]*clustercache.Resource) {
toNotify := make(map[string]bool)
@@ -445,12 +419,12 @@ func (c *liveStateCache) GetManagedLiveObjs(a *appv1.Application, targetObjs []*
})
}
func (c *liveStateCache) GetVersionsInfo(serverURL string) (string, []kube.APIResourceInfo, error) {
func (c *liveStateCache) GetVersionsInfo(serverURL string) (string, []metav1.APIGroup, error) {
clusterInfo, err := c.getSyncedCluster(serverURL)
if err != nil {
return "", nil, err
}
return clusterInfo.GetServerVersion(), clusterInfo.GetAPIResources(), nil
return clusterInfo.GetServerVersion(), clusterInfo.GetAPIGroups(), nil
}
func (c *liveStateCache) isClusterHasApps(apps []interface{}, cluster *appv1.Cluster) bool {

View File

@@ -1,12 +1,9 @@
package cache
import (
"errors"
"fmt"
"strings"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/argoproj/gitops-engine/pkg/utils/text"
v1 "k8s.io/api/core/v1"
@@ -89,36 +86,16 @@ func populateServiceInfo(un *unstructured.Unstructured, res *ResourceInfo) {
res.NetworkingInfo = &v1alpha1.ResourceNetworkingInfo{TargetLabels: targetLabels, Ingress: ingress}
}
func getServiceName(backend map[string]interface{}, gvk schema.GroupVersionKind) (string, error) {
switch gvk.Group {
case "extensions":
return fmt.Sprintf("%s", backend["serviceName"]), nil
case "networking.k8s.io":
switch gvk.Version {
case "v1beta1":
return fmt.Sprintf("%s", backend["serviceName"]), nil
case "v1":
if service, ok, err := unstructured.NestedMap(backend, "service"); ok && err == nil {
return fmt.Sprintf("%s", service["name"]), nil
}
}
}
return "", errors.New("unable to resolve string")
}
func populateIngressInfo(un *unstructured.Unstructured, res *ResourceInfo) {
ingress := getIngress(un)
targetsMap := make(map[v1alpha1.ResourceRef]bool)
gvk := un.GroupVersionKind()
if backend, ok, err := unstructured.NestedMap(un.Object, "spec", "backend"); ok && err == nil {
if serviceName, err := getServiceName(backend, gvk); err == nil {
targetsMap[v1alpha1.ResourceRef{
Group: "",
Kind: kube.ServiceKind,
Namespace: un.GetNamespace(),
Name: serviceName,
}] = true
}
targetsMap[v1alpha1.ResourceRef{
Group: "",
Kind: kube.ServiceKind,
Namespace: un.GetNamespace(),
Name: fmt.Sprintf("%s", backend["serviceName"]),
}] = true
}
urlsSet := make(map[string]bool)
if rules, ok, err := unstructured.NestedSlice(un.Object, "spec", "rules"); ok && err == nil {
@@ -146,15 +123,13 @@ func populateIngressInfo(un *unstructured.Unstructured, res *ResourceInfo) {
continue
}
if backend, ok, err := unstructured.NestedMap(path, "backend"); ok && err == nil {
if serviceName, err := getServiceName(backend, gvk); err == nil {
targetsMap[v1alpha1.ResourceRef{
Group: "",
Kind: kube.ServiceKind,
Namespace: un.GetNamespace(),
Name: serviceName,
}] = true
}
if serviceName, ok, err := unstructured.NestedString(path, "backend", "serviceName"); ok && err == nil {
targetsMap[v1alpha1.ResourceRef{
Group: "",
Kind: kube.ServiceKind,
Namespace: un.GetNamespace(),
Name: serviceName,
}] = true
}
if host == nil || host == "" {

View File

@@ -133,43 +133,6 @@ var (
ingress:
- ip: 107.178.210.11`)
testIngressNetworkingV1 = strToUnstructured(`
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: helm-guestbook
namespace: default
uid: "4"
spec:
backend:
service:
name: not-found-service
port:
number: 443
rules:
- host: helm-guestbook.com
http:
paths:
- backend:
service:
name: helm-guestbook
port:
number: 443
path: /
- backend:
service:
name: helm-guestbook
port:
name: https
path: /
tls:
- host: helm-guestbook.com
secretName: my-tls-secret
status:
loadBalancer:
ingress:
- ip: 107.178.210.11`)
testIstioVirtualService = strToUnstructured(`
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
@@ -292,35 +255,27 @@ func TestGetIstioVirtualServiceInfo(t *testing.T) {
}
func TestGetIngressInfo(t *testing.T) {
var tests = []struct {
Ingress *unstructured.Unstructured
}{
{testIngress},
{testIngressNetworkingV1},
}
for _, tc := range tests {
info := &ResourceInfo{}
populateNodeInfo(tc.Ingress, info)
assert.Equal(t, 0, len(info.Info))
sort.Slice(info.NetworkingInfo.TargetRefs, func(i, j int) bool {
return strings.Compare(info.NetworkingInfo.TargetRefs[j].Name, info.NetworkingInfo.TargetRefs[i].Name) < 0
})
assert.Equal(t, &v1alpha1.ResourceNetworkingInfo{
Ingress: []v1.LoadBalancerIngress{{IP: "107.178.210.11"}},
TargetRefs: []v1alpha1.ResourceRef{{
Namespace: "default",
Group: "",
Kind: kube.ServiceKind,
Name: "not-found-service",
}, {
Namespace: "default",
Group: "",
Kind: kube.ServiceKind,
Name: "helm-guestbook",
}},
ExternalURLs: []string{"https://helm-guestbook.com/"},
}, info.NetworkingInfo)
}
info := &ResourceInfo{}
populateNodeInfo(testIngress, info)
assert.Equal(t, 0, len(info.Info))
sort.Slice(info.NetworkingInfo.TargetRefs, func(i, j int) bool {
return strings.Compare(info.NetworkingInfo.TargetRefs[j].Name, info.NetworkingInfo.TargetRefs[i].Name) < 0
})
assert.Equal(t, &v1alpha1.ResourceNetworkingInfo{
Ingress: []v1.LoadBalancerIngress{{IP: "107.178.210.11"}},
TargetRefs: []v1alpha1.ResourceRef{{
Namespace: "default",
Group: "",
Kind: kube.ServiceKind,
Name: "not-found-service",
}, {
Namespace: "default",
Group: "",
Kind: kube.ServiceKind,
Name: "helm-guestbook",
}},
ExternalURLs: []string{"https://helm-guestbook.com/"},
}, info.NetworkingInfo)
}
func TestGetIngressInfoWildCardPath(t *testing.T) {
@@ -441,7 +396,7 @@ func TestGetIngressInfoNoHost(t *testing.T) {
}
func TestExternalUrlWithSubPath(t *testing.T) {
ingress := strToUnstructured(`
apiVersion: networking.k8s.io/v1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: helm-guestbook
@@ -469,7 +424,7 @@ func TestExternalUrlWithSubPath(t *testing.T) {
}
func TestExternalUrlWithMultipleSubPaths(t *testing.T) {
ingress := strToUnstructured(`
apiVersion: networking.k8s.io/v1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: helm-guestbook
@@ -508,7 +463,7 @@ func TestExternalUrlWithMultipleSubPaths(t *testing.T) {
}
func TestExternalUrlWithNoSubPath(t *testing.T) {
ingress := strToUnstructured(`
apiVersion: networking.k8s.io/v1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: helm-guestbook

View File

@@ -17,6 +17,8 @@ import (
unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
)
@@ -111,7 +113,7 @@ func (_m *LiveStateCache) GetNamespaceTopLevelResources(server string, namespace
}
// GetVersionsInfo provides a mock function with given fields: serverURL
func (_m *LiveStateCache) GetVersionsInfo(serverURL string) (string, []kube.APIResourceInfo, error) {
func (_m *LiveStateCache) GetVersionsInfo(serverURL string) (string, []v1.APIGroup, error) {
ret := _m.Called(serverURL)
var r0 string
@@ -121,12 +123,12 @@ func (_m *LiveStateCache) GetVersionsInfo(serverURL string) (string, []kube.APIR
r0 = ret.Get(0).(string)
}
var r1 []kube.APIResourceInfo
if rf, ok := ret.Get(1).(func(string) []kube.APIResourceInfo); ok {
var r1 []v1.APIGroup
if rf, ok := ret.Get(1).(func(string) []v1.APIGroup); ok {
r1 = rf(serverURL)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).([]kube.APIResourceInfo)
r1 = ret.Get(1).([]v1.APIGroup)
}
}

View File

@@ -106,7 +106,7 @@ func (c *clusterInfoUpdater) updateClusterInfo(cluster appv1.Cluster, info *cach
}
if info != nil {
clusterInfo.ServerVersion = info.K8SVersion
clusterInfo.APIVersions = argo.APIResourcesToStrings(info.APIResources, false)
clusterInfo.APIVersions = argo.APIGroupsToVersions(info.APIGroups)
if info.LastCacheSyncTime == nil {
clusterInfo.ConnectionState.Status = appv1.ConnectionStatusUnknown
} else if info.SyncError == nil {

View File

@@ -41,12 +41,6 @@ var (
descClusterDefaultLabels,
nil,
)
descClusterConnectionStatus = prometheus.NewDesc(
"argocd_cluster_connection_status",
"The k8s cluster current connection status.",
append(descClusterDefaultLabels, "k8s_version"),
nil,
)
)
type HasClustersInfo interface {
@@ -83,11 +77,9 @@ func (c *clusterCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- descClusterCacheResources
ch <- descClusterAPIs
ch <- descClusterCacheAgeSeconds
ch <- descClusterConnectionStatus
}
func (c *clusterCollector) Collect(ch chan<- prometheus.Metric) {
now := time.Now()
for _, c := range c.info {
defaultValues := []string{c.Server}
@@ -99,6 +91,5 @@ func (c *clusterCollector) Collect(ch chan<- prometheus.Metric) {
cacheAgeSeconds = int(now.Sub(*c.LastCacheSyncTime).Seconds())
}
ch <- prometheus.MustNewConstMetric(descClusterCacheAgeSeconds, prometheus.GaugeValue, float64(cacheAgeSeconds), defaultValues...)
ch <- prometheus.MustNewConstMetric(descClusterConnectionStatus, prometheus.GaugeValue, boolFloat64(c.SyncError == nil), append(defaultValues, c.K8SVersion)...)
}
}

View File

@@ -1,104 +0,0 @@
package metrics
import (
"errors"
"testing"
gitopsCache "github.com/argoproj/gitops-engine/pkg/cache"
)
func TestMetricClusterConnectivity(t *testing.T) {
type testCases struct {
testCombination
skip bool
description string
metricLabels []string
clustersInfo []gitopsCache.ClusterInfo
}
cases := []testCases{
{
description: "metric will have value 1 if connected with the cluster",
skip: false,
metricLabels: []string{"non-existing"},
testCombination: testCombination{
applications: []string{fakeApp},
responseContains: `
# TYPE argocd_cluster_connection_status gauge
argocd_cluster_connection_status{k8s_version="1.21",server="server1"} 1
`,
},
clustersInfo: []gitopsCache.ClusterInfo{
{
Server: "server1",
K8SVersion: "1.21",
SyncError: nil,
},
},
},
{
description: "metric will have value 0 if not connected with the cluster",
skip: false,
metricLabels: []string{"non-existing"},
testCombination: testCombination{
applications: []string{fakeApp},
responseContains: `
# TYPE argocd_cluster_connection_status gauge
argocd_cluster_connection_status{k8s_version="1.21",server="server1"} 0
`,
},
clustersInfo: []gitopsCache.ClusterInfo{
{
Server: "server1",
K8SVersion: "1.21",
SyncError: errors.New("error connecting with cluster"),
},
},
},
{
description: "will have one metric per cluster",
skip: false,
metricLabels: []string{"non-existing"},
testCombination: testCombination{
applications: []string{fakeApp},
responseContains: `
# TYPE argocd_cluster_connection_status gauge
argocd_cluster_connection_status{k8s_version="1.21",server="server1"} 1
argocd_cluster_connection_status{k8s_version="1.21",server="server2"} 1
argocd_cluster_connection_status{k8s_version="1.21",server="server3"} 1
`,
},
clustersInfo: []gitopsCache.ClusterInfo{
{
Server: "server1",
K8SVersion: "1.21",
SyncError: nil,
},
{
Server: "server2",
K8SVersion: "1.21",
SyncError: nil,
},
{
Server: "server3",
K8SVersion: "1.21",
SyncError: nil,
},
},
},
}
for _, c := range cases {
c := c
t.Run(c.description, func(t *testing.T) {
if !c.skip {
cfg := TestMetricServerConfig{
FakeAppYAMLs: c.applications,
ExpectedResponse: c.responseContains,
AppLabels: c.metricLabels,
ClustersInfo: c.clustersInfo,
}
runTest(t, cfg)
}
})
}
}

View File

@@ -7,7 +7,6 @@ import (
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/argoproj/gitops-engine/pkg/health"
@@ -21,7 +20,6 @@ import (
applister "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/git"
"github.com/argoproj/argo-cd/v2/util/healthz"
"github.com/argoproj/argo-cd/v2/util/profile"
)
type MetricsServer struct {
@@ -51,8 +49,6 @@ const (
var (
descAppDefaultLabels = []string{"namespace", "name", "project"}
descAppLabels *prometheus.Desc
descAppInfo = prometheus.NewDesc(
"argocd_app_info",
"Information about application.",
@@ -125,7 +121,7 @@ var (
redisRequestCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "argocd_redis_request_total",
Help: "Number of redis requests executed during application reconciliation.",
Help: "Number of kubernetes requests executed during application reconciliation.",
},
[]string{"hostname", "initiator", "failed"},
)
@@ -141,31 +137,19 @@ var (
)
// NewMetricsServer returns a new prometheus server which collects application metrics
func NewMetricsServer(addr string, appLister applister.ApplicationLister, appFilter func(obj interface{}) bool, healthCheck func(r *http.Request) error, appLabels []string) (*MetricsServer, error) {
func NewMetricsServer(addr string, appLister applister.ApplicationLister, appFilter func(obj interface{}) bool, healthCheck func(r *http.Request) error) (*MetricsServer, error) {
hostname, err := os.Hostname()
if err != nil {
return nil, err
}
if len(appLabels) > 0 {
normalizedLabels := normalizeLabels("label", appLabels)
descAppLabels = prometheus.NewDesc(
"argocd_app_labels",
"Argo Application labels converted to Prometheus labels",
append(descAppDefaultLabels, normalizedLabels...),
nil,
)
}
mux := http.NewServeMux()
registry := NewAppRegistry(appLister, appFilter, appLabels)
registry := NewAppRegistry(appLister, appFilter)
mux.Handle(MetricsPath, promhttp.HandlerFor(prometheus.Gatherers{
// contains app controller specific metrics
registry,
// contains process, golang and controller workqueues metrics
prometheus.DefaultGatherer,
}, promhttp.HandlerOpts{}))
profile.RegisterProfiler(mux)
healthz.ServeHealthCheck(mux, healthCheck)
registry.MustRegister(syncCounter)
@@ -196,17 +180,6 @@ func NewMetricsServer(addr string, appLister applister.ApplicationLister, appFil
}, nil
}
func normalizeLabels(prefix string, appLabels []string) []string {
results := []string{}
for _, label := range appLabels {
//prometheus labels don't accept dash in their name
curr := strings.ReplaceAll(label, "-", "_")
result := fmt.Sprintf("%s_%s", prefix, curr)
results = append(results, result)
}
return results
}
func (m *MetricsServer) RegisterClustersInfoSource(ctx context.Context, source HasClustersInfo) {
collector := &clusterCollector{infoSource: source}
go collector.Run(ctx)
@@ -299,30 +272,25 @@ func (m *MetricsServer) SetExpiration(cacheExpiration time.Duration) error {
type appCollector struct {
store applister.ApplicationLister
appFilter func(obj interface{}) bool
appLabels []string
}
// NewAppCollector returns a prometheus collector for application metrics
func NewAppCollector(appLister applister.ApplicationLister, appFilter func(obj interface{}) bool, appLabels []string) prometheus.Collector {
func NewAppCollector(appLister applister.ApplicationLister, appFilter func(obj interface{}) bool) prometheus.Collector {
return &appCollector{
store: appLister,
appFilter: appFilter,
appLabels: appLabels,
}
}
// NewAppRegistry creates a new prometheus registry that collects applications
func NewAppRegistry(appLister applister.ApplicationLister, appFilter func(obj interface{}) bool, appLabels []string) *prometheus.Registry {
func NewAppRegistry(appLister applister.ApplicationLister, appFilter func(obj interface{}) bool) *prometheus.Registry {
registry := prometheus.NewRegistry()
registry.MustRegister(NewAppCollector(appLister, appFilter, appLabels))
registry.MustRegister(NewAppCollector(appLister, appFilter))
return registry
}
// Describe implements the prometheus.Collector interface
func (c *appCollector) Describe(ch chan<- *prometheus.Desc) {
if len(c.appLabels) > 0 {
ch <- descAppLabels
}
ch <- descAppInfo
ch <- descAppSyncStatusCode
ch <- descAppHealthStatus
@@ -337,7 +305,7 @@ func (c *appCollector) Collect(ch chan<- prometheus.Metric) {
}
for _, app := range apps {
if c.appFilter(app) {
c.collectApps(ch, app)
collectApps(ch, app)
}
}
}
@@ -349,7 +317,7 @@ func boolFloat64(b bool) float64 {
return 0
}
func (c *appCollector) collectApps(ch chan<- prometheus.Metric, app *argoappv1.Application) {
func collectApps(ch chan<- prometheus.Metric, app *argoappv1.Application) {
addConstMetric := func(desc *prometheus.Desc, t prometheus.ValueType, v float64, lv ...string) {
project := app.Spec.GetProject()
lv = append([]string{app.Namespace, app.Name, project}, lv...)
@@ -376,15 +344,6 @@ func (c *appCollector) collectApps(ch chan<- prometheus.Metric, app *argoappv1.A
addGauge(descAppInfo, 1, git.NormalizeGitURL(app.Spec.Source.RepoURL), app.Spec.Destination.Server, app.Spec.Destination.Namespace, string(syncStatus), string(healthStatus), operation)
if len(c.appLabels) > 0 {
labelValues := []string{}
for _, desiredLabel := range c.appLabels {
value := app.GetLabels()[desiredLabel]
labelValues = append(labelValues, value)
}
addGauge(descAppLabels, 1, labelValues...)
}
// Deprecated controller metrics
if os.Getenv(EnvVarLegacyControllerMetrics) == "true" {
addGauge(descAppCreated, float64(app.CreationTimestamp.Unix()))

View File

@@ -10,7 +10,6 @@ import (
"testing"
"time"
gitopsCache "github.com/argoproj/gitops-engine/pkg/cache"
"github.com/argoproj/gitops-engine/pkg/sync/common"
"github.com/ghodss/yaml"
"github.com/stretchr/testify/assert"
@@ -30,9 +29,6 @@ kind: Application
metadata:
name: my-app
namespace: argocd
labels:
team-name: my-team
team-bu: bu-id
spec:
destination:
namespace: dummy-namespace
@@ -54,9 +50,6 @@ kind: Application
metadata:
name: my-app-2
namespace: argocd
labels:
team-name: my-team
team-bu: bu-id
spec:
destination:
namespace: dummy-namespace
@@ -84,9 +77,6 @@ metadata:
name: my-app-3
namespace: argocd
deletionTimestamp: "2020-03-16T09:17:45Z"
labels:
team-name: my-team
team-bu: bu-id
spec:
destination:
namespace: dummy-namespace
@@ -148,7 +138,7 @@ func newFakeLister(fakeAppYAMLs ...string) (context.CancelFunc, applister.Applic
fakeApps = append(fakeApps, a)
}
appClientset := appclientset.NewSimpleClientset(fakeApps...)
factory := appinformer.NewSharedInformerFactoryWithOptions(appClientset, 0, appinformer.WithNamespace("argocd"), appinformer.WithTweakListOptions(func(options *metav1.ListOptions) {}))
factory := appinformer.NewFilteredSharedInformerFactory(appClientset, 0, "argocd", func(options *metav1.ListOptions) {})
appInformer := factory.Argoproj().V1alpha1().Applications().Informer()
go appInformer.Run(ctx.Done())
if !cache.WaitForCacheSync(ctx.Done(), appInformer.HasSynced) {
@@ -158,71 +148,30 @@ func newFakeLister(fakeAppYAMLs ...string) (context.CancelFunc, applister.Applic
}
func testApp(t *testing.T, fakeAppYAMLs []string, expectedResponse string) {
t.Helper()
testMetricServer(t, fakeAppYAMLs, expectedResponse, []string{})
}
type fakeClusterInfo struct {
clustersInfo []gitopsCache.ClusterInfo
}
func (f *fakeClusterInfo) GetClustersInfo() []gitopsCache.ClusterInfo {
return f.clustersInfo
}
type TestMetricServerConfig struct {
FakeAppYAMLs []string
ExpectedResponse string
AppLabels []string
ClustersInfo []gitopsCache.ClusterInfo
}
func testMetricServer(t *testing.T, fakeAppYAMLs []string, expectedResponse string, appLabels []string) {
t.Helper()
cfg := TestMetricServerConfig{
FakeAppYAMLs: fakeAppYAMLs,
ExpectedResponse: expectedResponse,
AppLabels: appLabels,
ClustersInfo: []gitopsCache.ClusterInfo{},
}
runTest(t, cfg)
}
func runTest(t *testing.T, cfg TestMetricServerConfig) {
t.Helper()
cancel, appLister := newFakeLister(cfg.FakeAppYAMLs...)
cancel, appLister := newFakeLister(fakeAppYAMLs...)
defer cancel()
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, cfg.AppLabels)
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck)
assert.NoError(t, err)
if len(cfg.ClustersInfo) > 0 {
ci := &fakeClusterInfo{clustersInfo: cfg.ClustersInfo}
collector := &clusterCollector{
infoSource: ci,
info: ci.GetClustersInfo(),
}
metricsServ.registry.MustRegister(collector)
}
req, err := http.NewRequest("GET", "/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()
assertMetricsPrinted(t, cfg.ExpectedResponse, body)
log.Println(body)
assertMetricsPrinted(t, expectedResponse, body)
}
type testCombination struct {
applications []string
responseContains string
expectedResponse string
}
func TestMetrics(t *testing.T) {
combinations := []testCombination{
{
applications: []string{fakeApp, fakeApp2, fakeApp3},
responseContains: `
expectedResponse: `
# HELP argocd_app_info Information about application.
# TYPE argocd_app_info gauge
argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Degraded",name="my-app-3",namespace="argocd",operation="delete",project="important-project",repo="https://github.com/argoproj/argocd-example-apps",sync_status="OutOfSync"} 1
@@ -232,7 +181,7 @@ argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:
},
{
applications: []string{fakeDefaultApp},
responseContains: `
expectedResponse: `
# HELP argocd_app_info Information about application.
# TYPE argocd_app_info gauge
argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Healthy",name="my-app",namespace="argocd",operation="",project="default",repo="https://github.com/argoproj/argocd-example-apps",sync_status="Synced"} 1
@@ -241,50 +190,7 @@ argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:
}
for _, combination := range combinations {
testApp(t, combination.applications, combination.responseContains)
}
}
func TestMetricLabels(t *testing.T) {
type testCases struct {
testCombination
description string
metricLabels []string
}
cases := []testCases{
{
description: "will return the labels metrics successfully",
metricLabels: []string{"team-name", "team-bu"},
testCombination: testCombination{
applications: []string{fakeApp, fakeApp2, fakeApp3},
responseContains: `
# TYPE argocd_app_labels gauge
argocd_app_labels{label_team_bu="bu-id",label_team_name="my-team",name="my-app",namespace="argocd",project="important-project"} 1
argocd_app_labels{label_team_bu="bu-id",label_team_name="my-team",name="my-app-2",namespace="argocd",project="important-project"} 1
argocd_app_labels{label_team_bu="bu-id",label_team_name="my-team",name="my-app-3",namespace="argocd",project="important-project"} 1
`,
},
},
{
description: "metric will have empty label value if not present in the application",
metricLabels: []string{"non-existing"},
testCombination: testCombination{
applications: []string{fakeApp, fakeApp2, fakeApp3},
responseContains: `
# TYPE argocd_app_labels gauge
argocd_app_labels{label_non_existing="",name="my-app",namespace="argocd",project="important-project"} 1
argocd_app_labels{label_non_existing="",name="my-app-2",namespace="argocd",project="important-project"} 1
argocd_app_labels{label_non_existing="",name="my-app-3",namespace="argocd",project="important-project"} 1
`,
},
},
}
for _, c := range cases {
c := c
t.Run(c.description, func(t *testing.T) {
testMetricServer(t, c.applications, c.responseContains, c.metricLabels)
})
testApp(t, combination.applications, combination.expectedResponse)
}
}
@@ -316,7 +222,7 @@ argocd_app_sync_status{name="my-app",namespace="argocd",project="important-proje
func TestMetricsSyncCounter(t *testing.T) {
cancel, appLister := newFakeLister()
defer cancel()
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{})
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck)
assert.NoError(t, err)
appSyncTotal := `
@@ -346,12 +252,11 @@ argocd_app_sync_total{dest_server="https://localhost:6443",name="my-app",namespa
// assertMetricsPrinted asserts every line in the expected lines appears in the body
func assertMetricsPrinted(t *testing.T, expectedLines, body string) {
t.Helper()
for _, line := range strings.Split(expectedLines, "\n") {
if line == "" {
continue
}
assert.Contains(t, body, line, "expected metrics mismatch")
assert.Contains(t, body, line)
}
}
@@ -368,7 +273,7 @@ func assertMetricsNotPrinted(t *testing.T, expectedLines, body string) {
func TestReconcileMetrics(t *testing.T) {
cancel, appLister := newFakeLister()
defer cancel()
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{})
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck)
assert.NoError(t, err)
appReconcileMetrics := `
@@ -401,7 +306,7 @@ argocd_app_reconcile_count{dest_server="https://localhost:6443",namespace="argoc
func TestMetricsReset(t *testing.T) {
cancel, appLister := newFakeLister()
defer cancel()
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{})
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck)
assert.NoError(t, err)
appSyncTotal := `

View File

@@ -64,7 +64,6 @@ type AppStateManager interface {
SyncAppState(app *v1alpha1.Application, state *v1alpha1.OperationState)
}
// comparisonResult holds the state of an application after the reconciliation
type comparisonResult struct {
syncStatus *v1alpha1.SyncStatus
healthStatus *v1alpha1.HealthStatus
@@ -99,7 +98,6 @@ type appStateManager struct {
cache *appstatecache.Cache
namespace string
statusRefreshTimeout time.Duration
resourceTracking argo.ResourceTracking
}
func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1.ApplicationSource, appLabelKey, revision string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject) ([]*unstructured.Unstructured, *apiclient.ManifestResponse, error) {
@@ -150,7 +148,6 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
if err != nil {
return nil, nil, err
}
kustomizeOptions, err := kustomizeSettings.GetOptions(app.Spec.Source)
if err != nil {
return nil, nil, err
@@ -161,7 +158,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
return nil, nil, err
}
ts.AddCheckpoint("build_options_ms")
serverVersion, apiResources, err := m.liveStateCache.GetVersionsInfo(app.Spec.Destination.Server)
serverVersion, apiGroups, err := m.liveStateCache.GetVersionsInfo(app.Spec.Destination.Server)
if err != nil {
return nil, nil, err
}
@@ -179,10 +176,9 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
Plugins: tools,
KustomizeOptions: kustomizeOptions,
KubeVersion: serverVersion,
ApiVersions: argo.APIResourcesToStrings(apiResources, true),
ApiVersions: argo.APIGroupsToVersions(apiGroups),
VerifySignature: verifySignature,
HelmRepoCreds: permittedHelmCredentials,
TrackingMethod: string(argo.GetTrackingMethod(m.settingsMgr)),
HelmOptions: helmOptions,
})
if err != nil {
@@ -465,16 +461,14 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
// filter out all resources which are not permitted in the application project
for k, v := range liveObjByKey {
if !project.IsLiveResourcePermitted(v, app.Spec.Destination.Server, app.Spec.Destination.Name) {
if !project.IsLiveResourcePermitted(v, app.Spec.Destination.Server) {
delete(liveObjByKey, k)
}
}
trackingMethod := argo.GetTrackingMethod(m.settingsMgr)
for _, liveObj := range liveObjByKey {
if liveObj != nil {
appInstanceName := m.resourceTracking.GetAppName(liveObj, appLabelKey, trackingMethod)
appInstanceName := kubeutil.GetAppInstanceLabel(liveObj, appLabelKey)
if appInstanceName != "" && appInstanceName != app.Name {
conditions = append(conditions, v1alpha1.ApplicationCondition{
Type: v1alpha1.ApplicationConditionSharedResourceWarning,
@@ -509,10 +503,6 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
_, refreshRequested := app.IsRefreshRequested()
noCache = noCache || refreshRequested || app.Status.Expired(m.statusRefreshTimeout)
for i := range reconciliation.Target {
_ = m.resourceTracking.Normalize(reconciliation.Target[i], reconciliation.Live[i], appLabelKey, string(trackingMethod))
}
if noCache || specChanged || revisionChanged || m.cache.GetAppManagedResources(app.Name, &cachedDiff) != nil {
// (rare) cache miss
diffResults, err = diff.DiffArray(reconciliation.Target, reconciliation.Live, diffOpts...)
@@ -697,7 +687,6 @@ func NewAppStateManager(
metricsServer *metrics.MetricsServer,
cache *appstatecache.Cache,
statusRefreshTimeout time.Duration,
resourceTracking argo.ResourceTracking,
) AppStateManager {
return &appStateManager{
liveStateCache: liveStateCache,
@@ -711,6 +700,5 @@ func NewAppStateManager(
projInformer: projInformer,
metricsServer: metricsServer,
statusRefreshTimeout: statusRefreshTimeout,
resourceTracking: resourceTracking,
}
}

View File

@@ -60,16 +60,6 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
return
}
syncOp = *state.Operation.Sync
// validates if it should fail the sync if it finds shared resources
hasSharedResource, sharedResourceMessage := hasSharedResourceCondition(app)
if syncOp.SyncOptions.HasOption("FailOnSharedResource=true") &&
hasSharedResource {
state.Phase = common.OperationFailed
state.Message = fmt.Sprintf("Shared resouce found: %s", sharedResourceMessage)
return
}
if syncOp.Source == nil {
// normal sync case (where source is taken from app.spec.source)
source = app.Spec.Source
@@ -97,7 +87,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
revision = syncOp.Revision
}
proj, err := argo.GetAppProject(&app.Spec, listersv1alpha1.NewAppProjectLister(m.projInformer.GetIndexer()), m.namespace, m.settingsMgr, m.db, context.TODO())
proj, err := argo.GetAppProject(&app.Spec, listersv1alpha1.NewAppProjectLister(m.projInformer.GetIndexer()), m.namespace, m.settingsMgr)
if err != nil {
state.Phase = common.OperationError
state.Message = fmt.Sprintf("Failed to load application project: %v", err)
@@ -192,7 +182,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
if !proj.IsGroupKindPermitted(un.GroupVersionKind().GroupKind(), res.Namespaced) {
return fmt.Errorf("Resource %s:%s is not permitted in project %s.", un.GroupVersionKind().Group, un.GroupVersionKind().Kind, proj.Name)
}
if res.Namespaced && !proj.IsDestinationPermitted(v1alpha1.ApplicationDestination{Namespace: un.GetNamespace(), Server: app.Spec.Destination.Server, Name: app.Spec.Destination.Name}) {
if res.Namespaced && !proj.IsDestinationPermitted(v1alpha1.ApplicationDestination{Namespace: un.GetNamespace(), Server: app.Spec.Destination.Server}) {
return fmt.Errorf("namespace %v is not permitted in project '%s'", un.GetNamespace(), proj.Name)
}
return nil
@@ -261,18 +251,6 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
}
}
// hasSharedResourceCondition will check if the Application has any resource that has already
// been synced by another Application. If the resource is found in another Application it returns
// true along with a human readable message of which specific resource has this condition.
func hasSharedResourceCondition(app *v1alpha1.Application) (bool, string) {
for _, condition := range app.Status.Conditions {
if condition.Type == v1alpha1.ApplicationConditionSharedResourceWarning {
return true, condition.Message
}
}
return false, ""
}
// delayBetweenSyncWaves is a gitops-engine SyncWaveHook which introduces an artificial delay
// between each sync wave. We introduce an artificial delay in order give other controllers a
// _chance_ to react to the spec change that we just applied. This is important because without

View File

@@ -5,7 +5,6 @@ import (
"os"
"testing"
"github.com/argoproj/gitops-engine/pkg/sync/common"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/stretchr/testify/assert"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -143,71 +142,3 @@ func TestSyncComparisonError(t *testing.T) {
assert.NotEmpty(t, conditions)
assert.Equal(t, "abc123", opState.SyncResult.Revision)
}
func TestAppStateManager_SyncAppState(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{
SignatureKeys: []v1alpha1.SignatureKey{{KeyID: "test"}},
},
}
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)
return &fixture{
project: project,
application: app,
controller: ctrl,
}
}
t.Run("will fail the sync if finds shared resources", func(t *testing.T) {
// given
t.Parallel()
f := setup()
syncErrorMsg := "deployment already applied by another application"
condition := v1alpha1.ApplicationCondition{
Type: v1alpha1.ApplicationConditionSharedResourceWarning,
Message: syncErrorMsg,
}
f.application.Status.Conditions = append(f.application.Status.Conditions, condition)
// Sync with source unspecified
opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{
Sync: &v1alpha1.SyncOperation{
Source: &v1alpha1.ApplicationSource{},
SyncOptions: []string{"FailOnSharedResource=true"},
},
}}
// when
f.controller.appStateManager.SyncAppState(f.application, opState)
// then
assert.Equal(t, common.OperationFailed, opState.Phase)
assert.Contains(t, opState.Message, syncErrorMsg)
})
}

0
docs/assets/azure-enterprise-claims.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

0
docs/assets/azure-enterprise-saml-urls.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

0
docs/assets/azure-enterprise-users.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -15,7 +15,7 @@ Since the CI pipeline is triggered on Git commits, there is currently no (known)
If you are absolutely sure that the failure was due to a failure in the pipeline, and not an error within the changes you committed, you can push an empty commit to your branch, thus retriggering the pipeline without any code changes. To do so, issue
```bash
git commit -s --allow-empty -m "Retrigger CI pipeline"
git commit --allow-empty -m "Retrigger CI pipeline"
git push origin <yourbranch>
```
@@ -23,9 +23,7 @@ git push origin <yourbranch>
First, make sure the failing build step succeeds on your machine. Remember the containerized build toolchain is available, too.
If the build is failing at the `Ensure Go modules synchronicity` step, you need to first download all Go dependent modules locally via `go mod download` and then run `go mod tidy` to make sure the dependent Go modules are tidied up. Finally commit and push your changes to `go.mod` and `go.sum` to your branch.
If the build is failing at the `Build & cache Go code`, you need to make sure `make build-local` runs successfully on your local machine.
If the build is failing at the `Ensuring Gopkg.lock is up-to-date` step, you need to update the dependencies before you push your commits. Run `make dep-ensure` and `make dep` and commit the changes to `Gopkg.lock` to your branch.
### Why does the codegen step fail?

View File

@@ -45,7 +45,7 @@ If you make changes to the Argo UI component, and your Argo CD changes depend on
1. Make changes to Argo UI and submit the PR request.
2. Also, prepare your Argo CD changes, but don't create the PR just yet.
3. **After** the Argo UI PR has been merged to master, then as part of your Argo CD changes:
- Run `yarn add git+https://github.com/argoproj/argo-ui.git` in the `ui/` directory, and then,
- Run `yarn add git+https://github.com/argoproj/argo-ui.git`, and then,
- Check in the regenerated yarn.lock file as part of your Argo CD commit
4. Create the Argo CD PR when you are ready. The PR build and test checks should pass.

View File

@@ -24,7 +24,8 @@ You will need at least the following things in your toolchain in order to develo
* A Kubernetes cluster. You won't need a fully blown multi-master, multi-node cluster, but you will need something like K3S, Minikube or microk8s. You will also need a working Kubernetes client (`kubectl`) configuration in your development environment. The configuration must reside in `~/.kube/config` and the API server URL must point to the IP address of your local machine (or VM), and **not** to `localhost` or `127.0.0.1` if you are using the virtualized development toolchain (see below)
* You will also need a working Docker runtime environment, to be able to build and run images. The Docker version must be 17.05.0 or higher, to support multi-stage builds.
* You will also need a working Docker runtime environment, to be able to build and run images.
The Docker version must be fairly recent, and support multi-stage builds. You should not work as root. Make your local user a member of the `docker` group to be able to control the Docker service on your machine.
* Obviously, you will need a `git` client for pulling source code and pushing back your changes.
@@ -268,7 +269,7 @@ and others. Although you can make changes to these files and run them locally, i
6. Commit changes and open a PR to [Argo UI](https://github.com/argoproj/argo-ui).
7. Once your PR has been merged in Argo UI, `cd` into your `argo-cd/ui` folder and run `yarn add git+https://github.com/argoproj/argo-ui.git`. This will update the commit SHA in the `ui/yarn.lock` file to use the lastest master commit for argo-ui.
7. Once your PR has been merged in Argo UI, `cd` into your `argo-cd` folder and run `yarn add https://github.com/argoproj/argo-ui.git`. This will update the commit SHA in the `ui/yarn.lock` file to use the lastest master commit for argo-ui.
8. Submit changes to `ui/yarn.lock`in a PR to Argo CD.
@@ -303,7 +304,7 @@ You need to pull in all required Go dependencies. To do so, run
### Test your build toolchain
The first thing you can do to test whether your build toolchain is setup correctly is by generating the glue code for the API and after that, run a normal build:
The first thing you can do whether your build toolchain is setup correctly is by generating the glue code for the API and after that, run a normal build:
* `make codegen-local`
* `make build-local`

View File

@@ -73,9 +73,13 @@ in your Argo CD installation namespace. You can simply retrieve this password
using `kubectl`:
```bash
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
```
For better readability, e.g. if you want to copy & paste the generated password,
you can simply append `&& echo` to above command, which will add a newline to
the output.
!!! warning
You should delete the `argocd-initial-admin-secret` from the Argo CD
namespace once you changed the password. The secret serves no other
@@ -89,9 +93,6 @@ Using the username `admin` and the password from above, login to Argo CD's IP or
argocd login <ARGOCD_SERVER>
```
!!! note
The CLI environment must be able to communicate with the Argo CD controller. If it isn't directly accessible as described above in step 3, you can tell the CLI to access it using port forwarding through one of these mechanisms: 1) add `--port-forward-namespace argocd` flag to every CLI command; or 2) set `ARGOCD_OPTS` environment variable: `export ARGOCD_OPTS='--port-forward-namespace argocd'`.
Change the password using the command:
```bash
@@ -130,11 +131,10 @@ An example repository containing a guestbook application is available at
### Creating Apps Via CLI
Create the example guestbook application with the following command:
!!! note
You can access Argo CD using port forwarding: add `--port-forward-namespace argocd` flag to every CLI command or set `ARGOCD_OPTS` environment variable: `export ARGOCD_OPTS='--port-forward-namespace argocd'`:
```bash
argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace default`
```
`argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace default`
### Creating Apps Via UI
@@ -152,7 +152,7 @@ Connect the [https://github.com/argoproj/argocd-example-apps.git](https://github
![connect repo](assets/connect-repo.png)
For **Destination**, set cluster URL to `https://kubernetes.default.svc` (or `in-cluster` for cluster name) and namespace to `default`:
For **Destination**, set cluster to `in-cluster` and namespace to `default`:
![destination](assets/destination.png)

View File

@@ -82,14 +82,6 @@ spec:
- code: false
name: foo
value: bar
# Exclude contains a glob pattern to match paths against that should be explicitly excluded from being used during
# manifest generation. This takes precedence over the `include` field.
# To match multiple patterns, wrap the patterns in {} and separate them with commas. For example: '{config.yaml,env-use2/*}'
exclude: 'config.yaml'
# Include contains a glob pattern to match paths against that should be explicitly included during manifest
# generation. If this field is set, only matching manifests will be included.
# To match multiple patterns, wrap the patterns in {} and separate them with commas. For example: '{*.yml,*.yaml}'
include: '*.yaml'
# plugin specific config
plugin:

View File

@@ -228,23 +228,8 @@ data:
# Optional link for banner. If set, the entire banner text will become a link.
# You can have bannercontent without a bannerurl, but not the other way around.
ui.bannerurl: "https://argoproj.github.io"
# Uncomment to make the banner not show the close buttons, thereby making the banner permanent.
# Because it is permanent, only one line of text is available to not take up too much real estate in the UI,
# so it is recommended that the length of the bannercontent text is kept reasonably short. Note that you can
# have either a permanent banner or a regular closeable banner, and NOT both. eg. A user can't dismiss a
# notification message (closeable) banner, to then immediately see a permanent banner.
# ui.bannerpermanent: "true"
# An option to specify the position of the banner, either the top or bottom of the page. The default is at the top.
# Uncomment to make the banner appear at the bottom of the page. Any value other than "bottom" will make the banner appear at the top.
# ui.bannerposition: "bottom"
# Application reconciliation timeout is the max amount of time required to discover if a new manifests version got
# published to the repository. Reconciliation by timeout is disabled if timeout is set to 0. Three minutes by default.
# > Note: argocd-repo-server deployment must be manually restarted after changing the setting.
timeout.reconciliation: 180s
# oidc.tls.insecure.skip.verify determines whether certificate verification is skipped when verifying tokens with the
# configured OIDC provider (either external or the bundled Dex instance). Setting this to "true" will cause JWT
# token verification to pass despite the OIDC provider having an invalid certificate. Only set to "true" if you
# understand the risks.
oidc.tls.insecure.skip.verify: "false"

View File

@@ -28,8 +28,3 @@ data:
# If omitted, defaults to: '[groups]'. The scope value can be a string, or a list of strings.
scopes: '[cognito:groups, email]'
# matchMode configures the matchers function for casbin.
# There are two options for this, 'glob' for glob matcher or 'regex' for regex matcher. If omitted or mis-configured,
# will be set to 'glob' as default.
policy.matchMode: 'glob'

View File

@@ -96,23 +96,4 @@ Note that the CSS file should be mounted within a subdirectory of the "/shared/a
## Developing Style Overlays
The styles specified in the injected CSS file should be specific to components and classes defined in [argo-ui](https://github.com/argoproj/argo-ui).
It is recommended to test out the styles you wish to apply first by making use of your browser's built-in developer tools. For a more full-featured
experience, you may wish to build a separate project using the [Argo CD UI dev server](https://webpack.js.org/configuration/dev-server/).
## Banners
Argo CD can optionally display a banner that can be used to notify your users of upcoming maintenance and operational changes. This feature can be enabled by specifying the banner message using the `ui.bannercontent` field in the `argocd-cm` ConfigMap and Argo CD will display this message at the top of every UI page. You can optionally add a link to this message by setting `ui.bannerurl`.
### argocd-cm
```yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
...
name: argocd-cm
data:
ui.bannercontent: "Banner message linked to a URL"
ui.bannerurl: "www.bannerlink.com"
```
![banner with link](../assets/banner.png)
experience, you may wish to build a separate project using the [Argo CD UI dev server](https://webpack.js.org/configuration/dev-server/).

View File

@@ -171,9 +171,6 @@ Repository details are stored in secrets. To configure a repo, create a secret w
Consider using [bitnami-labs/sealed-secrets](https://github.com/bitnami-labs/sealed-secrets) to store an encrypted secret definition as a Kubernetes manifest.
Each repository must have a `url` field and, depending on whether you connect using HTTPS, SSH, or GitHub App, `username` and `password` (for HTTPS), `sshPrivateKey` (for SSH), or `githubAppPrivateKey` (for GitHub App).
!!!warning
When using [bitnami-labs/sealed-secrets](https://github.com/bitnami-labs/sealed-secrets) the labels will be removed and have to be readded as descibed here: https://github.com/bitnami-labs/sealed-secrets#sealedsecrets-as-templates-for-secrets
Example for HTTPS:
```yaml
@@ -185,7 +182,6 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
url: https://github.com/argoproj/private-repo
password: my-password
username: my-username
@@ -202,7 +198,6 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
url: git@github.com:argoproj/my-private-repository
sshPrivateKey: |
-----BEGIN OPENSSH PRIVATE KEY-----
@@ -220,7 +215,6 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
repo: https://github.com/argoproj/my-private-repository
githubAppID: 1
githubAppInstallationID: 2
@@ -237,7 +231,6 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
repo: https://ghe.example.com/argoproj/my-private-repository
githubAppID: 1
githubAppInstallationID: 2
@@ -264,7 +257,6 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
url: https://github.com/argoproj/private-repo
---
apiVersion: v1
@@ -275,7 +267,6 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
url: https://github.com/argoproj/other-private-repo
---
apiVersion: v1
@@ -286,7 +277,6 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repo-creds
stringData:
type: git
url: https://github.com/argoproj
password: my-password
username: my-username
@@ -428,7 +418,6 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
url: https://github.com/argoproj/private-repo
proxy: https://proxy-server-url:8888
password: my-password
@@ -482,7 +471,6 @@ The secret data must include following fields:
* `name` - cluster name
* `server` - cluster api server url
* `namespaces` - optional comma-separated list of namespaces which are accessible in that cluster. Cluster level resources would be ignored if namespace list is not empty.
* `clusterResources` - optional boolean string (`"true"` or `"false"`) determining whether Argo CD can manage cluster-level resources on this cluster. This setting is used only if the list of managed namespaces is not empty.
* `config` - JSON representation of following data structure:
```yaml
@@ -509,13 +497,13 @@ execProviderConfig:
installHint: string
# Transport layer security configuration settings
tlsClientConfig:
# Base64 encoded PEM-encoded bytes (typically read from a client certificate file).
# PEM-encoded bytes (typically read from a client certificate file).
caData: string
# Base64 encoded PEM-encoded bytes (typically read from a client certificate file).
# PEM-encoded bytes (typically read from a client certificate file).
certData: string
# Server should be accessed without verifying the TLS certificate
insecure: boolean
# Base64 encoded PEM-encoded bytes (typically read from a client certificate key file).
# PEM-encoded bytes (typically read from a client certificate key file).
keyData: string
# ServerName is passed to the server for SNI and is used in the client to check server
# certificates against. If ServerName is empty, the hostname used to contact the

View File

@@ -38,7 +38,7 @@ and might fail. To avoid failed syncs use `ARGOCD_GIT_ATTEMPTS_COUNT` environmen
* `argocd_git_request_total` - Number of git requests. The metric provides two tags: `repo` - Git repo URL; `request_type` - `ls-remote` or `fetch`.
* `ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM` - environment variable that enables collecting RPC performance metrics. Enable it if you need to troubleshoot performance issue. Note: metric is expensive to both query and store!
* `ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM` (v1.8+) - environment variable that enables collecting RPC performance metrics. Enable it if you need to troubleshoot performance issue. Note: metric is expensive to both query and store!
### argocd-application-controller
@@ -61,7 +61,7 @@ number of allowed concurrent kubectl fork/execs.
* The controller uses Kubernetes watch APIs to maintain lightweight Kubernetes cluster cache. This allows to avoid querying Kubernetes during app reconciliation and significantly improve
performance. For performance reasons controller monitors and caches only preferred the version of a resource. During reconciliation, the controller might have to convert cached resource from
preferred version into a version of the resource stored in Git. If `kubectl convert` fails because conversion is not supported then controller falls back to Kubernetes API query which slows down
reconciliation. In this case, we advise you to use the preferred resource version in Git.
reconciliation. In this case advice user-preferred resource version in Git.
* The controller polls Git every 3m by default. You can increase this duration using `timeout.reconciliation` setting in the `argocd-cm` ConfigMap.
@@ -86,7 +86,7 @@ spec:
value: "2"
```
* `ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM` - environment variable that enables collecting RPC performance metrics. Enable it if you need to troubleshoot performance issue. Note: metric is expensive to both query and store!
* `ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM` (v1.8+)- environment variable that enables collecting RPC performance metrics. Enable it if you need to troubleshoot performance issue. Note: metric is expensive to both query and store!
**metrics**
@@ -119,24 +119,26 @@ If the manifest generation has no side effects then requests are processed in pa
* **Multiple Helm based applications pointing to the same directory in one Git repository:** ensure that your Helm chart don't have conditional
[dependencies](https://helm.sh/docs/chart_best_practices/dependencies/#conditions-and-tags) and create `.argocd-allow-concurrency` file in chart directory.
* **Multiple Custom plugin based applications:** avoid creating temporal files during manifest generation and create `.argocd-allow-concurrency` file in app directory.
* **Multiple Custom plugin based applications:** avoid creating temporal files during manifest generation and and create `.argocd-allow-concurrency` file in app directory.
* **Multiple Kustomize or Ksonnet applications in same repository with [parameter overrides](../user-guide/parameters.md):** sorry, no workaround for now.
### Webhook and Manifest Paths Annotation
Argo CD aggressively caches generated manifests and uses the repository commit SHA as a cache key. A new commit to the Git repository invalidates the cache for all applications configured in the repository.
This can negatively affect repositories with multiple applications. You can use [webhooks](https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/webhook.md) and the `argocd.argoproj.io/manifest-generate-paths` Application CRD annotation to solve this problem and improve performance.
Argo CD aggressively caches generated manifests and uses repository commit SHA as a cache key. A new commit to the Git repository invalidates cache for all applications configured in the repository
that again negatively affect mono repositories with multiple applications. You might use [webhooks](https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/webhook.md) and `argocd.argoproj.io/manifest-generate-paths` Application
CRD annotation to solve this problem and improve performance.
The `argocd.argoproj.io/manifest-generate-paths` annotation contains a semicolon-separated list of paths within the Git repository that are used during manifest generation. The webhook compares paths specified in the annotation with the changed files specified in the webhook payload. If no modified files match the paths specified in `argocd.argoproj.io/manifest-generate-paths`, then the webhook will not trigger application reconciliation and the existing cache will be considered valid for the new commit.
The `argocd.argoproj.io/manifest-generate-paths` contains a semicolon-separated list of paths within the Git repository that are used during manifest generation. The webhook compares paths specified in the annotation
with the changed files specified in the webhook payload. If non of the changed files are located in the paths then webhook don't trigger application reconciliation and re-uses previously generated manifests cache for a new commit.
Installations that use a different repository for each application are **not** subject to this behavior and will likely get no benefit from using these annotations.
Installations that use a different repo for each app are **not** subject to this behavior and will likely get no benefit from using these annotations.
!!! note
Application manifest paths annotation support depends on the git provider used for the Application. It is currently only supported for GitHub, GitLab, and Gogs based repos.
* **Relative path** The annotation might contain a relative path. In this case the path is considered relative to the path specified in the application source:
Application manifest paths annotation support depends on the git provider used for the Application. It is currently only supported for GitHub, GitLab, and Gogs based repos
I'm using `.Second()` modifier to avoid distracting users who already rely on `--app-resync` flag.
* **Relative path** The annotation might contains relative path. In this case the path is considered relative to the path specified in the application source:
```yaml
apiVersion: argoproj.io/v1alpha1
@@ -154,8 +156,7 @@ spec:
path: guestbook
# ...
```
* **Absolute path** The annotation value might be an absolute path starting with '/'. In this case path is considered as an absolute path within the Git repository:
* **Absolute path** The annotation value might be an absolute path started from '/'. In this case path is considered as an absolute path within the Git repository:
```yaml
apiVersion: argoproj.io/v1alpha1

View File

@@ -79,7 +79,7 @@ Since Contour Ingress supports only a single protocol per Ingress object, define
Internal HTTP/HTTPS Ingress:
```yaml
apiVersion: networking.k8s.io/v1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: argocd-server-http
@@ -102,7 +102,7 @@ spec:
Internal gRPC Ingress:
```yaml
apiVersion: networking.k8s.io/v1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: argocd-server-grpc
@@ -124,7 +124,7 @@ spec:
External HTTPS SSO Callback Ingress:
```yaml
apiVersion: networking.k8s.io/v1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: argocd-server-external-callback-http
@@ -178,7 +178,7 @@ In order to expose the Argo CD API server with a single ingress rule and hostnam
must be used to passthrough TLS connections and terminate TLS at the Argo CD API server.
```yaml
apiVersion: networking.k8s.io/v1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: argocd-server-ingress
@@ -244,7 +244,7 @@ way would be to define two Ingress objects. One for HTTP/HTTPS, and the other fo
HTTP/HTTPS Ingress:
```yaml
apiVersion: networking.k8s.io/v1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: argocd-server-http-ingress
@@ -269,7 +269,7 @@ spec:
gRPC Ingress:
```yaml
apiVersion: networking.k8s.io/v1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: argocd-server-grpc-ingress
@@ -379,7 +379,7 @@ spec:
Once we create this service, we can configure the Ingress to conditionally route all `application/grpc` traffic to the new HTTP2 backend, using the `alb.ingress.kubernetes.io/conditions` annotation, as seen below. Note: The value after the . in the condition annotation _must_ be the same name as the service that you want traffic to route to - and will be applied on any path with a matching serviceName.
```yaml
apiVersion: networking.k8s.io/v1
apiVersion: networking.k8s.io/v1 # Use extensions/v1beta1 for Kubernetes 1.18 and older
kind: Ingress
metadata:
annotations:
@@ -408,162 +408,6 @@ Once we create this service, we can configure the Ingress to conditionally route
- argocd.argoproj.io
```
## Google Cloud load balancers with Kubernetes Ingress
You can make use of the integration of GKE with Google Cloud to deploy Load Balancers using just Kubernetes objects.
For this we will need these five objects:
- A Service
- A BackendConfig
- A FrontendConfig
- A secret with your SSL certificate
- An Ingress for GKE
If you need detail for all the options available for these Google integrations, you can check the [Google docs on configuring Ingress features](https://cloud.google.com/kubernetes-engine/docs/how-to/ingress-features)
### Disable internal TLS
First, to avoid internal redirection loops from HTTP to HTTPS, the API server should be run with TLS disabled. Edit the argocd-server deployment to add the --insecure flag to the argocd-server command. For this you can edit your resource live with `kubectl -n argocd edit deployments.apps argocd-server` or use a kustomize patch before installing Argo CD.
The container command should change from:
```yaml
containers:
- command:
- argocd-server
- --staticassets
- /shared/app
```
To:
```yaml
containers:
- command:
- argocd-server
- --insecure
- --staticassets
- /shared/app
```
### Creating a service
Now you need an externally accesible service. This is practically the same as the internal service Argo CD has, but as a NodePort and with Google Cloud annotations. Note that this service is annotated to use a [Network Endpoint Group](https://cloud.google.com/load-balancing/docs/negs) (NEG) to allow your load balancer to send traffic directly to your pods without using kube-proxy, so remove the `neg` annotation it that's not what you want.
The service:
```yaml
apiVersion: v1
kind: Service
metadata:
name: argocd-server-external
namespace: argocd
annotations:
cloud.google.com/neg: '{"ingress": true}'
cloud.google.com/backend-config: '{"ports": {"http":"argocd-backend-config"}}'
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
selector:
app.kubernetes.io/name: argocd-server
```
### Creating a BackendConfig
See that previous service referencing a backend config called `argo-backend-config`? So lets deploy it using this yaml:
```yaml
apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
name: argocd-backend-config
namespace: argocd
spec:
healthCheck:
checkIntervalSec: 30
timeoutSec: 5
healthyThreshold: 1
unhealthyThreshold: 2
type: HTTP
requestPath: /healthz
port: 8080
```
It uses the same health check as the pods.
### Creating a FrontendConfig
Now we can deploy a frontend config with an HTTP to HTTPS redirect:
```yaml
apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
name: argocd-frontend-config
namespace: argocd
spec:
redirectToHttps:
enabled: true
```
---
!!! note
The next two steps (the certificate secret and the Ingress) are described supposing that you manage the certificate yourself, and you have the certificate and key files for it. In the case that your certificate is Google-managed, fix the next two steps using the [guide to use a Google-managed SSL certificate](https://cloud.google.com/kubernetes-engine/docs/how-to/managed-certs#creating_an_ingress_with_a_google-managed_certificate).
---
### Creating a certificate secret
We need now to create a secret with the SSL certificate we want in our load balancer. It's as easy as executing this command on the path you have your certificate keys stored:
```
kubectl -n argocd create secret tls secret-yourdomain-com \
--cert cert-file.crt --key key-file.key
```
### Creating an Ingress
And finally, to top it all, our Ingress. Note the reference to our frontend config, the service, and to the certificate secret:
```yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: argocd
namespace: argocd
annotations:
networking.gke.io/v1beta1.FrontendConfig: argocd-frontend-config
spec:
tls:
- secretName: secret-yourdomain-com
rules:
- host: argocd.yourdomain.com
http:
paths:
- path: /*
backend:
serviceName: argocd-server-external
servicePort: http
```
---
!!! warning "Deprecation Warning"
Note that, according to this [deprecation guide](https://kubernetes.io/docs/reference/using-api/deprecation-guide/#ingress-v122), if you're using Kubernetes 1.22+, instead of `networking.k8s.io/v1beta1`, you should use `networking.k8s.io/v1`.
---
As you may know already, it can take some minutes to deploy the load balancer and become ready to accept connections. Once it's ready, get the public IP address for your Load Balancer, go to your DNS server (Google or third party) and point your domain or subdomain (i.e. argocd.yourdomain.com) to that IP address.
You can get that IP address describing the Ingress object like this:
```
kubectl -n argocd describe ingresses argocd | grep Address
```
Once the DNS change is propagated, you're ready to use Argo with your Google Cloud Load Balancer
## Authenticating through multiple layers of authenticating reverse proxies
ArgoCD endpoints may be protected by one or more reverse proxies layers, in that case, you can provide additional headers through the `argocd` CLI `--header` parameter to authenticate through those layers.

View File

@@ -1,27 +1,13 @@
# Metrics
Argo CD exposes different sets of Prometheus metrics per server.
Argo CD exposes two sets of Prometheus metrics
## Application Controller Metrics
## Application Metrics
Metrics about applications. Scraped at the `argocd-metrics:8082/metrics` endpoint.
| Metric | Type | Description |
|--------|:----:|-------------|
| `argocd_app_info` | gauge | Information about Applications. It contains labels such as `sync_status` and `health_status` that reflect the application state in ArgoCD. |
| `argocd_app_k8s_request_total` | counter | Number of kubernetes requests executed during application reconciliation |
| `argocd_app_labels` | gauge | Argo Application labels converted to Prometheus labels. Disabled by default. See section below about how to enable it. |
| `argocd_app_reconcile` | histogram | Application reconciliation performance. |
| `argocd_app_sync_total` | counter | Counter for application sync history |
| `argocd_cluster_api_resource_objects` | gauge | Number of k8s resource objects in the cache. |
| `argocd_cluster_api_resources` | gauge | Number of monitored kubernetes API resources. |
| `argocd_cluster_cache_age_seconds` | gauge | Cluster cache age in seconds. |
| `argocd_cluster_connection_status` | gauge | The k8s cluster current connection status. |
| `argocd_cluster_events_total` | counter | Number of processes k8s resource events. |
| `argocd_cluster_info` | gauge | Information about cluster. |
| `argocd_kubectl_exec_pending` | gauge | Number of pending kubectl executions |
| `argocd_kubectl_exec_total` | counter | Number of kubectl executions |
| `argocd_redis_request_duration` | histogram | Redis requests duration. |
| `argocd_redis_request_total` | counter | Number of redis requests executed during application reconciliation |
* Gauge for application health status
* Gauge for application sync status
* Counter for application sync history
If you use ArgoCD with many application and project creation and deletion,
the metrics page will keep in cache your application and project's history.
@@ -30,57 +16,10 @@ to deleted resources, you can schedule a metrics reset to clean the
history with an application controller flag. Example:
`--metrics-cache-expiration="24h0m0s"`.
### Exposing Application labels as Prometheus metrics
There are use-cases where ArgoCD Applications contain labels that are desired to be exposed as Prometheus metrics.
Some examples are:
* Having the team name as a label to allow routing alerts to specific receivers
* Creating dashboards broken down by business units
As the Application labels are specific to each company, this feature is disabled by default. To enable it, add the
`--metrics-application-labels` flag to the ArgoCD application controller.
The example below will expose the ArgoCD Application labels `team-name` and `business-unit` to Prometheus:
containers:
- command:
- argocd-application-controller
- --metrics-application-labels
- team-name
- --metrics-application-labels
- business-unit
In this case, the metric would look like:
```
# TYPE argocd_app_labels gauge
argocd_app_labels{label_business_unit="bu-id-1",label_team_name="my-team",name="my-app-1",namespace="argocd",project="important-project"} 1
argocd_app_labels{label_business_unit="bu-id-1",label_team_name="my-team",name="my-app-2",namespace="argocd",project="important-project"} 1
argocd_app_labels{label_business_unit="bu-id-2",label_team_name="another-team",name="my-app-3",namespace="argocd",project="important-project"} 1
```
## API Server Metrics
Metrics about API Server API request and response activity (request totals, response codes, etc...).
Scraped at the `argocd-server-metrics:8083/metrics` endpoint.
| Metric | Type | Description |
|--------|:----:|-------------|
| `argocd_redis_request_duration` | histogram | Redis requests duration. |
| `argocd_redis_request_total` | counter | Number of kubernetes requests executed during application reconciliation. |
## Repo Server Metrics
Metrics about the Repo Server.
Scraped at the `argocd-repo-server:8084/metrics` endpoint.
| Metric | Type | Description |
|--------|:----:|-------------|
| `argocd_git_request_duration_seconds` | histogram | Git requests duration seconds. |
| `argocd_git_request_total` | counter | Number of git requests performed by repo server |
| `argocd_redis_request_duration_seconds` | histogram | Redis requests duration seconds. |
| `argocd_redis_request_total` | counter | Number of kubernetes requests executed during application reconciliation. |
| `argocd_repo_pending_request_total` | gauge | Number of pending requests requiring repository lock |
## Prometheus Operator
If using Prometheus Operator, the following ServiceMonitor example manifests can be used.
@@ -126,7 +65,7 @@ metadata:
spec:
selector:
matchLabels:
app.kubernetes.io/name: argocd-repo-server
app.kubernetes.io/name: argocd-repo-server-metrics
endpoints:
- port: metrics
```

View File

@@ -39,10 +39,6 @@ configures a custom role, named `org-admin`. The role is assigned to any user wh
`your-github-org:your-team` group. All other users get the default policy of `role:readonly`,
which cannot modify Argo CD settings.
!!! warning
All authenticated users get _at least_ the permissions granted by the default policy. This access cannot be blocked
by a `deny` rule. Instead, restrict the default policy and then grant permissions to individual roles as needed.
*ArgoCD ConfigMap `argocd-rbac-cm` Example:*
```yaml

View File

@@ -4,7 +4,7 @@ Argo CD is un-opinionated about how secrets are managed. There's many ways to do
* [Bitnami Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets)
* [GoDaddy Kubernetes External Secrets](https://github.com/godaddy/kubernetes-external-secrets)
* [External Secrets Operator](https://github.com/external-secrets/external-secrets)
* [External Secrets Operator](https://github.com/ContainerSolutions/externalsecret-operator)
* [Hashicorp Vault](https://www.vaultproject.io)
* [Banzai Cloud Bank-Vaults](https://github.com/banzaicloud/bank-vaults)
* [Helm Secrets](https://github.com/jkroepke/helm-secrets)

View File

@@ -11,8 +11,7 @@ Authentication to Argo CD API server is performed exclusively using [JSON Web To
in one of the following ways:
1. For the local `admin` user, a username/password is exchanged for a JWT using the `/api/v1/session`
endpoint. This token is signed & issued by the Argo CD API server itself and it expires after 24 hours
(this token used not to expire, see [CVE-2021-26921](https://github.com/argoproj/argo-cd/security/advisories/GHSA-9h6w-j7w4-jr52)).
endpoint. This token is signed & issued by the Argo CD API server itself, and has no expiration.
When the admin password is updated, all existing admin JWT tokens are immediately revoked.
The password is stored as a bcrypt hash in the [`argocd-secret`](https://github.com/argoproj/argo-cd/blob/master/manifests/base/config/argocd-secret.yaml) Secret.
@@ -198,15 +197,6 @@ the involved applications of the webhook event (e.g. which repo was modified), t
the related application for reconciliation. This refresh is the same refresh which occurs regularly
at three minute intervals, just fast-tracked by the webhook event.
## Logging
Argo CD logs payloads of most API requests except request that are considered sensitive, such as
`/cluster.ClusterService/Create`, `/session.SessionService/Create` etc. The full list of method
can be found in [server/server.go](https://github.com/argoproj/argo-cd/blob/abba8dddce8cd897ba23320e3715690f465b4a95/server/server.go#L516).
Argo CD does not log IP addresses of clients requesting API endpoints, since the API server is typically behind a proxy. Instead, it is recommended
to configure IP addresses logging in the proxy server that sits in front of the API server.
## Limiting Directory App Memory Usage
> >2.2.10, 2.1.16, >2.3.5

View File

@@ -30,7 +30,6 @@ argocd-application-controller [flags]
--kubectl-parallelism-limit int Number of allowed concurrent kubectl fork/execs. Any value less the 1 means no limit. (default 20)
--logformat string Set the logging format. One of: text|json (default "text")
--loglevel string Set the logging level. One of: debug|info|warn|error (default "info")
--metrics-application-labels strings List of Application labels that will be added to the argocd_application_labels metric
--metrics-cache-expiration duration Prometheus metrics cache expiration (disabled by default. e.g. 24h0m0s)
--metrics-port int Start metrics server on given port (default 8082)
-n, --namespace string If present, the namespace scope for this CLI request

View File

@@ -1,89 +0,0 @@
# v2.1 to 2.2
## Upgraded Helm Version
Note that bundled Helm has been upgraded from 3.6.0 to v3.7+. This includes following breaking changes:
- Repository credentials are no longer passed to download charts that
are being served from a different domain than the repository.
You can still force older behavior with `--helm-pass-credentials` option to `argocd app create`.
More information in the [Helm v3.6.1 release notes](https://github.com/helm/helm/releases/tag/v3.6.1).
- Experimental OCI support has been rewritten.
More information in the [Helm v3.7.0 release notes](https://github.com/helm/helm/releases/tag/v3.7.0).
## Support for private repo SSH keys using the SHA-1 signature hash algorithm is removed in 2.2.12
Argo CD 2.2.12 upgraded its base image from Ubuntu 21.10 to Ubuntu 22.04, which upgraded OpenSSH to 8.9. OpenSSH starting
with 8.8 [dropped support for the `ssh-rsa` SHA-1 key signature algorithm](https://www.openssh.com/txt/release-8.8).
The signature algorithm is _not_ the same as the algorithm used when generating the key. There is no need to update
keys.
The signature algorithm is negotiated with the SSH server when the connection is being set up. The client offers its
list of accepted signature algorithms, and if the server has a match, the connection proceeds. For most SSH servers on
up-to-date git providers, acceptable algorithms other than `ssh-rsa` should be available.
Before upgrading to Argo CD 2.2.12, check whether your git provider(s) using SSH authentication support algorithms newer
than `rsa-ssh`.
1. Make sure your version of SSH >= 8.9 (the version used by Argo CD). If not, upgrade it before proceeding.
```shell
ssh -V
```
Example output: `OpenSSH_8.9p1 Ubuntu-3, OpenSSL 3.0.2 15 Mar 2022`
2. Once you have a recent version of OpenSSH, follow the directions from the [OpenSSH 8.8 release notes](https://www.openssh.com/txt/release-8.7):
> To check whether a server is using the weak ssh-rsa public key
> algorithm, for host authentication, try to connect to it after
> removing the ssh-rsa algorithm from ssh(1)'s allowed list:
>
> ```shell
> ssh -oHostKeyAlgorithms=-ssh-rsa user@host
> ```
>
> If the host key verification fails and no other supported host key
> types are available, the server software on that host should be
> upgraded.
If the server does not support an acceptable version, you will get an error similar to this;
```
$ ssh -oHostKeyAlgorithms=-ssh-rsa vs-ssh.visualstudio.com
Unable to negotiate with 20.42.134.1 port 22: no matching host key type found. Their offer: ssh-rsa
```
This indicates that the server needs to update its supported key signature algorithms, and Argo CD will not connect
to it.
### Workaround
The [OpenSSH 8.8 release notes](https://www.openssh.com/txt/release-8.8) describe a workaround if you cannot change the
server's key signature algorithms configuration.
> Incompatibility is more likely when connecting to older SSH
> implementations that have not been upgraded or have not closely tracked
> improvements in the SSH protocol. For these cases, it may be necessary
> to selectively re-enable RSA/SHA1 to allow connection and/or user
> authentication via the HostkeyAlgorithms and PubkeyAcceptedAlgorithms
> options. For example, the following stanza in ~/.ssh/config will enable
> RSA/SHA1 for host and user authentication for a single destination host:
>
> ```
> Host old-host
> HostkeyAlgorithms +ssh-rsa
> PubkeyAcceptedAlgorithms +ssh-rsa
> ```
>
> We recommend enabling RSA/SHA1 only as a stopgap measure until legacy
> implementations can be upgraded or reconfigured with another key type
> (such as ECDSA or Ed25519).
To apply this to Argo CD, you could create a ConfigMap with the desired ssh config file and then mount it at
`/home/argocd/.ssh/config`.

View File

@@ -3,7 +3,7 @@
!!!note
This section contains information on upgrading Argo CD. Before upgrading please make sure to read details about
the breaking changes between Argo CD versions.
the breaking changes between Argo CD versions.
Argo CD uses the semver versioning and ensures that following rules:
@@ -16,7 +16,7 @@ please make sure to check upgrading details in both [v1.3 to v1.4](./1.3-1.4.md
Argo CD settings using disaster recovery [guide](../disaster_recovery.md).
After reading the relevant notes about possible breaking changes introduced in Argo CD version use the following
command to upgrade Argo CD. Make sure to replace `<version>` with the required version number:
command to upgrade Argo CD. Make sure to replace `<version>` with the required version number:
**Non-HA**:
@@ -33,18 +33,15 @@ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/<v
Even though some releases require only image change it is still recommended to apply whole manifests set.
Manifest changes might include important parameter modifications and applying the whole set will protect you from
introducing misconfiguration.
introducing misconfiguration.
<hr/>
* [v2.1 to v2.2](./2.1-2.2.md)
* [v2.0 to v2.1](./2.0-2.1.md)
* [v1.8 to v2.0](./1.8-2.0.md)
* [v1.7 to v1.8](./1.7-1.8.md)
* [v1.6 to v1.7](./1.6-1.7.md)
* [v1.5 to v1.6](./1.5-1.6.md)
* [v1.4 to v1.5](./1.4-1.5.md)
* [v1.3 to v1.4](./1.3-1.4.md)
* [v1.7 to v1.8](./1.7-1.8.md)
* [v1.6 to v1.7](./1.6-1.7.md)
* [v1.5 to v1.6](./1.5-1.6.md)
* [v1.4 to v1.5](./1.4-1.5.md)
* [v1.3 to v1.4](./1.3-1.4.md)
* [v1.2 to v1.3](./1.2-1.3.md)
* [v1.1 to v1.2](./1.1-1.2.md)
* [v1.0 to v1.1](./1.0-1.1.md)
* [v1.1 to v1.2](./1.1-1.2.md)
* [v1.0 to v1.1](./1.0-1.1.md)

View File

@@ -1,13 +1,6 @@
# Google
There are three different ways to integrate Argo CD login with your Google Workspace users. Generally the OpenID Connect (_oidc_) method would be the recommended way of doing this integration (and easier, as well...), but depending on your needs, you may choose a different option.
* [OpenID Connect using Dex](#openid-connect-using-dex)
This is the recommended login method if you don't need information about the groups the user's belongs to. Google doesn't expose the `groups` claim via _oidc_, so you won't be able to use Google Groups membership information for RBAC.
* [SAML App Auth using Dex](#saml-app-auth-using-dex)
Dex [recommends avoiding this method](https://dexidp.io/docs/connectors/saml/#warning). Also, you won't get Google Groups membership information through this method.
* [OpenID Connect plus Google Groups using Dex](#openid-connect-plus-google-groups-using-dex)
This is the recommended method if you need to user Google Groups membership in your RBAC configuration.
* [G Suite SAML App Auth using Dex](#g-suite-saml-app-auth-using-dex)
Once you've set up one of the above integrations, be sure to edit `argo-rbac-cm` to configure permissions (as in the example below). See [RBAC Configurations](../rbac.md) for more detailed scenarios.
@@ -21,66 +14,10 @@ data:
policy.default: role:readonly
```
## OpenID Connect using Dex
### Configure your OAuth consent screen
If you've never configured this, you'll be redirected straight to this if you try to create an OAuth Client ID
1. Go to your [OAuth Consent](https://console.cloud.google.com/apis/credentials/consent) configuration. If you still haven't created one, select `Internal` or `External` and click `Create`
2. Go and [edit your OAuth consent screen](https://console.cloud.google.com/apis/credentials/consent/edit) Verify you're in the correct project!
3. Configure a name for your login app and a user support email address
4. The app logo and filling the information links is not mandatory, but it's a nice touch for the login page
5. In "Authorized domains" add the domains who are allowed to log in to ArgoCD (e.g. if you add `example.com`, all Google Workspace users with an `@example.com` address will be able to log in)
6. Save to continue to the "Scopes" section
7. Click on "Add or remove scopes" and add the `.../auth/userinfo.profile` and the `openid` scopes
8. Save, review the summary of your changes and finish
### Configure a new OAuth Client ID
1. Go to your [Google API Credentials](https://console.cloud.google.com/apis/credentials) console, and make sure you're in the correct project.
2. Click on "+Create Credentials"/"OAuth Client ID"
3. Select "Web Application" in the Application Type drop down menu, and enter an identifying name for your app (e.g. `Argo CD`)
4. Fill "Authorized JavaScript origins" with your Argo CD URL, e.g. `https://argocd.example.com`
5. Fill "Authorized redirect URIs" with your Argo CD URL plus `/api/dex/callback`, e.g. `https://argocd.example.com/api/dex/callback`
![](../../assets/google-admin-oidc-uris.png)
6. Click "Create" and save your "Client ID" and your "Client Secret" for later
### Configure Argo to use OpenID Connect
Edit `argo-cm` and add the following `dex.config` to the data section, replacing `clientID` and `clientSecret` with the values you saved before:
```yaml
data:
url: https://argocd.example.com
dex.config: |
connectors:
- config:
issuer: https://accounts.google.com
clientID: XXXXXXXXXXXXX.apps.googleusercontent.com
clientSecret: XXXXXXXXXXXXX
type: oidc
id: google
name: Google
```
### References
- [Dex oidc connector docs](https://dexidp.io/docs/connectors/oidc/)
## SAML App Auth using Dex
## G Suite SAML App Auth using Dex
### Configure a new SAML App
---
!!! warning "Deprecation Warning"
Note that, according to [Dex documentation](https://dexidp.io/docs/connectors/saml/#warning), SAML is considered unsafe and they are planning to deprecate that module.
---
1. In the [Google admin console](https://admin.google.com), open the left-side menu and select `Apps` > `SAML Apps`
![Google Admin Apps Menu](../../assets/google-admin-saml-apps-menu.png "Google Admin menu with the Apps / SAML Apps path selected")
@@ -139,97 +76,3 @@ data:
- [Dex SAML connector docs](https://dexidp.io/docs/connectors/saml/)
- [Google's SAML error messages](https://support.google.com/a/answer/6301076?hl=en)
## OpenID Connect plus Google Groups using Dex
---
!!! warning "Limited group information"
When using this feature you'll only receive the list of groups the user is a direct member.
So, lets say you have this hierarchy of groups and subgroups:
`all@example.com --> tech@example.com --> devs@example.com --> you@example.com`
The only group you would receive through Dex would be `devs@example.com`
---
We're going to use Dex's `google` connector to get additional Google Groups information from your users, allowing you to use group membership on your RBAC, i.e., giving `admin` role to the whole `sysadmins@yourcompany.com` group.
This connector uses two different credentials:
- An oidc client ID and secret
Same as when you're configuring an [OpenID connection](#openid-connect-using-dex), this authenticates your users
- A Google service account
This is used to connect to the Google Directory API and pull information about your user's group membership
Also, you'll need the email address for an admin user on this domain. Dex will impersonate that user identity to fetch user information from the API.
### Configure OpenID Connect
Go through the same steps as in [OpenID Connect using Dex](#openid-connect-using-dex), except for configuring `argocd-cm`. We'll do that later.
### Set up Directory API access
1. Follow [Google instructions to create a service account with Domain-Wide Delegation](https://developers.google.com/admin-sdk/directory/v1/guides/delegation)
- When assigning API scopes to the service account assign **only** the `https://www.googleapis.com/auth/admin.directory.group.readonly` scope and nothing else. If you assign any other scopes, you won't be able to fetch information from the API
- Create the credentials in JSON format and store them in a safe place, we'll need them later
2. Enable the [Admin SDK](https://console.developers.google.com/apis/library/admin.googleapis.com/)
### Configure Dex
1. Create a secret with the contents of the previous json file encoded in base64, like this:
apiVersion: v1
kind: Secret
metadata:
name: argocd-google-groups-json
namespace: argocd
data:
googleAuth.json: JSON_FILE_BASE64_ENCODED
2. Edit your `argocd-dex-server` deployment to mount that secret as a file
- Add a volume mount in `/spec/template/spec/containers/0/volumeMounts/` like this. Be aware of editing the running container and not the init container!
volumeMounts:
- mountPath: /shared
name: static-files
- mountPath: /tmp
name: dexconfig
- mountPath: /tmp/oidc
name: google-json
readOnly: true
- Add a volume in `/spec/template/spec/volumes/` like this:
volumes:
- emptyDir: {}
name: static-files
- emptyDir: {}
name: dexconfig
- name: google-json
secret:
defaultMode: 420
secretName: argocd-google-groups-json
3. Edit `argo-cm` and add the following `dex.config` to the data section, replacing `clientID` and `clientSecret` with the values you saved before, `adminEmail` with the address for the admin user you're going to impersonate, and editing `redirectURI` with your Argo CD domain:
dex.config: |
connectors:
- config:
redirectURI: https://argocd.example.com/api/dex/callback
clientID: XXXXXXXXXXXXX.apps.googleusercontent.com
clientSecret: XXXXXXXXXXXXX
serviceAccountFilePath: /tmp/oidc/googleAuth.json
adminEmail: admin-email@example.com
type: google
id: google
name: Google
4. Restart your `argocd-dex-server` deployment to be sure it's using the latest configuration
5. Login to Argo CD and go to the "User info" section, were you should see the groups you're member
![User info](../../assets/google-groups-membership.png)
6. Now you can use groups email addresses to give RBAC permissions
### References
- [Dex Google connector docs](https://dexidp.io/docs/connectors/google/)

View File

@@ -77,7 +77,6 @@ argocd account get --account <username>
* Set user password
```bash
# if you are managing users as the admin user, <current-user-password> should be the current admin password.
argocd account update-password \
--account <name> \
--current-password <current-user-password> \
@@ -115,8 +114,7 @@ There are two ways that SSO can be configured:
* [Bundled Dex OIDC provider](#dex) - use this option if your current provider does not support OIDC (e.g. SAML,
LDAP) or if you wish to leverage any of Dex's connector features (e.g. the ability to map GitHub
organizations and teams to OIDC groups claims). Dex also supports OIDC directly and can fetch user
information from the identity provider when the groups cannot be included in the IDToken.
organizations and teams to OIDC groups claims).
* [Existing OIDC provider](#existing-oidc-provider) - use this if you already have an OIDC provider which you are using (e.g.
[Okta](okta.md), [OneLogin](onelogin.md), [Auth0](auth0.md), [Microsoft](microsoft.md), [Keycloak](keycloak.md),
@@ -198,91 +196,6 @@ NOTES:
Argo CD will automatically use the correct `redirectURI` for any OAuth2 connectors, to match the
correct external callback URL (e.g. `https://argocd.example.com/api/dex/callback`)
## OIDC Configuration with DEX
Dex can be used for OIDC authentication instead of ArgoCD directly. This provides a separate set of
features such as fetching information from the `UserInfo` endpoint and
[federated tokens](https://dexidp.io/docs/custom-scopes-claims-clients/#cross-client-trust-and-authorized-party)
### Configuration:
* In the `argocd-cm` ConfigMap add the `OIDC` connector to the `connectors` sub field inside `dex.config`.
See Dex's [OIDC connect documentation](https://dexidp.io/docs/connectors/oidc/) to see what other
configuration options might be useful. We're going to be using a minimal configuration here.
* The issuer URL should be where Dex talks to the OIDC provider. There would normally be a
`.well-known/openid-configuration` under this URL which has information about what the provider supports.
e.g. https://accounts.google.com/.well-known/openid-configuration
```yaml
data:
url: "https://argocd.example.com"
dex.config: |
connectors:
# OIDC
- type: OIDC
id: oidc
name: OIDC
issuer: https://example-OIDC-provider.com
clientID: aaaabbbbccccddddeee
clientSecret: $dex.oidc.clientSecret
```
### Requesting additional ID token claims
By default Dex only retrieves the profile and email scopes. In order to retrieve more more claims you
can add them under the `scopes` entry in the Dex configuration. To enable group claims through Dex,
`insecureEnableGroups` also needs to enabled. Group information is currently only refreshed at authentication
time and support to refresh group information more dynamically can be tracked here: [dexidp/dex#1065](https://github.com/dexidp/dex/issues/1065).
```yaml
data:
url: "https://argocd.example.com"
dex.config: |
connectors:
# OIDC
- type: OIDC
id: oidc
name: OIDC
issuer: https://example-OIDC-provider.com
clientID: aaaabbbbccccddddeee
clientSecret: $dex.oidc.clientSecret
insecureEnableGroups: true
scopes:
- profile
- email
- groups
```
!!! warning
Because group information is only refreshed at authentication time just adding or removing an account from a group will not change a user's membership until they reauthenticate. Depending on your organization's needs this could be a security risk and could be mitigated by changing the authentication token's lifetime.
### Retrieving claims that are not in the token
When an Idp does not or cannot support certain claims in an IDToken they can be retrieved separately using
the UserInfo endpoint. Dex supports this functionality using the `getUserInfo` endpoint. One of the most
common claims that is not supported in the IDToken is the `groups` claim and both `getUserInfo` and `insecureEnableGroups`
must be set to true.
```yaml
data:
url: "https://argocd.example.com"
dex.config: |
connectors:
# OIDC
- type: OIDC
id: oidc
name: OIDC
issuer: https://example-OIDC-provider.com
clientID: aaaabbbbccccddddeee
clientSecret: $dex.oidc.clientSecret
insecureEnableGroups: true
scopes:
- profile
- email
- groups
getUserInfo: true
```
## Existing OIDC Provider
To configure Argo CD to delegate authenticate to your existing OIDC provider, add the OAuth2
@@ -373,21 +286,6 @@ You are not required to specify a logoutRedirectURL as this is automatically gen
!!! note
The post logout redirect URI may need to be whitelisted against your OIDC provider's client settings for ArgoCD.
### Configuring a custom root CA certificate for communicating with the OIDC provider
If your OIDC provider is setup with a certificate which is not signed by one of the well known certificate authorities
you can provide a custom certificate which will be used in verifying the OIDC provider's TLS certificate when
communicating with it.
Add a `rootCA` to your `oidc.config` which contains the PEM encoded root certificate:
```yaml
oidc.config: |
...
rootCA: |
-----BEGIN CERTIFICATE-----
... encoded certificate data here ...
-----END CERTIFICATE-----
```
## SSO Further Reading
@@ -492,20 +390,3 @@ data:
clientSecret: $another-secret:oidc.auth0.clientSecret # Mind the ':'
...
```
### Skipping certificate verification on OIDC provider connections
By default, all connections made by the API server to OIDC providers (either external providers or the bundled Dex
instance) must pass certificate validation. These connections occur when getting the OIDC provider's well-known
configuration, when getting the OIDC provider's keys, and when exchanging an authorization code or verifying an ID
token as part of an OIDC login flow.
Disabling certificate verification might make sense if:
* You are using the bundled Dex instance **and** your Argo CD instance has TLS configured with a self-signed certificate
**and** you understand and accept the risks of skipping OIDC provider cert verification.
* You are using an external OIDC provider **and** that provider uses an invalid certificate **and** you cannot solve
the problem by setting `oidcConfig.rootCA` **and** you understand and accept the risks of skipping OIDC provider cert
verification.
If either of those two applies, then you can disable OIDC provider certificate verification by setting
`oidc.tls.insecure.skip.verify` to `"true"` in the `argocd-cm` ConfigMap.

View File

@@ -57,19 +57,17 @@ Let's start by storing the client secret you generated earlier in the argocd sec
1. First you'll need to encode the client secret in base64: `$ echo -n '83083958-8ec6-47b0-a411-a8c55381fbd2' | base64`
2. Then you can edit the secret and add the base64 value to a new key called _oidc.keycloak.clientSecret_ using `$ kubectl edit secret argocd-secret`.
Your Secret should look something like this:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: argocd-secret
data:
...
oidc.keycloak.clientSecret: ODMwODM5NTgtOGVjNi00N2IwLWE0MTEtYThjNTUzODFmYmQy
...
```
Your Secret should look something like this:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: argocd-secret
data:
...
oidc.keycloak.clientSecret: ODMwODM5NTgtOGVjNi00N2IwLWE0MTEtYThjNTUzODFmYmQy
...
```
Now we can configure the config map and add the oidc configuration to enable our keycloak authentication.
You can use `$ kubectl edit configmap argocd-cm`.

View File

@@ -72,7 +72,7 @@ It is proposed that a git repository be used to contain the javascript code, as
In the most simplest form, an Argo CD extension could simply be a pointer to a git repository at a revision:
```yaml
```yaml=
kind: ArgoCDExtension
metadata:
name: argo-rollouts

View File

@@ -1,273 +0,0 @@
---
title: Change the way application resources are identified
authors:
- "@jannfis"
sponsors:
- TBD
reviewers:
- TBD
approvers:
- TBD
creation-date: 2021-06-07
last-updated: 2021-06-07
---
# Change the way application resources are identified
This is a proposal to introduce the tracking method settings that allows using
an annotation as the application identifier instead of the application instance label.
This will allow application names longer than 63 characters and solve issues caused by
copying `app.kubernetes.io/instance` label. As an additional goal, we propose to introduce an
installation ID that will allow multiple Argo CD instances to manage resources
on the same cluster.
## Summary
Argo CD identifies resources it manages by setting the _application instance
label_ to the name of the managing `Application` on all resources that are
managed (i.e. reconciled from Git). The default label used is the well-known
label `app.kubernetes.io/instance`.
This proposal suggests to introduce the `trackingMethod` setting that allows
controlling how applicaton resources are identified and allows switching to
using the annotation instead of `app.kubernetes.io/instance` label.
## Motivation
The main motivation behind this change is to solve the following known issues:
* The Kubernetes label value cannot be longer than 63 characters. In large scale
installations, in order to build up an easy to understand and
well-formed naming schemes for applications managed by Argo CD, people often
hit the 63 character limit and need to define the naming scheme around this
unnecessary limit.
* Popular off-the-shelf Helm charts often add the `app.kubernetes.io/instance` label
to the generated resource manifests. This label confuses Argo CD and makes it think the
resource is managed by the application.
* Kubernetes operators often create additional resources without creating owner reference
and copy the `app.kubernetes.io/instance` label from the application resource. This is
also confusing Argo CD and makes it think the resource is managed by the application.
An additional motivation - while we're at touching at application instance
label - is to improve the way how multiple Argo CD instances could manage
applications on the same cluster, without requiring the user to actually
perform instance specific configuration.
### Goals
* Allow application names of more than 63 characters
* Prevent confusion caused by copied/generated `app.kubernetes.io/instance` label
* Keep having a human-readable way to identify resources that belong to a
given Argo CD application
* As a stretch-goal, allow multiple Argo CD instances to manage resources on
the same cluster without the need for configuring application instance label
key (usually `app.kubernetes.io/instance`)
### Non-Goals
* Change the default name of the application instance label
## Proposal
We propose introducing a new setting `trackingMethod` that allows to control
how application resources are identified. The `trackingMethod` setting takes
one of the following values:
* `label` (default) - Argo CD keep using the `app.kubernetes.io/instance` label.
* `annotation+label` - Argo CD keep adding `app.kubernetes.io/instance` but only
for informational purposes: label is not used for tracking, value is truncated if
longer than 63 characters. The `app.kubernetes.io/instance` annotation is used
to track application resources.
* `annotation` - Argo CD uses the `app.kubernetes.io/instance` annotation to track
application resources.
The `app.kubernetes.io/instance` attribute values includes the application name,
resources identifier it is applied to, and optionally the Argo CD installation ID:
The application name allows to identify the application that manages the resource. The
resource identifier prevents confusion if an operation copies the
`app.kubernetes.io/instance` annotation to another resource. Finally optional
installation ID allows separate two Argo CD instances that manages resources in the same cluster.
The `trackingMethod` setting should be available at the system level and the application level to
allow the smooth transition from the old `app.kubernetes.io/instance` label to the new tracking method.
Using the app leverl settings users will be able to first switch applications one by one to the new tracking method
and prepare for the migration. Next system level setting can be changed to `annotation` or `annotation+label`
and not-migrated applications can be configured to use `labels` using application level setting.
### Use cases
Add a list of detailed use cases this enhancement intends to take care of.
#### Use case 1: Allow for more than 63 characters in application name
As a user, I would like to be able to give my applications names with arbitrary
length, because I want to include identifiers like target regions and possibly
availability zones, the environment and possibly other identifiers (e.g. a team
name) in the application names. The current restriction of 63 characters is not
sufficient for my naming requirements.
#### Use case 2: Allow for retrieving all resources using Kubernetes
As an administrator, I want to enable my users to use more than 63 characters
in their application names, but I still want to be able to retrieve all of the
resources managed by that particular application using Kubernetes mechanisms,
e.g. a label selector as in the following example:
```
kubectl get deployments -l app.kubernetes.io/instance=<application> --all-namespaces
```
#### Use case 3: Multiple Argo CD instances managing apps on same cluster
I also want to be able to see which application and Argo CD instance is the
one in charge of a given resource.
### Implementation Details/Notes/Constraints [optional]
#### Include resource identifies in the `app.kubernetes.io/instance` annotation
The `app.kubernetes.io/instance` annotation might be accidently added or copied
same as label. To prevent Argo CD confusion the annotation value should include
the identifier of the resource annotation was applied to. The resource identifier
includes the group, kind, namespace and name of the resource. It is proposed to use `;`
to separate identifier from the application name.
```yaml
annotations:
app.kubernetes.io/instance: <application-name>;<group>/<kind>/<namespace>/<name>
```
Example:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
namespace: default
annotations:
app.kubernetes.io/instance: my-application;apps/Deployment/default/my-deployment
```
#### Allow multiple Argo CD instances manage applications on same cluster
As of today, to allow two or more Argo CD instances with a similar set of
permissions (e.g. cluster-wide read access to resources) manage applications
on the same cluster, users would have to configure the _application instance
label key_ in the Argo CD configuration to a unique value. Otherwise, if an
application with the same name exists in two different Argo CD installations,
both would claim ownership of the resources of that application.
We do see the need for preventing such scenarios out-of-the-box in Argo CD.
For this, we do suggest the introduction of an _installation ID_ in the
form of a standard _GUID_.
This GUID would be generated once by Argo CD upon startup, and is persisted in
the Argo CD configuration, e.g. by storing it as `installationID` in the
`argocd-cm` ConfigMap. The GUID of the installation would need to be encoded
in some way in the resources managed by that Argo CD instance.
We suggest using a dedicated annotation to store the GUID and modify Argo CD so that it matches _both_, the app
instance key and the GUID to determine whether a resource is managed by
this Argo CD instance. Given above mentioned GUID, this may look like the
following on a resource:
```yaml
apiVersion: v1
Kind: Secret
metadata:
name: some-secret
namespace: some-namespace
annotations:
app.kubernetes.io/instance: my-application;/Secret/some-namespace/some-secret
argo-cd.argoproj.io/installation-id: 61199294-412c-4e78-a237-3ebba6784fcd
```
The user should be able to opt-out of this feature by setting the `installationID` to an empty string.
### Security Considerations
We think this change will not have a direct impact on the security of Argo CD
or the applications it manages.
### Risks and Mitigations
The proposal assumes that user can keep adding `app.kubernetes.io/instance` label
to be able to retrieve resources using `kubectl get -l app.kubernetes.io/instance=<application>` command.
However, Argo CD is going to truncate the value of the label if it is longer than 63 characters. There is
a small possibility that there are several applications with the same first 63 characters in the name. This
should be clearly stated in documentation.
### Upgrade / Downgrade Strategy
Upgrading to a version that implements this proposal should be seamless, as
previously injected labels will not be removed and additional annotations will
be applied to the resource. E.g. consider following resource in Git, that will
be synced as part of an application named `some-application`. In Git, the
resource looks like follows:
```yaml
apiVersion: v1
Kind: Secret
metadata:
name: some-secret
namespace: some-namespace
```
When synced with the current incarnation of Argo CD, Argo CD would inject the
application instance label and once the resource is applied in the cluster, it
would look like follows:
```yaml
apiVersion: v1
Kind: Secret
metadata:
name: some-secret
namespace: some-namespace
labels:
app.kubernetes.io/instance: some-application
```
Once Argo CD is updated to a version implementing this proposal, the resource
would be rewritten to look like the following:
```yaml
apiVersion: v1
Kind: Secret
metadata:
name: some-secret
namespace: some-namespace
labels:
app.kubernetes.io/instance: some-application
annotations:
app.kubernetes.io/instance: my-application;/Secret/some-namespace/some-secret
argo-cd.argoproj.io/installation-id: 61199294-412c-4e78-a237-3ebba6784fcd
```
On a rollback to a previous Argo CD version, this change would be reverted
and the resource would look like the first shown example above.
## Drawbacks
We do see some drawbacks to this implementation:
* This change would trigger a re-sync of each and every managed resource, which
may result in unexpected heavy load on Argo CD and the cluster at upgrade
time. The workaround is an ability to opt-out of this as a default and enable it
on application basis.
## Alternatives
* Enabling application names longer than 63 characters could also be done
by using the hashed value of the application name and additional metadata as a label.
The disadvantage of this approach is that hash value is not human friendly. In particular,
it is difficult to retrieve application manifests using `kubectl get -l app.kubernetes.io/instance=<application>`.

View File

@@ -1,6 +1,4 @@
mkdocs==1.2.3
mkdocs==1.1.2
mkdocs-material==7.1.7
markdown_include==0.6.0
pygments==2.7.4
jinja2==3.0.3
markdown==3.3.7
pygments==2.7.4

View File

@@ -1,26 +1,20 @@
# Roadmap
- [Roadmap](#roadmap)
- [v2.3](#v23)
- [Merge Argo CD Notifications into Argo CD](#merge-argo-cd-notifications-into-argo-cd)
- [v2.2](#v22)
- [Config Management Tools Integrations (proposal)](#config-management-tools-integrations-proposal)
- [Argo CD Extensions (proposal)](#argo-cd-extensions-proposal)
- [Project scoped repository and clusters (proposal)](#project-scoped-repository-and-clusters-proposal)
- [v2.3 and beyond](#v23-and-beyond)
- [Input Forms UI Refresh](#input-forms-ui-refresh)
- [Compact resources tree](#compact-resources-tree)
- [Maintain difference in cluster and git values for specific fields](#maintain-difference-in-cluster-and-git-values-for-specific-fields)
- [Web Shell](#web-shell)
- [Helm values from external repo](#helm-values-from-external-repo)
- [v2.4 and beyond](#v24-and-beyond)
- [Merge ApplicationSet controller into Argo CD](#merge-applicationset-controller-into-argo-cd)
- [Merge Argo CD Notifications into Argo CD](#merge-argo-cd-notifications-into-argo-cd)
- [Merge Argo CD Image Updater into Argo CD](#merge-argo-cd-image-updater-into-argo-cd)
- [Config Management Tools Integrations UI/CLI](#config-management-tools-integrations-uicli)
- [Allow specifying parent/child relationships in config](#allow-specifying-parentchild-relationships-in-config)
- [Dependencies between applications](#dependencies-between-applications)
- [Compact Resources Tree](#compact-resources-tree)
- [Multi-tenancy improvements](#multi-tenancy-improvements)
- [GitOps Engine Enhancements](#gitops-engine-enhancements)
- [Completed](#completed)
- [✅ Config Management Tools Integrations (proposal)](#-config-management-tools-integrations-proposal)
- [✅ Argo CD Extensions (proposal)](#-argo-cd-extensions-proposal)
- [✅ Project scoped repository and clusters (proposal)](#-project-scoped-repository-and-clusters-proposal)
- [✅ Core Argo CD (proposal)](#-core-argo-cd-proposal)
- [✅ Core Argo CD (proposal)](#core-argo-cd-aka-gitops-agent-proposal)
- [✅ Core Functionality Bug Fixes](#-core-functionality-bug-fixes)
- [✅ Performance](#-performance)
- [✅ ApplicationSet](#-applicationset)
@@ -30,61 +24,49 @@
- [✅ Automated Registry Monitoring](#-automated-registry-monitoring)
- [✅ Projects Enhancements](#-projects-enhancements)
## v2.3
## v2.2
### Merge Argo CD Notifications into Argo CD
### Config Management Tools Integrations ([proposal](https://github.com/argoproj/argo-cd/pull/5927))
The [Argo CD Notifications](https://github.com/argoproj-labs/argocd-notifications) should be merged into Argo CD and available out-of-the-box: [#7350](https://github.com/argoproj/argo-cd/issues/7350)
The community likes the first class support of Helm, Kustomize and keeps requesting support for more tools.
Argo CD provides a mechanism to integrate with any config management tool. We need to investigate why
it is not enough and implement missing features.
### Argo CD Extensions ([proposal](https://github.com/argoproj/argo-cd/pull/6240))
Argo CD supports customizing handling of Kubernetes resources via diffing customizations,
health checks, and custom actions. The Argo CD Extensions proposal takes it to next
level and allows to deliver the resource customizations along with custom visualization in Argo CD
via Git repository.
### Project scoped repository and clusters ([proposal](https://github.com/argoproj/argo-cd/blob/master/docs/proposals/project-repos-and-clusters.md))
The feature streamlines the process of adding repositories and clusters to the project and makes it self-service.
Instead of asking an administrator to change Argo CD settings end users can perform the change independently.
## v2.3 and beyond
### Input Forms UI Refresh
Improved design of the input forms in Argo CD Web UI: https://www.figma.com/file/IIlsFqqmM5UhqMVul9fQNq/Argo-CD?node-id=0%3A1
### Compact resources tree
An ability to collaps leaf resources tree to improve visualization of very large applications: [#7349](https://github.com/argoproj/argo-cd/issues/7349)
### Maintain difference in cluster and git values for specific fields
The feature allows to avoid updating fields excluded from diffing ([#2913](https://github.com/argoproj/argo-cd/issues/2913)).
### Web Shell
Exec into the Kubernetes Pod right from Argo CD Web UI! [#4351](https://github.com/argoproj/argo-cd/issues/4351)
### Helm values from external repo
The feature allows combining of-the-shelf Helm chart and value file in Git repository ([#2789](https://github.com/argoproj/argo-cd/issues/2789))
## v2.4 and beyond
### Merge ApplicationSet controller into Argo CD
The ApplicationSet functionality is available in Argo CD out-of-the-box ([#7351](https://github.com/argoproj/argo-cd/issues/7351)).
The Argo CD UI/CLI/API allows to manage ApplicationSet resources same as Argo CD Applications ([#7352](https://github.com/argoproj/argo-cd/issues/7352)).
### Merge Argo CD Notifications into Argo CD
The [Argo CD Notifications](https://github.com/argoproj-labs/argocd-notifications) should be merged into Argo CD and available out-of-the-box: [#7350](https://github.com/argoproj/argo-cd/issues/7350)
### Merge Argo CD Image Updater into Argo CD
The [Argo CD Image Updater](https://github.com/argoproj-labs/argocd-image-updater) should be merged into Argo CD and available out-of-the-box: [#7385](https://github.com/argoproj/argo-cd/issues/7385)
### Compact resources tree
### Config Management Tools Integrations UI/CLI
The continuation of the Config Management Tools of [proposal](https://github.com/argoproj/argo-cd/pull/5927). The Argo CD UI/CLI
should provide first class experience for configured third-party config management tools: [#5734](https://github.com/argoproj/argo-cd/issues/5734).
### Allow specifying parent/child relationships in config
The feature [#5082](https://github.com/argoproj/argo-cd/issues/5082) allows configuring parent/child relationships between resources. This allows to correctly
visualize custom resources that don't have owner references.
### Dependencies between applications
The feature allows specifying dependencies between applications that allow orchestrating synchronization of multiple applications. [#3517](https://github.com/argoproj/argo-cd/issues/3517)
An ability to collaps leaf resources tree to improve visualization of very large applications: [#7349](https://github.com/argoproj/argo-cd/issues/7349)
### Multi-tenancy improvements
@@ -105,25 +87,6 @@ A lot of Argo CD features are still not available in GitOps engine. The followin
## Completed
### ✅ Config Management Tools Integrations ([proposal](https://github.com/argoproj/argo-cd/pull/5927))
The community likes the first class support of Helm, Kustomize and keeps requesting support for more tools.
Argo CD provides a mechanism to integrate with any config management tool. We need to investigate why
it is not enough and implement missing features.
### ✅ Argo CD Extensions ([proposal](https://github.com/argoproj/argo-cd/pull/6240))
Argo CD supports customizing handling of Kubernetes resources via diffing customizations,
health checks, and custom actions. The Argo CD Extensions proposal takes it to next
level and allows to deliver the resource customizations along with custom visualization in Argo CD
via Git repository.
### ✅ Project scoped repository and clusters ([proposal](https://github.com/argoproj/argo-cd/blob/master/docs/proposals/project-repos-and-clusters.md))
The feature streamlines the process of adding repositories and clusters to the project and makes it self-service.
Instead of asking an administrator to change Argo CD settings end users can perform the change independently.
### ✅ Core Argo CD ([proposal](https://github.com/argoproj/argo-cd/pull/6385))
Core Argo CD allows to installation and use of lightweight Argo CD that includes only the backend without exposing the API or UI.

View File

@@ -12,5 +12,6 @@ Before effectively using Argo CD, it is necessary to understand the underlying t
* Depending on how you plan to template your applications:
* [Kustomize](https://kustomize.io)
* [Helm](https://helm.sh)
* [Ksonnet](https://ksonnet.io)
* If you're integrating with Jenkins:
* [Jenkins User Guide](https://jenkins.io)

View File

@@ -59,5 +59,5 @@ argocd account [flags]
* [argocd account get](argocd_account_get.md) - Get account details
* [argocd account get-user-info](argocd_account_get-user-info.md) - Get user info
* [argocd account list](argocd_account_list.md) - List accounts
* [argocd account update-password](argocd_account_update-password.md) - Update an account's password
* [argocd account update-password](argocd_account_update-password.md) - Update password

Some files were not shown because too many files have changed in this diff Show More