Compare commits

...

283 Commits

Author SHA1 Message Date
argo-bot
ecc2af9dca Bump version to 2.3.2 2022-03-23 00:32:13 +00:00
argo-bot
c5b0279050 Bump version to 2.3.2 2022-03-23 00:31:57 +00:00
Michael Crenshaw
6df17e7c56 chore: fix imports (#8859)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-03-22 12:55:09 -07:00
Michael Crenshaw
e55ecf9107 chore: remove lint-docs CI task (#8722) (#8858)
* chore: remove lint-docs CI task

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

* chore: remove not longer necessary url-allow-list

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

Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-03-22 12:54:37 -07:00
Alexander Matyushentsev
21f208f17e Merge pull request from GHSA-2f5v-8r3f-8pww
* fix: application resource APIs must enforce project restrictions

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

* Fix unit tests

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

Co-authored-by: jannfis <jann@mistrust.net>
2022-03-22 10:57:31 -07:00
argo-bot
b65c1699fa Bump version to 2.3.1 2022-03-10 22:43:44 +00:00
argo-bot
4c1428a6be Bump version to 2.3.1 2022-03-10 22:43:24 +00:00
Keith Chong
bca190bd0c fix: Retry checkbox unchecked unexpectedly; Sync up with YAML (#8682) (#8720)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2022-03-10 14:23:30 -08:00
Alexander Matyushentsev
88ca5aabf2 chore: Bump stable version of application set addon (#8744)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-03-10 13:19:44 -08:00
Alexander Matyushentsev
8297f827a8 fix: correct jsonnet paths resolution (#8721)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-03-08 15:59:03 -08:00
Yuan Tang
b85ef39e0d fix(ui): Applications page incorrectly resets to tiles view. Fixes #8702 (#8718)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2022-03-08 11:24:02 -08:00
argo-bot
fe42780229 Bump version to 2.3.0 2022-03-06 06:18:59 +00:00
argo-bot
057d95374d Bump version to 2.3.0 2022-03-06 06:18:41 +00:00
Yuan Tang
1546c1d314 fix: Health status bar button does not re-render properly. Fixes #8569 (#8668)
fix: Health status bar button does not re-render properly. Fixes #8569 (#8668)

Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2022-03-04 10:41:25 -08:00
jannfis
31564c6067 fix: Allow quoted RBAC group names in API (#8650)
Signed-off-by: jannfis <jann@mistrust.net>
Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>

Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
2022-03-04 07:35:21 +00:00
Alexander Matyushentsev
6e54e59e82 fix: prevent file traversal using helm file values param and application details api (#8606)
* fix: prevent file traversal using helm file values param and application details api

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

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

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-25 15:43:03 -08:00
Alexander Matyushentsev
196dab98dc Unique repo path and permissions (#8517)
Unique repo path and permissions (#8517)

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-25 15:42:59 -08:00
Michael Crenshaw
9d4ed2847e chore: bump redoc vesion to avoid CVE-2021-23820 (#8604)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-02-25 15:42:52 -08:00
Yuan Tang
ffc6080060 build: Bump up network timeout during yarn install (#8601)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2022-02-25 15:42:46 -08:00
Alexander Matyushentsev
ca2e3041f1 refactor: use argocd-git-ask-pass to pass git credentials to git/kustomize (#8516)
refactor: use argocd-git-ask-pass to pass git credentials to git/kustomize  (#8516)

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-25 15:42:11 -08:00
Michael Crenshaw
31676e2aea fix: add labels to sidecar CMP manifests (#8243) (#8367)
fix: add labels to sidecar CMP manifests (#8243) (#8367)

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-02-25 15:42:05 -08:00
Michael Crenshaw
81f9bc20ec chore: pass submodulesEnabled explicitly to avoid implicit parameter (#8337)
* chore: pass submodulesEnabled explicitly to avoid implicit parameter

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

* fix: update mock

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

* chore: lint

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

* fix: mock checkout invocations w/ 2 params

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

* chore: remove unnecessary comment

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-02-25 15:40:20 -08:00
Jesse Suen
0b868bd221 fix!: enforce app create/update privileges when getting repo details (#8558)
Signed-off-by: Jesse Suen <jesse@akuity.io>
2022-02-25 15:39:26 -08:00
Yuan Tang
37c1585c2f feat(cli): Allow to view previously terminated container logs (#8582)
* feat(cli): Allow to view previously terminated container logs

This is useful when we want to see the snapshot of previously terminated container logs.

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

* chore: Generate docs

Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2022-02-25 15:39:18 -08:00
pasha-codefresh
e095ef6e4c chore(deps): bump mkdocs from 1.1.2 to 1.2.3 in /docs (#8588)
chore(deps): bump mkdocs from 1.1.2 to 1.2.3 in /docs (#8588)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2022-02-25 15:39:04 -08:00
pasha-codefresh
8396e06121 fix: Upgrade monaco-editor from 0.15.6 to 0.27.0 (#8590)
fix: Upgrade monaco-editor from 0.15.6 to 0.27.0 (#8590)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2022-02-25 15:38:57 -08:00
Ben Ye
d4a6498d80 feat: expose cluster sync retry duration (#8481)
Signed-off-by: Ben Ye <ben.ye@bytedance.com>
2022-02-25 15:38:49 -08:00
Yi Cai
4fc814bc16 fix: UI: Favorite star icon is cut off (#8556)
* fix: UI: Favorite star icon is cut off

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

* fixed lint error

Signed-off-by: ciiay <yicai@redhat.com>
2022-02-25 15:38:39 -08:00
Michael Crenshaw
bf67d55f3f chore: upgrade redoc (#8573)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-02-25 15:38:33 -08:00
dependabot[bot]
87402fdc4c build(deps): bump url-parse from 1.5.3 to 1.5.7 in /ui (#8557)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.3 to 1.5.7.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.3...1.5.7)

---
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>
2022-02-25 15:38:19 -08:00
Alexander Matyushentsev
10b4c47aad feat: support custom helm values file schemes (#8535)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-25 15:37:45 -08:00
Alexander Matyushentsev
e6a9400c38 feat: support disabling manifest generation using config management tools (#8514)
* feat: support disabling manifest generation using config management tools

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

* rename EnableManifestGenerationForSourceType to EnableSourceTypes

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-25 15:36:27 -08:00
Alexander Matyushentsev
ebb21736df fix: build ui as part of 'make release-cli' command (#8536)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-25 15:36:21 -08:00
Alexander Matyushentsev
ea7ad844cb fix: refreshing label is hidden by resource tree (#8391)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-25 15:36:12 -08:00
jannfis
76c0b32887 fix: Return early on error when updating clusters (#8526)
Signed-off-by: jannfis <jann@mistrust.net>
2022-02-25 15:36:06 -08:00
Christian Roth
827096c195 docs: Using Dex with OIDC needs the config element in yaml (#8510)
In order to get Dex working with an OIDC provider, I had to structure the Dex config according to the [Dex Documentation](https://dexidp.io/docs/connectors/oidc/#configuration).
This means placing the OIDC configuration within their own `config` element in the `dex.config`, rather than listing them on the same level as the generic connector settings.
2022-02-25 15:35:48 -08:00
Yuan Tang
bca450f7aa docs: Clarify sync wave precedence by kind and add note on delay between waves (#8518)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2022-02-25 15:35:33 -08:00
Yuan Tang
3c7d99f82c test: Support e2e tests and improve robustness on k8s v1.21-v1.23 (#8431)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
Co-authored-by: Jesse Suen <jesse@akuity.io>
2022-02-25 15:35:23 -08:00
Daniel Helfand
c5c25cd75b docs: update ApplicationSet controller getting started link (#8482)
Signed-off-by: Daniel Helfand <helfand.4@gmail.com>
2022-02-25 15:35:09 -08:00
Jesse Suen
f54d0a037f chore: update protoc to 3.17.3 and make install portable (#7932)
Signed-off-by: Jesse Suen <jesse@akuity.io>
2022-02-25 15:34:44 -08:00
Alexander Matyushentsev
6da138956a docs: update chagelog - add v2.3.0, v2.2.1 ~ v2.2.3 releases (#8310)
docs: update chagelog - add v2.3.0, v2.2.1 ~ v2.2.3 releases (#8310)

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-25 15:34:24 -08:00
Keith Chong
b3a181ea88 fix: Adjust z-index for newly added tree view toolbar (#8422) (#8423)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2022-02-25 15:33:20 -08:00
Alexander Matyushentsev
2f5da24654 feat: add RespectIgnoreDifferences sync option to UI (#8390)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-25 15:32:59 -08:00
Soumya Ghosh Dastidar
cc572a5eb2 fix(cli): argo app diff passes --api-versions to helm template (#8371)
Signed-off-by: Soumya Ghosh Dastidar <soumya@akuity.io>
2022-02-25 15:32:37 -08:00
Alexander Matyushentsev
ae03c3b872 chore: fix broken TestHelmIgnoreMissingValueFiles test (#8368)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-25 15:31:31 -08:00
Jonah Back
79ac472382 fix: check for issuing condition on Certificate (#7217)
Signed-off-by: Jonah Back <jonah@jonahback.com>

Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-25 15:31:16 -08:00
Chetan Banavikalmutt
061ba811f1 chore: upgrade Helm to v3.8.0 (#8301)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2022-02-25 15:29:49 -08:00
Alexander Matyushentsev
b5909d59ec refactor: update gitops-engine version to v0.6.0
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-25 15:27:15 -08:00
jannfis
68f17dbe8e feat: Make cluster cache sync more robust (#8438)
* feat: Support retry for list operations in cluster cache sync

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

* Fix default retries

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

* Pull in latest gitops-engine

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

* Default retry limit should be 1

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

* Make type conversion earlier

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

* Rename limit to attempt

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

* Revert Makefile change

Signed-off-by: jannfis <jann@mistrust.net>
2022-02-16 11:56:22 +00:00
Jesse Suen
bc6b4950ba docs: add security documentation related to git repositories (#8463)
Signed-off-by: Jesse Suen <jesse@akuity.io>
2022-02-11 13:48:10 -08:00
jannfis
c2cf633bbc feat: Allow fine-tuning of K8s rest client connection properties (#8404)
* feat: Allow fine-tuning of K8s rest client connection properties

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

* Move initialization

Signed-off-by: jannfis <jann@mistrust.net>
2022-02-09 09:05:24 +00:00
Jonathan West
bdd05d5c7a Update Argo CD V2.3 to ApplicationSet v0.4.0 (#8416)
Signed-off-by: Jonathan West <jonwest@redhat.com>
2022-02-07 10:49:14 -08:00
Ishita Sequeira
4b04a39180 fix: fix deployment config health status (#8376)
Signed-off-by: ishitasequeira <isequeir@redhat.com>
2022-02-06 11:20:56 -08:00
argo-bot
aa54aa7eda Bump version to 2.3.0-rc5 2022-02-04 23:32:12 +00:00
argo-bot
4bbd0e57dd Bump version to 2.3.0-rc5 2022-02-04 23:32:00 +00:00
fredericfran-gds
2d6b619a86 fix: reload ArgoCD config if OIDC config changes (#8350)
fix: reload ArgoCD config if OIDC config changes (#8350)

Signed-off-by: Frederic Francois <frederic.francois@digital.cabinet-office.gov.uk>
2022-02-04 15:08:59 -08:00
Leonardo Luz Almeida
39487ef7c7 chore: Generate spdx for the UI project (#8385)
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-02-04 15:08:54 -08:00
jannfis
fcc7c0b080 fix: Resolve symlinked value files correctly (#8387)
* fix: Resolve symlinked value files correctly

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

* fix: Resolve symlinked value files correctly

Signed-off-by: jannfis <jann@mistrust.net>
2022-02-04 15:08:32 -08:00
argo-bot
ed734fedbb Bump version to 2.3.0-rc4 2022-02-03 21:46:08 +00:00
argo-bot
7414f2d42c Bump version to 2.3.0-rc4 2022-02-03 21:45:50 +00:00
jannfis
8139df8983 Merge pull request from GHSA-63qx-x74g-jcr7
Signed-off-by: jannfis <jann@mistrust.net>
2022-02-03 20:37:46 +01:00
pasha-codefresh
f364330de2 fix: fix example in project scoped repositories (#8357)
fix: fix example in project scoped repositories (#8357)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2022-02-03 09:45:43 -08:00
pasha-codefresh
4ec67d8b08 fix: applications page is crashing if nothing marked as favorites (#8356)
fix: applications page is crashing if nothing marked as favorites (#8356)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2022-02-03 09:45:39 -08:00
Leonardo Luz Almeida
3d3f81df4a chore: update actions/setup-go to v2 (#8349)
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-02-03 09:45:34 -08:00
argo-bot
37f01f6f32 Bump version to 2.3.0-rc2 2022-02-02 22:37:02 +00:00
argo-bot
36eab6b82c Bump version to 2.3.0-rc2 2022-02-02 22:36:47 +00:00
Leonardo Luz Almeida
793acc147f chore: Use go install to add spdx-sbom-generator (#8346)
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-02-02 13:51:14 -08:00
Leonardo Luz Almeida
b50609c0e6 chore: generate sbom for the released docker image (#8338)
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-02-02 13:51:10 -08:00
Michael Crenshaw
5f48ce96c6 chore: use go install instead of deprecated go get (#8333)
* chore: use go install instead of deprecated go get

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

* docs: readme fixes

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-02-02 13:30:43 -08:00
Alexander Matyushentsev
c32460a2bc chore: automate bundling argocd addons during release process (#8336)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-02 13:28:40 -08:00
Ben Ye
7eb1aba99b fix: register controller workqueue metrics correctly (#8318)
Signed-off-by: Ben Ye <ben.ye@bytedance.com>
2022-02-01 12:02:55 -08:00
Alexander Matyushentsev
1a8139f4d6 fix: make sure release workflow publish image with "v" in front of version (#8335)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-01 10:27:40 -08:00
Leonardo Luz Almeida
02c03c3b26 chore: generate and upload sbom during release (#8332)
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-02-01 10:27:34 -08:00
Alexander Matyushentsev
cdb20d5060 docs: mention argocd notifications and applicationset changes in upgrade instructions (#8312)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-02-01 10:27:27 -08:00
argo-bot
7d7eed4932 Bump version to 2.3.0-rc1 2022-01-30 21:42:54 +00:00
argo-bot
af8c5eb07a Bump version to 2.3.0-rc1 2022-01-30 21:42:41 +00:00
Alexander Matyushentsev
1a476f7564 fix: argocd build fails on windows (#8319)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-30 13:02:01 -08:00
Saumeya Katyal
7f15389c72 feat: favourite ui feature (#8210)
* feat: favourite ui feature (#8210)

Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2022-01-28 12:55:23 -08:00
Alexander Matyushentsev
1a3556e1cc fix: add missing steps in release workflow to setup docker buildx (#8311)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-28 12:04:34 -08:00
Yujun Zhang
4aa614dafb fix: fetch revision only then fallback to default refspec (#5605)
* fix: fallback to fetch default only on error

Ignoring commit SHA breaks gerrit when the commit is not merged

Signed-off-by: Yujun Zhang <yujunz@nvidia.com>

* revert util/git/client.go changes

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

Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-28 10:58:36 -08:00
Yuan Tang
6abccea3f0 docs: Add link to new blog (#8308)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2022-01-28 09:06:05 -08:00
Guilhem Lettron
5ffc60f88d chore(bug_report): put instructions in comment (#8283)
Users reporting a bug will see instructions, can keep it, it will be ignored in final issue

Signed-off-by: Guilhem Lettron <guilhem@barpilot.io>
2022-01-28 10:08:31 +01:00
Keisuke Wada
04e05c5106 docs: Add ZOZO to list of users (#8300)
Signed-off-by: keisuke.wada <keisuke.wada@zozo.com>
2022-01-28 10:05:12 +01:00
Keith Chong
f387ab846b feat: Zoom in and out on resource view (#7183) (#8290)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2022-01-27 15:59:53 -08:00
pasha-codefresh
6dc544db99 chore: update slack version (#8299)
chore: update slack version (#8299)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2022-01-27 12:09:14 -08:00
Michael Crenshaw
061e575d82 chore: fix docs formatting (#8293)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-01-27 10:01:48 -08:00
Snaipe
d9c1af9f25 docs: update ambassador mappings to avoid --grpc-web-root-path (#8028)
I found it non-intuitive to have to tell our users to use `--grpc-web-root-path /`
when logging in when the defaults should have just worked.

This commit updates the Host-based ambassador mappings to avoid that, making
plain `argocd login <host>` calls work.

Signed-off-by: Franklin "Snaipe" Mathieu <me@snai.pe>
2022-01-27 08:18:46 -08:00
Alexander Matyushentsev
6abc85a3a5 Revert "chore: Run dex reverse proxy only when dex is configured (#7999)" (#8291)
This reverts commit 303cc4613b.

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-27 07:09:10 +01:00
Alexander Matyushentsev
a16471b8a5 chore: upgrade gitops engine (#8288)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-26 19:04:41 -08:00
Alexander Matyushentsev
ecc3ab3cab feat: Use encrypted cookie to store OAuth2 state nonce (instead of redis) (#8241)
feat: Use encrypted cookie to store OAuth2 state nonce (instead of redis) (#8241)

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-26 10:59:50 -08:00
Dong Wang
0aeda4366d feat: Expose ARGOCD_APP_NAME to the kustomize build command (#8096)
Signed-off-by: Dong Wang <wd@wdicc.com>
2022-01-26 08:18:14 -08:00
Ishita Sequeira
cf601c96d3 feat: bundle applicationset-controller with argocd (#8148)
* feat: bundle applicationset-controller with argocd

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

* point applicationset to master branch

Signed-off-by: ishitasequeira <isequeir@redhat.com>
2022-01-26 06:18:23 -05:00
Michael Crenshaw
96f95ca1c1 Use gRPC timeout for sidecar CMPs (#8131) (#8236)
Use gRPC timeout for sidecar CMPs (#8131) (#8236)

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-01-25 15:45:37 -08:00
dependabot[bot]
0b2e585373 build(deps): bump nanoid from 3.1.23 to 3.2.0 in /ui (#8253)
Bumps [nanoid](https://github.com/ai/nanoid) from 3.1.23 to 3.2.0.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.1.23...3.2.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-25 09:35:31 -08:00
Keith Chong
83458e0bd9 feat: Allow external links on Application (#3487) (#8231)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2022-01-25 09:34:36 -08:00
pasha-codefresh
4aa7cbfb91 chore: go version inside mod file (#8275)
* update go version

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

* update go version

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

* change version in docs

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2022-01-25 15:23:43 +01:00
Michael Crenshaw
26db08931e docs: add chart field to application.yaml (#8239)
* docs: add chart field to application.yaml

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

* docs: more clarification

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-01-25 09:16:13 +01:00
Alexander Matyushentsev
3ae9bffa30 fix: argocd CLI fails in core mode (#8270)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-25 09:15:33 +01:00
jannfis
4c7651b5f8 chore: Update security policy (#8258)
Signed-off-by: jannfis <jann@mistrust.net>
2022-01-24 22:56:15 -08:00
pasha-codefresh
feaf949968 chore: update notifications version (#8267)
chore: update notifications version (#8267)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2022-01-24 13:43:23 -08:00
pasha-codefresh
b7bdb8ffe7 feat: Application generation strategies and clusters generation (#8263)
feat: Application generation strategies and clusters generation (#8263)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2022-01-24 09:24:39 -08:00
Patrick Jahns
c3b3521f59 fix: provide a semantic version parsed version for KUBE_VERSION (#8250)
Signed-off-by: Patrick Jahns <github@patrickjahns.de>
2022-01-23 13:01:12 +01:00
Ishita Sequeira
285454f011 chore: remove additional 'to' from description in swagger.json (#8254)
Signed-off-by: ishitasequeira <isequeir@redhat.com>
2022-01-23 12:51:58 +01:00
Saumeya Katyal
134f880aae docs: add saumeya to reviewers (#8248)
Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2022-01-21 09:52:45 -08:00
Michael Crenshaw
9ac935d59f docs: fix nested code block formatting (#8240)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-01-21 11:21:40 +01:00
Yi Cai
8c2cef6f28 docs: added ciiay to reviewers (#8242)
Signed-off-by: ciiay <yicai@redhat.com>

Co-authored-by: jannfis <jann@mistrust.net>
2022-01-21 11:12:28 +01:00
jannfis
26b9ba3dc6 chore: Publish latest build to quay instead of Docker Hub (#8238)
Signed-off-by: jannfis <jann@mistrust.net>
2022-01-21 10:08:32 +01:00
Leonardo Luz Almeida
de496d6b4b docs: add Leo and Michael as reviewers (#8244)
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-01-21 09:25:53 +01:00
Chetan Banavikalmutt
ae71475869 chore: exclude argocd-server rbac for core-install (#8234)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2022-01-20 16:29:19 -08:00
Alexander Matyushentsev
ef8ae570bf chore: upgrade dex to v2.30.2 (https://github.com/dexidp/dex/issues/2326) (#8237)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-20 14:07:49 -08:00
Alexander Matyushentsev
6962fc22ee chore: upgrade base image to ubuntu:21.10 (#8230)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-20 08:29:47 +01:00
Alexander Matyushentsev
25698fd9f5 chore: upgrade k8s client to v1.23 (#8213)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-20 08:28:11 +01:00
Alexander Matyushentsev
44d596f0ee chore: upgrade kustomize to most recent version (v4.4.1) (#8227)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-19 15:33:29 -08:00
Leonardo Luz Almeida
1547b44ffc feat: Allow configuring system wide ignore differences for all resources (#8224)
* feat: Allow configuring system wide ignore differences for all resources

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

* Add example config to argocd-cm.yaml

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-01-19 14:57:43 -08:00
Alexander Matyushentsev
9155d14f9a chore: upgrade golang to 1.17.6 (#8229)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-19 14:44:31 -08:00
Alexander Matyushentsev
2fc0a25c0a chore: upgrade helm to most recent version (v3.7.2) (#8226)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-19 14:17:57 -08:00
Yujun Zhang
988d760474 chore: fix typo in description (#8217)
Signed-off-by: Yujun Zhang <yujunz@nvidia.com>
2022-01-19 08:18:04 +01:00
Alexander Matyushentsev
a17c77e238 feat: allow selecting application on detail page (#8176)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-18 14:43:43 -08:00
Michael Crenshaw
dc24d05a31 chore: make lint-docs less flakey (#8182)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-01-18 12:03:32 -08:00
Vladimir Avdoshka
113b3da691 docs: Specifying the value format to avoid ambiguity due to mentioned default "90 seconds timeout" (#8029)
Signed-off-by: Vladimir Avdoshka <vova.avdoshka@gmail.com>
Signed-off-by: Vladimir Avdoshka <vavdoshka@kyriba.com>
2022-01-18 11:51:12 -08:00
Leonardo Luz Almeida
8608a3192a docs: Add RespectIgnoreDifferences sync option documentation (#8212)
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-01-18 09:54:54 -08:00
Tristan Keen
2fb3986386 fix: Allow all resources to add external links (#7923)
Signed-off-by: Tristan Keen <tristan.keen@gmail.com>
2022-01-18 08:23:58 -08:00
jannfis
8b95052720 chore: redis:alpine is incompatible with Dockerized toolchain (#8193)
Signed-off-by: jannfis <jann@mistrust.net>
2022-01-18 08:22:46 +01:00
jannfis
010411012f chore: Log out the resource triggering reconciliation (#8192)
* chore: Log out the resource triggering reconciliation

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

* chore: Log out the resource triggering reconciliation

Signed-off-by: jannfis <jann@mistrust.net>
2022-01-18 08:22:26 +01:00
Song Song Li
22f4a936cc fix invalid cmd (#8026)
Signed-off-by: Song Song Li <ssli@redhat.com>
2022-01-17 19:41:04 -08:00
Denis Krivenko
41fc70d17e fix: Add "Restarting MinIO" status to MiniO Tenant health check (#8191)
Signed-off-by: dnskr <dnskrv88@gmail.com>
2022-01-15 17:32:43 +01:00
Marco Kilchhofer
303cc4613b chore: Run dex reverse proxy only when dex is configured (#7999)
Signed-off-by: Marco Kilchhofer <mkilchhofer@users.noreply.github.com>
2022-01-15 16:18:47 +01:00
pasha-codefresh
2072d1a4b0 chore: upsert application e2e (#8190)
* move projects

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

* Revert "move projects"

This reverts commit d0e21353

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

* covering regression #8184 with e2e

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

* empty commit

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

* change semver

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

* fix test

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

* empty commit

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

* empty commit

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2022-01-15 15:41:08 +01:00
jannfis
d33caacb9b fix: Prevent possible out-of-bounds access when loading policies (#8186)
Signed-off-by: jannfis <jann@mistrust.net>
2022-01-15 07:30:40 +01:00
jannfis
3c5033c6bf refactor: Make user agent enforcer testable (#8174)
Signed-off-by: jannfis <jann@mistrust.net>
2022-01-15 07:30:14 +01:00
pasha-codefresh
978162fdee fix: application exist panic when execute api call (#8188)
fix: application exist panic when execute api call (#8188)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2022-01-14 17:19:43 -08:00
Alexander Matyushentsev
4f62aa4398 docs: update roadmap based on v2.3 progress (#8187)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-14 15:55:32 -08:00
Keith Chong
6f59fe660f feat: Add app list and details page views to navigation history (#7776) (#7937)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2022-01-14 14:46:53 -08:00
patst
0dfc125d95 feat: add skipCrds flag for helm charts (#8012)
* feat: add skipCrds flag for helm charts

* replace additionalTemplateArgs with includeCrds flag
* add testcase for skip crds

Signed-off-by: patst <patrick.steinig@googlemail.com>

* feat: add skipCrds flag for helm charts

* replace additionalTemplateArgs with includeCrds flag
* add testcase for skip crds

Signed-off-by: patst <patrick.steinig@googlemail.com>

* feat: add skipCrds flag for helm charts

* replace additionalTemplateArgs with includeCrds flag
* add testcase for skip crds

Signed-off-by: patst <patrick.steinig@googlemail.com>

* feat: add skipCrds flag for helm charts

* make sure include crds is not added for helm2

Signed-off-by: patst <patrick.steinig@googlemail.com>
2022-01-14 13:56:34 -08:00
pasha-codefresh
f65289748a feat: tool for generate argocd resources (#8037)
feat: tool for generate argocd resources  (#8037)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2022-01-14 12:53:51 -08:00
jannfis
47187bd30e fix: Prevent possible nil-pointer deref in normalizer (#8185)
Signed-off-by: jannfis <jann@mistrust.net>
2022-01-14 21:37:31 +01:00
pasha-codefresh
4f155b539b fix: argocd notifications troubleshooting cmd (#8183)
fix: argocd notifications troubleshooting cmd (#8183)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2022-01-14 11:45:02 -08:00
jannfis
cb47740d62 chore(deps): Update github.com/Masterminds/semver to v3.1.1 (#8180)
* chore(deps): Upgrade Masterminds/semver to v3.1.1

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

* Do not anchor regexp

Signed-off-by: jannfis <jann@mistrust.net>
2022-01-14 19:28:34 +01:00
jannfis
0b9b7c31f8 fix: Parse to correct uint32 type (#8177)
Signed-off-by: jannfis <jann@mistrust.net>
2022-01-14 10:17:30 -08:00
dependabot[bot]
35f5b32f53 build(deps): bump follow-redirects from 1.14.1 to 1.14.7 in /ui (#8161)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.1 to 1.14.7.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.1...v1.14.7)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-14 15:22:02 +01:00
inductor(Kohei)
2f83312800 docs: Update Ingress with GKE (#8163)
Signed-off-by: inductor <kohei.ota@hpe.com>
2022-01-14 12:43:33 +01:00
34FathomBelow
074db0cf28 docs: Update tls.md (#8169)
Signed-off-by: 34fathombelow <34fathombelow@protonmail.com>
2022-01-14 12:42:45 +01:00
dependabot[bot]
502762acc0 build(deps-dev): bump postcss from 8.2.10 to 8.2.13 in /ui (#8118)
Bumps [postcss](https://github.com/postcss/postcss) from 8.2.10 to 8.2.13.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.2.10...8.2.13)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-14 10:26:42 +01:00
Ishita Sequeira
55ea34292a fix: route health check stuck in 'Progressing' (#8170)
Signed-off-by: ishitasequeira <isequeir@redhat.com>
2022-01-14 10:02:51 +01:00
jannfis
7ff5f0755b chore: Update ghinstallation to v2.0.4 (#8171)
* chore: Update ghinstallation to v2.0.4

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

* Update go.sum

Signed-off-by: jannfis <jann@mistrust.net>
2022-01-14 10:01:48 +01:00
dependabot[bot]
4a04bb9096 build(deps): bump follow-redirects from 1.14.4 to 1.14.7 in /ui-test (#8173)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.4 to 1.14.7.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.4...v1.14.7)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-14 10:01:33 +01:00
pavan kumar ceemala
fb30f1bd03 Update USERS.md (#8166) 2022-01-13 15:58:56 -08:00
Yuan Tang
d6f3f87c69 chore: Migrate to use golang-jwt/jwt v4.2.0 (#8136)
chore: Migrate to use golang-jwt/jwt v4.2.0 (#8136)

Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2022-01-13 13:12:21 -08:00
Leonardo Luz Almeida
6240ef00e7 feat: new sync option to use ignore diff configs during sync (#8078)
feat: new sync option to use ignore diff configs during sync (#8078)

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-01-13 13:00:17 -08:00
jannfis
5c85df90d5 fix: Fix a possible crash when parsing RBAC (#8165)
Signed-off-by: jannfis <jann@mistrust.net>
2022-01-13 16:28:08 +01:00
Ishita Sequeira
07cc533896 chore: move resolveRevision from api-server to repo-server (#7966)
* chore: move resolveRevision to repo-server

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

* fix unit tests

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

* Retrigger CI pipeline

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

* Address PR comments

Signed-off-by: ishitasequeira <isequeir@redhat.com>
2022-01-12 22:06:00 +01:00
jannfis
d511fb8deb chore: Update to Redis 6.2.4 (#8157)
Signed-off-by: jannfis <jann@mistrust.net>
2022-01-12 12:37:10 -08:00
Michael Crenshaw
99583c74c3 docs: document fileParameters (#8156)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-01-12 19:43:34 +01:00
Michael Crenshaw
c92922e3d6 docs: reorganize and clarify CMP docs (#8130)
* docs: reorganize and clarify CMP docs

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

* docs: note that an empty plugin block is acceptable

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-01-12 19:42:58 +01:00
Tanmay_Bhat
5e6aee5961 docs: add Skit to users list (#8152) 2022-01-12 14:46:01 +01:00
Márk Sági-Kazár
57e0ffceb7 feat: Support XDG Base directory standard (#7638) (#7791)
* feat: support XDG Base directory standard

Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>

* chore: set XDG_CONFIG_HOME env var for docs generation

Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>

* chore: regenerate cli docs

Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-01-12 09:05:01 +01:00
Thomas Dy
c8bcabeba5 feat: Allow escaping dollar in Envsubst (#7961)
* feat: allow escaping dollar in Envsubst

Signed-off-by: Thomas Dy <thatsmydoing@gmail.com>

* docs: add variable escape documentation

Signed-off-by: Thomas Dy <thatsmydoing@gmail.com>
2022-01-12 08:09:41 +01:00
Chetan Banavikalmutt
4b5df692d7 docs: update the ARGOCD_SESSION_FAILURE_MAX_FAIL_COUNT variable in the docs (#8140)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2022-01-11 12:21:34 -08:00
Alexander Matyushentsev
5d770d6c54 chore: fix broken TestValidatePermissions unit test (#8147)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-11 12:17:11 -08:00
J. Mark Pim
dfd40efb93 fix: always call ValidateDestination (#7976)
* fix: always call ValidateDestination

Signed-off-by: Mark Pim <j.mark.pim@gmail.com>

* Revert part of the change to fix tests

Signed-off-by: Mark Pim <j.mark.pim@gmail.com>

* Fix linting

Signed-off-by: Mark Pim <j.mark.pim@gmail.com>
2022-01-11 09:02:23 -08:00
Alexander Matyushentsev
27af0b4924 refactor: introduce 'byClusterName' secret index to speedup cluster server URL lookup (#8133)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-10 12:38:44 -08:00
Alexander Matyushentsev
5d1fb9f775 chore: stop publishing image on every commit to dockerhub (#8135)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-10 12:38:26 -08:00
Alexander Matyushentsev
03c5d20d58 fix: fix broken image build and release workflows (#8119)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-10 10:24:23 -08:00
Brad Solomon
3fe924ebd6 docs: Add Deloitte to list of users (#8126) 2022-01-09 20:12:39 -08:00
Alexander Matyushentsev
5da1522b17 chore: build images on PR and conditionally build arm64 image on push (#8108)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-07 13:22:26 -08:00
Avinash Upadhyaya K R
8b57bc990c Provide address flag for admin dashboard command (#8095)
* feat: address flag for admin dashboard

Signed-off-by: Avinash Upadhyaya <avinashupadhya99@gmail.com>

* docs: address flag for admin dashboard

Signed-off-by: Avinash Upadhyaya <avinashupadhya99@gmail.com>
2022-01-06 23:25:38 -08:00
Alexander Matyushentsev
37851b165e refactor: move project filtering to server side (#8102)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-06 09:39:37 -08:00
Michael Crenshaw
722fe9273a chore: fix list depth (#8101)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-01-05 09:15:05 -08:00
icecoffee531
f1d4166a7c docs: Add Gllue to list of users (#8092)
Signed-off-by: icecoffee <2335250710@qq.com>
2022-01-04 23:39:41 -08:00
Mubarak Jama
d00e112791 docs: Add Ibotta to the list of users (#8087)
Signed-off-by: Mubarak Jama <mubarak.jama@gmail.com>
2022-01-04 22:57:46 -08:00
Alexander Matyushentsev
6cd0d97e23 docs: update roadmap document with v2.2 release changes (#8089)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-04 19:10:00 -08:00
Michael Crenshaw
2547176b29 chore: fix typo (#8088)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-01-04 16:00:08 -08:00
Yi Cai
9530b38f7a fix: Trailing line in Filter Dropdown Menus #7821 (#8001)
Signed-off-by: ciiay <yicai@redhat.com>
2022-01-04 11:09:16 -08:00
Sebastián Blázquez
4a55b13d66 docs: fix link (#8080)
Fix link in docs/user-guide/private-repositories.md

Signed-off-by: seblaz <sebastian.blazquez96@gmail.com>
2022-01-03 17:21:10 -08:00
Saumeya Katyal
c0349f3795 fix: network line colors and menu icon alignment (#8059)
* fix: network line colors and menu icon alignment

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

* change color order

Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2022-01-03 16:07:50 -08:00
Alexander Matyushentsev
48d46e395f feat: support specifying cluster by name in addition to API server URL in Cluster API (#8077)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-03 15:26:36 -08:00
Ayrton Araújo Santana
9cb9a380da docs: Newly created Arch Linux package (#8058)
Signed-off-by: Ayrton Santana <ayrton@linux.com>
2022-01-03 14:49:56 -08:00
Thomas Decaux
399d2a830b docs: fix swagger description typo (#8065)
Signed-off-by: Thomas Decaux <ebuildy@gmail.com>
2022-01-03 14:08:07 -08:00
Alexander Matyushentsev
3247090838 feat: store "Group Nodes" button state in application details preferences (#8036)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-03 11:31:12 -08:00
ocraviotto
99d1dcad03 feat: added a new Helm option ignoreMissingValueFiles (#7767) (#8003)
so as to allow operators to prevent Argo CD from passing valueFiles
to helm template if they don't exist in the source under the specified path.

Signed-off-by: Oscar Craviotto <craviotto@avellaneda.com>
2022-01-03 09:51:31 -08:00
Pablo Aguilar
8e6fcde4d6 Add omegaUp to the list of argocd users (#8062) 2022-01-03 09:51:15 -08:00
Gusty Sapto Ady Prakoso
160a4fda5e docs: add Flip to USERS.md (#8070)
Signed-off-by: Gusty Sapto Ady Prakoso <gusty.prakoso@flip.id>
2022-01-03 09:50:58 -08:00
pasha-codefresh
cb1f06c72a 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:09:57 -08:00
plakyda-codefresh
62f29865e7 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:18 -08:00
Saumeya Katyal
ae9abe5175 fix: application-icons-alignment (#8054)
Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2021-12-29 11:17:07 -08:00
pasha-codefresh
b558579f28 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:07:23 -08:00
Alexander Matyushentsev
b3ea0a38bb chore: add argocd-notifications to 'dev' image (#8034)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-27 14:46:56 -08:00
Yi Cai
32838b1f71 fix: adding pagination to grouped nodes sliding panel#7837 (#7915)
fix: adding pagination to grouped nodes sliding panel#7837 (#7915)

Signed-off-by: ciiay <yicai@redhat.com>
2021-12-24 22:08:26 -08:00
Moulick Aggarwal
e822437eb3 chore: bump go-jsonnet to v0.18.0 (#8011)
Signed-off-by: Moulick Aggarwal <moulickaggarwal@gmail.com>
2021-12-24 21:44:28 -08:00
Saumeya Katyal
de582e0bd5 fix: refreshing label toast (#7979)
Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2021-12-23 09:12:50 -08:00
Alexander Matyushentsev
26f83501ad fix: Controller panics if resource manifest has incorrect annotation (#8022)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-23 08:14:06 -08:00
plakyda-codefresh
000f951b9c fix: retry disabled text (#8004)
fix: retry disabled text (#8004)

Signed-off-by: viktorplakida <plakyda1@gmail.com>
2021-12-22 11:40:11 -08:00
Yi Cai
129e9ea89e fix: Grouped node list missing resources on Compact resources view #8014 (#8018)
Signed-off-by: ciiay <yicai@redhat.com>
2021-12-22 11:38:55 -08:00
Regina Scott
d1d82c6d6f feat: add visual indicator for newly created pods (#8006)
Signed-off-by: Regina Scott <rescott@redhat.com>
2021-12-22 11:26:36 -08:00
Niklas Steiner
d8c3113c06 fix: Opening app details shows UI error on some apps (#8016) (#8019)
Signed-off-by: Niklas Steiner <niklas@sbg.at>
2021-12-22 11:06:11 -08:00
Leonardo Luz Almeida
7bac2c151a fix: Inconsistent normalization logic during diff (#7980)
fix: Inconsistent normalization logic during diff (#7980)

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2021-12-22 08:57:48 -08:00
Yi Cai
800b1093e7 fix: Nested Refresh dropdown does not work on Application Details page #1524 (#7950)
* fix: Nested Refresh dropdown does not work on Application Details page #1524

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

* Removed unnecessary changes

Signed-off-by: ciiay <yicai@redhat.com>
2021-12-22 14:10:28 +01:00
jannfis
18f7b416a8 chore: Some minor changes to the docs linter (#7996)
chore: Some minor changes to the docs linter (#7996)

Signed-off-by: jannfis <jann@mistrust.net>
2021-12-21 09:22:54 -08:00
Jesse Suen
63dfc78917 fix: remove vendor dependency in virtualized toolchain (#8000)
Signed-off-by: Jesse Suen <jesse@akuity.io>
2021-12-20 17:24:27 -08:00
Alexander Matyushentsev
487db973d3 fix: correctly handle project field during partial cluster update (#7994)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-20 12:52:34 -08:00
Clive Jevons
fcaa8abd01 feat: enable specifying root ca for oidc (#6712)
When configuring an external OIDC provider which uses a private PKI
for its certificates it was not possible to properly verify the certificate
being served. Also, when using ArgoCD in insecure mode, e.g. when running
behind istio for providing mTLS, this resulted in errors.

Signed-off-by: Clive Jevons <clive@jevons-it.net>
2021-12-20 09:57:20 +01:00
Didrik Finnøy
e32c07007c docs: Helm plugins via initContainers (#7815)
* Docs: Helm plugins via initContainers

Related: #7066

Include an alternative method for installing Helm plugins that don't require users to maintain their own version of the ArgoCD container image.

Signed-off-by: Didrik Finnøy <djfinnoy@protonmail.com>

* add codeblock

Signed-off-by: Didrik Finnøy <djfinnoy@protonmail.com>

* change helm repo name in example code

Signed-off-by: Didrik Finnøy <djfinnoy@protonmail.com>
2021-12-19 20:43:02 +01:00
Zadkiel
e50d03eb61 fix(ui): use consistent case for diff modes (#7945)
Signed-off-by: GitHub <noreply@github.com>
2021-12-19 19:54:00 +01:00
Michael Crenshaw
e15c8a58a6 docs: Add a link to docs/operator-manual/security.md from root-level security.md (#7840)
* docs: add a link from the base security doc to the operator manual security page

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

* chore: better copy

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

* chore: bump doc version

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2021-12-19 19:53:08 +01:00
Michael Crenshaw
3bd8688004 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-19 17:09:36 +01:00
Michael Crenshaw
ad1ed1d51b chore: add target revision tests (#7963)
* fix: add nil check, add revision tests, add docs about webhook behavior

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

* chore: move single-use function into test

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

* chore: add comment about why some tests are absent

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

* chore: fix text names

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2021-12-17 13:33:57 -08:00
Michael Crenshaw
914fb8337e fix: webhook URL matching edge cases (#7981)
* fix: webhook URL matching edge cases

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

* docs: docstring

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

* chore: lint

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

* chore: move logging to non-utility function

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2021-12-17 20:47:55 +01:00
Alexander Matyushentsev
0676b65f7e fix: add aws cli into final argocd image (#7973)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-16 18:46:59 -08:00
Michael Crenshaw
2e494689cd chore: lint docs + CI job (#7959)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2021-12-16 15:52:18 -08:00
Shyukri Shyukriev
561a44d0a8 chore: upgrade awscli to 2.4.6 and remove python deps (#7947)
Remove python3-pip and deps
Use hack/installers since AWS doesn't provide pip packages for v2

Side effect: image downsize 842 MB -> 483MB

Signed-off-by: Shyukri Shyukriev <shyukri.shyukriev@mariadb.com>
2021-12-16 15:37:10 -08:00
Jesse Suen
63e70a9f71 chore: portable and simpler toolchain install (#7920)
Signed-off-by: Jesse Suen <jesse@akuity.io>
2021-12-16 15:16:36 -08:00
Alexander Matyushentsev
656f790aed 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 14:42:29 -08:00
Alexander Matyushentsev
7f09331e3f fix: notifications controller manifests shuold use argocd image (#7970)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-16 13:58:42 -08:00
pasha-codefresh
f9ba9e9811 fix: issue with headless installation (#7958)
fix: issue with headless installation (#7958)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-12-16 10:17:16 -08:00
jomenxiao
17c6daa9ea fix: targetervision compatible without prefix refs/heads or refs/tags (#7939)
fix: targetervision compatible without prefix refs/heads or refs/tags (#7939)

Signed-off-by: jomen.xiao <jomenxiao@gmail.com>
2021-12-15 10:56:31 -08:00
Alexander Matyushentsev
f89d40c9e0 fix: add missing notifications base to Argo CD HA (#7934)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-14 15:22:32 -08:00
Xabier Larrakoetxea Gallego
6a1472371f Fix Kubernetes labels normalization for Prometheus (#7925)
* When adding Kubernetes labels as Prometheus labels, replace with  all the invalid Prometheus label chars

Signed-off-by: Xabier Larrakoetxea <me@slok.dev>

* Add Fonoa company to users doc

Signed-off-by: Xabier Larrakoetxea <me@slok.dev>

* Add comment and link to the Prometheus label valid characters

Signed-off-by: Xabier Larrakoetxea <me@slok.dev>
2021-12-14 12:38:25 -08:00
Alexander Matyushentsev
3ea2ba06f5 docs: update CHANGELOG: mention v2.2.0 release and v2.1.8 releases (#7930)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-14 12:28:08 -08:00
Leonardo Luz Almeida
29a6be4afe Feat: Ignore differences owned by trusted managers from managedFields (#7869)
* feat: implement managed fields normalizer

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2021-12-14 10:49:55 -08:00
Saumeya Katyal
bed36e2027 fix: add all resources in list view (#7295)
* fix: add all resources in list view

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

add resources from applicationTree

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

minor spacing fixes

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

changes

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

* merge conflicts and improvement

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

* change variable name

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

* review comments

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

* lint-fix

Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2021-12-14 09:32:54 +01:00
Jesse Suen
9ff7c0b9c7 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:39:25 -08:00
May Zhang
cf78fe429a fix: during import, if stop-operation flag is provided, then nil oper… (#7916)
* fix: during import, if stop-operation flag is provided, then nil operation field of application

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

* fix: during import, if stop-operation flag is provided, then nil operation field of application

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

* run goimports -local

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

* updated docs

Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-12-13 15:30:43 -08:00
Yi Cai
5b17fc36d4 feat: Added toggle button for compact view #7836 (#7900)
feat: Added toggle button for compact view #7836 (#7900)

Signed-off-by: ciiay <yicai@redhat.com>
2021-12-13 13:39:57 -08:00
Alexander Matyushentsev
5978dfa167 fix: resource tracking normalization should not always drop old label (#7911)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-13 08:25:46 -08:00
Sho Iizuka
ddb90ab496 docs: fix flag name to use external variables in Jsonnet (#7659)
Signed-off-by: sho-iizuka <sho-iizuka@cybozu.co.jp>
2021-12-12 23:47:34 -08:00
Alexander Matyushentsev
0a792fefac fix: resource tracking normalization shuold drop empty labels (#7909)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-11 11:16:45 -08:00
jomenxiao
e48350756b fix nil point (#7905)
Signed-off-by: jomenxiao <jomenxiao@gmail.com>
2021-12-10 21:23:37 -08:00
Alexander Matyushentsev
6d8ff61b16 fix: improve migration from label to annotation tracking (#7899)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-10 16:14:38 -08:00
Michael Weibel
238ff275c4 docs: add Helio (#7902)
Signed-off-by: Michael Weibel <michael@helio.exchange>
2021-12-10 15:20:42 -08:00
Saumeya Katyal
7eccd21b47 fix: css warning icon color change (#7903)
Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2021-12-10 14:06:11 -08:00
Keith Chong
c9ddaabf08 fix: Event timestamp incorrectly shows unix epoch (#7879) (#7892)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2021-12-10 10:32:56 -08:00
May Zhang
a51169e8c0 fix: Cluster API does not support updating labels and annotations (#7901)
Signed-off-by: May Zhang <may_zhang@intuit.com>
2021-12-09 16:39:34 -08:00
Alexander Matyushentsev
bea379b036 refactor: add indexes to secret informers to speedup settings parsing (#7882)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-07 14:15:11 -08:00
jannfis
b813301ed6 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-07 12:59:25 -08:00
Alan Clucas
458a10310c docs: Add argocd-vault-replacer (#7814)
Adding argocd-vault-replacer as another hashicorp vault tool with different abilities from the IBM version. Primary differences:
* Ability to use kubernetes authentication
* Textual replacement rather than understanding the YAML so secrets can be anywhere, not just in limited locations.
* Ability to process the secrets into other forms (e.g. base64 encode)

Signed-off-by: Alan Clucas <alan@clucas.org>

Co-authored-by: jannfis <jann@mistrust.net>
2021-12-07 15:37:11 +01:00
Alexandre Gaudreault
6221ef20af feat(health): support of external-secrets.io/ExternalSecret (#7798)
* feat(health): support of external-secrets.io/ExternalSecret

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

* move to folder

Signed-off-by: Alexandre Gaudreault <alexandre.gaudreault@logmein.com>
2021-12-07 14:47:47 +01:00
pasha-codefresh
2087eaa4c7 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-07 14:05:23 +01:00
Saumeya Katyal
7d59cbb5be fix: css change for clear button in filters (#7868)
Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2021-12-06 15:44:39 -08:00
pasha-codefresh
dae43a23f9 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-06 10:16:14 -08:00
Alexander Matyushentsev
78e256eef3 fix: fix UI build failure: use correct monaco editor setting name (#7856)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-03 14:29:51 -08:00
Alexander Matyushentsev
ccd15d1151 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:18 -08:00
Alexander Matyushentsev
05935a9d7e refactor: avoid loading project in frequently executed controller methods (#7853)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-03 13:18:08 -08:00
Jacob Wernette
891d9b2f38 docs: update argocd-vault-plugin repo (#7834)
Signed-off-by: Jacob Wernette <werne2j@gmail.com>
2021-12-02 09:26:26 -08:00
Chetan Banavikalmutt
0f845a0416 fix: admin dashboard doesn't use the right context (#7826)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2021-12-02 08:38:06 -08:00
Yuan Tang
a456a92493 build: Disable non-testing CI builds on forks (#7832)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-12-02 08:37:45 -08:00
Alexander Matyushentsev
e967f8836a fix: resource custom actions are not visible in resource actions dropdown (#7823)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-12-02 08:31:19 -08:00
Yi Cai
a8ed010921 feat: Compact application resources tree #7349 (#7632)
* feat: Compact application resources tree #7349 #7632

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

* Updates for comments

Signed-off-by: ciiay <yicai@redhat.com>
2021-12-02 08:01:03 -08:00
Yi Cai
0c352f8bd6 feat: add refresh/hard refresh apps button #7256 (#7411)
feat: add refresh/hard refresh apps button #7256 (#7411)

Signed-off-by: ciiay <yicai@redhat.com>
2021-12-01 15:28:48 -08:00
Regina Scott
e81f25026d feat: add quick-start buttons (#7292)
Signed-off-by: Regina Scott <rescott@redhat.com>
2021-12-01 15:21:33 -08:00
Phil Wright- Christie
cd497c4eec Fix secret key name (#7763) 2021-12-01 14:27:06 -08:00
Jonas Janz
7490ee483e docs: mention finalizer in app-of-apps doc (#7753)
* docs: mention finalizer in app-of-apps doc

As it's easy to overlook the need for a specific finalizer in the Application CR to ensure cascading deletion I added an extra section describing the need and linking to the ArgoCD Docs for further information about App deletion.

Signed-off-by: PixelJonas <5434875+PixelJonas@users.noreply.github.com>

* doc: fix typo in cluster-bootstrappring docs

small typo fix

Signed-off-by: PixelJonas <5434875+PixelJonas@users.noreply.github.com>
2021-12-01 14:26:29 -08:00
pasha-codefresh
ced5c1deed fix: notifications link (#7807)
fix: notifications link (#7807)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-12-01 14:15:48 -08:00
Yuan Tang
b977813e9a docs: Add 2.2-2.3 upgrading notes on ArgoCD binaries (#7812)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-12-01 09:42:34 -08:00
pasha-codefresh
a2f97af2e4 feat: resolve sync window for cluster name also, not only server (#7817)
* resolve sync window for clsuter name also, not only server

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-12-01 08:58:51 -08:00
pasha-codefresh
6b4a13c4bd feat: ToUpper and ToLower expression (#7816)
* ToUpper and ToLower expression

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-12-01 08:58:11 -08:00
ln3333
d64014364c fix: SyncWindow link not honoring basehref (#7811)
* fix SyncWindow link when using baseherf

Signed-off-by: ln3333 <liangxu@outlook.com>

* fix: SyncWindow link not honoring basehref

Signed-off-by: ln3333 <liangxu@outlook.com>
2021-11-30 14:10:11 -08:00
Alexander Matyushentsev
0f75eecbd2 chore: increase e2e tests timeout (#7803)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-30 10:58:43 -08:00
Márk Sági-Kazár
335becebb1 docs: add Cisco ETI to users (#7808)
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-11-30 10:58:29 -08:00
Alexander Matyushentsev
d89c708399 refactor: upgrade casbin to latest stable version (v2.39.1) (#7802)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-30 10:51:05 -08:00
Yuan Tang
d8cfafbd92 feat: Configurable ArgoCD binary download links on Help page. Fixes #7698 (#7755)
feat: Configurable ArgoCD binary download links on Help page. Fixes #7698 (#7755)

Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-11-30 10:10:43 -08:00
Marco Kilchhofer
394a2c8318 docs: Add Swiss Post to USERS.md (#7771)
Signed-off-by: Marco Kilchhofer <marco.kilchhofer.2@post.ch>
2021-11-30 10:03:05 -08:00
pasha-codefresh
faee047081 fix: flaky test (#7809)
* fix flaky test

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

* fix flaky test

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

* fix linter

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

* empty commit

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-11-30 09:54:42 -08:00
Takumasa Sakao
a05a2633ba docs: Fix invalid example manifest (#7792)
Signed-off-by: Takumasa Sakao <tsakao@zlab.co.jp>
2021-11-30 09:52:41 -08:00
pasha-codefresh
0f2f9a97e3 feat: Migrate argocd notifications to argocd (#7744)
feat: Migrate argocd notifications to argocd (#7744)

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-11-29 18:47:46 -08:00
Moshe Avni
d346fceea9 Add critical part-of label (#7642) 2021-11-29 15:36:00 -08:00
Ardi Mehist
b40508323b Add Nitro to users list (#7789) 2021-11-29 14:26:01 -08:00
Greg
8851842d8e docs: update users in order to add Casavo (#7777)
Signed-off-by: Alessandro Gregori <alessandro.gregori@casavo.com>
2021-11-29 02:43:09 -08:00
pasha-codefresh
70a08a0aa6 chore: Remove deprecated action from CI (#7785)
* 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>

* update python version

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

* remove gh pages step

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

* remove gh pages step

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-11-26 13:01:56 +01:00
Jesse Suen
9cb9ef6752 fix: env vars to tune cluster cache were broken (#7779)
Signed-off-by: Jesse Suen <jesse@akuity.io>
2021-11-24 18:16:46 -08:00
Alexander Matyushentsev
23967f8717 Revert "chore: upgrade node-sass (#7631)" (#7765)
This reverts commit 012268d619.

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-22 09:36:16 -08:00
Gyorgy Hrabovszki
475bea599d docs: Add Allianz Direct to ArgoCD users (#7751)
Signed-off-by: Gyorgy Hrabovszki <gyoergy.hrabovszki@allianzdirect.de>
2021-11-19 21:36:05 -08:00
Yuan Tang
8e8a1ded27 build!: Remove non-Linux binaries from the image and fix image building on Mac ARM (#7668)
* build: Support image building on Mac ARM

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

* Pass GOOS and GOARCH explicitly

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

* Retrigger CI pipeline

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

* Remove windows and mac binaries in the image

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

* Update download handler registration

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

* Inject arch to env var via webpack

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

* Fix lint

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

* Add BUILD_ALL_CLIS env flag for make release-cli

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

* Run in release-cli target directly

Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2021-11-18 21:42:14 -08:00
Alexander Matyushentsev
0c0bc1f769 refactor: use cached project while calculating resource tree (#7747)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-18 15:45:19 -08:00
Alexander Matyushentsev
8bbf8887d2 docs: add v2.2 changelog (#7681)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-11-18 08:41:49 -08:00
Remington Breeze
012268d619 chore: upgrade node-sass (#7631)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-11-18 08:40:48 -08:00
Matteo Ruina
af3fb9a4d0 docs: Add Skyscanner as ArgoCD user (#7730)
Signed-off-by: Matteo Ruina <matteo.ruina@gmail.com>
2021-11-18 08:13:06 -08:00
Kostis (Codefresh)
2370164c98 docs: clarify Helm application deployment (#7713)
Signed-off-by: Kostis Kapelonis <kostis@codefresh.io>
2021-11-17 07:51:06 -08:00
Mark Sarcevicz
18a1b07d1a 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-16 22:49:21 -08:00
Michael Crenshaw
fafa79fac1 feat: add health check for applicationset (#7695)
Signed-off-by: Michael Crenshaw <michael_crenshaw@intuit.com>
2021-11-16 16:54:26 -08:00
Oscar
8a5b34581a feat: only ask for confirmation when creating argocd-manager service account (#7720)
Signed-off-by: Oscar Chen <oscar.chen.btw@gmail.com>
2021-11-16 16:51:30 -08:00
Keith Chong
27928d0dc6 fix: Use binary units in pod view (#7649) (#7726)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2021-11-16 16:13:16 -08:00
Remington Breeze
0c91f65e67 chore(ui): Switch to esbuild instead of ts-loader for performance (#7336)
Signed-off-by: Remington Breeze <remington@breeze.software>
2021-11-16 13:00:52 -08:00
Jan Domanski
09c5d5f42a Add Devopsi Company (#7687)
Adding my software house company
2021-11-12 08:59:55 -08:00
642 changed files with 58963 additions and 4702 deletions

View File

@@ -6,7 +6,7 @@ labels: 'bug'
assignees: ''
---
If you are trying to resolve an environment-specific issue or have a one-off question about the edge case that does not require a feature then please consider asking a question in argocd slack [channel](https://argoproj.github.io/community/join-slack).
<!-- If you are trying to resolve an environment-specific issue or have a one-off question about the edge case that does not require a feature then please consider asking a question in argocd slack [channel](https://argoproj.github.io/community/join-slack). -->
Checklist:
@@ -16,19 +16,19 @@ Checklist:
**Describe the bug**
A clear and concise description of what the bug is.
<!-- A clear and concise description of what the bug is. -->
**To Reproduce**
A list of the steps required to reproduce the issue. Best of all, give us the URL to a repository that exhibits this issue.
<!-- A list of the steps required to reproduce the issue. Best of all, give us the URL to a repository that exhibits this issue. -->
**Expected behavior**
A clear and concise description of what you expected to happen.
<!-- A clear and concise description of what you expected to happen. -->
**Screenshots**
If applicable, add screenshots to help explain your problem.
<!-- If applicable, add screenshots to help explain your problem. -->
**Version**

View File

@@ -12,19 +12,9 @@ on:
env:
# Golang version to use across CI steps
GOLANG_VERSION: '1.16.5'
GOLANG_VERSION: '1.17.6'
jobs:
build-docker:
name: Build Docker image
runs-on: ubuntu-latest
if: github.head_ref != ''
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Build Docker image
run: |
make image
check-go:
name: Ensure Go modules synchronicity
runs-on: ubuntu-latest
@@ -264,6 +254,7 @@ jobs:
env:
NODE_ENV: production
NODE_ONLINE_ENV: online
HOST_ARCH: amd64
working-directory: ui/
- name: Run ESLint
run: yarn lint
@@ -340,7 +331,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
k3s-version: [v1.21.2, v1.20.2, v1.19.2, v1.18.9, v1.17.11]
k3s-version: [v1.23.3, v1.22.6, v1.21.2]
needs:
- build-go
env:
@@ -385,10 +376,13 @@ jobs:
- name: Add /usr/local/bin to PATH
run: |
echo "/usr/local/bin" >> $GITHUB_PATH
- name: Add ./dist to PATH
run: |
echo "$(pwd)/dist" >> $GITHUB_PATH
- name: Download Go dependencies
run: |
go mod download
go get github.com/mattn/goreman
go install github.com/mattn/goreman@latest
- name: Install all tools required for building & testing
run: |
make install-test-tools-local
@@ -400,7 +394,7 @@ jobs:
run: |
docker pull quay.io/dexidp/dex:v2.25.0
docker pull argoproj/argo-cd-ci-builder:v1.0.0
docker pull redis:6.2.4-alpine
docker pull redis:6.2.6-alpine
- name: Create target directory for binaries in the build-process
run: |
mkdir -p dist

View File

@@ -8,6 +8,7 @@ on:
jobs:
CodeQL-Build:
if: github.repository == 'argoproj/argo-cd'
# CodeQL runs on ubuntu-latest and windows-latest
runs-on: ubuntu-latest

View File

@@ -1,23 +0,0 @@
name: Deploy
on:
push:
branches:
- master
pull_request:
branches:
- 'master'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Setup Python
uses: actions/setup-python@v1
with:
python-version: 3.9.8
- name: build
run: |
pip install -r docs/requirements.txt
mkdocs build

View File

@@ -4,12 +4,17 @@ on:
push:
branches:
- master
pull_request:
branches:
- master
types: [ labeled, unlabeled, opened, synchronize, reopened ]
env:
GOLANG_VERSION: '1.16.5'
GOLANG_VERSION: '1.17.6'
jobs:
publish:
if: github.repository == 'argoproj/argo-cd'
runs-on: ubuntu-latest
env:
GOPATH: /home/runner/work/argo-cd/argo-cd
@@ -26,28 +31,36 @@ jobs:
working-directory: ./src/github.com/argoproj/argo-cd
id: image
# build
- run: |
docker images -a --format "{{.ID}}" | xargs -I {} docker rmi {}
make image DEV_IMAGE=true DOCKER_PUSH=false IMAGE_NAMESPACE=ghcr.io/argoproj IMAGE_TAG=${{ steps.image.outputs.tag }}
working-directory: ./src/github.com/argoproj/argo-cd
# publish
# login
- run: |
docker login ghcr.io --username $USERNAME --password $PASSWORD
docker push ghcr.io/argoproj/argocd:${{ steps.image.outputs.tag }}
docker login --username "${DOCKER_USERNAME}" --password "${DOCKER_TOKEN}"
docker tag ghcr.io/argoproj/argocd:${{ steps.image.outputs.tag }} argoproj/argocd:latest
docker push argoproj/argocd:latest
docker login quay.io --username "${DOCKER_USERNAME}" --password "${DOCKER_TOKEN}"
if: github.event_name == 'push'
env:
USERNAME: ${{ secrets.USERNAME }}
PASSWORD: ${{ secrets.TOKEN }}
DOCKER_USERNAME: ${{ secrets.RELEASE_DOCKERHUB_USERNAME }}
DOCKER_TOKEN: ${{ secrets.RELEASE_DOCKERHUB_TOKEN }}
DOCKER_USERNAME: ${{ secrets.RELEASE_QUAY_USERNAME }}
DOCKER_TOKEN: ${{ secrets.RELEASE_QUAY_TOKEN }}
# build
- uses: docker/setup-qemu-action@v1
- uses: docker/setup-buildx-action@v1
- run: |
IMAGE_PLATFORMS=linux/amd64
if [[ "${{ github.event_name }}" == "push" || "${{ contains(github.event.pull_request.labels.*.name, 'test-arm-image') }}" == "true" ]]
then
IMAGE_PLATFORMS=linux/amd64,linux/arm64
fi
echo "Building image for platforms: $IMAGE_PLATFORMS"
docker buildx build --platform $IMAGE_PLATFORMS --push="${{ github.event_name == 'push' }}" \
-t ghcr.io/argoproj/argocd:${{ steps.image.outputs.tag }} \
-t quay.io/argoproj/argocd:latest .
working-directory: ./src/github.com/argoproj/argo-cd
# deploy
- run: git clone "https://$TOKEN@github.com/argoproj/argoproj-deployments"
if: github.event_name == 'push'
env:
TOKEN: ${{ secrets.TOKEN }}
- run: |
@@ -55,5 +68,6 @@ jobs:
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)
if: github.event_name == 'push'
working-directory: argoproj-deployments/argocd
# TODO: clean up old images once github supports it: https://github.community/t5/How-to-use-Git-and-GitHub/Deleting-images-from-GitHub-Package-Registry/m-p/41202/thread-id/9811

View File

@@ -12,11 +12,12 @@ on:
- '!release-v0*'
env:
GOLANG_VERSION: '1.16.5'
GOLANG_VERSION: '1.17.6'
jobs:
prepare-release:
name: Perform automatic release on trigger ${{ github.ref }}
if: github.repository == 'argoproj/argo-cd'
runs-on: ubuntu-latest
env:
# The name of the tag as supplied by the GitHub event
@@ -94,7 +95,7 @@ jobs:
echo "=========== BEGIN COMMIT MESSAGE ============="
git show ${SOURCE_TAG}
echo "============ END COMMIT MESSAGE =============="
# Quite dirty hack to get the release notes from the annotated tag
# into a temporary file.
RELEASE_NOTES=$(mktemp -p /tmp release-notes.XXXXXX)
@@ -141,7 +142,7 @@ jobs:
echo "RELEASE_NOTES=${RELEASE_NOTES}" >> $GITHUB_ENV
- name: Setup Golang
uses: actions/setup-go@v1
uses: actions/setup-go@v2
with:
go-version: ${{ env.GOLANG_VERSION }}
@@ -182,18 +183,7 @@ jobs:
echo "Creating release ${RELEASE_TAG}"
git tag ${RELEASE_TAG}
- name: Build Docker image for release
run: |
set -ue
git clean -fd
mkdir -p dist/
make image IMAGE_TAG="${TARGET_VERSION}" DOCKER_PUSH=false
make release-cli
chmod +x ./dist/argocd-linux-amd64
./dist/argocd-linux-amd64 version --client
if: ${{ env.DRY_RUN != 'true' }}
- name: Push docker image to repository
- name: Login to docker repositories
env:
DOCKER_USERNAME: ${{ secrets.RELEASE_DOCKERHUB_USERNAME }}
DOCKER_TOKEN: ${{ secrets.RELEASE_DOCKERHUB_TOKEN }}
@@ -202,11 +192,22 @@ jobs:
run: |
set -ue
docker login quay.io --username "${QUAY_USERNAME}" --password "${QUAY_TOKEN}"
docker push ${IMAGE_NAMESPACE}/argocd:v${TARGET_VERSION}
# Remove the following when Docker Hub is gone
docker login --username "${DOCKER_USERNAME}" --password "${DOCKER_TOKEN}"
docker tag ${IMAGE_NAMESPACE}/argocd:v${TARGET_VERSION} argoproj/argocd:v${TARGET_VERSION}
docker push argoproj/argocd:v${TARGET_VERSION}
if: ${{ env.DRY_RUN != 'true' }}
- uses: docker/setup-qemu-action@v1
- uses: docker/setup-buildx-action@v1
- name: Build and push Docker image for release
run: |
set -ue
git clean -fd
mkdir -p dist/
docker buildx build --platform linux/amd64,linux/arm64 --push -t ${IMAGE_NAMESPACE}/argocd:v${TARGET_VERSION} -t argoproj/argocd:v${TARGET_VERSION} .
make release-cli
chmod +x ./dist/argocd-linux-amd64
./dist/argocd-linux-amd64 version --client
if: ${{ env.DRY_RUN != 'true' }}
- name: Read release notes file
@@ -244,6 +245,17 @@ jobs:
asset_content_type: application/octet-stream
if: ${{ env.DRY_RUN != 'true' }}
- name: Upload argocd-linux-arm64 binary to release assets
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./dist/argocd-linux-arm64
asset_name: argocd-linux-arm64
asset_content_type: application/octet-stream
if: ${{ env.DRY_RUN != 'true' }}
- name: Upload argocd-darwin-amd64 binary to release assets
uses: actions/upload-release-asset@v1
env:
@@ -255,6 +267,17 @@ jobs:
asset_content_type: application/octet-stream
if: ${{ env.DRY_RUN != 'true' }}
- name: Upload argocd-darwin-arm64 binary to release assets
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./dist/argocd-darwin-arm64
asset_name: argocd-darwin-arm64
asset_content_type: application/octet-stream
if: ${{ env.DRY_RUN != 'true' }}
- name: Upload argocd-windows-amd64 binary to release assets
uses: actions/upload-release-asset@v1
env:
@@ -266,6 +289,48 @@ jobs:
asset_content_type: application/octet-stream
if: ${{ env.DRY_RUN != 'true' }}
- name: Generate SBOM (spdx)
id: spdx-builder
env:
# defines the spdx/spdx-sbom-generator version to use.
SPDX_GEN_VERSION: v0.0.13
# defines the sigs.k8s.io/bom version to use.
SIGS_BOM_VERSION: v0.2.1
# comma delimited list of project relative folders to inspect for package
# managers (gomod, yarn, npm).
PROJECT_FOLDERS: ".,./ui"
# full qualified name of the docker image to be inspected
DOCKER_IMAGE: ${{env.IMAGE_NAMESPACE}}/argocd:v${{env.TARGET_VERSION}}
run: |
yarn install --cwd ./ui
go install github.com/spdx/spdx-sbom-generator/cmd/generator@$SPDX_GEN_VERSION
go install sigs.k8s.io/bom/cmd/bom@$SIGS_BOM_VERSION
# Generate SPDX for project dependencies analyzing package managers
for folder in $(echo $PROJECT_FOLDERS | sed "s/,/ /g")
do
generator -p $folder -o /tmp
done
# Generate SPDX for binaries analyzing the docker image
if [[ ! -z $DOCKER_IMAGE ]]; then
bom generate -o /tmp/bom-docker-image.spdx -i $DOCKER_IMAGE
fi
cd /tmp && tar -zcf sbom.tar.gz *.spdx
if: ${{ env.DRY_RUN != 'true' }}
- name: Upload SBOM to release assets
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: /tmp/sbom.tar.gz
asset_name: sbom.tar.gz
asset_content_type: application/octet-stream
if: ${{ env.DRY_RUN != 'true' }}
- name: Update homebrew formula
env:
HOMEBREW_TOKEN: ${{ secrets.RELEASE_HOMEBREW_TOKEN }}
@@ -280,3 +345,4 @@ jobs:
set -ue
git push --delete origin ${SOURCE_TAG}
if: ${{ always() }}

2
.gitpod.Dockerfile vendored
View File

@@ -9,7 +9,7 @@ RUN curl -L https://go.kubebuilder.io/dl/2.3.1/$(go env GOOS)/$(go env GOARCH) |
tar -xz -C /tmp/ && mv /tmp/kubebuilder_2.3.1_$(go env GOOS)_$(go env GOARCH) /usr/local/kubebuilder
RUN apt-get install redis-server -y
RUN go get github.com/mattn/goreman
RUN go install github.com/mattn/goreman@latest
USER gitpod

View File

@@ -2,5 +2,5 @@ image:
file: .gitpod.Dockerfile
tasks:
- init: make mod-download-local dep-ui-local && GO111MODULE=off go get github.com/mattn/goreman
- init: make mod-download-local dep-ui-local && GO111MODULE=off go install github.com/mattn/goreman@latest
command: make start-test-k8s

View File

@@ -1,5 +1,224 @@
# Changelog
## v2.3.0 (Unreleased)
### Argo CD ApplicationSet and Notifications are now part of Argo CD
Two popular [Argoproj Labs](https://github.com/argoproj-labs) projects [Argo CD ApplicationSet](https://github.com/argoproj/applicationset) and
[Argo CD Notifications](https://github.com/argoproj-labs/argocd-notifications) are now part of Argo CD! The default Argo CD installation manifests now
bundle both projects out of the box. Going forward you can expect more tightened integration of these projects into Argo CD.
### New sync and diff strategies
Users can now configure the Application resource to instruct Argo CD to consider the ignore difference setup during the sync process.
In order to do so, add the new sync option RespectIgnoreDifferences=true in the Application resource. Once the sync option is added,
Argo CD won't change ignored fields during the syncing process.
Configuring ignored fields is also easier now. Instead of listing fields one by one users can now leverage the
managedFields metadata to instruct Argo CD about trusted managers and automatically ignore any fields owned by them. A new diff customization
(managedFieldsManagers) is now available allowing users to specify managers the application should trust and to ignore all fields owned by those managers.
Read more about these changes at [New sync and diff strategies in ArgoCD](https://blog.argoproj.io/new-sync-and-diff-strategies-in-argocd-44195d3f8b8c) blog post.
### ARM Images
An officially supported ARM 64 image is now available. Enjoy running Argo CD on your Raspberry Pi! Additionally, the image size was reduced by nearly ~50%
and is only 200MB now. The ARM version of `argocd` CLI is also available and published as a Github release artifact.
### Compact Tree View And Click Application Navigation
The application details page now supports compact application resources tree visualization. Using the "Group Nodes" button, you can collapse the similar resources
into a single group node to remove the clutter and make it easier to understand the state of application resources. You still can get detailed information about the collapsed resources by clicking on the group node. The list of collapsed resources will be available in a sliding panel. Compact resource tree is still too big?
You can use the zoom in and zoom out feature to make it smaller - or even larger!
You no longer need to move back and forth between the application details page and the application list page. Instead you can navigate directly to the required application by clicking the search icon in the application details page title.
### Upgraded Config Management Tools
Both bundled Helm and Kustomize binaries have been upgraded to the latest versions. Kustomize has been upgraded from 4.2.0 to 4.4.1 and Helm has been upgraded from 3.7.1 to 3.8.0.
### Bug Fixes and Performance Enhancements
* Config management tools enhancements:
* The skipCrds flag and ability to ignore missing values files for Helm (#8012, #8003)
* Additional environment variables for Kustomize (#8096)
* Argo CD CLI follows the XDG Base directory standard (#7638)
* Redis is no longer used during SSO login (#8241)
### Features
- feat: Add app list and details page views to navigation history (#7776) (#7937)
- feat: Add skipCrds flag for helm charts (#8012)
- feat: Add visual indicator for newly created pods (#8006)
- feat: Added a new Helm option ignoreMissingValueFiles (#7767) (#8003)
- feat: Allow configuring system wide ignore differences for all resources (#8224)
- feat: Allow escaping dollar in Envsubst (#7961)
- feat: Allow external links on Application (#3487) (#8231)
- feat: Allow selecting application on detail page (#8176)
- feat: Bundle applicationset-controller with argocd (#8148)
- feat: Enable specifying root ca for oidc (#6712)
- feat: Expose ARGOCD_APP_NAME to the `kustomize build` command (#8096)
- feat: Ignore differences owned by trusted managers from managedFields (#7869)
- feat: New sync option to use ignore diff configs during sync (#8078)
- feat: Provide address flag for admin dashboard command (#8095)
- feat: Store "Group Nodes" button state in application details preferences (#8036)
- feat: Support specifying cluster by name in addition to API server URL in Cluster API (#8077)
- feat: Support XDG Base directory standard (#7638) (#7791)
- feat: Use encrypted cookie to store OAuth2 state nonce (instead of redis) (#8241)
- feat: Build images on PR and conditionally build arm64 image on push (#8108)
### Bug Fixes
- fix: Add "Restarting MinIO" status to MiniO Tenant health check (#8191)
- fix: Add all resources in list view (#7295)
- fix: Adding pagination to grouped nodes sliding panel#7837 (#7915)
- fix: Allow all resources to add external links (#7923)
- fix: Always call ValidateDestination (#7976)
- fix: Application exist panic when execute api call (#8188)
- fix: Application-icons-alignment (#8054)
- fix: Controller panics if resource manifest has incorrect annotation (#8022)
- fix: Correctly handle project field during partial cluster update (#7994)
- fix: Default value for retry validation #8055 (#8064)
- fix: Fix a possible crash when parsing RBAC (#8165)
- fix: Grouped node list missing resources on Compact resources view #8014 (#8018)
- fix: Issue with headless installation (#7958)
- fix: Issue with project scoped resources (#8048)
- fix: Kubernetes labels normalization for Prometheus (#7925)
- fix: Nested Refresh dropdown does not work on Application Details page #1524 (#7950)
- fix: Network line colors and menu icon alignment (#8059)
- fix: Opening app details shows UI error on some apps (#8016) (#8019)
- fix: Parse to correct uint32 type (#8177)
- fix: Prevent possible nil-pointer deref in normalizer (#8185)
- fix: Prevent possible out-of-bounds access when loading policies (#8186)
- fix: Provide a semantic version parsed version for KUBE_VERSION (#8250)
- fix: Refreshing label toast (#7979)
- fix: Resource details page crashes when resource is not deployed and hide managed fields is selected (#7971)
- fix: Retry disabled text (#8004)
- fix: Route health check stuck in 'Progressing' (#8170)
- fix: Sync window panel is crashed if resource name not contain letters (#8053)
- fix: Targetervision compatible without prefix refs/heads or refs/tags (#7939)
- fix: Trailing line in Filter Dropdown Menus #7821 (#8001)
- fix: Webhook URL matching edge cases (#7981)
- fix(ui): Use consistent case for diff modes (#7945)
- fix: Use gRPC timeout for sidecar CMPs (#8131) (#8236)
### Other
- chore: Bump go-jsonnet to v0.18.0 (#8011)
- chore: Escape proj in regex (#7985)
- chore: Exclude argocd-server rbac for core-install (#8234)
- chore: Log out the resource triggering reconciliation (#8192)
- chore: Migrate to use golang-jwt/jwt v4.2.0 (#8136)
- chore: Move resolveRevision from api-server to repo-server (#7966)
- chore: Update notifications version (#8267)
- chore: Update slack version (#8299)
- chore: Update to Redis 6.2.4 (#8157)
- chore: Upgrade awscli to 2.4.6 and remove python deps (#7947)
- chore: Upgrade base image to ubuntu:21.10 (#8230)
- chore: Upgrade dex to v2.30.2 (https://github.com/dexidp/dex/issues/2326) (#8237)
- chore: Upgrade gitops engine (#8288)
- chore: Upgrade golang to 1.17.6 (#8229)
- chore: Upgrade helm to most recent version (v3.7.2) (#8226)
- chore: Upgrade k8s client to v1.23 (#8213)
- chore: Upgrade kustomize to most recent version (v4.4.1) (#8227)
- refactor: Introduce 'byClusterName' secret index to speedup cluster server URL lookup (#8133)
- refactor: Move project filtering to server side (#8102)
## v2.2.3 (2022-01-18)
- fix: Application exist panic when execute api call (#8188)
- fix: Route health check stuck in 'Progressing' (#8170)
- refactor: Introduce 'byClusterName' secret index to speedup cluster server URL lookup (#8133)
- chore: Update to Redis 6.2.4 (#8157) (#8158)
## v2.2.2 (2021-12-31)
- fix: Issue with project scoped resources (#8048)
- fix: Escape proj in regex (#7985)
- fix: Default value for retry validation #8055 (#8064)
- fix: Sync window panel is crashed if resource name not contain letters (#8053)
- fix: Upgrade github.com/argoproj/gitops-engine to v0.5.2
- fix: Retry disabled text (#8004)
- fix: Opening app details shows UI error on some apps (#8016) (#8019)
- fix: Correctly handle project field during partial cluster update (#7994)
- fix: Cluster API does not support updating labels and annotations (#7901)
## v2.2.1 (2021-12-16)
- fix: Resource details page crashes when resource is not deployed and hide managed fields is selected (#7971)
- fix: Issue with headless installation (#7958)
- fix: Nil pointer (#7905)
## v2.2.0 (2021-12-14)
> [Upgrade instructions](./docs/operator-manual/upgrading/2.1-2.2.md)
### Project Scoped repositories and clusters
The project scoped repositories and clusters is a feature that simplifies registering the repositories and cluster credentials.
Instead of requiring operators to set up in advance all clusters and git repositories that can be used, developers can now do
this on their own in a self-service manner.
### Config Management Plugins V2
The Config Management Plugins V2 is set of enhancement of the existing config management plugins feature.
The list includes improved installation experience, ability to package plugin into a separate image and
improved plugin manifests discovery.
### Resource tracking
Argo CD has traditionally tracked the resources it manages by the well-known "app.kubernetes.io/instance" property.
While using this property works ok in simple scenarios, it also has several limitations. ArgoCD now allows you to use
a new annotation (argocd.argoproj.io/tracking-id) for tracking your resources. Using this annotation is a much more flexible approach
as there are no conflicts with other Kubernetes tools, and you can easily install multiple Argo CD instances on the same clusters.
### Bug Fixes and Performance Enhancements
* Argo CD API server caches RBAC checks that significantly improves the GET /api/v1/applications API performance (#7587)
* Argo CD RBAC supports regex matches (#7165)
* Health check support for KubeVirt (#7176), Cassandra (#7017), Openshift Route (#7112), DeploymentConfig (#7114), Confluent (#6957) and SparkApplication (#7434) CRDs.
* Persistent banner (#7312) with custom positioning (#7462)
* Cluster name support in project destinations (#7198)
* around 30 more features and a total of 84 bug fixes
## v2.1.7 (2021-12-14)
- fix: issue with keepalive (#7861)
- fix nil pointer dereference error (#7905)
- fix: env vars to tune cluster cache were broken (#7779)
- fix: upgraded gitops engine to v0.4.2 (fixes #7561)
## v2.1.6 (2021-11-16)
- fix: don't use revision caching during app creation (#7508)
- fix: supporting OCI dependencies. Fixes #6062 (#6994)
## v2.1.5 (2021-11-16)
- fix: Invalid memory address or nil pointer dereference in processRequestedAppOperation (#7501)
## v2.1.4 (2021-11-15)
- fix: Operation has completed with phase: Running (#7482)
- fix: Application status panel shows Syncing instead of Deleting (#7486)
- fix(ui): Add Error Boundary around Extensions and comply with new Extensions API (#7215)
## v2.1.3 (2021-10-29)
- fix: core-install.yaml always refers to latest argocd image (#7321)
- fix: handle applicationset backup forbidden error (#7306)
- fix: Argo CD should not use cached git/helm revision during app creation/update validation (#7244)
## v2.1.2 (2021-10-02)
- fix: cluster filter popping out of box (#7135)
- fix: gracefully shutdown metrics server when dex config changes (#7138)
- fix: upgrade gitops engine version to v0.4.1 (#7088)
- fix: repository name already exists when multiple helm dependencies (#7096)
## v2.1.1 (2021-08-25)
### Bug Fixes
@@ -753,7 +972,7 @@ More documentation and tools are coming in patch releases.
The Argo CD deletes all **in-flight** hooks if you terminate running sync operation. The hook state assessment change implemented in this release the Argo CD enables detection of
an in-flight state for all Kubernetes resources including `Deployment`, `PVC`, `StatefulSet`, `ReplicaSet` etc. So if you terminate the sync operation that has, for example,
`StatefulSet` hook that is `Progressing` it will be deleted. The long-running jobs are not supposed to be used as a sync hook and you should consider using
[Sync Waves](https://argoproj.github.io/argo-cd/user-guide/sync-waves/) instead.
[Sync Waves](https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/) instead.
#### Enhancements
* feat: Add custom health checks for cert-manager v0.11.0 (#2689)

View File

@@ -1,10 +1,10 @@
ARG BASE_IMAGE=docker.io/library/ubuntu:21.04
ARG BASE_IMAGE=docker.io/library/ubuntu:21.10
####################################################################################################
# Builder image
# Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image
# Also used as the image in CI jobs so needs all dependencies
####################################################################################################
FROM docker.io/library/golang:1.16.5 as builder
FROM docker.io/library/golang:1.17.6 as builder
RUN echo 'deb http://deb.debian.org/debian buster-backports main' >> /etc/apt/sources.list
@@ -32,6 +32,7 @@ RUN ./install.sh ksonnet-linux
RUN ./install.sh helm2-linux
RUN ./install.sh helm-linux
RUN ./install.sh kustomize-linux
RUN ./install.sh awscli-linux
####################################################################################################
# Argo CD Base - used as the base for both the release and dev argocd images
@@ -49,21 +50,21 @@ RUN groupadd -g 999 argocd && \
chmod g=u /home/argocd && \
apt-get update && \
apt-get dist-upgrade -y && \
apt-get install -y git git-lfs python3-pip tini gpg tzdata && \
apt-get install -y git git-lfs tini gpg tzdata && \
apt-get clean && \
pip3 install awscli==1.18.80 && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY hack/git-ask-pass.sh /usr/local/bin/git-ask-pass.sh
COPY hack/gpg-wrapper.sh /usr/local/bin/gpg-wrapper.sh
COPY hack/git-verify-wrapper.sh /usr/local/bin/git-verify-wrapper.sh
COPY --from=builder /usr/local/bin/ks /usr/local/bin/ks
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 --from=builder /usr/local/aws-cli/v2/current/dist /usr/local/aws-cli/v2/current/dist
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
RUN ln -s /usr/local/aws-cli/v2/current/dist/aws /usr/local/bin/aws
# support for mounting configuration from a configmap
RUN mkdir -p /app/config/ssh && \
@@ -90,18 +91,18 @@ FROM docker.io/library/node:12.18.4 as argocd-ui
WORKDIR /src
ADD ["ui/package.json", "ui/yarn.lock", "./"]
RUN yarn install
RUN yarn install --network-timeout 200000
ADD ["ui/", "."]
ARG ARGO_VERSION=latest
ENV ARGO_VERSION=$ARGO_VERSION
RUN NODE_ENV='production' NODE_ONLINE_ENV='online' yarn build
RUN HOST_ARCH='amd64' NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OPTIONS=--max_old_space_size=8192 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.17.6 as argocd-build
WORKDIR /go/src/github.com/argoproj/argo-cd
@@ -115,12 +116,6 @@ COPY . .
COPY --from=argocd-ui /src/dist/app /go/src/github.com/argoproj/argo-cd/ui/dist/app
RUN make argocd-all
ARG BUILD_ALL_CLIS=true
RUN if [ "$BUILD_ALL_CLIS" = "true" ] ; then \
make BIN_NAME=argocd-darwin-amd64 GOOS=darwin argocd-all && \
make BIN_NAME=argocd-windows-amd64.exe GOOS=windows argocd-all \
; fi
####################################################################################################
# Final image
####################################################################################################
@@ -133,5 +128,6 @@ 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
RUN ln -s /usr/local/bin/argocd /usr/local/bin/argocd-notifications
USER 999

View File

@@ -3,12 +3,11 @@
####################################################################################################
FROM argocd-base
COPY argocd /usr/local/bin/
COPY argocd-darwin-amd64 /usr/local/bin/
COPY argocd-windows-amd64.exe /usr/local/bin/
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-application-controller
RUN ln -s /usr/local/bin/argocd /usr/local/bin/argocd-dex
RUN ln -s /usr/local/bin/argocd /usr/local/bin/argocd-notifications
USER 999

View File

@@ -4,6 +4,8 @@ DIST_DIR=${CURRENT_DIR}/dist
CLI_NAME=argocd
BIN_NAME=argocd
GEN_RESOURCES_CLI_NAME=argocd-resources-gen
HOST_OS:=$(shell go env GOOS)
HOST_ARCH:=$(shell go env GOARCH)
@@ -13,7 +15,7 @@ GIT_COMMIT=$(shell git rev-parse HEAD)
GIT_TAG=$(shell if [ -z "`git status --porcelain`" ]; then git describe --exact-match --tags HEAD 2>/dev/null; fi)
GIT_TREE_STATE=$(shell if [ -z "`git status --porcelain`" ]; then echo "clean" ; else echo "dirty"; fi)
VOLUME_MOUNT=$(shell if test "$(go env GOOS)" = "darwin"; then echo ":delegated"; elif test selinuxenabled; then echo ":delegated"; else echo ""; fi)
KUBECTL_VERSION=$(shell go list -m all | grep k8s.io/client-go | cut -d ' ' -f5)
KUBECTL_VERSION=$(shell go list -m k8s.io/client-go | head -n 1 | rev | cut -d' ' -f1 | rev)
GOPATH?=$(shell if test -x `which go`; then go env GOPATH; else echo "$(HOME)/go"; fi)
GOCACHE?=$(HOME)/.cache/go-build
@@ -45,7 +47,7 @@ ARGOCD_E2E_DEX_PORT?=5556
ARGOCD_E2E_YARN_HOST?=localhost
ARGOCD_E2E_DISABLE_AUTH?=
ARGOCD_E2E_TEST_TIMEOUT?=20m
ARGOCD_E2E_TEST_TIMEOUT?=30m
ARGOCD_IN_CI?=false
ARGOCD_TEST_E2E?=true
@@ -177,7 +179,7 @@ gogen: ensure-gopath
go generate ./util/argo/...
.PHONY: protogen
protogen: ensure-gopath
protogen: ensure-gopath mod-vendor-local
export GO111MODULE=off
./hack/generate-proto.sh
@@ -186,6 +188,16 @@ openapigen: ensure-gopath
export GO111MODULE=off
./hack/update-openapi.sh
.PHONY: notification-catalog
notification-catalog:
go run ./hack/gen-catalog catalog
.PHONY: notification-docs
notification-docs:
go run ./hack/gen-docs
go run ./hack/gen-catalog docs
.PHONY: clientgen
clientgen: ensure-gopath
export GO111MODULE=off
@@ -195,8 +207,9 @@ clientgen: ensure-gopath
clidocsgen: ensure-gopath
go run tools/cmd-docs/main.go
.PHONY: codegen-local
codegen-local: ensure-gopath mod-vendor-local gogen protogen clientgen openapigen clidocsgen manifests-local
codegen-local: ensure-gopath mod-vendor-local notification-docs notification-catalog gogen protogen clientgen openapigen clidocsgen manifests-local
rm -rf vendor/
.PHONY: codegen
@@ -211,13 +224,17 @@ cli: test-tools-image
cli-local: clean-debug
CGO_ENABLED=0 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${CLI_NAME} ./cmd
.PHONY: gen-resources-cli-local
gen-resources-cli-local: clean-debug
CGO_ENABLED=0 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${GEN_RESOURCES_CLI_NAME} ./hack/gen-resources/cmd
.PHONY: release-cli
release-cli: clean-debug image
docker create --name tmp-argocd-linux $(IMAGE_PREFIX)argocd:$(IMAGE_TAG)
docker cp tmp-argocd-linux:/usr/local/bin/argocd ${DIST_DIR}/argocd-linux-amd64
docker cp tmp-argocd-linux:/usr/local/bin/argocd-darwin-amd64 ${DIST_DIR}/argocd-darwin-amd64
docker cp tmp-argocd-linux:/usr/local/bin/argocd-windows-amd64.exe ${DIST_DIR}/argocd-windows-amd64.exe
docker rm tmp-argocd-linux
release-cli: clean-debug build-ui
make BIN_NAME=argocd-darwin-amd64 GOOS=darwin argocd-all
make BIN_NAME=argocd-darwin-arm64 GOOS=darwin GOARCH=arm64 argocd-all
make BIN_NAME=argocd-linux-amd64 GOOS=linux argocd-all
make BIN_NAME=argocd-linux-arm64 GOOS=linux GOARCH=arm64 argocd-all
make BIN_NAME=argocd-windows-amd64.exe GOOS=windows argocd-all
.PHONY: test-tools-image
test-tools-image:
@@ -235,7 +252,7 @@ manifests: test-tools-image
# consolidated binary for cli, util, server, repo-server, controller
.PHONY: argocd-all
argocd-all: clean-debug
CGO_ENABLED=0 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${BIN_NAME} ./cmd
CGO_ENABLED=0 GOOS=${GOOS} GOARCH=${GOARCH} go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${BIN_NAME} ./cmd
.PHONY: server
server: clean-debug
@@ -249,20 +266,21 @@ repo-server:
controller:
CGO_ENABLED=0 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-application-controller ./cmd
.PHONY: build-ui
build-ui:
docker build -t argocd-ui --target argocd-ui .
find ./ui/dist -type f -not -name gitkeep -delete
docker run -v ${CURRENT_DIR}/ui/dist/app:/tmp/app --rm -t argocd-ui sh -c 'cp -r ./dist/app/* /tmp/app/'
.PHONY: image
ifeq ($(DEV_IMAGE), true)
# The "dev" image builds the binaries from the users desktop environment (instead of in Docker)
# which speeds up builds. Dockerfile.dev needs to be copied into dist to perform the build, since
# the dist directory is under .dockerignore.
IMAGE_TAG="dev-$(shell git describe --always --dirty)"
image:
image: build-ui
docker build -t argocd-base --target argocd-base .
docker build -t argocd-ui --target argocd-ui .
find ./ui/dist -type f -not -name gitkeep -delete
docker run -v ${CURRENT_DIR}/ui/dist/app:/tmp/app --rm -t argocd-ui sh -c 'cp -r ./dist/app/* /tmp/app/'
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd ./cmd
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-darwin-amd64 ./cmd
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-windows-amd64.exe ./cmd
ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-server
ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-application-controller
ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-repo-server
@@ -277,10 +295,8 @@ endif
@if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) ; fi
.PHONY: armimage
# The "BUILD_ALL_CLIS" argument is to skip building the CLIs for darwin and windows
# which would take a really long time.
armimage:
docker build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG)-arm . --build-arg BUILD_ALL_CLIS="false"
docker build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG)-arm .
.PHONY: builder-image
builder-image:
@@ -493,10 +509,6 @@ serve-docs-local:
serve-docs:
docker run ${MKDOCS_RUN_ARGS} --rm -it -p 8000:8000 -v ${CURRENT_DIR}:/docs ${MKDOCS_DOCKER_IMAGE} serve -a 0.0.0.0:8000
.PHONY: lint-docs
lint-docs:
# https://github.com/dkhamsing/awesome_bot
find docs -name '*.md' -exec grep -l http {} + | xargs docker run --rm -v $(PWD):/mnt:ro dkhamsing/awesome_bot -t 3 --allow-dupe --allow-redirect --white-list `cat white-list | grep -v "#" | tr "\n" ','` --skip-save-results --
# Verify that kubectl can connect to your K8s cluster from Docker
.PHONY: verify-kube-connect
@@ -542,3 +554,7 @@ dep-ui-local:
start-test-k8s:
go run ./hack/k8s
.PHONY: list
list:
@LC_ALL=C $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'

6
OWNERS
View File

@@ -20,4 +20,8 @@ reviewers:
- hblixt
- chetan-rns
- wanghong230
- pasha-codefresh
- pasha-codefresh
- ciiay
- leoluz
- crenshaw-dev
- saumeya

View File

@@ -1,8 +1,8 @@
controller: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller go run ./cmd/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
api-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-server go run ./cmd/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} "
dex: sh -c "ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/v2/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:v2.30.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}"
controller: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
api-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} "
dex: sh -c "ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/v2/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:v2.30.2 dex serve /dex.yaml"
redis: bash -c "if [ \"$ARGOCD_REDIS_LOCAL\" == 'true' ]; then redis-server --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; else docker run --rm --name argocd-redis -i -p ${ARGOCD_E2E_REDIS_PORT:-6379}:${ARGOCD_E2E_REDIS_PORT:-6379} redis:6.2.6-alpine --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; fi"
repo-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_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} $COMMAND --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

@@ -46,6 +46,7 @@ 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. [Unveil the Secret Ingredients of Continuous Delivery at Enterprise Scale with Argo CD](https://blog.akuity.io/unveil-the-secret-ingredients-of-continuous-delivery-at-enterprise-scale-with-argo-cd-7c5b4057ee49)
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)

View File

@@ -1,6 +1,6 @@
# Security Policy for Argo CD
Version: **v1.2 (2020-08-07)**
Version: **v1.4 (2022-01-23)**
## Preface
@@ -26,8 +26,12 @@ are well aware of the issues that may affect Argo CD and are constantly
working on the remediation of those that affect Argo CD and our users.
If you believe that we might have missed an issue that we should take a look
at (that can happen), then please discuss it with us. But please, do validate
that assumption before at least roughly.
at (that can happen), then please discuss it with us. If there is a CVE
assigned to the issue, please do open an issue on our GitHub tracker instead
of writing to the security contact e-mail, since things reported by scanners
are public already and the discussion that might emerge is of benefit to the
general community. However, please validate your scanner results and its
impact on Argo CD before opening an issue at least roughly.
## Supported Versions
@@ -64,3 +68,9 @@ findings (unless you prefer to stay anonymous, of course).
Please report vulnerabilities by e-mail to the following address:
* cncf-argo-security@lists.cncf.io
## Securing your Argo CD Instance
See the [operator manual security page](docs/operator-manual/security.md) for
additional information about Argo CD's security features and how to make your
Argo CD production ready.

View File

@@ -11,6 +11,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Adventure](https://jp.adventurekk.com/)
1. [Akuity](https://akuity.io/)
1. [Alibaba Group](https://www.alibabagroup.com/)
1. [Allianz Direct](https://www.allianzdirect.de/)
1. [Ambassador Labs](https://www.getambassador.io/)
1. [Ant Group](https://www.antgroup.com/)
1. [ANSTO - Australian Synchrotron](https://www.synchrotron.org.au/)
@@ -30,6 +31,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [CARFAX](https://www.carfax.com)
1. [Celonis](https://www.celonis.com/)
1. [Chime](https://www.chime.com)
1. [Cisco ET&I](https://eti.cisco.com/)
1. [Codefresh](https://www.codefresh.io/)
1. [Codility](https://www.codility.com/)
1. [Commonbond](https://commonbond.co/)
@@ -39,6 +41,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Cybozu](https://cybozu-global.com)
1. [Chargetrip](https://chargetrip.com)
1. [D2iQ](https://www.d2iq.com)
1. [Deloitte](https://www.deloitte.com/)
1. [Devtron Labs](https://github.com/devtron-labs/devtron)
1. [EDF Renewables](https://www.edf-re.com/)
1. [edX](https://edx.org)
@@ -47,21 +50,26 @@ Currently, the following organizations are **officially** using Argo CD:
1. [END.](https://www.endclothing.com/)
1. [Energisme](https://energisme.com/)
1. [Fave](https://myfave.com)
1. [Flip](https://flip.id)
1. [Fonoa](https://www.fonoa.com/)
1. [Future PLC](https://www.futureplc.com/)
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. [Gllue](https://gllue.com)
1. [GMETRI](https://gmetri.com/)
1. [Gojek](https://www.gojek.io/)
1. [Greenpass](https://www.greenpass.com.br/)
1. [Handelsbanken](https://www.handelsbanken.se)
1. [Healy](https://www.healyworld.net)
1. [Helio](https://helio.exchange)
1. [hipages](https://hipages.com.au/)
1. [Hiya](https://hiya.com)
1. [Honestbank](https://honestbank.com)
1. [IBM](https://www.ibm.com/)
1. [Ibotta](https://home.ibotta.com)
1. [IITS-Consulting](https://iits-consulting.de)
1. [Index Exchange](https://www.indexexchange.com/)
1. [InsideBoard](https://www.insideboard.com)
@@ -93,7 +101,9 @@ Currently, the following organizations are **officially** using Argo CD:
1. [New Relic](https://newrelic.com/)
1. [Nextdoor](https://nextdoor.com/)
1. [Nikkei](https://www.nikkei.co.jp/nikkeiinfo/en/)
1. [Nitro](https://gonitro.com)
1. [Octadesk](https://octadesk.com)
1. [omegaUp](https://omegaUp.com)
1. [openEuler](https://openeuler.org)
1. [openGauss](https://opengauss.org/)
1. [openLooKeng](https://openlookeng.io)
@@ -119,11 +129,13 @@ 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. [Skit](https://skit.ai/)
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. [Swiss Post](https://github.com/swisspost)
1. [Swisscom](https://www.swisscom.ch)
1. [Swissquote](https://github.com/swissquote)
1. [Syncier](https://syncier.com/)
@@ -178,3 +190,8 @@ Currently, the following organizations are **officially** using Argo CD:
1. [p3r](https://www.p3r.one/)
1. [Faro](https://www.faro.com/)
1. [Rise](https://www.risecard.eu/)
1. [Devopsi - Poland Software/DevOps Consulting](https://devopsi.pl/)
1. [Skyscanner](https://www.skyscanner.net/)
1. [Casavo](https://casavo.com)
1. [Majid Al Futtaim](https://www.majidalfuttaim.com/)
1. [ZOZO](https://corp.zozo.com/)

View File

@@ -1 +1 @@
2.2.0
2.3.2

View File

@@ -256,7 +256,7 @@
},
{
"type": "string",
"description": "the selector to to restrict returned list to applications only with matched labels.",
"description": "the selector to restrict returned list to applications only with matched labels.",
"name": "selector",
"in": "query"
},
@@ -520,7 +520,7 @@
},
{
"type": "string",
"description": "the selector to to restrict returned list to applications only with matched labels.",
"description": "the selector to restrict returned list to applications only with matched labels.",
"name": "selector",
"in": "query"
},
@@ -1605,6 +1605,18 @@
"type": "string",
"name": "name",
"in": "query"
},
{
"type": "string",
"description": "type is the type of the specified cluster identifier ( \"server\" - default, \"name\" ).",
"name": "id.type",
"in": "query"
},
{
"type": "string",
"description": "value holds the cluster server URL or cluster name.",
"name": "id.value",
"in": "query"
}
],
"responses": {
@@ -1659,7 +1671,53 @@
}
}
},
"/api/v1/clusters/{cluster.server}": {
"/api/v1/clusters/{id.value}": {
"get": {
"tags": [
"ClusterService"
],
"summary": "Get returns a cluster by server address",
"operationId": "ClusterService_Get",
"parameters": [
{
"type": "string",
"description": "value holds the cluster server URL or cluster name",
"name": "id.value",
"in": "path",
"required": true
},
{
"type": "string",
"name": "server",
"in": "query"
},
{
"type": "string",
"name": "name",
"in": "query"
},
{
"type": "string",
"description": "type is the type of the specified cluster identifier ( \"server\" - default, \"name\" ).",
"name": "id.type",
"in": "query"
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1alpha1Cluster"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
}
},
"put": {
"tags": [
"ClusterService"
@@ -1669,8 +1727,8 @@
"parameters": [
{
"type": "string",
"description": "Server is the API server URL of the Kubernetes cluster",
"name": "cluster.server",
"description": "value holds the cluster server URL or cluster name",
"name": "id.value",
"in": "path",
"required": true
},
@@ -1690,41 +1748,11 @@
"collectionFormat": "multi",
"name": "updatedFields",
"in": "query"
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1alpha1Cluster"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
}
}
},
"/api/v1/clusters/{server}": {
"get": {
"tags": [
"ClusterService"
],
"summary": "Get returns a cluster by server address",
"operationId": "ClusterService_Get",
"parameters": [
{
"type": "string",
"name": "server",
"in": "path",
"required": true
},
{
"type": "string",
"name": "name",
"description": "type is the type of the specified cluster identifier ( \"server\" - default, \"name\" ).",
"name": "id.type",
"in": "query"
}
],
@@ -1752,14 +1780,26 @@
"parameters": [
{
"type": "string",
"name": "server",
"description": "value holds the cluster server URL or cluster name",
"name": "id.value",
"in": "path",
"required": true
},
{
"type": "string",
"name": "server",
"in": "query"
},
{
"type": "string",
"name": "name",
"in": "query"
},
{
"type": "string",
"description": "type is the type of the specified cluster identifier ( \"server\" - default, \"name\" ).",
"name": "id.type",
"in": "query"
}
],
"responses": {
@@ -1778,7 +1818,7 @@
}
}
},
"/api/v1/clusters/{server}/invalidate-cache": {
"/api/v1/clusters/{id.value}/invalidate-cache": {
"post": {
"tags": [
"ClusterService"
@@ -1788,7 +1828,8 @@
"parameters": [
{
"type": "string",
"name": "server",
"description": "value holds the cluster server URL or cluster name",
"name": "id.value",
"in": "path",
"required": true
}
@@ -1809,7 +1850,7 @@
}
}
},
"/api/v1/clusters/{server}/rotate-auth": {
"/api/v1/clusters/{id.value}/rotate-auth": {
"post": {
"tags": [
"ClusterService"
@@ -1819,7 +1860,8 @@
"parameters": [
{
"type": "string",
"name": "server",
"description": "value holds the cluster server URL or cluster name",
"name": "id.value",
"in": "path",
"required": true
}
@@ -2702,6 +2744,16 @@
"type": "string",
"name": "revision",
"in": "query"
},
{
"type": "string",
"name": "appName",
"in": "query"
},
{
"type": "string",
"name": "appProject",
"in": "query"
}
],
"responses": {
@@ -3106,7 +3158,7 @@
},
{
"type": "string",
"description": "the selector to to restrict returned list to applications only with matched labels.",
"description": "the selector to restrict returned list to applications only with matched labels.",
"name": "selector",
"in": "query"
},
@@ -3530,6 +3582,20 @@
}
}
},
"clusterClusterID": {
"type": "object",
"title": "ClusterID holds a cluster server URL or cluster name",
"properties": {
"type": {
"type": "string",
"title": "type is the type of the specified cluster identifier ( \"server\" - default, \"name\" )"
},
"value": {
"type": "string",
"title": "value holds the cluster server URL or cluster name"
}
}
},
"clusterClusterResponse": {
"type": "object"
},
@@ -3570,6 +3636,13 @@
"type": "object",
"title": "Help settings",
"properties": {
"binaryUrls": {
"type": "object",
"title": "the URLs for downloading argocd binaries",
"additionalProperties": {
"type": "string"
}
},
"chatText": {
"type": "string",
"title": "the text for getting chat help, defaults to \"Chat now!\""
@@ -4042,6 +4115,9 @@
"appName": {
"type": "string"
},
"appProject": {
"type": "string"
},
"source": {
"$ref": "#/definitions/v1alpha1ApplicationSource"
}
@@ -4892,6 +4968,10 @@
"$ref": "#/definitions/v1alpha1HelmFileParameter"
}
},
"ignoreMissingValueFiles": {
"type": "boolean",
"title": "IgnoreMissingValueFiles prevents helm template from failing when valueFiles do not exist locally by not appending them to helm template --values"
},
"parameters": {
"type": "array",
"title": "Parameters is a list of Helm parameters which are passed to the helm template command upon manifest generation",
@@ -4907,6 +4987,10 @@
"type": "string",
"title": "ReleaseName is the Helm release name to use. If omitted it will use the application name"
},
"skipCrds": {
"type": "boolean",
"title": "SkipCrds skips custom resource definition installation step (Helm's --skip-crds)"
},
"valueFiles": {
"type": "array",
"title": "ValuesFiles is a list of Helm value files to use when generating a template",
@@ -5785,16 +5869,25 @@
},
"v1alpha1OverrideIgnoreDiff": {
"type": "object",
"title": "TODO: describe this type",
"title": "OverrideIgnoreDiff contains configurations about how fields should be ignored during diffs between\nthe desired state and live state",
"properties": {
"jSONPointers": {
"type": "array",
"title": "JSONPointers is a JSON path list following the format defined in RFC4627 (https://datatracker.ietf.org/doc/html/rfc6902#section-3)",
"items": {
"type": "string"
}
},
"jqPathExpressions": {
"type": "array",
"title": "JQPathExpressions is a JQ path list that will be evaludated during the diff process",
"items": {
"type": "string"
}
},
"managedFieldsManagers": {
"type": "array",
"title": "ManagedFieldsManagers is a list of trusted managers. Fields mutated by those managers will take precedence over the\ndesired state defined in the SCM and won't be displayed in diffs",
"items": {
"type": "string"
}
@@ -6157,6 +6250,13 @@
"kind": {
"type": "string"
},
"managedFieldsManagers": {
"type": "array",
"title": "ManagedFieldsManagers is a list of trusted managers. Fields mutated by those managers will take precedence over the\ndesired state defined in the SCM and won't be displayed in diffs",
"items": {
"type": "string"
}
},
"name": {
"type": "string"
},

View File

@@ -0,0 +1,57 @@
package commands
import (
"context"
"fmt"
"os"
"strings"
"github.com/argoproj/argo-cd/v2/util/git"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"github.com/argoproj/argo-cd/v2/reposerver/askpass"
"github.com/argoproj/argo-cd/v2/util/errors"
grpc_util "github.com/argoproj/argo-cd/v2/util/grpc"
"github.com/argoproj/argo-cd/v2/util/io"
)
const (
// cliName is the name of the CLI
cliName = "argocd-git-ask-pass"
)
func NewCommand() *cobra.Command {
var command = cobra.Command{
Use: cliName,
Short: "Argo CD git credential helper",
DisableAutoGenTag: true,
Run: func(c *cobra.Command, args []string) {
if len(os.Args) != 2 {
errors.CheckError(fmt.Errorf("expected 1 argument, got %d", len(os.Args)-1))
}
nonce := os.Getenv(git.ASKPASS_NONCE_ENV)
if nonce == "" {
errors.CheckError(fmt.Errorf("%s is not set", git.ASKPASS_NONCE_ENV))
}
conn, err := grpc_util.BlockingDial(context.Background(), "unix", askpass.SocketPath, nil, grpc.WithInsecure())
errors.CheckError(err)
defer io.Close(conn)
client := askpass.NewAskPassServiceClient(conn)
creds, err := client.GetCredentials(context.Background(), &askpass.CredentialsRequest{Nonce: nonce})
errors.CheckError(err)
switch {
case strings.HasPrefix(os.Args[1], "Username"):
fmt.Println(creds.Username)
case strings.HasPrefix(os.Args[1], "Password"):
fmt.Println(creds.Password)
default:
errors.CheckError(fmt.Errorf("unknown credential type '%s'", os.Args[1]))
}
},
}
return &command
}

View File

@@ -0,0 +1,132 @@
package commands
import (
"context"
"fmt"
"net/http"
"os"
"strings"
service "github.com/argoproj/argo-cd/v2/util/notification/argocd"
notificationscontroller "github.com/argoproj/argo-cd/v2/notification_controller/controller"
controller "github.com/argoproj/notifications-engine/pkg/controller"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
"k8s.io/client-go/tools/clientcmd"
)
const (
defaultMetricsPort = 9001
)
func addK8SFlagsToCmd(cmd *cobra.Command) clientcmd.ClientConfig {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
overrides := clientcmd.ConfigOverrides{}
kflags := clientcmd.RecommendedConfigOverrideFlags("")
cmd.PersistentFlags().StringVar(&loadingRules.ExplicitPath, "kubeconfig", "", "Path to a kube config. Only required if out-of-cluster")
clientcmd.BindOverrideFlags(&overrides, cmd.PersistentFlags(), kflags)
return clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, &overrides, os.Stdin)
}
func NewCommand() *cobra.Command {
var (
clientConfig clientcmd.ClientConfig
processorsCount int
namespace string
appLabelSelector string
logLevel string
logFormat string
metricsPort int
argocdRepoServer string
argocdRepoServerPlaintext bool
argocdRepoServerStrictTLS bool
configMapName string
secretName string
)
var command = cobra.Command{
Use: "controller",
Short: "Starts Argo CD Notifications controller",
RunE: func(c *cobra.Command, args []string) error {
restConfig, err := clientConfig.ClientConfig()
if err != nil {
return err
}
dynamicClient, err := dynamic.NewForConfig(restConfig)
if err != nil {
return err
}
k8sClient, err := kubernetes.NewForConfig(restConfig)
if err != nil {
return err
}
if namespace == "" {
namespace, _, err = clientConfig.Namespace()
if err != nil {
return err
}
}
level, err := log.ParseLevel(logLevel)
if err != nil {
return err
}
log.SetLevel(level)
switch strings.ToLower(logFormat) {
case "json":
log.SetFormatter(&log.JSONFormatter{})
case "text":
if os.Getenv("FORCE_LOG_COLORS") == "1" {
log.SetFormatter(&log.TextFormatter{ForceColors: true})
}
default:
return fmt.Errorf("Unknown log format '%s'", logFormat)
}
argocdService, err := service.NewArgoCDService(k8sClient, namespace, argocdRepoServer, argocdRepoServerPlaintext, argocdRepoServerStrictTLS)
if err != nil {
return err
}
defer argocdService.Close()
registry := controller.NewMetricsRegistry("argocd")
http.Handle("/metrics", promhttp.HandlerFor(prometheus.Gatherers{registry, prometheus.DefaultGatherer}, promhttp.HandlerOpts{}))
go func() {
log.Fatal(http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", metricsPort), http.DefaultServeMux))
}()
log.Infof("serving metrics on port %d", metricsPort)
log.Infof("loading configuration %d", metricsPort)
ctrl := notificationscontroller.NewController(k8sClient, dynamicClient, argocdService, namespace, appLabelSelector, registry, secretName, configMapName)
err = ctrl.Init(context.Background())
if err != nil {
return err
}
go ctrl.Run(context.Background(), processorsCount)
<-context.Background().Done()
return nil
},
}
clientConfig = addK8SFlagsToCmd(&command)
command.Flags().IntVar(&processorsCount, "processors-count", 1, "Processors count.")
command.Flags().StringVar(&appLabelSelector, "app-label-selector", "", "App label selector.")
command.Flags().StringVar(&namespace, "namespace", "", "Namespace which controller handles. Current namespace if empty.")
command.Flags().StringVar(&logLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")
command.Flags().StringVar(&logFormat, "logformat", "text", "Set the logging format. One of: text|json")
command.Flags().IntVar(&metricsPort, "metrics-port", defaultMetricsPort, "Metrics port")
command.Flags().StringVar(&argocdRepoServer, "argocd-repo-server", "argocd-repo-server:8081", "Argo CD repo server address")
command.Flags().BoolVar(&argocdRepoServerPlaintext, "argocd-repo-server-plaintext", false, "Use a plaintext client (non-TLS) to connect to repository server")
command.Flags().BoolVar(&argocdRepoServerStrictTLS, "argocd-repo-server-strict-tls", false, "Perform strict validation of TLS certificates when connecting to repo server")
command.Flags().StringVar(&configMapName, "config-map-name", "argocd-notifications-cm", "Set notifications ConfigMap name")
command.Flags().StringVar(&secretName, "secret-name", "argocd-notifications-secret", "Set notifications Secret name")
return &command
}

View File

@@ -18,6 +18,7 @@ import (
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/reposerver"
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/reposerver/askpass"
reposervercache "github.com/argoproj/argo-cd/v2/reposerver/cache"
"github.com/argoproj/argo-cd/v2/reposerver/metrics"
"github.com/argoproj/argo-cd/v2/reposerver/repository"
@@ -61,6 +62,10 @@ func getPauseGenerationOnFailureForRequests() int {
return env.ParseNumFromEnv(common.EnvPauseGenerationRequests, defaultPauseGenerationOnFailureForRequests, 0, math.MaxInt32)
}
func getSubmoduleEnabled() bool {
return env.ParseBoolFromEnv(common.EnvGitSubmoduleEnabled, true)
}
func NewCommand() *cobra.Command {
var (
parallelismLimit int64
@@ -90,6 +95,7 @@ func NewCommand() *cobra.Command {
cache, err := cacheSrc()
errors.CheckError(err)
askPassServer := askpass.NewServer()
metricsServer := metrics.NewMetricsServer()
cacheutil.CollectMetrics(redisClient, metricsServer)
server, err := reposerver.NewServer(metricsServer, cache, tlsConfigCustomizer, repository.RepoServerInitConstants{
@@ -97,7 +103,8 @@ func NewCommand() *cobra.Command {
PauseGenerationAfterFailedGenerationAttempts: getPauseGenerationAfterFailedGenerationAttempts(),
PauseGenerationOnFailureForMinutes: getPauseGenerationOnFailureForMinutes(),
PauseGenerationOnFailureForRequests: getPauseGenerationOnFailureForRequests(),
})
SubmoduleEnabled: getSubmoduleEnabled(),
}, askPassServer)
errors.CheckError(err)
grpc := server.CreateGRPC()
@@ -128,6 +135,7 @@ func NewCommand() *cobra.Command {
})
http.Handle("/metrics", metricsServer.GetHandler())
go func() { errors.CheckError(http.ListenAndServe(fmt.Sprintf(":%d", metricsPort), nil)) }()
go func() { errors.CheckError(askPassServer.Run(askpass.SocketPath)) }()
if gpg.IsGPGEnabled() {
log.Infof("Initializing GnuPG keyring at %s", common.GetGnuPGHomePath())

View File

@@ -55,6 +55,7 @@ func NewAdminCommand() *cobra.Command {
command.AddCommand(NewImportCommand())
command.AddCommand(NewExportCommand())
command.AddCommand(NewDashboardCommand())
command.AddCommand(NewNotificationsCommand())
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", "text", "Set the logging format. One of: text|json")
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")

View File

@@ -111,10 +111,11 @@ func NewExportCommand() *cobra.Command {
// NewImportCommand defines a new command for exporting Kubernetes and Argo CD resources.
func NewImportCommand() *cobra.Command {
var (
clientConfig clientcmd.ClientConfig
prune bool
dryRun bool
verbose bool
clientConfig clientcmd.ClientConfig
prune bool
dryRun bool
verbose bool
stopOperation bool
)
var command = cobra.Command{
Use: "import SOURCE",
@@ -228,14 +229,14 @@ func NewImportCommand() *cobra.Command {
fmt.Printf("%s/%s %s created%s\n", gvk.Group, gvk.Kind, bakObj.GetName(), dryRunMsg)
}
} else if specsEqual(*bakObj, liveObj) {
} else if specsEqual(*bakObj, liveObj) && checkAppHasNoNeedToStopOperation(liveObj, stopOperation) {
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)
newLive := updateLive(bakObj, &liveObj, stopOperation)
_, err = dynClient.Update(context.Background(), newLive, v1.UpdateOptions{})
if apierr.IsForbidden(err) || apierr.IsNotFound(err) {
isForbidden = true
@@ -300,10 +301,23 @@ func NewImportCommand() *cobra.Command {
command.Flags().BoolVar(&dryRun, "dry-run", false, "Print what will be performed")
command.Flags().BoolVar(&prune, "prune", false, "Prune secrets, applications and projects which do not appear in the backup")
command.Flags().BoolVar(&verbose, "verbose", false, "Verbose output (versus only changed output)")
command.Flags().BoolVar(&stopOperation, "stop-operation", false, "Stop any existing operations")
return &command
}
// check app has no need to stop operation.
func checkAppHasNoNeedToStopOperation(liveObj unstructured.Unstructured, stopOperation bool) bool {
if !stopOperation {
return true
}
switch liveObj.GetKind() {
case "Application":
return liveObj.Object["operation"] == nil
}
return true
}
// export writes the unstructured object and removes extraneous cruft from output before writing
func export(w io.Writer, un unstructured.Unstructured) {
name := un.GetName()
@@ -329,7 +343,7 @@ func export(w io.Writer, un unstructured.Unstructured) {
// updateLive replaces the live object's finalizers, spec, annotations, labels, and data from the
// backup object but leaves all other fields intact (status, other metadata, etc...)
func updateLive(bak, live *unstructured.Unstructured) *unstructured.Unstructured {
func updateLive(bak, live *unstructured.Unstructured, stopOperation bool) *unstructured.Unstructured {
newLive := live.DeepCopy()
newLive.SetAnnotations(bak.GetAnnotations())
newLive.SetLabels(bak.GetLabels())
@@ -344,6 +358,10 @@ func updateLive(bak, live *unstructured.Unstructured) *unstructured.Unstructured
if _, ok := bak.Object["status"]; ok {
newLive.Object["status"] = bak.Object["status"]
}
if stopOperation {
newLive.Object["operation"] = nil
}
case "ApplicationSet":
newLive.Object["spec"] = bak.Object["spec"]
}

View File

@@ -13,18 +13,20 @@ import (
func NewDashboardCommand() *cobra.Command {
var (
port int
port int
address string
)
cmd := &cobra.Command{
Use: "dashboard",
Short: "Starts Argo CD Web UI locally",
Run: func(cmd *cobra.Command, args []string) {
println(fmt.Sprintf("Argo CD UI is available at http://localhost:%d", port))
println(fmt.Sprintf("Argo CD UI is available at http://%s:%d", address, port))
<-context.Background().Done()
},
}
clientOpts := &apiclient.ClientOptions{Core: true}
headless.InitCommand(cmd, clientOpts, &port)
headless.InitCommand(cmd, clientOpts, &port, &address)
cmd.Flags().IntVar(&port, "port", common.DefaultPortAPIServer, "Listen on given port")
cmd.Flags().StringVar(&address, "address", common.DefaultAddressAPIServer, "Listen on given address")
return cmd
}

View File

@@ -0,0 +1,51 @@
package admin
import (
"log"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
service "github.com/argoproj/argo-cd/v2/util/notification/argocd"
settings "github.com/argoproj/argo-cd/v2/util/notification/settings"
"github.com/argoproj/notifications-engine/pkg/cmd"
"github.com/spf13/cobra"
)
var (
applications = schema.GroupVersionResource{Group: "argoproj.io", Version: "v1alpha1", Resource: "applications"}
)
func NewNotificationsCommand() *cobra.Command {
var (
argocdRepoServer string
argocdRepoServerPlaintext bool
argocdRepoServerStrictTLS bool
)
var argocdService service.Service
toolsCommand := cmd.NewToolsCommand(
"notifications",
"notifications",
applications,
settings.GetFactorySettings(argocdService, "argocd-notifications-secret", "argocd-notifications-cm"), func(clientConfig clientcmd.ClientConfig) {
k8sCfg, err := clientConfig.ClientConfig()
if err != nil {
log.Fatalf("Failed to parse k8s config: %v", err)
}
ns, _, err := clientConfig.Namespace()
if err != nil {
log.Fatalf("Failed to parse k8s config: %v", err)
}
argocdService, err = service.NewArgoCDService(kubernetes.NewForConfigOrDie(k8sCfg), ns, argocdRepoServer, argocdRepoServerPlaintext, argocdRepoServerStrictTLS)
if err != nil {
log.Fatalf("Failed to initalize Argo CD service: %v", err)
}
})
toolsCommand.PersistentFlags().StringVar(&argocdRepoServer, "argocd-repo-server", "argocd-repo-server:8081", "Argo CD repo server address")
toolsCommand.PersistentFlags().BoolVar(&argocdRepoServerPlaintext, "argocd-repo-server-plaintext", false, "Use a plaintext client (non-TLS) to connect to repository server")
toolsCommand.PersistentFlags().BoolVar(&argocdRepoServerStrictTLS, "argocd-repo-server-strict-tls", false, "Perform strict validation of TLS certificates when connecting to repo server")
return toolsCommand
}

View File

@@ -406,6 +406,10 @@ argocd admin settings resource-overrides ignore-differences ./deploy.yaml --argo
return
}
// This normalizer won't verify 'managedFieldsManagers' ignore difference
// configurations. This requires access to live resources which is not the
// purpose of this command. This will just apply jsonPointers and
// jqPathExpressions configurations.
normalizer, err := normalizers.NewIgnoreNormalizer(nil, overrides)
errors.CheckError(err)

View File

@@ -16,7 +16,6 @@ import (
"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"
"github.com/argoproj/gitops-engine/pkg/sync/ignore"
@@ -46,6 +45,7 @@ import (
repoapiclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/reposerver/repository"
"github.com/argoproj/argo-cd/v2/util/argo"
argodiff "github.com/argoproj/argo-cd/v2/util/argo/diff"
"github.com/argoproj/argo-cd/v2/util/cli"
"github.com/argoproj/argo-cd/v2/util/errors"
"github.com/argoproj/argo-cd/v2/util/git"
@@ -283,6 +283,7 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
untilTime string
filter string
container string
previous bool
)
var command = &cobra.Command{
Use: "logs APPNAME",
@@ -312,6 +313,7 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
UntilTime: &untilTime,
Filter: &filter,
Container: container,
Previous: previous,
})
if err != nil {
log.Fatalf("failed to get pod logs: %v", err)
@@ -353,6 +355,7 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
command.Flags().StringVar(&untilTime, "until-time", "", "Show logs until this time")
command.Flags().StringVar(&filter, "filter", "", "Show logs contain this string")
command.Flags().StringVar(&container, "container", "", "Optional container name")
command.Flags().BoolVarP(&previous, "previous", "p", false, "Specify if the previously terminated container logs should be returned")
return command
}
@@ -558,15 +561,16 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
// NewApplicationUnsetCommand returns a new instance of an `argocd app unset` command
func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
parameters []string
valuesLiteral bool
valuesFiles []string
nameSuffix bool
namePrefix bool
kustomizeVersion bool
kustomizeImages []string
pluginEnvs []string
appOpts cmdutil.AppOptions
parameters []string
valuesLiteral bool
valuesFiles []string
ignoreMissingValueFiles bool
nameSuffix bool
namePrefix bool
kustomizeVersion bool
kustomizeImages []string
pluginEnvs []string
appOpts cmdutil.AppOptions
)
var command = &cobra.Command{
Use: "unset APPNAME parameters",
@@ -643,7 +647,7 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
}
}
if app.Spec.Source.Helm != nil {
if len(parameters) == 0 && len(valuesFiles) == 0 && !valuesLiteral {
if len(parameters) == 0 && len(valuesFiles) == 0 && !valuesLiteral && !ignoreMissingValueFiles {
c.HelpFunc()(c, args)
os.Exit(1)
}
@@ -671,6 +675,10 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
}
}
}
if ignoreMissingValueFiles {
app.Spec.Source.Helm.IgnoreMissingValueFiles = false
updated = true
}
if app.Spec.Source.Helm.PassCredentials {
app.Spec.Source.Helm.PassCredentials = false
updated = true
@@ -706,6 +714,7 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
command.Flags().StringArrayVarP(&parameters, "parameter", "p", []string{}, "Unset a parameter override (e.g. -p guestbook=image)")
command.Flags().StringArrayVar(&valuesFiles, "values", []string{}, "Unset one or more Helm values files")
command.Flags().BoolVar(&valuesLiteral, "values-literal", false, "Unset literal Helm values block")
command.Flags().BoolVar(&ignoreMissingValueFiles, "ignore-missing-value-files", false, "Unset the helm ignore-missing-value-files option (revert to false)")
command.Flags().BoolVar(&nameSuffix, "namesuffix", false, "Kustomize namesuffix")
command.Flags().BoolVar(&namePrefix, "nameprefix", false, "Kustomize nameprefix")
command.Flags().BoolVar(&kustomizeVersion, "kustomize-version", false, "Kustomize version")
@@ -740,9 +749,9 @@ func liveObjects(resources []*argoappv1.ResourceDiff) ([]*unstructured.Unstructu
return objs, nil
}
func getLocalObjects(app *argoappv1.Application, local, localRepoRoot, appLabelKey, kubeVersion string, kustomizeOptions *argoappv1.KustomizeOptions,
func getLocalObjects(app *argoappv1.Application, local, localRepoRoot, appLabelKey, kubeVersion string, apiVersions []string, kustomizeOptions *argoappv1.KustomizeOptions,
configManagementPlugins []*argoappv1.ConfigManagementPlugin, trackingMethod string) []*unstructured.Unstructured {
manifestStrings := getLocalObjectsString(app, local, localRepoRoot, appLabelKey, kubeVersion, kustomizeOptions, configManagementPlugins, trackingMethod)
manifestStrings := getLocalObjectsString(app, local, localRepoRoot, appLabelKey, kubeVersion, apiVersions, kustomizeOptions, configManagementPlugins, trackingMethod)
objs := make([]*unstructured.Unstructured, len(manifestStrings))
for i := range manifestStrings {
obj := unstructured.Unstructured{}
@@ -753,10 +762,10 @@ func getLocalObjects(app *argoappv1.Application, local, localRepoRoot, appLabelK
return objs
}
func getLocalObjectsString(app *argoappv1.Application, local, localRepoRoot, appLabelKey, kubeVersion string, kustomizeOptions *argoappv1.KustomizeOptions,
func getLocalObjectsString(app *argoappv1.Application, local, localRepoRoot, appLabelKey, kubeVersion string, apiVersions []string, kustomizeOptions *argoappv1.KustomizeOptions,
configManagementPlugins []*argoappv1.ConfigManagementPlugin, trackingMethod string) []string {
res, err := repository.GenerateManifests(local, localRepoRoot, app.Spec.Source.TargetRevision, &repoapiclient.ManifestRequest{
res, err := repository.GenerateManifests(context.Background(), local, localRepoRoot, app.Spec.Source.TargetRevision, &repoapiclient.ManifestRequest{
Repo: &argoappv1.Repository{Repo: app.Spec.Source.RepoURL},
AppLabelKey: appLabelKey,
AppName: app.Name,
@@ -764,9 +773,10 @@ func getLocalObjectsString(app *argoappv1.Application, local, localRepoRoot, app
ApplicationSource: &app.Spec.Source,
KustomizeOptions: kustomizeOptions,
KubeVersion: kubeVersion,
ApiVersions: apiVersions,
Plugins: configManagementPlugins,
TrackingMethod: trackingMethod,
}, true)
}, true, &git.NoopCredsStore{})
errors.CheckError(err)
return res.Manifests
@@ -851,7 +861,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
defer argoio.Close(conn)
cluster, err := clusterIf.Get(context.Background(), &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server})
errors.CheckError(err)
localObjs := groupObjsByKey(getLocalObjects(app, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod), liveObjs, app.Spec.Destination.Namespace)
localObjs := groupObjsByKey(getLocalObjects(app, local, localRepoRoot, argoSettings.AppLabelKey, cluster.Info.ServerVersion, cluster.Info.APIVersions, 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
@@ -893,10 +903,18 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
val := argoSettings.ResourceOverrides[k]
overrides[k] = *val
}
normalizer, err := argo.NewDiffNormalizer(app.Spec.IgnoreDifferences, overrides)
// TODO remove hardcoded IgnoreAggregatedRoles and retrieve the
// compareOptions in the protobuf
ignoreAggregatedRoles := false
diffConfig, err := argodiff.NewDiffConfigBuilder().
WithDiffSettings(app.Spec.IgnoreDifferences, overrides, ignoreAggregatedRoles).
WithTracking(argoSettings.AppLabelKey, argoSettings.TrackingMethod).
WithNoCache().
Build()
errors.CheckError(err)
diffRes, err := diff.Diff(item.target, item.live, diff.WithNormalizer(normalizer))
diffRes, err := argodiff.StateDiff(item.live, item.target, diffConfig)
errors.CheckError(err)
if diffRes.Modified || item.target == nil || item.live == nil {
@@ -1388,7 +1406,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
cluster, err := clusterIf.Get(context.Background(), &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server})
errors.CheckError(err)
argoio.Close(conn)
localObjsStrings = getLocalObjectsString(app, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod)
localObjsStrings = getLocalObjectsString(app, local, localRepoRoot, argoSettings.AppLabelKey, cluster.Info.ServerVersion, cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod)
}
syncOptionsFactory := func() *applicationpkg.SyncOptions {

View File

@@ -85,15 +85,6 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
log.Fatalf("Context %s does not exist in kubeconfig", contextName)
}
isTerminal := isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd())
if isTerminal && !skipConfirmation {
message := fmt.Sprintf("WARNING: This will create a service account `argocd-manager` on the cluster referenced by context `%s` with full cluster level admin privileges. Do you want to continue [y/N]? ", contextName)
if !cli.AskToProceed(message) {
os.Exit(1)
}
}
overrides := clientcmd.ConfigOverrides{
Context: *clstContext,
}
@@ -124,6 +115,14 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
if clusterOpts.ServiceAccount != "" {
managerBearerToken, err = clusterauth.GetServiceAccountBearerToken(clientset, clusterOpts.SystemNamespace, clusterOpts.ServiceAccount)
} else {
isTerminal := isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd())
if isTerminal && !skipConfirmation {
message := fmt.Sprintf("WARNING: This will create a service account `argocd-manager` on the cluster referenced by context `%s` with full cluster level admin privileges. Do you want to continue [y/N]? ", contextName)
if !cli.AskToProceed(message) {
os.Exit(1)
}
}
managerBearerToken, err = clusterauth.InstallClusterManagerRBAC(clientset, clusterOpts.SystemNamespace, clusterOpts.Namespaces)
}
errors.CheckError(err)

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

@@ -16,6 +16,7 @@ import (
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/utils/pointer"
argoapi "github.com/argoproj/argo-cd/v2/pkg/apiclient"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
@@ -27,6 +28,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,9 +46,16 @@ func testAPI(clientOpts *argoapi.ClientOptions) error {
return err
}
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 {
func InitCommand(cmd *cobra.Command, clientOpts *argoapi.ClientOptions, port *int, address *string) *cobra.Command {
ctx, cancel := context.WithCancel(context.Background())
flags := pflag.NewFlagSet("tmp", pflag.ContinueOnError)
clientConfig := cli.AddKubectlFlagsToSet(flags)
@@ -81,8 +91,12 @@ func InitCommand(cmd *cobra.Command, clientOpts *argoapi.ClientOptions, port *in
cli.SetLogLevel(log.ErrorLevel.String())
log.SetLevel(log.ErrorLevel)
os.Setenv(v1alpha1.EnvVarFakeInClusterConfig, "true")
if address == nil {
address = pointer.String("localhost")
}
if port == nil || *port == 0 {
ln, err := net.Listen("tcp", "localhost:0")
addr := fmt.Sprintf("%s:0", *address)
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
@@ -108,12 +122,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,
@@ -124,12 +140,12 @@ func InitCommand(cmd *cobra.Command, clientOpts *argoapi.ClientOptions, port *in
Cache: servercache.NewCache(appstateCache, 0, 0, 0),
KubeClientset: kubeClientset,
Insecure: true,
ListenHost: "localhost",
RepoClientset: &forwardRepoClientset{namespace: namespace},
ListenHost: *address,
RepoClientset: &forwardRepoClientset{namespace: namespace, context: context},
})
go srv.Run(ctx, *port, 0)
clientOpts.ServerAddr = fmt.Sprintf("localhost:%d", *port)
clientOpts.ServerAddr = fmt.Sprintf("%s:%d", *address, *port)
clientOpts.PlainText = true
if !cache.WaitForCacheSync(ctx.Done(), srv.Initialized) {
log.Fatal("Timed out waiting for project cache to sync")

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

@@ -13,7 +13,7 @@ import (
"time"
"github.com/coreos/go-oidc"
"github.com/dgrijalva/jwt-go/v4"
"github.com/golang-jwt/jwt/v4"
log "github.com/sirupsen/logrus"
"github.com/skratchdot/open-golang/open"
"github.com/spf13/cobra"
@@ -127,9 +127,7 @@ argocd login cd.argoproj.io --core`,
errors.CheckError(err)
tokenString, refreshToken = oauth2Login(ctx, ssoPort, acdSet.GetOIDCConfig(), oauth2conf, provider)
}
parser := &jwt.Parser{
ValidationHelper: jwt.NewValidationHelper(jwt.WithoutClaimsValidation(), jwt.WithoutAudienceValidation()),
}
parser := jwt.NewParser(jwt.WithoutClaimsValidation())
claims := jwt.MapClaims{}
_, _, err := parser.ParseUnverified(tokenString, &claims)
errors.CheckError(err)

View File

@@ -3,7 +3,7 @@ package commands
import (
"testing"
"github.com/dgrijalva/jwt-go/v4"
"github.com/golang-jwt/jwt/v4"
"github.com/stretchr/testify/assert"
)

View File

@@ -9,7 +9,7 @@ import (
"time"
timeutil "github.com/argoproj/pkg/time"
jwtgo "github.com/dgrijalva/jwt-go/v4"
jwtgo "github.com/golang-jwt/jwt/v4"
"github.com/spf13/cobra"
argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient"

View File

@@ -40,19 +40,19 @@ func NewCommand() *cobra.Command {
}
command.AddCommand(NewCompletionCommand())
command.AddCommand(headless.InitCommand(NewVersionCmd(&clientOpts), &clientOpts, nil))
command.AddCommand(headless.InitCommand(NewClusterCommand(&clientOpts, pathOpts), &clientOpts, nil))
command.AddCommand(headless.InitCommand(NewApplicationCommand(&clientOpts), &clientOpts, nil))
command.AddCommand(headless.InitCommand(NewVersionCmd(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(headless.InitCommand(NewClusterCommand(&clientOpts, pathOpts), &clientOpts, nil, nil))
command.AddCommand(headless.InitCommand(NewApplicationCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(NewLoginCommand(&clientOpts))
command.AddCommand(NewReloginCommand(&clientOpts))
command.AddCommand(headless.InitCommand(NewRepoCommand(&clientOpts), &clientOpts, nil))
command.AddCommand(headless.InitCommand(NewRepoCredsCommand(&clientOpts), &clientOpts, nil))
command.AddCommand(headless.InitCommand(NewRepoCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(headless.InitCommand(NewRepoCredsCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(NewContextCommand(&clientOpts))
command.AddCommand(headless.InitCommand(NewProjectCommand(&clientOpts), &clientOpts, nil))
command.AddCommand(headless.InitCommand(NewAccountCommand(&clientOpts), &clientOpts, nil))
command.AddCommand(headless.InitCommand(NewProjectCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(headless.InitCommand(NewAccountCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(NewLogoutCommand(&clientOpts))
command.AddCommand(headless.InitCommand(NewCertCommand(&clientOpts), &clientOpts, nil))
command.AddCommand(headless.InitCommand(NewGPGCommand(&clientOpts), &clientOpts, nil))
command.AddCommand(headless.InitCommand(NewCertCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(headless.InitCommand(NewGPGCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(admin.NewAdminCommand())
defaultLocalConfigPath, err := localconfig.DefaultLocalConfigPath()

View File

@@ -10,6 +10,8 @@ import (
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"
gitaskpass "github.com/argoproj/argo-cd/v2/cmd/argocd-git-ask-pass/commands"
notification "github.com/argoproj/argo-cd/v2/cmd/argocd-notification/commands"
reposerver "github.com/argoproj/argo-cd/v2/cmd/argocd-repo-server/commands"
apiserver "github.com/argoproj/argo-cd/v2/cmd/argocd-server/commands"
cli "github.com/argoproj/argo-cd/v2/cmd/argocd/commands"
@@ -39,6 +41,10 @@ func main() {
command = cmpserver.NewCommand()
case "argocd-dex":
command = dex.NewCommand()
case "argocd-notifications":
command = notification.NewCommand()
case "argocd-git-ask-pass":
command = gitaskpass.NewCommand()
default:
command = cli.NewCommand()
}

View File

@@ -36,6 +36,7 @@ type AppOptions struct {
destNamespace string
Parameters []string
valuesFiles []string
ignoreMissingValueFiles bool
values string
releaseName string
helmSets []string
@@ -43,6 +44,7 @@ type AppOptions struct {
helmSetFiles []string
helmVersion string
helmPassCredentials bool
helmSkipCrds bool
project string
syncPolicy string
syncOptions []string
@@ -86,6 +88,7 @@ func AddAppFlags(command *cobra.Command, opts *AppOptions) {
command.Flags().StringVar(&opts.destNamespace, "dest-namespace", "", "K8s target namespace (overrides the namespace specified in the ksonnet app.yaml)")
command.Flags().StringArrayVarP(&opts.Parameters, "parameter", "p", []string{}, "set a parameter override (e.g. -p guestbook=image=example/guestbook:latest)")
command.Flags().StringArrayVar(&opts.valuesFiles, "values", []string{}, "Helm values file(s) to use")
command.Flags().BoolVar(&opts.ignoreMissingValueFiles, "ignore-missing-value-files", false, "Ignore locally missing valueFiles when setting helm template --values")
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")
@@ -93,6 +96,7 @@ func AddAppFlags(command *cobra.Command, opts *AppOptions) {
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)")
command.Flags().BoolVar(&opts.helmSkipCrds, "helm-skip-crds", false, "Skip helm crd installation step")
command.Flags().StringVar(&opts.project, "project", "", "Application project name")
command.Flags().StringVar(&opts.syncPolicy, "sync-policy", "", "Set the sync policy (one of: none, automated (aliases of automated: auto, automatic))")
command.Flags().StringArrayVar(&opts.syncOptions, "sync-option", []string{}, "Add or remove a sync option, e.g add `Prune=false`. Remove using `!` prefix, e.g. `!Prune=false`")
@@ -147,6 +151,8 @@ func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap
spec.RevisionHistoryLimit = &i
case "values":
setHelmOpt(&spec.Source, helmOpts{valueFiles: appOpts.valuesFiles})
case "ignore-missing-value-files":
setHelmOpt(&spec.Source, helmOpts{ignoreMissingValueFiles: appOpts.ignoreMissingValueFiles})
case "values-literal-file":
var data []byte
@@ -171,6 +177,8 @@ func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap
setHelmOpt(&spec.Source, helmOpts{helmSetStrings: appOpts.helmSetStrings})
case "helm-set-file":
setHelmOpt(&spec.Source, helmOpts{helmSetFiles: appOpts.helmSetFiles})
case "helm-skip-crds":
setHelmOpt(&spec.Source, helmOpts{skipCrds: appOpts.helmSkipCrds})
case "directory-recurse":
if spec.Source.Directory != nil {
spec.Source.Directory.Recurse = appOpts.directoryRecurse
@@ -381,14 +389,16 @@ func setPluginOptEnvs(src *argoappv1.ApplicationSource, envs []string) {
}
type helmOpts struct {
valueFiles []string
values string
releaseName string
version string
helmSets []string
helmSetStrings []string
helmSetFiles []string
passCredentials bool
valueFiles []string
ignoreMissingValueFiles bool
values string
releaseName string
version string
helmSets []string
helmSetStrings []string
helmSetFiles []string
passCredentials bool
skipCrds bool
}
func setHelmOpt(src *argoappv1.ApplicationSource, opts helmOpts) {
@@ -398,6 +408,9 @@ func setHelmOpt(src *argoappv1.ApplicationSource, opts helmOpts) {
if len(opts.valueFiles) > 0 {
src.Helm.ValueFiles = opts.valueFiles
}
if opts.ignoreMissingValueFiles {
src.Helm.IgnoreMissingValueFiles = opts.ignoreMissingValueFiles
}
if len(opts.values) > 0 {
src.Helm.Values = opts.values
}
@@ -410,6 +423,9 @@ func setHelmOpt(src *argoappv1.ApplicationSource, opts helmOpts) {
if opts.passCredentials {
src.Helm.PassCredentials = opts.passCredentials
}
if opts.skipCrds {
src.Helm.SkipCrds = opts.skipCrds
}
for _, text := range opts.helmSets {
p, err := argoappv1.NewHelmParameter(text, false)
if err != nil {

View File

@@ -24,6 +24,11 @@ func Test_setHelmOpt(t *testing.T) {
setHelmOpt(&src, helmOpts{valueFiles: []string{"foo"}})
assert.Equal(t, []string{"foo"}, src.Helm.ValueFiles)
})
t.Run("IgnoreMissingValueFiles", func(t *testing.T) {
src := v1alpha1.ApplicationSource{}
setHelmOpt(&src, helmOpts{ignoreMissingValueFiles: true})
assert.Equal(t, true, src.Helm.IgnoreMissingValueFiles)
})
t.Run("ReleaseName", func(t *testing.T) {
src := v1alpha1.ApplicationSource{}
setHelmOpt(&src, helmOpts{releaseName: "foo"})
@@ -54,6 +59,11 @@ func Test_setHelmOpt(t *testing.T) {
setHelmOpt(&src, helmOpts{passCredentials: true})
assert.Equal(t, true, src.Helm.PassCredentials)
})
t.Run("HelmSkipCrds", func(t *testing.T) {
src := v1alpha1.ApplicationSource{}
setHelmOpt(&src, helmOpts{skipCrds: true})
assert.Equal(t, true, src.Helm.SkipCrds)
})
}
func Test_setKustomizeOpt(t *testing.T) {

View File

@@ -24,27 +24,23 @@ type Clientset interface {
}
type clientSet struct {
address string
timeoutSeconds int
address string
}
func (c *clientSet) NewConfigManagementPluginClient() (io.Closer, ConfigManagementPluginServiceClient, error) {
conn, err := NewConnection(c.address, c.timeoutSeconds)
conn, err := NewConnection(c.address)
if err != nil {
return nil, nil, err
}
return conn, NewConfigManagementPluginServiceClient(conn), nil
}
func NewConnection(address string, timeoutSeconds int) (*grpc.ClientConn, error) {
func NewConnection(address string) (*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...)),
@@ -60,7 +56,7 @@ func NewConnection(address string, timeoutSeconds int) (*grpc.ClientConn, error)
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}
// NewConfigManagementPluginClientSet creates new instance of config management plugin server Clientset
func NewConfigManagementPluginClientSet(address string) Clientset {
return &clientSet{address: address}
}

View File

@@ -1,21 +1,31 @@
package plugin
import (
"bytes"
"context"
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"github.com/argoproj/pkg/rand"
"github.com/argoproj/argo-cd/v2/util/buffered_context"
"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"
)
// cmpTimeoutBuffer is the amount of time before the request deadline to timeout server-side work. It makes sure there's
// enough time before the client times out to send a meaningful error message.
const cmpTimeoutBuffer = 100 * time.Millisecond
// Service implements ConfigManagementPluginService interface
type Service struct {
initConstants CMPServerInitConstants
@@ -32,14 +42,78 @@ func NewService(initConstants CMPServerInitConstants) *Service {
}
}
func runCommand(command Command, path string, env []string) (string, error) {
func runCommand(ctx context.Context, 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 := exec.CommandContext(ctx, command.Command[0], append(command.Command[1:], command.Args...)...)
cmd.Env = env
cmd.Dir = path
return executil.Run(cmd)
execId, err := rand.RandString(5)
if err != nil {
return "", err
}
logCtx := log.WithFields(log.Fields{"execID": execId})
// log in a way we can copy-and-paste into a terminal
args := strings.Join(cmd.Args, " ")
logCtx.WithFields(log.Fields{"dir": cmd.Dir}).Info(args)
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
// Make sure the command is killed immediately on timeout. https://stackoverflow.com/a/38133948/684776
cmd.SysProcAttr = newSysProcAttr(true)
start := time.Now()
err = cmd.Start()
if err != nil {
return "", err
}
go func() {
<-ctx.Done()
// Kill by group ID to make sure child processes are killed. The - tells `kill` that it's a group ID.
// Since we didn't set Pgid in SysProcAttr, the group ID is the same as the process ID. https://pkg.go.dev/syscall#SysProcAttr
_ = sysCallKill(-cmd.Process.Pid)
}()
err = cmd.Wait()
duration := time.Since(start)
output := stdout.String()
logCtx.WithFields(log.Fields{"duration": duration}).Debug(output)
if err != nil {
err := newCmdError(args, errors.New(err.Error()), strings.TrimSpace(stderr.String()))
logCtx.Error(err.Error())
return strings.TrimSuffix(output, "\n"), err
}
return strings.TrimSuffix(output, "\n"), nil
}
type CmdError struct {
Args string
Stderr string
Cause error
}
func (ce *CmdError) Error() string {
res := fmt.Sprintf("`%v` failed %v", ce.Args, ce.Cause)
if ce.Stderr != "" {
res = fmt.Sprintf("%s: %s", res, ce.Stderr)
}
return res
}
func newCmdError(args string, cause error, stderr string) *CmdError {
return &CmdError{Args: args, Stderr: stderr, Cause: cause}
}
// Environ returns a list of environment variables in name=value format from a list of variables
@@ -55,17 +129,26 @@ func environ(envVars []*apiclient.EnvEntry) []string {
// 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) {
bufferedCtx, cancel := buffered_context.WithEarlierDeadline(ctx, cmpTimeoutBuffer)
defer cancel()
if deadline, ok := bufferedCtx.Deadline(); ok {
log.Infof("Generating manifests with deadline %v from now", time.Until(deadline))
} else {
log.Info("Generating manifests with no request-level timeout")
}
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)
_, err := runCommand(bufferedCtx, config.Spec.Init, q.AppPath, env)
if err != nil {
return &apiclient.ManifestResponse{}, err
}
}
out, err := runCommand(config.Spec.Generate, q.AppPath, env)
out, err := runCommand(bufferedCtx, config.Spec.Generate, q.AppPath, env)
if err != nil {
return &apiclient.ManifestResponse{}, err
}
@@ -82,6 +165,9 @@ func (s *Service) GenerateManifest(ctx context.Context, q *apiclient.ManifestReq
// 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) {
bufferedCtx, cancel := buffered_context.WithEarlierDeadline(ctx, cmpTimeoutBuffer)
defer cancel()
var repoResponse apiclient.RepositoryResponse
config := s.initConstants.PluginConfig
if config.Spec.Discover.FileName != "" {
@@ -113,7 +199,7 @@ func (s *Service) MatchRepository(ctx context.Context, q *apiclient.RepositoryRe
}
log.Debugf("Going to try runCommand.")
find, err := runCommand(config.Spec.Discover.Find.Command, q.Path, os.Environ())
find, err := runCommand(bufferedCtx, config.Spec.Discover.Find.Command, q.Path, os.Environ())
if err != nil {
return &repoResponse, err
}

View File

@@ -4,7 +4,9 @@ import (
"context"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/argoproj/argo-cd/v2/cmpserver/apiclient"
@@ -63,3 +65,19 @@ func TestGenerateManifest(t *testing.T) {
require.Equal(t, expectedOutput, res1.Manifests[0])
}
}
// TestRunCommandContextTimeout makes sure the command dies at timeout rather than sleeping past the timeout.
func TestRunCommandContextTimeout(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 990*time.Millisecond)
defer cancel()
// Use a subshell so there's a child command.
command := Command{
Command: []string{"sh", "-c"},
Args: []string{"sleep 5"},
}
before := time.Now()
_, err := runCommand(ctx, command, "", []string{})
after := time.Now()
assert.Error(t, err) // The command should time out, causing an error.
assert.Less(t, after.Sub(before), 1*time.Second)
}

View File

@@ -0,0 +1,16 @@
//go:build !windows
// +build !windows
package plugin
import (
"syscall"
)
func newSysProcAttr(setpgid bool) *syscall.SysProcAttr {
return &syscall.SysProcAttr{Setpgid: setpgid}
}
func sysCallKill(pid int) error {
return syscall.Kill(pid, syscall.SIGKILL)
}

View File

@@ -0,0 +1,16 @@
//go:build windows
// +build windows
package plugin
import (
"syscall"
)
func newSysProcAttr(setpgid bool) *syscall.SysProcAttr {
return &syscall.SysProcAttr{}
}
func sysCallKill(pid int) error {
return nil
}

View File

@@ -42,6 +42,11 @@ const (
DefaultPortRepoServerMetrics = 8084
)
// Default listener address for ArgoCD components
const (
DefaultAddressAPIServer = "localhost"
)
// Default paths on the pod's file system
const (
// The default path where TLS certificates for repositories are located
@@ -71,6 +76,10 @@ const (
ArgoCDUserAgentName = "argocd-client"
// AuthCookieName is the HTTP cookie name where we store our auth token
AuthCookieName = "argocd.token"
// StateCookieName is the HTTP cookie name that holds temporary nonce tokens for CSRF protection
StateCookieName = "argocd.oauthstate"
// StateCookieMaxAge is the maximum age of the oauth state cookie
StateCookieMaxAge = time.Minute * 5
// ChangePasswordSSOTokenMaxAge is the max token age for password change operation
ChangePasswordSSOTokenMaxAge = time.Minute * 5

View File

@@ -28,6 +28,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
apiruntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
@@ -36,9 +37,6 @@ import (
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
// make sure to register workqueue prometheus metrics
_ "k8s.io/component-base/metrics/prometheus/workqueue"
statecache "github.com/argoproj/argo-cd/v2/controller/cache"
"github.com/argoproj/argo-cd/v2/controller/metrics"
"github.com/argoproj/argo-cd/v2/pkg/apis/application"
@@ -48,6 +46,7 @@ import (
applisters "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/util/argo"
argodiff "github.com/argoproj/argo-cd/v2/util/argo/diff"
appstatecache "github.com/argoproj/argo-cd/v2/util/cache/appstate"
"github.com/argoproj/argo-cd/v2/util/db"
"github.com/argoproj/argo-cd/v2/util/errors"
@@ -166,19 +165,26 @@ func NewApplicationController(
AddFunc: func(obj interface{}) {
if key, err := cache.MetaNamespaceKeyFunc(obj); err == nil {
ctrl.projectRefreshQueue.Add(key)
ctrl.InvalidateProjectsCache()
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)
ctrl.InvalidateProjectsCache()
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)
ctrl.InvalidateProjectsCache()
if projMeta, ok := obj.(metav1.Object); ok {
ctrl.InvalidateProjectsCache(projMeta.GetName())
}
}
},
})
@@ -207,11 +213,17 @@ func NewApplicationController(
return &ctrl, nil
}
func (ctrl *ApplicationController) InvalidateProjectsCache() {
ctrl.projByNameCache.Range(func(key, _ interface{}) bool {
ctrl.projByNameCache.Delete(key)
return true
})
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 {
@@ -284,12 +296,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
}
}
}
@@ -309,12 +317,27 @@ func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]b
if isManagedResource {
level = CompareWithRecent
}
// Additional check for debug level so we don't need to evaluate the
// format string in case of non-debug scenarios
if log.GetLevel() >= log.DebugLevel {
var resKey string
if ref.Namespace != "" {
resKey = ref.Namespace + "/" + ref.Name
} else {
resKey = "(cluster-scoped)/" + ref.Name
}
log.Debugf("Refreshing app %s for change in cluster of object %s of type %s/%s", appName, resKey, ref.APIVersion, ref.Kind)
}
ctrl.requestAppRefresh(appName, &level, nil)
}
}
// setAppManagedResources will build a list of ResourceDiff based on the provided comparisonResult
// and persist app resources related data in the cache. Will return the persisted ApplicationTree.
func (ctrl *ApplicationController) setAppManagedResources(a *appv1.Application, comparisonResult *comparisonResult) (*appv1.ApplicationTree, error) {
managedResources, err := ctrl.managedResources(comparisonResult)
managedResources, err := ctrl.hideSecretData(a, comparisonResult)
if err != nil {
return nil, fmt.Errorf("error getting managed resources: %s", err)
}
@@ -360,7 +383,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, ctrl.db, context.TODO())
proj, err := ctrl.getAppProj(a)
if err != nil {
return nil, err
}
@@ -399,8 +422,12 @@ func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managed
},
})
} else {
err := ctrl.stateCache.IterateHierarchy(a.Spec.Destination.Server, kube.GetResourceKey(live), func(child appv1.ResourceNode, appName string) {
err := ctrl.stateCache.IterateHierarchy(a.Spec.Destination.Server, kube.GetResourceKey(live), func(child appv1.ResourceNode, appName string) bool {
if !proj.IsResourcePermitted(schema.GroupKind{Group: child.ResourceRef.Group, Kind: child.ResourceRef.Kind}, child.Namespace, a.Spec.Destination) {
return false
}
nodes = append(nodes, child)
return true
})
if err != nil {
return nil, err
@@ -410,16 +437,18 @@ func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managed
orphanedNodes := make([]appv1.ResourceNode, 0)
for k := range orphanedNodesMap {
if k.Namespace != "" && proj.IsGroupKindPermitted(k.GroupKind(), true) && !isKnownOrphanedResourceExclusion(k, proj) {
err := ctrl.stateCache.IterateHierarchy(a.Spec.Destination.Server, k, func(child appv1.ResourceNode, appName string) {
err := ctrl.stateCache.IterateHierarchy(a.Spec.Destination.Server, k, func(child appv1.ResourceNode, appName string) bool {
belongToAnotherApp := false
if appName != "" {
if _, exists, err := ctrl.appInformer.GetIndexer().GetByKey(ctrl.namespace + "/" + appName); exists && err == nil {
belongToAnotherApp = true
}
}
if !belongToAnotherApp {
orphanedNodes = append(orphanedNodes, child)
if belongToAnotherApp || !proj.IsResourcePermitted(schema.GroupKind{Group: child.ResourceRef.Group, Kind: child.ResourceRef.Kind}, child.Namespace, a.Spec.Destination) {
return false
}
orphanedNodes = append(orphanedNodes, child)
return true
})
if err != nil {
return nil, err
@@ -534,7 +563,7 @@ func (ctrl *ApplicationController) getAppHosts(a *appv1.Application, appNodes []
return hosts, nil
}
func (ctrl *ApplicationController) managedResources(comparisonResult *comparisonResult) ([]*appv1.ResourceDiff, error) {
func (ctrl *ApplicationController) hideSecretData(app *appv1.Application, comparisonResult *comparisonResult) ([]*appv1.ResourceDiff, error) {
items := make([]*appv1.ResourceDiff, len(comparisonResult.managedResources))
for i := range comparisonResult.managedResources {
res := comparisonResult.managedResources[i]
@@ -560,14 +589,34 @@ func (ctrl *ApplicationController) managedResources(comparisonResult *comparison
if err != nil {
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))
resourceOverrides, err := ctrl.settingsMgr.GetResourceOverrides()
if err != nil {
return nil, fmt.Errorf("error getting resource overrides: %s", err)
}
appLabelKey, err := ctrl.settingsMgr.GetAppInstanceLabelKey()
if err != nil {
return nil, fmt.Errorf("error getting app instance label key: %s", err)
}
trackingMethod, err := ctrl.settingsMgr.GetTrackingMethod()
if err != nil {
return nil, fmt.Errorf("error getting tracking method: %s", err)
}
diffConfig, err := argodiff.NewDiffConfigBuilder().
WithDiffSettings(app.Spec.IgnoreDifferences, resourceOverrides, compareOptions.IgnoreAggregatedRoles).
WithTracking(appLabelKey, trackingMethod).
WithNoCache().
WithLogger(logutils.NewLogrusLogger(logutils.NewWithCurrentConfig())).
Build()
if err != nil {
return nil, fmt.Errorf("appcontroller error building diff config: %s", err)
}
diffResult, err := argodiff.StateDiff(live, target, diffConfig)
if err != nil {
return nil, fmt.Errorf("error applying diff: %s", err)
}
resDiff = *resDiffPtr
resDiff = diffResult
}
if live != nil {
@@ -1093,7 +1142,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 {
@@ -1249,6 +1298,13 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
app.Status.Sync.Status = appv1.SyncStatusCodeUnknown
app.Status.Health.Status = health.HealthStatusUnknown
ctrl.persistAppStatus(origApp, &app.Status)
if err := ctrl.cache.SetAppResourcesTree(app.Name, &appv1.ApplicationTree{}); err != nil {
log.Warnf("failed to set app resource tree: %v", err)
}
if err := ctrl.cache.SetAppManagedResources(app.Name, nil); err != nil {
log.Warnf("failed to set app managed resources tree: %v", err)
}
return
}
@@ -1638,7 +1694,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

@@ -136,12 +136,12 @@ func newFakeController(data *fakeData) *ApplicationController {
mockStateCache.On("GetClusterCache", mock.Anything).Return(&clusterCacheMock, nil)
mockStateCache.On("IterateHierarchy", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
key := args[1].(kube.ResourceKey)
action := args[2].(func(child argoappv1.ResourceNode, appName string))
action := args[2].(func(child argoappv1.ResourceNode, appName string) bool)
appName := ""
if res, ok := data.namespacedResources[key]; ok {
appName = res.AppName
}
action(argoappv1.ResourceNode{ResourceRef: argoappv1.ResourceRef{Kind: key.Kind, Group: key.Group, Namespace: key.Namespace, Name: key.Name}}, appName)
_ = action(argoappv1.ResourceNode{ResourceRef: argoappv1.ResourceRef{Kind: key.Kind, Group: key.Group, Namespace: key.Namespace, Name: key.Name}}, appName)
}).Return(nil)
return ctrl
}
@@ -785,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) {

View File

@@ -2,10 +2,12 @@ package cache
import (
"context"
"errors"
"fmt"
"os"
"math"
"reflect"
"sync"
"syscall"
"time"
clustercache "github.com/argoproj/gitops-engine/pkg/cache"
@@ -14,6 +16,7 @@ import (
log "github.com/sirupsen/logrus"
"golang.org/x/sync/semaphore"
v1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -24,6 +27,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,20 +36,64 @@ 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"
// EnvClusterRetryTimeoutDuration is the env variable that holds cluster retry duration when sync error happens
EnvClusterSyncRetryTimeoutDuration = "ARGOCD_CLUSTER_SYNC_RETRY_TIMEOUT_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"
// EnvClusterCacheRetryLimit is the env variable to control the retry limit for listing resources during cluster cache sync
EnvClusterCacheAttemptLimit = "ARGOCD_CLUSTER_CACHE_ATTEMPT_LIMIT"
// EnvClusterCacheRetryUseBackoff is the env variable to control whether to use a backoff strategy with the retry during cluster cache sync
EnvClusterCacheRetryUseBackoff = "ARGOCD_CLUSTER_CACHE_RETRY_USE_BACKOFF"
)
// 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
// clusterSyncRetryTimeoutDuration controls the sync retry duration when cluster sync error happens
clusterSyncRetryTimeoutDuration = 10 * time.Second
// 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
// clusterCacheRetryLimit sets a retry limit for failed requests during cluster cache sync
// If set to 1, retries are disabled.
clusterCacheAttemptLimit int32 = 1
// clusterCacheRetryUseBackoff specifies whether to use a backoff strategy on cluster cache sync, if retry is enabled
clusterCacheRetryUseBackoff bool = false
)
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)
clusterSyncRetryTimeoutDuration = env.ParseDurationFromEnv(EnvClusterSyncRetryTimeoutDuration, clusterSyncRetryTimeoutDuration, 0, math.MaxInt64)
clusterCacheListPageSize = env.ParseInt64FromEnv(EnvClusterCacheListPageSize, clusterCacheListPageSize, 0, math.MaxInt64)
clusterCacheListSemaphoreSize = env.ParseInt64FromEnv(EnvClusterCacheListSemaphore, clusterCacheListSemaphoreSize, 0, math.MaxInt64)
clusterCacheAttemptLimit = int32(env.ParseInt64FromEnv(EnvClusterCacheAttemptLimit, 1, 1, math.MaxInt32))
clusterCacheRetryUseBackoff = env.ParseBoolFromEnv(EnvClusterCacheRetryUseBackoff, false)
}
type LiveStateCache interface {
@@ -56,7 +104,7 @@ type LiveStateCache interface {
// Returns synced cluster cache
GetClusterCache(server string) (clustercache.ClusterCache, error)
// Executes give callback against resource specified by the key and all its children
IterateHierarchy(server string, key kube.ResourceKey, action func(child appv1.ResourceNode, appName string)) error
IterateHierarchy(server string, key kube.ResourceKey, action func(child appv1.ResourceNode, appName string) bool) error
// Returns state of live nodes which correspond for target nodes of specified application.
GetManagedLiveObjs(a *appv1.Application, targetObjs []*unstructured.Unstructured) (map[kube.ResourceKey]*unstructured.Unstructured, error)
// IterateResources iterates all resource stored in cache
@@ -109,15 +157,13 @@ func NewLiveStateCache(
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),
appInformer: appInformer,
db: db,
clusters: make(map[string]clustercache.ClusterCache),
onObjectUpdated: onObjectUpdated,
kubectl: kubectl,
settingsMgr: settingsMgr,
metricsServer: metricsServer,
clusterFilter: clusterFilter,
resourceTracking: resourceTracking,
}
@@ -138,10 +184,6 @@ type liveStateCache struct {
clusterFilter func(cluster *appv1.Cluster) bool
resourceTracking argo.ResourceTracking
// listSemaphore is used to limit the number of concurrent memory consuming operations on the
// k8s list queries results across all clusters to avoid memory spikes during cache initialization.
listSemaphore *semaphore.Weighted
clusters map[string]clustercache.ClusterCache
cacheSettings cacheSettings
lock sync.RWMutex
@@ -261,6 +303,19 @@ func skipAppRequeuing(key kube.ResourceKey) bool {
return ignoredRefreshResources[key.Group+"/"+key.Kind]
}
// isRetryableError is a helper method to see whether an error
// returned from the dynamic client is potentially retryable.
func isRetryableError(err error) bool {
return kerrors.IsInternalError(err) ||
kerrors.IsInvalid(err) ||
kerrors.IsServerTimeout(err) ||
kerrors.IsServiceUnavailable(err) ||
kerrors.IsTimeout(err) ||
kerrors.IsUnexpectedObjectError(err) ||
kerrors.IsUnexpectedServerError(err) ||
errors.Is(err, syscall.ECONNRESET)
}
func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, error) {
c.lock.RLock()
clusterCache, ok := c.clusters[server]
@@ -289,9 +344,12 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
}
trackingMethod := argo.GetTrackingMethod(c.settingsMgr)
clusterCache = clustercache.NewClusterCache(cluster.RESTConfig(),
clustercache.SetListSemaphore(c.listSemaphore),
clustercache.SetResyncTimeout(K8SClusterResyncDuration),
clusterCacheOpts := []clustercache.UpdateSettingsFunc{
clustercache.SetListSemaphore(semaphore.NewWeighted(clusterCacheListSemaphoreSize)),
clustercache.SetListPageSize(clusterCacheListPageSize),
clustercache.SetWatchResyncTimeout(clusterCacheWatchResyncDuration),
clustercache.SetClusterSyncRetryTimeout(clusterSyncRetryTimeoutDuration),
clustercache.SetResyncTimeout(clusterCacheResyncDuration),
clustercache.SetSettings(cacheSettings.clusterSettings),
clustercache.SetNamespaces(cluster.Namespaces),
clustercache.SetClusterResources(cluster.ClusterResources),
@@ -311,7 +369,10 @@ 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.SetRetryOptions(clusterCacheAttemptLimit, clusterCacheRetryUseBackoff, isRetryableError),
}
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)
@@ -376,13 +437,13 @@ func (c *liveStateCache) IsNamespaced(server string, gk schema.GroupKind) (bool,
return clusterInfo.IsNamespaced(gk)
}
func (c *liveStateCache) IterateHierarchy(server string, key kube.ResourceKey, action func(child appv1.ResourceNode, appName string)) error {
func (c *liveStateCache) IterateHierarchy(server string, key kube.ResourceKey, action func(child appv1.ResourceNode, appName string) bool) error {
clusterInfo, err := c.getSyncedCluster(server)
if err != nil {
return err
}
clusterInfo.IterateHierarchy(key, func(resource *clustercache.Resource, namespaceResources map[kube.ResourceKey]*clustercache.Resource) {
action(asResourceNode(resource), getApp(resource, namespaceResources))
clusterInfo.IterateHierarchy(key, func(resource *clustercache.Resource, namespaceResources map[kube.ResourceKey]*clustercache.Resource) bool {
return action(asResourceNode(resource), getApp(resource, namespaceResources))
})
return nil
}

View File

@@ -30,25 +30,20 @@ func populateNodeInfo(un *unstructured.Unstructured, res *ResourceInfo) {
switch gvk.Kind {
case kube.PodKind:
populatePodInfo(un, res)
return
case kube.ServiceKind:
populateServiceInfo(un, res)
return
case "Node":
populateHostNodeInfo(un, res)
return
}
case "extensions", "networking.k8s.io":
switch gvk.Kind {
case kube.IngressKind:
populateIngressInfo(un, res)
return
}
case "networking.istio.io":
switch gvk.Kind {
case "VirtualService":
populateIstioVirtualServiceInfo(un, res)
return
}
}

View File

@@ -43,6 +43,25 @@ var (
ingress:
- hostname: localhost`)
testLinkAnnotatedService = strToUnstructured(`
apiVersion: v1
kind: Service
metadata:
name: helm-guestbook
namespace: default
resourceVersion: "123"
uid: "4"
annotations:
link.argocd.argoproj.io/external-link: http://my-grafana.com/pre-generated-link
spec:
selector:
app: guestbook
type: LoadBalancer
status:
loadBalancer:
ingress:
- hostname: localhost`)
testIngress = strToUnstructured(`
apiVersion: extensions/v1beta1
kind: Ingress
@@ -74,6 +93,39 @@ var (
ingress:
- ip: 107.178.210.11`)
testLinkAnnotatedIngress = strToUnstructured(`
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: helm-guestbook
namespace: default
uid: "4"
annotations:
link.argocd.argoproj.io/external-link: http://my-grafana.com/ingress-link
spec:
backend:
serviceName: not-found-service
servicePort: 443
rules:
- host: helm-guestbook.com
http:
paths:
- backend:
serviceName: helm-guestbook
servicePort: 443
path: /
- backend:
serviceName: helm-guestbook
servicePort: https
path: /
tls:
- host: helm-guestbook.com
secretName: my-tls-secret
status:
loadBalancer:
ingress:
- ip: 107.178.210.11`)
testIngressWildCardPath = strToUnstructured(`
apiVersion: extensions/v1beta1
kind: Ingress
@@ -268,6 +320,17 @@ func TestGetServiceInfo(t *testing.T) {
}, info.NetworkingInfo)
}
func TestGetLinkAnnotatedServiceInfo(t *testing.T) {
info := &ResourceInfo{}
populateNodeInfo(testLinkAnnotatedService, info)
assert.Equal(t, 0, len(info.Info))
assert.Equal(t, &v1alpha1.ResourceNetworkingInfo{
TargetLabels: map[string]string{"app": "guestbook"},
Ingress: []v1.LoadBalancerIngress{{Hostname: "localhost"}},
ExternalURLs: []string{"http://my-grafana.com/pre-generated-link"},
}, info.NetworkingInfo)
}
func TestGetIstioVirtualServiceInfo(t *testing.T) {
info := &ResourceInfo{}
populateNodeInfo(testIstioVirtualService, info)
@@ -323,6 +386,30 @@ func TestGetIngressInfo(t *testing.T) {
}
}
func TestGetLinkAnnotatedIngressInfo(t *testing.T) {
info := &ResourceInfo{}
populateNodeInfo(testLinkAnnotatedIngress, 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/", "http://my-grafana.com/ingress-link"},
}, info.NetworkingInfo)
}
func TestGetIngressInfoWildCardPath(t *testing.T) {
info := &ResourceInfo{}
populateNodeInfo(testIngressWildCardPath, info)

View File

@@ -176,11 +176,11 @@ func (_m *LiveStateCache) IsNamespaced(server string, gk schema.GroupKind) (bool
}
// IterateHierarchy provides a mock function with given fields: server, key, action
func (_m *LiveStateCache) IterateHierarchy(server string, key kube.ResourceKey, action func(v1alpha1.ResourceNode, string)) error {
func (_m *LiveStateCache) IterateHierarchy(server string, key kube.ResourceKey, action func(v1alpha1.ResourceNode, string) bool) error {
ret := _m.Called(server, key, action)
var r0 error
if rf, ok := ret.Get(0).(func(string, kube.ResourceKey, func(v1alpha1.ResourceNode, string)) error); ok {
if rf, ok := ret.Get(0).(func(string, kube.ResourceKey, func(v1alpha1.ResourceNode, string) bool) error); ok {
r0 = rf(server, key, action)
} else {
r0 = ret.Error(0)

View File

@@ -64,6 +64,7 @@ func (c *clusterInfoUpdater) updateClusters() {
clusters, err := c.db.ListClusters(context.Background())
if err != nil {
log.Warnf("Failed to save clusters info: %v", err)
return
}
var clustersFiltered []appv1.Cluster
if c.clusterFilter == nil {

View File

@@ -6,8 +6,8 @@ import (
"fmt"
"net/http"
"os"
"regexp"
"strconv"
"strings"
"time"
"github.com/argoproj/gitops-engine/pkg/health"
@@ -159,6 +159,7 @@ func NewMetricsServer(addr string, appLister applister.ApplicationLister, appFil
mux := http.NewServeMux()
registry := NewAppRegistry(appLister, appFilter, appLabels)
registry.MustRegister(depth, adds, latency, workDuration, unfinished, longestRunningProcessor, retries)
mux.Handle(MetricsPath, promhttp.HandlerFor(prometheus.Gatherers{
// contains app controller specific metrics
registry,
@@ -196,11 +197,14 @@ func NewMetricsServer(addr string, appLister applister.ApplicationLister, appFil
}, nil
}
// Prometheus invalid labels, more info: https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels.
var invalidPromLabelChars = regexp.MustCompile(`[^a-zA-Z0-9_]`)
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, "-", "_")
curr := invalidPromLabelChars.ReplaceAllString(label, "_")
result := fmt.Sprintf("%s_%s", prefix, curr)
results = append(results, result)
}

View File

@@ -33,6 +33,7 @@ metadata:
labels:
team-name: my-team
team-bu: bu-id
argoproj.io/cluster: test-cluster
spec:
destination:
namespace: dummy-namespace
@@ -57,6 +58,7 @@ metadata:
labels:
team-name: my-team
team-bu: bu-id
argoproj.io/cluster: test-cluster
spec:
destination:
namespace: dummy-namespace
@@ -87,6 +89,7 @@ metadata:
labels:
team-name: my-team
team-bu: bu-id
argoproj.io/cluster: test-cluster
spec:
destination:
namespace: dummy-namespace
@@ -254,14 +257,14 @@ func TestMetricLabels(t *testing.T) {
cases := []testCases{
{
description: "will return the labels metrics successfully",
metricLabels: []string{"team-name", "team-bu"},
metricLabels: []string{"team-name", "team-bu", "argoproj.io/cluster"},
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
argocd_app_labels{label_argoproj_io_cluster="test-cluster",label_team_bu="bu-id",label_team_name="my-team",name="my-app",namespace="argocd",project="important-project"} 1
argocd_app_labels{label_argoproj_io_cluster="test-cluster",label_team_bu="bu-id",label_team_name="my-team",name="my-app-2",namespace="argocd",project="important-project"} 1
argocd_app_labels{label_argoproj_io_cluster="test-cluster",label_team_bu="bu-id",label_team_name="my-team",name="my-app-3",namespace="argocd",project="important-project"} 1
`,
},
},

View File

@@ -0,0 +1,101 @@
package metrics
import (
"github.com/prometheus/client_golang/prometheus"
"k8s.io/client-go/util/workqueue"
)
const (
WorkQueueSubsystem = "workqueue"
DepthKey = "depth"
AddsKey = "adds_total"
QueueLatencyKey = "queue_duration_seconds"
WorkDurationKey = "work_duration_seconds"
UnfinishedWorkKey = "unfinished_work_seconds"
LongestRunningProcessorKey = "longest_running_processor_seconds"
RetriesKey = "retries_total"
)
var (
depth = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Subsystem: WorkQueueSubsystem,
Name: DepthKey,
Help: "Current depth of workqueue",
}, []string{"name"})
adds = prometheus.NewCounterVec(prometheus.CounterOpts{
Subsystem: WorkQueueSubsystem,
Name: AddsKey,
Help: "Total number of adds handled by workqueue",
}, []string{"name"})
latency = prometheus.NewHistogramVec(prometheus.HistogramOpts{
Subsystem: WorkQueueSubsystem,
Name: QueueLatencyKey,
Help: "How long in seconds an item stays in workqueue before being requested",
Buckets: []float64{1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1, 5, 10, 15, 30, 60, 120, 180},
}, []string{"name"})
workDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
Subsystem: WorkQueueSubsystem,
Name: WorkDurationKey,
Help: "How long in seconds processing an item from workqueue takes.",
Buckets: []float64{1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1, 5, 10, 15, 30, 60, 120, 180},
}, []string{"name"})
unfinished = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Subsystem: WorkQueueSubsystem,
Name: UnfinishedWorkKey,
Help: "How many seconds of work has been done that " +
"is in progress and hasn't been observed by work_duration. Large " +
"values indicate stuck threads. One can deduce the number of stuck " +
"threads by observing the rate at which this increases.",
}, []string{"name"})
longestRunningProcessor = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Subsystem: WorkQueueSubsystem,
Name: LongestRunningProcessorKey,
Help: "How many seconds has the longest running " +
"processor for workqueue been running.",
}, []string{"name"})
retries = prometheus.NewCounterVec(prometheus.CounterOpts{
Subsystem: WorkQueueSubsystem,
Name: RetriesKey,
Help: "Total number of retries handled by workqueue",
}, []string{"name"})
)
func init() {
workqueue.SetProvider(workqueueMetricsProvider{})
}
type workqueueMetricsProvider struct{}
func (workqueueMetricsProvider) NewDepthMetric(name string) workqueue.GaugeMetric {
return depth.WithLabelValues(name)
}
func (workqueueMetricsProvider) NewAddsMetric(name string) workqueue.CounterMetric {
return adds.WithLabelValues(name)
}
func (workqueueMetricsProvider) NewLatencyMetric(name string) workqueue.HistogramMetric {
return latency.WithLabelValues(name)
}
func (workqueueMetricsProvider) NewWorkDurationMetric(name string) workqueue.HistogramMetric {
return workDuration.WithLabelValues(name)
}
func (workqueueMetricsProvider) NewUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric {
return unfinished.WithLabelValues(name)
}
func (workqueueMetricsProvider) NewLongestRunningProcessorSecondsMetric(name string) workqueue.SettableGaugeMetric {
return longestRunningProcessor.WithLabelValues(name)
}
func (workqueueMetricsProvider) NewRetriesMetric(name string) workqueue.CounterMetric {
return retries.WithLabelValues(name)
}

View File

@@ -13,7 +13,6 @@ import (
hookutil "github.com/argoproj/gitops-engine/pkg/sync/hook"
"github.com/argoproj/gitops-engine/pkg/sync/ignore"
resourceutil "github.com/argoproj/gitops-engine/pkg/sync/resource"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
kubeutil "github.com/argoproj/gitops-engine/pkg/utils/kube"
log "github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -30,6 +29,7 @@ import (
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/util/argo"
argodiff "github.com/argoproj/argo-cd/v2/util/argo/diff"
appstatecache "github.com/argoproj/argo-cd/v2/util/cache/appstate"
"github.com/argoproj/argo-cd/v2/util/db"
"github.com/argoproj/argo-cd/v2/util/gpg"
@@ -71,7 +71,7 @@ type comparisonResult struct {
resources []v1alpha1.ResourceStatus
managedResources []managedResource
reconciliationResult sync.ReconciliationResult
diffNormalizer diff.Normalizer
diffConfig argodiff.DiffConfig
appSourceType v1alpha1.ApplicationSourceType
// timings maps phases of comparison to the duration it took to complete (for statistical purposes)
timings map[string]time.Duration
@@ -140,6 +140,10 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
if err != nil {
return nil, nil, err
}
enabledSourceTypes, err := m.settingsMgr.GetEnabledSourceTypes()
if err != nil {
return nil, nil, err
}
ts.AddCheckpoint("plugins_ms")
tools := make([]*appv1.ConfigManagementPlugin, len(plugins))
for i := range plugins {
@@ -155,6 +159,11 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
if err != nil {
return nil, nil, err
}
helmOptions, err := m.settingsMgr.GetHelmSettings()
if err != nil {
return nil, nil, err
}
ts.AddCheckpoint("build_options_ms")
serverVersion, apiResources, err := m.liveStateCache.GetVersionsInfo(app.Spec.Destination.Server)
if err != nil {
@@ -162,22 +171,24 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
}
ts.AddCheckpoint("version_ms")
manifestInfo, err := repoClient.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
Repo: repo,
Repos: permittedHelmRepos,
Revision: revision,
NoCache: noCache,
NoRevisionCache: noRevisionCache,
AppLabelKey: appLabelKey,
AppName: app.Name,
Namespace: app.Spec.Destination.Namespace,
ApplicationSource: &source,
Plugins: tools,
KustomizeOptions: kustomizeOptions,
KubeVersion: serverVersion,
ApiVersions: argo.APIResourcesToStrings(apiResources, true),
VerifySignature: verifySignature,
HelmRepoCreds: permittedHelmCredentials,
TrackingMethod: string(argo.GetTrackingMethod(m.settingsMgr)),
Repo: repo,
Repos: permittedHelmRepos,
Revision: revision,
NoCache: noCache,
NoRevisionCache: noRevisionCache,
AppLabelKey: appLabelKey,
AppName: app.Name,
Namespace: app.Spec.Destination.Namespace,
ApplicationSource: &source,
Plugins: tools,
KustomizeOptions: kustomizeOptions,
KubeVersion: serverVersion,
ApiVersions: argo.APIResourcesToStrings(apiResources, true),
VerifySignature: verifySignature,
HelmRepoCreds: permittedHelmCredentials,
TrackingMethod: string(argo.GetTrackingMethod(m.settingsMgr)),
EnabledSourceTypes: enabledSourceTypes,
HelmOptions: helmOptions,
})
if err != nil {
return nil, nil, err
@@ -251,24 +262,22 @@ func DeduplicateTargetObjects(
return result, conditions, nil
}
func (m *appStateManager) getComparisonSettings(app *appv1.Application) (string, map[string]v1alpha1.ResourceOverride, diff.Normalizer, *settings.ResourcesFilter, error) {
// getComparisonSettings will return the system level settings related to the
// diff/normalization process.
func (m *appStateManager) getComparisonSettings() (string, map[string]v1alpha1.ResourceOverride, *settings.ResourcesFilter, error) {
resourceOverrides, err := m.settingsMgr.GetResourceOverrides()
if err != nil {
return "", nil, nil, nil, err
return "", nil, nil, err
}
appLabelKey, err := m.settingsMgr.GetAppInstanceLabelKey()
if err != nil {
return "", nil, nil, nil, err
}
diffNormalizer, err := argo.NewDiffNormalizer(app.Spec.IgnoreDifferences, resourceOverrides)
if err != nil {
return "", nil, nil, nil, err
return "", nil, nil, err
}
resFilter, err := m.settingsMgr.GetResourcesFilter()
if err != nil {
return "", nil, nil, nil, err
return "", nil, nil, err
}
return appLabelKey, resourceOverrides, diffNormalizer, resFilter, nil
return appLabelKey, resourceOverrides, resFilter, nil
}
// verifyGnuPGSignature verifies the result of a GnuPG operation for a given git
@@ -310,64 +319,13 @@ func verifyGnuPGSignature(revision string, project *appv1.AppProject, manifestIn
return conditions
}
func (m *appStateManager) diffArrayCached(configArray []*unstructured.Unstructured, liveArray []*unstructured.Unstructured, cachedDiff []*appv1.ResourceDiff, opts ...diff.Option) (*diff.DiffResultList, error) {
numItems := len(configArray)
if len(liveArray) != numItems {
return nil, fmt.Errorf("left and right arrays have mismatched lengths")
}
diffByKey := map[kube.ResourceKey]*appv1.ResourceDiff{}
for i := range cachedDiff {
res := cachedDiff[i]
diffByKey[kube.NewResourceKey(res.Group, res.Kind, res.Namespace, res.Name)] = cachedDiff[i]
}
diffResultList := diff.DiffResultList{
Diffs: make([]diff.DiffResult, numItems),
}
for i := 0; i < numItems; i++ {
config := configArray[i]
live := liveArray[i]
resourceVersion := ""
var key kube.ResourceKey
if live != nil {
key = kube.GetResourceKey(live)
resourceVersion = live.GetResourceVersion()
} else {
key = kube.GetResourceKey(config)
}
var dr *diff.DiffResult
if cachedDiff, ok := diffByKey[key]; ok && cachedDiff.ResourceVersion == resourceVersion {
dr = &diff.DiffResult{
NormalizedLive: []byte(cachedDiff.NormalizedLiveState),
PredictedLive: []byte(cachedDiff.PredictedLiveState),
Modified: cachedDiff.Modified,
}
} else {
res, err := diff.Diff(configArray[i], liveArray[i], opts...)
if err != nil {
return nil, err
}
dr = res
}
if dr != nil {
diffResultList.Diffs[i] = *dr
if dr.Modified {
diffResultList.Modified = true
}
}
}
return &diffResultList, nil
}
// CompareAppState compares application git state to the live app state, using the specified
// revision and supplied source. If revision or overrides are empty, then compares against
// revision and overrides in the app spec.
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *appv1.AppProject, revision string, source v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localManifests []string) *comparisonResult {
ts := stats.NewTimingStats()
appLabelKey, resourceOverrides, diffNormalizer, resFilter, err := m.getComparisonSettings(app)
appLabelKey, resourceOverrides, resFilter, err := m.getComparisonSettings()
ts.AddCheckpoint("settings_ms")
// return unknown comparison result if basic comparison settings cannot be loaded
@@ -488,32 +446,26 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
compareOptions = settings.GetDefaultDiffOptions()
}
logCtx.Debugf("built managed objects list")
var diffResults *diff.DiffResultList
diffOpts := []diff.Option{
diff.WithNormalizer(diffNormalizer),
diff.IgnoreAggregatedRoles(compareOptions.IgnoreAggregatedRoles),
}
cachedDiff := make([]*appv1.ResourceDiff, 0)
// restore comparison using cached diff result if previous comparison was performed for the same revision
revisionChanged := manifestInfo == nil || app.Status.Sync.Revision != manifestInfo.Revision
specChanged := !reflect.DeepEqual(app.Status.Sync.ComparedTo, appv1.ComparedTo{Source: app.Spec.Source, Destination: app.Spec.Destination})
_, refreshRequested := app.IsRefreshRequested()
noCache = noCache || refreshRequested || app.Status.Expired(m.statusRefreshTimeout)
noCache = noCache || refreshRequested || app.Status.Expired(m.statusRefreshTimeout) || specChanged || revisionChanged
for i := range reconciliation.Target {
_ = m.resourceTracking.Normalize(reconciliation.Target[i], reconciliation.Live[i], appLabelKey, string(trackingMethod))
}
diffConfigBuilder := argodiff.NewDiffConfigBuilder().
WithDiffSettings(app.Spec.IgnoreDifferences, resourceOverrides, compareOptions.IgnoreAggregatedRoles).
WithTracking(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...)
if noCache {
diffConfigBuilder.WithNoCache()
} else {
diffResults, err = m.diffArrayCached(reconciliation.Target, reconciliation.Live, cachedDiff, diffOpts...)
diffConfigBuilder.WithCache(m.cache, app.GetName())
}
// it necessary to ignore the error at this point to avoid creating duplicated
// application conditions as argo.StateDiffs will validate this diffConfig again.
diffConfig, _ := diffConfigBuilder.Build()
diffResults, err := argodiff.StateDiffs(reconciliation.Live, reconciliation.Target, diffConfig)
if err != nil {
diffResults = &diff.DiffResultList{}
failedToLoadObjs = true
@@ -634,7 +586,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
resources: resourceSummaries,
managedResources: managedResources,
reconciliationResult: reconciliation,
diffNormalizer: diffNormalizer,
diffConfig: diffConfig,
diffResultList: diffResults,
}
if manifestInfo != nil {

View File

@@ -2,6 +2,7 @@ package controller
import (
"context"
"encoding/json"
"fmt"
"os"
"strconv"
@@ -11,6 +12,7 @@ import (
"github.com/argoproj/gitops-engine/pkg/sync"
"github.com/argoproj/gitops-engine/pkg/sync/common"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
jsonpatch "github.com/evanphx/json-patch"
log "github.com/sirupsen/logrus"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -22,6 +24,7 @@ import (
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
listersv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/argo"
"github.com/argoproj/argo-cd/v2/util/argo/diff"
logutils "github.com/argoproj/argo-cd/v2/util/log"
"github.com/argoproj/argo-cd/v2/util/lua"
"github.com/argoproj/argo-cd/v2/util/rand"
@@ -172,9 +175,24 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
return
}
reconciliationResult := compareResult.reconciliationResult
// if RespectIgnoreDifferences is enabled, it should normalize the target
// resources which in this case applies the live values in the configured
// ignore differences fields.
if syncOp.SyncOptions.HasOption("RespectIgnoreDifferences=true") {
patchedTargets, err := normalizeTargetResources(compareResult)
if err != nil {
state.Phase = common.OperationError
state.Message = fmt.Sprintf("Failed to normalize target resources: %s", err)
return
}
reconciliationResult.Target = patchedTargets
}
syncCtx, cleanup, err := sync.NewSyncContext(
compareResult.syncStatus.Revision,
compareResult.reconciliationResult,
reconciliationResult,
restConfig,
rawConfig,
m.kubectl,
@@ -255,6 +273,147 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
}
}
// normalizeTargetResources will apply the diff normalization in all live and target resources.
// Then it calculates the merge patch between the normalized live and the current live resources.
// Finally it applies the merge patch in the normalized target resources. This is done to ensure
// that target resources have the same ignored diff fields values from live ones to avoid them to
// be applied in the cluster. Returns the list of normalized target resources.
func normalizeTargetResources(cr *comparisonResult) ([]*unstructured.Unstructured, error) {
// normalize live and target resources
normalized, err := diff.Normalize(cr.reconciliationResult.Live, cr.reconciliationResult.Target, cr.diffConfig)
if err != nil {
return nil, err
}
patchedTargets := []*unstructured.Unstructured{}
for idx, live := range cr.reconciliationResult.Live {
normalizedTarget := normalized.Targets[idx]
if normalizedTarget == nil {
patchedTargets = append(patchedTargets, nil)
continue
}
originalTarget := cr.reconciliationResult.Target[idx]
if live == nil {
patchedTargets = append(patchedTargets, originalTarget)
continue
}
// calculate targetPatch between normalized and target resource
targetPatch, err := getMergePatch(normalizedTarget, originalTarget)
if err != nil {
return nil, err
}
// check if there is a patch to apply. An empty patch is identified by a '{}' string.
if len(targetPatch) > 2 {
livePatch, err := getMergePatch(normalized.Lives[idx], live)
if err != nil {
return nil, err
}
// generate a minimal patch that uses the fields from targetPatch (template)
// with livePatch values
patch, err := compilePatch(targetPatch, livePatch)
if err != nil {
return nil, err
}
normalizedTarget, err = applyMergePatch(normalizedTarget, patch)
if err != nil {
return nil, err
}
} else {
// if there is no patch just use the original target
normalizedTarget = originalTarget
}
patchedTargets = append(patchedTargets, normalizedTarget)
}
return patchedTargets, nil
}
// compilePatch will generate a patch using the fields from templatePatch with
// the values from valuePatch.
func compilePatch(templatePatch, valuePatch []byte) ([]byte, error) {
templateMap := make(map[string]interface{})
err := json.Unmarshal(templatePatch, &templateMap)
if err != nil {
return nil, err
}
valueMap := make(map[string]interface{})
err = json.Unmarshal(valuePatch, &valueMap)
if err != nil {
return nil, err
}
resultMap := intersectMap(templateMap, valueMap)
return json.Marshal(resultMap)
}
// intersectMap will return map with the fields intersection from the 2 provided
// maps populated with the valueMap values.
func intersectMap(templateMap, valueMap map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{})
for k, v := range templateMap {
if innerTMap, ok := v.(map[string]interface{}); ok {
if innerVMap, ok := valueMap[k].(map[string]interface{}); ok {
result[k] = intersectMap(innerTMap, innerVMap)
}
} else if innerTSlice, ok := v.([]interface{}); ok {
if innerVSlice, ok := valueMap[k].([]interface{}); ok {
items := []interface{}{}
for idx, innerTSliceValue := range innerTSlice {
if idx < len(innerVSlice) {
if tSliceValueMap, ok := innerTSliceValue.(map[string]interface{}); ok {
if vSliceValueMap, ok := innerVSlice[idx].(map[string]interface{}); ok {
item := intersectMap(tSliceValueMap, vSliceValueMap)
items = append(items, item)
}
} else {
items = append(items, innerVSlice[idx])
}
}
}
if len(items) > 0 {
result[k] = items
}
}
} else {
if _, ok := valueMap[k]; ok {
result[k] = valueMap[k]
}
}
}
return result
}
// getMergePatch calculates and returns the patch between the original and the
// modified unstructures.
func getMergePatch(original, modified *unstructured.Unstructured) ([]byte, error) {
originalJSON, err := original.MarshalJSON()
if err != nil {
return nil, err
}
modifiedJSON, err := modified.MarshalJSON()
if err != nil {
return nil, err
}
return jsonpatch.CreateMergePatch(originalJSON, modifiedJSON)
}
// applyMergePatch will apply the given patch in the obj and return the patched
// unstructure.
func applyMergePatch(obj *unstructured.Unstructured, patch []byte) (*unstructured.Unstructured, error) {
originalJSON, err := obj.MarshalJSON()
if err != nil {
return nil, err
}
patchedJSON, err := jsonpatch.MergePatch(originalJSON, patch)
if err != nil {
return nil, err
}
patchedObj := &unstructured.Unstructured{}
_, _, err = unstructured.UnstructuredJSONScheme.Decode(patchedJSON, nil, patchedObj)
if err != nil {
return nil, err
}
return patchedObj, nil
}
// 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.

View File

@@ -5,16 +5,20 @@ import (
"os"
"testing"
"github.com/argoproj/gitops-engine/pkg/sync"
"github.com/argoproj/gitops-engine/pkg/sync/common"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"github.com/argoproj/argo-cd/v2/controller/testdata"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/test"
"github.com/argoproj/argo-cd/v2/util/argo/diff"
)
func TestPersistRevisionHistory(t *testing.T) {
@@ -211,3 +215,136 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
assert.Contains(t, opState.Message, syncErrorMsg)
})
}
func TestNormalizeTargetResources(t *testing.T) {
type fixture struct {
comparisonResult *comparisonResult
}
setup := func(t *testing.T, ignores []v1alpha1.ResourceIgnoreDifferences) *fixture {
t.Helper()
dc, err := diff.NewDiffConfigBuilder().
WithDiffSettings(ignores, nil, true).
WithNoCache().
Build()
require.NoError(t, err)
live := test.YamlToUnstructured(testdata.LiveDeploymentYaml)
target := test.YamlToUnstructured(testdata.TargetDeploymentYaml)
return &fixture{
&comparisonResult{
reconciliationResult: sync.ReconciliationResult{
Live: []*unstructured.Unstructured{live},
Target: []*unstructured.Unstructured{target},
},
diffConfig: dc,
},
}
}
t.Run("will modify target resource adding live state in fields it should ignore", func(t *testing.T) {
// given
ignore := v1alpha1.ResourceIgnoreDifferences{
Group: "*",
Kind: "*",
ManagedFieldsManagers: []string{"janitor"},
}
ignores := []v1alpha1.ResourceIgnoreDifferences{ignore}
f := setup(t, ignores)
// when
targets, err := normalizeTargetResources(f.comparisonResult)
// then
require.NoError(t, err)
require.Equal(t, 1, len(targets))
iksmVersion := targets[0].GetAnnotations()["iksm-version"]
assert.Equal(t, "2.0", iksmVersion)
})
t.Run("will not modify target resource if ignore difference is not configured", func(t *testing.T) {
// given
f := setup(t, []v1alpha1.ResourceIgnoreDifferences{})
// when
targets, err := normalizeTargetResources(f.comparisonResult)
// then
require.NoError(t, err)
require.Equal(t, 1, len(targets))
iksmVersion := targets[0].GetAnnotations()["iksm-version"]
assert.Equal(t, "1.0", iksmVersion)
})
t.Run("will remove fields from target if not present in live", func(t *testing.T) {
ignore := v1alpha1.ResourceIgnoreDifferences{
Group: "apps",
Kind: "Deployment",
JSONPointers: []string{"/metadata/annotations/iksm-version"},
}
ignores := []v1alpha1.ResourceIgnoreDifferences{ignore}
f := setup(t, ignores)
live := f.comparisonResult.reconciliationResult.Live[0]
unstructured.RemoveNestedField(live.Object, "metadata", "annotations", "iksm-version")
// when
targets, err := normalizeTargetResources(f.comparisonResult)
// then
require.NoError(t, err)
require.Equal(t, 1, len(targets))
_, ok := targets[0].GetAnnotations()["iksm-version"]
assert.False(t, ok)
})
t.Run("will correctly normalize with multiple ignore configurations", func(t *testing.T) {
// given
ignores := []v1alpha1.ResourceIgnoreDifferences{
{
Group: "apps",
Kind: "Deployment",
JSONPointers: []string{"/spec/replicas"},
},
{
Group: "*",
Kind: "*",
ManagedFieldsManagers: []string{"janitor"},
},
}
f := setup(t, ignores)
// when
targets, err := normalizeTargetResources(f.comparisonResult)
// then
require.NoError(t, err)
require.Equal(t, 1, len(targets))
normalized := targets[0]
iksmVersion, ok := normalized.GetAnnotations()["iksm-version"]
require.True(t, ok)
assert.Equal(t, "2.0", iksmVersion)
replicas, ok, err := unstructured.NestedInt64(normalized.Object, "spec", "replicas")
require.NoError(t, err)
require.True(t, ok)
assert.Equal(t, int64(4), replicas)
})
t.Run("will keep new array entries not found in live state if not ignored", func(t *testing.T) {
t.Skip("limitation in the current implementation")
// given
ignores := []v1alpha1.ResourceIgnoreDifferences{
{
Group: "apps",
Kind: "Deployment",
JQPathExpressions: []string{".spec.template.spec.containers[] | select(.name == \"guestbook-ui\")"},
},
}
f := setup(t, ignores)
target := test.YamlToUnstructured(testdata.TargetDeploymentNewEntries)
f.comparisonResult.reconciliationResult.Target = []*unstructured.Unstructured{target}
// when
targets, err := normalizeTargetResources(f.comparisonResult)
// then
require.NoError(t, err)
require.Equal(t, 1, len(targets))
containers, ok, err := unstructured.NestedSlice(targets[0].Object, "spec", "template", "spec", "containers")
require.NoError(t, err)
require.True(t, ok)
assert.Equal(t, 2, len(containers))
})
}

14
controller/testdata/data.go vendored Normal file
View File

@@ -0,0 +1,14 @@
package testdata
import _ "embed"
var (
//go:embed live-deployment.yaml
LiveDeploymentYaml string
//go:embed target-deployment.yaml
TargetDeploymentYaml string
//go:embed target-deployment-new-entries.yaml
TargetDeploymentNewEntries string
)

177
controller/testdata/live-deployment.yaml vendored Normal file
View File

@@ -0,0 +1,177 @@
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
argocd.argoproj.io/tracking-id: 'guestbook:apps/Deployment:default/kustomize-guestbook-ui'
deployment.kubernetes.io/revision: '9'
iksm-version: '2.0'
kubectl.kubernetes.io/last-applied-configuration: >
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{"argocd.argoproj.io/tracking-id":"guestbook:apps/Deployment:default/kustomize-guestbook-ui","iksm-version":"2.0"},"name":"kustomize-guestbook-ui","namespace":"default"},"spec":{"replicas":4,"revisionHistoryLimit":3,"selector":{"matchLabels":{"app":"guestbook-ui"}},"template":{"metadata":{"labels":{"app":"guestbook-ui"}},"spec":{"containers":[{"env":[{"name":"SOME_ENV_VAR","value":"some_value"}],"image":"gcr.io/heptio-images/ks-guestbook-demo:0.1","name":"guestbook-ui","ports":[{"containerPort":80}],"resources":{"requests":{"cpu":"50m","memory":"100Mi"}}}]}}}}
creationTimestamp: '2022-01-05T15:45:21Z'
generation: 119
managedFields:
- apiVersion: apps/v1
fieldsType: FieldsV1
fieldsV1:
'f:metadata':
'f:annotations':
'f:iksm-version': {}
manager: janitor
operation: Apply
time: '2022-01-06T18:21:04Z'
- apiVersion: apps/v1
fieldsType: FieldsV1
fieldsV1:
'f:metadata':
'f:annotations':
.: {}
'f:argocd.argoproj.io/tracking-id': {}
'f:kubectl.kubernetes.io/last-applied-configuration': {}
'f:spec':
'f:progressDeadlineSeconds': {}
'f:replicas': {}
'f:revisionHistoryLimit': {}
'f:selector': {}
'f:strategy':
'f:rollingUpdate':
.: {}
'f:maxSurge': {}
'f:maxUnavailable': {}
'f:type': {}
'f:template':
'f:metadata':
'f:labels':
.: {}
'f:app': {}
'f:spec':
'f:containers':
'k:{"name":"guestbook-ui"}':
.: {}
'f:env':
.: {}
'k:{"name":"SOME_ENV_VAR"}':
.: {}
'f:name': {}
'f:value': {}
'f:image': {}
'f:imagePullPolicy': {}
'f:name': {}
'f:ports':
.: {}
'k:{"containerPort":80,"protocol":"TCP"}':
.: {}
'f:containerPort': {}
'f:protocol': {}
'f:resources':
.: {}
'f:requests':
.: {}
'f:cpu': {}
'f:memory': {}
'f:terminationMessagePath': {}
'f:terminationMessagePolicy': {}
'f:dnsPolicy': {}
'f:restartPolicy': {}
'f:schedulerName': {}
'f:securityContext': {}
'f:terminationGracePeriodSeconds': {}
manager: argocd
operation: Update
time: '2022-01-06T15:04:15Z'
- apiVersion: apps/v1
fieldsType: FieldsV1
fieldsV1:
'f:metadata':
'f:annotations':
'f:deployment.kubernetes.io/revision': {}
'f:status':
'f:availableReplicas': {}
'f:conditions':
.: {}
'k:{"type":"Available"}':
.: {}
'f:lastTransitionTime': {}
'f:lastUpdateTime': {}
'f:message': {}
'f:reason': {}
'f:status': {}
'f:type': {}
'k:{"type":"Progressing"}':
.: {}
'f:lastTransitionTime': {}
'f:lastUpdateTime': {}
'f:message': {}
'f:reason': {}
'f:status': {}
'f:type': {}
'f:observedGeneration': {}
'f:readyReplicas': {}
'f:replicas': {}
'f:updatedReplicas': {}
manager: kube-controller-manager
operation: Update
time: '2022-01-06T18:15:14Z'
name: kustomize-guestbook-ui
namespace: default
resourceVersion: '8289211'
uid: ef253575-ce44-4c5e-84ad-16e81d0df6eb
spec:
progressDeadlineSeconds: 600
replicas: 4
revisionHistoryLimit: 3
selector:
matchLabels:
app: guestbook-ui
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: guestbook-ui
spec:
containers:
- env:
- name: SOME_ENV_VAR
value: some_value
image: 'gcr.io/heptio-images/ks-guestbook-demo:0.1'
imagePullPolicy: IfNotPresent
name: guestbook-ui
ports:
- containerPort: 80
protocol: TCP
resources:
requests:
cpu: 50m
memory: 100Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
status:
availableReplicas: 4
conditions:
- lastTransitionTime: '2022-01-05T22:20:37Z'
lastUpdateTime: '2022-01-05T22:43:47Z'
message: >-
ReplicaSet "kustomize-guestbook-ui-6549d54677" has successfully
progressed.
reason: NewReplicaSetAvailable
status: 'True'
type: Progressing
- lastTransitionTime: '2022-01-06T18:15:14Z'
lastUpdateTime: '2022-01-06T18:15:14Z'
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: 'True'
type: Available
observedGeneration: 119
readyReplicas: 4
replicas: 4
updatedReplicas: 4

View File

@@ -0,0 +1,36 @@
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
argocd.argoproj.io/tracking-id: 'guestbook:apps/Deployment:default/kustomize-guestbook-ui'
iksm-version: '1.0'
name: kustomize-guestbook-ui
namespace: default
spec:
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app: guestbook-ui
template:
metadata:
labels:
app: guestbook-ui
spec:
containers:
- name: guestbook-ui
image: 'gcr.io/heptio-images/ks-guestbook-demo:0.1'
env:
- name: SOME_ENV_VAR
value: some_value
- name: NEW_ENV_VAR
value: new_value
ports:
- containerPort: 80
- grpcPort: 8081
resources:
requests:
cpu: 50m
memory: 100Mi
- name: new-container
image: 'new-image:1.0'

View File

@@ -0,0 +1,31 @@
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
argocd.argoproj.io/tracking-id: 'guestbook:apps/Deployment:default/kustomize-guestbook-ui'
iksm-version: '1.0'
name: kustomize-guestbook-ui
namespace: default
spec:
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app: guestbook-ui
template:
metadata:
labels:
app: guestbook-ui
spec:
containers:
- env:
- name: SOME_ENV_VAR
value: some_value
image: 'gcr.io/heptio-images/ks-guestbook-demo:0.1'
name: guestbook-ui
ports:
- containerPort: 80
resources:
requests:
cpu: 50m
memory: 100Mi

View File

@@ -4,6 +4,12 @@ You can download the latest Argo CD version from [the latest release page of thi
## Linux and WSL
### ArchLinux User Repository ([AUR](https://aur.archlinux.org/packages/))
```bash
yay -Sy argocd-bin
```
### Homebrew
```bash

View File

@@ -29,7 +29,7 @@ The Docker version must be fairly recent, and support multi-stage builds. You sh
* Obviously, you will need a `git` client for pulling source code and pushing back your changes.
* Last but not least, you will need a Go SDK and related tools (such as GNU `make`) installed and working on your development environment. The minimum required Go version for building and testing Argo CD is **v1.16**.
* Last but not least, you will need a Go SDK and related tools (such as GNU `make`) installed and working on your development environment. The minimum required Go version for building and testing Argo CD is **v1.17**.
* We will assume that your Go workspace is at `~/go`.

View File

@@ -86,6 +86,18 @@ data:
name: stable
```
## After deploying my Helm application with Argo CD I cannot see it with `helm ls` and other Helm commands
When deploying a Helm application Argo CD is using Helm
only as a template mechanism. It runs `helm template` and
then deploys the resulting manifests on the cluster instead of doing `helm install`. This means that you cannot use any Helm command
to view/verify the application. It is fully managed by Argo CD.
Note that Argo CD supports natively some capabilities that you might miss in Helm (such as the history and rollback commands).
This decision was made so that Argo CD is neutral
to all manifest generators.
## I've configured [cluster secret](./operator-manual/declarative-setup.md#clusters) but it does not show up in CLI/UI, how do I fix it?
Check if cluster secret has `argocd.argoproj.io/secret-type: cluster` label. If secret has the label but the cluster is

View File

@@ -18,7 +18,7 @@ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/st
This will create a new namespace, `argocd`, where Argo CD services and application resources will live.
!!! warning
The installation manifests include `ClusterRoleBinding` resources that reference `argocd` namespace. If you installing Argo CD into a different
The installation manifests include `ClusterRoleBinding` resources that reference `argocd` namespace. If you are installing Argo CD into a different
namespace then make sure to update the namespace reference.
If you are not interested in UI, SSO, multi-cluster features then you can install [core](operator-manual/installation.md#core) Argo CD components only:
@@ -133,7 +133,7 @@ An example repository containing a guestbook application is available at
Create the example guestbook application with the following command:
```bash
argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace default`
argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace default
```
### Creating Apps Via UI

View File

@@ -4,7 +4,7 @@ metadata:
name: guestbook
# You'll usually want to add your resources to the argocd namespace.
namespace: argocd
# Add a this finalizer ONLY if you want these to cascade delete.
# Add this finalizer ONLY if you want these to cascade delete.
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
@@ -13,11 +13,12 @@ spec:
# Source of the application manifests
source:
repoURL: https://github.com/argoproj/argocd-example-apps.git
targetRevision: HEAD
path: guestbook
repoURL: https://github.com/argoproj/argocd-example-apps.git # Can point to either a Helm chart repo or a git repo.
targetRevision: HEAD # For Helm, this refers to the chart version.
path: guestbook # This has no meaning for Helm charts pulled directly from a Helm repo instead of git.
# helm specific config
chart: chart-name # Set this when pulling directly from a Helm repo. DO NOT set for git-hosted Helm charts.
helm:
# Extra parameters to set (same as setting through values.yaml, but these take precedence)
parameters:
@@ -27,6 +28,11 @@ spec:
value: "true"
forceString: true # ensures that value is treated as a string
# Use the contents of files as parameters (uses Helm's --set-file)
fileParameters:
- name: config
path: files/config.json
# Release name override (defaults to application name)
releaseName: guestbook
@@ -85,6 +91,9 @@ spec:
# plugin specific config
plugin:
# Only set the plugin name if the plugin is defined in argocd-cm.
# If the plugin is defined as a sidecar, omit the name. The plugin will be automatically matched with the
# Application according to the plugin's discovery rules.
name: mypluginname
# environment variables passed to the plugin
env:
@@ -115,9 +124,16 @@ spec:
factor: 2 # a factor to multiply the base duration after each failed retry
maxDuration: 3m # the maximum amount of time allowed for the backoff strategy
# Ignore differences at the specified json pointers
# Will ignore differences between live and desired states during the diff. Note that these configurations are not
# used during the sync process.
ignoreDifferences:
# for the specified json pointers
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas
# for the specified managedFields managers
- group: "*"
kind: "*"
managedFieldsManagers:
- kube-controller-manager

View File

@@ -31,4 +31,3 @@ The application controller is a Kubernetes controller which continuously monitor
applications and compares the current, live state against the desired target state (as specified in
the repo). It detects `OutOfSync` application state and optionally takes corrective action. It
is responsible for invoking any user-defined hooks for lifecycle events (PreSync, Sync, PostSync)

View File

@@ -30,6 +30,12 @@ data:
help.chatUrl: "https://mycorp.slack.com/argo-cd"
# the text for getting chat help, defaults to "Chat now!"
help.chatText: "Chat now!"
# The URLs to download additional ArgoCD binaries (besides the Linux amd64 binary included by default)
# for different OS architectures. If provided, additional download buttons will be displayed on the help page.
help.download.linux-arm64: "path-or-url-to-download"
help.download.darwin-amd64: "path-or-url-to-download"
help.download.darwin-arm64: "path-or-url-to-download"
help.download.windows-amd64: "path-or-url-to-download"
# A dex connector configuration (optional). See SSO configuration documentation:
# https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/sso
@@ -75,6 +81,16 @@ data:
- /webhooks/0/clientConfig/caBundle
jqPathExpressions:
- .webhooks[0].clientConfig.caBundle
managedFieldsManagers:
- kube-controller-manager
# Configuration to define customizations ignoring differences between live and desired states for
# all resources (GK).
resource.customizations.ignoreDifferences.all: |
managedFieldsManagers:
- kube-controller-manager
jsonPointers:
- /spec/replicas
resource.customizations.health.certmanager.k8s.io-Certificate: |
hs = {}
@@ -183,6 +199,13 @@ data:
generate:
command: [kasane, show]
# A set of settings that allow enabling or disabling the config management tool.
# If unset, each defaults to "true".
kustomize.enabled: true
jsonnet.enabled: true
helm.enabled: true
ksonnet.enabled: true
# Build options/parameters to use with `kustomize build` (optional)
kustomize.buildOptions: --load_restrictor none
@@ -194,6 +217,10 @@ data:
kustomize.version.v3.5.1: /custom-tools/kustomize_3_5_1
kustomize.version.v3.5.4: /custom-tools/kustomize_3_5_4
# Comma delimited list of additional custom remote values file schemes (http are https are allowed by default).
# Change to empty value if you want to disable remote values files altogether.
helm.valuesFileSchemes: http, https
# The metadata.label key name where Argo CD injects the app name as a tracking label (optional).
# Tracking labels are used to determine which resources need to be deleted when pruning.
# If omitted, Argo CD injects the app name into the label: 'app.kubernetes.io/instance'

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

@@ -93,3 +93,21 @@ argocd app sync -l app.kubernetes.io/instance=apps
```
View [the example on GitHub](https://github.com/argoproj/argocd-example-apps/tree/master/apps).
### Cascading deletion
If you want to ensure that child-apps and all of their resources are deleted when the parent-app is deleted make sure to add the appropriate [finalizer](https://argo-cd-docs.readthedocs.io/en/latest/user-guide/app_deletion/#about-the-deletion-finalizer) to your `Application` definition
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: guestbook
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
...
```

View File

@@ -5,9 +5,9 @@ as part of its container images. Sometimes, it may be desired to use a specific
other than what Argo CD bundles. Some reasons to do this might be:
* To upgrade/downgrade to a specific version of a tool due to bugs or bug fixes.
* To install additional dependencies which to be used by kustomize's configmap/secret generators
* To install additional dependencies to be used by kustomize's configmap/secret generators.
(e.g. curl, vault, gpg, AWS CLI)
* To install a [config management plugin](../user-guide/application_sources.md#config-management-plugins)
* To install a [config management plugin](../user-guide/config-management-plugins.md).
As the Argo CD repo-server is the single service responsible for generating Kubernetes manifests, it
can be customized to use alternative toolchain required by your environment.
@@ -46,7 +46,7 @@ the helm binary with a different version than what is bundled in Argo CD:
## BYOI (Build Your Own Image)
Sometimes replacing a binary isn't sufficient and you need to install other dependencies. The
Sometimes replacing a binary isn't sufficient, and you need to install other dependencies. The
following example builds an entirely customized repo-server from a Dockerfile, installing extra
dependencies that may be needed for generating manifests.

View File

@@ -213,6 +213,7 @@ stringData:
Example for GitHub App:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: github-repo
@@ -224,7 +225,7 @@ stringData:
repo: https://github.com/argoproj/my-private-repository
githubAppID: 1
githubAppInstallationID: 2
githubAppPrivateKeySecret: |
githubAppPrivateKey: |
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
@@ -406,6 +407,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

View File

@@ -32,7 +32,7 @@ and might fail. To avoid failed syncs use `ARGOCD_GIT_ATTEMPTS_COUNT` environmen
* `argocd-repo-server` Every 3m (by default) Argo CD checks for changes to the app manifests. Argo CD assumes by default that manifests only change when the repo changes, so it caches generated manifests (for 24h by default). With Kustomize remote bases, or Helm patch releases, the manifests can change even though the repo has not changed. By reducing the cache time, you can get the changes without waiting for 24h. Use `--repo-cache-expiration duration`, and we'd suggest in low volume environments you try '1h'. Bear in mind this will negate the benefit of caching if set too low.
* `argocd-repo-server` fork exec config management tools such as `helm` or `kustomize` and enforces 90 seconds timeout. The timeout can be increased using `ARGOCD_EXEC_TIMEOUT` env variable.
* `argocd-repo-server` fork exec config management tools such as `helm` or `kustomize` and enforces 90 seconds timeout. The timeout can be increased using `ARGOCD_EXEC_TIMEOUT` env variable. The value should be in Go time duration string format, for example, `2m30s`.
**metrics:**

View File

@@ -32,15 +32,19 @@ metadata:
name: argocd-server-cli
namespace: argocd
spec:
# NOTE: the port must be ignored if you have strip_matching_host_port enabled on envoy
host: argocd.example.com:443
prefix: /
service: argocd-server:443
service: argocd-server:80
regex_headers:
Content-Type: "^application/grpc.*$"
grpc: true
```
Login with the `argocd` CLI using the extra `--grpc-web-root-path` flag for gRPC-web.
Login with the `argocd` CLI:
```shell
argocd login <host>:<port> --grpc-web-root-path /
argocd login <host>
```
### Option 2: Mapping CRD for Path-based Routing
@@ -446,7 +450,7 @@ To:
### 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.
Now you need an externally accesible service. This is practically the same as the internal service Argo CD has, but 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:
@@ -454,13 +458,13 @@ The service:
apiVersion: v1
kind: Service
metadata:
name: argocd-server-external
name: argocd-server
namespace: argocd
annotations:
cloud.google.com/neg: '{"ingress": true}'
cloud.google.com/backend-config: '{"ports": {"http":"argocd-backend-config"}}'
spec:
type: NodePort
type: ClusterIP
ports:
- name: http
port: 80
@@ -528,7 +532,7 @@ kubectl -n argocd create secret tls secret-yourdomain-com \
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
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd
@@ -540,19 +544,16 @@ spec:
- secretName: secret-yourdomain-com
rules:
- host: argocd.yourdomain.com
http:
paths:
- path: /*
backend:
serviceName: argocd-server-external
servicePort: http
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: argocd-server
port:
number: 80
```
---
!!! 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.

View File

@@ -1,14 +0,0 @@
# Notifications
The notifications support is not bundled into the Argo CD itself. Instead of reinventing the wheel and implementing opinionated notifications system Argo CD leverages integrations
with the third-party notification system. Following integrations are recommended:
* To monitor Argo CD performance or health state of managed applications use [Prometheus Metrics](./metrics.md) in combination with [Grafana](https://grafana.com/),
[Alertmanager](https://prometheus.io/docs/alerting/alertmanager/).
* To notify the end-users of Argo CD about events like application upgrades, user errors in application definition, etc use one of the following projects:
* [ArgoCD Notifications](https://github.com/argoproj-labs/argocd-notifications) - Argo CD specific notification system that continuously monitors Argo CD applications
and aims to integrate with various notification services such as Slack, SMTP, Telegram, Discord, etc.
* [Argo Kube Notifier](https://github.com/argoproj-labs/argo-kube-notifier) - generic Kubernetes resource controller that allows monitoring any Kubernetes resource and sends a
notification when the configured rule is met.
* [Kube Watch](https://github.com/bitnami-labs/kubewatch) - a Kubernetes watcher that could publishes notification to Slack/hipchat/mattermost/flock channels. It watches the
cluster for resource changes and notifies them through webhooks.

View File

@@ -0,0 +1,95 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
# Triggers define the condition when the notification should be sent and list of templates required to generate the message
# Recipients can subscribe to the trigger and specify the required message template and destination notification service.
trigger.on-sync-status-unknown: |
- when: app.status.sync.status == 'Unknown'
send: [my-custom-template]
# Optional 'oncePer' property ensure that notification is sent only once per specified field value
# E.g. following is triggered once per sync revision
trigger.on-deployed: |
- when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status == 'Healthy'
oncePer: app.status.sync.revision
send: [app-sync-succeeded]
# Templates are used to generate the notification template message
template.my-custom-template: |
message: |
Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
# Templates might have notification service specific fields. E.g. slack message might include annotations
template.my-custom-template-slack-template: |
message: |
Application {{.app.metadata.name}} sync is {{.app.status.sync.status}}.
Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
email:
subject: Application {{.app.metadata.name}} sync status is {{.app.status.sync.status}}
slack:
attachments: |
[{
"title": "{{.app.metadata.name}}",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#18be52"
}]
# Holds list of triggers that are used by default if trigger is not specified explicitly in the subscription
defaultTriggers: |
- on-sync-status-unknown
# Notification services are used to deliver message.
# Service definition might reference values from argocd-notifications-secret Secret using $my-key format
# Service format key is: service.<type>.<optional-custom-name>
# Slack
service.slack: |
token: $slack-token
username: <override-username> # optional username
icon: <override-icon> # optional icon for the message (supports both emoij and url notation)
# Slack based notifier with name mattermost
service.slack.mattermost: |
apiURL: https://my-mattermost-url.com/api
token: $slack-token
username: <override-username> # optional username
icon: <override-icon> # optional icon for the message (supports both emoij and url notation)
# Email
service.email: |
host: smtp.gmail.com
port: 587
from: <myemail>@gmail.com
username: $email-username
password: $email-password
# Opsgenie
service.opsgenie: |
apiUrl: api.opsgenie.com
apiKeys:
$opsgenie-team-id: $opsgenie-team-api-key
...
# Telegram
service.telegram: |
token: $telegram-token
# Context holds list of variables that can be referenced in templates
context: |
argocdUrl: https://cd.apps.argoproj.io/
# Contains centrally managed global application subscriptions
subscriptions: |
# subscription for on-sync-status-unknown trigger notifications
- recipients:
- slack:test2
- email:test@gmail.com
triggers:
- on-sync-status-unknown
# subscription restricted to applications with matching labels only
- recipients:
- slack:test3
selector: test=true
triggers:
- on-sync-status-unknown

View File

@@ -0,0 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: argocd-notifications-secret
stringData:
slack-token: <my-slack-token>
email-username: <myemail>@gmail.com
email-password: <mypassword>
type: Opaque

View File

@@ -0,0 +1,531 @@
# Triggers and Templates Catalog
## Triggers
| NAME | DESCRIPTION | TEMPLATE |
|------------------------|---------------------------------------------------------------|-----------------------------------------------------|
| on-created | Application is created. | [app-created](#app-created) |
| on-deleted | Application is deleted. | [app-deleted](#app-deleted) |
| on-deployed | Application is synced and healthy. Triggered once per commit. | [app-deployed](#app-deployed) |
| on-health-degraded | Application has degraded | [app-health-degraded](#app-health-degraded) |
| on-sync-failed | Application syncing has failed | [app-sync-failed](#app-sync-failed) |
| on-sync-running | Application is being synced | [app-sync-running](#app-sync-running) |
| on-sync-status-unknown | Application status is 'Unknown' | [app-sync-status-unknown](#app-sync-status-unknown) |
| on-sync-succeeded | Application syncing has succeeded | [app-sync-succeeded](#app-sync-succeeded) |
## Templates
### app-created
**definition**:
```yaml
email:
subject: Application {{.app.metadata.name}} has been created.
message: Application {{.app.metadata.name}} has been created.
teams:
title: Application {{.app.metadata.name}} has been created.
```
### app-deleted
**definition**:
```yaml
email:
subject: Application {{.app.metadata.name}} has been deleted.
message: Application {{.app.metadata.name}} has been deleted.
teams:
title: Application {{.app.metadata.name}} has been deleted.
```
### app-deployed
**definition**:
```yaml
email:
subject: New version of an application {{.app.metadata.name}} is up and running.
message: |
{{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} is now running new version of deployments manifests.
slack:
attachments: |
[{
"title": "{{ .app.metadata.name}}",
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#18be52",
"fields": [
{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
},
{
"title": "Repository",
"value": "{{.app.spec.source.repoURL}}",
"short": true
},
{
"title": "Revision",
"value": "{{.app.status.sync.revision}}",
"short": true
}
{{range $index, $c := .app.status.conditions}}
{{if not $index}},{{end}}
{{if $index}},{{end}}
{
"title": "{{$c.type}}",
"value": "{{$c.message}}",
"short": true
}
{{end}}
]
}]
deliveryPolicy: Post
groupingKey: ""
notifyBroadcast: false
teams:
facts: |
[{
"name": "Sync Status",
"value": "{{.app.status.sync.status}}"
},
{
"name": "Repository",
"value": "{{.app.spec.source.repoURL}}"
},
{
"name": "Revision",
"value": "{{.app.status.sync.revision}}"
}
{{range $index, $c := .app.status.conditions}}
{{if not $index}},{{end}}
{{if $index}},{{end}}
{
"name": "{{$c.type}}",
"value": "{{$c.message}}"
}
{{end}}
]
potentialAction: |-
[{
"@type":"OpenUri",
"name":"Operation Application",
"targets":[{
"os":"default",
"uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}"
}]
},
{
"@type":"OpenUri",
"name":"Open Repository",
"targets":[{
"os":"default",
"uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
}]
}]
themeColor: '#000080'
title: New version of an application {{.app.metadata.name}} is up and running.
```
### app-health-degraded
**definition**:
```yaml
email:
subject: Application {{.app.metadata.name}} has degraded.
message: |
{{if eq .serviceType "slack"}}:exclamation:{{end}} Application {{.app.metadata.name}} has degraded.
Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
slack:
attachments: |
[{
"title": "{{ .app.metadata.name}}",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#f4c030",
"fields": [
{
"title": "Health Status",
"value": "{{.app.status.health.status}}",
"short": true
},
{
"title": "Repository",
"value": "{{.app.spec.source.repoURL}}",
"short": true
}
{{range $index, $c := .app.status.conditions}}
{{if not $index}},{{end}}
{{if $index}},{{end}}
{
"title": "{{$c.type}}",
"value": "{{$c.message}}",
"short": true
}
{{end}}
]
}]
deliveryPolicy: Post
groupingKey: ""
notifyBroadcast: false
teams:
facts: |
[{
"name": "Health Status",
"value": "{{.app.status.health.status}}"
},
{
"name": "Repository",
"value": "{{.app.spec.source.repoURL}}"
}
{{range $index, $c := .app.status.conditions}}
{{if not $index}},{{end}}
{{if $index}},{{end}}
{
"name": "{{$c.type}}",
"value": "{{$c.message}}"
}
{{end}}
]
potentialAction: |
[{
"@type":"OpenUri",
"name":"Open Application",
"targets":[{
"os":"default",
"uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}"
}]
},
{
"@type":"OpenUri",
"name":"Open Repository",
"targets":[{
"os":"default",
"uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
}]
}]
themeColor: '#FF0000'
title: Application {{.app.metadata.name}} has degraded.
```
### app-sync-failed
**definition**:
```yaml
email:
subject: Failed to sync application {{.app.metadata.name}}.
message: |
{{if eq .serviceType "slack"}}:exclamation:{{end}} The sync operation of application {{.app.metadata.name}} has failed at {{.app.status.operationState.finishedAt}} with the following error: {{.app.status.operationState.message}}
Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true .
slack:
attachments: |
[{
"title": "{{ .app.metadata.name}}",
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#E96D76",
"fields": [
{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
},
{
"title": "Repository",
"value": "{{.app.spec.source.repoURL}}",
"short": true
}
{{range $index, $c := .app.status.conditions}}
{{if not $index}},{{end}}
{{if $index}},{{end}}
{
"title": "{{$c.type}}",
"value": "{{$c.message}}",
"short": true
}
{{end}}
]
}]
deliveryPolicy: Post
groupingKey: ""
notifyBroadcast: false
teams:
facts: |
[{
"name": "Sync Status",
"value": "{{.app.status.sync.status}}"
},
{
"name": "Failed at",
"value": "{{.app.status.operationState.finishedAt}}"
},
{
"name": "Repository",
"value": "{{.app.spec.source.repoURL}}"
}
{{range $index, $c := .app.status.conditions}}
{{if not $index}},{{end}}
{{if $index}},{{end}}
{
"name": "{{$c.type}}",
"value": "{{$c.message}}"
}
{{end}}
]
potentialAction: |-
[{
"@type":"OpenUri",
"name":"Open Operation",
"targets":[{
"os":"default",
"uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
}]
},
{
"@type":"OpenUri",
"name":"Open Repository",
"targets":[{
"os":"default",
"uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
}]
}]
themeColor: '#FF0000'
title: Failed to sync application {{.app.metadata.name}}.
```
### app-sync-running
**definition**:
```yaml
email:
subject: Start syncing application {{.app.metadata.name}}.
message: |
The sync operation of application {{.app.metadata.name}} has started at {{.app.status.operationState.startedAt}}.
Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true .
slack:
attachments: |
[{
"title": "{{ .app.metadata.name}}",
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#0DADEA",
"fields": [
{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
},
{
"title": "Repository",
"value": "{{.app.spec.source.repoURL}}",
"short": true
}
{{range $index, $c := .app.status.conditions}}
{{if not $index}},{{end}}
{{if $index}},{{end}}
{
"title": "{{$c.type}}",
"value": "{{$c.message}}",
"short": true
}
{{end}}
]
}]
deliveryPolicy: Post
groupingKey: ""
notifyBroadcast: false
teams:
facts: |
[{
"name": "Sync Status",
"value": "{{.app.status.sync.status}}"
},
{
"name": "Started at",
"value": "{{.app.status.operationState.startedAt}}"
},
{
"name": "Repository",
"value": "{{.app.spec.source.repoURL}}"
}
{{range $index, $c := .app.status.conditions}}
{{if not $index}},{{end}}
{{if $index}},{{end}}
{
"name": "{{$c.type}}",
"value": "{{$c.message}}"
}
{{end}}
]
potentialAction: |-
[{
"@type":"OpenUri",
"name":"Open Operation",
"targets":[{
"os":"default",
"uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
}]
},
{
"@type":"OpenUri",
"name":"Open Repository",
"targets":[{
"os":"default",
"uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
}]
}]
title: Start syncing application {{.app.metadata.name}}.
```
### app-sync-status-unknown
**definition**:
```yaml
email:
subject: Application {{.app.metadata.name}} sync status is 'Unknown'
message: |
{{if eq .serviceType "slack"}}:exclamation:{{end}} Application {{.app.metadata.name}} sync is 'Unknown'.
Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
{{if ne .serviceType "slack"}}
{{range $c := .app.status.conditions}}
* {{$c.message}}
{{end}}
{{end}}
slack:
attachments: |
[{
"title": "{{ .app.metadata.name}}",
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#E96D76",
"fields": [
{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
},
{
"title": "Repository",
"value": "{{.app.spec.source.repoURL}}",
"short": true
}
{{range $index, $c := .app.status.conditions}}
{{if not $index}},{{end}}
{{if $index}},{{end}}
{
"title": "{{$c.type}}",
"value": "{{$c.message}}",
"short": true
}
{{end}}
]
}]
deliveryPolicy: Post
groupingKey: ""
notifyBroadcast: false
teams:
facts: |
[{
"name": "Sync Status",
"value": "{{.app.status.sync.status}}"
},
{
"name": "Repository",
"value": "{{.app.spec.source.repoURL}}"
}
{{range $index, $c := .app.status.conditions}}
{{if not $index}},{{end}}
{{if $index}},{{end}}
{
"name": "{{$c.type}}",
"value": "{{$c.message}}"
}
{{end}}
]
potentialAction: |-
[{
"@type":"OpenUri",
"name":"Open Application",
"targets":[{
"os":"default",
"uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}"
}]
},
{
"@type":"OpenUri",
"name":"Open Repository",
"targets":[{
"os":"default",
"uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
}]
}]
title: Application {{.app.metadata.name}} sync status is 'Unknown'
```
### app-sync-succeeded
**definition**:
```yaml
email:
subject: Application {{.app.metadata.name}} has been successfully synced.
message: |
{{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} has been successfully synced at {{.app.status.operationState.finishedAt}}.
Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true .
slack:
attachments: |
[{
"title": "{{ .app.metadata.name}}",
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#18be52",
"fields": [
{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
},
{
"title": "Repository",
"value": "{{.app.spec.source.repoURL}}",
"short": true
}
{{range $index, $c := .app.status.conditions}}
{{if not $index}},{{end}}
{{if $index}},{{end}}
{
"title": "{{$c.type}}",
"value": "{{$c.message}}",
"short": true
}
{{end}}
]
}]
deliveryPolicy: Post
groupingKey: ""
notifyBroadcast: false
teams:
facts: |
[{
"name": "Sync Status",
"value": "{{.app.status.sync.status}}"
},
{
"name": "Synced at",
"value": "{{.app.status.operationState.finishedAt}}"
},
{
"name": "Repository",
"value": "{{.app.spec.source.repoURL}}"
}
{{range $index, $c := .app.status.conditions}}
{{if not $index}},{{end}}
{{if $index}},{{end}}
{
"name": "{{$c.type}}",
"value": "{{$c.message}}"
}
{{end}}
]
potentialAction: |-
[{
"@type":"OpenUri",
"name":"Operation Details",
"targets":[{
"os":"default",
"uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
}]
},
{
"@type":"OpenUri",
"name":"Open Repository",
"targets":[{
"os":"default",
"uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
}]
}]
themeColor: '#000080'
title: Application {{.app.metadata.name}} has been successfully synced
```

View File

@@ -0,0 +1,79 @@
### **time**
Time related functions.
<hr>
**`time.Now() Time`**
Executes function built-in Golang [time.Now](https://golang.org/pkg/time/#Now) function. Returns an instance of
Golang [Time](https://golang.org/pkg/time/#Time).
<hr>
**`time.Parse(val string) Time`**
Parses specified string using RFC3339 layout. Returns an instance of Golang [Time](https://golang.org/pkg/time/#Time).
### **strings**
String related functions.
<hr>
**`strings.ReplaceAll() string`**
Executes function built-in Golang [strings.ReplaceAll](https://pkg.go.dev/strings#ReplaceAll) function.
<hr>
**`strings.ToUpper() string`**
Executes function built-in Golang [strings.ToUpper](https://pkg.go.dev/strings#ToUpper) function.
<hr>
**`strings.ToLower() string`**
Executes function built-in Golang [strings.ToLower](https://pkg.go.dev/strings#ToLower) function.
### **sync**
<hr>
**`sync.GetInfoItem(app map, name string) string`**
Returns the `info` item value by given name stored in the Argo CD App sync operation.
### **repo**
Functions that provide additional information about Application source repository.
<hr>
**`repo.RepoURLToHTTPS(url string) string`**
Transforms given GIT URL into HTTPs format.
<hr>
**`repo.FullNameByRepoURL(url string) string`**
Returns repository URL full name `(<owner>/<repoName>)`. Currently supports only Github, Gitlab and Bitbucket.
<hr>
**`repo.GetCommitMetadata(sha string) CommitMetadata`**
Returns commit metadata. The commit must belong to the application source repository. `CommitMetadata` fields:
* `Message string` commit message
* `Author string` - commit author
* `Date time.Time` - commit creation date
* `Tags []string` - Associated tags
<hr>
**`repo.GetAppDetails() AppDetail`**
Returns application details. `AppDetail` fields:
* `Type string` - AppDetail type
* `Helm HelmAppSpec` - Helm details
* Fields :
* `Name string`
* `ValueFiles []string`
* `Parameters []*v1alpha1.HelmParameter`
* `Values string`
* `FileParameters []*v1alpha1.HelmFileParameter`
* Methods :
* `GetParameterValueByName(Name string)` Retrieve value by name in Parameters field
* `GetFileParameterPathByName(Name string)` Retrieve path by name in FileParameters field
* `Ksonnet *apiclient.KsonnetAppSpec` - Ksonnet details
* `Kustomize *apiclient.KustomizeAppSpec` - Kustomize details
* `Directory *apiclient.DirectoryAppSpec` - Directory details

View File

@@ -0,0 +1,305 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"id": 4,
"iteration": 1589141097815,
"links": [],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "$datasource",
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"hiddenSeries": false,
"id": 4,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "sum(increase(argocd_notifications_trigger_eval_total[$interval])) by (notifier)",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Trigger Evaluations",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "$datasource",
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"hiddenSeries": false,
"id": 2,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "sum(increase(argocd_notifications_deliveries_total[$interval])) by (notifier)",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Notification deliveries",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
}
],
"schemaVersion": 21,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"current": {
"text": "Prometheus",
"value": "Prometheus"
},
"hide": 0,
"includeAll": false,
"label": null,
"multi": false,
"name": "datasource",
"options": [],
"query": "prometheus",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
},
{
"auto": true,
"auto_count": 30,
"auto_min": "10s",
"current": {
"selected": false,
"text": "1m",
"value": "1m"
},
"hide": 0,
"label": null,
"name": "interval",
"options": [
{
"selected": false,
"text": "auto",
"value": "$__auto_interval_interval"
},
{
"selected": true,
"text": "1m",
"value": "1m"
},
{
"selected": false,
"text": "5m",
"value": "5m"
},
{
"selected": false,
"text": "10m",
"value": "10m"
},
{
"selected": false,
"text": "30m",
"value": "30m"
},
{
"selected": false,
"text": "1h",
"value": "1h"
},
{
"selected": false,
"text": "2h",
"value": "2h"
},
{
"selected": false,
"text": "4h",
"value": "4h"
},
{
"selected": false,
"text": "8h",
"value": "8h"
}
],
"query": "1m,5m,10m,30m,1h,2h,4h,8h",
"refresh": 2,
"skipUrlSync": false,
"type": "interval"
}
]
},
"time": {
"from": "now-15m",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "",
"title": "Argo CD Notifications",
"uid": "3qXvXigMz",
"version": 1
}

View File

@@ -0,0 +1,46 @@
# Overview
Argo CD Notifications continuously monitors Argo CD applications and provides a flexible way to notify
users about important changes in the application state. Using a flexible mechanism of
[triggers](triggers.md) and [templates](templates.md) you can configure when the notification should be sent as
well as notification content. Argo CD Notifications includes the [catalog](catalog.md) of useful triggers and templates.
So you can just use them instead of reinventing new ones.
## Getting Started
* Install Triggers and Templates from the catalog
```
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/notifications_catalog/install.yaml
```
* Add Email username and password token to `argocd-notifications-secret` secret
```bash
export EMAIL_USER=<your-username>
export PASSWORD=<your-password>
kubectl apply -n argocd -f - << EOF
apiVersion: v1
kind: Secret
metadata:
name: argocd-notifications-secret
stringData:
email-username: $EMAIL_USER
email-password: $PASSWORD
type: Opaque
EOF
```
* Register Email notification service
```bash
kubectl patch cm argocd-notifications-cm -n argocd --type merge -p '{"data": {"service.email.gmail": "{ username: $email-username, password: $email-password, host: smtp.gmail.com, port: 465, from: $email-username }" }}'
```
* Subscribe to notifications by adding the `notifications.argoproj.io/subscribe.on-sync-succeeded.slack` annotation to the Argo CD application or project:
```bash
kubectl patch app <my-app> -n argocd -p '{"metadata": {"annotations": {"notifications.argoproj.io/subscribe.on-sync-succeeded.slack":"<my-channel>"}}}' --type merge
```
Try syncing and application and get the notification once sync is completed.

View File

@@ -0,0 +1,30 @@
# Monitoring
The Argo CD Notification controller serves Prometheus metrics on port 9001.
!!! note
Metrics port might be changed using the `--metrics-port` flag in `argocd-notifications-controller` deployment.
## Metrics
The following metrics are available:
### `argocd_notifications_deliveries_total`
Number of delivered notifications.
Labels:
* `template` - notification template name
* `notifier` - notification service name
* `succeeded` - flag that indicates if notification was successfully sent or failed.
### `argocd_notifications_trigger_eval_total`
Number of trigger evaluations.
Labels:
* `name` - trigger name
* `triggered` - flag that indicates if trigger condition returned true of false.
# Examples:
* Grafana Dashboard: [grafana-dashboard.json](grafana-dashboard.json)

View File

@@ -0,0 +1,164 @@
# Alertmanager
## Parameters
The notification service is used to push events to [Alertmanager](https://github.com/prometheus/alertmanager), and the following settings need to be specified:
* `targets` - the alertmanager service address, array type
* `scheme` - optional, default is "http", e.g. http or https
* `apiPath` - optional, default is "/api/v2/alerts"
* `insecureSkipVerify` - optional, default is "false", when scheme is https whether to skip the verification of ca
* `basicAuth` - optional, server auth
* `bearerToken` - optional, server auth
* `timeout` - optional, the timeout in seconds used when sending alerts, default is "3 seconds"
`basicAuth` or `bearerToken` is used for authentication, you can choose one. If the two are set at the same time, `basicAuth` takes precedence over `bearerToken`.
## Example
### Prometheus Alertmanager config
```yaml
global:
resolve_timeout: 5m
route:
group_by: ['alertname']
group_wait: 10s
group_interval: 10s
repeat_interval: 1h
receiver: 'default'
receivers:
- name: 'default'
webhook_configs:
- send_resolved: false
url: 'http://10.5.39.39:10080/api/alerts/webhook'
```
You should turn off "send_resolved" or you will receive unnecessary recovery notifications after "resolve_timeout".
### Send one alertmanager without auth
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.alertmanager: |
targets:
- 10.5.39.39:9093
```
### Send alertmanager cluster with custom api path
If your alertmanager has changed the default api, you can customize "apiPath".
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.alertmanager: |
targets:
- 10.5.39.39:443
scheme: https
apiPath: /api/events
insecureSkipVerify: true
```
### Send high availability alertmanager with auth
Store auth token in `argocd-notifications-secret` Secret and use configure in `argocd-notifications-cm` ConfigMap.
```yaml
apiVersion: v1
kind: Secret
metadata:
name: <secret-name>
stringData:
alertmanager-username: <username>
alertmanager-password: <password>
alertmanager-bearer-token: <token>
```
- with basicAuth
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.alertmanager: |
targets:
- 10.5.39.39:19093
- 10.5.39.39:29093
- 10.5.39.39:39093
scheme: https
apiPath: /api/v2/alerts
insecureSkipVerify: true
basicAuth:
username: $alertmanager-username
password: $alertmanager-password
```
- with bearerToken
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.alertmanager: |
targets:
- 10.5.39.39:19093
- 10.5.39.39:29093
- 10.5.39.39:39093
scheme: https
apiPath: /api/v2/alerts
insecureSkipVerify: true
bearerToken: $alertmanager-bearer-token
```
## Templates
* `labels` - at least one label pair required, implement different notification strategies according to alertmanager routing
* `annotations` - optional, specifies a set of information labels, which can be used to store longer additional information, but only for display
* `generatorURL` - optional, default is '{{.app.spec.source.repoURL}}', backlink used to identify the entity that caused this alert in the client
the `label` or `annotations` or `generatorURL` values can be templated.
```yaml
context: |
argocdUrl: https://example.com/argocd
template.app-deployed: |
message: Application {{.app.metadata.name}} has been healthy.
alertmanager:
labels:
fault_priority: "P5"
event_bucket: "deploy"
event_status: "succeed"
recipient: "{{.recipient}}"
annotations:
application: '<a href="{{.context.argocdUrl}}/applications/{{.app.metadata.name}}">{{.app.metadata.name}}</a>'
author: "{{(call .repo.GetCommitMetadata .app.status.sync.revision).Author}}"
message: "{{(call .repo.GetCommitMetadata .app.status.sync.revision).Message}}"
```
You can do targeted push on [Alertmanager](https://github.com/prometheus/alertmanager) according to labels.
```yaml
template.app-deployed: |
message: Application {{.app.metadata.name}} has been healthy.
alertmanager:
labels:
alertname: app-deployed
fault_priority: "P5"
event_bucket: "deploy"
```
There is a special label `alertname`. If you dont set its value, it will be equal to the template name by default.

View File

@@ -0,0 +1,63 @@
# Email
## Parameters
The Email notification service sends email notifications using SMTP protocol and requires specifying the following settings:
* `host` - the SMTP server host name
* `port` - the SMTP server port
* `username` - username
* `password` - password
* `from` - from email address
* `html` - optional bool, true or false
* `insecure_skip_verify` - optional bool, true or false
## Example
The following snippet contains sample Gmail service configuration:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.email.gmail: |
username: $email-username
password: $email-password
host: smtp.gmail.com
port: 465
from: $email-username
```
Without authentication:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.email.example: |
host: smtp.example.com
port: 587
from: $email-username
```
## Template
Notification templates support specifying subject for email notifications:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
template.app-sync-succeeded: |
email:
subject: Application {{.app.metadata.name}} has been successfully synced.
message: |
{{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} has been successfully synced at {{.app.status.operationState.finishedAt}}.
Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true .
```

View File

@@ -0,0 +1,72 @@
# GitHub
## Parameters
The GitHub notification service changes commit status using [GitHub Apps](https://docs.github.com/en/developers/apps) and requires specifying the following settings:
* `appID` - the app id
* `installationID` - the app installation id
* `privateKey` - the app private key
* `enterpriseBaseURL` - optional URL, e.g. https://git.example.com/
## Configuration
1. Create a GitHub Apps using https://github.com/settings/apps/new
2. Change repository permissions to enable write commit statuses
![2](https://user-images.githubusercontent.com/18019529/108397381-3ca57980-725b-11eb-8d17-5b8992dc009e.png)
3. Generate a private key, and download it automatically
![3](https://user-images.githubusercontent.com/18019529/108397926-d4a36300-725b-11eb-83fe-74795c8c3e03.png)
4. Install app to account
5. Store privateKey in `argocd-notifications-secret` Secret and configure GitHub integration
in `argocd-notifications-cm` ConfigMap
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.github: |
appID: <app-id>
installationID: <installation-id>
privateKey: $github-privateKey
```
```yaml
apiVersion: v1
kind: Secret
metadata:
name: <secret-name>
stringData:
github-privateKey: |
-----BEGIN RSA PRIVATE KEY-----
(snip)
-----END RSA PRIVATE KEY-----
```
6. Create subscription for your GitHub integration
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.<trigger-name>.github: ""
```
## Templates
![](https://user-images.githubusercontent.com/18019529/108520497-168ce180-730e-11eb-93cb-b0b91f99bdc5.png)
If the message is set to 140 characters or more, it will be truncate.
```yaml
template.app-deployed: |
message: |
Application {{.app.metadata.name}} is now running new version of deployments manifests.
github:
status:
state: success
label: "continuous-delivery/{{.app.metadata.name}}"
targetURL: "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
```

View File

@@ -0,0 +1,81 @@
# Google Chat
## Parameters
The Google Chat notification service send message notifications to a google chat webhook. This service uses the following settings:
* `webhooks` - a map of the form `webhookName: webhookUrl`
## Configuration
1. Open `Google chat` and go to the space to which you want to send messages
2. From the menu at the top of the page, select **Configure Webhooks**
3. Under **Incoming Webhooks**, click **Add Webhook**
4. Give a name to the webhook, optionally add an image and click **Save**
5. Copy the URL next to your webhook
6. Store the URL in `argocd-notification-secret` and declare it in `argocd-notifications-cm`
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.googlechat: |
webhooks:
spaceName: $space-webhook-url
```
```yaml
apiVersion: v1
kind: Secret
metadata:
name: <secret-name>
stringData:
space-webhook-url: https://chat.googleapis.com/v1/spaces/<space_id>/messages?key=<key>&token=<token>
```
6. Create a subscription for your space
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.googlechat: spaceName
```
## Templates
You can send [simple text](https://developers.google.com/chat/reference/message-formats/basic) or [card messages](https://developers.google.com/chat/reference/message-formats/cards) to a Google Chat space. A simple text message template can be defined as follows:
```yaml
template.app-sync-succeeded: |
message: The app {{ .app.metadata.name }} has succesfully synced!
```
A card message can be defined as follows:
```yaml
template.app-sync-succeeded: |
googlechat:
cards: |
- header:
title: ArgoCD Bot Notification
sections:
- widgets:
- textParagraph:
text: The app {{ .app.metadata.name }} has succesfully synced!
- widgets:
- keyValue:
topLabel: Repository
content: {{ call .repo.RepoURLToHTTPS .app.spec.source.repoURL }}
- keyValue:
topLabel: Revision
content: {{ .app.spec.source.targetRevision }}
- keyValue:
topLabel: Author
content: {{ (call .repo.GetCommitMetadata .app.status.sync.revision).Author }}
```
The card message can be written in JSON too.

View File

@@ -0,0 +1,45 @@
# Grafana
To be able to create Grafana annotation with argocd-notifications you have to create an [API Key](https://grafana.com/docs/grafana/latest/http_api/auth/#create-api-key) inside your [Grafana](https://grafana.com).
![sample](https://user-images.githubusercontent.com/18019529/112024976-0f106080-8b78-11eb-9658-7663305899be.png)
1. Login to your Grafana instance as `admin`
2. On the left menu, go to Configuration / API Keys
3. Click "Add API Key"
4. Fill the Key with name `ArgoCD Notification`, role `Editor` and Time to Live `10y` (for example)
5. Click on Add button
6. Store apiKey in `argocd-notifications-secret` Secret and Copy your API Key and define it in `argocd-notifications-cm` ConfigMap
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.grafana: |
apiUrl: https://grafana.example.com/api
apiKey: $grafana-api-key
```
```yaml
apiVersion: v1
kind: Secret
metadata:
name: <secret-name>
stringData:
grafana-api-key: api-key
```
7. Create subscription for your Grafana integration
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.<trigger-name>.grafana: tag1|tag2 # list of tags separated with |
```
8. Change the annotations settings
![8](https://user-images.githubusercontent.com/18019529/112022083-47fb0600-8b75-11eb-849b-d25d41925909.png)

View File

@@ -0,0 +1,78 @@
# Mattermost
## Parameters
* `apiURL` - the server url, e.g. https://mattermost.example.com
* `token` - the bot token
* `insecureSkipVerify` - optional bool, true or false
## Configuration
1. Create a bot account and copy token after creating it
![1](https://user-images.githubusercontent.com/18019529/111499520-62ed0500-8786-11eb-88b0-d0aade61fed4.png)
2. Invite team
![2](https://user-images.githubusercontent.com/18019529/111500197-1229dc00-8787-11eb-98e5-587ee36c94a9.png)
3. Store token in `argocd-notifications-secret` Secret and configure Mattermost integration
in `argocd-notifications-cm` ConfigMap
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.mattermost: |
apiURL: <api-url>
token: $mattermost-token
```
```yaml
apiVersion: v1
kind: Secret
metadata:
name: <secret-name>
stringData:
mattermost-token: token
```
4. Copy channel id
![4](https://user-images.githubusercontent.com/18019529/111501289-333efc80-8788-11eb-9731-8353170cd73a.png)
5. Create subscription for your Mattermost integration
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.<trigger-name>.mattermost: <channel-id>
```
## Templates
![](https://user-images.githubusercontent.com/18019529/111502636-5fa74880-8789-11eb-97c5-5eac22c00a37.png)
You can reuse the template of slack.
Mattermost is compatible with attachments of Slack. See [Mattermost Integration Guide](https://docs.mattermost.com/developer/message-attachments.html).
```yaml
template.app-deployed: |
message: |
Application {{.app.metadata.name}} is now running new version of deployments manifests.
mattermost:
attachments: |
[{
"title": "{{.app.metadata.name}}",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#18be52",
"fields": [{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
}, {
"title": "Repository",
"value": "{{.app.spec.source.repoURL}}",
"short": true
}]
}]
```

View File

@@ -0,0 +1,28 @@
# Opsgenie
To be able to send notifications with argocd-notifications you have to create an [API Integration](https://docs.opsgenie.com/docs/integrations-overview) inside your [Opsgenie Team](https://docs.opsgenie.com/docs/teams).
1. Login to Opsgenie at https://app.opsgenie.com or https://app.eu.opsgenie.com (if you have an account in the european union)
2. Make sure you already have a team, if not follow this guide https://docs.opsgenie.com/docs/teams
3. Click "Teams" in the Menu on the left
4. Select the team that you want to notify
5. In the teams configuration menu select "Integrations"
6. click "Add Integration" in the top right corner
7. Select "API" integration
8. Give your integration a name, copy the "API key" and safe it somewhere for later
9. Make sure the checkboxes for "Create and Update Access" and "enable" are selected, disable the other checkboxes to remove unnecessary permissions
10. Click "Safe Integration" at the bottom
11. Check your browser for the correct server apiURL. If it is "app.opsgenie.com" then use the us/international api url `api.opsgenie.com` in the next step, otherwise use `api.eu.opsgenie.com` (european api).
12. You are finished with configuring opsgenie. Now you need to configure argocd-notifications. Use the apiUrl, the team name and the apiKey to configure the opsgenie integration in the `argocd-notifications-secret` secret.
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.opsgenie: |
apiUrl: <api-url>
apiKeys:
<your-team>: <integration-api-key>
```

View File

@@ -0,0 +1,53 @@
The notification services represent integration with services such as slack, email or custom webhook. Services are configured in `argocd-notifications-cm` ConfigMap
using `service.<type>.(<custom-name>)` keys and might reference sensitive data from `argocd-notifications-secret` Secret. Following example demonstrates slack
service configuration:
```yaml
service.slack: |
token: $slack-token
```
The `slack` indicates that service sends slack notification; name is missing and defaults to `slack`.
## Sensitive Data
Sensitive data like authentication tokens should be stored in `<secret-name>` Secret and can be referenced in
service configuration using `$<secret-key>` format. For example `$slack-token` referencing value of key `slack-token` in
`<secret-name>` Secret.
## Custom Names
Service custom names allow configuring two instances of the same service type.
```yaml
service.slack.workspace1: |
token: $slack-token-workspace1
service.slack.workspace2: |
token: $slack-token-workspace2
```
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.workspace1: my-channel
notifications.argoproj.io/subscribe.on-sync-succeeded.workspace2: my-channel
```
## Service Types
* [Email](./email.md)
* [GitHub](./github.md)
* [Slack](./slack.md)
* [Mattermost](./mattermost.md)
* [Opsgenie](./opsgenie.md)
* [Grafana](./grafana.md)
* [Webhook](./webhook.md)
* [Telegram](./telegram.md)
* [Teams](./teams.md)
* [Google Chat](./googlechat.md)
* [Rocket.Chat](./rocketchat.md)
* [Pushover](./pushover.md)
* [Alertmanager](./alertmanager.md)

View File

@@ -0,0 +1,33 @@
# Pushover
1. Create an app at [pushover.net](https://pushover.net/apps/build).
2. Store the API key in `<secret-name>` Secret and define the secret name in `<config-map-name>` ConfigMap:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.pushover: |
token: $pushover-token
```
```yaml
apiVersion: v1
kind: Secret
metadata:
name: <secret-name>
stringData:
pushover-token: avtc41pn13asmra6zaiyf7dh6cgx97
```
3. Add your user key to your Application resource:
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.pushover: uumy8u4owy7bgkapp6mc5mvhfsvpcd
```

View File

@@ -0,0 +1,96 @@
# Rocket.Chat
## Parameters
The Rocket.Chat notification service configuration includes following settings:
* `email` - the Rocker.Chat user's email
* `password` - the Rocker.Chat user's password
* `alias` - optional alias that should be used to post message
* `icon` - optional message icon
* `avatar` - optional message avatar
* `serverUrl` - optional Rocket.Chat server url
## Configuration
1. Login to your RocketChat instance
2. Go to user management
![2](https://user-images.githubusercontent.com/15252187/115824993-7ccad900-a411-11eb-89de-6a0c4438ffdf.png)
3. Add new user with `bot` role. Also note that `Require password change` checkbox mus be not checked
![3](https://user-images.githubusercontent.com/15252187/115825174-b4d21c00-a411-11eb-8f20-cda48cea9fad.png)
4. Copy username and password that you was created for bot user
5. Create a public or private channel, or a team, for this example `my_channel`
6. Add your bot to this channel **otherwise it won't work**
7. Store email and password in argocd_notifications-secret Secret
```yaml
apiVersion: v1
kind: Secret
metadata:
name: <secret-name>
stringData:
rocketchat-email: <email>
rocketchat-password: <password>
```
8. Finally, use these credentials to configure the RocketChat integration in the `argocd-configmap` config map:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.rocketchat: |
email: $rocketchat-email
password: $rocketchat-password
```
9. Create a subscription for your Rocket.Chat integration:
*Note: channel, team or user must be prefixed with # or @ elsewhere we will be interpretative destination as a room ID*
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.rocketchat: #my_channel
```
## Templates
Notification templates can be customized with RocketChat [attachments](https://developer.rocket.chat/api/rest-api/methods/chat/postmessage#attachments-detail).
*Note: Attachments structure in Rocketchat is same with Slack attachments [feature](https://api.slack.com/messaging/composing/layouts).*
<!-- TODO: @sergeyshevch Need to add screenshot with RocketChat attachments -->
The message attachments can be specified in `attachments` string fields under `rocketchat` field:
```yaml
template.app-sync-status: |
message: |
Application {{.app.metadata.name}} sync is {{.app.status.sync.status}}.
Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
rocketchat:
attachments: |
[{
"title": "{{.app.metadata.name}}",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#18be52",
"fields": [{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
}, {
"title": "Repository",
"value": "{{.app.spec.source.repoURL}}",
"short": true
}]
}]
```

View File

@@ -0,0 +1,149 @@
# Slack
If you want to send message using incoming webhook, you can use [webhook](./webhook.md#send-slack).
## Parameters
The Slack notification service configuration includes following settings:
* `token` - the app token
* `apiURL` - optional, the server url, e.g. https://example.com/api
* `username` - optional, the app username
* `icon` - optional, the app icon, e.g. :robot_face: or https://example.com/image.png
* `insecureSkipVerify` - optional bool, true or false
## Configuration
1. Create Slack Application using https://api.slack.com/apps?new_app=1
![1](https://user-images.githubusercontent.com/426437/73604308-4cb0c500-4543-11ea-9092-6ca6bae21cbb.png)
1. Once application is created navigate to `Enter OAuth & Permissions`
![2](https://user-images.githubusercontent.com/426437/73604309-4d495b80-4543-11ea-9908-4dea403d3399.png)
1. Click `Permissions` under `Add features and functionality` section and add `chat:write` scope. To use the optional username and icon overrides in the Slack notification service also add the `chat:write.customize` scope.
![3](https://user-images.githubusercontent.com/426437/73604310-4d495b80-4543-11ea-8576-09cd91aea0e5.png)
1. Scroll back to the top, click 'Install App to Workspace' button and confirm the installation.
![4](https://user-images.githubusercontent.com/426437/73604311-4d495b80-4543-11ea-9155-9d216b20ec86.png)
1. Once installation is completed copy the OAuth token.
![5](https://user-images.githubusercontent.com/426437/73604312-4d495b80-4543-11ea-832b-a9d9d5e4bc29.png)
1. Create a public or private channel, for this example `my_channel`
1. Invite your slack bot to this channel **otherwise slack bot won't be able to deliver notifications to this channel**
1. Store Oauth access token in `argocd-notifications-secret` secret
```yaml
apiVersion: v1
kind: Secret
metadata:
name: <secret-name>
stringData:
slack-token: <Oauth-access-token>
```
1. Define service type slack in data section of `argocd-notifications-cm` configmap:
service
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.slack: |
token: $slack-token
```
1. Add annotation in application yaml file to enable notifications for specific argocd app
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.slack: my_channel
```
## Templates
Notification templates can be customized to leverage slack message blocks and attachments
[feature](https://api.slack.com/messaging/composing/layouts).
![](https://user-images.githubusercontent.com/426437/72776856-6dcef880-3bc8-11ea-8e3b-c72df16ee8e6.png)
The message blocks and attachments can be specified in `blocks` and `attachments` string fields under `slack` field:
```yaml
template.app-sync-status: |
message: |
Application {{.app.metadata.name}} sync is {{.app.status.sync.status}}.
Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
slack:
attachments: |
[{
"title": "{{.app.metadata.name}}",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#18be52",
"fields": [{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
}, {
"title": "Repository",
"value": "{{.app.spec.source.repoURL}}",
"short": true
}]
}]
```
The messages can be aggregated to the slack threads by grouping key which can be specified in a `groupingKey` string field under `slack` field.
`groupingKey` is used across each template and works independently on each slack channel.
When multiple applications will be updated at the same time or frequently, the messages in slack channel can be easily read by aggregating with git commit hash, application name, etc.
Furthermore, the messages can be broadcast to the channel at the specific template by `notifyBroadcast` field.
```yaml
template.app-sync-status: |
message: |
Application {{.app.metadata.name}} sync is {{.app.status.sync.status}}.
Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
slack:
attachments: |
[{
"title": "{{.app.metadata.name}}",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#18be52",
"fields": [{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
}, {
"title": "Repository",
"value": "{{.app.spec.source.repoURL}}",
"short": true
}]
}]
# Aggregate the messages to the thread by git commit hash
groupingKey: "{{.app.status.sync.revision}}"
notifyBroadcast: false
template.app-sync-failed: |
message: |
Application {{.app.metadata.name}} sync is {{.app.status.sync.status}}.
Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
slack:
attachments: |
[{
"title": "{{.app.metadata.name}}",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#ff0000",
"fields": [{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
}, {
"title": "Repository",
"value": "{{.app.spec.source.repoURL}}",
"short": true
}]
}]
# Aggregate the messages to the thread by git commit hash
groupingKey: "{{.app.status.sync.revision}}"
notifyBroadcast: true
```
The message is sent according to the `deliveryPolicy` string field under the `slack` field. The available modes are `Post` (default), `PostAndUpdate`, and `Update`. The `PostAndUpdate` and `Update` settings require `groupingKey` to be set.

View File

@@ -0,0 +1,126 @@
# Teams
## Parameters
The Teams notification service send message notifications using Teams bot and requires specifying the following settings:
* `recipientUrls` - the webhook url map, e.g. `channelName: https://example.com`
## Configuration
1. Open `Teams` and goto `Apps`
2. Find `Incoming Webhook` microsoft app and click on it
3. Press `Add to a team` -> select team and channel -> press `Set up a connector`
4. Enter webhook name and upload image (optional)
5. Press `Create` then copy webhook url and store it in `argocd-notifications-secret` and define it in `argocd-notifications-cm`
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.teams: |
recipientUrls:
channelName: $channel-teams-url
```
```yaml
apiVersion: v1
kind: Secret
metadata:
name: <secret-name>
stringData:
channel-teams-url: https://example.com
```
6. Create subscription for your Teams integration:
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.teams: channelName
```
## Templates
![](https://user-images.githubusercontent.com/18019529/114271500-9d2b8880-9a4c-11eb-85c1-f6935f0431d5.png)
Notification templates can be customized to leverage teams message sections, facts, themeColor, summary and potentialAction [feature](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using).
```yaml
template.app-sync-succeeded: |
teams:
themeColor: "#000080"
sections: |
[{
"facts": [
{
"name": "Sync Status",
"value": "{{.app.status.sync.status}}"
},
{
"name": "Repository",
"value": "{{.app.spec.source.repoURL}}"
}
]
}]
potentialAction: |-
[{
"@type":"OpenUri",
"name":"Operation Details",
"targets":[{
"os":"default",
"uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
}]
}]
title: Application {{.app.metadata.name}} has been successfully synced
text: Application {{.app.metadata.name}} has been successfully synced at {{.app.status.operationState.finishedAt}}.
summary: "{{.app.metadata.name}} sync succeeded"
```
### facts field
You can use `facts` field instead of `sections` field.
```yaml
template.app-sync-succeeded: |
teams:
facts: |
[{
"name": "Sync Status",
"value": "{{.app.status.sync.status}}"
},
{
"name": "Repository",
"value": "{{.app.spec.source.repoURL}}"
}]
```
### theme color field
You can set theme color as hex string for the message.
![](https://user-images.githubusercontent.com/1164159/114864810-0718a900-9e24-11eb-8127-8d95da9544c1.png)
```yaml
template.app-sync-succeeded: |
teams:
themeColor: "#000080"
```
### summary field
You can set a summary of the message that will be shown on Notifcation & Activity Feed
![](https://user-images.githubusercontent.com/6957724/116587921-84c4d480-a94d-11eb-9da4-f365151a12e7.jpg)
![](https://user-images.githubusercontent.com/6957724/116588002-99a16800-a94d-11eb-807f-8626eb53b980.jpg)
```yaml
template.app-sync-succeeded: |
teams:
summary: "Sync Succeeded"
```

View File

@@ -0,0 +1,35 @@
# Telegram
1. Get an API token using [@Botfather](https://t.me/Botfather).
2. Store token in `<secret-name>` Secret and configure telegram integration
in `<config-map-name>` ConfigMap:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.telegram: |
token: $telegram-token
```
3. Create new Telegram [channel](https://telegram.org/blog/channels).
4. Add your bot as an administrator.
5. Use this channel `username` (public channel) or `chatID` (private channel) in the subscription for your Telegram integration:
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.telegram: username
```
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.telegram: -1000000000000
```

View File

@@ -0,0 +1,177 @@
## Configuration
The webhook notification service allows sending a generic HTTP request using the templatized request body and URL.
Using Webhook you might trigger a Jenkins job, update Github commit status.
Use the following steps to configure webhook:
1 Register webhook in `argocd-notifications-cm` ConfigMap:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.webhook.<webhook-name>: |
url: https://<hostname>/<optional-path>
headers: #optional headers
- name: <header-name>
value: <header-value>
basicAuth: #optional username password
username: <username>
password: <api-key>
```
2 Define template that customizes webhook request method, path and body:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
template.github-commit-status: |
webhook:
<webhook-name>:
method: POST # one of: GET, POST, PUT, PATCH. Default value: GET
path: <optional-path-template>
body: |
<optional-body-template>
trigger.<trigger-name>: |
- when: app.status.operationState.phase in ['Succeeded']
send: [github-commit-status]
```
3 Create subscription for webhook integration:
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.<trigger-name>.<webhook-name>: ""
```
## Examples
### Set Github commit status
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.webhook.github: |
url: https://api.github.com
headers: #optional headers
- name: Authorization
value: token $github-token
```
2 Define template that customizes webhook request method, path and body:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.webhook.github: |
url: https://api.github.com
headers: #optional headers
- name: Authorization
value: token $github-token
template.github-commit-status: |
webhook:
github:
method: POST
path: /repos/{{call .repo.FullNameByRepoURL .app.spec.source.repoURL}}/statuses/{{.app.status.operationState.operation.sync.revision}}
body: |
{
{{if eq .app.status.operationState.phase "Running"}} "state": "pending"{{end}}
{{if eq .app.status.operationState.phase "Succeeded"}} "state": "success"{{end}}
{{if eq .app.status.operationState.phase "Error"}} "state": "error"{{end}}
{{if eq .app.status.operationState.phase "Failed"}} "state": "error"{{end}},
"description": "ArgoCD",
"target_url": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"context": "continuous-delivery/{{.app.metadata.name}}"
}
```
### Start Jenkins Job
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.webhook.jenkins: |
url: http://<jenkins-host>/job/<job-name>/build?token=<job-secret>
basicAuth:
username: <username>
password: <api-key>
type: Opaque
```
### Send form-data
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.webhook.form: |
url: https://form.example.com
headers:
- name: Content-Type
value: application/x-www-form-urlencoded
template.form-data: |
webhook:
form:
method: POST
body: key1=value1&key2=value2
```
### Send Slack
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.webhook.slack_webhook: |
url: https://hooks.slack.com/services/xxxxx
headers:
- name: Content-Type
value: application/json
template.send-slack: |
webhook:
slack_webhook:
method: POST
body: |
{
"attachments": [{
"title": "{{.app.metadata.name}}",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#18be52",
"fields": [{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
}, {
"title": "Repository",
"value": "{{.app.spec.source.repoURL}}",
"short": true
}]
}]
}
```

View File

@@ -0,0 +1,71 @@
The subscription to Argo CD application events can be defined using `notifications.argoproj.io/subscribe.<trigger>.<service>: <recipient>` annotation.
For example, the following annotation subscribes two Slack channels to notifications about every successful synchronization of the Argo CD application:
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.slack: my-channel1;my-channel2
```
Annotation key consists of following parts:
* `on-sync-succeeded` - trigger name
* `slack` - notification service name
* `my-channel1;my-channel2` - a semicolon separated list of recipients
You can create subscriptions for all applications of the Argo CD project by adding the same annotation to AppProject CRD:
```yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.slack: my-channel1;my-channel2
```
## Default Subscriptions
The subscriptions might be configured globally in the `argocd-notifications-cm` ConfigMap using `subscriptions` field. The default subscriptions
are applied to all applications. The trigger and applications might be configured using the
`triggers` and `selector` fields:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
# Contains centrally managed global application subscriptions
subscriptions: |
# subscription for on-sync-status-unknown trigger notifications
- recipients:
- slack:test2
- email:test@gmail.com
triggers:
- on-sync-status-unknown
# subscription restricted to applications with matching labels only
- recipients:
- slack:test3
selector: test=true
triggers:
- on-sync-status-unknown
```
If you want to use webhook in subscriptions, you need to store the custom name to recipients.
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
service.webhook.<webhook-name>: |
(snip)
subscriptions: |
- recipients:
- <webhook-name>
triggers:
- on-sync-status-unknown
```

View File

@@ -0,0 +1,93 @@
The notification template is used to generate the notification content and configured in `argocd-notifications-cm` ConfigMap. The template is leveraging
[html/template](https://golang.org/pkg/html/template/) golang package and allow to customize notification message.
Templates are meant to be reusable and can be referenced by multiple triggers.
The following template is used to notify the user about application sync status.
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
template.my-custom-template-slack-template: |
message: |
Application {{.app.metadata.name}} sync is {{.app.status.sync.status}}.
Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
```
Each template has access to the following fields:
- `app` holds the application object.
- `context` is user defined string map and might include any string keys and values.
- `serviceType` holds the notification service type name. The field can be used to conditionally
render service specific fields.
- `recipient` holds the recipient name.
## Defining user-defined `context`
It is possible to define some shared context between all notification templates by setting a top-level
YAML document of key-value pairs, which can then be used within templates, like so:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
context: |
region: east
environmentName: staging
template.a-slack-template-with-context: |
message: "Something happened in {{ .context.environmentName }} in the {{ .context.region }} data center!"
```
## Notification Service Specific Fields
The `message` field of the template definition allows creating a basic notification for any notification service. You can leverage notification service-specific
fields to create complex notifications. For example using service-specific you can add blocks and attachments for Slack, subject for Email or URL path, and body for Webhook.
See corresponding service [documentation](services/overview.md) for more information.
## Change the timezone
You can change the timezone to show it as follows.
1. Call time functions.
```
{{ (call .time.Parse .app.status.operationState.startedAt).Local.Format "2006-01-02T15:04:05Z07:00" }}
```
2. Set environment to container.
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: argocd-notifications-controller
spec:
(snip)
spec:
containers:
- name: argocd-notifications-controller
env:
- name: TZ
value: Asia/Tokyo
```
## Functions
Templates have access to the set of built-in functions:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
template.my-custom-template-slack-template: |
message: "Author: {{(call .repo.GetCommitMetadata .app.status.sync.revision).Author}}"
```
{!functions.md!}

View File

@@ -0,0 +1,125 @@
The trigger defines the condition when the notification should be sent. The definition includes name, condition
and notification templates reference. The condition is a predicate expression that returns true if the notification
should be sent. The trigger condition evaluation is powered by [antonmedv/expr](https://github.com/antonmedv/expr).
The condition language syntax is described at [Language-Definition.md](https://github.com/antonmedv/expr/blob/master/docs/Language-Definition.md).
The trigger is configured in `argocd-notifications-cm` ConfigMap. For example the following trigger sends a notification
when application sync status changes to `Unknown` using the `app-sync-status` template:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
trigger.on-sync-status-unknown: |
- when: app.status.sync.status == 'Unknown' # trigger condition
send: [app-sync-status, github-commit-status] # template names
```
Each condition might use several templates. Typically each template is responsible for generating a service-specific notification part.
In the example above `app-sync-status` template "knows" how to create email and slack notification and `github-commit-status` knows how to
generate payload for Github webhook.
## Conditions Bundles
Triggers are typically managed by administrators and encapsulate information about when and which notification should be sent.
The end users just need to subscribe to the trigger and specify the notification destination. In order to improve user experience
triggers might include multiple conditions with a different set of templates for each condition. For example, the following trigger
covers all stages of sync status operation and use a different template for different cases:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
trigger.sync-operation-change: |
- when: app.status.operationState.phase in ['Succeeded']
send: [github-commit-status]
- when: app.status.operationState.phase in ['Running']
send: [github-commit-status]
- when: app.status.operationState.phase in ['Error', 'Failed']
send: [app-sync-failed, github-commit-status]
```
## Avoid Sending Same Notification Too Often
In some cases, the trigger condition might be "flapping". The example below illustrates the problem.
The trigger is supposed to generate a notification once when Argo CD application is successfully synchronized and healthy.
However, the application health status might intermittently switch to `Progressing` and then back to `Healthy` so the trigger might unnecessarily generate
multiple notifications. The `oncePer` field configures triggers to generate the notification only when the corresponding application field changes.
The `on-deployed` trigger from the example below sends the notification only once per observed Git revision of the deployment repository.
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
# Optional 'oncePer' property ensure that notification is sent only once per specified field value
# E.g. following is triggered once per sync revision
trigger.on-deployed: |
when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status == 'Healthy'
oncePer: app.status.sync.revision
send: [app-sync-succeeded]
```
### oncePer
The `oncePer` filed is supported like as follows.
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
example.com/version: v0.1
```
```yaml
oncePer: app.metadata.annotations["example.com/version"]
```
## Default Triggers
You can use `defaultTriggers` field instead of specifying individual triggers to the annotations.
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
# Holds list of triggers that are used by default if trigger is not specified explicitly in the subscription
defaultTriggers: |
- on-sync-status-unknown
defaultTriggers.mattermost: |
- on-sync-running
- on-sync-succeeded
```
Specify the annotations as follows to use `defaultTriggers`. In this example, `slack` sends when `on-sync-status-unknown`, and `mattermost` sends when `on-sync-running` and `on-sync-succeeded`.
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.slack: my-channel
notifications.argoproj.io/subscribe.mattermost: my-mattermost-channel
```
## Functions
Triggers have access to the set of built-in functions.
Example:
```yaml
when: time.Now().Sub(time.Parse(app.status.operationState.startedAt)).Minutes() >= 5
```
{!functions.md!}

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