Compare commits

..

337 Commits

Author SHA1 Message Date
argo-bot
03b17e0233 Bump version to 2.2.2 2022-01-01 06:18:52 +00:00
argo-bot
d5909f7168 Bump version to 2.2.2 2022-01-01 06:18:35 +00:00
pasha-codefresh
7d0d665747 fix: issue with project scoped resources (#8048)
fix: issue with project scoped resources (#8048)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-12-30 09:12:45 -08:00
Michael Crenshaw
834a102c09 chore: escape proj in regex (#7985)
* chore: escape proj in regex

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

* chore: test normal cases

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

* chore: typo

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2021-12-30 09:12:40 -08:00
plakyda-codefresh
4bcd8cf733 fix: Default value for retry validation #8055 (#8064)
fix: Default value for retry validation #8055 (#8064)

Signed-off-by: viktorplakida <plakyda1@gmail.com>
2021-12-30 09:04:56 -08:00
pasha-codefresh
a069c602dc fix: sync window panel is crashed if resource name not contain letters (#8053)
fix: sync window panel is crashed if resource name not contain letters (#8053)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-12-29 11:08:52 -08:00
Alexander Matyushentsev
e309ceebac fix: upgrade github.com/argoproj/gitops-engine to v0.5.2
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-22 13:45:57 -08:00
plakyda-codefresh
4a7f0bbfd8 fix: retry disabled text (#8004)
fix: retry disabled text (#8004)

Signed-off-by: viktorplakida <plakyda1@gmail.com>
2021-12-22 11:40:30 -08:00
Niklas Steiner
28a54bf2a2 fix: Opening app details shows UI error on some apps (#8016) (#8019)
Signed-off-by: Niklas Steiner <niklas@sbg.at>
2021-12-22 11:17:50 -08:00
Alexander Matyushentsev
e209426a7e fix: correctly handle project field during partial cluster update (#7994)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-21 11:10:39 -08:00
May Zhang
06a95f86ce fix: Cluster API does not support updating labels and annotations (#7901)
Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-12-21 11:10:32 -08:00
argo-bot
122ecefc3a Bump version to 2.2.1 2021-12-17 01:23:50 +00:00
argo-bot
004d73ce92 Bump version to 2.2.1 2021-12-17 01:23:35 +00:00
Alexander Matyushentsev
81e1a58328 fix: resource details page crashes when resource is not deployed and hide managed fields is selected (#7971)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-16 17:21:54 -08:00
pasha-codefresh
84f949ff17 fix: issue with headless installation (#7958)
fix: issue with headless installation (#7958)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-12-16 10:20:06 -08:00
jomenxiao
a7e7f32a0f fix nil point (#7905)
Signed-off-by: jomenxiao <jomenxiao@gmail.com>
2021-12-16 08:24:54 -08:00
argo-bot
6da92a8e81 Bump version to 2.2.0 2021-12-14 18:01:04 +00:00
argo-bot
d5368f5714 Bump version to 2.2.0 2021-12-14 18:00:47 +00:00
Jesse Suen
25cfb27d51 feat: update gitops-engine to v0.5.1 and add additional tuning options (#7917)
Signed-off-by: Jesse Suen <jesse@akuity.io>
2021-12-13 18:51:41 -08:00
Alexander Matyushentsev
47d23e1f07 fix: resource tracking normalization should not always drop old label (#7911)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-13 10:16:00 -08:00
Alexander Matyushentsev
1dc14dc172 fix: resource tracking normalization shuold drop empty labels (#7909)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-11 11:17:22 -08:00
Alexander Matyushentsev
5c06333914 fix: improve migration from label to annotation tracking (#7899)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-10 16:15:37 -08:00
jannfis
656bee1402 chore: Upgrade to golang 1.16.11 (#7874)
* chore: Upgrade to golang 1.16.11

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

* Missed this one

Signed-off-by: jannfis <jann@mistrust.net>
2021-12-09 07:04:49 +00:00
pasha-codefresh
2a30c92a7e fix: Resource tracking typo (#7873)
* move projects

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

* Revert "move projects"

This reverts commit d0e21353

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

* fix typo in resource tracking

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-12-08 09:59:05 -08:00
pasha-codefresh
6a1fec9d33 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-08 09:58:43 -08:00
Alexander Matyushentsev
0faeeb843d refactor: add indexes to secret informers to speedup settings parsing (#7882)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-07 14:15:55 -08:00
Saumeya Katyal
48bdabad1a fix: css change for clear button in filters (#7868)
Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2021-12-07 10:02:34 -08:00
Alexander Matyushentsev
c3fd7f5f2d fix: fix UI build failure: use correct monaco editor setting name (#7856)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-03 14:32:37 -08:00
Alexander Matyushentsev
3f75a7faa3 feat: allow hiding managed fields in resource manifest viewer (#7855)
* fix: remove double scroll in editor

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

* feat: add Hide Managed Fields checkbox

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-03 13:46:43 -08:00
Alexander Matyushentsev
0f14657301 refactor: avoid loading project in frequently executed controller methods (#7853)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-03 13:20:46 -08:00
Chetan Banavikalmutt
02768367b5 fix: admin dashboard doesn't use the right context (#7826)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2021-12-02 22:23:11 -08:00
Jesse Suen
3b628b3af8 fix: env vars to tune cluster cache were broken (#7779)
Signed-off-by: Jesse Suen <jesse@akuity.io>
2021-11-30 13:49:21 -08:00
Alexander Matyushentsev
d8d2920eff refactor: upgrade casbin to latest stable version (v2.39.1) (#7802)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-30 13:48:42 -08:00
Alexander Matyushentsev
1a72853ca3 refactor: use cached project while calculating resource tree (#7747)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-19 13:15:24 -08:00
Alexander Matyushentsev
5354e7d823 chore: use gitops-engine v0.5.0
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-19 13:14:53 -08:00
Mark Sarcevicz
34d8f12c99 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:44 -08:00
argo-bot
8840688e6e Bump version to 2.2.0-rc1 2021-11-12 16:25:15 +00:00
argo-bot
c081ef0b00 Bump version to 2.2.0-rc1 2021-11-12 16:24:57 +00:00
Alexander Matyushentsev
caa246a38d refactor: allow using own config maps to register the cmp plugins instead of 'argocd-cmp-cm' (#7677)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-10 14:57:14 -08:00
pasha-codefresh
ebf27dea3e feat: Improve unit test coverage for util/app/app.go (#7641)
feat: Improve unit test coverage for util/app/app.go (#7641)
Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-11-10 13:41:04 -08:00
Yuan Tang
98fcb417eb build: Pin Python to 3.9.8 to work with arch x64 on GitHub Actions (#7678)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-11-10 12:44:48 -08:00
Yuan Tang
a3517d594b docs: Update CI troubleshooting guide on build steps (#7639)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-11-08 09:49:00 -08:00
Yuan Tang
e0c9827a37 chore: Correct function names in docstring in server/project/project.go (#7650)
* docs: Correct function names in docstring in server/project/project.go

Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-11-08 09:48:28 -08:00
May Zhang
375e27bd7a Feat: cmp server (#6585)
* feat: config management plugin enhancement (#6585)

Signed-off-by: kshamajain99 <kshamajain99@gmail.com>
Signed-off-by: May Zhang <may_zhang@intuit.com>
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-08 09:47:10 -08:00
Yuan Tang
46fdb6f364 fix: Add missing passCredentials in swagger.json (#7640)
* fix: Add missing passCredentials in swagger.json

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

* Retrigger CI pipeline

Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-11-08 08:49:28 -08:00
pasha-codefresh
2e84638827 fix: timezone fix test (#7643)
* group diff should set resource id use new interface

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

* remove redundant

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

* remove eof

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

* sync window broken tests

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

* sync window broken tests

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-11-07 19:08:02 +01:00
Yuan Tang
0a64781616 build: Add Helm v3.7.1 checksum for arm64 to fix build on Apple M1 (#7635)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-11-05 14:39:57 -07:00
Yuan Tang
43a29e6b2d docs: Add -s to sign off empty commits that retriggers CI (#7628)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-11-05 14:39:42 -07:00
Leonardo Luz Almeida
b77f947e1d fix: TestRepository should assume git by default (#7630)
* fix: TestRepository should assume git by default

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

* fix proto diff

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2021-11-05 13:51:02 -07:00
Leonardo Luz Almeida
dc24380065 chore: refactoring gpg test data embeding it in go code (#7625)
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2021-11-05 08:45:14 +01:00
Leonardo Luz Almeida
b0278c4493 fix: handle repo creation when secret does not have proper label (#7617)
* fix: handle repo creation when secret does not have proper label

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

* address code review comments with linters

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

* remove gpg test data refactoring code

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2021-11-04 17:14:53 -07:00
Alexander Matyushentsev
1431e04b90 fix: add missing await on cluster list page (#7621)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-04 17:14:25 -07:00
Alexander Matyushentsev
5bb45435e0 docs: more post v2.3 roadmap items (#7509)
* docs: more post v2.3 roadmap items

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

* replace multiple sources with helm + repo; add app dependencies feature

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-04 09:36:48 -07:00
pasha-codefresh
691b77ff9e feat: split yamls (#7595)
feat: split yamls (#7595)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-11-04 08:33:08 -07:00
Yuan Tang
b52793ab07 docs: Add link to awesome-argo for more resources (#7619)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-11-04 08:25:34 -07:00
Chandler Wilkerson
fc13eda8d6 feat: Add KubeVirt custom health checks (#7176)
Signed-off-by: cwilkers <cwilkers@redhat.com>
2021-11-04 08:23:48 -07:00
Ishita Sequeira
ff45418948 feat: add timezone option to sync window (#7442)
* feat: add timezone option to sync window

Signed-off-by: ishitasequeira <isequeir@redhat.com>

* Retrigger CI pipeline

Signed-off-by: ishitasequeira <isequeir@redhat.com>

* Addressed PR comments

Signed-off-by: ishitasequeira <isequeir@redhat.com>

* feat: add timezone option to sync window

Signed-off-by: ishitasequeira <isequeir@redhat.com>

* Addressed PR comments

Signed-off-by: ishitasequeira <isequeir@redhat.com>

* Addressed PR comments

Signed-off-by: ishitasequeira <isequeir@redhat.com>
2021-11-04 08:22:24 +01:00
Leonardo Luz Almeida
0d4e40ed6a fix: Address issue during diff when secret data is nil (#7603)
* fix: update gitops-engine to latest + log improvements

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

* run go mod tidy

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2021-11-03 12:46:05 -07:00
pasha-codefresh
fe3cc7218c feat: cache argo cd rbac (#7587)
feat: cache argo cd rbac (#7587)

Part of: #4296

Signed-off-by: Jan Jansen <jan.jansen@gdata.de>
Signed-off-by: pashavictorovich <pavel@codefresh.io>
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-03 11:28:52 -07:00
Alexander Matyushentsev
513d8a4ae0 fix: fix invalid resource icons (#7610)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-03 08:19:06 +01:00
plakyda-codefresh
6036e9b4c9 feat: remove cluster confirmation (#7602)
feat: remove cluster confirmation (#7602)

Signed-off-by: viktorplakida <plakyda1@gmail.com>
2021-11-02 11:37:59 -07:00
Leonardo Luz Almeida
8a6b759c4a fix: address edge cases with sync windows (#7517)
* fix: address edge cases with sync windows

Signed-off-by: Leonardo Luz Almeida <leoluz@users.noreply.github.com>

* trigger build

Signed-off-by: Leonardo Luz Almeida <leoluz@users.noreply.github.com>

* trigger build

Signed-off-by: Leonardo Luz Almeida <leoluz@users.noreply.github.com>
2021-11-02 08:48:00 -07:00
Saumeya Katyal
c2b3e74089 feat: autocompletion for resource shortnames (#7466)
* feat: autocompletion for resource shortnames

Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2021-11-02 08:33:51 -07:00
John Keates
8b10b64dfa Update USERS.md (#7589)
Add Wehkamp as a argocd user.
2021-11-01 11:31:57 -07:00
jphelton
e5c34f472e fix: argocd-dex now merges existing dex.config.oauth2 block instead of overwriting (#7583)
* fix: argocd-dex now merges existing dex.config.oauth2 block with autogenerated block

Signed-off-by: Joshua Helton <jdoghelton@gmail.com>
Signed-off-by: jphelton <jdoghelton@gmail.com>

* simplified statement based on PR feedback

Signed-off-by: Joshua Helton <jdoghelton@gmail.com>
2021-11-01 11:30:42 -07:00
Ben Ye
49b71522c4 feat: support pprof endpoints (#7533)
Signed-off-by: Ben Ye <ben.ye@bytedance.com>
2021-11-01 10:49:43 -07:00
Alexander Matyushentsev
7a6b2ffe56 fix: controller fails to connect to cluster using exec auth provider (#7586)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-01 10:02:57 +01:00
jannfis
c7792522c5 fix: Improve user experience for update-password CLI command (#7581)
* fix: Improve user experience for update-password CLI command

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

* Regenerate CLI docs

Signed-off-by: jannfis <jann@mistrust.net>
2021-10-30 10:30:58 +02:00
Simon Ninon
f4fd836a1b fix: return a codes.NotFound error when trying to get a non-existent repository (#7548)
* fix: return a codes.NotFound error when trying to get a non-existent repository

Signed-off-by: Simon Ninon <simon.ninon@gmail.com>

* move s.db.RepositoryExists call after the permission check

Signed-off-by: Simon Ninon <simon.ninon@gmail.com>

* update ArgoDB mock and add unit tests

Signed-off-by: Simon Ninon <simon.ninon@gmail.com>
2021-10-30 10:11:19 +02:00
Mathieu Parent
2770c690a5 Update to Helm v3.7.1, allow to pass credentials and new OCI support (#7249)
* chore: Update Helm to v3.7.1

Signed-off-by: Mathieu Parent <math.parent@gmail.com>
2021-10-29 17:48:27 -07:00
Nills Franssens
5b914750a4 docs: remove mention of ksonnet in basics (#7567)
Signed-off-by: Nills Franssens <nills.franssens@gmail.com>
2021-10-29 10:46:05 -07:00
Yuan Tang
43cba9cc0b docs: Remove misleading minus sign after version number (#7559)
* docs: Remove unnecessary version numbers in high_availability.md

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

* Fix

Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-10-28 15:49:32 -07:00
Alex Stockinger
0dbffb8557 Clarify key/cert encoding in cluster credentials (#7545)
Fixes #7544

Signed-off-by: Alex Stockinger <mail@alexstockinger.de>
2021-10-28 13:02:19 -07:00
pasha-codefresh
7b0cf773cc feat: Replace option in cli, sync command (#7526)
feat: Replace option in cli, sync command (#7526)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-28 13:01:32 -07:00
Denis Lavrushko
d3bec0faaa docs: Added iits-consulting to the Users.md (#7566)
* added IITS organizations to the USERS.md file

Signed-off-by: Denis Lavrushko <denis.lavrushko@iits-consulting.de>
2021-10-28 12:21:09 -07:00
Saumeya Katyal
7750f579bb docs: toolchain doc minor command update (#7568)
Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2021-10-28 12:16:54 -07:00
Jeff Maaks
5aeb113968 Update private-repositories.md -- add Azure Repos (#7040)
Added a link to the documentation for creating an access token on Azure Repos
2021-10-28 12:11:40 -07:00
Engin Diri
4522a88289 feat: Show "Open application" link in Application details list view (#7455)
Signed-off-by: Engin Diri <engin.diri@mail.schwarz>
2021-10-28 12:04:29 -07:00
Ben Ye
5f4ecf1ef2 feat: improve cluster info fetch from secret by reducing unnecessary unmarshalling (#7530)
Signed-off-by: Ben Ye <ben.ye@bytedance.com>
2021-10-28 11:11:25 -07:00
Masakinpo
7ced59f346 chore: fix typo in docs/operator-manual/high_availability.md (#7551)
* fix typo in docs/operator-manual/high_availability.md

Signed-off-by: Masakinpo <masakinpo.jp@gmail.com>

* chore: fix typo in docs/operator-manual/high_availability.md

Signed-off-by: Masakinpo <masakinpo.jp@gmail.com>
2021-10-27 10:44:43 -07:00
Omer Kahani
a912611b7a Adding Snyk (#7537)
Signed-off-by: Omer Kahani <kahaniomer@gmail.com>
2021-10-25 18:19:21 -07:00
Alexander Matyushentsev
a21b0363e3 fix: Argo CD should provide apiversion and kinds to 'helm template' command (#7519)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-25 16:52:19 -07:00
Viktor Farcic
07b8a1f63c docs: Video about Image Updater (#7547)
Signed-off-by: Viktor Farcic <viktor@farcic.com>
2021-10-25 20:23:57 +02:00
Keith Chong
1804d771c7 feat: Add banner position option #7313 (#7462)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2021-10-23 11:09:17 -07:00
kiran
7fe8e5ff37 Added paytmlabs argocd blog in readme (#7529)
Signed-off-by: kiran <kiran.sundaravarathan@paytm.com>

Co-authored-by: kiran <kiran.sundaravarathan@paytm.com>
2021-10-22 17:26:47 -07:00
pasha-codefresh
b8510f35f1 fix: mkdocs doesnt work with 3.10.0 python (#7518)
fix: mkdocs doesnt work with 3.10.0 python (#7518)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-21 15:46:31 -07:00
pasha-codefresh
aa6aed3c04 feat: max cookie length (#7515)
feat: max cookie length (#7515)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-21 14:37:39 -07:00
Snyk bot
d6d620e98c fix: upgrade @types/react-helmet from 5.0.8 to 5.0.17 (#7473)
Snyk has created this PR to upgrade @types/react-helmet from 5.0.8 to 5.0.17.

See this package in npm:


See this project in Snyk:
https://app.snyk.io/org/argoproj/project/e257be49-1bf5-455e-a11b-cdab3dbef067?utm_source=github&utm_medium=referral&page=upgrade-pr
2021-10-21 11:13:23 -07:00
Michael Crenshaw
3e17a69df3 chore: default to no gpg for Procfile - avoids missing temp dir failure (#7506)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

Co-authored-by: Michael Crenshaw <michael_crenshaw@intuit.com>
2021-10-21 11:12:47 -07:00
Alexander Matyushentsev
da63fb26d1 fix: don't use revision caching during app creation (#7508)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-20 20:24:14 -07:00
Mohammad Yosefpor
401b266235 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:22:37 -07:00
Alexander Matyushentsev
f46ac844b8 chore: add pasha-codefresh to reviewers list (#7503)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-20 13:09:13 -07:00
May Zhang
046840dcf7 fix: docker image for ui-test (#7461)
fix: docker image for ui-test (#7461)

Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-10-20 11:34:28 -07:00
Atsushin
d460f844a4 fix: Fix Color Support in Logs (#7476)
Signed-off-by: Atsushi Neki <nekiaiken@gmail.com>
2021-10-20 11:31:24 -07:00
Leonardo Luz Almeida
970bb80b28 feat: add new sync option to fail if finds shared resources (#7444)
* feat: add new sync option to fail if finds shared resources

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

* docs: add docs for FailOnSharedResource sync option

Signed-off-by: Leonardo Luz Almeida <leoluz@users.noreply.github.com>
2021-10-20 08:06:41 -07:00
Alexander Matyushentsev
81e801d8ee fix: Invalid memory address or nil pointer dereference in processRequestedAppOperation (#7501)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-20 08:03:55 -07:00
Alexander Matyushentsev
872eff292b 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:16:31 -07:00
Julian Strobl
00874af5f2 fix: client certificate ignored during (re)login (#7423)
fix: client certificate ignored during (re)login (#7423)

Signed-off-by: Julian Strobl <julian.strobl@telekom.de>

Co-authored-by: Julian Strobl <julian.strobl@telekom.de>
2021-10-19 13:12:35 -07:00
Hritik Gupta
ad97ed52d5 doc: fixed content in toolchain guide (#7470)
doc: fixed content in toolchain guide (#7470)

Signed-off-by: hgupta3 <hritik_gupta@intuit.com>
2021-10-19 13:08:41 -07:00
Alexander Matyushentsev
7ea35924c9 fix: Application status panel shows Syncing instead of Deleting (#7486)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-19 10:30:09 -07:00
Byungjin Park (Claud)
c7074fe67a docs: Add KarrotPay to Users (#7467)
Signed-off-by: Byungjin Park <posquit0.bj@gmail.com>
2021-10-19 10:13:27 -07:00
jannfis
9a11790df2 fix: Allow plugins to lock repository at top-level to prevent git races (#6223)
* fix: Allow plugins to lock complete repository

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

* Add some documentation

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

* Adapt documentation

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

* Codegen

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

* Update codegen

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

* Update codegen

Signed-off-by: jannfis <jann@mistrust.net>
2021-10-19 18:51:59 +02:00
Yuan Tang
695699d08e docs: Add Akuity to the list of users (#7480)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-10-19 08:20:32 -07:00
Álvaro González
374965a606 docs: add a google warning and fix some formats (#7340)
Signed-off-by: alvarogonzalez-packlink <alvarogonzalez@packlink.com>
2021-10-19 01:36:59 -07:00
pasha-codefresh
ddc9f56d05 feat: Cluster name as part of sync (#7394)
feat: Cluster name as part of sync (#7394)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-18 18:44:54 -07:00
pasha-codefresh
3312dc0037 feat: Resource id tracking method doc (#7468)
feat: Resource id tracking method doc (#7468)
Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-18 18:44:08 -07:00
pasha-codefresh
67dd012b87 feat: add cluster name UI (#7409)
* group diff should set resource id use new interface

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

* add cluster destination should support name

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-18 13:03:49 -07:00
Leonardo Luz Almeida
10bb1c4e1f docs: add remaining metric docs (#7469)
Signed-off-by: Leonardo Luz Almeida <leoluz@users.noreply.github.com>
2021-10-18 10:10:34 -07:00
ChangZhuo Chen (陳昌倬)
f3730da01e fix: Fix typo in SparkApplication health check script (#7433) (#7434)
Closes: #7433

Signed-off-by: ChangZhuo Chen (陳昌倬) <czchen@czchen.org>
2021-10-17 22:24:42 -07:00
Snyk bot
d8f6ee2d72 fix: upgrade @types/react-dom from 16.8.5 to 16.9.14 (#7400)
Snyk has created this PR to upgrade @types/react-dom from 16.8.5 to 16.9.14.

See this package in npm:


See this project in Snyk:
https://app.snyk.io/org/argoproj/project/e257be49-1bf5-455e-a11b-cdab3dbef067?utm_source=github&utm_medium=referral&page=upgrade-pr
2021-10-17 20:35:07 -07:00
Leonardo Luz Almeida
b5d1433a1f Fix argocd_cluster_connection_status metric (#7419)
* bug: fix argocd_cluster_connection_status metric + docs

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2021-10-17 19:58:02 -07:00
Vaibhav Thakur
83ff035df7 Add Tigera to USERS.md (#7435)
Signed-off-by: Vaibhav Thakur <vaibhav@tigera.io>

Co-authored-by: Vaibhav Thakur <vaibhav@tigera.io>
2021-10-17 11:50:02 -07:00
jiraguha
1d4b91efa2 Add Rise the money app for teens to USERS.md (#7465)
Signed-off-by: jpiraguha <jiraguha@gmail.com>
2021-10-17 11:39:43 -07:00
May Zhang
43bcbfb093 fix: makeslice: cap out of range (#7463)
Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-10-17 10:43:14 -07:00
May Zhang
f0cd21a9f3 fix: invalid memory address or nil pointer dereference during cluster… (#7445)
Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-10-16 21:57:39 -07:00
Guy Elia
d7d8fe3da2 Add BigPanda to USERS.md (#7416)
Add BigPanda as an ArgoCD user
2021-10-12 10:00:51 -07:00
Assel Meher
c80c1d4f95 fix: fix parameter name when the value is a list (#7360) (#7362)
* fix: #7360

Signed-off-by: Assel Meher <asselmeher@gmail.com>

* fix assert in tests

Signed-off-by: Assel Meher <asselmeher@gmail.com>
2021-10-12 09:50:50 -07:00
Alexander Krantz
6644cbe452 fix: prevent displayed namespace from being undefined (#7401)
Signed-off-by: Alex Krantz <alex@krantz.dev>
2021-10-12 08:28:24 -07:00
Regina Scott
ae02bc27fc feat: add hide toggle for health status bar (#7153)
Signed-off-by: Regina Scott <rescott@redhat.com>
2021-10-11 14:41:48 -07:00
Mustafa
5faea8f339 docs: Append echo to kubectl in getting_started.md (#7403)
Add echo to the end of the kubectl command to fetch initial admin secrets so that '%' new line character is not printed at the end of the secret.

Signed-off-by: mustafa89 <mustafa.mujahid@outlook.com>

Co-authored-by: Mustafa Mujahid <mustafa.mujahid@tradebyte.com>
2021-10-11 22:49:06 +02:00
pasha-codefresh
678d35d850 feat: project destination cli (#7407)
feat: project destination cli (#7407)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-11 06:42:47 -07:00
c1_zh
363e1d2d49 feat: Make Casbin matcher configurable on runtime(globMatch(default) or RegexMatch) (#7165)
* feat: Make Casbin matcher configurable on runtime(globMatch(default) or RegexMatch)

Signed-off-by: cezhang <c1zhang.dev@gmail.com>
2021-10-09 12:01:09 -07:00
Alexander Matyushentsev
b2c70df619 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-08 15:46:15 -07:00
May Zhang
3c874ae065 fix: Utilize a backoff for git retried operations (#7395)
* fix: git retry duration

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

* fix: adjust default values

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

* fix: adjust default values

Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-10-08 14:00:09 -07:00
Jan-Otto Kröpke
4dd570eb11 docs: Kustomize load_restrictor -> load-restrictor (#7358)
Signed-off-by: Jan-Otto Kröpke <joe@adorsys.de>
2021-10-08 11:56:05 -07:00
Chetan Banavikalmutt
1bc231dd99 fix: failing automated UI smoke tests (#7392)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2021-10-08 11:49:00 -07:00
Hritik Gupta
8a8373faba feat(ui): Ability to view previous container logs in log viewer (#7393)
feat(ui): Ability to view previous container logs in log viewer (#7393)

Signed-off-by: hgupta3 <hritik_gupta@intuit.com>
2021-10-08 11:33:26 -07:00
Leonardo Luz Almeida
384f5b2bae Expose Application labels in prometheus metric (#7374)
Expose Application labels in prometheus metric (#7374)

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2021-10-08 10:15:51 -07:00
pasha-codefresh
b0736219b6 feat: Resources should be normalized in order to prevent our of sync during migration (#7388)
feat: Resources should be normalized in order to prevent our of sync during migration (#7388)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-07 09:51:29 -07:00
Hrittik Roy
4399348ae5 docs: Add p3r to Users.md (#7346)
docs: Add p3r to Users.md (#7346)

* Update USERS.md

* Add p3r to Users.md

Signed-off-by: GitHub <noreply@github.com>

* Update USERS.md

Signed-off-by: GitHub <noreply@github.com>
2021-10-07 09:49:39 -07:00
Chetan Banavikalmutt
df5cce866f fix: unable to read jqPathExpressions (#7375)
The commit introduces the following changes:
1. Update the admin settings resource-overrides CLI to work with jqPathExpressions
2. Allow jqPathExpressions to be set from the UI

Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2021-10-06 09:59:09 -07:00
pasha-codefresh
07eeddf5f1 feat: group diff should set resource id use new interface (#7381)
feat: group diff should set resource id use new interface (#7381)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-06 09:08:20 -07:00
Chetan Banavikalmutt
0c757534ed fix: remove misleading Helm labels from Redis resources in HA mode (#7368)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2021-10-05 13:00:26 +02:00
Chetan Banavikalmutt
d8d7b30f58 fix: username is required with access token (#7359)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2021-10-04 14:58:16 -07:00
Alexander Matyushentsev
9d88e614cd fix: creating JWT token fails (#7366)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-04 14:43:49 -07:00
Fabiano Arruda
4e025838c0 Update USERS.md (#7348) 2021-10-04 09:49:15 -07:00
pasha-codefresh
d0c6280d38 feat: change annotation format (#7345)
* change annotation format

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-04 09:48:51 -07:00
Keith Chong
e084a110e4 feat: Allow Banner to be non-closable #7261 (#7312)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2021-10-04 09:45:13 -07:00
pasha-codefresh
df7e5ffd96 feat: annotation-label tracking method (#7342)
feat: annotation-label tracking method (#7342)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-03 16:08:51 -07:00
Oleksandr Saulyak
6f8b10c324 fix: updated argo-ui package with fixes for #7192 / #7262 (#7344)
Signed-off-by: oleksandr-codefresh <oleksandr.saulyak@codefresh.io>
2021-10-02 10:50:32 -07:00
Jille Timmermans
eb70a1e3fa docs: Add an example for setting up Helm charts with GitOps (#7060)
Took me embarrassingly long to figure out.

Signed-off-by: Jille Timmermans <jille@quis.cx>
2021-10-01 11:18:30 -07:00
plakyda-codefresh
35bd9e1ed6 fix: retry options in app details modal (#7329)
fix: retry options in app details modal (#7329)

Signed-off-by: viktorplakida <plakyda1@gmail.com>
2021-10-01 10:24:46 -07:00
Matt Pursley
778be231b9 fix: a few typos in kustomize.md (#7334)
Signed-off-by: Matt Pursley <mattpursley@improbable.io>
2021-10-01 10:17:47 -07:00
Abhishek Veeramalla
d790e96aa9 fix: Retry with exponential backoff result in time to wait of zero(#7173) (#7339)
* fix: Retry with exponential backoff result in time to wait of zero(#7173)

Signed-off-by: iam-veeramalla <abhishek.veeramalla@gmail.com>

* fix issue reported by golintci

Signed-off-by: iam-veeramalla <abhishek.veeramalla@gmail.com>
2021-10-01 10:02:44 -07:00
Saumeya Katyal
a6039e1be9 fix: add url check and wrapping for commit msg field (#7218)
* fix: add url check and wrapping for commit msg field

Signed-off-by: saumeya <saumeyakatyal@gmail.com>

* move url regex to util

lint check

Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2021-10-01 09:23:49 -07:00
pasha-codefresh
3d4deeb4f0 fix: compare app state (#7341)
* fix compare app state

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-01 09:18:01 -07:00
pasha-codefresh
ebd87b77ed feat: improve sync logic (#7328)
feat: improve sync logic (#7328)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-09-30 14:49:29 -07:00
Yuan Tang
31b2cbee70 chore: More informative error message when redirect URL is invalid (#7331)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-09-30 13:29:12 -07:00
pasha-codefresh
a2677f5537 fix: Rm browser history (#7327)
fix: Rm browser history (#7327)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-09-30 13:25:46 -07:00
Álvaro González
65d669565b docs: configuring Google OIDC and Google groups for RBAC (#7308)
Signed-off-by: alvarogonzalez-packlink <alvarogonzalez@packlink.com>
2021-09-30 02:02:19 -07:00
Ishita Sequeira
07f4034aaa feat: lua script for pause/resume action for Deployments (#7293)
Signed-off-by: ishitasequeira <isequeir@redhat.com>
2021-09-29 17:58:35 -07:00
Yi Cai
459833d7c3 fix: default schedule options are cropped #5261 (#7289)
* fix: default schedule options are cropped #5261

Signed-off-by: ciiay <yicai@redhat.com>
2021-09-29 14:53:49 -07:00
Andrii Shaforostov
bbdbf81108 feat: update argo-ui (#7323)
* use merged argo-ui, align dependencies with argo-ui

Signed-off-by: andrii-codefresh <andrii@codefresh.io>

* use merged argo-ui, align dependencies with argo-ui

Signed-off-by: andrii-codefresh <andrii@codefresh.io>
2021-09-29 14:51:42 -07:00
Alexander Matyushentsev
1842c98374 fix: core-install.yaml always refers to latest argocd image (#7321)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-29 14:05:18 -07:00
Chetan Banavikalmutt
94372adcd4 fix: handle applicationset backup forbidden error (#7306)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2021-09-29 12:33:58 -07:00
plakyda-codefresh
e3df023310 fix: Move orphaned filter to Filters block (#7082)
fix: Move orphaned filter to Filters block (#7082)

Signed-off-by: viktorplakida <plakyda1@gmail.com>
2021-09-29 12:29:21 -07:00
Duy Le
6f5f7ffeee fix: tooltip zindex overwrite toolbar (#7220)
Signed-off-by: Duy Le <duyngoc834@gmail.com>
2021-09-29 12:24:41 -07:00
chandu484
97302103d9 Add Keeeb User to userlist (#7288) 2021-09-29 11:03:29 -07:00
Regina Scott
380037b63d fix: preventOverflow console warnings (#7298)
Signed-off-by: Regina Scott <rescott@redhat.com>
2021-09-29 10:27:25 -07:00
pasha-codefresh
0d68194205 feat: tracking method for annotations should be in another format (#7316)
feat: tracking method for annotations should be in another format (#7316)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-09-29 10:14:49 -07:00
Abhishek Veeramalla
20313adbe2 docs: minor formatting change in the docs (#7305)
Signed-off-by: iam-veeramalla <abhishek.veeramalla@gmail.com>
2021-09-29 11:43:57 +02:00
pasha-codefresh
a731997c59 feat: tracking method e2e (#7310)
feat: tracking method e2e (#7310)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-09-28 12:46:01 -07:00
pasha-codefresh
bb88a1c975 feat: rename app identifier (#7251)
feat: rename app identifier (#7251)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-09-28 08:35:17 -07:00
Alexander Matyushentsev
917d0797fa fix: deploy CI task should start docker using current user id to avoid permission denied error (#7300)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-27 19:01:55 -07:00
plakyda-codefresh
993cb838a9 feat: Project autocomplete (Connect repo SSH) (#7286)
feat: Project autocomplete (Connect repo SSH) (#7286)

Signed-off-by: viktorplakida <plakyda1@gmail.com>
2021-09-27 17:19:00 -07:00
Regina Scott
eb2c69d45e fix: long banner messages get cut off (#7264)
Signed-off-by: Regina Scott <rescott@redhat.com>
2021-09-27 13:31:14 -07:00
Alexander Matyushentsev
65012f502b chore: use kustomize verison bundled into argocd to upgrade argocd manifests in argoproj/argoproj-deployments (#7299)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-27 12:58:15 -07:00
ml
2f6e91ad22 chore: fix typo in directory name (#7248)
Signed-off-by: ml <ml@visu.li>
2021-09-27 11:33:00 -07:00
shivjm
b264729bfb docs: fix example ServiceMonitor for argocd-repo-server (#7254)
Signed-off-by: Shiv Jha-Mathur <shivjm@users.noreply.github.com>
2021-09-23 12:46:19 -07:00
pasha-codefresh
3952f66fc7 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-09-22 14:27:07 +02:00
plakyda-codefresh
b1f979aad6 feat: retry option app creation (#7252)
feat: retry option app creation (#7252)

Signed-off-by: viktorplakida <plakyda1@gmail.com>
2021-09-21 15:42:26 -07:00
Yuan Tang
2a579a6c05 docs: Add missing links to 1.8-2.1 upgrading guides (#7263)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-09-21 15:02:26 -07:00
dependabot[bot]
9e234b9dec chore(deps): bump tmpl from 1.0.4 to 1.0.5 in /ui (#7266)
Bumps [tmpl](https://github.com/daaku/nodejs-tmpl) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/daaku/nodejs-tmpl/releases)
- [Commits](https://github.com/daaku/nodejs-tmpl/commits/v1.0.5)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-21 15:02:14 -07:00
John Chen
4f69e93802 docs: add comment about current-user-password (#7258)
It is not immediately clear what the `<current-user-password>` should be as shown by this issue: https://github.com/argoproj/argo-cd/issues/4096.
This comment should make it more clear that when users are setting passwords as the default `admin` user, they should be using the `admin` password here.

Signed-off-by: John Chen <johnchen456@gmail.com>
2021-09-21 14:34:13 -07:00
Alexander Matyushentsev
3799d706df refactor: cache virtual project calculation to improve performance (#7274)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-21 12:20:49 -07:00
yyyyyy888
344353cb16 docs: Add Sutpc company into the user list. (#7267)
Signed-off-by: yangtian9999 <yangtian9999@163.com>
2021-09-21 12:20:08 -07:00
dependabot[bot]
d698e5d68a chore(deps): bump prismjs from 1.24.1 to 1.25.0 in /ui (#7265)
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.24.1 to 1.25.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.24.1...v1.25.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-21 11:32:50 -07:00
dependabot[bot]
5f9993a75b chore(deps): bump nth-check from 2.0.0 to 2.0.1 in /ui (#7270)
Bumps [nth-check](https://github.com/fb55/nth-check) from 2.0.0 to 2.0.1.
- [Release notes](https://github.com/fb55/nth-check/releases)
- [Commits](https://github.com/fb55/nth-check/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: nth-check
  dependency-type: indirect
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-21 09:43:13 -07:00
Alexander Matyushentsev
f613fab6f3 refactor: stop using @beyonk/google-fonts-webpack-plugin to download google fonts (#7253)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-18 08:22:53 +02:00
Alexander Matyushentsev
183d729d40 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:15 -07:00
Regina Scott
b26e92873f fix: typo causing docs to not render properly (#7242)
Signed-off-by: Regina Scott <rescott@redhat.com>
2021-09-16 13:00:02 -07:00
Alexander Matyushentsev
36ab4dadda fix: Argo CD server address unspecified with Argo CD CLI v2.1.x (#7238)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-16 11:23:29 -07:00
pasha-codefresh
91fea1470f feat: add test to redis_hook.go (#7233)
* add test to redis_hook.go

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

* restart action

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-09-16 08:06:29 -07:00
pasha-codefresh
17e6ebdce1 feat: show difference in repos that exist and that should be changed (#7224)
* show difference in repos that exist and that should be changed

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-09-16 08:02:50 -07:00
pasha-codefresh
6f794d0dc9 fix: Redis should reconnect on connectivity issue (#7207)
fix: Redis should reconnect on connectivity issue (#7207)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-09-15 09:05:48 -07:00
Miguel Ángel Cabrera Miñagorri
9cf71bef90 fix: support gpg keys generation in centos-7 distros (#7221)
Signed-off-by: Miguel A. Cabrera Minagorri <mcabrera@vmware.com>
2021-09-15 08:26:46 -07:00
gin
25db5038c7 docs(users): add mixi in users.md (#7210)
Signed-off-by: gin <10017674+lirlia@users.noreply.github.com>
2021-09-14 12:52:19 -07:00
Remington Breeze
b6c458e8f4 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-09-14 12:51:37 -07:00
Alexander Matyushentsev
2147ed3aea fix: cluster API should not drop system labels and annotations (#7212)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-14 10:37:57 -07:00
Remington Breeze
3df6be73e7 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-13 22:18:38 -07:00
jannfis
d823efee5d proposal: Change application identifier to allow app names longer than 63 chars (#6425)
proposal: Change application identifier to allow app names longer than 63 chars (#6425)

Signed-off-by: jannfis <jann@mistrust.net>
2021-09-13 08:49:15 -07:00
pasha-codefresh
1817b6b4d4 Scoped resources doc (#7206)
* add doc about scoped resources

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

* docs: explain project scoped resources

Signed-off-by: Kostis Kapelonis <kostis@codefresh.io>

Co-authored-by: Kostis Kapelonis <kostis@codefresh.io>
2021-09-13 08:47:39 -07:00
pasha-codefresh
7ed06cc9f6 feat: Scoped resources cluster e2e (#7199)
feat: Scoped resources cluster e2e (#7199)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-09-12 19:05:49 -07:00
Yuan Tang
49378a95c4 chore: Update Ingress apiVersion to networking.k8s.io/v1beta1 (#7188)
* chore: Update Ingress apiVersion to networking.k8s.io/v1beta1

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

* Revert changes in  controller/cache/info_test.go

Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-09-10 10:04:52 -07:00
jannfis
a38f3176e2 chore: Update haproxy for redis-ha to 2.0.25 (#7194)
Signed-off-by: jannfis <jann@mistrust.net>
2021-09-10 09:13:27 -07:00
pasha-codefresh
08d1cf0e55 feat: Ability to test rbac and implement it with scoped repos (#7187)
feat: Ability to test rbac and implement it with scoped repos (#7187)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-09-09 21:42:32 -07:00
Thomas
85c45ca76e fix: use selected helm-values (#7166)
Signed-off-by: Thomas Münzl <thomasmuenzl@icloud.com>
2021-09-09 20:48:32 -07:00
Yi Cai
626c963b1c docs: minor update on dependencies.md (#7190)
Signed-off-by: ciiay <yicai@redhat.com>
2021-09-09 15:28:49 -07:00
Suraj Bodade
fc49eb2e46 fixed small typos in github credentials types (#7161)
Signed-off-by: suraj-zemoso <suraj.bodade@zemosolabs.com>
2021-09-09 11:40:06 -07:00
irizzant
e0c07b8027 #7144 fix: add custom volume as Helm working dir (#7162)
#7144 fix: add custom volume as Helm working dir (#7162)

Signed-off-by: irizzant <i.rizzante@gmail.com>
2021-09-09 10:31:03 -07:00
Chetan Banavikalmutt
7122b83fc3 feat: support adding labels and annotations to cluster secret (#7139)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2021-09-09 09:03:32 -07:00
pasha-codefresh
c64e8df84c feat: ability to switch user during test execution (#7164)
feat: ability to switch user during test execution (#7164)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-09-09 08:58:46 -07:00
Ben Ye
be884d2172 feat: Support delete-resource command in cli (#7093)
* feat: support delete-resource command in argocd cli

Signed-off-by: Ben Ye <ben.ye@bytedance.com>

* add E2E test and fix documents

Signed-off-by: Ben Ye <ben.ye@bytedance.com>

* sync app

Signed-off-by: Ben Ye <ben.ye@bytedance.com>
2021-09-06 09:11:06 -07:00
Ijeh Onyeka
d2100a30a0 add youverify to companies actively using argocd (#7163) 2021-09-04 15:09:51 -07:00
ThoTischner
9559613c8f feat: Closes #6956 - Adding confluent health checks (#6957)
* Issue argoproj#6956 - Adding confluent health checks

Signed-off-by: ThoTischner <thomas-schwaig@web.de>

* Issue argoproj#6956 - Change Unknown to Progressing

Signed-off-by: ThoTischner <thomas-schwaig@web.de>
2021-09-03 21:51:00 +02:00
dependabot[bot]
bd7f8c8eda chore(deps): bump tar from 6.1.3 to 6.1.11 in /ui (#7123)
Bumps [tar](https://github.com/npm/node-tar) from 6.1.3 to 6.1.11.
- [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.3...v6.1.11)

---
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-09-03 19:32:33 +02:00
jannfis
a90ab1a2e1 chore: Upgrade github.com/bradleyfalzon/ghinstallation to v2.0.2 (#7151)
Signed-off-by: jannfis <jann@mistrust.net>
2021-09-03 10:28:10 -07:00
Thomas
a5126648e1 fix: use basehref as cookie-path (#7105)
Signed-off-by: Thomas Münzl <thomasmuenzl@icloud.com>
2021-09-03 19:21:31 +02:00
Petr Drastil
d9e8a0fc31 chore: Upgrade dex server image to 2.30.0 (#7102)
* chore: Upgrade dex server to 2.30.0

Signed-off-by: Petr Drastil <petr.drastil@gmail.com>

* Revert dex server probes

Signed-off-by: Petr Drastil <petr.drastil@gmail.com>
2021-09-03 19:20:01 +02:00
Ishita Sequeira
b559bf88d1 feat: Add health checks for route.openshift.io (#7112)
* feat: Add health checks for route.openshift.io

Signed-off-by: ishitasequeira <isequeir@redhat.com>

* Addressed PR comments

Signed-off-by: ishitasequeira <isequeir@redhat.com>
2021-09-03 17:27:16 +02:00
Ishita Sequeira
c0f2bf55a7 feat: health check for openshift DeploymentConfig (#7114)
* feat: health check for openshift DeploymentConfig

Signed-off-by: ishitasequeira <isequeir@redhat.com>

* Address PR comments

Signed-off-by: ishitasequeira <isequeir@redhat.com>
2021-09-03 17:26:31 +02:00
Ishita Sequeira
4b92f96034 feat: Add health checks for olm operators (#7126)
* feat: Add health checks for olm operators

Signed-off-by: ishitasequeira <isequeir@redhat.com>

* Addressed the PR comments

Signed-off-by: ishitasequeira <isequeir@redhat.com>
2021-09-03 17:25:42 +02:00
smartbit
24054820da docs: update url of External Secrets Operator (#7120)
has moved from ContainerSolutions' github account to it's own github project
2021-09-03 11:10:58 +02:00
Alexander Matyushentsev
22600228c2 fix: Correct this attempt to modify const 'store' variable (#7145)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-02 11:37:20 -07:00
renjikari
9025318adf docs: Add freee as a user (#7140)
Signed-off-by: Shunki Fujiwara <shunki-fujiwara@freee.co.jp>
2021-09-02 03:43:13 -07:00
Alexander Matyushentsev
5d9aa989f3 fix: gracefully shutdown metrics server when dex config changes (#7138)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-01 18:55:05 -07:00
Alexander Matyushentsev
9613b240fb fix: upgrade gitops engine (fix #7088) (#7137)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-01 17:45:42 -07:00
Alexander Matyushentsev
8fbcc1c7fc fix: cluster filter popping out of box (#7135)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-09-01 15:33:27 -07:00
Remington Breeze
d2ff65ae39 feat(ui): Display event timestamps in human readable format (#7132)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-09-01 15:08:40 -07:00
c1_zh
dd26a48f8a fix: Network view is confusing if same ingress is targeting two services #2338 (#7113)
Signed-off-by: cezhang <c1zhang.dev@gmail.com>
2021-09-01 14:46:40 -07:00
Chetan Banavikalmutt
8c19c7864d docs: add a section about banners (#7109)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2021-09-01 12:52:59 -07:00
pasha-codefresh
a9f009cb10 feat: e2e for clusters (#7118)
feat: e2e for clusters (#7118)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-08-31 10:32:54 -07:00
May Zhang
ce1d8031ae 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-08-31 08:30:03 -07:00
pasha-codefresh
dd2900eaeb feat: scoped repo e2e tests (#7110)
feat: scoped repo e2e tests (#7110)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-08-30 10:10:32 -07:00
pasha-codefresh
c0bcd6b255 feat: repo list and repo get command + e2e tests (#7108)
feat: repo list and repo get command + e2e tests (#7108)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-08-30 10:08:33 -07:00
Álvaro González
6897aa4ed2 docs: add configuration guide for using Google Load Balancers with GKE (#6747)
* docs: add configuration guide for using Google Load Balancers with GKE

Signed-off-by: alvarogonzalez-packlink <alvarogonzalez@packlink.com>

* docs: fix format on notes and warnings

Signed-off-by: alvarogonzalez-packlink <alvarogonzalez@packlink.com>
2021-08-30 15:58:49 +02:00
Yi Cai
42903044f3 fix: Summary Colors don't match key and numbers don't match colors #5200 (#7042)
Signed-off-by: ciiay <yicai@redhat.com>
2021-08-27 12:41:09 -07:00
Thomas
700806f408 fix: reset token-cookie on logout (oidc) (#7092)
fix: reset token-cookie on logout (oidc) (#7092)

Signed-off-by: jimtoniq <thomasmuenzl@icloud.com>
2021-08-27 11:09:19 -07:00
pasha-codefresh
b271d6ac5c feat: Test create repository with project ( part of scoped resources e2e tests ) (#7103)
feat: Test create repository with project ( part of scoped resources e2e tests ) (#7103)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-08-27 10:29:31 -07:00
Jonah Back
a940cb5914 fix(ui): calculate service info correctly for networking.k8s.io/v1 ingress (#6923)
Signed-off-by: Jonah Back <jonah@jonahback.com>
2021-08-26 14:47:26 -07:00
Alexander Matyushentsev
87de4edd15 fix: document IP addresses logging (#7094)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-26 13:01:40 -07:00
Alexander Matyushentsev
abba8dddce docs: update VERSION file and CHANGELOG (#7083)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-26 11:28:51 -07:00
plakyda-codefresh
44520ea479 feat: resource name filter + filter block for resource table view (#7081)
feat: resource name filter + filter block for resource table view (#7081)

Signed-off-by: viktorplakida <plakyda1@gmail.com>
2021-08-26 10:32:36 -07:00
pasha-codefresh
ae803a2f1e feat: goreman option to exclude (#7080)
feat: goreman option to exclude (#7080)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-08-25 12:40:55 -07:00
pasha-codefresh
49a854a738 feat: Scoped clusters (#7039)
feat: Scoped clusters (#7039)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-08-25 09:53:58 -07:00
Benjamin Manifold
81155ccb0c feat: Cassandra Health Check. Closes #6843 (#7017)
Signed-off-by: benmanifold <benmanifold@gmail.com>
2021-08-25 11:27:07 +02:00
Josh Gavant
18057fa5ee docs: clarify new repo, port-forward flags (#6937)
The instructions for telling the CLI how to automatically use
port-forward were intertwined with the instructions for registering a
repo; this separates them.

This also moves the port-forward flags instructions to the first place
in the doc a user would need them.

Signed-off-by: Josh Gavant <joshgavant@gmail.com>
2021-08-25 11:26:44 +02:00
May Zhang
ca5003f3ba fix: password reset requirements (#7071)
* fix: password reset meet requirement

Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-08-24 23:21:03 -07:00
Alexander Matyushentsev
1d3d03f5d3 fix: Custom Styles feature is broken (#7067)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-24 15:08:12 -07:00
Remington Breeze
a894d4b128 fix(ui): Unschedulable button changed widths on click (#7030)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-24 11:29:45 -07:00
Remington Breeze
440e4dc5d9 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 11:23:56 -07:00
Alexander Matyushentsev
d6973c7b8a fix: fix building remote container (#7062)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-24 09:48:14 -07:00
pasha-codefresh
34e904dd7b fix: make codegen (#7059)
fix: make codegen

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-08-24 09:02:44 -07:00
Omar De Donato
c7e532941f docs: added Technacy in USERS.md (#7051)
We at Technacy love using Argo CD

Signed-off-by: Omar <omar.dedonato@technacy.it>
2021-08-23 13:23:28 +02:00
Alexander Matyushentsev
613db278a7 fix: keep uid_entrypoint.sh for backward compatibility (#7047)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-23 08:38:29 +02:00
pasha-codefresh
91c883668e feat: Scoped repo unit tests (#7026)
feat: Scoped repo unit tests

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-08-22 18:01:36 -07:00
Yi Cai
d12eafa826 fix: Truncated synchronize check-boxes should have tooltips #4233 (#6954)
Signed-off-by: ciiay <yicai@redhat.com>
2021-08-20 12:41:25 -07:00
Alexander Matyushentsev
0dcac9a8d9 fix: reload extension when selected resource node changes (#7034)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-19 22:14:00 -07:00
Jesse Suen
0078a4d9ee docs: add @wanghong230 as a reviewer (#7029)
Signed-off-by: Jesse Suen <jessesuen@gmail.com>
2021-08-19 17:02:51 -07:00
Jesse Suen
8ceceb8b55 docs: add @rbreeze as an approver (#7028)
Signed-off-by: Jesse Suen <jessesuen@gmail.com>
2021-08-19 13:56:47 -07:00
Remington Breeze
2e3405134b fix(ui): Resource details crashed due to extensions (#7025)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-19 09:55:16 -07:00
pasha-codefresh
5b1906d2a7 feat: Cover grpc crud rbac (#7008)
feat: Cover grpc crud rbac (#7008)

Signed-off-by: Victor Plakyda <plakyda1@gmail.com>
Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-08-19 08:43:48 -07:00
pasha-codefresh
0093bddc39 fix(ui): user account list yaml (#7021)
fix(ui): user account list yaml (#7021)

Signed-off-by: Victor Plakyda <plakyda1@gmail.com>
2021-08-19 08:40:20 -07:00
Alexander Matyushentsev
788613cb14 feat: support loading extensions in Argo CD UI (#7019)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-19 08:39:51 -07:00
pasha-codefresh
53dd0da8c3 fix(ui): applications table view, Closes #6733 (#6995)
Co-authored-by: Victor Plakyda <plakyda1@gmail.com>
2021-08-18 12:23:34 -07:00
Guido Zockoll
8f21138d54 docs: added type:git to secret examples (fixes #6984) (#7013)
* Update declarative-setup.md

added `type: git` to the secrets

* warning about labels getting lost

when using sealed-secrets the labels will get lost and has to be readded
2021-08-18 20:18:28 +02:00
Saumeya Katyal
676a8714bf fix: Unschedulable button style (#7003)
Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2021-08-18 09:24:03 -07:00
Philipp Dallig
4ae1d876fd fix: Running on Openshift 4.x with readOnlyRootFilesystem (#6998)
Signed-off-by: Philipp Dallig <philipp.dallig@gmail.com>
2021-08-18 12:18:01 +02:00
Chris Sinjakli
efc8ec1d78 chore: Log application name for invalid application spec (#6991)
When creating an application directly through the CLI or a `kubectl
apply`, it's relatively obvious which application is invalid (provided
you aren't applying several at once) as you're there creating it
interactively.

It's less clear when applications are generated by the application set
controller. When that happens, you need to go looking in the controller
logs, where you'll find something like:

> time="2021-08-10T11:36:02Z" level=error msg="application spec is
> invalid: InvalidSpecError: application destination
> {https://kubernetes.default.svc default} is not permitted in project
> 'my-project'"

which doesn't have any connection back to the application being
generated. This is particularly tricky to track down if you're searching
your logs via some sort of aggregator rather than watching `kubectl logs
-f`.

After this change, the log produced would be:

> time="2021-08-10T11:36:02Z" level=error msg="application spec for
> guestbook is invalid: InvalidSpecError: application destination
> {https://kubernetes.default.svc default} is not permitted in project
> 'my-project'"

There's probably fancier ways this information could be presented (e.g.
if application sets were represented in the UI and knew about failures
to apply their generated applications), but this logging change seems
like a cheap way to make this situation more debuggable.

Signed-off-by: Chris Sinjakli <chris@sinjakli.co.uk>
2021-08-18 11:10:52 +02:00
Alexander Matyushentsev
e3b7a2be13 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:34:27 -07:00
Alexander Matyushentsev
44ec4e0a82 fix: upgrade argo-ui version (#7010)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-17 12:50:07 -07:00
pasha-codefresh
24ad4618c2 fix: Git errors to grpc (#7005)
fix: Git errors to grpc (#7005)

Signed-off-by: olegz-codefresh <olegz@codefresh.io>
2021-08-17 12:27:44 -07:00
Yuan Tang
d3fb6fb7db chore: Update to use NewSharedInformerFactoryWithOptions due to deprecation (#7009)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-08-17 21:23:13 +02:00
RoCha
95d9016ed4 feat: healtcheck for iam.cnrm.cloud.google.com/IAMPolicyMember (#6783)
Signed-off-by: Romain Chalumeau <rchalumeau@magicleap.com>
2021-08-17 21:20:30 +02:00
Alexander Matyushentsev
e195995790 docs: update obsolete resource customization docs (#7000)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-16 10:49:34 -07:00
Spiros Economakis
124995c275 feat: Add a metric to express connection status to each cluster (#6862)
The cluster collector includes one more metric for kubernetes cluster connection
which rely on `SyncError`.

Ticket: #6855
Signed-off-by: Spiros Economakis <spiros.oikonomakis@gmail.com>
2021-08-16 09:52:47 -07:00
pasha-codefresh
7b89c4e53c feat: Project scoped repo (#6943)
feat: Project scoped repo (#6943)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-08-16 09:38:37 -07:00
David Collom
1ab85de378 fix: Disable generating of CA Certificates (#6987)
Signed-off-by: David Collom <david.collom@jetstack.io>
2021-08-14 10:04:41 +02:00
Remington Breeze
eb76649ef5 chore(ui): Relocate CheckboxRow component to Filters instead of argo-ui (#6990)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-13 15:33:36 -07:00
Remington Breeze
3887289090 fix(ui): Migrate to keyhook helpers in argo-ui, update keybindings accordingly (#6953)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-13 14:26:11 -07:00
Yi Cai
d842e8333a feat: Allow collapsing of individual diff sections in diff view #3608 (#6978)
Signed-off-by: ciiay <yicai@redhat.com>
2021-08-13 08:31:37 -07:00
Alexander Matyushentsev
311926b8c9 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:10:59 -07:00
Yuan Tang
63d809614c 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-12 22:50:15 -07:00
Yuan Tang
741329afb6 docs: Add cluster URL when creating an app to be consistent with the screenshot (#6731)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-08-12 22:23:00 -07:00
Nico Schottelius
d36cf3e2bb Update USERS.md - added ungleich.ch (#6979)
Signed-off-by: Nico Schottelius <nico.schottelius@ungleich.ch>

Co-authored-by: Nico Schottelius <nico@nico-notebook.schottelius.org>
2021-08-12 22:17:54 -07:00
Alexander Matyushentsev
53bbb8ecf4 docs: update roadmap and release checklist (#6980)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-12 16:59:39 -07:00
dependabot[bot]
86ca66b2d6 chore(deps): bump jszip from 3.5.0 to 3.7.1 in /ui-test (#6952)
Bumps [jszip](https://github.com/Stuk/jszip) from 3.5.0 to 3.7.1.
- [Release notes](https://github.com/Stuk/jszip/releases)
- [Changelog](https://github.com/Stuk/jszip/blob/master/CHANGES.md)
- [Commits](https://github.com/Stuk/jszip/compare/v3.5.0...v3.7.1)

---
updated-dependencies:
- dependency-name: jszip
  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-12 13:19:20 -07:00
pasha-codefresh
6ac9753b63 feat: support ability get cluster by name from cli, Closes #6865 (#6972)
feat: support ability get cluster by name from cli, Closes #6865 (#6972)

Support get cluster cmd by name
https://github.com/argoproj/argo-cd/issues/6865

Signed-off-by: olegz-codefresh <olegz@codefresh.io>
2021-08-12 13:18:18 -07:00
pasha-codefresh
afb1c8b210 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:35:20 -07:00
dependabot[bot]
117eadaceb chore(deps): bump path-parse from 1.0.6 to 1.0.7 in /ui-test (#6950)
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  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-12 12:33:41 -07:00
dependabot[bot]
10b4e44c42 chore(deps): bump path-parse from 1.0.6 to 1.0.7 in /ui (#6949)
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  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-12 12:33:18 -07:00
dependabot[bot]
8cf8a8cf81 chore(deps): bump url-parse from 1.5.1 to 1.5.3 in /ui (#6951)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.1 to 1.5.3.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.1...1.5.3)

---
updated-dependencies:
- dependency-name: url-parse
  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-12 12:33:10 -07:00
pasha-codefresh
8a29cf8fbf fix(ui): Fix checkbox style in Delete pod modal Closes #6947 (#6961)
* Fix checkbox style in Delete pod modal

Signed-off-by: Victor Plakyda <plakyda1@gmail.com>

* Fix checkbox

Signed-off-by: Victor Plakyda <plakyda1@gmail.com>

Co-authored-by: Victor Plakyda <plakyda1@gmail.com>
2021-08-12 12:05:17 -07:00
ritchiekng
4a3dd76f19 Create USERS.md (#6973)
Fixing issue where link not working
2021-08-12 12:02:30 -07:00
Jesse Suen
b91732a8eb 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:37:08 -07:00
ritchiekng
97e8c7d00d Update USERS.md - added MeDirect (#6955)
* Update USERS.md

Signed-off-by: Steve Ritchie <steve.ritchie@medirect.com.mt>

* Update USERS.md

Updating website for Medirect
2021-08-11 16:28:51 -07:00
Alexander Matyushentsev
e5ee00f4d0 fix: basehref not set correctly (#6962)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-11 15:22:33 -07:00
Alexander Matyushentsev
aab0b173d5 fix: update deprecated helm2 installation URL (#6960)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-11 12:33:59 -07:00
Alexander Matyushentsev
50993206a5 fix: make sure repo server discard cached empty response (#6948)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-10 19:25:07 -07:00
Alexander Matyushentsev
4164db88f5 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-10 17:10:24 -07:00
May Zhang
c5eb25ceba 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-09 19:22:10 -07:00
pasha-codefresh
685b07ed34 feat(ui): Retry strategy, Application + Applications, #5318 (#6864)
feat(ui): Retry strategy, Application + Applications, #5318 (#6864)

Signed-off-by: Victor Plakyda <plakyda1@gmail.com>
2021-08-09 17:26:31 -07:00
jannfis
3091bc5b6f 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 12:15:21 +02:00
Saravanan Arumugam (Aswath)
810a977846 Added RightRev As the user's list. (#6929)
Added RightRev As the user's list.

Signed-off-by: Saravanan Arumugam (Aswath) <saravanan.a@rightrev.com>
2021-08-08 08:55:39 -07:00
jannfis
adade448a8 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-08 08:55:01 -07:00
jannfis
c22d8321cc docs: Update security contacts in security policy (#6928)
* docs: Update security contact

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

* docs: Update security contact

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

* docs: Update security contact

Signed-off-by: jannfis <jann@mistrust.net>
2021-08-07 17:58:21 -07:00
Daisuke Taniwaki
819225c709 fix: Set header to OIDC requests (#6869)
Signed-off-by: Daisuke Taniwaki <daisuketaniwaki@gmail.com>
2021-08-05 12:02:22 +02:00
Connor
dd50b88cd1 docs: Add documentation on using OIDC with Dex (#6904)
* docs: Add documentation on using OIDC with Dex

Signed-off-by: Connor Kelly <connor.r.kelly@gmail.com>

* docs: Add documentation on using OIDC with Dex -- fix typo

Signed-off-by: Connor Kelly <connor.r.kelly@gmail.com>

* Fix warning box for Dex OIDC group configuration knob

Signed-off-by: Connor Kelly <connor.r.kelly@gmail.com>
2021-08-05 11:57:18 +02:00
Alexander Matyushentsev
8b1c364f58 fix: application sync panel crashes if app has no sync options (#6914)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-04 16:56:08 -07:00
Yi Cai
d74ce38c8c fix: Reword Generate new token dialog (#6913)
Signed-off-by: ciiay <yicai@redhat.com>
2021-08-04 16:48:27 -07:00
Alexander Matyushentsev
826288f861 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:51:16 -07:00
Yi Cai
e86c5ea17c 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:05:49 -07:00
Noam Gal
f7614e0c4e fixed max to use MaxInt64 value (#6911)
Signed-off-by: Noam Gal <noam.gal@codefresh.io>
2021-08-04 11:07:54 -07:00
Chetan Banavikalmutt
2130c8a949 fix: unset command should remove env vars when there's no error (#6908)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2021-08-04 10:54:16 -07:00
pasha-codefresh
9d6ccee305 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 10:51:54 -07:00
Remington Breeze
9c0495d9a3 fix: Add https prefix to ingress URLs if hosts field is present (#6901)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-04 09:33:41 -07:00
woshicai
ef653cac57 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 14:20:18 +02:00
Bob Claerhout
9099d0ba83 docs: Add replace description on individual resource level (#6905)
Signed-off-by: Bob Claerhout <claerhout.bob@gmail.com>
2021-08-04 14:14:21 +02:00
May Zhang
50b0010470 fix: logout redirect URL (#6903)
Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-08-03 17:05:58 -07:00
Alexander Matyushentsev
6b0d449997 refactor: update resources install order according to helm implementation (#6902)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-03 16:53:39 -07:00
Alexander Matyushentsev
c607a3b294 fix: controller should not create orphaned resources warning by default (#6898)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-03 16:05:19 -07:00
Alexander Matyushentsev
4fef2114fe feat: Improve Replace sync option description in UI (#6899)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-03 16:05:08 -07:00
dependabot[bot]
8c216ed7a8 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 13:50:29 -07:00
Joseph Michael Casey
d404f0e425 docs(users): add Capital One (#6897) 2021-08-03 10:51:49 -07:00
Yi Cai
c5ebc584d0 fix: menu for application loses text when title area buttons collapse #6474 (#6887)
Signed-off-by: ciiay <yicai@redhat.com>
2021-08-03 10:06:12 -07:00
Remington Breeze
241a6fb1ba 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:34:07 -07:00
Remington Breeze
93e624d590 fix(ui): Add View Details option to resource actions menu (#6893)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-03 09:33:25 -07:00
Jan-Otto Kröpke
8f4e002ae4 fix: upgrade to kustomize 4.2.0 (#6861)
Signed-off-by: Jan-Otto Kröpke <joe@adorsys.de>
2021-08-03 09:24:22 -07:00
May Zhang
3abf8c6735 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 10:48:20 +02:00
Jun
3ff8481694 feat: Rollback command support omit history id (#6863)
Signed-off-by: junnplus <junnplus@gmail.com>
2021-08-02 22:32:09 -07:00
Remington Breeze
0d23207c59 fix(ui): Incorrect path for non-namespaced resources (#6895)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-02 17:56:12 -07:00
balchua
fcd28b6eb1 docs: rename credit agricole to credit agricole CIB. (#6871)
* rename credit agricole to credit agricole CIB.

Signed-off-by: balchua <balchua@yahoo.com>

* fix semantic pr.

Signed-off-by: balchua <balchua@yahoo.com>
2021-08-02 12:29:54 -07:00
Remington Breeze
7e27d1072f fix(ui): Page navigation no longer visible with status bar (#6888)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-08-02 12:29:37 -07:00
Alexander Matyushentsev
1e5c763d6f fix: make sure orphaned filter checkbox is clickable (#6886)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-08-02 11:51:40 -07:00
woshicai
7fbf50493b 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-02 11:43:01 -07:00
Geoffrey Huntley
f170d24ed1 docs(users): add gitpod (#6879)
Signed-off-by: Geoffrey Huntley <ghuntley@ghuntley.com>
2021-08-02 11:39:08 -07:00
Joe Bowbeer
bcfc112d82 docs: installation.md (#6860)
Signed-off-by: Joe Bowbeer <joe.bowbeer@gmail.com>
2021-07-30 15:57:17 -07:00
Yi Cai
66acd16bce fix: Project filter selector does not get unset upon clear filters #6750 (#6866)
Signed-off-by: ciiay <yicai@redhat.com>
2021-07-30 15:47:00 -07:00
Remington Breeze
bee20c2154 fix(ui): Prevent UI crash if app status or resources is empty (#6858) 2021-07-30 08:48:05 -07:00
Alexander Matyushentsev
17bef1c2c6 fix: util.cli.SetLogLevel should update global log level (#6852)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-07-29 13:01:38 -07:00
Alexander Matyushentsev
2abf284f81 fix: include cluster level RBAC into argocd-core manifests (#6854)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-07-29 12:49:06 -07:00
David Maciel
221d0c048d Fix #6567 Admin token now expires (#6846) 2021-07-29 11:19:53 -07:00
dependabot[bot]
cd9dcecccd chore(deps): bump glob-parent from 5.1.1 to 5.1.2 in /ui-test (#6848)
Bumps [glob-parent](https://github.com/gulpjs/glob-parent) from 5.1.1 to 5.1.2.
- [Release notes](https://github.com/gulpjs/glob-parent/releases)
- [Changelog](https://github.com/gulpjs/glob-parent/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gulpjs/glob-parent/compare/v5.1.1...v5.1.2)

---
updated-dependencies:
- dependency-name: glob-parent
  dependency-type: indirect
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-29 11:18:57 -07:00
dependabot[bot]
52090425c6 chore(deps): bump ws from 7.4.1 to 7.5.3 in /ui-test (#6849)
Bumps [ws](https://github.com/websockets/ws) from 7.4.1 to 7.5.3.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.4.1...7.5.3)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-29 11:18:19 -07:00
Klaus Dorninger
228c465393 fix: #6844 multiple global projects can be configured (#6845)
Signed-off-by: Klaus Dorninger <github@dornimaug.org>
2021-07-29 11:01:52 -07:00
Keith Chong
4a69cce7b1 test: Add initial automated UI smoke tests (#4393) (#4694)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2021-07-29 10:11:11 -07:00
Alexander Matyushentsev
c7738a0cae fix: core installation must include CRD definitions (#6841)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-07-28 16:30:11 -07:00
493 changed files with 23825 additions and 3564 deletions

View File

@@ -12,7 +12,7 @@ on:
env:
# Golang version to use across CI steps
GOLANG_VERSION: '1.16.5'
GOLANG_VERSION: '1.16.11'
jobs:
build-docker:

View File

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

View File

@@ -6,7 +6,7 @@ on:
- master
env:
GOLANG_VERSION: '1.16.5'
GOLANG_VERSION: '1.16.11'
jobs:
publish:
@@ -51,7 +51,7 @@ jobs:
env:
TOKEN: ${{ secrets.TOKEN }}
- run: |
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 }}
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 }}
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,7 +12,7 @@ on:
- '!release-v0*'
env:
GOLANG_VERSION: '1.16.5'
GOLANG_VERSION: '1.16.11'
jobs:
prepare-release:

View File

@@ -1,6 +1,15 @@
# Changelog
## v2.1.0 (Unreleased)
## 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)
> [Upgrade instructions](./docs/operator-manual/upgrading/2.0-2.1.md)

View File

@@ -4,7 +4,7 @@ ARG BASE_IMAGE=docker.io/library/ubuntu:21.04
# 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.5 as builder
FROM docker.io/library/golang:1.16.11 as builder
RUN echo 'deb http://deb.debian.org/debian buster-backports main' >> /etc/apt/sources.list
@@ -62,6 +62,8 @@ COPY --from=builder /usr/local/bin/helm2 /usr/local/bin/helm2
COPY --from=builder /usr/local/bin/helm /usr/local/bin/helm
COPY --from=builder /usr/local/bin/kustomize /usr/local/bin/kustomize
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
# keep uid_entrypoint.sh for backward compatibility
RUN ln -s /usr/local/bin/entrypoint.sh /usr/local/bin/uid_entrypoint.sh
# support for mounting configuration from a configmap
RUN mkdir -p /app/config/ssh && \
@@ -99,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 golang:1.16.5 as argocd-build
FROM docker.io/library/golang:1.16.11 as argocd-build
WORKDIR /go/src/github.com/argoproj/argo-cd
@@ -128,6 +130,7 @@ 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

@@ -266,6 +266,7 @@ 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
@@ -409,12 +410,14 @@ 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) \
@@ -451,6 +454,12 @@ 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

3
OWNERS
View File

@@ -9,6 +9,7 @@ approvers:
- jessesuen
- jgwest
- mayzhang2000
- rbreeze
reviewers:
- dthomson25
@@ -18,3 +19,5 @@ 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.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}"
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.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_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}"
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,6 +45,8 @@ 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)
@@ -69,3 +71,4 @@ 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.1 (2020-06-29)**
Version: **v1.2 (2020-08-07)**
## Preface
@@ -56,13 +56,11 @@ 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 SA 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 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).
Please report vulnerabilities by e-mail to all of the following people:
Please report vulnerabilities by e-mail to the following address:
* jfischer@redhat.com
* Jesse_Suen@intuit.com
* Alexander_Matyushentsev@intuit.com
* Edward_Lee@intuit.com
* cncf-argo-security@lists.cncf.io

View File

@@ -9,6 +9,7 @@ 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/)
@@ -22,15 +23,17 @@ 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](https://www.ca-cib.com)
1. [Crédit Agricole CIB](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)
@@ -48,6 +51,7 @@ 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/)
@@ -58,12 +62,14 @@ 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/)
@@ -74,9 +80,11 @@ 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/)
@@ -93,6 +101,7 @@ 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/)
@@ -110,9 +119,11 @@ 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/)
@@ -122,10 +133,12 @@ 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/)
@@ -135,6 +148,7 @@ 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
@@ -154,3 +168,13 @@ 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/)

View File

@@ -1 +1 @@
2.1.0
2.2.2

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) && globMatch(r.res, p.res) && globMatch(r.act, p.act) && globMatch(r.obj, p.obj)
m = g(r.sub, p.sub) && globOrRegexMatch(r.res, p.res) && globOrRegexMatch(r.act, p.act) && globOrRegexMatch(r.obj, p.obj)

View File

@@ -753,6 +753,11 @@
"type": "string",
"name": "resourceName",
"in": "query"
},
{
"type": "boolean",
"name": "previous",
"in": "query"
}
],
"responses": {
@@ -932,6 +937,11 @@
"type": "string",
"name": "resourceName",
"in": "query"
},
{
"type": "boolean",
"name": "previous",
"in": "query"
}
],
"responses": {
@@ -2081,6 +2091,37 @@
}
}
},
"/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": [
@@ -2863,6 +2904,12 @@
"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": {
@@ -3605,6 +3652,9 @@
"oidcConfig": {
"$ref": "#/definitions/clusterOIDCConfig"
},
"passwordPattern": {
"type": "string"
},
"plugins": {
"type": "array",
"items": {
@@ -3620,9 +3670,18 @@
"statusBadgeEnabled": {
"type": "boolean"
},
"trackingMethod": {
"type": "string"
},
"uiBannerContent": {
"type": "string"
},
"uiBannerPermanent": {
"type": "boolean"
},
"uiBannerPosition": {
"type": "string"
},
"uiBannerURL": {
"type": "string"
},
@@ -3674,6 +3733,32 @@
}
}
},
"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"
},
@@ -4283,6 +4368,10 @@
"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"
}
@@ -4437,7 +4526,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",
"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",
"properties": {
"apiVersion": {
"type": "string",
@@ -4470,8 +4559,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.",
@@ -4810,6 +4899,10 @@
"$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"
@@ -5106,6 +5199,13 @@
"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"
@@ -5119,6 +5219,13 @@
"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"
@@ -5130,6 +5237,10 @@
"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"
},
@@ -5276,6 +5387,9 @@
"init": {
"$ref": "#/definitions/v1alpha1Command"
},
"lockRepo": {
"type": "boolean"
},
"name": {
"type": "string"
}
@@ -5846,6 +5960,10 @@
"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"
@@ -6534,6 +6652,10 @@
"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,6 +49,7 @@ func NewCommand() *cobra.Command {
glogLevel int
metricsPort int
metricsCacheExpiration time.Duration
metricsAplicationLabels []string
kubectlParallelismLimit int64
cacheSrc func() (*appstatecache.Cache, error)
redisClient *redis.Client
@@ -110,10 +111,14 @@ func NewCommand() *cobra.Command {
errors.CheckError(err)
cache.Cache.SetClient(cacheutil.NewTwoLevelClient(cache.Cache.GetClient(), 10*time.Minute))
settingsMgr := settings.NewSettingsManager(ctx, kubeClient, namespace)
var appController *controller.ApplicationController
settingsMgr := settings.NewSettingsManager(ctx, kubeClient, namespace, settings.WithRepoOrClusterChangedHandler(func() {
appController.InvalidateProjectsCache()
}))
kubectl := kubeutil.NewKubectl()
clusterFilter := getClusterFilter()
appController, err := controller.NewApplicationController(
appController, err = controller.NewApplicationController(
namespace,
settingsMgr,
kubeClient,
@@ -125,6 +130,7 @@ func NewCommand() *cobra.Command {
time.Duration(selfHealTimeoutSeconds)*time.Second,
metricsPort,
metricsCacheExpiration,
metricsAplicationLabels,
kubectlParallelismLimit,
clusterFilter)
errors.CheckError(err)
@@ -158,6 +164,7 @@ 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

@@ -0,0 +1,58 @@
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

@@ -63,6 +63,7 @@ func NewCommand() *cobra.Command {
frameOptions string
repoServerPlaintext bool
repoServerStrictTLS bool
staticAssetsDir string
)
var command = &cobra.Command{
Use: cliName,
@@ -139,6 +140,7 @@ func NewCommand() *cobra.Command {
Cache: cache,
XFrameOptions: frameOptions,
RedisClient: redisClient,
StaticAssetsDir: staticAssetsDir,
}
stats.RegisterStackDumper()
@@ -157,9 +159,7 @@ func NewCommand() *cobra.Command {
clientConfig = cli.AddKubectlFlagsToCmd(command)
command.Flags().BoolVar(&insecure, "insecure", env.ParseBoolFromEnv("ARGOCD_SERVER_INSECURE", false), "Run server without TLS")
var staticAssetsDir string
command.Flags().StringVar(&staticAssetsDir, "staticassets", "", "Static assets directory path")
_ = command.Flags().MarkDeprecated("staticassets", "The --staticassets flag is not longer supported. Static assets are embedded into binary.")
command.Flags().StringVar(&staticAssetsDir, "staticassets", env.StringFromEnv("ARGOCD_SERVER_STATIC_ASSETS", "/shared/app"), "Directory path that contains additional static assets")
command.Flags().StringVar(&baseHRef, "basehref", env.StringFromEnv("ARGOCD_SERVER_BASEHREF", "/"), "Value for base href in index.html. Used if Argo CD is running behind reverse proxy under subpath different from /")
command.Flags().StringVar(&rootPath, "rootpath", env.StringFromEnv("ARGOCD_SERVER_ROOTPATH", ""), "Used if Argo CD is running behind reverse proxy under subpath different from /")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")

View File

@@ -54,7 +54,19 @@ func NewAccountUpdatePasswordCommand(clientOpts *argocdclient.ClientOptions) *co
)
var command = &cobra.Command{
Use: "update-password",
Short: "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
`,
Run: func(c *cobra.Command, args []string) {
if len(args) != 0 {
c.HelpFunc()(c, args)
@@ -67,16 +79,20 @@ func NewAccountUpdatePasswordCommand(clientOpts *argocdclient.ClientOptions) *co
userInfo := getCurrentAccount(acdClient)
if userInfo.Iss == sessionutil.SessionManagerClaimsIssuer && currentPassword == "" {
fmt.Print("*** Enter current password: ")
fmt.Printf("*** Enter password of currently logged in user (%s): ", userInfo.Username)
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()
newPassword, err = cli.ReadAndConfirmPassword(account)
errors.CheckError(err)
}
@@ -111,7 +127,7 @@ func NewAccountUpdatePasswordCommand(clientOpts *argocdclient.ClientOptions) *co
},
}
command.Flags().StringVar(&currentPassword, "current-password", "", "current password you wish to change")
command.Flags().StringVar(&currentPassword, "current-password", "", "password of the currently logged on user")
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,6 +10,8 @@ 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"
@@ -88,9 +90,12 @@ 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) {
app, err := cmdutil.ConstructApp(fileURL, appName, labels, annotations, args, appOpts, c.Flags())
apps, err := cmdutil.ConstructApps(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)
@@ -329,11 +334,11 @@ func reconcileApplications(
settingsMgr := settings.NewSettingsManager(context.Background(), kubeClientset, namespace)
argoDB := db.NewDB(namespace, settingsMgr, kubeClientset)
appInformerFactory := appinformers.NewFilteredSharedInformerFactory(
appInformerFactory := appinformers.NewSharedInformerFactoryWithOptions(
appClientset,
1*time.Hour,
namespace,
func(options *v1.ListOptions) {},
appinformers.WithNamespace(namespace),
appinformers.WithTweakListOptions(func(options *v1.ListOptions) {}),
)
appInformer := appInformerFactory.Argoproj().V1alpha1().Applications().Informer()
@@ -350,7 +355,7 @@ func reconcileApplications(
return true
}, func(r *http.Request) error {
return nil
})
}, []string{})
if err != nil {
return nil, err
@@ -366,7 +371,7 @@ func reconcileApplications(
)
appStateManager := controller.NewAppStateManager(
argoDB, appClientset, repoServerClient, namespace, kubeutil.NewKubectl(), settingsMgr, stateCache, projInformer, server, cache, time.Second)
argoDB, appClientset, repoServerClient, namespace, kubeutil.NewKubectl(), settingsMgr, stateCache, projInformer, server, cache, time.Second, argo.NewResourceTracking())
appsList, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(context.Background(), v1.ListOptions{LabelSelector: selector})
if err != nil {
@@ -408,5 +413,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)
return cache.NewLiveStateCache(argoDB, appInformer, settingsMgr, kubeutil.NewKubectl(), server, func(managedByApp map[string]bool, ref apiv1.ObjectReference) {}, nil, argo.NewResourceTracking())
}

View File

@@ -10,7 +10,7 @@ import (
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/ghodss/yaml"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
apierr "k8s.io/apimachinery/pkg/api/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -88,7 +88,11 @@ func NewExportCommand() *cobra.Command {
}
applicationSets, err := acdClients.applicationSets.List(context.Background(), v1.ListOptions{})
if err != nil && !apierr.IsNotFound(err) {
errors.CheckError(err)
if apierr.IsForbidden(err) {
log.Warn(err)
} else {
errors.CheckError(err)
}
}
if applicationSets != nil {
for _, appSet := range applicationSets.Items {
@@ -176,6 +180,17 @@ func NewImportCommand() *cobra.Command {
for _, proj := range projects.Items {
pruneObjects[kube.ResourceKey{Group: "argoproj.io", Kind: "AppProject", Name: proj.GetName()}] = proj
}
applicationSets, err := acdClients.applicationSets.List(context.Background(), v1.ListOptions{})
if apierr.IsForbidden(err) || apierr.IsNotFound(err) {
log.Warnf("argoproj.io/ApplicationSet: %v\n", err)
} else {
errors.CheckError(err)
}
if applicationSets != nil {
for _, appSet := range applicationSets.Items {
pruneObjects[kube.ResourceKey{Group: "argoproj.io", Kind: "ApplicationSet", Name: appSet.GetName()}] = appSet
}
}
// Create or replace existing object
backupObjects, err := kube.SplitYAML(input)
@@ -199,22 +214,39 @@ func NewImportCommand() *cobra.Command {
dynClient = acdClients.applicationSets
}
if !exists {
isForbidden := false
if !dryRun {
_, err = dynClient.Create(context.Background(), bakObj, v1.CreateOptions{})
errors.CheckError(err)
if apierr.IsForbidden(err) || apierr.IsNotFound(err) {
isForbidden = true
log.Warnf("%s/%s %s: %v", gvk.Group, gvk.Kind, bakObj.GetName(), err)
} else {
errors.CheckError(err)
}
}
fmt.Printf("%s/%s %s created%s\n", gvk.Group, gvk.Kind, bakObj.GetName(), dryRunMsg)
if !isForbidden {
fmt.Printf("%s/%s %s created%s\n", gvk.Group, gvk.Kind, bakObj.GetName(), dryRunMsg)
}
} else if specsEqual(*bakObj, liveObj) {
if verbose {
fmt.Printf("%s/%s %s unchanged%s\n", gvk.Group, gvk.Kind, bakObj.GetName(), dryRunMsg)
}
} else {
isForbidden := false
if !dryRun {
newLive := updateLive(bakObj, &liveObj)
_, err = dynClient.Update(context.Background(), newLive, v1.UpdateOptions{})
errors.CheckError(err)
if apierr.IsForbidden(err) || apierr.IsNotFound(err) {
isForbidden = true
log.Warnf("%s/%s %s: %v", gvk.Group, gvk.Kind, bakObj.GetName(), err)
} else {
errors.CheckError(err)
}
}
if !isForbidden {
fmt.Printf("%s/%s %s updated%s\n", gvk.Group, gvk.Kind, bakObj.GetName(), dryRunMsg)
}
fmt.Printf("%s/%s %s updated%s\n", gvk.Group, gvk.Kind, bakObj.GetName(), dryRunMsg)
}
}
@@ -239,16 +271,24 @@ func NewImportCommand() *cobra.Command {
}
}
}
case "ApplicationSet":
dynClient = acdClients.applicationSets
default:
logrus.Fatalf("Unexpected kind '%s' in prune list", key.Kind)
log.Fatalf("Unexpected kind '%s' in prune list", key.Kind)
}
isForbidden := false
if !dryRun {
err = dynClient.Delete(context.Background(), key.Name, v1.DeleteOptions{})
if err != nil && !apierr.IsNotFound(err) {
if apierr.IsForbidden(err) || apierr.IsNotFound(err) {
isForbidden = true
log.Warnf("%s/%s %s: %v\n", key.Group, key.Kind, key.Name, err)
} else {
errors.CheckError(err)
}
}
fmt.Printf("%s/%s %s pruned%s\n", key.Group, key.Kind, key.Name, dryRunMsg)
if !isForbidden {
fmt.Printf("%s/%s %s pruned%s\n", key.Group, key.Kind, key.Name, dryRunMsg)
}
} else {
fmt.Printf("%s/%s %s needs pruning\n", key.Group, key.Kind, key.Name)
}
@@ -304,6 +344,8 @@ func updateLive(bak, live *unstructured.Unstructured) *unstructured.Unstructured
if _, ok := bak.Object["status"]; ok {
newLive.Object["status"] = bak.Object["status"]
}
case "ApplicationSet":
newLive.Object["spec"] = bak.Object["spec"]
}
return newLive
}

View File

@@ -35,6 +35,7 @@ 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 {
@@ -508,6 +509,8 @@ 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",
@@ -561,7 +564,13 @@ func NewGenClusterConfigCommand(pathOpts *clientcmd.PathOptions) *cobra.Command
if clusterOpts.Name != "" {
contextName = clusterOpts.Name
}
clst := cmdutil.NewCluster(contextName, clusterOpts.Namespaces, clusterOpts.ClusterResources, conf, bearerToken, awsAuthConf, execProviderConf)
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)
if clusterOpts.InCluster {
clst.Server = argoappv1.KubernetesInternalAPIServerAddr
}
@@ -590,6 +599,8 @@ 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
}

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 {
if len(override.IgnoreDifferences.JSONPointers) == 0 && len(override.IgnoreDifferences.JQPathExpressions) == 0 {
_, _ = fmt.Printf("Ignore differences are not configured for '%s/%s'\n", gvk.Group, gvk.Kind)
return
}

View File

@@ -14,6 +14,8 @@ 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"
@@ -48,7 +50,6 @@ 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"
)
@@ -92,6 +93,7 @@ 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))
@@ -133,24 +135,27 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
Run: func(c *cobra.Command, args []string) {
argocdClient := argocdclient.NewClientOrDie(clientOpts)
app, err := cmdutil.ConstructApp(fileURL, appName, labels, annotations, args, appOpts, c.Flags())
apps, err := cmdutil.ConstructApps(fileURL, appName, labels, annotations, args, appOpts, c.Flags())
errors.CheckError(err)
if app.Name == "" {
c.HelpFunc()(c, args)
os.Exit(1)
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)
}
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)")
@@ -666,6 +671,10 @@ 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 {
@@ -732,8 +741,8 @@ func liveObjects(resources []*argoappv1.ResourceDiff) ([]*unstructured.Unstructu
}
func getLocalObjects(app *argoappv1.Application, local, localRepoRoot, appLabelKey, kubeVersion string, kustomizeOptions *argoappv1.KustomizeOptions,
configManagementPlugins []*argoappv1.ConfigManagementPlugin) []*unstructured.Unstructured {
manifestStrings := getLocalObjectsString(app, local, localRepoRoot, appLabelKey, kubeVersion, kustomizeOptions, configManagementPlugins)
configManagementPlugins []*argoappv1.ConfigManagementPlugin, trackingMethod string) []*unstructured.Unstructured {
manifestStrings := getLocalObjectsString(app, local, localRepoRoot, appLabelKey, kubeVersion, kustomizeOptions, configManagementPlugins, trackingMethod)
objs := make([]*unstructured.Unstructured, len(manifestStrings))
for i := range manifestStrings {
obj := unstructured.Unstructured{}
@@ -745,7 +754,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) []string {
configManagementPlugins []*argoappv1.ConfigManagementPlugin, trackingMethod string) []string {
res, err := repository.GenerateManifests(local, localRepoRoot, app.Spec.Source.TargetRevision, &repoapiclient.ManifestRequest{
Repo: &argoappv1.Repository{Repo: app.Spec.Source.RepoURL},
@@ -756,6 +765,7 @@ func getLocalObjectsString(app *argoappv1.Application, local, localRepoRoot, app
KustomizeOptions: kustomizeOptions,
KubeVersion: kubeVersion,
Plugins: configManagementPlugins,
TrackingMethod: trackingMethod,
}, true)
errors.CheckError(err)
@@ -841,7 +851,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), liveObjs, app.Spec.Destination.Namespace)
localObjs := groupObjsByKey(getLocalObjects(app, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod), liveObjs, app.Spec.Destination.Namespace)
items = groupObjsForDiff(resources, localObjs, items, argoSettings, appName)
} else if revision != "" {
var unstructureds []*unstructured.Unstructured
@@ -923,6 +933,7 @@ 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)
@@ -936,7 +947,7 @@ func groupObjsForDiff(resources *application.ManagedResourcesResponse, objs map[
}
if local, ok := objs[key]; ok || live != nil {
if local != nil && !kube.IsCRD(local) {
err = argokube.SetAppInstanceLabel(local, argoSettings.AppLabelKey, appName)
err = resourceTracking.SetAppInstance(local, argoSettings.AppLabelKey, appName, "", argoappv1.TrackingMethod(argoSettings.GetTrackingMethod()))
errors.CheckError(err)
}
@@ -1269,6 +1280,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
timeout uint
strategy string
force bool
replace bool
async bool
retryLimit int64
retryBackoffDuration time.Duration
@@ -1376,18 +1388,35 @@ 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)
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
}
syncReq := applicationpkg.ApplicationSyncRequest{
Name: &appName,
DryRun: dryRun,
Revision: revision,
Resources: selectedResources,
Prune: prune,
Manifests: localObjsStrings,
Infos: getInfos(infos),
Name: &appName,
DryRun: dryRun,
Revision: revision,
Resources: selectedResources,
Prune: prune,
Manifests: localObjsStrings,
Infos: getInfos(infos),
SyncOptions: syncOptionsFactory(),
}
switch strategy {
case "apply":
syncReq.Strategy = &argoappv1.SyncStrategy{Apply: &argoappv1.SyncStrategyApply{}}
@@ -1444,6 +1473,7 @@ 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")
@@ -2202,3 +2232,59 @@ 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,13 +4,18 @@ 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"
@@ -18,7 +23,6 @@ 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"
@@ -60,6 +64,8 @@ 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,18 +128,27 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
}
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)
clst := cmdutil.NewCluster(contextName, clusterOpts.Namespaces, clusterOpts.ClusterResources, conf, managerBearerToken, awsAuthConf, execProviderConf, labelsMap, annotationsMap)
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,
@@ -148,6 +163,8 @@ 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
}
@@ -158,9 +175,10 @@ func NewClusterGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
output string
)
var command = &cobra.Command{
Use: "get SERVER",
Short: "Get cluster information",
Example: `argocd cluster get https://12.34.567.89`,
Use: "get SERVER/NAME",
Short: "Get cluster information",
Example: `argocd cluster get https://12.34.567.89
argocd cluster get in-cluster`,
Run: func(c *cobra.Command, args []string) {
if len(args) == 0 {
c.HelpFunc()(c, args)
@@ -169,8 +187,8 @@ func NewClusterGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
conn, clusterIf := argocdclient.NewClientOrDie(clientOpts).NewClusterClientOrDie()
defer io.Close(conn)
clusters := make([]argoappv1.Cluster, 0)
for _, clusterName := range args {
clst, err := clusterIf.Get(context.Background(), &clusterpkg.ClusterQuery{Server: clusterName})
for _, clusterSelector := range args {
clst, err := clusterIf.Get(context.Background(), getQueryBySelector(clusterSelector))
errors.CheckError(err)
clusters = append(clusters, *clst)
}
@@ -257,17 +275,29 @@ 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\n")
_, _ = fmt.Fprintf(w, "SERVER\tNAME\tVERSION\tSTATUS\tMESSAGE\tPROJECT\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\n", server, c.Name, c.ServerVersion, c.ConnectionState.Status, c.ConnectionState.Message)
_, _ = 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)
}
_ = 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,8 +6,24 @@ 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,6 +18,7 @@ import (
type forwardCacheClient struct {
namespace string
context string
init sync.Once
client cache.CacheClient
err error
@@ -25,7 +26,9 @@ type forwardCacheClient struct {
func (c *forwardCacheClient) doLazy(action func(client cache.CacheClient) error) error {
c.init.Do(func() {
overrides := clientcmd.ConfigOverrides{}
overrides := clientcmd.ConfigOverrides{
CurrentContext: c.context,
}
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 {
@@ -74,6 +77,7 @@ func (c *forwardCacheClient) NotifyUpdated(key string) error {
type forwardRepoClientset struct {
namespace string
context string
init sync.Once
repoClientset repoapiclient.Clientset
err error
@@ -81,7 +85,9 @@ type forwardRepoClientset struct {
func (c *forwardRepoClientset) NewRepoServerClient() (io.Closer, repoapiclient.RepoServerServiceClient, error) {
c.init.Do(func() {
overrides := clientcmd.ConfigOverrides{}
overrides := clientcmd.ConfigOverrides{
CurrentContext: c.context,
}
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,6 +27,8 @@ 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 {
@@ -43,21 +45,27 @@ func testAPI(clientOpts *argoapi.ClientOptions) error {
return err
}
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)
func retrieveContextIfChanged(contextFlag *flag.Flag) string {
if contextFlag != nil && contextFlag.Changed {
return contextFlag.Value.String()
}
return ""
}
// 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())
clientConfig := addKubectlFlagsToCmd(cmd)
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)
})
cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
startInProcessAPI := clientOpts.Core
if !startInProcessAPI {
@@ -109,12 +117,14 @@ 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}), time.Hour)
appstateCache := appstatecache.NewCache(cacheutil.NewCache(&forwardCacheClient{namespace: namespace, context: context}), time.Hour)
srv := server.NewServer(ctx, server.ArgoCDServerOpts{
EnableGZip: false,
Namespace: namespace,
@@ -126,7 +136,7 @@ func InitCommand(cmd *cobra.Command, clientOpts *argoapi.ClientOptions, port *in
KubeClientset: kubeClientset,
Insecure: true,
ListenHost: "localhost",
RepoClientset: &forwardRepoClientset{namespace: namespace},
RepoClientset: &forwardRepoClientset{namespace: namespace, context: context},
})
go srv.Run(ctx, *port, 0)

View File

@@ -0,0 +1,80 @@
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,6 +90,8 @@ 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,8 +219,17 @@ 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 NAMESPACE",
Use: "add-destination PROJECT SERVER/NAME NAMESPACE",
Short: "Add project destination",
Run: func(c *cobra.Command, args []string) {
if len(args) != 3 {
@@ -228,8 +237,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)
@@ -237,15 +246,18 @@ func NewProjectAddDestinationCommand(clientOpts *argocdclient.ClientOptions) *co
errors.CheckError(err)
for _, dest := range proj.Spec.Destinations {
if dest.Namespace == namespace && dest.Server == server {
dstServerExist := destination.Server != "" && dest.Server == destination.Server
dstNameExist := destination.Name != "" && dest.Name == destination.Name
if dest.Namespace == namespace && (dstServerExist || dstNameExist) {
log.Fatal("Specified destination is already defined in project")
}
}
proj.Spec.Destinations = append(proj.Spec.Destinations, v1alpha1.ApplicationDestination{Server: server, Namespace: namespace})
proj.Spec.Destinations = append(proj.Spec.Destinations, destination)
_, 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,6 +116,7 @@ func NewProjectWindowsAddWindowCommand(clientOpts *argocdclient.ClientOptions) *
namespaces []string
clusters []string
manualSync bool
timeZone string
)
var command = &cobra.Command{
Use: "add PROJECT",
@@ -132,7 +133,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)
err = proj.Spec.AddWindow(kind, schedule, duration, applications, namespaces, clusters, manualSync, timeZone)
errors.CheckError(err)
_, err = projIf.Update(context.Background(), &projectpkg.ProjectUpdateRequest{Project: proj})
@@ -146,6 +147,7 @@ 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
}
@@ -189,6 +191,7 @@ func NewProjectWindowsUpdateCommand(clientOpts *argocdclient.ClientOptions) *cob
applications []string
namespaces []string
clusters []string
timeZone string
)
var command = &cobra.Command{
Use: "update PROJECT ID",
@@ -212,7 +215,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)
err := window.Update(schedule, duration, applications, namespaces, clusters, timeZone)
if err != nil {
errors.CheckError(err)
}
@@ -228,6 +231,7 @@ 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,13 +43,15 @@ 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,
GRPCWeb: globalClientOpts.GRPCWeb,
GRPCWebRootPath: globalClientOpts.GRPCWebRootPath,
PlainText: configCtx.Server.PlainText,
Headers: globalClientOpts.Headers,
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,
}
acdClient := argocdclient.NewClientOrDie(&clientOpts)
claims, err := configCtx.User.Claims()

View File

@@ -182,6 +182,7 @@ 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)
@@ -226,7 +227,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\n")
_, _ = fmt.Fprintf(w, "TYPE\tNAME\tREPO\tINSECURE\tOCI\tLFS\tCREDS\tSTATUS\tMESSAGE\tPROJECT\n")
for _, r := range repos {
var hasCreds string
if !r.HasCredentials() {
@@ -238,7 +239,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\n", r.Type, r.Name, r.Repo, r.IsInsecure(), r.EnableOCI, r.EnableLFS, hasCreds, r.ConnectionState.Status, r.ConnectionState.Message)
_, _ = 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)
}
_ = w.Flush()
}

View File

@@ -8,6 +8,7 @@ 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"
@@ -34,6 +35,8 @@ 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,6 +9,8 @@ import (
"strings"
"time"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@@ -40,6 +42,7 @@ type AppOptions struct {
helmSetStrings []string
helmSetFiles []string
helmVersion string
helmPassCredentials bool
project string
syncPolicy string
syncOptions []string
@@ -86,6 +89,7 @@ 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)")
@@ -122,6 +126,9 @@ 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 {
@@ -156,6 +163,8 @@ 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":
@@ -372,13 +381,14 @@ func setPluginOptEnvs(src *argoappv1.ApplicationSource, envs []string) {
}
type helmOpts struct {
valueFiles []string
values string
releaseName string
version string
helmSets []string
helmSetStrings []string
helmSetFiles []string
valueFiles []string
values string
releaseName string
version string
helmSets []string
helmSetStrings []string
helmSetFiles []string
passCredentials bool
}
func setHelmOpt(src *argoappv1.ApplicationSource, opts helmOpts) {
@@ -397,6 +407,9 @@ 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 {
@@ -518,39 +531,99 @@ func SetParameterOverrides(app *argoappv1.Application, parameters []string) {
}
}
func readAppFromStdin(app *argoappv1.Application) error {
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 {
reader := bufio.NewReader(os.Stdin)
err := config.UnmarshalReader(reader, &app)
data, err := ioutil.ReadAll(reader)
if err != nil {
return err
}
err = readApps(data, apps)
if err != nil {
return fmt.Errorf("unable to read manifest from stdin: %v", err)
}
return nil
}
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)
func readAppsFromURI(fileURL string, apps *[]*argoappv1.Application) error {
readFilePayload := func() ([]byte, error) {
parsedURL, err := url.ParseRequestURI(fileURL)
if err != nil || !(parsedURL.Scheme == "http" || parsedURL.Scheme == "https") {
return ioutil.ReadFile(fileURL)
}
return config.ReadRemoteFile(fileURL)
}
return err
yml, err := readFilePayload()
if err != nil {
return err
}
return readApps(yml, apps)
}
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
}
} else if fileURL != "" {
// read uri
err := readAppFromURI(fileURL, &app)
if err != nil {
return nil, err
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])
}
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)
}
@@ -561,32 +634,20 @@ func ConstructApp(fileURL, appName string, labels, annotations, args []string, a
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)
} 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)
SetParameterOverrides(app, appOpts.Parameters)
mergeLabels(app, labels)
setAnnotations(app, annotations)
}
return &app, nil
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)
}
func mergeLabels(app *argoappv1.Application, labels []string) {

View File

@@ -1,12 +1,16 @@
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) {
@@ -45,6 +49,11 @@ 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) {
@@ -190,3 +199,106 @@ 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) *argoappv1.Cluster {
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 {
tlsClientConfig := argoappv1.TLSClientConfig{
Insecure: conf.TLSClientConfig.Insecure,
ServerName: conf.TLSClientConfig.ServerName,
@@ -89,6 +89,8 @@ 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,
@@ -111,6 +113,7 @@ type ClusterOptions struct {
Namespaces []string
ClusterResources bool
Name string
Project string
Shard int64
ExecProviderCommand string
ExecProviderArgs []string
@@ -126,6 +129,7 @@ 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,6 +11,8 @@ 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,
@@ -23,11 +25,13 @@ func Test_newCluster(t *testing.T) {
},
"test-bearer-token",
&v1alpha1.AWSAuthConfig{},
&v1alpha1.ExecProviderConfig{})
&v1alpha1.ExecProviderConfig{}, labels, annotations)
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{
@@ -41,11 +45,13 @@ func Test_newCluster(t *testing.T) {
},
"test-bearer-token",
&v1alpha1.AWSAuthConfig{},
&v1alpha1.ExecProviderConfig{})
&v1alpha1.ExecProviderConfig{}, labels, nil)
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{
@@ -57,7 +63,9 @@ func Test_newCluster(t *testing.T) {
},
"test-bearer-token",
&v1alpha1.AWSAuthConfig{},
&v1alpha1.ExecProviderConfig{})
&v1alpha1.ExecProviderConfig{}, nil, nil)
assert.Equal(t, "test-bearer-token", clusterWithBearerToken.Config.BearerToken)
assert.Nil(t, clusterWithBearerToken.Labels)
assert.Nil(t, clusterWithBearerToken.Annotations)
}

View File

@@ -27,6 +27,7 @@ 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

@@ -0,0 +1,66 @@
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

@@ -0,0 +1,91 @@
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
}

137
cmpserver/plugin/plugin.go Normal file
View File

@@ -0,0 +1,137 @@
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

@@ -0,0 +1,61 @@
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

@@ -0,0 +1,65 @@
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

@@ -0,0 +1,15 @@
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

View File

@@ -0,0 +1,16 @@
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

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

View File

@@ -0,0 +1,16 @@
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

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

107
cmpserver/server.go Normal file
View File

@@ -0,0 +1,107 @@
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,6 +54,12 @@ 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
@@ -70,6 +76,9 @@ const (
ChangePasswordSSOTokenMaxAge = time.Minute * 5
// GithubAppCredsExpirationDuration is the default time used to cache the GitHub app credentials
GithubAppCredsExpirationDuration = time.Minute * 60
// PasswordPatten is the default password patten
PasswordPatten = `^.{8,32}$`
)
// Dex related constants
@@ -110,6 +119,9 @@ 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"
@@ -141,6 +153,12 @@ 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
@@ -169,6 +187,10 @@ 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 (
@@ -181,6 +203,12 @@ const (
CacheVersion = "1.8.3"
)
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 == "" {
@@ -189,3 +217,12 @@ 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

@@ -112,6 +112,7 @@ type ApplicationController struct {
metricsServer *metrics.MetricsServer
kubectlSemaphore *semaphore.Weighted
clusterFilter func(cluster *appv1.Cluster) bool
projByNameCache sync.Map
}
// NewApplicationController creates new instance of ApplicationController.
@@ -127,6 +128,7 @@ func NewApplicationController(
selfHealTimeout time.Duration,
metricsPort int,
metricsCacheExpiration time.Duration,
metricsApplicationLabels []string,
kubectlParallelismLimit int64,
clusterFilter func(cluster *appv1.Cluster) bool,
) (*ApplicationController, error) {
@@ -151,6 +153,7 @@ func NewApplicationController(
settingsMgr: settingsMgr,
selfHealTimeout: selfHealTimeout,
clusterFilter: clusterFilter,
projByNameCache: sync.Map{},
}
if kubectlParallelismLimit > 0 {
ctrl.kubectlSemaphore = semaphore.NewWeighted(kubectlParallelismLimit)
@@ -163,16 +166,26 @@ 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())
}
}
},
})
@@ -180,7 +193,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
}
@@ -190,8 +203,8 @@ func NewApplicationController(
return nil, err
}
}
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)
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())
ctrl.appInformer = appInformer
ctrl.appLister = appLister
ctrl.projInformer = projInformer
@@ -201,6 +214,19 @@ 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
}
@@ -230,8 +256,35 @@ 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) {
return argo.GetAppProject(&app.Spec, applisters.NewAppProjectLister(ctrl.projInformer.GetIndexer()), ctrl.namespace, ctrl.settingsMgr)
projCache, _ := ctrl.projByNameCache.LoadOrStore(app.Spec.GetProject(), ctrl.newAppProjCache(app.Spec.GetProject()))
return projCache.(*appProjCache).GetAppProject(context.TODO())
}
func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]bool, ref v1.ObjectReference) {
@@ -244,12 +297,8 @@ 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] = false
}
managedByApp[app.Name] = true
}
}
}
@@ -276,17 +325,21 @@ 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, err
return nil, fmt.Errorf("error getting managed resources: %s", err)
}
tree, err := ctrl.getResourceTree(a, managedResources)
if err != nil {
return nil, err
return nil, fmt.Errorf("error getting resource tree: %s", err)
}
err = ctrl.cache.SetAppResourcesTree(a.Name, tree)
if err != nil {
return nil, err
return nil, fmt.Errorf("error setting app resource tree: %s", err)
}
return tree, ctrl.cache.SetAppManagedResources(a.Name, managedResources)
err = ctrl.cache.SetAppManagedResources(a.Name, managedResources)
if err != nil {
return nil, fmt.Errorf("error setting app managed resources: %s", err)
}
return tree, nil
}
// returns true of given resources exist in the namespace by default and not managed by the user
@@ -316,7 +369,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 := argo.GetAppProject(&a.Spec, applisters.NewAppProjectLister(ctrl.projInformer.GetIndexer()), ctrl.namespace, ctrl.settingsMgr)
proj, err := ctrl.getAppProj(a)
if err != nil {
return nil, err
}
@@ -510,18 +563,18 @@ func (ctrl *ApplicationController) managedResources(comparisonResult *comparison
var err error
target, live, err = diff.HideSecretData(res.Target, res.Live)
if err != nil {
return nil, err
return nil, fmt.Errorf("error hiding secret data: %s", err)
}
compareOptions, err := ctrl.settingsMgr.GetResourceCompareOptions()
if err != nil {
return nil, err
return nil, fmt.Errorf("error getting resource compare options: %s", 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, err
return nil, fmt.Errorf("error applying diff: %s", err)
}
resDiff = *resDiffPtr
}
@@ -529,7 +582,7 @@ func (ctrl *ApplicationController) managedResources(comparisonResult *comparison
if live != nil {
data, err := json.Marshal(live)
if err != nil {
return nil, err
return nil, fmt.Errorf("error marshaling live json: %s", err)
}
item.LiveState = string(data)
} else {
@@ -539,7 +592,7 @@ func (ctrl *ApplicationController) managedResources(comparisonResult *comparison
if target != nil {
data, err := json.Marshal(target)
if err != nil {
return nil, err
return nil, fmt.Errorf("error marshaling target json: %s", err)
}
item.TargetState = string(data)
} else {
@@ -665,6 +718,18 @@ func (ctrl *ApplicationController) processAppOperationQueueItem() (processNext b
}
app := origApp.DeepCopy()
if app.Operation != nil {
// If we get here, we are about process an operation but we cannot rely on informer since it might has stale data.
// So always retrieve the latest version to ensure it is not stale to avoid unnecessary syncing.
// We cannot rely on informer since applications might be updated by both application controller and api server.
freshApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).Get(context.Background(), app.ObjectMeta.Name, metav1.GetOptions{})
if err != nil {
log.Errorf("Failed to retrieve latest application state: %v", err)
return
}
app = freshApp
}
if app.Operation != nil {
ctrl.processRequestedAppOperation(app)
} else if app.DeletionTimestamp != nil && app.CascadedDeletion() {
@@ -789,7 +854,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) {
if !proj.IsLiveResourcePermitted(v, app.Spec.Destination.Server, app.Spec.Destination.Name) {
delete(objsMap, k)
}
}
@@ -1037,7 +1102,7 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
}
ctrl.setOperationState(app, state)
if state.Phase.Completed() && !app.Operation.Sync.DryRun {
if state.Phase.Completed() && (app.Operation.Sync != nil && !app.Operation.Sync.DryRun) {
// if we just completed an operation, force a refresh so that UI will report up-to-date
// sync/health information
if _, err := cache.MetaNamespaceKeyFunc(app); err == nil {
@@ -1085,7 +1150,7 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
}
appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace)
patchedApp, err := appClient.Patch(context.Background(), app.Name, types.MergePatchType, patchJSON, metav1.PatchOptions{})
_, err = appClient.Patch(context.Background(), app.Name, types.MergePatchType, patchJSON, metav1.PatchOptions{})
if err != nil {
// Stop retrying updating deleted application
if apierr.IsNotFound(err) {
@@ -1115,10 +1180,6 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
ctrl.auditLogger.LogAppEvent(app, eventInfo, strings.Join(messages, " "))
ctrl.metricsServer.IncSync(app, state)
}
// write back to informer in order to avoid stale cache
if err := ctrl.appInformer.GetStore().Update(patchedApp); err != nil {
log.Warnf("Fails to update informer: %v", err)
}
return nil
})
}
@@ -1586,7 +1647,7 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar
return nil, nil
}
proj, err := ctrl.getAppProj(app)
proj, err := applisters.NewAppProjectLister(ctrl.projInformer.GetIndexer()).AppProjects(ctrl.namespace).Get(app.Spec.GetProject())
if err != nil {
return nil, nil
}

View File

@@ -106,6 +106,7 @@ func newFakeController(data *fakeData) *ApplicationController {
time.Minute,
common.DefaultPortArgoCDMetrics,
data.metricsCacheExpiration,
[]string{},
0,
nil,
)
@@ -784,11 +785,11 @@ func TestHandleOrphanedResourceUpdated(t *testing.T) {
isRequested, level := ctrl.isRefreshRequested(app1.Name)
assert.True(t, isRequested)
assert.Equal(t, ComparisonWithNothing, level)
assert.Equal(t, CompareWithRecent, level)
isRequested, level = ctrl.isRefreshRequested(app2.Name)
assert.True(t, isRequested)
assert.Equal(t, ComparisonWithNothing, level)
assert.Equal(t, CompareWithRecent, level)
}
func TestGetResourceTree_HasOrphanedResources(t *testing.T) {
@@ -1083,12 +1084,10 @@ func TestProcessRequestedAppOperation_FailedNoRetries(t *testing.T) {
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]interface{}{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
patchedApp := &v1alpha1.Application{}
if patchAction, ok := action.(kubetesting.PatchAction); ok {
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
}
return true, patchedApp, nil
return true, nil, nil
})
ctrl.processRequestedAppOperation(app)
@@ -1110,12 +1109,10 @@ func TestProcessRequestedAppOperation_InvalidDestination(t *testing.T) {
fakeAppCs.Lock()
defer fakeAppCs.Unlock()
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
patchedApp := &v1alpha1.Application{}
if patchAction, ok := action.(kubetesting.PatchAction); ok {
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
}
return true, patchedApp, nil
return true, nil, nil
})
}()
@@ -1138,12 +1135,10 @@ func TestProcessRequestedAppOperation_FailedHasRetries(t *testing.T) {
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]interface{}{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
patchedApp := &v1alpha1.Application{}
if patchAction, ok := action.(kubetesting.PatchAction); ok {
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
}
return true, patchedApp, nil
return true, nil, nil
})
ctrl.processRequestedAppOperation(app)
@@ -1183,12 +1178,10 @@ func TestProcessRequestedAppOperation_RunningPreviouslyFailed(t *testing.T) {
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]interface{}{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
patchedApp := &v1alpha1.Application{}
if patchAction, ok := action.(kubetesting.PatchAction); ok {
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
}
return true, patchedApp, nil
return true, nil, nil
})
ctrl.processRequestedAppOperation(app)
@@ -1218,12 +1211,10 @@ func TestProcessRequestedAppOperation_HasRetriesTerminated(t *testing.T) {
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]interface{}{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
patchedApp := &v1alpha1.Application{}
if patchAction, ok := action.(kubetesting.PatchAction); ok {
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
}
return true, patchedApp, nil
return true, nil, nil
})
ctrl.processRequestedAppOperation(app)

View File

@@ -3,7 +3,7 @@ package cache
import (
"context"
"fmt"
"os"
"math"
"reflect"
"sync"
"time"
@@ -24,6 +24,7 @@ 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"
@@ -32,25 +33,47 @@ 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 (
// K8SClusterResyncDuration controls the duration of cluster cache refresh
K8SClusterResyncDuration = 12 * time.Hour
// 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
)
func init() {
if clusterResyncDurationStr := os.Getenv(EnvClusterCacheResyncDuration); clusterResyncDurationStr != "" {
if duration, err := time.ParseDuration(clusterResyncDurationStr); err == nil {
K8SClusterResyncDuration = duration
}
}
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)
}
type LiveStateCache interface {
// Returns k8s server version
GetVersionsInfo(serverURL string) (string, []metav1.APIGroup, error)
GetVersionsInfo(serverURL string) (string, []kube.APIResourceInfo, error)
// Returns true of given group kind is a namespaced resource
IsNamespaced(server string, gk schema.GroupKind) (bool, error)
// Returns synced cluster cache
@@ -105,19 +128,19 @@ func NewLiveStateCache(
kubectl kube.Kubectl,
metricsServer *metrics.MetricsServer,
onObjectUpdated ObjectUpdatedHandler,
clusterFilter func(cluster *appv1.Cluster) bool) LiveStateCache {
clusterFilter func(cluster *appv1.Cluster) bool,
resourceTracking argo.ResourceTracking) LiveStateCache {
return &liveStateCache{
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,
appInformer: appInformer,
db: db,
clusters: make(map[string]clustercache.ClusterCache),
onObjectUpdated: onObjectUpdated,
kubectl: kubectl,
settingsMgr: settingsMgr,
metricsServer: metricsServer,
clusterFilter: clusterFilter,
resourceTracking: resourceTracking,
}
}
@@ -127,17 +150,14 @@ 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
// 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
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
clusters map[string]clustercache.ClusterCache
cacheSettings cacheSettings
@@ -285,9 +305,12 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
return nil, fmt.Errorf("controller is configured to ignore cluster %s", cluster.Server)
}
clusterCache = clustercache.NewClusterCache(cluster.RESTConfig(),
clustercache.SetListSemaphore(c.listSemaphore),
clustercache.SetResyncTimeout(K8SClusterResyncDuration),
trackingMethod := argo.GetTrackingMethod(c.settingsMgr)
clusterCacheOpts := []clustercache.UpdateSettingsFunc{
clustercache.SetListSemaphore(semaphore.NewWeighted(clusterCacheListSemaphoreSize)),
clustercache.SetListPageSize(clusterCacheListPageSize),
clustercache.SetWatchResyncTimeout(clusterCacheWatchResyncDuration),
clustercache.SetResyncTimeout(clusterCacheResyncDuration),
clustercache.SetSettings(cacheSettings.clusterSettings),
clustercache.SetNamespaces(cluster.Namespaces),
clustercache.SetClusterResources(cluster.ClusterResources),
@@ -295,7 +318,8 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
res := &ResourceInfo{}
populateNodeInfo(un, res)
res.Health, _ = health.GetResourceHealth(un, cacheSettings.clusterSettings.ResourceHealthOverride)
appName := kube.GetAppInstanceLabel(un, cacheSettings.appInstanceLabelKey)
appName := c.resourceTracking.GetAppName(un, cacheSettings.appInstanceLabelKey, trackingMethod)
if isRoot && appName != "" {
res.AppName = appName
}
@@ -306,7 +330,9 @@ 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)
@@ -419,12 +445,12 @@ func (c *liveStateCache) GetManagedLiveObjs(a *appv1.Application, targetObjs []*
})
}
func (c *liveStateCache) GetVersionsInfo(serverURL string) (string, []metav1.APIGroup, error) {
func (c *liveStateCache) GetVersionsInfo(serverURL string) (string, []kube.APIResourceInfo, error) {
clusterInfo, err := c.getSyncedCluster(serverURL)
if err != nil {
return "", nil, err
}
return clusterInfo.GetServerVersion(), clusterInfo.GetAPIGroups(), nil
return clusterInfo.GetServerVersion(), clusterInfo.GetAPIResources(), nil
}
func (c *liveStateCache) isClusterHasApps(apps []interface{}, cluster *appv1.Cluster) bool {

View File

@@ -1,9 +1,12 @@
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"
@@ -86,16 +89,36 @@ 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 {
targetsMap[v1alpha1.ResourceRef{
Group: "",
Kind: kube.ServiceKind,
Namespace: un.GetNamespace(),
Name: fmt.Sprintf("%s", backend["serviceName"]),
}] = true
if serviceName, err := getServiceName(backend, gvk); err == nil {
targetsMap[v1alpha1.ResourceRef{
Group: "",
Kind: kube.ServiceKind,
Namespace: un.GetNamespace(),
Name: serviceName,
}] = true
}
}
urlsSet := make(map[string]bool)
if rules, ok, err := unstructured.NestedSlice(un.Object, "spec", "rules"); ok && err == nil {
@@ -123,13 +146,15 @@ func populateIngressInfo(un *unstructured.Unstructured, res *ResourceInfo) {
continue
}
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 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 host == nil || host == "" {

View File

@@ -133,6 +133,43 @@ 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
@@ -255,27 +292,35 @@ func TestGetIstioVirtualServiceInfo(t *testing.T) {
}
func TestGetIngressInfo(t *testing.T) {
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)
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)
}
}
func TestGetIngressInfoWildCardPath(t *testing.T) {
@@ -396,7 +441,7 @@ func TestGetIngressInfoNoHost(t *testing.T) {
}
func TestExternalUrlWithSubPath(t *testing.T) {
ingress := strToUnstructured(`
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: helm-guestbook
@@ -424,7 +469,7 @@ func TestExternalUrlWithSubPath(t *testing.T) {
}
func TestExternalUrlWithMultipleSubPaths(t *testing.T) {
ingress := strToUnstructured(`
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: helm-guestbook
@@ -463,7 +508,7 @@ func TestExternalUrlWithMultipleSubPaths(t *testing.T) {
}
func TestExternalUrlWithNoSubPath(t *testing.T) {
ingress := strToUnstructured(`
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: helm-guestbook

View File

@@ -17,8 +17,6 @@ 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"
)
@@ -113,7 +111,7 @@ func (_m *LiveStateCache) GetNamespaceTopLevelResources(server string, namespace
}
// GetVersionsInfo provides a mock function with given fields: serverURL
func (_m *LiveStateCache) GetVersionsInfo(serverURL string) (string, []v1.APIGroup, error) {
func (_m *LiveStateCache) GetVersionsInfo(serverURL string) (string, []kube.APIResourceInfo, error) {
ret := _m.Called(serverURL)
var r0 string
@@ -123,12 +121,12 @@ func (_m *LiveStateCache) GetVersionsInfo(serverURL string) (string, []v1.APIGro
r0 = ret.Get(0).(string)
}
var r1 []v1.APIGroup
if rf, ok := ret.Get(1).(func(string) []v1.APIGroup); ok {
var r1 []kube.APIResourceInfo
if rf, ok := ret.Get(1).(func(string) []kube.APIResourceInfo); ok {
r1 = rf(serverURL)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).([]v1.APIGroup)
r1 = ret.Get(1).([]kube.APIResourceInfo)
}
}

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.APIGroupsToVersions(info.APIGroups)
clusterInfo.APIVersions = argo.APIResourcesToStrings(info.APIResources, false)
if info.LastCacheSyncTime == nil {
clusterInfo.ConnectionState.Status = appv1.ConnectionStatusUnknown
} else if info.SyncError == nil {

View File

@@ -41,6 +41,12 @@ var (
descClusterDefaultLabels,
nil,
)
descClusterConnectionStatus = prometheus.NewDesc(
"argocd_cluster_connection_status",
"The k8s cluster current connection status.",
append(descClusterDefaultLabels, "k8s_version"),
nil,
)
)
type HasClustersInfo interface {
@@ -77,9 +83,11 @@ 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}
@@ -91,5 +99,6 @@ 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

@@ -0,0 +1,104 @@
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,6 +7,7 @@ import (
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/argoproj/gitops-engine/pkg/health"
@@ -20,6 +21,7 @@ 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 {
@@ -49,6 +51,8 @@ const (
var (
descAppDefaultLabels = []string{"namespace", "name", "project"}
descAppLabels *prometheus.Desc
descAppInfo = prometheus.NewDesc(
"argocd_app_info",
"Information about application.",
@@ -121,7 +125,7 @@ var (
redisRequestCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "argocd_redis_request_total",
Help: "Number of kubernetes requests executed during application reconciliation.",
Help: "Number of redis requests executed during application reconciliation.",
},
[]string{"hostname", "initiator", "failed"},
)
@@ -137,19 +141,31 @@ 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) (*MetricsServer, error) {
func NewMetricsServer(addr string, appLister applister.ApplicationLister, appFilter func(obj interface{}) bool, healthCheck func(r *http.Request) error, appLabels []string) (*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)
registry := NewAppRegistry(appLister, appFilter, appLabels)
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)
@@ -180,6 +196,17 @@ 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)
@@ -272,25 +299,30 @@ 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) prometheus.Collector {
func NewAppCollector(appLister applister.ApplicationLister, appFilter func(obj interface{}) bool, appLabels []string) 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) *prometheus.Registry {
func NewAppRegistry(appLister applister.ApplicationLister, appFilter func(obj interface{}) bool, appLabels []string) *prometheus.Registry {
registry := prometheus.NewRegistry()
registry.MustRegister(NewAppCollector(appLister, appFilter))
registry.MustRegister(NewAppCollector(appLister, appFilter, appLabels))
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
@@ -305,7 +337,7 @@ func (c *appCollector) Collect(ch chan<- prometheus.Metric) {
}
for _, app := range apps {
if c.appFilter(app) {
collectApps(ch, app)
c.collectApps(ch, app)
}
}
}
@@ -317,7 +349,7 @@ func boolFloat64(b bool) float64 {
return 0
}
func collectApps(ch chan<- prometheus.Metric, app *argoappv1.Application) {
func (c *appCollector) 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...)
@@ -344,6 +376,15 @@ func collectApps(ch chan<- prometheus.Metric, app *argoappv1.Application) {
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,6 +10,7 @@ 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"
@@ -29,6 +30,9 @@ kind: Application
metadata:
name: my-app
namespace: argocd
labels:
team-name: my-team
team-bu: bu-id
spec:
destination:
namespace: dummy-namespace
@@ -50,6 +54,9 @@ kind: Application
metadata:
name: my-app-2
namespace: argocd
labels:
team-name: my-team
team-bu: bu-id
spec:
destination:
namespace: dummy-namespace
@@ -77,6 +84,9 @@ 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
@@ -138,7 +148,7 @@ func newFakeLister(fakeAppYAMLs ...string) (context.CancelFunc, applister.Applic
fakeApps = append(fakeApps, a)
}
appClientset := appclientset.NewSimpleClientset(fakeApps...)
factory := appinformer.NewFilteredSharedInformerFactory(appClientset, 0, "argocd", func(options *metav1.ListOptions) {})
factory := appinformer.NewSharedInformerFactoryWithOptions(appClientset, 0, appinformer.WithNamespace("argocd"), appinformer.WithTweakListOptions(func(options *metav1.ListOptions) {}))
appInformer := factory.Argoproj().V1alpha1().Applications().Informer()
go appInformer.Run(ctx.Done())
if !cache.WaitForCacheSync(ctx.Done(), appInformer.HasSynced) {
@@ -148,30 +158,71 @@ func newFakeLister(fakeAppYAMLs ...string) (context.CancelFunc, applister.Applic
}
func testApp(t *testing.T, fakeAppYAMLs []string, expectedResponse string) {
cancel, appLister := newFakeLister(fakeAppYAMLs...)
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...)
defer cancel()
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck)
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, cfg.AppLabels)
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()
log.Println(body)
assertMetricsPrinted(t, expectedResponse, body)
assertMetricsPrinted(t, cfg.ExpectedResponse, body)
}
type testCombination struct {
applications []string
expectedResponse string
responseContains string
}
func TestMetrics(t *testing.T) {
combinations := []testCombination{
{
applications: []string{fakeApp, fakeApp2, fakeApp3},
expectedResponse: `
responseContains: `
# 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
@@ -181,7 +232,7 @@ argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:
},
{
applications: []string{fakeDefaultApp},
expectedResponse: `
responseContains: `
# 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
@@ -190,7 +241,50 @@ argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:
}
for _, combination := range combinations {
testApp(t, combination.applications, combination.expectedResponse)
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)
})
}
}
@@ -222,7 +316,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)
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{})
assert.NoError(t, err)
appSyncTotal := `
@@ -252,11 +346,12 @@ 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)
assert.Contains(t, body, line, "expected metrics mismatch")
}
}
@@ -273,7 +368,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)
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{})
assert.NoError(t, err)
appReconcileMetrics := `
@@ -306,7 +401,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)
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{})
assert.NoError(t, err)
appSyncTotal := `

View File

@@ -64,6 +64,7 @@ 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
@@ -98,6 +99,7 @@ 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) {
@@ -148,12 +150,13 @@ 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
}
ts.AddCheckpoint("build_options_ms")
serverVersion, apiGroups, err := m.liveStateCache.GetVersionsInfo(app.Spec.Destination.Server)
serverVersion, apiResources, err := m.liveStateCache.GetVersionsInfo(app.Spec.Destination.Server)
if err != nil {
return nil, nil, err
}
@@ -171,9 +174,10 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
Plugins: tools,
KustomizeOptions: kustomizeOptions,
KubeVersion: serverVersion,
ApiVersions: argo.APIGroupsToVersions(apiGroups),
ApiVersions: argo.APIResourcesToStrings(apiResources, true),
VerifySignature: verifySignature,
HelmRepoCreds: permittedHelmCredentials,
TrackingMethod: string(argo.GetTrackingMethod(m.settingsMgr)),
})
if err != nil {
return nil, nil, err
@@ -455,14 +459,16 @@ 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) {
if !project.IsLiveResourcePermitted(v, app.Spec.Destination.Server, app.Spec.Destination.Name) {
delete(liveObjByKey, k)
}
}
trackingMethod := argo.GetTrackingMethod(m.settingsMgr)
for _, liveObj := range liveObjByKey {
if liveObj != nil {
appInstanceName := kubeutil.GetAppInstanceLabel(liveObj, appLabelKey)
appInstanceName := m.resourceTracking.GetAppName(liveObj, appLabelKey, trackingMethod)
if appInstanceName != "" && appInstanceName != app.Name {
conditions = append(conditions, v1alpha1.ApplicationCondition{
Type: v1alpha1.ApplicationConditionSharedResourceWarning,
@@ -497,6 +503,10 @@ 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...)
@@ -681,6 +691,7 @@ func NewAppStateManager(
metricsServer *metrics.MetricsServer,
cache *appstatecache.Cache,
statusRefreshTimeout time.Duration,
resourceTracking argo.ResourceTracking,
) AppStateManager {
return &appStateManager{
liveStateCache: liveStateCache,
@@ -694,5 +705,6 @@ func NewAppStateManager(
projInformer: projInformer,
metricsServer: metricsServer,
statusRefreshTimeout: statusRefreshTimeout,
resourceTracking: resourceTracking,
}
}

View File

@@ -60,6 +60,16 @@ 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
@@ -87,7 +97,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)
proj, err := argo.GetAppProject(&app.Spec, listersv1alpha1.NewAppProjectLister(m.projInformer.GetIndexer()), m.namespace, m.settingsMgr, m.db, context.TODO())
if err != nil {
state.Phase = common.OperationError
state.Message = fmt.Sprintf("Failed to load application project: %v", err)
@@ -176,7 +186,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}) {
if res.Namespaced && !proj.IsDestinationPermitted(v1alpha1.ApplicationDestination{Namespace: un.GetNamespace(), Server: app.Spec.Destination.Server, Name: app.Spec.Destination.Name}) {
return fmt.Errorf("namespace %v is not permitted in project '%s'", un.GetNamespace(), proj.Name)
}
return nil
@@ -245,6 +255,18 @@ 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,6 +5,7 @@ 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"
@@ -142,3 +143,71 @@ 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 Executable file → Normal 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 Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

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

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

BIN
docs/assets/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

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 --allow-empty -m "Retrigger CI pipeline"
git commit -s --allow-empty -m "Retrigger CI pipeline"
git push origin <yourbranch>
```
@@ -23,7 +23,9 @@ 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 `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.
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.
### 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`, and then,
- Run `yarn add git+https://github.com/argoproj/argo-ui.git` in the `ui/` directory, 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

@@ -269,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` 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.
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.
8. Submit changes to `ui/yarn.lock`in a PR to Argo CD.
@@ -304,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 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 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:
* `make codegen-local`
* `make build-local`

View File

@@ -73,13 +73,9 @@ 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
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo
```
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
@@ -93,6 +89,9 @@ 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
@@ -131,10 +130,11 @@ An example repository containing a guestbook application is available at
### Creating Apps Via CLI
!!! 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'`:
Create the example guestbook application with the following command:
`argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace default`
```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`
```
### 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 to `in-cluster` and namespace to `default`:
For **Destination**, set cluster URL to `https://kubernetes.default.svc` (or `in-cluster` for cluster name) and namespace to `default`:
![destination](assets/destination.png)

View File

@@ -18,6 +18,9 @@ data:
# Specifies token expiration duration
users.session.duration: "24h"
# Specifies regex expression for password
passwordPattern: "^.{8,32}$"
# Enables google analytics tracking is specified
ga.trackingid: "UA-12345-1"
# Unless set to 'false' then user ids are hashed before sending to google analytics
@@ -221,6 +224,15 @@ 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.

View File

@@ -48,6 +48,8 @@ data:
server.basehref: "/"
# Used if Argo CD is running behind reverse proxy under subpath different from /
server.rootpath: "/"
# Directory path that contains additional static assets
server.staticassets: "/shared/app"
# Set the logging format. One of: text|json (default "text")
server.log.format: "text"

View File

@@ -28,3 +28,8 @@ 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

@@ -14,3 +14,5 @@ data:
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl

View File

@@ -88,11 +88,31 @@ spec:
name: styles
```
Note that the CSS file should be mounted within a subdirectory of the existing "/shared/app" directory
Note that the CSS file should be mounted within a subdirectory of the "/shared/app" directory
(e.g. "/shared/app/custom"). Otherwise, the file will likely fail to be imported by the browser with an
"incorrect MIME type" error.
"incorrect MIME type" error. The subdirectory can be changed using `server.staticassets` key of the
[argocd-cmd-params-cm.yaml](./argocd-cmd-params-cm.yaml) ConfigMap.
## 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/).
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)

View File

@@ -171,6 +171,9 @@ 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
@@ -182,6 +185,7 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
url: https://github.com/argoproj/private-repo
password: my-password
username: my-username
@@ -198,6 +202,7 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
url: git@github.com:argoproj/my-private-repository
sshPrivateKey: |
-----BEGIN OPENSSH PRIVATE KEY-----
@@ -215,6 +220,7 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
repo: https://github.com/argoproj/my-private-repository
githubAppID: 1
githubAppInstallationID: 2
@@ -231,6 +237,7 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
repo: https://ghe.example.com/argoproj/my-private-repository
githubAppID: 1
githubAppInstallationID: 2
@@ -257,6 +264,7 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
url: https://github.com/argoproj/private-repo
---
apiVersion: v1
@@ -267,6 +275,7 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
url: https://github.com/argoproj/other-private-repo
---
apiVersion: v1
@@ -277,6 +286,7 @@ metadata:
labels:
argocd.argoproj.io/secret-type: repo-creds
stringData:
type: git
url: https://github.com/argoproj
password: my-password
username: my-username
@@ -396,6 +406,8 @@ data:
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
```
!!! note
@@ -416,6 +428,7 @@ 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
@@ -495,13 +508,13 @@ execProviderConfig:
installHint: string
# Transport layer security configuration settings
tlsClientConfig:
# PEM-encoded bytes (typically read from a client certificate file).
# Base64 encoded PEM-encoded bytes (typically read from a client certificate file).
caData: string
# PEM-encoded bytes (typically read from a client certificate file).
# Base64 encoded PEM-encoded bytes (typically read from a client certificate file).
certData: string
# Server should be accessed without verifying the TLS certificate
insecure: boolean
# PEM-encoded bytes (typically read from a client certificate key file).
# Base64 encoded 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` (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_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-application-controller
@@ -86,7 +86,7 @@ spec:
value: "2"
```
* `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_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!
**metrics**
@@ -119,7 +119,7 @@ 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 and create `.argocd-allow-concurrency` file in app directory.
* **Multiple Custom plugin based applications:** avoid creating temporal files during manifest generation 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.

View File

@@ -79,7 +79,7 @@ Since Contour Ingress supports only a single protocol per Ingress object, define
Internal HTTP/HTTPS Ingress:
```yaml
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server-http
@@ -102,7 +102,7 @@ spec:
Internal gRPC Ingress:
```yaml
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server-grpc
@@ -124,7 +124,7 @@ spec:
External HTTPS SSO Callback Ingress:
```yaml
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1
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: extensions/v1beta1
apiVersion: networking.k8s.io/v1
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: extensions/v1beta1
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server-http-ingress
@@ -269,7 +269,7 @@ spec:
gRPC Ingress:
```yaml
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1
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 # Use extensions/v1beta1 for Kubernetes 1.18 and older
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
@@ -408,6 +408,162 @@ 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,13 +1,27 @@
# Metrics
Argo CD exposes two sets of Prometheus metrics
Argo CD exposes different sets of Prometheus metrics per server.
## Application Metrics
## Application Controller Metrics
Metrics about applications. Scraped at the `argocd-metrics:8082/metrics` endpoint.
* Gauge for application health status
* Gauge for application sync status
* Counter for application sync history
| 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 bellow 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 |
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.
@@ -16,10 +30,57 @@ 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 bellow 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.
@@ -65,7 +126,7 @@ metadata:
spec:
selector:
matchLabels:
app.kubernetes.io/name: argocd-repo-server-metrics
app.kubernetes.io/name: argocd-repo-server
endpoints:
- port: metrics
```

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/ContainerSolutions/externalsecret-operator)
* [External Secrets Operator](https://github.com/external-secrets/external-secrets)
* [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,7 +11,8 @@ 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 has no expiration.
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)).
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.
@@ -154,3 +155,12 @@ Payloads from webhook events are considered untrusted. Argo CD only examines the
the involved applications of the webhook event (e.g. which repo was modified), then refreshes
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.

View File

@@ -30,6 +30,7 @@ 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

@@ -56,6 +56,7 @@ argocd-server [flags]
--sentinel stringArray Redis sentinel hostname and port (e.g. argocd-redis-ha-announce-0:6379).
--sentinelmaster string Redis sentinel master group name. (default "master")
--server string The address and port of the Kubernetes API server
--staticassets string Directory path that contains additional static assets (default "/shared/app")
--tls-server-name string If provided, this name will be used to validate server certificate. If this is not provided, hostname used to contact the server is used.
--tlsciphers string The list of acceptable ciphers to be used when establishing TLS connections. Use 'list' to list available ciphers. (default "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_256_GCM_SHA384")
--tlsmaxversion string The maximum SSL/TLS version that is acceptable (one of: 1.0|1.1|1.2|1.3) (default "1.3")

View File

@@ -0,0 +1,16 @@
# 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).

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,15 +33,18 @@ 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/>
* [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)
* [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.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,6 +1,13 @@
# Google
* [G Suite SAML App Auth using Dex](#g-suite-saml-app-auth-using-dex)
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.
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.
@@ -14,10 +21,66 @@ data:
policy.default: role:readonly
```
## G Suite SAML App Auth using Dex
## 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
### 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")
@@ -76,3 +139,97 @@ 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,6 +77,7 @@ 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> \
@@ -114,7 +115,8 @@ 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).
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.
* [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),
@@ -196,6 +198,91 @@ 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

View File

@@ -57,17 +57,19 @@ 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

@@ -0,0 +1,273 @@
---
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

@@ -5,12 +5,22 @@
- [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-aka-gitops-agent-proposal)
- [v2.3 and beyond](#v23-and-beyond)
- [Application Details Page Usability](#application-details-page-usability)
- [Cluster Management User Interface](#cluster-management-user-interface)
- [Input Forms UI Refresh](#input-forms-ui-refresh)
- [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)
- [Compact Resources Tree](#compact-resources-tree)
- [Web Shell](#web-shell)
- [Helm values from external repo](#helm-values-from-external-repo)
- [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)
- [Maintain difference in cluster and git values for specific fields](#maintain-difference-in-cluster-and-git-values-for-specific-fields)
- [Multi-tenancy improvements](#multi-tenancy-improvements)
- [GitOps Engine Enhancements](#gitops-engine-enhancements)
- [Completed](#completed)
- [✅ Core Argo CD (proposal)](#core-argo-cd-aka-gitops-agent-proposal)
- [✅ Core Functionality Bug Fixes](#-core-functionality-bug-fixes)
- [✅ Performance](#-performance)
- [✅ ApplicationSet](#-applicationset)
@@ -20,7 +30,6 @@
- [✅ Automated Registry Monitoring](#-automated-registry-monitoring)
- [✅ Projects Enhancements](#-projects-enhancements)
## v2.2
### Config Management Tools Integrations ([proposal](https://github.com/argoproj/argo-cd/pull/5927))
@@ -44,17 +53,59 @@ Instead of asking an administrator to change Argo CD settings end users can perf
## v2.3 and beyond
### Application Details Page Usability
### Input Forms UI Refresh
Application details page has accumulated multiple usability and feature requests such as
[Node view](https://github.com/argoproj/argo-cd/issues/1483),
Network view ([1](https://github.com/argoproj/argo-cd/issues/2892), [2](https://github.com/argoproj/argo-cd/issues/2338))
[etc](https://github.com/argoproj/argo-cd/issues/2199).
Improved design of the input forms in Argo CD Web UI: https://www.figma.com/file/IIlsFqqmM5UhqMVul9fQNq/Argo-CD?node-id=0%3A1
### Cluster Management User Interface
### 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
An ability to collaps leaf resources tree to improve visualization of very large applications: [#7349](https://github.com/argoproj/argo-cd/issues/7349)
### 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))
### 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)
### 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)).
### Multi-tenancy improvements
The multi-tenancy improvements that allow end-users to create Argo CD applications using Kubernetes directly without accessing Argo CD API.
* [Applications outside argocd namespace](https://github.com/argoproj/argo-cd/pull/6409)
* [AppSource](https://github.com/argoproj-labs/appsource)
Argo CD has information about whole clusters, not just applications in it.
We need to provide a user interface for cluster administrators that visualize cluster level resources.
### GitOps Engine Enhancements
@@ -109,7 +160,7 @@ to improve user experience.
To make Argo CD successful we need to build tools that enable Argo CD administrators to handle scalability and performance issues in a self-service model.
That includes more metrics, out of the box alerts and a cluster management user interface.
That includes more metrics, out-of-the-box alerts and a cluster management user interface.
### ✅ Argo CD Notifications

View File

@@ -12,6 +12,5 @@ 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)

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