Compare commits

...

197 Commits

Author SHA1 Message Date
gcp-cherry-pick-bot[bot]
3f170be710 fix: Updated docs about using a slash in ignoreDifferences (#15144) (#15170)
Signed-off-by: Christian Hernandez <christian@chernand.io>
Co-authored-by: Christian Hernandez <christianh814@users.noreply.github.com>
2023-11-14 10:59:57 -05:00
Shyukri Shyukriev
63f0cbbe65 chore: Upgrade Redis to redis:7.0.14 (#16164) (#16220)
* chore: Upgrade Redis to redis:7.0.14 (#16164)

Fixes https://github.com/argoproj/argo-cd/issues/15448

Signed-off-by: Shyukri Shyukriev <shukera@gmail.com>
Co-authored-by: Shyukri Shyukriev <shyukri.shyukriev@mariadb.com>
(cherry picked from commit 570c24e38e)
Signed-off-by: Shyukri Shyukriev <shukera@gmail.com>

* chore: Redis HA securityContext

Signed-off-by: Shyukri Shyukriev <shukera@gmail.com>

---------

Signed-off-by: Shyukri Shyukriev <shukera@gmail.com>
Co-authored-by: Shyukri Shyukriev <shyukri.shyukriev@mariadb.com>
2023-11-02 15:31:19 -04:00
May Zhang
8b88abd951 fix: argocd notification controller app cluster permission issue (#16057) (#16166)
* if applicationNamespaces is not provided as input parameter, then use namespaced appClient



* fix go lint error



---------

Signed-off-by: May Zhang <may_zhang@intuit.com>
2023-10-31 10:10:50 -04:00
Michael Crenshaw
394211c425 fix(notifications): Allow notifications controller to notify on all namespaces (cherry-pick 2.6) (#15857)
* fix(notifications): Allow notifications controller to notify on all namespaces (#15702)

* Allow notifications controller to notify on all namespaces

This adds functionality to the notifications controller to be notified
of and send notifications for applications in any namespace. The
namespaces to watch are controlled by the same --application-namespaces
and ARGOCD_APPLICATION_NAMESPACES variables as in the application
controller.

Signed-off-by: Nikolas Skoufis <nskoufis@seek.com.au>

* Add SEEK to users.md

Signed-off-by: Nikolas Skoufis <nskoufis@seek.com.au>

* Remove unused fields

Signed-off-by: Nikolas Skoufis <nskoufis@seek.com.au>

* Revert changes to Procfile

Signed-off-by: Nik Skoufis <n.skoufis@gmail.com>

* Fix unit tests

Signed-off-by: Nikolas Skoufis <nskoufis@seek.com.au>

* - add argocd namespaces environment variable to notifications controller

Signed-off-by: Stewart Thomson <sthomson@wynshop.com>

* - add example cluster role rbac

Signed-off-by: Stewart Thomson <sthomson@wynshop.com>

* - only look for projects in the controller's namespace (argocd by default)

Signed-off-by: Stewart Thomson <sthomson@wynshop.com>

* - update base manifest

Signed-off-by: Stewart Thomson <sthomson@wynshop.com>

* - skip app processing in notification controller

Signed-off-by: Stewart Thomson <sthomson@wynshop.com>

* added unit test and updated doc

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

* added unit test and updated doc

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

* updated examples/k8s-rbac/argocd-server-applications/kustomization.yaml's resources

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

---------

Signed-off-by: Nikolas Skoufis <nskoufis@seek.com.au>
Signed-off-by: Nik Skoufis <n.skoufis@gmail.com>
Signed-off-by: Stewart Thomson <sthomson@wynshop.com>
Signed-off-by: May Zhang <may_zhang@intuit.com>
Co-authored-by: Nikolas Skoufis <nskoufis@seek.com.au>
Co-authored-by: Nik Skoufis <n.skoufis@gmail.com>
Co-authored-by: Stewart Thomson <sthomson@wynshop.com>

undo unnecessary manifest changes

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

undo unnecessary manifest changes

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

* revert unnecessary changes

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

---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: May Zhang <may_zhang@intuit.com>
2023-10-26 11:33:04 -04:00
Abhishek Veeramalla
348d45cc6a chore(deps): upgrade Go version to 1.20 (#16105)
Signed-off-by: iam-veeramalla <abhishek.veeramalla@gmail.com>
2023-10-25 13:14:20 -04:00
gcp-cherry-pick-bot[bot]
975f78a126 fix: helm set parameter to allow passing list parameters (#15978) (#15996)
Signed-off-by: kkk777-7 <kota.kimura0725@gmail.com>
Co-authored-by: Kota Kimura <86363983+kkk777-7@users.noreply.github.com>
2023-10-16 16:48:01 -04:00
gcp-cherry-pick-bot[bot]
4bf8e7fa66 docs: 'action' RBAC example for Kind without group (#15589) (#15599)
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-09-20 11:14:38 -04:00
gcp-cherry-pick-bot[bot]
869e722af2 fix(#12862): Update FlinkDeployment health check to support Flink v1.x (#15065) (#15560)
Signed-off-by: Dylan Slavin <dylan@sla.vin>
Co-authored-by: Dylan Slavin <dylan@sla.vin>
2023-09-19 09:06:17 -04:00
gcp-cherry-pick-bot[bot]
38fbe0225a fix(repo-server): avoid fetching commit sha for multisource applications (#15037) (#15067) (#15557)
* Rebase Signed-off-by: ozlevka-work <lev@ozeryansky.com>



* Remove test file Signed-off-by: ozlevka-work <lev@ozeryansky.com>



* Go linter fmt Signed-off-by: ozlevka-work <lev@ozeryansky.com>



* Additional linter fmt Signed-off-by: ozlevka-work <lev@ozeryansky.com>




* Add unit test for changes Signed-off-by: Lev <lozeryan@akami.com>



* Update reposerver/repository/repository.go





* Trigger CI



---------

Signed-off-by: Lev <lozeryan@akami.com>
Signed-off-by: Lev <lev@ozeryansky.com>
Signed-off-by: Lev Ozeryansky <lozeryan@akamai.com>
Co-authored-by: Lev Ozeryansky <lozeryan@akamai.com>
Co-authored-by: Lev <lozeryan@akami.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-09-19 09:05:24 -04:00
gcp-cherry-pick-bot[bot]
e274c3ab93 docs: Fix docs for destinations in AppProjects (#15153) (#15182) (#15540)
Signed-off-by: Andreas Lindhé <andreas@lindhe.io>
Co-authored-by: Andreas Lindhé <lindhe@users.noreply.github.com>
2023-09-18 09:13:24 -04:00
gcp-cherry-pick-bot[bot]
b763d194f4 fix: make WatchResourceTree use namespaced cache key (#15258) (#15524)
* fix: make WatchResourceTree use namespaced application cache key



* chore: add PGS to USERS.md



---------

Signed-off-by: Torbjørn Fjørtoft <torbjorn.fjortoft@pgs.com>
Co-authored-by: Torbjørn Fjørtoft <torbjorn.fjortoft@gmail.com>
2023-09-15 12:00:06 -04:00
gcp-cherry-pick-bot[bot]
8152092918 fix: handle annotations for resources with ':' in the name (#15101) (#15380) (#15412)
* fix: handle annotations for resources with ':' in the name



* fix: switch to using splitN for handling annotation splitting



* fix: check len(parts) !=3



* Retrigger CI pipeline



---------

Signed-off-by: Oreon Lothamer <oreon.lothamer@softrams.com>
Co-authored-by: Oreon Lothamer <73498677+oreonl@users.noreply.github.com>
2023-09-08 13:55:01 -04:00
argo-bot
2f7922be9c Bump version to 2.6.15 2023-09-07 17:39:13 +00:00
argo-bot
f30a20a116 Bump version to 2.6.15 2023-09-07 17:38:54 +00:00
Alexander Matyushentsev
3b50226e76 Merge pull request from GHSA-fwr2-64vr-xv9m
* fix: prevent seeing/editing 'kubectl.kubernetes.io/last-applied-configuration' cluster annotation

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

* fix: failing unit test

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

* fix: issues with codegen

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

---------

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Signed-off-by: iam-veeramalla <abhishek.veeramalla@gmail.com>
Co-authored-by: iam-veeramalla <abhishek.veeramalla@gmail.com>
2023-09-07 10:14:57 -04:00
pasha-codefresh
0c6cfa306d Merge pull request from GHSA-g687-f2gx-6wm8
* feat: use untar with limiter

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

* feat: use untar with limiter

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

* feat: use untar with limiter

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

* feat: use untar with limiter

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

---------

Signed-off-by: pashakostohrys <pavel@codefresh.io>
2023-09-07 10:12:15 -04:00
gcp-cherry-pick-bot[bot]
1fb3d3fb11 chore: add example jq path expression (#15130) (#15211)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-08-29 12:44:26 -04:00
gcp-cherry-pick-bot[bot]
d9ce38f357 docs: document sourceNamespaces field (#15195) (#15214)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-08-29 12:43:54 -04:00
argo-bot
d16bc2610b Bump version to 2.6.14 2023-08-24 21:08:16 +00:00
argo-bot
a443ab06e0 Bump version to 2.6.14 2023-08-24 21:08:11 +00:00
Michael Crenshaw
d5ba03b5f2 chore: free up less disk space
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-08-24 17:07:08 -04:00
Michael Crenshaw
71d7bb67a4 chore(ci): free up disk space
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-08-24 15:32:29 -04:00
Michael Crenshaw
6f0b7cb1a4 chore: revert version number to fix build
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-08-24 13:40:36 -04:00
Michael Crenshaw
2b15397479 Revert "Bump version to 2.6.14"
This reverts commit 84f935a615.

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-08-23 17:00:17 -04:00
Marie Katrine Ekeberg
999132d9e8 fix: Disable keep alives for helm https connections (#13848)
Signed-off-by: Marie Katrine Ekeberg <marie.ekeberg@tietoevry.com>
2023-08-23 16:13:13 -04:00
gcp-cherry-pick-bot[bot]
eb34149e7a fix(ui): code lint (#15150) (#15162)
Signed-off-by: ebuildy <ebuildy@gmail.com>
Co-authored-by: Thomas Decaux <ebuildy@gmail.com>
2023-08-22 14:20:58 -04:00
gcp-cherry-pick-bot[bot]
970329f99b fix: windows build (#15154) (#15158)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-08-22 13:08:18 -04:00
pasha-codefresh
fbf49f72e7 Merge pull request from GHSA-c8xw-vjgf-94hr
Signed-off-by: pashakostohrys <pavel@codefresh.io>
2023-08-21 16:15:09 -04:00
gcp-cherry-pick-bot[bot]
cc56e70718 docs(progressive syncs): specify which ConfigMap to use (#15119) (#15135)
Signed-off-by: Gaël Jourdan-Weil <gjourdanweil@gmail.com>
Co-authored-by: Gaël Jourdan-Weil <gjourdanweil@gmail.com>
2023-08-21 16:13:55 -04:00
gcp-cherry-pick-bot[bot]
8d758733ad docs: add docs for various annotations and labels (#14020) (#15114)
* docs: add docs for various annotations



* more info



* more docs



---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-08-18 11:23:01 -04:00
gcp-cherry-pick-bot[bot]
0432c40a85 docs: fix typo (#15083) (#15088)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-08-18 11:18:56 -04:00
gcp-cherry-pick-bot[bot]
09d1a1356d docs: document permitOnlyProjectScopedClusters field (#15076) (#15080)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-08-16 15:43:59 -04:00
gcp-cherry-pick-bot[bot]
343cc02339 fix(cmp): send sigterm to cmp commands before sigkill to allow for potential cleanup (#9180) (#14955) (#14960)
* fix: send sigterm to cmp commands before sigkill to allow for potential cleanup



* fix: unit test for runCommand in cmpserver to test cleanup modified



* fix: change unit test for plugin/runCommand to avoid bad trap along with lint fix



---------

Signed-off-by: Ashin Sabu <ashin.sabu@harness.io>
Co-authored-by: Ashin Sabu <139749674+ashinsabu3@users.noreply.github.com>
2023-08-08 11:38:22 -04:00
argo-bot
84f935a615 Bump version to 2.6.14 2023-08-07 16:49:37 +00:00
argo-bot
3aa3b5c778 Bump version to 2.6.14 2023-08-07 16:49:31 +00:00
gcp-cherry-pick-bot[bot]
201513d1c9 fix(ui): COPY JSON for ArgoCD version should include trailing newline (#5117) (#14917) (#14940)
Signed-off-by: Vipin M S <vipinachar2016@gmail.com>
Co-authored-by: Vipin M S <40431065+vipinachar@users.noreply.github.com>
2023-08-07 11:02:53 -04:00
gcp-cherry-pick-bot[bot]
cea6f80266 docs: Update Generators-Git.md (#14921) (#14936)
Remove a misleading symbol from the pattern for the path.Match function. The pipe symbol doesn't have any special meaning.

Signed-off-by: German Lashevich <german.lashevich@gmail.com>
Co-authored-by: German Lashevich <design.ber@gmail.com>
2023-08-07 10:48:32 -04:00
gcp-cherry-pick-bot[bot]
deddacf6cc docs: add ignoreDifferences name and namespace fields (#14741) (#14807)
* Update application.yaml



* Update docs/operator-manual/application.yaml



---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-08-03 10:28:21 -04:00
gcp-cherry-pick-bot[bot]
bd7bd4b18c docs: Update application.yaml (#14742) (#14811)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-08-03 10:26:56 -04:00
gcp-cherry-pick-bot[bot]
95587118a1 docs: Change Generator docs for List Generator to note any key/value pairs can be used (#14825) (#14834)
This is no longer limited to cluster/url value pairs.

Signed-off-by: JesseBot <jessebot@linux.com>
Co-authored-by: JesseBot <jessebot@linux.com>
2023-08-01 13:56:19 -04:00
gcp-cherry-pick-bot[bot]
0d93b20796 fix: ManagedResources API should not return diff for hooks (#14816) (#14828)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2023-08-01 09:07:18 -07:00
Alexander Matyushentsev
1f6174eebb fix(controller): cache deadlock on delete and re-add cluster (cherry-pick #14780) (#14814)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2023-08-01 08:24:02 -07:00
gcp-cherry-pick-bot[bot]
4261d08b29 docs: Clarify that security policy covers last 3 versions (cherry-pick #14786) (#14793)
* docs: Clarify that security policy covers last 3 versions (#14786)

* docs: Clarify that security policy covers last 3 versions

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

* Update SECURITY.md

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

---------

Signed-off-by: Kostis Kapelonis <kostis@codefresh.io>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

* docs: Clarify that security policy covers last 3 versions (#14786)

* docs: Clarify that security policy covers last 3 versions

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

* Update SECURITY.md

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

---------

Signed-off-by: Kostis Kapelonis <kostis@codefresh.io>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

---------

Signed-off-by: Kostis Kapelonis <kostis@codefresh.io>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Kostis (Codefresh) <39800303+kostis-codefresh@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-07-31 16:38:25 -04:00
gcp-cherry-pick-bot[bot]
966919792f fix: OCI dependency url can't contain part of repository (#14699) (#14758)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2023-07-27 16:19:16 -04:00
gcp-cherry-pick-bot[bot]
2bb1587333 fix(sso): Set redirectURI for gitea, google, oauth Dex connectors (#11237) (#14738)
Signed-off-by: ylxianzhe <ylxianzhe@outlook.com>
Co-authored-by: XianzheTM <ylxianzhe@outlook.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-07-27 10:16:28 -04:00
gcp-cherry-pick-bot[bot]
f685ee61e1 fix(server): handle PATCH in http/s server (#2677) (#14530) (#14733)
Signed-off-by: mmerrill3 <jjpaacks@gmail.com>
Co-authored-by: Michael Merrill <jjpaacks@gmail.com>
2023-07-27 10:15:12 -04:00
Yuan Tang
2883620bb0 chore: Print in-cluster svr addr disabled warning when server starts (#14684)
* chore: Update log level to warn when in-cluster svr addr is disabled but internal addr is used (#14520)

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

* chore: Print in-cluster svr addr disabled warning during ArgoDB initialization (#14539)

* chore: Print in-cluster svr addr disabled warning during ArgoDB initialization

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

* fix: undo a change

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

* chore: move to a function

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

* chore: rename

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

---------

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

* chore: Print in-cluster svr addr disabled warning when server starts (#14553)

* chore: Print in-cluster svr addr disabled warning when server starts

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

* fix: mock

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

* no interface change

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

---------

Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

---------

Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-07-24 17:25:32 -04:00
gcp-cherry-pick-bot[bot]
261e665bd9 fix: ApplicationSet Controller crashes when tag is not closed; panic: Cannot find end tag="}}"(#14227) ( #14227) (#14689) (#14690)
* appSet fix



* Update applicationset/utils/utils_test.go



---------

Signed-off-by: schakrad <58915923+schakrad@users.noreply.github.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: schakrad <58915923+schakrad@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-07-24 17:25:02 -04:00
gcp-cherry-pick-bot[bot]
b05386d8b7 fix: webhook handler fails to refresh when alternate application namespaces are configured (#13976) (#14654)
* fix: Add failing test for webhooks in all namespaces

This adds a failing test that properly exercises this functionality over
all namespaces. The issue with the code that is under test is that it
does not pass the namespace correctly to the patch of the application,
resulting in the patch not taking place in the correct namespace



* fix: queue webhook refresh for apps in all namespaces

This passes the test in the previous commit, to ensure that webhooks
correctly refresh applications across all namespaces.



* fix: Use existing NamespacedName type

Use the existing type instead of a custom type



---------

Signed-off-by: Nikolas Skoufis <nskoufis@seek.com.au>
Co-authored-by: Nik Skoufis <n.skoufis@gmail.com>
2023-07-21 14:31:19 -04:00
gcp-cherry-pick-bot[bot]
ce87bf951e docs: Skip export keyword in notification docs (#14633) (#14644)
This change does three things:

1. It removes the `export` keyword. It's not required since the example
   executes a script where the variables are evaluated as an inline
   string. One could even argue that there is a slight security issue
   with using `export` here, since that will expose the credentials to
   all applications started in the current context.
2. It adds a space (` `) before the `PASSWORD` variable. This will keep
   it out of the user's Bash history by default. See [HISTIGNORE][bash].
3. Add a newline for clarity.

[bash]: https://www.gnu.org/software/bash/manual/bash.html#index-HISTIGNORE

Signed-off-by: Andreas Lindhé <andreas@lindhe.io>
Co-authored-by: Andreas Lindhé <lindhe@users.noreply.github.com>
2023-07-21 10:17:17 -04:00
gcp-cherry-pick-bot[bot]
6ecb081ac8 fix(ui): Fix Destination Cluster URL/Name Drop down not updating destination field (#13813) (#14216) (#14628)
* fix(ui): Fix Destination Cluster URL/Name Drop down not updating destination field (fixes #13813)



* Address linting errors



---------

Signed-off-by: Kyle Purkiss <kyle.purkiss@procore.com>
Co-authored-by: Kyle Purkiss <kyle.purkiss@procore.com>
2023-07-20 14:54:40 -04:00
argo-bot
4c4fa201a3 Bump version to 2.6.13 2023-07-19 17:21:37 +00:00
argo-bot
3c94817fb2 Bump version to 2.6.13 2023-07-19 17:21:31 +00:00
gcp-cherry-pick-bot[bot]
a05a3eef80 fix(cli): allow argocd cli app command for multi source apps (#14256) (#14589)
Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>
Co-authored-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>
2023-07-18 16:36:53 -04:00
gcp-cherry-pick-bot[bot]
1974b8a2bf fix(cli): argocd CLI RBAC validation doesn't work on actions (#13911) (#14578) (#14583)
* #11602 fix : Object options menu truncated when selected in ApplicationListView.



* #11602 fix : Object options menu truncated when selected in ApplicationListView.



* changes for argocd_rbac



---------

Signed-off-by: schakradari <saisindhu_chakradari@intuit.com>
Signed-off-by: schakrad <chakradari.sindhu@gmail.com>
Co-authored-by: schakrad <58915923+schakrad@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-07-18 16:22:24 -04:00
gcp-cherry-pick-bot[bot]
a117187138 docs: Correct example ClusterRole to allow Events in any namespace (#14544) (#14552)
Fixes: #14477

Signed-off-by: Dimitar Georgievski <dgeorgievski@gmail.com>
Co-authored-by: Dimitar Georgievski <dgeorgievski@gmail.com>
2023-07-17 12:56:49 -04:00
gcp-cherry-pick-bot[bot]
5456570f8d fix: 'argocd-server-tls' Secret should be loaded from informer (#14522) (#14548)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2023-07-17 12:02:26 -04:00
Alexander Matyushentsev
aa7a849859 Cherry[2.6] Helm repository might affect manifest generation of not related helm charts (#14529)
* Merge pull request from GHSA-94mc-2ch7-r5r5

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

* fix: fix broken helm repo alias/name support (#13647)

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

---------

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2023-07-15 09:54:58 -04:00
gcp-cherry-pick-bot[bot]
969c68c2b3 fix(ui): Fix Link warnings (#13694) (#13854) (#14519)
Signed-off-by: Geoffrey Muselli <geoffrey.muselli@gmail.com>
Co-authored-by: Geoffrey MUSELLI <geoffrey.muselli@gmail.com>
2023-07-14 16:09:14 -04:00
gcp-cherry-pick-bot[bot]
c508244cf8 fix: deeplinks API checking wrong permissions (#13664) (#14518)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2023-07-14 16:04:45 -04:00
Haitao Li
f3d159f2a8 fix: Update bitbucket.org rsa ssh key (cherry-pick #14392) (#14408)
The key change announcement at https://bitbucket.org/blog/ssh-host-key-changes

Signed-off-by: Haitao Li <hli@atlassian.com>
2023-07-11 10:48:51 -04:00
gcp-cherry-pick-bot[bot]
690524e93c docs: managedFieldsManagers example in docs needs double-quotes (#14324) (#14373)
* is a Yaml special character and must be quoted, otherwise ArgoCD fails to parse and shows an error.

Signed-off-by: Paul Martin <paul.martin@gmail.com>
Co-authored-by: Paul Martin <paul.martin@gmail.com>
2023-07-06 13:50:22 -04:00
argo-bot
52497ce0fb Bump version to 2.6.12 2023-07-05 19:29:23 +00:00
argo-bot
ce5de62fc5 Bump version to 2.6.12 2023-07-05 19:29:19 +00:00
Venkata Mutyala
77be41caba feat: upgrade dexIDP from 2.36.0 -> 2.37.0 (#14305) (#14310) (#14321)
* feat: update dexidp image tag from v2.36.0 -> v2.37.0



* chore: adding GlueOps to USERS.md



---------

Signed-off-by: Venkata Mutyala <venkata@venkatamutyala.com>
2023-07-03 12:55:15 -07:00
gcp-cherry-pick-bot[bot]
bba517dda0 docs: Adding explanation for CMP yaml/json generation (must be K8S object) (#9471) (#14295) (#14303)
Signed-off-by: Christian Hernandez <christian@chernand.io>
Co-authored-by: Christian Hernandez <christianh814@users.noreply.github.com>
2023-06-30 19:38:55 -04:00
gcp-cherry-pick-bot[bot]
c53bfedacd docs: Clarify "SSH known host public keys" text (#13537) (#14299)
Add `ssh_keyscan` example usage

Signed-off-by: Daniel Perevalov <daniel.perevalov@gmail.com>
Co-authored-by: Daniel Perevalov <daniel.perevalov@gmail.com>
2023-06-30 19:35:23 -04:00
gcp-cherry-pick-bot[bot]
500504849c docs: explicit that ArgoCD hooks replaces the Helm ones (#14283) (#14289)
* docs: explicit that ArgoCD hooks replace the Helm ones

After digging a bit in the code, I've found this comment that confirms
that if we define some ArgoCD hooks the Helm ones are ignored.
425d65e076/pkg/sync/hook/hook.go (L36C2-L36C46)



* docs: add Back Market in the user list



* Update docs/user-guide/helm.md



---------

Signed-off-by: Benoît Sauvère <benoit.sauvere@backmarket.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Benoît Sauvère <benoit@sauve.re>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-06-30 11:39:10 -04:00
jannfis
69c22df5e2 fix: Correctly verify signatures when targetRevision is a branch name (#14214) (#14238)
* fix: Correctly verify signatures when targetRevision is a branch name



* Add more e2e tests



* Fix a bug and add unit test



---------

Signed-off-by: jannfis <jann@mistrust.net>
2023-06-29 17:37:05 -04:00
gcp-cherry-pick-bot[bot]
4761611390 fix(appset): handles a race condition where RollingSync does not properly detect a successful sync (#13926) (#14201)
Signed-off-by: wmgroot <wmgroot@gmail.com>
Co-authored-by: wmgroot <wmgroot@gmail.com>
2023-06-25 19:12:38 -04:00
gcp-cherry-pick-bot[bot]
86c831a042 docs: Add documentation on background cascading deletion (#12229) (#14150)
Signed-off-by: toyamagu2021@gmail.com <toyamagu2021@gmail.com>
Co-authored-by: toyamagu <83329336+toyamagu-2021@users.noreply.github.com>
2023-06-20 21:29:44 -04:00
argo-bot
697fd7c9a3 Bump version to 2.6.11 2023-06-20 20:38:26 +00:00
argo-bot
d194eaa6a2 Bump version to 2.6.11 2023-06-20 20:38:17 +00:00
Michael Crenshaw
b7fedfa497 fix: retain count and order of revisions for multi source apps (#14108) (#14113) (#14136)
* fix: retain order of revisions for multi source apps (#14108)



* fix: retain revision for multi source app with ref-repos



* calculate commitSHA before quitting manifest generation



---------

Signed-off-by: Lukas Wöhrl <lukas.woehrl@plentymarkets.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Lukas Wöhrl <lukas@woehrl.net>
2023-06-20 14:33:48 -04:00
argo-bot
34094a2d04 Bump version to 2.6.10 2023-06-16 14:24:19 +00:00
argo-bot
df200b044b Bump version to 2.6.10 2023-06-16 14:24:14 +00:00
Michael Crenshaw
7449f26e8b fix(cmp): discover plugins relative to app path (#13940) (#13946) (#14085)
* fix(cmp): discover plugins relative to app path (#13940)



* securejoin



* intuitive constant names



* comments



* add missing import



---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-06-16 09:43:57 -04:00
gcp-cherry-pick-bot[bot]
9ce19c6c80 fix: Multi source apps resolve revision in .status field (#14081) (#14087)
Signed-off-by: Jorge Turrado <jorge.turrado@scrm.lidl>
Co-authored-by: Jorge Turrado Ferrero <Jorge_turrado@hotmail.es>
2023-06-15 17:44:15 -04:00
gcp-cherry-pick-bot[bot]
9aaade6981 fix(cli): support application in any namespace with argocd app diff (#13978) (#13980) (#14062)
Closes https://github.com/argoproj/argo-cd/issues/13978.

Signed-off-by: mugioka <okamugi0722@gmail.com>
Co-authored-by: mugi <62197019+mugioka@users.noreply.github.com>
2023-06-14 15:21:51 -04:00
gcp-cherry-pick-bot[bot]
9adc9159e6 docs: add golang upgrade note for 2.5 (#14048) (#14058)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-06-14 15:08:08 -04:00
gcp-cherry-pick-bot[bot]
75eeb6dbb6 docs: add documentation for child elements of path (#14044) (#14055)
* docs: add documentation for child elements of path

When using go templating, the parent `{{ path }}` becomes `{{ .path.path }}, however, the other values are not at `{{ .path.path.* }}`, but at `{{ .path.* }}`.

This documentation update seeks to make this easier to understand since we just ran into this.



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




---------

Signed-off-by: Morre <mmeyer@anaconda.com>
Signed-off-by: Morre <morre@mor.re>
Co-authored-by: Morre <morre@mor.re>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-06-14 15:07:10 -04:00
gcp-cherry-pick-bot[bot]
89051845c1 chore(deps): upgrade haproxy to 2.6.14-alpine (#14018) (#14052)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-06-14 15:06:09 -04:00
Michael Crenshaw
c145657347 chore(deps): upgrade go to 1.19.10 (#13943)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-06-14 11:38:09 -04:00
gcp-cherry-pick-bot[bot]
0ee904746a fix(ui): Fix Patch and Get Manifests (#13949) (#13953)
Signed-off-by: Geoffrey Muselli <geoffrey.muselli@gmail.com>
Co-authored-by: Geoffrey MUSELLI <geoffrey.muselli@gmail.com>
2023-06-08 08:12:07 -04:00
argo-bot
3f1e7d401e Bump version to 2.6.9 2023-06-05 18:44:10 +00:00
argo-bot
85838126fc Bump version to 2.6.9 2023-06-05 18:44:04 +00:00
gcp-cherry-pick-bot[bot]
822788f0f9 fix(ui): Patch Resource missing appNamespace (#13839) (#13841)
Signed-off-by: Geoffrey Muselli <geoffrey.muselli@gmail.com>
Co-authored-by: Geoffrey MUSELLI <geoffrey.muselli@gmail.com>
2023-06-01 09:58:09 -04:00
Lewis Marsden-Lambert
8bc460fe28 fix(appset): Post selector with Go templates in ApplicationSet (cherry-pick #13584) (#13823)
* fix(appset): Post selector with Go templates in ApplicationSet (#13584)

* fixes #12524

Signed-off-by: Lewis Marsden-Lambert <lewis.lambert@zserve.co.uk>

* refactor keepOnlyStringLabels function into more generic map flattening function

Signed-off-by: Lewis Marsden-Lambert <lewis.lambert@zserve.co.uk>

* updated USERS.md

Signed-off-by: Lewis Marsden-Lambert <lewis.marsden-lambert@smartpension.co.uk>

* use flatten library to replace custom flatten function

Signed-off-by: Lewis Marsden-Lambert <lewis.marsden-lambert@smartpension.co.uk>

---------

Signed-off-by: Lewis Marsden-Lambert <lewis.lambert@zserve.co.uk>
Signed-off-by: Lewis Marsden-Lambert <lewis.marsden-lambert@smartpension.co.uk>

* fixed tests

Signed-off-by: Lewis Marsden-Lambert <lewis.lambert@zserve.co.uk>

---------

Signed-off-by: Lewis Marsden-Lambert <lewis.lambert@zserve.co.uk>
Signed-off-by: Lewis Marsden-Lambert <lewis.marsden-lambert@smartpension.co.uk>
2023-06-01 09:56:24 -04:00
Brian Fox
814b2367c8 fix: ensure repositories are correctly marked with inherited creds in CLI output (#13428) (#13809)
* tests: ensure `InheritedCreds` is propagated via repo API endpoints



* fix: ensure `InheritedCreds` is propagated via repo API endpoints



* tests: add e2e test for `argocd repo get` with inherited credentials



* fix(cli): prioritise value of `InheritedCreds` over `HasCredentials()`

Since the API does not return sensitive information `HasCredentials()` will return false for all scenarios except when username/password is used as credentials. Given the current logic this means that the code will never even check `InheritedCreds` resulting in an output of `false` for `CREDS` column (in the case of inherited credentials).

Note: There remains a bug in this code in that any repo that has explicit (sensitive) credentials (e.g. SSH private key) will still be displayed as `CREDS = false`.


---------

Signed-off-by: OneMatchFox <878612+onematchfox@users.noreply.github.com>
2023-05-29 10:23:55 -04:00
Tete17
92ced542b8 fix(ui): Stop using the deprecated url format for gitlab instances (#13687) (#13796)
* fix: Stop using the deprecated url format for gitlab instances

The legacy URLs format has been deprecated since february 2023 and
now gitlab is make these urls invalid.

Ref: https://docs.gitlab.com/ee/update/deprecations.html#legacy-urls-replaced-or-removed


* docs: Add Urbantz to the list of organizations using argo-cd



---------



(cherry picked from commit 5662367474)

Signed-off-by: Miguel Sacristán Izcue <miguel_tete17@hotmail.com>
2023-05-28 16:17:15 -04:00
gcp-cherry-pick-bot[bot]
0d579a0ec1 docs: update openunison authChainName (#13531) (#13794)
Signed-off-by: Samir-NT <133138781+Samir-NT@users.noreply.github.com>
Co-authored-by: Samir-NT <133138781+Samir-NT@users.noreply.github.com>
2023-05-28 15:50:57 -04:00
gcp-cherry-pick-bot[bot]
9c685cf021 docs: Update disaster_recovery.md to reflect quay.io as docker container registry (#13520) (#13791)
ArgoCD docker images are being used from `quay.io` registry.
Updated document to reflect that in the `bash` commands.

Signed-off-by: Divyang Patel <divyang.jp@gmail.com>
Co-authored-by: Divyang Patel <divyang.jp@gmail.com>
2023-05-28 15:48:18 -04:00
Blake Pettersson
37e24408a8 test: remove testmatchvaluesgotemplate (#13786)
This test came with the previous cherry-pick, but should not be present
for 2.5 - 2.7.

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
2023-05-28 08:23:37 -04:00
gcp-cherry-pick-bot[bot]
fdcbfade20 docs: Fixed titles in app deletion doc (#13469) (#13783)
Signed-off-by: michaelkot97 <michael.kot97@gmail.com>
Co-authored-by: Michael Kotelnikov <36506417+michaelkotelnikov@users.noreply.github.com>
2023-05-27 21:47:11 -04:00
gcp-cherry-pick-bot[bot]
cf02b10d01 fix: Regression in signature verification for git tags (#12797) (#13112)
Signed-off-by: jannfis <jann@mistrust.net>
Co-authored-by: jannfis <jann@mistrust.net>
2023-05-27 21:25:06 -04:00
gcp-cherry-pick-bot[bot]
46dc70b6c6 docs: add helm values declarative syntax (#13661) (#13779)
The Helm section of the user guide is missing an example of using `source.helm.values`.

Signed-off-by: Nicholas Morey <nicholas@morey.tech>
Co-authored-by: Nicholas Morey <nicholas@morey.tech>
2023-05-27 20:56:18 -04:00
gcp-cherry-pick-bot[bot]
d7e4ada9af docs: fix incorrect instructions for site documentation (#13209) (#13774)
* fix: incorrect instructions for site documentation



* drop checking external links



---------

Signed-off-by: Regina Scott <rescott@redhat.com>
Co-authored-by: Regina Scott <50851526+reginapizza@users.noreply.github.com>
2023-05-27 16:46:03 -04:00
Blake Pettersson
292e69f97f fix(appset): allow cluster urls to be matched (#13715) (#13771)
* fix: allow cluster urls to be matched

Related to #13646, and after discussion with @crenshaw-dev, it turns
out that matching on cluster urls is not possible. This is due to the
fact that the implementation of `LabelSelectorAsSelector` from
`k8s.io/apimachinery` validates that a label value is no longer than 63
characters, and validates that it's alphanumeric. In order to work
around that, we'll create our own implementation of
`LabelSelectorAsSelector`.

This implementation has been copied verbatim, with the difference that
in `isValidLabelValue`, we first check if the label value is a valid
url. If it is not, we proceed with the label checks as with the
original implementation.

Apart from that, the only other differences are making as much as
possible to be package-private; the intent is to only make `Matches`
and `LabelSelectorAsSelector` available from outside the package.



* chore: drop all label value restrictions

We want to be more flexible in what we accept in post-selectors, mainly
that we want to allow other values than only server urls. For this, we
will drop all restrictions that a typical "label value" would typically
have.



---------

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
2023-05-27 16:08:41 -04:00
gcp-cherry-pick-bot[bot]
618bd14c09 fix: argocd app sync/wait falsely failed with completed with phase: Running (#13637) (#13673)
Signed-off-by: Jesse Suen <jesse@akuity.io>
Co-authored-by: Jesse Suen <jessesuen@users.noreply.github.com>
2023-05-27 12:32:21 -04:00
gcp-cherry-pick-bot[bot]
a047d72688 docs: correct indentation for gke ingress (#13680) (#13762)
Signed-off-by: Carlos Sanchez <carlos@apache.org>
Co-authored-by: Carlos Sanchez <carlos@apache.org>
2023-05-27 12:31:26 -04:00
gcp-cherry-pick-bot[bot]
472d4eb16d fix: prevent concurrent processing if kustomize commonAnnotations exist (#13697) (#13703)
Signed-off-by: yilmazo <onuryilmaz93@yandex.com>
Co-authored-by: Onur Yilmaz <onuryilmaz93@yandex.com>
2023-05-27 12:05:49 -04:00
argo-bot
674cf8d6e2 Bump version to 2.6.8 2023-05-25 15:43:11 +00:00
argo-bot
c1dba1c764 Bump version to 2.6.8 2023-05-25 15:43:05 +00:00
Michael Crenshaw
d383379b0c Revert "Bump version to 2.6.8 (#13725)" (#13728)
This reverts commit adbb1f50c8.

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-05-24 11:18:21 -04:00
github-actions[bot]
adbb1f50c8 Bump version to 2.6.8 (#13725)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: crenshaw-dev <crenshaw-dev@users.noreply.github.com>
2023-05-24 10:39:08 -04:00
Alexander Matyushentsev
419165a296 fix: CMPv2 does not allow symlinks to adjacent files in same git repo. Fixes #13342 (#13360) (#13724)
fix: CMPv2 does not allow symlinks to adjacent files in same git repo. Fixes #13342 (#13360)

Signed-off-by: Jiacheng Xu <xjcmaxwellcjx@gmail.com>
Co-authored-by: Jiacheng Xu <xjcmaxwellcjx@gmail.com>
2023-05-24 10:23:38 -04:00
Michael Crenshaw
19f5d43235 Revert "Bump version to 2.6.8 (#13718)" (#13721)
This reverts commit 2a433f168a.

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-05-24 10:23:28 -04:00
github-actions[bot]
2a433f168a Bump version to 2.6.8 (#13718)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: crenshaw-dev <crenshaw-dev@users.noreply.github.com>
2023-05-24 09:36:12 -04:00
gcp-cherry-pick-bot[bot]
494e9eeb51 fix(appset): handle templating of raw JSON fields (#12947) (#12949) (#13653)
* fix(appset): handle templating of raw JSON fields (#12947)



* revert unnecessary changes



---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-05-18 19:57:58 -04:00
Justin Marquis
cc75f42a10 chore: upgrade redis to 7.0.11 to avoid CVE-2023-0464(release-2.6) (#13559)
Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
2023-05-18 18:22:36 -04:00
gcp-cherry-pick-bot[bot]
876ff3035e fix: avoid acquiring lock on two mutexes at the same time to prevent deadlock (#13636) (#13649)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2023-05-18 13:05:54 -07:00
gcp-cherry-pick-bot[bot]
4d63d279d6 docs: Update kustomize resource to correct path (#13196) (#13631)
This commit updates the kustomize section to include the correct path.  Without the `\base` at the end of the path kustomize errors out trying to find a `kustomization.yaml` since there isn't one in the `ha` directory.

Signed-off-by: Chris Wiggins <5607419+cwiggs@users.noreply.github.com>
Co-authored-by: Chris Wiggins <5607419+cwiggs@users.noreply.github.com>
2023-05-18 09:12:55 -04:00
Jaideep Rao
62ae79ab5e fix: consume cluster cache deadlock fix from gitops-engine (#13613)
Signed-off-by: Jaideep Rao <jaideep.r97@gmail.com>
2023-05-17 13:39:55 -04:00
gcp-cherry-pick-bot[bot]
6f5eaff91f fix: surface errors when compressing files (#13491) (#13493)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-05-09 12:37:02 -04:00
gcp-cherry-pick-bot[bot]
c8b4707c55 docs: fix typo (#12960) (#13437)
Signed-off-by: mikutas <23391543+mikutas@users.noreply.github.com>
Co-authored-by: Takumi Sue <23391543+mikutas@users.noreply.github.com>
2023-05-04 18:21:17 -04:00
gcp-cherry-pick-bot[bot]
09143f26a4 chore: upgrade haproxy to 2.6.12 to avoid CVE-2023-0464 (#13388) (#13400)
Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
Co-authored-by: Justin Marquis <34fathombelow@protonmail.com>
2023-05-01 16:43:28 -04:00
gcp-cherry-pick-bot[bot]
f08375665b docs: Application Info field documentation (#10814) (#13351) (#13376)
* add Application info field documentation



* Extra Application info docs



* Added info field documentation



* Add space to comment




* docs: Add extra_info.md to table of contents



---------

Signed-off-by: Hapshanko <112761282+Hapshanko@users.noreply.github.com>
Co-authored-by: Hapshanko <112761282+Hapshanko@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-05-01 15:42:41 -04:00
gcp-cherry-pick-bot[bot]
0901195cd9 docs: s/No supported/Not supported (#13189) (#13254)
Signed-off-by: Vincent Verleye <124772102+smals-vinve@users.noreply.github.com>
Co-authored-by: Vincent Verleye <124772102+smals-vinve@users.noreply.github.com>
2023-04-16 01:34:23 -04:00
gcp-cherry-pick-bot[bot]
463e62ff80 docs: Fix wrong link to non existing page for applicationset reference (#13207) (#13248)
Signed-off-by: TheDatabaseMe <philip.haberkern@googlemail.com>
Co-authored-by: Philip Haberkern <59010269+thedatabaseme@users.noreply.github.com>
2023-04-15 14:33:43 -04:00
Alexander Matyushentsev
71e523e776 fix: --file usage is broken for 'argocd proj create' command (#13130)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2023-04-07 09:52:13 -07:00
gcp-cherry-pick-bot[bot]
61d0ef7614 fix(cli): add redis-compress flag to argocd admin dashboard command (#13055) (#13056) (#13115)
* add `redis-compress` flag to `argocd admin dashboard` command

Previously, gzip compression was disabled and not configurable,
which made it impossible to work with gzipped Redis cache.
This commit adds support for gzip compression to the ArgoCD admin dashboard.



* update dashboard docs for --redis-compress flag



* add support for REDIS_COMRESSION env in cli admin dashboard



* update flag description




* update dashboard docs



---------

Signed-off-by: Pavel Aborilov <aborilov@gmail.com>
Signed-off-by: Pavel <aborilov@gmail.com>
Co-authored-by: Pavel <aborilov@gmail.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-04-06 16:08:37 -07:00
Michael Crenshaw
d54d931f3e fix(security): upgrade go to 1.19 (#13104)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-04-04 16:50:06 -04:00
gcp-cherry-pick-bot[bot]
0c31efd158 chore: disable codeql workflow on cherry-pick branches (#12893) (#12900)
Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
Co-authored-by: Justin Marquis <34fathombelow@protonmail.com>
2023-04-04 16:45:09 -04:00
gcp-cherry-pick-bot[bot]
a325c35320 docs: fix broken version selector (#13102) (#13106)
Signed-off-by: Harold Cheng <niuchangcun@gmail.com>
Co-authored-by: cjc7373 <niuchangcun@gmail.com>
2023-04-04 16:23:47 -04:00
gcp-cherry-pick-bot[bot]
9d56d4fa26 fix: log error when failing to get git client (#12876) (#12997)
* fix: log error when failing to get git client



* Update reposerver/repository/repository.go




* Update reposerver/repository/repository.go




---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: jannfis <jann@mistrust.net>
2023-03-24 11:42:22 -04:00
Steve Ramage
707342d707 fix: make webhook handler work in all configured application namespaces (#11867) (#12386)
Signed-off-by: Steve Ramage <commits@sjrx.net>
Co-authored-by: Steve Ramage <commits@sjrx.net>
2023-03-24 11:29:35 -04:00
Nobuo Takizawa
de600c0222 chore: Bump dex from v2.35.3 to v2.36.0 (#12933)
Signed-off-by: nobuyo <longzechangsheng@gmail.com>
2023-03-24 09:54:57 -04:00
gcp-cherry-pick-bot[bot]
937e88a164 fix: trigger ApplicationSet reconciliation for clusters matching cluster generators in matrix or merge generators (#12543) (#12991)
Signed-off-by: alexandre.vilain <alexandre.vilain@corp.ovh.com>
Co-authored-by: Alexandre Vilain <alexandrevilain@users.noreply.github.com>
2023-03-24 09:51:30 -04:00
gcp-cherry-pick-bot[bot]
4f3e5080a5 fix: pass env when getting param announcement (#11812) (#11815) (#12966)
* fix: pass env when getting param announcement (#11812)



* use same method as other methods



* better tests



* make sure env var tests are meaningful



---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-23 14:03:00 -04:00
gcp-cherry-pick-bot[bot]
cf74364052 chore: fix lint (#12972) (#12977)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-23 13:27:35 -04:00
argo-bot
5bcd846fa1 Bump version to 2.6.7 2023-03-23 14:41:44 +00:00
argo-bot
7af7aaa08f Bump version to 2.6.7 2023-03-23 14:41:38 +00:00
Michael Crenshaw
ccb64f1c7e Merge pull request from GHSA-2q5c-qw9c-fmvq
* fix: prevent app enumeration

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

fix tests

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

better comments

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

tests for streaming API calls

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

fix logging

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

logs

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

warn

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

fix reversed arg order

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

* more tests, fix incorrect param use

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

similar requests

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

* fix merge issue

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

* fix CLI to understand permission denied is not a fatal error

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

* fix test to expect permission denied instead of validation error

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

* upgrade notes

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

---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-23 09:22:05 -04:00
argo-bot
6d4de2ec5d Bump version to 2.6.6 2023-03-16 22:12:55 +00:00
argo-bot
bc13533afa Bump version to 2.6.6 2023-03-16 22:12:45 +00:00
dependabot[bot]
3260ecc729 chore(deps): bump actions/setup-go from 3.5.0 to 4.0.0 (#12888)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3.5.0 to 4.0.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](6edd4406fa...4d34df0c23)

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-16 12:53:23 -04:00
Michael Crenshaw
d3f81decf3 docs: fix version numbers in upgrade notes (#12896)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-16 12:50:41 -04:00
dependabot[bot]
25823b88d9 chore(deps): bump actions/checkout from 3.3.0 to 3.4.0 (#12889)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](ac59398561...24cb908017)

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

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-16 10:48:55 -04:00
jannfis
56a8ce5ff2 build: Enable CI checks on PRs to release branches (#12887)
Signed-off-by: jannfis <jann@mistrust.net>
2023-03-16 09:50:27 -04:00
gcp-cherry-pick-bot[bot]
153bf967e9 test: wait longer after repo server restarted to avoid errors on s390x (#12839) (#12886)
Signed-off-by: Sam Ding <samding@ca.ibm.com>
Co-authored-by: Sam Ding <samding@ca.ibm.com>
2023-03-16 09:32:59 -04:00
gcp-cherry-pick-bot[bot]
2c10c033db fix(appset): git files generator in matrix generator produces no params (#12881) (#12882)
* fix(appset): git files generator in matrix generator produces no params



* upgrade notes



* fix lint



---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-16 09:23:55 -04:00
gcp-cherry-pick-bot[bot]
e883e7498f fix: log plugin commands in a better format (#12260) (#12875)
* fix: log plugin commands in a better format



* comments



---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-15 09:49:03 -04:00
gcp-cherry-pick-bot[bot]
0c3c7e2fa9 docs: cleanup HA operator manual (#10409) (#12867)
Signed-off-by: Prasad Katti <prasadmkatti@gmail.com>
Co-authored-by: Prasad Katti <prasadmkatti@gmail.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-15 09:27:40 -04:00
gcp-cherry-pick-bot[bot]
de63eb4e52 docs: fix list formatting in keycloak.md (#11061) (#12864)
Signed-off-by: Jack Henschel <jackdev@mailbox.org>
Co-authored-by: Jack Henschel <jackdev@mailbox.org>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-15 09:26:54 -04:00
Michael Crenshaw
a119a5cc93 fix: support 'project' filter field for backwards-compatibility (#12594)
* fix: support 'project' filter field for backwards-compatibility

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

* fix codegen

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

* add upgrade notes

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

* fix upgrade notes

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

* tests

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

---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-14 17:11:25 -04:00
gcp-cherry-pick-bot[bot]
dc744bb21d docs: Post Selector moved to Generators section (#11109) (#12858)
Co-authored-by: Guðmundur Kristinn Ögmundsson <gummikr@icelandair.is>
2023-03-14 14:41:53 -04:00
dependabot[bot]
4d5f9bdb5d chore(deps): bump actions/cache from 3.2.6 to 3.3.1 (#12845)
Bumps [actions/cache](https://github.com/actions/cache) from 3.2.6 to 3.3.1.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](69d9d449ac...88522ab9f3)

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-14 13:56:43 -04:00
argo-bot
60104aca6f Bump version to 2.6.5 2023-03-14 14:06:46 +00:00
argo-bot
3ea15f05f2 Bump version to 2.6.5 2023-03-14 14:06:37 +00:00
Michael Crenshaw
d557447214 chore: upgrade https lib to avoid CVE-2022-41723
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-13 09:51:12 -04:00
gcp-cherry-pick-bot[bot]
67379d881b fix: ignore gitlab projects w/o repository (#12819) (#12820) (#12827)
* fix: ignore gitlab projects w/o repository (#12819)



* chore: Add Redpill Linpro to USERS.md



---------

Signed-off-by: Pip Oomen <pepijn@redpill-linpro.com>
Co-authored-by: Pip Oomen <oomen@piprograms.com>
2023-03-11 20:02:49 -05:00
gcp-cherry-pick-bot[bot]
7d335432cd docs: Provide example RBAC for API server in apps-in-any-namespace (#12341) (#12824)
Signed-off-by: jannfis <jann@mistrust.net>
Co-authored-by: jannfis <jann@mistrust.net>
2023-03-11 11:17:43 -05:00
gcp-cherry-pick-bot[bot]
f7b6b82a04 docs: Fix Jenkins guide link in understand_the_basics.md (#12814) (#12818)
Signed-off-by: Arkadiusz Podkowa <55452766+czuhajster@users.noreply.github.com>
Co-authored-by: Arkadiusz Podkowa <55452766+czuhajster@users.noreply.github.com>
2023-03-10 16:36:52 -05:00
gcp-cherry-pick-bot[bot]
e81b22bc61 fix: use field-wise templating for child matrix generators (#11661) (#12287) (#12771)
* fix: use field-wise templating for child matrix generators (#11661)



* test shouldn't use go template



* Update applicationset/utils/utils.go



---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-08 13:10:30 -05:00
gcp-cherry-pick-bot[bot]
65d43364ec fix: Fix the applicationset kind typo (#12690) (#12767)
Signed-off-by: Shaw Ho <tossmilestone@gmail.com>
Co-authored-by: Shaw Ho <tossmilestone@gmail.com>
2023-03-08 09:43:51 -05:00
argo-bot
7be094f38d Bump version to 2.6.4 2023-03-07 22:35:05 +00:00
argo-bot
db2869c866 Bump version to 2.6.4 2023-03-07 22:35:00 +00:00
gcp-cherry-pick-bot[bot]
2b6d55bfe5 fix: typo in doc link (#12744) (#12760)
Signed-off-by: Noah Krause <krausenoah@gmail.com>
Co-authored-by: Noah Krause <krausenoah@gmail.com>
2023-03-07 16:40:20 -05:00
gcp-cherry-pick-bot[bot]
e81ddb0855 fix: Validate chat button url only when chatUrl is set (#12655) (#12749) (#12757)
* Validate chat button url only when chatUrl is set



* Add Info Support to argocd USERS.md



* Fix linter error



* Fix linter error



---------

Signed-off-by: Rouke Broersma <rouke.broersma@infosupport.com>
Co-authored-by: Rouke Broersma <rouke.broersma@infosupport.com>
2023-03-07 14:38:02 -05:00
gcp-cherry-pick-bot[bot]
8dcdbb588d fix: suppress Kubernetes API deprecation warnings from application controller (#12067) (#12742)
Completely suppress warning logs only for log levels that are less than Debug.

Signed-off-by: toVersus <toversus2357@gmail.com>
Co-authored-by: Tsubasa Nagasawa <toversus2357@gmail.com>
2023-03-06 16:50:56 -05:00
gcp-cherry-pick-bot[bot]
1e7aab19aa fix: Use CredsStore for GoogleCloudCreds (#12391) (#12741)
git-ask-pass.sh is no longer supported for credentials

Signed-off-by: David Becher <becher.david@googlemail.com>
Co-authored-by: david-becher <becher.david@googlemail.com>
2023-03-06 16:45:23 -05:00
gcp-cherry-pick-bot[bot]
ec6e05afca docs: add namespace to initial-password command (#12718) (#12737)
Added " -n argocd " to avoid unexpected error.

Signed-off-by: Devarsh <devarshshah2608@gmail.com>
Co-authored-by: Devarsh <devarshshah2608@gmail.com>
2023-03-06 16:41:09 -05:00
gcp-cherry-pick-bot[bot]
09ea76364c docs: Update kustomization example (#12555) (#12738)
...to align with documented usage of kustomize.

As it was, this example stops working with Kustomize v5

Signed-off-by: Jonas Bergler <jonas@bergler.name>
Co-authored-by: Jonas Bergler <jonas@bergler.name>
2023-03-06 16:40:29 -05:00
dependabot[bot]
b795fcad3d chore(deps): bump actions/cache from 3.2.5 to 3.2.6 (#12567)
Bumps [actions/cache](https://github.com/actions/cache) from 3.2.5 to 3.2.6.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](6998d139dd...69d9d449ac)

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-06 16:36:37 -05:00
dependabot[bot]
896b143866 chore(deps): bump sigstore/cosign-installer from 2.8.1 to 3.0.1 (#12689)
Bumps [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) from 2.8.1 to 3.0.1.
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](9becc61764...c3667d9942)

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
---
updated-dependencies:
- dependency-name: sigstore/cosign-installer
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-06 16:33:40 -05:00
gcp-cherry-pick-bot[bot]
10051833a5 docs: unset finalizer before deleting an app non-cascadingly (#10949) (#12733)
Signed-off-by: Bo Huang <beyondbill@users.noreply.github.com>
Co-authored-by: Bo Huang <beyondbill@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-06 14:53:04 -05:00
gcp-cherry-pick-bot[bot]
705ca3c95a docs: 2.6 addendum for plugin.name (#12701) (#12704)
* 2.6 addendum for plugin.name



* Clearer doc on plugin.name

---------

Signed-off-by: Raymond Wong <61470342+rwong2888@users.noreply.github.com>
Co-authored-by: Raymond Wong <61470342+rwong2888@users.noreply.github.com>
2023-03-06 12:39:57 -05:00
gcp-cherry-pick-bot[bot]
fca7f58a93 chore: Add unit tests for the shared health resource feature and fix docs (#12715) (#12720) (#12731)
* Dummy action in



* Dummy action in



* happy happy joy joy



* will the tests fail?



* happy happy joy joy



* lua tests with relative path



* bye bye custom action



* placatin custom actions tests



* added tests and fixed docs



* added tests and fixed docs



* Update docs/operator-manual/health.md




---------

Signed-off-by: reggie <reginakagan@gmail.com>
Signed-off-by: reggie-k <reginakagan@gmail.com>
Co-authored-by: reggie-k <reginakagan@gmail.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-06 12:39:19 -05:00
gcp-cherry-pick-bot[bot]
85d1c0fac7 fix: ensure certificate gets updated on reload (#12076) (#12696)
* fix: ensure certificate gets updated on reload

Fixes #10707. `GetCertificate` ensures that the most current version of
 `a.settings.Certificate` is used. It's still a bit of a mystery to me
 as to why the reloading of the server does not work for this, since it
 should fulfill the same function.



* fix: remove break from cert changes

With 3553ef8, there's no longer any need to break out of the loop. The
webhook reloading logic needs another look (since it likely no longer
works), but can be handled in another PR.



---------

Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2023-03-02 09:27:45 -05:00
gcp-cherry-pick-bot[bot]
bb7ec0ff32 docs: link directly to HA manifests (#11970) (#12682)
This updates the manifest link directly to the High Availability header in the manifest readme. I chose this over linking to the `ha` folder since it explains the options and links to them.

Signed-off-by: Nicholas Morey <nicholas@morey.tech>
Co-authored-by: Nicholas Morey <nicholas@morey.tech>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-03-01 16:59:04 -05:00
Justin Marquis
57f6703d08 chore: upgrade redis to 7.0.8 to avoid several CVEs (#12627)
Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
2023-02-28 09:26:34 -05:00
gcp-cherry-pick-bot[bot]
f016977b5d chore: upgrade haproxy to 2.6.9 to avoid multiple CVEs (#12628) (#12658)
Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
Co-authored-by: Justin Marquis <34fathombelow@protonmail.com>
2023-02-28 09:25:29 -05:00
argo-bot
e05298b9c6 Bump version to 2.6.3 2023-02-27 14:27:28 +00:00
argo-bot
57c30b5e04 Bump version to 2.6.3 2023-02-27 14:27:24 +00:00
gcp-cherry-pick-bot[bot]
8e544cbb97 fix: traverse generator tree when getting requeue time (#12407) (#12612)
* add unit test reproducing




* feat: Begin polishing top bar design (#12327)



* chore: add dist to path to use our kustomize version (#12352)

* chore: add dist to path to use our kustomize version



* correct path



* missed a spot



---------




* fix: when resource does not exist node menu and resource details shou… (#12360)

* fix: when resource does not exist node menu and resource details should still render



* Retrigger CI pipeline



---------




* fix: traverse generator tree when getting requeue time



* fix: traverse generator tree when getting requeue time



* remove duplicate code



* Retrigger CI pipeline



* revert gitignore



* update from code review



---------

Signed-off-by: rumstead <rjumstead@gmail.com>
Signed-off-by: rumstead <37445536+rumstead@users.noreply.github.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: Joshua Helton <jdoghelton@gmail.com>
Co-authored-by: rumstead <37445536+rumstead@users.noreply.github.com>
Co-authored-by: Remington Breeze <remington@breeze.software>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: jphelton <jdoghelton@gmail.com>
2023-02-24 16:31:08 -05:00
gcp-cherry-pick-bot[bot]
a5fb6ffe6b fix: evaluate all possible refresh reasons for multi-source apps (#12379) (#12609)
* fix: evaluate all possible refresh reasons for multi-source apps (#12379)



* remove redundant parentheses



* tests



* don't auto-sync, it makes tests flaky



* auto-sync because sync CLI doesn't work for multi-source apps



* don't require out-of-sync - app may sync quickly



* timeout 60



* fix timeout



---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-02-24 13:39:40 -05:00
Michael Crenshaw
691f20461e docs: add 2.5->2.6 upgrade notes to table of contents (#12319)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-02-17 17:03:26 -05:00
Justin Marquis
7756a816ab chore: use registry.k8s.io instead of k8s.gcr.io (#12362)
Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-02-17 15:13:38 -05:00
Nicholas Morey
fd4c5f694a docs: add multi source app ref in helm section (#12499)
Signed-off-by: Nicholas Morey <nicholas@morey.tech>
2023-02-17 15:04:44 -05:00
dependabot[bot]
f148fa42a1 chore(deps): bump imjasonh/setup-crane from 0.2 to 0.3 (#12504)
Bumps [imjasonh/setup-crane](https://github.com/imjasonh/setup-crane) from 0.2 to 0.3.
- [Release notes](https://github.com/imjasonh/setup-crane/releases)
- [Commits](e82f1b9a80...00c9e93efa)

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
---
updated-dependencies:
- dependency-name: imjasonh/setup-crane
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-17 14:39:52 -05:00
Josh Soref
c3e96be67f docs: FAQ improvements (#12146)
* docs: use more backticks in FAQ

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* docs: add FAQ entry

The order in patch list … doesn't match $setElementOrder list: …

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

---------

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2023-02-17 14:14:48 -05:00
Dmitriy Mann
d17aaf23c9 fix: valid username in webhook URL matching regex (#9055) (#12203)
This commit fixes incorrect regular expression used for URL matching.

Expected behavior: valid user info part is matched => webhook is sent.
Actual behavior: some valid user info is not matched, example: `ssh://user-name@example.com/org/repo` => webhook is not sent.

Context:
 - [RFC 3986 3.2.1 - User Information](https://www.rfc-editor.org/rfc/rfc3986#section-3.2.1)
 - [Username validation regex in shadow Linux package](https://github.com/shadow-maint/shadow/blob/master/libmisc/chkname.c#L36)

Signed-off-by: mdsjip <2284562+mdsjip@users.noreply.github.com>
2023-02-17 14:11:16 -05:00
Steve Ramage
21cdcc124d docs: fix a few typos and grammar mistakes (#12280)
Signed-off-by: Steve Ramage <commits@sjrx.net>
Co-authored-by: Steve Ramage <commits@sjrx.net>
2023-02-17 14:07:07 -05:00
dependabot[bot]
d195568c90 chore(deps): bump docker/setup-buildx-action from 2.4.0 to 2.4.1 (#12308)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2.4.0 to 2.4.1.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](15c905b16b...f03ac48505)

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-17 14:00:25 -05:00
atusy
860503fc07 docs: fix typo (#12389)
Signed-off-by: atusy <30277794+atusy@users.noreply.github.com>
2023-02-17 13:57:26 -05:00
dependabot[bot]
27c6913bfe chore(deps): bump actions/cache from 3.2.4 to 3.2.5 (#12433)
Bumps [actions/cache](https://github.com/actions/cache) from 3.2.4 to 3.2.5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](627f0f41f6...6998d139dd)

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-17 13:52:30 -05:00
Vaibhav Bhembre
9c0ca76d2e fix: setting spec.SyncPolicy crashes 'argocd appset get' output (#12424) (#12425)
Signed-off-by: Vaibhav Bhembre <vaibhav@digitalocean.com>
2023-02-17 13:50:57 -05:00
Wojtek Cichoń
0d0570de53 docs: Updated link to Jenkins and added GitHub Actions link (#12465)
Signed-off-by: Wojtek Cichoń <wojtek.cichon@protonmail.com>
2023-02-17 13:36:26 -05:00
Zadkiel Aharonian
a731a38026 docs: fix typo in health documentation (#12497)
Signed-off-by: Zadkiel Aharonian <hello@zadkiel.fr>
2023-02-17 13:34:23 -05:00
Saumeya Katyal
03d1c052f6 fix(security): add url validation for help chat (#9956) (#10417)
* fix: add url validation for help chat

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

* lint check

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

* lint fix

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

* review comments

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

---------

Signed-off-by: saumeya <saumeyakatyal@gmail.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-02-17 13:19:35 -05:00
Michael Chen
312683216e docs: Clarify cascade delete of resource and finalizer (#11064)
* Clarify cascade delete of resource and finalizer.

The wording of this warning was confusing.

Signed-off-by: Michael Chen <4326639+mcgitty@users.noreply.github.com>

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

Co-authored-by: Nicholas Morey <nicholas@morey.tech>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

---------

Signed-off-by: Michael Chen <4326639+mcgitty@users.noreply.github.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Nicholas Morey <nicholas@morey.tech>
2023-02-17 13:17:47 -05:00
schakrad
4412a770d5 fix: show full event message in pod event view (#12104) (#12267)
* #11602 fix : Object options menu truncated when selected in ApplicationListView.

Signed-off-by: schakradari <saisindhu_chakradari@intuit.com>

* fix for the message to be fully shown under the events section.

Signed-off-by: schakradari <saisindhu_chakradari@intuit.com>

* fixing lint

Signed-off-by: schakradari <saisindhu_chakradari@intuit.com>

* Update application-resource-list.tsx

Signed-off-by: schakrad <58915923+schakrad@users.noreply.github.com>

* fix for  lint error

Signed-off-by: schakradari <saisindhu_chakradari@intuit.com>

---------

Signed-off-by: schakradari <saisindhu_chakradari@intuit.com>
Signed-off-by: schakrad <58915923+schakrad@users.noreply.github.com>
2023-02-17 11:57:52 -05:00
jphelton
7bbedff9da fix: when resource does not exist node menu and resource details shou… (#12360)
* fix: when resource does not exist node menu and resource details should still render

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

* Retrigger CI pipeline

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

---------

Signed-off-by: Joshua Helton <jdoghelton@gmail.com>
2023-02-16 09:06:43 -08:00
argo-bot
6e02f8b232 Bump version to 2.6.2 2023-02-16 14:52:52 +00:00
argo-bot
e2b280c3dd Bump version to 2.6.2 2023-02-16 14:52:45 +00:00
Michael Crenshaw
74726cf11e Merge pull request from GHSA-3jfq-742w-xg8j
fix test name

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-02-16 09:07:57 -05:00
Michael Crenshaw
d4a0c252b8 chore: add dist to path to use our kustomize version (#12352)
* chore: add dist to path to use our kustomize version

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

* correct path

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

* missed a spot

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

---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2023-02-09 12:18:06 -05:00
223 changed files with 6194 additions and 1391 deletions

View File

@@ -9,10 +9,11 @@ on:
pull_request:
branches:
- 'master'
- 'release-*'
env:
# Golang version to use across CI steps
GOLANG_VERSION: '1.18'
GOLANG_VERSION: '1.20.10'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -27,9 +28,9 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Download all Go modules
@@ -45,13 +46,13 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Restore go build cache
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -69,9 +70,9 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Run golangci-lint
@@ -92,11 +93,11 @@ jobs:
- name: Create checkout directory
run: mkdir -p ~/go/src/github.com/argoproj
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
- name: Create symlink in GOPATH
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Install required packages
@@ -116,13 +117,17 @@ jobs:
run: |
echo "/usr/local/bin" >> $GITHUB_PATH
- name: Restore go build cache
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
- name: Install all tools required for building & testing
run: |
make install-test-tools-local
# We install kustomize in the dist directory
- name: Add dist to PATH
run: |
echo "/home/runner/work/argo-cd/argo-cd/dist" >> $GITHUB_PATH
- name: Setup git username and email
run: |
git config --global user.name "John Doe"
@@ -155,11 +160,11 @@ jobs:
- name: Create checkout directory
run: mkdir -p ~/go/src/github.com/argoproj
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
- name: Create symlink in GOPATH
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Install required packages
@@ -179,13 +184,17 @@ jobs:
run: |
echo "/usr/local/bin" >> $GITHUB_PATH
- name: Restore go build cache
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
- name: Install all tools required for building & testing
run: |
make install-test-tools-local
# We install kustomize in the dist directory
- name: Add dist to PATH
run: |
echo "/home/runner/work/argo-cd/argo-cd/dist" >> $GITHUB_PATH
- name: Setup git username and email
run: |
git config --global user.name "John Doe"
@@ -206,9 +215,9 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Create symlink in GOPATH
@@ -232,6 +241,10 @@ jobs:
make install-codegen-tools-local
make install-go-tools-local
working-directory: /home/runner/go/src/github.com/argoproj/argo-cd
# We install kustomize in the dist directory
- name: Add dist to PATH
run: |
echo "/home/runner/work/argo-cd/argo-cd/dist" >> $GITHUB_PATH
- name: Run codegen
run: |
set -x
@@ -250,14 +263,14 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
- name: Setup NodeJS
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
with:
node-version: '12.18.4'
- name: Restore node dependency cache
id: cache-dependencies
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
with:
path: ui/node_modules
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
@@ -287,12 +300,12 @@ jobs:
sonar_secret: ${{ secrets.SONAR_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
with:
fetch-depth: 0
- name: Restore node dependency cache
id: cache-dependencies
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
with:
path: ui/node_modules
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
@@ -366,9 +379,9 @@ jobs:
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: GH actions workaround - Kill XSP4 process
@@ -386,7 +399,7 @@ jobs:
sudo chown runner $HOME/.kube/config
kubectl version
- name: Restore go build cache
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -412,9 +425,9 @@ jobs:
git config --global user.email "john.doe@example.com"
- name: Pull Docker image required for tests
run: |
docker pull ghcr.io/dexidp/dex:v2.35.3
docker pull ghcr.io/dexidp/dex:v2.37.0
docker pull argoproj/argo-cd-ci-builder:v1.0.0
docker pull redis:7.0.7-alpine
docker pull redis:7.0.14-alpine
- name: Create target directory for binaries in the build-process
run: |
mkdir -p dist

View File

@@ -5,6 +5,7 @@ on:
# Secrets aren't available for dependabot on push. https://docs.github.com/en/enterprise-cloud@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/troubleshooting-the-codeql-workflow#error-403-resource-not-accessible-by-integration-when-using-dependabot
branches-ignore:
- 'dependabot/**'
- 'cherry-pick-*'
pull_request:
schedule:
- cron: '0 19 * * 0'
@@ -29,7 +30,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL

View File

@@ -10,7 +10,7 @@ on:
types: [ labeled, unlabeled, opened, synchronize, reopened ]
env:
GOLANG_VERSION: '1.18'
GOLANG_VERSION: '1.20.10'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -29,10 +29,10 @@ jobs:
env:
GOPATH: /home/runner/work/argo-cd/argo-cd
steps:
- uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
- uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
with:
go-version: ${{ env.GOLANG_VERSION }}
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
- uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
with:
path: src/github.com/argoproj/argo-cd
@@ -54,7 +54,7 @@ jobs:
# build
- uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0
- uses: docker/setup-buildx-action@15c905b16b06416d2086efa066dd8e3a35cc7f98 # v2.4.0
- uses: docker/setup-buildx-action@f03ac48505955848960e80bbb68046aa35c7b9e7 # v2.4.1
- run: |
IMAGE_PLATFORMS=linux/amd64
if [[ "${{ github.event_name }}" == "push" || "${{ contains(github.event.pull_request.labels.*.name, 'test-arm-image') }}" == "true" ]]
@@ -69,12 +69,12 @@ jobs:
# sign container images
- name: Install cosign
uses: sigstore/cosign-installer@9becc617647dfa20ae7b1151972e9b3a2c338a2b # v2.8.1
uses: sigstore/cosign-installer@c3667d99424e7e6047999fb6246c0da843953c65 # v3.0.1
with:
cosign-release: 'v1.13.1'
- name: Install crane to get digest of image
uses: imjasonh/setup-crane@e82f1b9a8007d399333baba4d75915558e9fb6a4
uses: imjasonh/setup-crane@00c9e93efa4e1138c9a7a5c594acd6c75a2fbf0c
- name: Get digest of image
run: |

View File

@@ -12,7 +12,7 @@ on:
- "!release-v0*"
env:
GOLANG_VERSION: '1.18'
GOLANG_VERSION: '1.20.10'
permissions:
contents: read
@@ -43,7 +43,7 @@ jobs:
GIT_EMAIL: argoproj@gmail.com
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
@@ -147,7 +147,7 @@ jobs:
echo "RELEASE_NOTES=${RELEASE_NOTES}" >> $GITHUB_ENV
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
with:
go-version: ${{ env.GOLANG_VERSION }}
@@ -177,6 +177,10 @@ jobs:
run: |
set -ue
make install-codegen-tools-local
# We install kustomize in the dist directory
echo "/home/runner/work/argo-cd/argo-cd/dist" >> $GITHUB_PATH
make manifests-local VERSION=${TARGET_VERSION}
git diff
git commit manifests/ -m "Bump version to ${TARGET_VERSION}"
@@ -201,7 +205,7 @@ jobs:
if: ${{ env.DRY_RUN != 'true' }}
- uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0
- uses: docker/setup-buildx-action@15c905b16b06416d2086efa066dd8e3a35cc7f98 # v2.4.0
- uses: docker/setup-buildx-action@f03ac48505955848960e80bbb68046aa35c7b9e7 # v2.4.1
- name: Build and push Docker image for release
run: |
set -ue
@@ -215,12 +219,12 @@ jobs:
if: ${{ env.DRY_RUN != 'true' }}
- name: Install cosign
uses: sigstore/cosign-installer@9becc617647dfa20ae7b1151972e9b3a2c338a2b # v2.8.1
uses: sigstore/cosign-installer@c3667d99424e7e6047999fb6246c0da843953c65 # v3.0.1
with:
cosign-release: 'v1.13.1'
- name: Install crane to get digest of image
uses: imjasonh/setup-crane@e82f1b9a8007d399333baba4d75915558e9fb6a4
uses: imjasonh/setup-crane@00c9e93efa4e1138c9a7a5c594acd6c75a2fbf0c
- name: Get digest of image
run: |
@@ -262,6 +266,14 @@ jobs:
body: ${{ steps.release-notes.outputs.content }}
if: ${{ env.DRY_RUN == 'true' }}
# Based on this suggestion: https://github.com/actions/runner-images/issues/2840#issuecomment-1284059930
- name: Free Up Disk Space
id: free-up-disk-space
run: |
df -h
sudo rm -rf /usr/share/dotnet
df -h
- name: Generate SBOM (spdx)
id: spdx-builder
env:

View File

@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Build reports

View File

@@ -4,7 +4,7 @@ ARG BASE_IMAGE=docker.io/library/ubuntu:22.04
# Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image
# Also used as the image in CI jobs so needs all dependencies
####################################################################################################
FROM docker.io/library/golang:1.18 AS builder
FROM docker.io/library/golang:1.20.10@sha256:077ff85b374b23916b4b41835e242e5a3ddad9fc537ea7e980f230431747d245 AS builder
RUN echo 'deb http://deb.debian.org/debian buster-backports main' >> /etc/apt/sources.list
@@ -99,7 +99,7 @@ RUN HOST_ARCH=$TARGETARCH NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OP
####################################################################################################
# Argo CD Build stage which performs the actual build of Argo CD binaries
####################################################################################################
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.18 AS argocd-build
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.20.10@sha256:077ff85b374b23916b4b41835e242e5a3ddad9fc537ea7e980f230431747d245 AS argocd-build
WORKDIR /go/src/github.com/argoproj/argo-cd

View File

@@ -35,9 +35,7 @@ impact on Argo CD before opening an issue at least roughly.
## Supported Versions
We currently support the most recent release (`N`, e.g. `1.8`) and the release
previous to the most recent one (`N-1`, e.g. `1.7`). With the release of
`N+1`, `N-1` drops out of support and `N` becomes `N-1`.
We currently support the last 3 minor versions of Argo CD with security and bug fixes.
We regularly perform patch releases (e.g. `1.8.5` and `1.7.12`) for the
supported versions, which will contain fixes for security vulnerabilities and

View File

@@ -23,6 +23,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Arctiq Inc.](https://www.arctiq.ca)
1. [ARZ Allgemeines Rechenzentrum GmbH](https://www.arz.at/)
1. [Axual B.V.](https://axual.com)
1. [Back Market](https://www.backmarket.com)
1. [Baloise](https://www.baloise.com)
1. [BCDevExchange DevOps Platform](https://bcdevexchange.org/DevOpsPlatform)
1. [Beat](https://thebeat.co/en/)
@@ -89,6 +90,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [gloat](https://gloat.com/)
1. [GLOBIS](https://globis.com)
1. [Glovo](https://www.glovoapp.com)
1. [GlueOps](https://glueops.dev)
1. [GMETRI](https://gmetri.com/)
1. [Gojek](https://www.gojek.io/)
1. [Greenpass](https://www.greenpass.com.br/)
@@ -107,6 +109,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [imaware](https://imaware.health)
1. [Indeed](https://indeed.com)
1. [Index Exchange](https://www.indexexchange.com/)
1. [Info Support](https://www.infosupport.com/)
1. [InsideBoard](https://www.insideboard.com)
1. [Intuit](https://www.intuit.com/)
1. [Joblift](https://joblift.com/)
@@ -172,6 +175,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Patreon](https://www.patreon.com/)
1. [PayPay](https://paypay.ne.jp/)
1. [Peloton Interactive](https://www.onepeloton.com/)
1. [PGS](https://www.pgs.com)
1. [Pigment](https://www.gopigment.com/)
1. [Pipefy](https://www.pipefy.com/)
1. [Pismo](https://pismo.io/)
@@ -187,6 +191,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [RapidAPI](https://www.rapidapi.com/)
1. [Recreation.gov](https://www.recreation.gov/)
1. [Red Hat](https://www.redhat.com/)
1. [Redpill Linpro](https://www.redpill-linpro.com/)
1. [reev.com](https://www.reev.com/)
1. [RightRev](https://rightrev.com/)
1. [Rise](https://www.risecard.eu/)
@@ -200,6 +205,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [SI Analytics](https://si-analytics.ai)
1. [Skit](https://skit.ai/)
1. [Skyscanner](https://www.skyscanner.net/)
1. [Smart Pension](https://www.smartpension.co.uk/)
1. [Smilee.io](https://smilee.io)
1. [Snapp](https://snapp.ir/)
1. [Snyk](https://snyk.io/)
@@ -237,6 +243,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [ungleich.ch](https://ungleich.ch/)
1. [Unifonic Inc](https://www.unifonic.com/)
1. [Universidad Mesoamericana](https://www.umes.edu.gt/)
1. [Urbantz](https://urbantz.com/)
1. [Viaduct](https://www.viaduct.ai/)
1. [Vinted](https://vinted.com/)
1. [Virtuo](https://www.govirtuo.com/)

View File

@@ -1 +1 @@
2.6.1
2.6.15

View File

@@ -1028,7 +1028,12 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
}
if currentAppStatus.Status == "Pending" {
if operationPhaseString == "Succeeded" && app.Status.OperationState.StartedAt.After(currentAppStatus.LastTransitionTime.Time) {
// check for successful syncs started less than 10s before the Application transitioned to Pending
// this covers race conditions where syncs initiated by RollingSync miraculously have a sync time before the transition to Pending state occurred (could be a few seconds)
if operationPhaseString == "Succeeded" && app.Status.OperationState.StartedAt.Add(time.Duration(10)*time.Second).After(currentAppStatus.LastTransitionTime.Time) {
if !app.Status.OperationState.StartedAt.After(currentAppStatus.LastTransitionTime.Time) {
log.Warnf("Application %v was synced less than 10s prior to entering Pending status, we'll assume the AppSet controller triggered this sync and update its status to Progressing", app.Name)
}
log.Infof("Application %v has completed a sync successfully, updating its ApplicationSet status to Progressing", app.Name)
currentAppStatus.LastTransitionTime = &now
currentAppStatus.Status = "Progressing"

View File

@@ -3996,6 +3996,63 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
},
},
},
{
name: "progresses a pending application with a successful sync <1s ago to progressing",
appSet: v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSetSpec{
Strategy: &v1alpha1.ApplicationSetStrategy{
Type: "RollingSync",
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{},
},
},
Status: v1alpha1.ApplicationSetStatus{
ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{
{
Application: "app1",
LastTransitionTime: &metav1.Time{
Time: time.Now(),
},
Message: "",
Status: "Pending",
Step: "1",
},
},
},
},
apps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
},
Status: v1alpha1.ApplicationStatus{
Health: v1alpha1.HealthStatus{
Status: health.HealthStatusDegraded,
},
OperationState: &v1alpha1.OperationState{
Phase: common.OperationSucceeded,
StartedAt: metav1.Time{
Time: time.Now().Add(time.Duration(-1) * time.Second),
},
},
Sync: v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeSynced,
},
},
},
},
expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{
{
Application: "app1",
Message: "Application resource completed a sync successfully, updating status from Pending to Progressing.",
Status: "Progressing",
Step: "1",
},
},
},
{
name: "does not progresses a pending application with an old successful sync to progressing",
appSet: argov1alpha1.ApplicationSet{
@@ -4014,7 +4071,7 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
{
Application: "app1",
LastTransitionTime: &metav1.Time{
Time: time.Now().Add(time.Duration(-1) * time.Minute),
Time: time.Now(),
},
Message: "Application moved to Pending status, watching for the Application resource to start Progressing.",
Status: "Pending",
@@ -4035,7 +4092,7 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
OperationState: &argov1alpha1.OperationState{
Phase: common.OperationSucceeded,
StartedAt: metav1.Time{
Time: time.Now().Add(time.Duration(-2) * time.Minute),
Time: time.Now().Add(time.Duration(-11) * time.Second),
},
},
Sync: argov1alpha1.SyncStatus{

View File

@@ -2,6 +2,7 @@ package controllers
import (
"context"
"fmt"
log "github.com/sirupsen/logrus"
@@ -46,7 +47,6 @@ type addRateLimitingInterface interface {
}
func (h *clusterSecretEventHandler) queueRelatedAppGenerators(q addRateLimitingInterface, object client.Object) {
// Check for label, lookup all ApplicationSets that might match the cluster, queue them all
if object.GetLabels()[generators.ArgoCDSecretTypeLabel] != generators.ArgoCDSecretTypeCluster {
return
@@ -73,6 +73,40 @@ func (h *clusterSecretEventHandler) queueRelatedAppGenerators(q addRateLimitingI
foundClusterGenerator = true
break
}
if generator.Matrix != nil {
ok, err := nestedGeneratorsHaveClusterGenerator(generator.Matrix.Generators)
if err != nil {
h.Log.
WithFields(log.Fields{
"namespace": appSet.GetNamespace(),
"name": appSet.GetName(),
}).
WithError(err).
Error("Unable to check if ApplicationSet matrix generators have cluster generator")
}
if ok {
foundClusterGenerator = true
break
}
}
if generator.Merge != nil {
ok, err := nestedGeneratorsHaveClusterGenerator(generator.Merge.Generators)
if err != nil {
h.Log.
WithFields(log.Fields{
"namespace": appSet.GetNamespace(),
"name": appSet.GetName(),
}).
WithError(err).
Error("Unable to check if ApplicationSet merge generators have cluster generator")
}
if ok {
foundClusterGenerator = true
break
}
}
}
if foundClusterGenerator {
@@ -82,3 +116,42 @@ func (h *clusterSecretEventHandler) queueRelatedAppGenerators(q addRateLimitingI
}
}
}
// nestedGeneratorsHaveClusterGenerator iterate over provided nested generators to check if they have a cluster generator.
func nestedGeneratorsHaveClusterGenerator(generators []argoprojiov1alpha1.ApplicationSetNestedGenerator) (bool, error) {
for _, generator := range generators {
if ok, err := nestedGeneratorHasClusterGenerator(generator); ok || err != nil {
return ok, err
}
}
return false, nil
}
// nestedGeneratorHasClusterGenerator checks if the provided generator has a cluster generator.
func nestedGeneratorHasClusterGenerator(nested argoprojiov1alpha1.ApplicationSetNestedGenerator) (bool, error) {
if nested.Clusters != nil {
return true, nil
}
if nested.Matrix != nil {
nestedMatrix, err := argoprojiov1alpha1.ToNestedMatrixGenerator(nested.Matrix)
if err != nil {
return false, fmt.Errorf("unable to get nested matrix generator: %w", err)
}
if nestedMatrix != nil {
return nestedGeneratorsHaveClusterGenerator(nestedMatrix.ToMatrixGenerator().Generators)
}
}
if nested.Merge != nil {
nestedMerge, err := argoprojiov1alpha1.ToNestedMergeGenerator(nested.Merge)
if err != nil {
return false, fmt.Errorf("unable to get nested merge generator: %w", err)
}
if nestedMerge != nil {
return nestedGeneratorsHaveClusterGenerator(nestedMerge.ToMergeGenerator().Generators)
}
}
return false, nil
}

View File

@@ -6,6 +6,7 @@ import (
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
@@ -163,7 +164,6 @@ func TestClusterEventHandler(t *testing.T) {
{NamespacedName: types.NamespacedName{Namespace: "another-namespace", Name: "my-app-set"}},
},
},
{
name: "non-argo cd secret should not match",
items: []argov1alpha1.ApplicationSet{
@@ -189,6 +189,348 @@ func TestClusterEventHandler(t *testing.T) {
},
expectedRequests: []reconcile.Request{},
},
{
name: "a matrix generator with a cluster generator should produce a request",
items: []argov1alpha1.ApplicationSet{
{
ObjectMeta: v1.ObjectMeta{
Name: "my-app-set",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
{
Matrix: &argov1alpha1.MatrixGenerator{
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
{
Clusters: &argov1alpha1.ClusterGenerator{},
},
},
},
},
},
},
},
},
secret: corev1.Secret{
ObjectMeta: v1.ObjectMeta{
Namespace: "argocd",
Name: "my-secret",
Labels: map[string]string{
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
},
},
},
expectedRequests: []reconcile.Request{{
NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"},
}},
},
{
name: "a matrix generator with non cluster generator should not match",
items: []argov1alpha1.ApplicationSet{
{
ObjectMeta: v1.ObjectMeta{
Name: "my-app-set",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
{
Matrix: &argov1alpha1.MatrixGenerator{
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
{
List: &argov1alpha1.ListGenerator{},
},
},
},
},
},
},
},
},
secret: corev1.Secret{
ObjectMeta: v1.ObjectMeta{
Namespace: "argocd",
Name: "my-secret",
Labels: map[string]string{
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
},
},
},
expectedRequests: []reconcile.Request{},
},
{
name: "a matrix generator with a nested matrix generator containing a cluster generator should produce a request",
items: []argov1alpha1.ApplicationSet{
{
ObjectMeta: v1.ObjectMeta{
Name: "my-app-set",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
{
Matrix: &argov1alpha1.MatrixGenerator{
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
{
Matrix: &apiextensionsv1.JSON{
Raw: []byte(
`{
"generators": [
{
"clusters": {
"selector": {
"matchLabels": {
"argocd.argoproj.io/secret-type": "cluster"
}
}
}
}
]
}`,
),
},
},
},
},
},
},
},
},
},
secret: corev1.Secret{
ObjectMeta: v1.ObjectMeta{
Namespace: "argocd",
Name: "my-secret",
Labels: map[string]string{
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
},
},
},
expectedRequests: []reconcile.Request{{
NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"},
}},
},
{
name: "a matrix generator with a nested matrix generator containing non cluster generator should not match",
items: []argov1alpha1.ApplicationSet{
{
ObjectMeta: v1.ObjectMeta{
Name: "my-app-set",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
{
Matrix: &argov1alpha1.MatrixGenerator{
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
{
Matrix: &apiextensionsv1.JSON{
Raw: []byte(
`{
"generators": [
{
"list": {
"elements": [
"a",
"b"
]
}
}
]
}`,
),
},
},
},
},
},
},
},
},
},
secret: corev1.Secret{
ObjectMeta: v1.ObjectMeta{
Namespace: "argocd",
Name: "my-secret",
Labels: map[string]string{
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
},
},
},
expectedRequests: []reconcile.Request{},
},
{
name: "a merge generator with a cluster generator should produce a request",
items: []argov1alpha1.ApplicationSet{
{
ObjectMeta: v1.ObjectMeta{
Name: "my-app-set",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
{
Merge: &argov1alpha1.MergeGenerator{
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
{
Clusters: &argov1alpha1.ClusterGenerator{},
},
},
},
},
},
},
},
},
secret: corev1.Secret{
ObjectMeta: v1.ObjectMeta{
Namespace: "argocd",
Name: "my-secret",
Labels: map[string]string{
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
},
},
},
expectedRequests: []reconcile.Request{{
NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"},
}},
},
{
name: "a matrix generator with non cluster generator should not match",
items: []argov1alpha1.ApplicationSet{
{
ObjectMeta: v1.ObjectMeta{
Name: "my-app-set",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
{
Merge: &argov1alpha1.MergeGenerator{
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
{
List: &argov1alpha1.ListGenerator{},
},
},
},
},
},
},
},
},
secret: corev1.Secret{
ObjectMeta: v1.ObjectMeta{
Namespace: "argocd",
Name: "my-secret",
Labels: map[string]string{
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
},
},
},
expectedRequests: []reconcile.Request{},
},
{
name: "a merge generator with a nested merge generator containing a cluster generator should produce a request",
items: []argov1alpha1.ApplicationSet{
{
ObjectMeta: v1.ObjectMeta{
Name: "my-app-set",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
{
Merge: &argov1alpha1.MergeGenerator{
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
{
Merge: &apiextensionsv1.JSON{
Raw: []byte(
`{
"generators": [
{
"clusters": {
"selector": {
"matchLabels": {
"argocd.argoproj.io/secret-type": "cluster"
}
}
}
}
]
}`,
),
},
},
},
},
},
},
},
},
},
secret: corev1.Secret{
ObjectMeta: v1.ObjectMeta{
Namespace: "argocd",
Name: "my-secret",
Labels: map[string]string{
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
},
},
},
expectedRequests: []reconcile.Request{{
NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"},
}},
},
{
name: "a merge generator with a nested merge generator containing non cluster generator should not match",
items: []argov1alpha1.ApplicationSet{
{
ObjectMeta: v1.ObjectMeta{
Name: "my-app-set",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
{
Merge: &argov1alpha1.MergeGenerator{
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
{
Merge: &apiextensionsv1.JSON{
Raw: []byte(
`{
"generators": [
{
"list": {
"elements": [
"a",
"b"
]
}
}
]
}`,
),
},
},
},
},
},
},
},
},
},
secret: corev1.Secret{
ObjectMeta: v1.ObjectMeta{
Namespace: "argocd",
Name: "my-secret",
Labels: map[string]string{
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
},
},
},
expectedRequests: []reconcile.Request{},
},
}
for _, test := range tests {

View File

@@ -0,0 +1,179 @@
package controllers
import (
"context"
"testing"
"time"
"github.com/argoproj/argo-cd/v2/applicationset/generators"
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
dynfake "k8s.io/client-go/dynamic/fake"
kubefake "k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/tools/record"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)
func TestRequeueAfter(t *testing.T) {
mockServer := argoCDServiceMock{}
ctx := context.Background()
scheme := runtime.NewScheme()
err := argov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
gvrToListKind := map[schema.GroupVersionResource]string{{
Group: "mallard.io",
Version: "v1",
Resource: "ducks",
}: "DuckList"}
appClientset := kubefake.NewSimpleClientset()
k8sClient := fake.NewClientBuilder().Build()
duckType := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v2quack",
"kind": "Duck",
"metadata": map[string]interface{}{
"name": "mightyduck",
"namespace": "namespace",
"labels": map[string]interface{}{"duck": "all-species"},
},
"status": map[string]interface{}{
"decisions": []interface{}{
map[string]interface{}{
"clusterName": "staging-01",
},
map[string]interface{}{
"clusterName": "production-01",
},
},
},
},
}
fakeDynClient := dynfake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), gvrToListKind, duckType)
terminalGenerators := map[string]generators.Generator{
"List": generators.NewListGenerator(),
"Clusters": generators.NewClusterGenerator(k8sClient, ctx, appClientset, "argocd"),
"Git": generators.NewGitGenerator(mockServer),
"SCMProvider": generators.NewSCMProviderGenerator(fake.NewClientBuilder().WithObjects(&corev1.Secret{}).Build(), generators.SCMAuthProviders{}),
"ClusterDecisionResource": generators.NewDuckTypeGenerator(ctx, fakeDynClient, appClientset, "argocd"),
"PullRequest": generators.NewPullRequestGenerator(k8sClient, generators.SCMAuthProviders{}),
}
nestedGenerators := map[string]generators.Generator{
"List": terminalGenerators["List"],
"Clusters": terminalGenerators["Clusters"],
"Git": terminalGenerators["Git"],
"SCMProvider": terminalGenerators["SCMProvider"],
"ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"],
"PullRequest": terminalGenerators["PullRequest"],
"Matrix": generators.NewMatrixGenerator(terminalGenerators),
"Merge": generators.NewMergeGenerator(terminalGenerators),
}
topLevelGenerators := map[string]generators.Generator{
"List": terminalGenerators["List"],
"Clusters": terminalGenerators["Clusters"],
"Git": terminalGenerators["Git"],
"SCMProvider": terminalGenerators["SCMProvider"],
"ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"],
"PullRequest": terminalGenerators["PullRequest"],
"Matrix": generators.NewMatrixGenerator(nestedGenerators),
"Merge": generators.NewMergeGenerator(nestedGenerators),
}
client := fake.NewClientBuilder().WithScheme(scheme).Build()
r := ApplicationSetReconciler{
Client: client,
Scheme: scheme,
Recorder: record.NewFakeRecorder(0),
Generators: topLevelGenerators,
}
type args struct {
appset *argov1alpha1.ApplicationSet
}
tests := []struct {
name string
args args
want time.Duration
wantErr assert.ErrorAssertionFunc
}{
{name: "Cluster", args: args{appset: &argov1alpha1.ApplicationSet{
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{{Clusters: &argov1alpha1.ClusterGenerator{}}},
},
}}, want: generators.NoRequeueAfter, wantErr: assert.NoError},
{name: "ClusterMergeNested", args: args{&argov1alpha1.ApplicationSet{
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
{Clusters: &argov1alpha1.ClusterGenerator{}},
{Merge: &argov1alpha1.MergeGenerator{
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
{
Clusters: &argov1alpha1.ClusterGenerator{},
Git: &argov1alpha1.GitGenerator{},
},
},
}},
},
},
}}, want: generators.DefaultRequeueAfterSeconds, wantErr: assert.NoError},
{name: "ClusterMatrixNested", args: args{&argov1alpha1.ApplicationSet{
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
{Clusters: &argov1alpha1.ClusterGenerator{}},
{Matrix: &argov1alpha1.MatrixGenerator{
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
{
Clusters: &argov1alpha1.ClusterGenerator{},
Git: &argov1alpha1.GitGenerator{},
},
},
}},
},
},
}}, want: generators.DefaultRequeueAfterSeconds, wantErr: assert.NoError},
{name: "ListGenerator", args: args{appset: &argov1alpha1.ApplicationSet{
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{{List: &argov1alpha1.ListGenerator{}}},
},
}}, want: generators.NoRequeueAfter, wantErr: assert.NoError},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, r.getMinRequeueAfter(tt.args.appset), "getMinRequeueAfter(%v)", tt.args.appset)
})
}
}
type argoCDServiceMock struct {
mock *mock.Mock
}
func (a argoCDServiceMock) GetApps(ctx context.Context, repoURL string, revision string) ([]string, error) {
args := a.mock.Called(ctx, repoURL, revision)
return args.Get(0).([]string), args.Error(1)
}
func (a argoCDServiceMock) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) {
args := a.mock.Called(ctx, repoURL, revision, pattern)
return args.Get(0).(map[string][]byte), args.Error(1)
}
func (a argoCDServiceMock) GetFileContent(ctx context.Context, repoURL string, revision string, path string) ([]byte, error) {
args := a.mock.Called(ctx, repoURL, revision, path)
return args.Get(0).([]byte), args.Error(1)
}
func (a argoCDServiceMock) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) {
args := a.mock.Called(ctx, repoURL, revision)
return args.Get(0).([]string), args.Error(1)
}

View File

@@ -51,6 +51,8 @@ func NewClusterGenerator(c client.Client, ctx context.Context, clientset kuberne
return g
}
// GetRequeueAfter never requeue the cluster generator because the `clusterSecretEventHandler` will requeue the appsets
// when the cluster secrets change
func (g *ClusterGenerator) GetRequeueAfter(appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator) time.Duration {
return NoRequeueAfter
}

View File

@@ -2,12 +2,11 @@ package generators
import (
"fmt"
"encoding/json"
"reflect"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
"github.com/jeremywohl/flatten"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
@@ -25,9 +24,12 @@ type TransformResult struct {
Template argoprojiov1alpha1.ApplicationSetTemplate
}
//Transform a spec generator to list of paramSets and a template
// Transform a spec generator to list of paramSets and a template
func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, allGenerators map[string]Generator, baseTemplate argoprojiov1alpha1.ApplicationSetTemplate, appSet *argoprojiov1alpha1.ApplicationSet, genParams map[string]interface{}) ([]TransformResult, error) {
selector, err := metav1.LabelSelectorAsSelector(requestedGenerator.Selector)
// This is a custom version of the `LabelSelectorAsSelector` that is in k8s.io/apimachinery. This has been copied
// verbatim from that package, with the difference that we do not have any restrictions on label values. This is done
// so that, among other things, we can match on cluster urls.
selector, err := utils.LabelSelectorAsSelector(requestedGenerator.Selector)
if err != nil {
return nil, fmt.Errorf("error parsing label selector: %w", err)
}
@@ -72,8 +74,17 @@ func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, al
}
var filterParams []map[string]interface{}
for _, param := range params {
flatParam, err := flattenParameters(param)
if err != nil {
log.WithError(err).WithField("generator", g).
Error("error flattening params")
if firstError == nil {
firstError = err
}
continue
}
if requestedGenerator.Selector != nil && !selector.Matches(labels.Set(keepOnlyStringValues(param))) {
if requestedGenerator.Selector != nil && !selector.Matches(labels.Set(flatParam)) {
continue
}
filterParams = append(filterParams, param)
@@ -88,18 +99,6 @@ func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, al
return res, firstError
}
func keepOnlyStringValues(in map[string]interface{}) map[string]string {
var out map[string]string = map[string]string{}
for key, value := range in {
if _, ok := value.(string); ok {
out[key] = value.(string)
}
}
return out
}
func GetRelevantGenerators(requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, generators map[string]Generator) []Generator {
var res []Generator
@@ -122,6 +121,20 @@ func GetRelevantGenerators(requestedGenerator *argoprojiov1alpha1.ApplicationSet
return res
}
func flattenParameters(in map[string]interface{}) (map[string]string, error) {
flat, err := flatten.Flatten(in, "", flatten.DotStyle)
if err != nil {
return nil, err
}
out := make(map[string]string, len(flat))
for k, v := range flat {
out[k] = fmt.Sprintf("%v", v)
}
return out, nil
}
func mergeGeneratorTemplate(g Generator, requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetTemplate argoprojiov1alpha1.ApplicationSetTemplate) (argoprojiov1alpha1.ApplicationSetTemplate, error) {
// Make a copy of the value from `GetTemplate()` before merge, rather than copying directly into
// the provided parameter (which will touch the original resource object returned by client-go)
@@ -132,27 +145,15 @@ func mergeGeneratorTemplate(g Generator, requestedGenerator *argoprojiov1alpha1.
return *dest, err
}
// Currently for Matrix Generator. Allows interpolating the matrix's 2nd child generator with values from the 1st child generator
// InterpolateGenerator allows interpolating the matrix's 2nd child generator with values from the 1st child generator
// "params" parameter is an array, where each index corresponds to a generator. Each index contains a map w/ that generator's parameters.
func InterpolateGenerator(requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, params map[string]interface{}, useGoTemplate bool) (argoprojiov1alpha1.ApplicationSetGenerator, error) {
interpolatedGenerator := requestedGenerator.DeepCopy()
tmplBytes, err := json.Marshal(interpolatedGenerator)
if err != nil {
log.WithError(err).WithField("requestedGenerator", interpolatedGenerator).Error("error marshalling requested generator for interpolation")
return *interpolatedGenerator, err
}
render := utils.Render{}
replacedTmplStr, err := render.Replace(string(tmplBytes), params, useGoTemplate)
interpolatedGenerator, err := render.RenderGeneratorParams(requestedGenerator, params, useGoTemplate)
if err != nil {
log.WithError(err).WithField("interpolatedGeneratorString", replacedTmplStr).Error("error interpolating generator with other generator's parameter")
log.WithError(err).WithField("interpolatedGenerator", interpolatedGenerator).Error("error interpolating generator with other generator's parameter")
return *interpolatedGenerator, err
}
err = json.Unmarshal([]byte(replacedTmplStr), interpolatedGenerator)
if err != nil {
log.WithError(err).WithField("requestedGenerator", interpolatedGenerator).Error("error unmarshalling requested generator for interpolation")
return *interpolatedGenerator, err
}
return *interpolatedGenerator, nil
}

View File

@@ -6,9 +6,11 @@ import (
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
testutils "github.com/argoproj/argo-cd/v2/applicationset/utils/test"
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/stretchr/testify/mock"
@@ -92,8 +94,160 @@ func TestMatchValues(t *testing.T) {
}
}
func emptyTemplate() argoprojiov1alpha1.ApplicationSetTemplate {
return argoprojiov1alpha1.ApplicationSetTemplate{
func TestMatchValuesGoTemplate(t *testing.T) {
testCases := []struct {
name string
elements []apiextensionsv1.JSON
selector *metav1.LabelSelector
expected []map[string]interface{}
}{
{
name: "no filter",
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
selector: &metav1.LabelSelector{},
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}},
},
{
name: "nil",
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
selector: nil,
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}},
},
{
name: "values.foo should be foo but is ignore element",
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"values.foo": "foo",
},
},
expected: []map[string]interface{}{},
},
{
name: "values.foo should be bar",
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"values.foo": "bar",
},
},
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url", "values": map[string]interface{}{"foo": "bar"}}},
},
{
name: "values.0 should be bar",
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":["bar"]}`)}},
selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"values.0": "bar",
},
},
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url", "values": []interface{}{"bar"}}},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var listGenerator = NewListGenerator()
var data = map[string]Generator{
"List": listGenerator,
}
applicationSetInfo := argov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
},
Spec: argov1alpha1.ApplicationSetSpec{
GoTemplate: true,
},
}
results, err := Transform(argov1alpha1.ApplicationSetGenerator{
Selector: testCase.selector,
List: &argov1alpha1.ListGenerator{
Elements: testCase.elements,
Template: emptyTemplate(),
}},
data,
emptyTemplate(),
&applicationSetInfo, nil)
assert.NoError(t, err)
assert.ElementsMatch(t, testCase.expected, results[0].Params)
})
}
}
func TestTransForm(t *testing.T) {
testCases := []struct {
name string
selector *metav1.LabelSelector
expected []map[string]interface{}
}{
{
name: "server filter",
selector: &metav1.LabelSelector{
MatchLabels: map[string]string{"server": "https://production-01.example.com"},
},
expected: []map[string]interface{}{{
"metadata.annotations.foo.argoproj.io": "production",
"metadata.labels.argocd.argoproj.io/secret-type": "cluster",
"metadata.labels.environment": "production",
"metadata.labels.org": "bar",
"name": "production_01/west",
"nameNormalized": "production-01-west",
"server": "https://production-01.example.com",
}},
},
{
name: "server filter with long url",
selector: &metav1.LabelSelector{
MatchLabels: map[string]string{"server": "https://some-really-long-url-that-will-exceed-63-characters.com"},
},
expected: []map[string]interface{}{{
"metadata.annotations.foo.argoproj.io": "production",
"metadata.labels.argocd.argoproj.io/secret-type": "cluster",
"metadata.labels.environment": "production",
"metadata.labels.org": "bar",
"name": "some-really-long-server-url",
"nameNormalized": "some-really-long-server-url",
"server": "https://some-really-long-url-that-will-exceed-63-characters.com",
}},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
testGenerators := map[string]Generator{
"Clusters": getMockClusterGenerator(),
}
applicationSetInfo := argov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
},
Spec: argov1alpha1.ApplicationSetSpec{},
}
results, err := Transform(
argov1alpha1.ApplicationSetGenerator{
Selector: testCase.selector,
Clusters: &argov1alpha1.ClusterGenerator{
Selector: metav1.LabelSelector{},
Template: argov1alpha1.ApplicationSetTemplate{},
Values: nil,
}},
testGenerators,
emptyTemplate(),
&applicationSetInfo, nil)
assert.NoError(t, err)
assert.ElementsMatch(t, testCase.expected, results[0].Params)
})
}
}
func emptyTemplate() argov1alpha1.ApplicationSetTemplate {
return argov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
},
@@ -150,8 +304,35 @@ func getMockClusterGenerator() Generator {
},
Type: corev1.SecretType("Opaque"),
},
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "some-really-long-server-url",
Namespace: "namespace",
Labels: map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "production",
"org": "bar",
},
Annotations: map[string]string{
"foo.argoproj.io": "production",
},
},
Data: map[string][]byte{
"config": []byte("{}"),
"name": []byte("some-really-long-server-url"),
"server": []byte("https://some-really-long-url-that-will-exceed-63-characters.com"),
},
Type: corev1.SecretType("Opaque"),
},
}
runtimeClusters := []runtime.Object{}
for _, clientCluster := range clusters {
runtimeClusters = append(runtimeClusters, clientCluster)
}
appClientset := kubefake.NewSimpleClientset(runtimeClusters...)
fakeClient := fake.NewClientBuilder().WithObjects(clusters...).Build()
@@ -159,8 +340,8 @@ func getMockClusterGenerator() Generator {
}
func getMockGitGenerator() Generator {
argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}}
argoCDServiceMock.mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return([]string{"app1", "app2", "app_3", "p1/app4"}, nil)
argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}}
argoCDServiceMock.Mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return([]string{"app1", "app2", "app_3", "p1/app4"}, nil)
var gitGenerator = NewGitGenerator(argoCDServiceMock)
return gitGenerator
}
@@ -248,6 +429,60 @@ func TestInterpolateGenerator(t *testing.T) {
Path: "{{server}}",
}
requestedGenerator = &argoprojiov1alpha1.ApplicationSetGenerator{
Git: &argoprojiov1alpha1.GitGenerator{
Files: append([]argoprojiov1alpha1.GitFileGeneratorItem{}, fileNamePath, fileServerPath),
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
},
}
clusterGeneratorParams := map[string]interface{}{
"name": "production_01/west", "server": "https://production-01.example.com",
}
interpolatedGenerator, err = InterpolateGenerator(requestedGenerator, clusterGeneratorParams, false)
if err != nil {
log.WithError(err).WithField("requestedGenerator", requestedGenerator).Error("error interpolating Generator")
return
}
assert.Equal(t, "production_01/west", interpolatedGenerator.Git.Files[0].Path)
assert.Equal(t, "https://production-01.example.com", interpolatedGenerator.Git.Files[1].Path)
}
func TestInterpolateGenerator_go(t *testing.T) {
requestedGenerator := &argoprojiov1alpha1.ApplicationSetGenerator{
Clusters: &argoprojiov1alpha1.ClusterGenerator{
Selector: metav1.LabelSelector{
MatchLabels: map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"path-basename": "{{base .path.path}}",
"path-zero": "{{index .path.segments 0}}",
"path-full": "{{.path.path}}",
"kubernetes.io/environment": `{{default "foo" .my_label}}`,
}},
},
}
gitGeneratorParams := map[string]interface{}{
"path": map[string]interface{}{
"path": "p1/p2/app3",
"segments": []string{"p1", "p2", "app3"},
},
}
interpolatedGenerator, err := InterpolateGenerator(requestedGenerator, gitGeneratorParams, true)
require.NoError(t, err)
if err != nil {
log.WithError(err).WithField("requestedGenerator", requestedGenerator).Error("error interpolating Generator")
return
}
assert.Equal(t, "app3", interpolatedGenerator.Clusters.Selector.MatchLabels["path-basename"])
assert.Equal(t, "p1", interpolatedGenerator.Clusters.Selector.MatchLabels["path-zero"])
assert.Equal(t, "p1/p2/app3", interpolatedGenerator.Clusters.Selector.MatchLabels["path-full"])
fileNamePath := argoprojiov1alpha1.GitFileGeneratorItem{
Path: "{{.name}}",
}
fileServerPath := argoprojiov1alpha1.GitFileGeneratorItem{
Path: "{{.server}}",
}
requestedGenerator = &argoprojiov1alpha1.ApplicationSetGenerator{
Git: &argoprojiov1alpha1.GitGenerator{
Files: append([]argoprojiov1alpha1.GitFileGeneratorItem{}, fileNamePath, fileServerPath),

View File

@@ -58,9 +58,9 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
var err error
var res []map[string]interface{}
if appSetGenerator.Git.Directories != nil {
if len(appSetGenerator.Git.Directories) != 0 {
res, err = g.generateParamsForGitDirectories(appSetGenerator, appSet.Spec.GoTemplate)
} else if appSetGenerator.Git.Files != nil {
} else if len(appSetGenerator.Git.Files) != 0 {
res, err = g.generateParamsForGitFiles(appSetGenerator, appSet.Spec.GoTemplate)
} else {
return nil, EmptyAppSetGeneratorError

View File

@@ -1,7 +1,6 @@
package generators
import (
"context"
"fmt"
"testing"
@@ -9,6 +8,7 @@ import (
"github.com/stretchr/testify/mock"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
testutils "github.com/argoproj/argo-cd/v2/applicationset/utils/test"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
)
@@ -20,33 +20,6 @@ import (
// return io.NewCloser(func() error { return nil }), c.RepoServerServiceClient, nil
// }
type argoCDServiceMock struct {
mock *mock.Mock
}
func (a argoCDServiceMock) GetApps(ctx context.Context, repoURL string, revision string) ([]string, error) {
args := a.mock.Called(ctx, repoURL, revision)
return args.Get(0).([]string), args.Error(1)
}
func (a argoCDServiceMock) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) {
args := a.mock.Called(ctx, repoURL, revision, pattern)
return args.Get(0).(map[string][]byte), args.Error(1)
}
func (a argoCDServiceMock) GetFileContent(ctx context.Context, repoURL string, revision string, path string) ([]byte, error) {
args := a.mock.Called(ctx, repoURL, revision, path)
return args.Get(0).([]byte), args.Error(1)
}
func (a argoCDServiceMock) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) {
args := a.mock.Called(ctx, repoURL, revision)
return args.Get(0).([]string), args.Error(1)
}
func Test_generateParamsFromGitFile(t *testing.T) {
params, err := (*GitGenerator)(nil).generateParamsFromGitFile("path/dir/file_name.yaml", []byte(`
foo:
@@ -271,9 +244,9 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}}
argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}}
argoCDServiceMock.mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
argoCDServiceMock.Mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
var gitGenerator = NewGitGenerator(argoCDServiceMock)
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
@@ -301,7 +274,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
assert.Equal(t, testCaseCopy.expected, got)
}
argoCDServiceMock.mock.AssertExpectations(t)
argoCDServiceMock.Mock.AssertExpectations(t)
})
}
}
@@ -566,9 +539,9 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) {
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}}
argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}}
argoCDServiceMock.mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
argoCDServiceMock.Mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
var gitGenerator = NewGitGenerator(argoCDServiceMock)
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
@@ -597,7 +570,7 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) {
assert.Equal(t, testCaseCopy.expected, got)
}
argoCDServiceMock.mock.AssertExpectations(t)
argoCDServiceMock.Mock.AssertExpectations(t)
})
}
@@ -857,8 +830,8 @@ cluster:
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}}
argoCDServiceMock.mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}}
argoCDServiceMock.Mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError)
var gitGenerator = NewGitGenerator(argoCDServiceMock)
@@ -887,7 +860,7 @@ cluster:
assert.ElementsMatch(t, testCaseCopy.expected, got)
}
argoCDServiceMock.mock.AssertExpectations(t)
argoCDServiceMock.Mock.AssertExpectations(t)
})
}
}
@@ -1206,8 +1179,8 @@ cluster:
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}}
argoCDServiceMock.mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}}
argoCDServiceMock.Mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError)
var gitGenerator = NewGitGenerator(argoCDServiceMock)
@@ -1237,7 +1210,7 @@ cluster:
assert.ElementsMatch(t, testCaseCopy.expected, got)
}
argoCDServiceMock.mock.AssertExpectations(t)
argoCDServiceMock.Mock.AssertExpectations(t)
})
}
}

View File

@@ -80,28 +80,13 @@ func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.App
}
func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet, params map[string]interface{}) ([]map[string]interface{}, error) {
var matrix *argoprojiov1alpha1.MatrixGenerator
if appSetBaseGenerator.Matrix != nil {
// Since nested matrix generator is represented as a JSON object in the CRD, we unmarshall it back to a Go struct here.
nestedMatrix, err := argoprojiov1alpha1.ToNestedMatrixGenerator(appSetBaseGenerator.Matrix)
if err != nil {
return nil, fmt.Errorf("unable to unmarshall nested matrix generator: %v", err)
}
if nestedMatrix != nil {
matrix = nestedMatrix.ToMatrixGenerator()
}
matrixGen, err := getMatrixGenerator(appSetBaseGenerator)
if err != nil {
return nil, err
}
var mergeGenerator *argoprojiov1alpha1.MergeGenerator
if appSetBaseGenerator.Merge != nil {
// Since nested merge generator is represented as a JSON object in the CRD, we unmarshall it back to a Go struct here.
nestedMerge, err := argoprojiov1alpha1.ToNestedMergeGenerator(appSetBaseGenerator.Merge)
if err != nil {
return nil, fmt.Errorf("unable to unmarshall nested merge generator: %v", err)
}
if nestedMerge != nil {
mergeGenerator = nestedMerge.ToMergeGenerator()
}
mergeGen, err := getMergeGenerator(appSetBaseGenerator)
if err != nil {
return nil, err
}
t, err := Transform(
@@ -112,8 +97,8 @@ func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Appli
SCMProvider: appSetBaseGenerator.SCMProvider,
ClusterDecisionResource: appSetBaseGenerator.ClusterDecisionResource,
PullRequest: appSetBaseGenerator.PullRequest,
Matrix: matrix,
Merge: mergeGenerator,
Matrix: matrixGen,
Merge: mergeGen,
Selector: appSetBaseGenerator.Selector,
},
m.supportedGenerators,
@@ -143,11 +128,15 @@ func (m *MatrixGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Ap
var found bool
for _, r := range appSetGenerator.Matrix.Generators {
matrixGen, _ := getMatrixGenerator(r)
mergeGen, _ := getMergeGenerator(r)
base := &argoprojiov1alpha1.ApplicationSetGenerator{
List: r.List,
Clusters: r.Clusters,
Git: r.Git,
PullRequest: r.PullRequest,
Matrix: matrixGen,
Merge: mergeGen,
}
generators := GetRelevantGenerators(base, m.supportedGenerators)
@@ -168,6 +157,17 @@ func (m *MatrixGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Ap
}
func getMatrixGenerator(r argoprojiov1alpha1.ApplicationSetNestedGenerator) (*argoprojiov1alpha1.MatrixGenerator, error) {
if r.Matrix == nil {
return nil, nil
}
matrix, err := argoprojiov1alpha1.ToNestedMatrixGenerator(r.Matrix)
if err != nil {
return nil, err
}
return matrix.ToMatrixGenerator(), nil
}
func (m *MatrixGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate {
return &appSetGenerator.Matrix.Template
}

View File

@@ -5,6 +5,7 @@ import (
"testing"
"time"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -16,6 +17,7 @@ import (
"github.com/stretchr/testify/mock"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
testutils "github.com/argoproj/argo-cd/v2/applicationset/utils/test"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
)
@@ -28,7 +30,7 @@ func TestMatrixGenerate(t *testing.T) {
}
listGenerator := &argoprojiov1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "Cluster","url": "Url"}`)}},
Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "Cluster","url": "Url", "templated": "test-{{path.basenameNormalized}}"}`)}},
}
testCases := []struct {
@@ -48,8 +50,8 @@ func TestMatrixGenerate(t *testing.T) {
},
},
expected: []map[string]interface{}{
{"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "cluster": "Cluster", "url": "Url"},
{"path": "app2", "path.basename": "app2", "path.basenameNormalized": "app2", "cluster": "Cluster", "url": "Url"},
{"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "cluster": "Cluster", "url": "Url", "templated": "test-app1"},
{"path": "app2", "path.basename": "app2", "path.basenameNormalized": "app2", "cluster": "Cluster", "url": "Url", "templated": "test-app2"},
},
},
{
@@ -857,3 +859,72 @@ func (g *generatorMock) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Appl
return args.Get(0).(time.Duration)
}
func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) {
// Given a matrix generator over a list generator and a git files generator, the nested git files generator should
// be treated as a files generator, and it should produce parameters.
// This tests for a specific bug where a nested git files generator was being treated as a directory generator. This
// happened because, when the matrix generator was being processed, the nested git files generator was being
// interpolated by the deeplyReplace function. That function cannot differentiate between a nil slice and an empty
// slice. So it was replacing the `Directories` field with an empty slice, which the ApplicationSet controller
// interpreted as meaning this was a directory generator, not a files generator.
// Now instead of checking for nil, we check whether the field is a non-empty slice. This test prevents a regression
// of that bug.
listGeneratorMock := &generatorMock{}
listGeneratorMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), mock.AnythingOfType("*v1alpha1.ApplicationSet")).Return([]map[string]interface{}{
{"some": "value"},
}, nil)
listGeneratorMock.On("GetTemplate", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator")).Return(&argoprojiov1alpha1.ApplicationSetTemplate{})
gitGeneratorSpec := &argoprojiov1alpha1.GitGenerator{
RepoURL: "https://git.example.com",
Files: []argoprojiov1alpha1.GitFileGeneratorItem{
{Path: "some/path.json"},
},
}
repoServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}}
repoServiceMock.Mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{
"some/path.json": []byte("test: content"),
}, nil)
gitGenerator := NewGitGenerator(repoServiceMock)
matrixGenerator := NewMatrixGenerator(map[string]Generator{
"List": listGeneratorMock,
"Git": gitGenerator,
})
matrixGeneratorSpec := &argoprojiov1alpha1.MatrixGenerator{
Generators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
{
List: &argoprojiov1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{
{
Raw: []byte(`{"some": "value"}`),
},
},
},
},
{
Git: gitGeneratorSpec,
},
},
}
params, err := matrixGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
Matrix: matrixGeneratorSpec,
}, &argoprojiov1alpha1.ApplicationSet{})
require.NoError(t, err)
assert.Equal(t, []map[string]interface{}{{
"path": "some",
"path.basename": "some",
"path.basenameNormalized": "some",
"path.filename": "path.json",
"path.filenameNormalized": "path.json",
"path[0]": "some",
"some": "value",
"test": "content",
}}, params)
}

View File

@@ -137,27 +137,13 @@ func getParamSetsByMergeKey(mergeKeys []string, paramSets []map[string]interface
// getParams get the parameters generated by this generator.
func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) {
var matrix *argoprojiov1alpha1.MatrixGenerator
if appSetBaseGenerator.Matrix != nil {
nestedMatrix, err := argoprojiov1alpha1.ToNestedMatrixGenerator(appSetBaseGenerator.Matrix)
if err != nil {
return nil, err
}
if nestedMatrix != nil {
matrix = nestedMatrix.ToMatrixGenerator()
}
matrixGen, err := getMatrixGenerator(appSetBaseGenerator)
if err != nil {
return nil, err
}
var mergeGenerator *argoprojiov1alpha1.MergeGenerator
if appSetBaseGenerator.Merge != nil {
nestedMerge, err := argoprojiov1alpha1.ToNestedMergeGenerator(appSetBaseGenerator.Merge)
if err != nil {
return nil, err
}
if nestedMerge != nil {
mergeGenerator = nestedMerge.ToMergeGenerator()
}
mergeGen, err := getMergeGenerator(appSetBaseGenerator)
if err != nil {
return nil, err
}
t, err := Transform(
@@ -168,8 +154,8 @@ func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Applic
SCMProvider: appSetBaseGenerator.SCMProvider,
ClusterDecisionResource: appSetBaseGenerator.ClusterDecisionResource,
PullRequest: appSetBaseGenerator.PullRequest,
Matrix: matrix,
Merge: mergeGenerator,
Matrix: matrixGen,
Merge: mergeGen,
Selector: appSetBaseGenerator.Selector,
},
m.supportedGenerators,
@@ -197,10 +183,15 @@ func (m *MergeGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.App
var found bool
for _, r := range appSetGenerator.Merge.Generators {
matrixGen, _ := getMatrixGenerator(r)
mergeGen, _ := getMergeGenerator(r)
base := &argoprojiov1alpha1.ApplicationSetGenerator{
List: r.List,
Clusters: r.Clusters,
Git: r.Git,
List: r.List,
Clusters: r.Clusters,
Git: r.Git,
PullRequest: r.PullRequest,
Matrix: matrixGen,
Merge: mergeGen,
}
generators := GetRelevantGenerators(base, m.supportedGenerators)
@@ -221,6 +212,17 @@ func (m *MergeGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.App
}
func getMergeGenerator(r argoprojiov1alpha1.ApplicationSetNestedGenerator) (*argoprojiov1alpha1.MergeGenerator, error) {
if r.Merge == nil {
return nil, nil
}
merge, err := argoprojiov1alpha1.ToNestedMergeGenerator(r.Merge)
if err != nil {
return nil, err
}
return merge.ToMergeGenerator(), nil
}
// GetTemplate gets the Template field for the MergeGenerator.
func (m *MergeGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate {
return &appSetGenerator.Merge.Template

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"net/http"
pathpkg "path"
gitlab "github.com/xanzy/go-gitlab"
@@ -144,7 +145,11 @@ func (g *GitlabProvider) listBranches(_ context.Context, repo *Repository) ([]gi
branches := []gitlab.Branch{}
// If we don't specifically want to query for all branches, just use the default branch and call it a day.
if !g.allBranches {
gitlabBranch, _, err := g.client.Branches.GetBranch(repo.RepositoryId, repo.Branch, nil)
gitlabBranch, resp, err := g.client.Branches.GetBranch(repo.RepositoryId, repo.Branch, nil)
// 404s are not an error here, just a normal false.
if resp != nil && resp.StatusCode == http.StatusNotFound {
return []gitlab.Branch{}, nil
}
if err != nil {
return nil, err
}
@@ -157,6 +162,10 @@ func (g *GitlabProvider) listBranches(_ context.Context, repo *Repository) ([]gi
}
for {
gitlabBranches, resp, err := g.client.Branches.ListBranches(repo.RepositoryId, opt)
// 404s are not an error here, just a normal false.
if resp != nil && resp.StatusCode == http.StatusNotFound {
return []gitlab.Branch{}, nil
}
if err != nil {
return nil, err
}

View File

@@ -274,6 +274,8 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
if err != nil {
t.Fail()
}
case "/api/v4/projects/27084533/repository/branches/foo":
w.WriteHeader(http.StatusNotFound)
default:
_, err := io.WriteString(w, `[]`)
if err != nil {
@@ -391,3 +393,29 @@ func TestGitlabHasPath(t *testing.T) {
})
}
}
func TestGitlabGetBranches(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gitlabMockHandler(t)(w, r)
}))
host, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, false, true)
repo := &Repository{
RepositoryId: 27084533,
Branch: "master",
}
t.Run("branch exists", func(t *testing.T) {
repos, err := host.GetBranches(context.Background(), repo)
assert.Nil(t, err)
assert.Equal(t, repos[0].Branch, "master")
})
repo2 := &Repository{
RepositoryId: 27084533,
Branch: "foo",
}
t.Run("unknown branch", func(t *testing.T) {
_, err := host.GetBranches(context.Background(), repo2)
assert.NoError(t, err)
})
}

View File

@@ -0,0 +1,261 @@
package utils
import (
"fmt"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/klog/v2"
"sort"
"strconv"
"strings"
)
var (
unaryOperators = []string{
string(selection.Exists), string(selection.DoesNotExist),
}
binaryOperators = []string{
string(selection.In), string(selection.NotIn),
string(selection.Equals), string(selection.DoubleEquals), string(selection.NotEquals),
string(selection.GreaterThan), string(selection.LessThan),
}
validRequirementOperators = append(binaryOperators, unaryOperators...)
)
// Selector represents a label selector.
type Selector interface {
// Matches returns true if this selector matches the given set of labels.
Matches(labels.Labels) bool
// Add adds requirements to the Selector
Add(r ...Requirement) Selector
}
type internalSelector []Requirement
// ByKey sorts requirements by key to obtain deterministic parser
type ByKey []Requirement
func (a ByKey) Len() int { return len(a) }
func (a ByKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByKey) Less(i, j int) bool { return a[i].key < a[j].key }
// Matches for a internalSelector returns true if all
// its Requirements match the input Labels. If any
// Requirement does not match, false is returned.
func (s internalSelector) Matches(l labels.Labels) bool {
for ix := range s {
if matches := s[ix].Matches(l); !matches {
return false
}
}
return true
}
// Add adds requirements to the selector. It copies the current selector returning a new one
func (s internalSelector) Add(reqs ...Requirement) Selector {
ret := make(internalSelector, 0, len(s)+len(reqs))
ret = append(ret, s...)
ret = append(ret, reqs...)
sort.Sort(ByKey(ret))
return ret
}
type nothingSelector struct{}
func (n nothingSelector) Matches(l labels.Labels) bool {
return false
}
func (n nothingSelector) Add(r ...Requirement) Selector {
return n
}
// Nothing returns a selector that matches no labels
func nothing() Selector {
return nothingSelector{}
}
// Everything returns a selector that matches all labels.
func everything() Selector {
return internalSelector{}
}
// LabelSelectorAsSelector converts the LabelSelector api type into a struct that implements
// labels.Selector
// Note: This function should be kept in sync with the selector methods in pkg/labels/selector.go
func LabelSelectorAsSelector(ps *v1.LabelSelector) (Selector, error) {
if ps == nil {
return nothing(), nil
}
if len(ps.MatchLabels)+len(ps.MatchExpressions) == 0 {
return everything(), nil
}
requirements := make([]Requirement, 0, len(ps.MatchLabels)+len(ps.MatchExpressions))
for k, v := range ps.MatchLabels {
r, err := newRequirement(k, selection.Equals, []string{v})
if err != nil {
return nil, err
}
requirements = append(requirements, *r)
}
for _, expr := range ps.MatchExpressions {
var op selection.Operator
switch expr.Operator {
case v1.LabelSelectorOpIn:
op = selection.In
case v1.LabelSelectorOpNotIn:
op = selection.NotIn
case v1.LabelSelectorOpExists:
op = selection.Exists
case v1.LabelSelectorOpDoesNotExist:
op = selection.DoesNotExist
default:
return nil, fmt.Errorf("%q is not a valid pod selector operator", expr.Operator)
}
r, err := newRequirement(expr.Key, op, append([]string(nil), expr.Values...))
if err != nil {
return nil, err
}
requirements = append(requirements, *r)
}
selector := newSelector()
selector = selector.Add(requirements...)
return selector, nil
}
// NewSelector returns a nil selector
func newSelector() Selector {
return internalSelector(nil)
}
func validateLabelKey(k string, path *field.Path) *field.Error {
if errs := validation.IsQualifiedName(k); len(errs) != 0 {
return field.Invalid(path, k, strings.Join(errs, "; "))
}
return nil
}
// NewRequirement is the constructor for a Requirement.
// If any of these rules is violated, an error is returned:
// (1) The operator can only be In, NotIn, Equals, DoubleEquals, Gt, Lt, NotEquals, Exists, or DoesNotExist.
// (2) If the operator is In or NotIn, the values set must be non-empty.
// (3) If the operator is Equals, DoubleEquals, or NotEquals, the values set must contain one value.
// (4) If the operator is Exists or DoesNotExist, the value set must be empty.
// (5) If the operator is Gt or Lt, the values set must contain only one value, which will be interpreted as an integer.
// (6) The key is invalid due to its length, or sequence
//
// of characters. See validateLabelKey for more details.
//
// The empty string is a valid value in the input values set.
// Returned error, if not nil, is guaranteed to be an aggregated field.ErrorList
func newRequirement(key string, op selection.Operator, vals []string, opts ...field.PathOption) (*Requirement, error) {
var allErrs field.ErrorList
path := field.ToPath(opts...)
if err := validateLabelKey(key, path.Child("key")); err != nil {
allErrs = append(allErrs, err)
}
valuePath := path.Child("values")
switch op {
case selection.In, selection.NotIn:
if len(vals) == 0 {
allErrs = append(allErrs, field.Invalid(valuePath, vals, "for 'in', 'notin' operators, values set can't be empty"))
}
case selection.Equals, selection.DoubleEquals, selection.NotEquals:
if len(vals) != 1 {
allErrs = append(allErrs, field.Invalid(valuePath, vals, "exact-match compatibility requires one single value"))
}
case selection.Exists, selection.DoesNotExist:
if len(vals) != 0 {
allErrs = append(allErrs, field.Invalid(valuePath, vals, "values set must be empty for exists and does not exist"))
}
case selection.GreaterThan, selection.LessThan:
if len(vals) != 1 {
allErrs = append(allErrs, field.Invalid(valuePath, vals, "for 'Gt', 'Lt' operators, exactly one value is required"))
}
for i := range vals {
if _, err := strconv.ParseInt(vals[i], 10, 64); err != nil {
allErrs = append(allErrs, field.Invalid(valuePath.Index(i), vals[i], "for 'Gt', 'Lt' operators, the value must be an integer"))
}
}
default:
allErrs = append(allErrs, field.NotSupported(path.Child("operator"), op, validRequirementOperators))
}
return &Requirement{key: key, operator: op, strValues: vals}, allErrs.ToAggregate()
}
// Requirement contains values, a key, and an operator that relates the key and values.
// The zero value of Requirement is invalid.
// Requirement implements both set based match and exact match
// Requirement should be initialized via NewRequirement constructor for creating a valid Requirement.
// +k8s:deepcopy-gen=true
type Requirement struct {
key string
operator selection.Operator
// In the majority of cases we have at most one value here.
// It is generally faster to operate on a single-element slice
// than on a single-element map, so we have a slice here.
strValues []string
}
func (r *Requirement) hasValue(value string) bool {
for i := range r.strValues {
if r.strValues[i] == value {
return true
}
}
return false
}
func (r *Requirement) Matches(ls labels.Labels) bool {
switch r.operator {
case selection.In, selection.Equals, selection.DoubleEquals:
if !ls.Has(r.key) {
return false
}
return r.hasValue(ls.Get(r.key))
case selection.NotIn, selection.NotEquals:
if !ls.Has(r.key) {
return true
}
return !r.hasValue(ls.Get(r.key))
case selection.Exists:
return ls.Has(r.key)
case selection.DoesNotExist:
return !ls.Has(r.key)
case selection.GreaterThan, selection.LessThan:
if !ls.Has(r.key) {
return false
}
lsValue, err := strconv.ParseInt(ls.Get(r.key), 10, 64)
if err != nil {
klog.V(10).Infof("ParseInt failed for value %+v in label %+v, %+v", ls.Get(r.key), ls, err)
return false
}
// There should be only one strValue in r.strValues, and can be converted to an integer.
if len(r.strValues) != 1 {
klog.V(10).Infof("Invalid values count %+v of requirement %#v, for 'Gt', 'Lt' operators, exactly one value is required", len(r.strValues), r)
return false
}
var rValue int64
for i := range r.strValues {
rValue, err = strconv.ParseInt(r.strValues[i], 10, 64)
if err != nil {
klog.V(10).Infof("ParseInt failed for value %+v in requirement %#v, for 'Gt', 'Lt' operators, the value must be an integer", r.strValues[i], r)
return false
}
}
return (r.operator == selection.GreaterThan && lsValue > rValue) || (r.operator == selection.LessThan && lsValue < rValue)
default:
return false
}
}

View File

@@ -0,0 +1,34 @@
package test
import (
"context"
"github.com/stretchr/testify/mock"
)
type ArgoCDServiceMock struct {
Mock *mock.Mock
}
func (a ArgoCDServiceMock) GetApps(ctx context.Context, repoURL string, revision string) ([]string, error) {
args := a.Mock.Called(ctx, repoURL, revision)
return args.Get(0).([]string), args.Error(1)
}
func (a ArgoCDServiceMock) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) {
args := a.Mock.Called(ctx, repoURL, revision, pattern)
return args.Get(0).(map[string][]byte), args.Error(1)
}
func (a ArgoCDServiceMock) GetFileContent(ctx context.Context, repoURL string, revision string, path string) ([]byte, error) {
args := a.Mock.Called(ctx, repoURL, revision, path)
return args.Get(0).([]byte), args.Error(1)
}
func (a ArgoCDServiceMock) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) {
args := a.Mock.Called(ctx, repoURL, revision)
return args.Get(0).([]string), args.Error(1)
}

View File

@@ -96,6 +96,25 @@ func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[stri
// specific case time
if currentType == "time.Time" {
copy.Field(i).Set(original.Field(i))
} else if currentType == "Raw.k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" {
var unmarshaled interface{}
originalBytes := original.Field(i).Bytes()
err := json.Unmarshal(originalBytes, &unmarshaled)
if err != nil {
return fmt.Errorf("failed to unmarshal JSON field: %w", err)
}
jsonOriginal := reflect.ValueOf(&unmarshaled)
jsonCopy := reflect.New(jsonOriginal.Type()).Elem()
err = r.deeplyReplace(jsonCopy, jsonOriginal, replaceMap, useGoTemplate)
if err != nil {
return fmt.Errorf("failed to deeply replace JSON field contents: %w", err)
}
jsonCopyInterface := jsonCopy.Interface().(*interface{})
data, err := json.Marshal(jsonCopyInterface)
if err != nil {
return fmt.Errorf("failed to marshal templated JSON field: %w", err)
}
copy.Field(i).Set(reflect.ValueOf(data))
} else if err := r.deeplyReplace(copy.Field(i), original.Field(i), replaceMap, useGoTemplate); err != nil {
return err
}
@@ -174,7 +193,7 @@ func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[stri
func (r *Render) RenderTemplateParams(tmpl *argoappsv1.Application, syncPolicy *argoappsv1.ApplicationSetSyncPolicy, params map[string]interface{}, useGoTemplate bool) (*argoappsv1.Application, error) {
if tmpl == nil {
return nil, fmt.Errorf("application template is empty ")
return nil, fmt.Errorf("application template is empty")
}
if len(params) == 0 {
@@ -204,6 +223,27 @@ func (r *Render) RenderTemplateParams(tmpl *argoappsv1.Application, syncPolicy *
return replacedTmpl, nil
}
func (r *Render) RenderGeneratorParams(gen *argoappsv1.ApplicationSetGenerator, params map[string]interface{}, useGoTemplate bool) (*argoappsv1.ApplicationSetGenerator, error) {
if gen == nil {
return nil, fmt.Errorf("generator is empty")
}
if len(params) == 0 {
return gen, nil
}
original := reflect.ValueOf(gen)
copy := reflect.New(original.Type()).Elem()
if err := r.deeplyReplace(copy, original, params, useGoTemplate); err != nil {
return nil, fmt.Errorf("failed to replace parameters in generator: %w", err)
}
replacedGen := copy.Interface().(*argoappsv1.ApplicationSetGenerator)
return replacedGen, nil
}
var isTemplatedRegex = regexp.MustCompile(".*{{.*}}.*")
// Replace executes basic string substitution of a template with replacement values.
@@ -227,7 +267,10 @@ func (r *Render) Replace(tmpl string, replaceMap map[string]interface{}, useGoTe
return tmpl, nil
}
fstTmpl := fasttemplate.New(tmpl, "{{", "}}")
fstTmpl, err := fasttemplate.NewTemplate(tmpl, "{{", "}}")
if err != nil {
return "", fmt.Errorf("invalid template: %w", err)
}
replacedTmpl := fstTmpl.ExecuteFuncString(func(w io.Writer, tag string) (int, error) {
trimmedTag := strings.TrimSpace(tag)
replacement, ok := replaceMap[trimmedTag].(string)

View File

@@ -464,6 +464,14 @@ func TestRenderTemplateParamsGoTemplate(t *testing.T) {
}
}
func Test_Render_Replace_no_panic_on_missing_closing_brace(t *testing.T) {
r := &Render{}
assert.NotPanics(t, func() {
_, err := r.Replace("{{properly.closed}} {{improperly.closed}", nil, false)
assert.Error(t, err)
})
}
func TestRenderTemplateKeys(t *testing.T) {
t.Run("fasttemplate", func(t *testing.T) {
application := &argoappsv1.Application{

View File

@@ -271,6 +271,16 @@
"description": "the application's namespace.",
"name": "appNamespace",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "the project names to restrict returned list applications (legacy name for backwards-compatibility).",
"name": "project",
"in": "query"
}
],
"responses": {
@@ -585,6 +595,16 @@
"description": "the application's namespace.",
"name": "appNamespace",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "the project names to restrict returned list applications (legacy name for backwards-compatibility).",
"name": "project",
"in": "query"
}
],
"responses": {
@@ -3670,6 +3690,16 @@
"description": "the application's namespace.",
"name": "appNamespace",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "the project names to restrict returned list applications (legacy name for backwards-compatibility).",
"name": "project",
"in": "query"
}
],
"responses": {

View File

@@ -55,6 +55,7 @@ func NewCommand() *cobra.Command {
argocdRepoServerStrictTLS bool
configMapName string
secretName string
applicationNamespaces []string
)
var command = cobra.Command{
Use: "controller",
@@ -138,7 +139,7 @@ func NewCommand() *cobra.Command {
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)
ctrl := notificationscontroller.NewController(k8sClient, dynamicClient, argocdService, namespace, applicationNamespaces, appLabelSelector, registry, secretName, configMapName)
err = ctrl.Init(ctx)
if err != nil {
return err
@@ -161,5 +162,6 @@ func NewCommand() *cobra.Command {
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")
command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces that this controller should send notifications for")
return &command
}

View File

@@ -84,6 +84,8 @@ func NewCommand() *cobra.Command {
allowOutOfBoundsSymlinks bool
streamedManifestMaxTarSize string
streamedManifestMaxExtractedSize string
helmManifestMaxExtractedSize string
disableManifestMaxExtractedSize bool
)
var command = cobra.Command{
Use: cliName,
@@ -122,6 +124,9 @@ func NewCommand() *cobra.Command {
streamedManifestMaxExtractedSizeQuantity, err := resource.ParseQuantity(streamedManifestMaxExtractedSize)
errors.CheckError(err)
helmManifestMaxExtractedSizeQuantity, err := resource.ParseQuantity(helmManifestMaxExtractedSize)
errors.CheckError(err)
askPassServer := askpass.NewServer()
metricsServer := metrics.NewMetricsServer()
cacheutil.CollectMetrics(redisClient, metricsServer)
@@ -136,6 +141,7 @@ func NewCommand() *cobra.Command {
AllowOutOfBoundsSymlinks: allowOutOfBoundsSymlinks,
StreamedManifestMaxExtractedSize: streamedManifestMaxExtractedSizeQuantity.ToDec().Value(),
StreamedManifestMaxTarSize: streamedManifestMaxTarSizeQuantity.ToDec().Value(),
HelmManifestMaxExtractedSize: helmManifestMaxExtractedSizeQuantity.ToDec().Value(),
}, askPassServer)
errors.CheckError(err)
@@ -216,6 +222,8 @@ func NewCommand() *cobra.Command {
command.Flags().BoolVar(&allowOutOfBoundsSymlinks, "allow-oob-symlinks", env.ParseBoolFromEnv("ARGOCD_REPO_SERVER_ALLOW_OUT_OF_BOUNDS_SYMLINKS", false), "Allow out-of-bounds symlinks in repositories (not recommended)")
command.Flags().StringVar(&streamedManifestMaxTarSize, "streamed-manifest-max-tar-size", env.StringFromEnv("ARGOCD_REPO_SERVER_STREAMED_MANIFEST_MAX_TAR_SIZE", "100M"), "Maximum size of streamed manifest archives")
command.Flags().StringVar(&streamedManifestMaxExtractedSize, "streamed-manifest-max-extracted-size", env.StringFromEnv("ARGOCD_REPO_SERVER_STREAMED_MANIFEST_MAX_EXTRACTED_SIZE", "1G"), "Maximum size of streamed manifest archives when extracted")
command.Flags().StringVar(&helmManifestMaxExtractedSize, "helm-manifest-max-extracted-size", env.StringFromEnv("ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE", "1G"), "Maximum size of helm manifest archives when extracted")
command.Flags().BoolVar(&disableManifestMaxExtractedSize, "disable-helm-manifest-max-extracted-size", env.ParseBoolFromEnv("ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE", false), "Disable maximum size of helm manifest archives when extracted")
tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(&command)
cacheSrc = reposervercache.AddCacheFlagsToCmd(&command, func(client *redis.Client) {
redisClient = client

View File

@@ -9,13 +9,16 @@ import (
"github.com/argoproj/argo-cd/v2/cmd/argocd/commands/initialize"
"github.com/argoproj/argo-cd/v2/common"
argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient"
"github.com/argoproj/argo-cd/v2/util/cache"
"github.com/argoproj/argo-cd/v2/util/env"
"github.com/argoproj/argo-cd/v2/util/errors"
)
func NewDashboardCommand() *cobra.Command {
var (
port int
address string
port int
address string
compressionStr string
)
cmd := &cobra.Command{
Use: "dashboard",
@@ -23,7 +26,9 @@ func NewDashboardCommand() *cobra.Command {
Run: func(cmd *cobra.Command, args []string) {
ctx := cmd.Context()
errors.CheckError(headless.StartLocalServer(ctx, &argocdclient.ClientOptions{Core: true}, initialize.RetrieveContextIfChanged(cmd.Flag("context")), &port, &address))
compression, err := cache.CompressionTypeFromString(compressionStr)
errors.CheckError(err)
errors.CheckError(headless.StartLocalServer(ctx, &argocdclient.ClientOptions{Core: true}, initialize.RetrieveContextIfChanged(cmd.Flag("context")), &port, &address, compression))
println(fmt.Sprintf("Argo CD UI is available at http://%s:%d", address, port))
<-ctx.Done()
},
@@ -31,5 +36,6 @@ func NewDashboardCommand() *cobra.Command {
initialize.InitCommand(cmd)
cmd.Flags().IntVar(&port, "port", common.DefaultPortAPIServer, "Listen on given port")
cmd.Flags().StringVar(&address, "address", common.DefaultAddressAPIServer, "Listen on given address")
cmd.Flags().StringVar(&compressionStr, "redis-compress", env.StringFromEnv("REDIS_COMPRESSION", string(cache.RedisCompressionNone)), "Enable this if the application controller is configured with redis compression enabled. (possible values: none, gzip)")
return cmd
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"strings"
"github.com/ghodss/yaml"
log "github.com/sirupsen/logrus"
@@ -373,6 +374,9 @@ func resolveRBACResourceName(name string) string {
// isValidRBACAction checks whether a given action is a valid RBAC action
func isValidRBACAction(action string) bool {
if strings.HasPrefix(action, rbacpolicy.ActionAction+"/") {
return true
}
_, ok := validRBACActions[action]
return ok
}

View File

@@ -27,6 +27,11 @@ func Test_isValidRBACAction(t *testing.T) {
})
}
func Test_isValidRBACAction_ActionAction(t *testing.T) {
ok := isValidRBACAction("action/apps/Deployment/restart")
assert.True(t, ok)
}
func Test_isValidRBACResource(t *testing.T) {
for k := range validRBACResources {
t.Run(k, func(t *testing.T) {

View File

@@ -165,7 +165,9 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
// Get app before creating to see if it is being updated or no change
existing, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &app.Name})
if grpc.UnwrapGRPCStatus(err).Code() != codes.NotFound {
unwrappedError := grpc.UnwrapGRPCStatus(err).Code()
// As part of the fix for CVE-2022-41354, the API will return Permission Denied when an app does not exist.
if unwrappedError != codes.NotFound && unwrappedError != codes.PermissionDenied {
errors.CheckError(err)
}
@@ -1001,7 +1003,7 @@ func findandPrintDiff(ctx context.Context, app *argoappv1.Application, resources
unstructureds = append(unstructureds, obj)
}
groupedObjs := groupObjsByKey(unstructureds, liveObjs, app.Spec.Destination.Namespace)
items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.Name)
items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace))
} else if diffOptions.serversideRes != nil {
var unstructureds []*unstructured.Unstructured
for _, mfst := range diffOptions.serversideRes.Manifests {
@@ -1010,7 +1012,7 @@ func findandPrintDiff(ctx context.Context, app *argoappv1.Application, resources
unstructureds = append(unstructureds, obj)
}
groupedObjs := groupObjsByKey(unstructureds, liveObjs, app.Spec.Destination.Namespace)
items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.Name)
items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace))
} else {
for i := range resources.Items {
res := resources.Items[i]
@@ -1444,7 +1446,7 @@ func NewApplicationWaitCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
}
}
for _, appName := range appNames {
_, err := waitOnApplicationStatus(ctx, acdClient, appName, timeout, watch, selectedResources)
_, _, err := waitOnApplicationStatus(ctx, acdClient, appName, timeout, watch, selectedResources)
errors.CheckError(err)
}
},
@@ -1605,8 +1607,15 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
errors.CheckError(err)
if app.Spec.HasMultipleSources() {
log.Fatal("argocd cli does not work on multi-source app")
return
if revision != "" {
log.Fatal("argocd cli does not work on multi-source app with --revision flag")
return
}
if local != "" {
log.Fatal("argocd cli does not work on multi-source app with --local flag")
return
}
}
if local != "" {
@@ -1710,15 +1719,15 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
errors.CheckError(err)
if !async {
app, err := waitOnApplicationStatus(ctx, acdClient, appQualifiedName, timeout, watchOpts{operation: true}, selectedResources)
app, opState, err := waitOnApplicationStatus(ctx, acdClient, appQualifiedName, timeout, watchOpts{operation: true}, selectedResources)
errors.CheckError(err)
if !dryRun {
if !app.Status.OperationState.Phase.Successful() {
log.Fatalf("Operation has completed with phase: %s", app.Status.OperationState.Phase)
if !opState.Phase.Successful() {
log.Fatalf("Operation has completed with phase: %s", opState.Phase)
} else if len(selectedResources) == 0 && app.Status.Sync.Status != argoappv1.SyncStatusCodeSynced {
// Only get resources to be pruned if sync was application-wide and final status is not synced
pruningRequired := app.Status.OperationState.SyncResult.Resources.PruningRequired()
pruningRequired := opState.SyncResult.Resources.PruningRequired()
if pruningRequired > 0 {
log.Fatalf("%d resources require pruning", pruningRequired)
}
@@ -1918,7 +1927,10 @@ func checkResourceStatus(watch watchOpts, healthStatus string, syncStatus string
const waitFormatString = "%s\t%5s\t%10s\t%10s\t%20s\t%8s\t%7s\t%10s\t%s\n"
func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client, appName string, timeout uint, watch watchOpts, selectedResources []*argoappv1.SyncOperationResource) (*argoappv1.Application, error) {
// waitOnApplicationStatus watches an application and blocks until either the desired watch conditions
// are fulfiled or we reach the timeout. Returns the app once desired conditions have been filled.
// Additionally return the operationState at time of fulfilment (which may be different than returned app).
func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client, appName string, timeout uint, watch watchOpts, selectedResources []*argoappv1.SyncOperationResource) (*argoappv1.Application, *argoappv1.OperationState, error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
@@ -1976,10 +1988,20 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
AppNamespace: &appNs,
})
errors.CheckError(err)
// printFinalStatus() will refresh and update the app object, potentially causing the app's
// status.operationState to be different than the version when we break out of the event loop.
// This means the app.status is unreliable for determining the final state of the operation.
// finalOperationState captures the operationState as it was seen when we met the conditions of
// the wait, so the caller can rely on it to determine the outcome of the operation.
// See: https://github.com/argoproj/argo-cd/issues/5592
finalOperationState := app.Status.OperationState
appEventCh := acdClient.WatchApplicationWithRetry(ctx, appName, app.ResourceVersion)
for appEvent := range appEventCh {
app = &appEvent.Application
finalOperationState = app.Status.OperationState
operationInProgress := false
// consider the operation is in progress
if app.Operation != nil {
@@ -2017,7 +2039,7 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
if selectedResourcesAreReady && (!operationInProgress || !watch.operation) {
app = printFinalStatus(app)
return app, nil
return app, finalOperationState, nil
}
newStates := groupResourceStates(app, selectedResources)
@@ -2027,7 +2049,7 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
if prevState, found := prevStates[stateKey]; found {
if watch.health && prevState.Health != string(health.HealthStatusUnknown) && prevState.Health != string(health.HealthStatusDegraded) && newState.Health == string(health.HealthStatusDegraded) {
_ = printFinalStatus(app)
return nil, fmt.Errorf("application '%s' health state has transitioned from %s to %s", appName, prevState.Health, newState.Health)
return nil, finalOperationState, fmt.Errorf("application '%s' health state has transitioned from %s to %s", appName, prevState.Health, newState.Health)
}
doPrint = prevState.Merge(newState)
} else {
@@ -2041,7 +2063,7 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
_ = w.Flush()
}
_ = printFinalStatus(app)
return nil, fmt.Errorf("timed out (%ds) waiting for app %q match desired state", timeout, appName)
return nil, finalOperationState, fmt.Errorf("timed out (%ds) waiting for app %q match desired state", timeout, appName)
}
// setParameterOverrides updates an existing or appends a new parameter override in the application
@@ -2197,7 +2219,7 @@ func NewApplicationRollbackCommand(clientOpts *argocdclient.ClientOptions) *cobr
})
errors.CheckError(err)
_, err = waitOnApplicationStatus(ctx, acdClient, app.QualifiedName(), timeout, watchOpts{
_, _, err = waitOnApplicationStatus(ctx, acdClient, app.QualifiedName(), timeout, watchOpts{
operation: true,
}, nil)
errors.CheckError(err)

View File

@@ -343,16 +343,19 @@ func printAppSetSummaryTable(appSet *arogappsetv1.ApplicationSet) {
fmt.Printf(printOpFmtStr, "Path:", source.Path)
printAppSourceDetails(&source)
var syncPolicy string
if appSet.Spec.SyncPolicy != nil && appSet.Spec.Template.Spec.SyncPolicy.Automated != nil {
syncPolicy = "Automated"
if appSet.Spec.Template.Spec.SyncPolicy.Automated.Prune {
syncPolicy += " (Prune)"
var (
syncPolicyStr string
syncPolicy = appSet.Spec.Template.Spec.SyncPolicy
)
if syncPolicy != nil && syncPolicy.Automated != nil {
syncPolicyStr = "Automated"
if syncPolicy.Automated.Prune {
syncPolicyStr += " (Prune)"
}
} else {
syncPolicy = "<none>"
syncPolicyStr = "<none>"
}
fmt.Printf(printOpFmtStr, "SyncPolicy:", syncPolicy)
fmt.Printf(printOpFmtStr, "SyncPolicy:", syncPolicyStr)
}

View File

@@ -1,6 +1,8 @@
package commands
import (
"io/ioutil"
"os"
"testing"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
@@ -68,3 +70,124 @@ func TestPrintApplicationSetTable(t *testing.T) {
expectation := "NAME NAMESPACE PROJECT SYNCPOLICY CONDITIONS\napp-name default nil [{ResourcesUpToDate <nil> True }]\napp-name default nil [{ResourcesUpToDate <nil> True }]\n"
assert.Equal(t, expectation, output)
}
func TestPrintAppSetSummaryTable(t *testing.T) {
baseAppSet := &arogappsetv1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "app-name",
},
Spec: arogappsetv1.ApplicationSetSpec{
Generators: []arogappsetv1.ApplicationSetGenerator{
arogappsetv1.ApplicationSetGenerator{
Git: &arogappsetv1.GitGenerator{
RepoURL: "https://github.com/argoproj/argo-cd.git",
Revision: "head",
Directories: []arogappsetv1.GitDirectoryGeneratorItem{
arogappsetv1.GitDirectoryGeneratorItem{
Path: "applicationset/examples/git-generator-directory/cluster-addons/*",
},
},
},
},
},
Template: arogappsetv1.ApplicationSetTemplate{
Spec: v1alpha1.ApplicationSpec{
Project: "default",
},
},
},
Status: arogappsetv1.ApplicationSetStatus{
Conditions: []arogappsetv1.ApplicationSetCondition{
arogappsetv1.ApplicationSetCondition{
Status: v1alpha1.ApplicationSetConditionStatusTrue,
Type: arogappsetv1.ApplicationSetConditionResourcesUpToDate,
},
},
},
}
appsetSpecSyncPolicy := baseAppSet.DeepCopy()
appsetSpecSyncPolicy.Spec.SyncPolicy = &arogappsetv1.ApplicationSetSyncPolicy{
PreserveResourcesOnDeletion: true,
}
appSetTemplateSpecSyncPolicy := baseAppSet.DeepCopy()
appSetTemplateSpecSyncPolicy.Spec.Template.Spec.SyncPolicy = &arogappsetv1.SyncPolicy{
Automated: &arogappsetv1.SyncPolicyAutomated{
SelfHeal: true,
},
}
appSetBothSyncPolicies := baseAppSet.DeepCopy()
appSetBothSyncPolicies.Spec.SyncPolicy = &arogappsetv1.ApplicationSetSyncPolicy{
PreserveResourcesOnDeletion: true,
}
appSetBothSyncPolicies.Spec.Template.Spec.SyncPolicy = &arogappsetv1.SyncPolicy{
Automated: &arogappsetv1.SyncPolicyAutomated{
SelfHeal: true,
},
}
for _, tt := range []struct {
name string
appSet *arogappsetv1.ApplicationSet
expectedOutput string
}{
{
name: "appset with only spec.syncPolicy set",
appSet: appsetSpecSyncPolicy,
expectedOutput: `Name: app-name
Project: default
Server:
Namespace:
Repo:
Target:
Path:
SyncPolicy: <none>
`,
},
{
name: "appset with only spec.template.spec.syncPolicy set",
appSet: appSetTemplateSpecSyncPolicy,
expectedOutput: `Name: app-name
Project: default
Server:
Namespace:
Repo:
Target:
Path:
SyncPolicy: Automated
`,
},
{
name: "appset with both spec.SyncPolicy and spec.template.spec.syncPolicy set",
appSet: appSetBothSyncPolicies,
expectedOutput: `Name: app-name
Project: default
Server:
Namespace:
Repo:
Target:
Path:
SyncPolicy: Automated
`,
},
} {
t.Run(tt.name, func(t *testing.T) {
oldStdout := os.Stdout
defer func() {
os.Stdout = oldStdout
}()
r, w, _ := os.Pipe()
os.Stdout = w
printAppSetSummaryTable(tt.appSet)
w.Close()
out, err := ioutil.ReadAll(r)
assert.NoError(t, err)
assert.Equal(t, tt.expectedOutput, string(out))
})
}
}

View File

@@ -38,11 +38,12 @@ import (
)
type forwardCacheClient struct {
namespace string
context string
init sync.Once
client cache.CacheClient
err error
namespace string
context string
init sync.Once
client cache.CacheClient
compression cache.RedisCompressionType
err error
}
func (c *forwardCacheClient) doLazy(action func(client cache.CacheClient) error) error {
@@ -58,7 +59,7 @@ func (c *forwardCacheClient) doLazy(action func(client cache.CacheClient) error)
}
redisClient := redis.NewClient(&redis.Options{Addr: fmt.Sprintf("localhost:%d", redisPort)})
c.client = cache.NewRedisCache(redisClient, time.Hour, cache.RedisCompressionNone)
c.client = cache.NewRedisCache(redisClient, time.Hour, c.compression)
})
if c.err != nil {
return c.err
@@ -139,7 +140,7 @@ func testAPI(ctx context.Context, clientOpts *apiclient.ClientOptions) error {
// StartLocalServer 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 StartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOptions, ctxStr string, port *int, address *string) error {
func StartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOptions, ctxStr string, port *int, address *string, compression cache.RedisCompressionType) error {
flags := pflag.NewFlagSet("tmp", pflag.ContinueOnError)
clientConfig := cli.AddKubectlFlagsToSet(flags)
startInProcessAPI := clientOpts.Core
@@ -200,7 +201,7 @@ func StartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOptions,
if err != nil {
return err
}
appstateCache := appstatecache.NewCache(cache.NewCache(&forwardCacheClient{namespace: namespace, context: ctxStr}), time.Hour)
appstateCache := appstatecache.NewCache(cache.NewCache(&forwardCacheClient{namespace: namespace, context: ctxStr, compression: compression}), time.Hour)
srv := server.NewServer(ctx, server.ArgoCDServerOpts{
EnableGZip: false,
Namespace: namespace,
@@ -243,7 +244,7 @@ func NewClientOrDie(opts *apiclient.ClientOptions, c *cobra.Command) apiclient.C
ctx := c.Context()
ctxStr := initialize.RetrieveContextIfChanged(c.Flag("context"))
err := StartLocalServer(ctx, opts, ctxStr, nil, nil)
err := StartLocalServer(ctx, opts, ctxStr, nil, nil, cache.RedisCompressionNone)
if err != nil {
log.Fatal(err)
}

View File

@@ -3,6 +3,7 @@ package commands
import (
"fmt"
"os"
"strconv"
"text/tabwriter"
log "github.com/sirupsen/logrus"
@@ -250,15 +251,12 @@ func printRepoTable(repos appsv1.Repositories) {
_, _ = fmt.Fprintf(w, "TYPE\tNAME\tREPO\tINSECURE\tOCI\tLFS\tCREDS\tSTATUS\tMESSAGE\tPROJECT\n")
for _, r := range repos {
var hasCreds string
if !r.HasCredentials() {
hasCreds = "false"
if r.InheritedCreds {
hasCreds = "inherited"
} else {
if r.InheritedCreds {
hasCreds = "inherited"
} else {
hasCreds = "true"
}
hasCreds = strconv.FormatBool(r.HasCredentials())
}
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%v\t%v\t%v\t%s\t%s\t%s\t%s\n", r.Type, r.Name, r.Repo, r.IsInsecure(), r.EnableOCI, r.EnableLFS, hasCreds, r.ConnectionState.Status, r.ConnectionState.Message, r.Project)
}
_ = w.Flush()

View File

@@ -138,7 +138,10 @@ func readProjFromURI(fileURL string, proj *v1alpha1.AppProject) error {
} else {
err = config.UnmarshalRemoteFile(fileURL, &proj)
}
return fmt.Errorf("error reading proj from uri: %w", err)
if err != nil {
return fmt.Errorf("error reading proj from uri: %w", err)
}
return nil
}
func SetProjSpecOptions(flags *pflag.FlagSet, spec *v1alpha1.AppProjectSpec, projOpts *ProjectOpts) int {

View File

@@ -9,8 +9,10 @@ import (
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"time"
"unicode"
"github.com/argoproj/pkg/rand"
@@ -22,6 +24,7 @@ import (
"github.com/argoproj/argo-cd/v2/util/io/files"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/cyphar/filepath-securejoin"
"github.com/mattn/go-zglob"
log "github.com/sirupsen/logrus"
)
@@ -73,9 +76,8 @@ func runCommand(ctx context.Context, command Command, path string, env []string)
}
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)
argsToLog := getCommandArgsToLog(cmd)
logCtx.WithFields(log.Fields{"dir": cmd.Dir}).Info(argsToLog)
var stdout bytes.Buffer
var stderr bytes.Buffer
@@ -95,6 +97,14 @@ func runCommand(ctx context.Context, command Command, path string, env []string)
<-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
// Sending a TERM signal first to allow any potential cleanup if needed, and then sending a KILL signal
_ = sysCallTerm(-cmd.Process.Pid)
// modify cleanup timeout to allow process to cleanup
cleanupTimeout := 5 * time.Second
time.Sleep(cleanupTimeout)
_ = sysCallKill(-cmd.Process.Pid)
}()
@@ -106,7 +116,7 @@ func runCommand(ctx context.Context, command Command, path string, env []string)
logCtx.WithFields(log.Fields{"duration": duration}).Debug(output)
if err != nil {
err := newCmdError(args, errors.New(err.Error()), strings.TrimSpace(stderr.String()))
err := newCmdError(argsToLog, errors.New(err.Error()), strings.TrimSpace(stderr.String()))
logCtx.Error(err.Error())
return strings.TrimSuffix(output, "\n"), err
}
@@ -114,6 +124,28 @@ func runCommand(ctx context.Context, command Command, path string, env []string)
return strings.TrimSuffix(output, "\n"), nil
}
// getCommandArgsToLog represents the given command in a way that we can copy-and-paste into a terminal
func getCommandArgsToLog(cmd *exec.Cmd) string {
var argsToLog []string
for _, arg := range cmd.Args {
containsSpace := false
for _, r := range arg {
if unicode.IsSpace(r) {
containsSpace = true
break
}
}
if containsSpace {
// add quotes and escape any internal quotes
argsToLog = append(argsToLog, strconv.Quote(arg))
} else {
argsToLog = append(argsToLog, arg)
}
}
args := strings.Join(argsToLog, " ")
return args
}
type CmdError struct {
Args string
Stderr string
@@ -153,7 +185,7 @@ func getTempDirMustCleanup(baseDir string) (workDir string, cleanup func(), err
if err := os.RemoveAll(workDir); err != nil {
log.WithFields(map[string]interface{}{
common.SecurityField: common.SecurityHigh,
common.SecurityCWEField: 459,
common.SecurityCWEField: common.SecurityCWEIncompleteCleanup,
}).Errorf("Failed to clean up temp directory: %s", err)
}
}
@@ -273,7 +305,7 @@ func (s *Service) matchRepositoryGeneric(stream MatchRepositoryStream) error {
return fmt.Errorf("match repository error receiving stream: %w", err)
}
isSupported, isDiscoveryEnabled, err := s.matchRepository(bufferedCtx, workDir, metadata.GetEnv())
isSupported, isDiscoveryEnabled, err := s.matchRepository(bufferedCtx, workDir, metadata.GetEnv(), metadata.GetAppRelPath())
if err != nil {
return fmt.Errorf("match repository error: %w", err)
}
@@ -286,12 +318,20 @@ func (s *Service) matchRepositoryGeneric(stream MatchRepositoryStream) error {
return nil
}
func (s *Service) matchRepository(ctx context.Context, workdir string, envEntries []*apiclient.EnvEntry) (isSupported bool, isDiscoveryEnabled bool, err error) {
func (s *Service) matchRepository(ctx context.Context, workdir string, envEntries []*apiclient.EnvEntry, appRelPath string) (isSupported bool, isDiscoveryEnabled bool, err error) {
config := s.initConstants.PluginConfig
appPath, err := securejoin.SecureJoin(workdir, appRelPath)
if err != nil {
log.WithFields(map[string]interface{}{
common.SecurityField: common.SecurityHigh,
common.SecurityCWEField: common.SecurityCWEIncompleteCleanup,
}).Errorf("error joining workdir %q and appRelPath %q: %v", workdir, appRelPath, err)
}
if config.Spec.Discover.FileName != "" {
log.Debugf("config.Spec.Discover.FileName is provided")
pattern := filepath.Join(workdir, config.Spec.Discover.FileName)
pattern := filepath.Join(appPath, config.Spec.Discover.FileName)
matches, err := filepath.Glob(pattern)
if err != nil {
e := fmt.Errorf("error finding filename match for pattern %q: %w", pattern, err)
@@ -303,7 +343,7 @@ func (s *Service) matchRepository(ctx context.Context, workdir string, envEntrie
if config.Spec.Discover.Find.Glob != "" {
log.Debugf("config.Spec.Discover.Find.Glob is provided")
pattern := filepath.Join(workdir, config.Spec.Discover.Find.Glob)
pattern := filepath.Join(appPath, config.Spec.Discover.Find.Glob)
// filepath.Glob doesn't have '**' support hence selecting third-party lib
// https://github.com/golang/go/issues/11862
matches, err := zglob.Glob(pattern)
@@ -319,7 +359,7 @@ func (s *Service) matchRepository(ctx context.Context, workdir string, envEntrie
if len(config.Spec.Discover.Find.Command.Command) > 0 {
log.Debugf("Going to try runCommand.")
env := append(os.Environ(), environ(envEntries)...)
find, err := runCommand(ctx, config.Spec.Discover.Find.Command, workdir, env)
find, err := runCommand(ctx, config.Spec.Discover.Find.Command, appPath, env)
if err != nil {
return false, true, fmt.Errorf("error running find command: %w", err)
}
@@ -355,7 +395,7 @@ func (s *Service) GetParametersAnnouncement(stream apiclient.ConfigManagementPlu
return fmt.Errorf("illegal appPath: out of workDir bound")
}
repoResponse, err := getParametersAnnouncement(bufferedCtx, appPath, s.initConstants.PluginConfig.Spec.Parameters.Static, s.initConstants.PluginConfig.Spec.Parameters.Dynamic)
repoResponse, err := getParametersAnnouncement(bufferedCtx, appPath, s.initConstants.PluginConfig.Spec.Parameters.Static, s.initConstants.PluginConfig.Spec.Parameters.Dynamic, metadata.GetEnv())
if err != nil {
return fmt.Errorf("get parameters announcement error: %w", err)
}
@@ -367,11 +407,12 @@ func (s *Service) GetParametersAnnouncement(stream apiclient.ConfigManagementPlu
return nil
}
func getParametersAnnouncement(ctx context.Context, appDir string, announcements []*repoclient.ParameterAnnouncement, command Command) (*apiclient.ParametersAnnouncementResponse, error) {
func getParametersAnnouncement(ctx context.Context, appDir string, announcements []*repoclient.ParameterAnnouncement, command Command, envEntries []*apiclient.EnvEntry) (*apiclient.ParametersAnnouncementResponse, error) {
augmentedAnnouncements := announcements
if len(command.Command) > 0 {
stdout, err := runCommand(ctx, command, appDir, os.Environ())
env := append(os.Environ(), environ(envEntries)...)
stdout, err := runCommand(ctx, command, appDir, env)
if err != nil {
return nil, fmt.Errorf("error executing dynamic parameter output command: %w", err)
}

View File

@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"os"
"os/exec"
"path"
"path/filepath"
"testing"
@@ -99,7 +100,7 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
// then
assert.NoError(t, err)
@@ -114,7 +115,7 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
// then
assert.NoError(t, err)
@@ -129,7 +130,7 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
_, _, err := f.service.matchRepository(context.Background(), f.path, f.env)
_, _, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
// then
assert.ErrorContains(t, err, "syntax error")
@@ -144,7 +145,7 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
// then
assert.NoError(t, err)
@@ -161,7 +162,7 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
// then
assert.NoError(t, err)
@@ -178,7 +179,7 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
_, _, err := f.service.matchRepository(context.Background(), f.path, f.env)
_, _, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
// then
assert.ErrorContains(t, err, "error finding glob match for pattern")
@@ -195,7 +196,7 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
// then
assert.NoError(t, err)
@@ -214,7 +215,7 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
// then
assert.NoError(t, err)
assert.False(t, match)
@@ -232,7 +233,7 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
// then
assert.NoError(t, err)
@@ -252,7 +253,7 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
// then
assert.NoError(t, err)
@@ -271,7 +272,7 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
// then
assert.Error(t, err)
@@ -284,7 +285,7 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
// then
assert.NoError(t, err)
@@ -368,6 +369,28 @@ func TestRunCommandEmptyCommand(t *testing.T) {
assert.ErrorContains(t, err, "Command is empty")
}
// TestRunCommandContextTimeoutWithGracefulTermination makes sure that the process is given enough time to cleanup before sending SIGKILL.
func TestRunCommandContextTimeoutWithCleanup(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 900*time.Millisecond)
defer cancel()
// Use a subshell so there's a child command.
// This command sleeps for 4 seconds which is currently less than the 5 second delay between SIGTERM and SIGKILL signal and then exits successfully.
command := Command{
Command: []string{"sh", "-c"},
Args: []string{`(trap 'echo "cleanup completed"; exit' TERM; sleep 4)`},
}
before := time.Now()
output, 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)
// The command should still have completed the cleanup after termination.
assert.Contains(t, output, "cleanup completed")
}
func Test_getParametersAnnouncement_empty_command(t *testing.T) {
staticYAML := `
- name: static-a
@@ -380,7 +403,7 @@ func Test_getParametersAnnouncement_empty_command(t *testing.T) {
Command: []string{"echo"},
Args: []string{`[]`},
}
res, err := getParametersAnnouncement(context.Background(), "", *static, command)
res, err := getParametersAnnouncement(context.Background(), "", *static, command, []*apiclient.EnvEntry{})
require.NoError(t, err)
assert.Equal(t, []*repoclient.ParameterAnnouncement{{Name: "static-a"}, {Name: "static-b"}}, res.ParameterAnnouncements)
}
@@ -394,7 +417,7 @@ func Test_getParametersAnnouncement_no_command(t *testing.T) {
err := yaml.Unmarshal([]byte(staticYAML), static)
require.NoError(t, err)
command := Command{}
res, err := getParametersAnnouncement(context.Background(), "", *static, command)
res, err := getParametersAnnouncement(context.Background(), "", *static, command, []*apiclient.EnvEntry{})
require.NoError(t, err)
assert.Equal(t, []*repoclient.ParameterAnnouncement{{Name: "static-a"}, {Name: "static-b"}}, res.ParameterAnnouncements)
}
@@ -411,7 +434,7 @@ func Test_getParametersAnnouncement_static_and_dynamic(t *testing.T) {
Command: []string{"echo"},
Args: []string{`[{"name": "dynamic-a"}, {"name": "dynamic-b"}]`},
}
res, err := getParametersAnnouncement(context.Background(), "", *static, command)
res, err := getParametersAnnouncement(context.Background(), "", *static, command, []*apiclient.EnvEntry{})
require.NoError(t, err)
expected := []*repoclient.ParameterAnnouncement{
{Name: "dynamic-a"},
@@ -427,7 +450,7 @@ func Test_getParametersAnnouncement_invalid_json(t *testing.T) {
Command: []string{"echo"},
Args: []string{`[`},
}
_, err := getParametersAnnouncement(context.Background(), "", []*repoclient.ParameterAnnouncement{}, command)
_, err := getParametersAnnouncement(context.Background(), "", []*repoclient.ParameterAnnouncement{}, command, []*apiclient.EnvEntry{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "unexpected end of JSON input")
}
@@ -437,7 +460,7 @@ func Test_getParametersAnnouncement_bad_command(t *testing.T) {
Command: []string{"exit"},
Args: []string{"1"},
}
_, err := getParametersAnnouncement(context.Background(), "", []*repoclient.ParameterAnnouncement{}, command)
_, err := getParametersAnnouncement(context.Background(), "", []*repoclient.ParameterAnnouncement{}, command, []*apiclient.EnvEntry{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "error executing dynamic parameter output command")
}
@@ -729,16 +752,17 @@ func TestService_GetParametersAnnouncement(t *testing.T) {
require.NoError(t, err)
t.Run("successful response", func(t *testing.T) {
s, err := NewMockParametersAnnouncementStream("./testdata/kustomize", "./testdata/kustomize", nil)
s, err := NewMockParametersAnnouncementStream("./testdata/kustomize", "./testdata/kustomize", []string{"MUST_BE_SET=yep"})
require.NoError(t, err)
err = service.GetParametersAnnouncement(s)
require.NoError(t, err)
require.NotNil(t, s.response)
require.Len(t, s.response.ParameterAnnouncements, 1)
assert.Equal(t, repoclient.ParameterAnnouncement{Name: "test-param", String_: "test-value"}, *s.response.ParameterAnnouncements[0])
require.Len(t, s.response.ParameterAnnouncements, 2)
assert.Equal(t, repoclient.ParameterAnnouncement{Name: "dynamic-test-param", String_: "yep"}, *s.response.ParameterAnnouncements[0])
assert.Equal(t, repoclient.ParameterAnnouncement{Name: "test-param", String_: "test-value"}, *s.response.ParameterAnnouncements[1])
})
t.Run("out of bounds app", func(t *testing.T) {
s, err := NewMockParametersAnnouncementStream("./testdata/kustomize", "./testdata/kustomize", nil)
s, err := NewMockParametersAnnouncementStream("./testdata/kustomize", "./testdata/kustomize", []string{"MUST_BE_SET=yep"})
require.NoError(t, err)
// set a malicious app path on the metadata
s.metadataRequest.Request.(*apiclient.AppStreamRequest_Metadata).Metadata.AppRelPath = "../out-of-bounds"
@@ -746,4 +770,38 @@ func TestService_GetParametersAnnouncement(t *testing.T) {
require.ErrorContains(t, err, "illegal appPath")
require.Nil(t, s.response)
})
t.Run("fails when script fails", func(t *testing.T) {
s, err := NewMockParametersAnnouncementStream("./testdata/kustomize", "./testdata/kustomize", []string{"WRONG_ENV_VAR=oops"})
require.NoError(t, err)
err = service.GetParametersAnnouncement(s)
require.ErrorContains(t, err, "error executing dynamic parameter output command")
require.Nil(t, s.response)
})
}
func Test_getCommandArgsToLog(t *testing.T) {
testCases := []struct {
name string
args []string
expected string
}{
{
name: "no spaces",
args: []string{"sh", "-c", "cat"},
expected: "sh -c cat",
},
{
name: "spaces",
args: []string{"sh", "-c", `echo "hello world"`},
expected: `sh -c "echo \"hello world\""`,
},
}
for _, tc := range testCases {
tcc := tc
t.Run(tcc.name, func(t *testing.T) {
t.Parallel()
assert.Equal(t, tcc.expected, getCommandArgsToLog(exec.Command(tcc.args[0], tcc.args[1:]...)))
})
}
}

View File

@@ -14,3 +14,7 @@ func newSysProcAttr(setpgid bool) *syscall.SysProcAttr {
func sysCallKill(pid int) error {
return syscall.Kill(pid, syscall.SIGKILL)
}
func sysCallTerm(pid int) error {
return syscall.Kill(pid, syscall.SIGTERM)
}

View File

@@ -14,3 +14,7 @@ func newSysProcAttr(setpgid bool) *syscall.SysProcAttr {
func sysCallKill(pid int) error {
return nil
}
func sysCallTerm(pid int) error {
return nil
}

View File

@@ -5,9 +5,15 @@ metadata:
spec:
version: v1.0
init:
command: [kustomize, version]
command: [sh, -c]
args:
- |
kustomize version
generate:
command: [sh, -c, "kustomize build"]
command: [sh, -c]
args:
- |
kustomize build
discover:
find:
command: [sh, -c, find . -name kustomization.yaml]
@@ -16,3 +22,12 @@ spec:
static:
- name: test-param
string: test-value
dynamic:
command: [sh, -c]
args:
- |
# Make sure env vars are making it to the plugin.
if [ -z "$MUST_BE_SET" ]; then
exit 1
fi
echo "[{\"name\": \"dynamic-test-param\", \"string\": \"$MUST_BE_SET\"}]"

View File

@@ -8,6 +8,8 @@ import (
"time"
"github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// Default service addresses and URLS of Argo CD internal services
@@ -303,16 +305,21 @@ const (
// Security severity logging
const (
SecurityField = "security"
SecurityCWEField = "CWE"
SecurityEmergency = 5 // Indicates unmistakably malicious events that should NEVER occur accidentally and indicates an active attack (i.e. brute forcing, DoS)
SecurityCritical = 4 // Indicates any malicious or exploitable event that had a side effect (i.e. secrets being left behind on the filesystem)
SecurityHigh = 3 // Indicates likely malicious events but one that had no side effects or was blocked (i.e. out of bounds symlinks in repos)
SecurityMedium = 2 // Could indicate malicious events, but has a high likelihood of being user/system error (i.e. access denied)
SecurityLow = 1 // Unexceptional entries (i.e. successful access logs)
SecurityField = "security"
// SecurityCWEField is the logs field for the CWE associated with a log line. CWE stands for Common Weakness Enumeration. See https://cwe.mitre.org/
SecurityCWEField = "CWE"
SecurityCWEIncompleteCleanup = 459
SecurityCWEMissingReleaseOfFileDescriptor = 775
SecurityEmergency = 5 // Indicates unmistakably malicious events that should NEVER occur accidentally and indicates an active attack (i.e. brute forcing, DoS)
SecurityCritical = 4 // Indicates any malicious or exploitable event that had a side effect (i.e. secrets being left behind on the filesystem)
SecurityHigh = 3 // Indicates likely malicious events but one that had no side effects or was blocked (i.e. out of bounds symlinks in repos)
SecurityMedium = 2 // Could indicate malicious events, but has a high likelihood of being user/system error (i.e. access denied)
SecurityLow = 1 // Unexceptional entries (i.e. successful access logs)
)
// Common error messages
const TokenVerificationError = "failed to verify the token"
var TokenVerificationErr = errors.New(TokenVerificationError)
var PermissionDeniedAPIError = status.Error(codes.PermissionDenied, "permission denied")

View File

@@ -1469,6 +1469,13 @@ func resourceStatusKey(res appv1.ResourceStatus) string {
return strings.Join([]string{res.Group, res.Kind, res.Namespace, res.Name}, "/")
}
func currentSourceEqualsSyncedSource(app *appv1.Application) bool {
if app.Spec.HasMultipleSources() {
return app.Spec.Sources.Equals(app.Status.Sync.ComparedTo.Sources)
}
return app.Spec.Source.Equals(app.Status.Sync.ComparedTo.Source)
}
// needRefreshAppStatus answers if application status needs to be refreshed.
// Returns true if application never been compared, has changed or comparison result has expired.
// Additionally returns whether full refresh was requested or not.
@@ -1487,14 +1494,12 @@ func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application,
refreshType = requestedType
reason = fmt.Sprintf("%s refresh requested", refreshType)
} else {
if app.Spec.HasMultipleSources() {
if (len(app.Spec.Sources) != len(app.Status.Sync.ComparedTo.Sources)) || !reflect.DeepEqual(app.Spec.Sources, app.Status.Sync.ComparedTo.Sources) {
reason = "atleast one of the spec.sources differs"
compareWith = CompareWithLatestForceResolve
}
} else if !app.Spec.Source.Equals(app.Status.Sync.ComparedTo.Source) {
if !currentSourceEqualsSyncedSource(app) {
reason = "spec.source differs"
compareWith = CompareWithLatestForceResolve
if app.Spec.HasMultipleSources() {
reason = "at least one of the spec.sources differs"
}
} else if hardExpired || softExpired {
// The commented line below mysteriously crashes if app.Status.ReconciledAt is nil
// reason = fmt.Sprintf("comparison expired. reconciledAt: %v, expiry: %v", app.Status.ReconciledAt, statusRefreshTimeout)

View File

@@ -50,6 +50,7 @@ type namespacedResource struct {
type fakeData struct {
apps []runtime.Object
manifestResponse *apiclient.ManifestResponse
manifestResponses []*apiclient.ManifestResponse
managedLiveObjs map[kube.ResourceKey]*unstructured.Unstructured
namespacedResources map[kube.ResourceKey]namespacedResource
configMapData map[string]string
@@ -65,7 +66,15 @@ func newFakeController(data *fakeData) *ApplicationController {
// Mock out call to GenerateManifest
mockRepoClient := mockrepoclient.RepoServerServiceClient{}
mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(data.manifestResponse, nil)
if len(data.manifestResponses) > 0 {
for _, response := range data.manifestResponses {
mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(response, nil).Once()
}
} else {
mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(data.manifestResponse, nil)
}
mockRepoClientset := mockrepoclient.Clientset{RepoServerServiceClient: &mockRepoClient}
secret := corev1.Secret{
@@ -209,6 +218,64 @@ status:
repoURL: https://github.com/argoproj/argocd-example-apps.git
`
var fakeMultiSourceApp = `
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
uid: "123"
name: my-app
namespace: ` + test.FakeArgoCDNamespace + `
spec:
destination:
namespace: ` + test.FakeDestNamespace + `
server: https://localhost:6443
project: default
sources:
- path: some/path
helm:
valueFiles:
- $values_test/values.yaml
repoURL: https://github.com/argoproj/argocd-example-apps.git
- path: some/other/path
repoURL: https://github.com/argoproj/argocd-example-apps-fake.git
- ref: values_test
repoURL: https://github.com/argoproj/argocd-example-apps-fake-ref.git
syncPolicy:
automated: {}
status:
operationState:
finishedAt: 2018-09-21T23:50:29Z
message: successfully synced
operation:
sync:
revisions:
- HEAD
- HEAD
- HEAD
phase: Succeeded
startedAt: 2018-09-21T23:50:25Z
syncResult:
resources:
- kind: RoleBinding
message: |-
rolebinding.rbac.authorization.k8s.io/always-outofsync reconciled
rolebinding.rbac.authorization.k8s.io/always-outofsync configured
name: always-outofsync
namespace: default
status: Synced
revisions:
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
- cccccccccccccccccccccccccccccccccccccccc
sources:
- path: some/path
repoURL: https://github.com/argoproj/argocd-example-apps.git
- path: some/other/path
repoURL: https://github.com/argoproj/argocd-example-apps-fake.git
- path: some/other/path
repoURL: https://github.com/argoproj/argocd-example-apps-fake-ref.git
`
var fakeAppWithDestName = `
apiVersion: argoproj.io/v1alpha1
kind: Application
@@ -263,6 +330,10 @@ func newFakeApp() *argoappv1.Application {
return createFakeApp(fakeApp)
}
func newFakeMultiSourceApp() *argoappv1.Application {
return createFakeApp(fakeMultiSourceApp)
}
func newFakeAppWithDestMismatch() *argoappv1.Application {
return createFakeApp(fakeAppWithDestMismatch)
}
@@ -857,101 +928,133 @@ func TestSetOperationStateOnDeletedApp(t *testing.T) {
}
func TestNeedRefreshAppStatus(t *testing.T) {
ctrl := newFakeController(&fakeData{apps: []runtime.Object{}})
app := newFakeApp()
now := metav1.Now()
app.Status.ReconciledAt = &now
app.Status.Sync = argoappv1.SyncStatus{
Status: argoappv1.SyncStatusCodeSynced,
ComparedTo: argoappv1.ComparedTo{
Source: app.Spec.GetSource(),
Destination: app.Spec.Destination,
testCases := []struct {
name string
app *argoappv1.Application
}{
{
name: "single-source app",
app: newFakeApp(),
},
{
name: "multi-source app",
app: newFakeMultiSourceApp(),
},
}
// no need to refresh just reconciled application
needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour)
assert.False(t, needRefresh)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
ctrl := newFakeController(&fakeData{apps: []runtime.Object{}})
app := tc.app
now := metav1.Now()
app.Status.ReconciledAt = &now
// refresh app using the 'deepest' requested comparison level
ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil)
ctrl.requestAppRefresh(app.Name, ComparisonWithNothing.Pointer(), nil)
app.Status.Sync = argoappv1.SyncStatus{
Status: argoappv1.SyncStatusCodeSynced,
ComparedTo: argoappv1.ComparedTo{
Destination: app.Spec.Destination,
},
}
needRefresh, refreshType, compareWith := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour)
assert.True(t, needRefresh)
assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType)
assert.Equal(t, CompareWithRecent, compareWith)
if app.Spec.HasMultipleSources() {
app.Status.Sync.ComparedTo.Sources = app.Spec.Sources
} else {
app.Status.Sync.ComparedTo.Source = app.Spec.GetSource()
}
// refresh application which status is not reconciled using latest commit
app.Status.Sync = argoappv1.SyncStatus{Status: argoappv1.SyncStatusCodeUnknown}
// no need to refresh just reconciled application
needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour)
assert.False(t, needRefresh)
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour)
assert.True(t, needRefresh)
assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType)
assert.Equal(t, CompareWithLatestForceResolve, compareWith)
// refresh app using the 'deepest' requested comparison level
ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil)
ctrl.requestAppRefresh(app.Name, ComparisonWithNothing.Pointer(), nil)
{
// refresh app using the 'latest' level if comparison expired
app := app.DeepCopy()
ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil)
reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour))
app.Status.ReconciledAt = &reconciledAt
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Minute, 2*time.Hour)
assert.True(t, needRefresh)
assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType)
assert.Equal(t, CompareWithLatestForceResolve, compareWith)
}
needRefresh, refreshType, compareWith := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour)
assert.True(t, needRefresh)
assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType)
assert.Equal(t, CompareWithRecent, compareWith)
{
// refresh app using the 'latest' level if comparison expired for hard refresh
app := app.DeepCopy()
app.Status.Sync = argoappv1.SyncStatus{
Status: argoappv1.SyncStatusCodeSynced,
ComparedTo: argoappv1.ComparedTo{
Source: app.Spec.GetSource(),
Destination: app.Spec.Destination,
},
}
ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil)
reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour))
app.Status.ReconciledAt = &reconciledAt
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 2*time.Hour, 1*time.Minute)
assert.True(t, needRefresh)
assert.Equal(t, argoappv1.RefreshTypeHard, refreshType)
assert.Equal(t, CompareWithLatest, compareWith)
}
// refresh application which status is not reconciled using latest commit
app.Status.Sync = argoappv1.SyncStatus{Status: argoappv1.SyncStatusCodeUnknown}
{
app := app.DeepCopy()
// execute hard refresh if app has refresh annotation
reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour))
app.Status.ReconciledAt = &reconciledAt
app.Annotations = map[string]string{
v1alpha1.AnnotationKeyRefresh: string(argoappv1.RefreshTypeHard),
}
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour)
assert.True(t, needRefresh)
assert.Equal(t, argoappv1.RefreshTypeHard, refreshType)
assert.Equal(t, CompareWithLatestForceResolve, compareWith)
}
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour)
assert.True(t, needRefresh)
assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType)
assert.Equal(t, CompareWithLatestForceResolve, compareWith)
{
app := app.DeepCopy()
// ensure that CompareWithLatest level is used if application source has changed
ctrl.requestAppRefresh(app.Name, ComparisonWithNothing.Pointer(), nil)
// sample app source change
app.Spec.Source.Helm = &argoappv1.ApplicationSourceHelm{
Parameters: []argoappv1.HelmParameter{{
Name: "foo",
Value: "bar",
}},
}
t.Run("refresh app using the 'latest' level if comparison expired", func(t *testing.T) {
app := app.DeepCopy()
ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil)
reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour))
app.Status.ReconciledAt = &reconciledAt
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Minute, 2*time.Hour)
assert.True(t, needRefresh)
assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType)
assert.Equal(t, CompareWithLatestForceResolve, compareWith)
})
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour)
assert.True(t, needRefresh)
assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType)
assert.Equal(t, CompareWithLatestForceResolve, compareWith)
t.Run("refresh app using the 'latest' level if comparison expired for hard refresh", func(t *testing.T) {
app := app.DeepCopy()
app.Status.Sync = argoappv1.SyncStatus{
Status: argoappv1.SyncStatusCodeSynced,
ComparedTo: argoappv1.ComparedTo{
Destination: app.Spec.Destination,
},
}
if app.Spec.HasMultipleSources() {
app.Status.Sync.ComparedTo.Sources = app.Spec.Sources
} else {
app.Status.Sync.ComparedTo.Source = app.Spec.GetSource()
}
ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil)
reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour))
app.Status.ReconciledAt = &reconciledAt
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 2*time.Hour, 1*time.Minute)
assert.True(t, needRefresh)
assert.Equal(t, argoappv1.RefreshTypeHard, refreshType)
assert.Equal(t, CompareWithLatest, compareWith)
})
t.Run("execute hard refresh if app has refresh annotation", func(t *testing.T) {
app := app.DeepCopy()
reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour))
app.Status.ReconciledAt = &reconciledAt
app.Annotations = map[string]string{
v1alpha1.AnnotationKeyRefresh: string(argoappv1.RefreshTypeHard),
}
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour)
assert.True(t, needRefresh)
assert.Equal(t, argoappv1.RefreshTypeHard, refreshType)
assert.Equal(t, CompareWithLatestForceResolve, compareWith)
})
t.Run("ensure that CompareWithLatest level is used if application source has changed", func(t *testing.T) {
app := app.DeepCopy()
ctrl.requestAppRefresh(app.Name, ComparisonWithNothing.Pointer(), nil)
// sample app source change
if app.Spec.HasMultipleSources() {
app.Spec.Sources[0].Helm = &argoappv1.ApplicationSourceHelm{
Parameters: []argoappv1.HelmParameter{{
Name: "foo",
Value: "bar",
}},
}
} else {
app.Spec.Source.Helm = &argoappv1.ApplicationSourceHelm{
Parameters: []argoappv1.HelmParameter{{
Name: "foo",
Value: "bar",
}},
}
}
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour)
assert.True(t, needRefresh)
assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType)
assert.Equal(t, CompareWithLatestForceResolve, compareWith)
})
})
}
}

View File

@@ -25,6 +25,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"github.com/argoproj/argo-cd/v2/controller/metrics"
@@ -394,6 +395,20 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
return nil, fmt.Errorf("error getting custom label: %w", err)
}
clusterCacheConfig := cluster.RESTConfig()
// Controller dynamically fetches all resource types available on the cluster
// using a discovery API that may contain deprecated APIs.
// This causes log flooding when managing a large number of clusters.
// https://github.com/argoproj/argo-cd/issues/11973
// However, we can safely suppress deprecation warnings
// because we do not rely on resources with a particular API group or version.
// https://kubernetes.io/blog/2020/09/03/warnings/#customize-client-handling
//
// Completely suppress warning logs only for log levels that are less than Debug.
if log.GetLevel() < log.DebugLevel {
clusterCacheConfig.WarningHandler = rest.NoWarnings{}
}
clusterCacheOpts := []clustercache.UpdateSettingsFunc{
clustercache.SetListSemaphore(semaphore.NewWeighted(clusterCacheListSemaphoreSize)),
clustercache.SetListPageSize(clusterCacheListPageSize),
@@ -425,7 +440,7 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
clustercache.SetRetryOptions(clusterCacheAttemptLimit, clusterCacheRetryUseBackoff, isRetryableError),
}
clusterCache = clustercache.NewClusterCache(cluster.RESTConfig(), clusterCacheOpts...)
clusterCache = clustercache.NewClusterCache(clusterCacheConfig, clusterCacheOpts...)
_ = clusterCache.OnResourceUpdated(func(newRes *clustercache.Resource, oldRes *clustercache.Resource, namespaceResources map[kube.ResourceKey]*clustercache.Resource) {
toNotify := make(map[string]bool)
@@ -473,10 +488,11 @@ func (c *liveStateCache) getSyncedCluster(server string) (clustercache.ClusterCa
func (c *liveStateCache) invalidate(cacheSettings cacheSettings) {
log.Info("invalidating live state cache")
c.lock.Lock()
defer c.lock.Unlock()
c.cacheSettings = cacheSettings
for _, clust := range c.clusters {
clusters := c.clusters
c.lock.Unlock()
for _, clust := range clusters {
clust.Invalidate(clustercache.SetSettings(cacheSettings.clusterSettings))
}
log.Info("live state cache invalidated")
@@ -686,12 +702,14 @@ func (c *liveStateCache) handleModEvent(oldCluster *appv1.Cluster, newCluster *a
}
func (c *liveStateCache) handleDeleteEvent(clusterServer string) {
c.lock.Lock()
defer c.lock.Unlock()
c.lock.RLock()
cluster, ok := c.clusters[clusterServer]
c.lock.RUnlock()
if ok {
cluster.Invalidate()
c.lock.Lock()
delete(c.clusters, clusterServer)
c.lock.Unlock()
}
}

View File

@@ -1,10 +1,13 @@
package cache
import (
"context"
"errors"
"net"
"net/url"
"sync"
"testing"
"time"
apierr "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -14,8 +17,10 @@ import (
"github.com/argoproj/gitops-engine/pkg/cache"
"github.com/argoproj/gitops-engine/pkg/cache/mocks"
"github.com/stretchr/testify/mock"
"k8s.io/client-go/kubernetes/fake"
appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argosettings "github.com/argoproj/argo-cd/v2/util/settings"
)
type netError string
@@ -106,6 +111,98 @@ func TestHandleAddEvent_ClusterExcluded(t *testing.T) {
assert.Len(t, clustersCache.clusters, 0)
}
func TestHandleDeleteEvent_CacheDeadlock(t *testing.T) {
testCluster := &appv1.Cluster{
Server: "https://mycluster",
Config: appv1.ClusterConfig{Username: "bar"},
}
fakeClient := fake.NewSimpleClientset()
settingsMgr := argosettings.NewSettingsManager(context.TODO(), fakeClient, "argocd")
externalLockRef := sync.RWMutex{}
gitopsEngineClusterCache := &mocks.ClusterCache{}
clustersCache := liveStateCache{
clusters: map[string]cache.ClusterCache{
testCluster.Server: gitopsEngineClusterCache,
},
clusterFilter: func(cluster *appv1.Cluster) bool {
return true
},
settingsMgr: settingsMgr,
// Set the lock here so we can reference it later
// nolint We need to overwrite here to have access to the lock
lock: externalLockRef,
}
channel := make(chan string)
// Mocked lock held by the gitops-engine cluster cache
mockMutex := sync.RWMutex{}
// Locks to force trigger condition during test
// Condition order:
// EnsuredSynced -> Locks gitops-engine
// handleDeleteEvent -> Locks liveStateCache
// EnsureSynced via sync, newResource, populateResourceInfoHandler -> attempts to Lock liveStateCache
// handleDeleteEvent via cluster.Invalidate -> attempts to Lock gitops-engine
handleDeleteWasCalled := sync.Mutex{}
engineHoldsLock := sync.Mutex{}
handleDeleteWasCalled.Lock()
engineHoldsLock.Lock()
gitopsEngineClusterCache.On("EnsureSynced").Run(func(args mock.Arguments) {
// Held by EnsureSync calling into sync and watchEvents
mockMutex.Lock()
defer mockMutex.Unlock()
// Continue Execution of timer func
engineHoldsLock.Unlock()
// Wait for handleDeleteEvent to be called triggering the lock
// on the liveStateCache
handleDeleteWasCalled.Lock()
t.Logf("handleDelete was called, EnsureSynced continuing...")
handleDeleteWasCalled.Unlock()
// Try and obtain the lock on the liveStateCache
alreadyFailed := !externalLockRef.TryLock()
if alreadyFailed {
channel <- "DEADLOCKED -- EnsureSynced could not obtain lock on liveStateCache"
return
}
externalLockRef.Lock()
t.Logf("EnsureSynce was able to lock liveStateCache")
externalLockRef.Unlock()
}).Return(nil).Once()
gitopsEngineClusterCache.On("Invalidate").Run(func(args mock.Arguments) {
// If deadlock is fixed should be able to acquire lock here
alreadyFailed := !mockMutex.TryLock()
if alreadyFailed {
channel <- "DEADLOCKED -- Invalidate could not obtain lock on gitops-engine"
return
}
mockMutex.Lock()
t.Logf("Invalidate was able to lock gitops-engine cache")
mockMutex.Unlock()
}).Return()
go func() {
// Start the gitops-engine lock holds
go func() {
err := gitopsEngineClusterCache.EnsureSynced()
if err != nil {
assert.Fail(t, err.Error())
}
}()
// Wait for EnsureSynced to grab the lock for gitops-engine
engineHoldsLock.Lock()
t.Log("EnsureSynced has obtained lock on gitops-engine")
engineHoldsLock.Unlock()
// Run in background
go clustersCache.handleDeleteEvent(testCluster.Server)
// Allow execution to continue on clusters cache call to trigger lock
handleDeleteWasCalled.Unlock()
channel <- "PASSED"
}()
select {
case str := <-channel:
assert.Equal(t, "PASSED", str, str)
case <-time.After(5 * time.Second):
assert.Fail(t, "Ended up in deadlock")
}
}
func TestIsRetryableError(t *testing.T) {
var (
tlsHandshakeTimeoutErr net.Error = netError("net/http: TLS handshake timeout")

View File

@@ -107,7 +107,7 @@ type appStateManager struct {
persistResourceHealth bool
}
func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject) ([]*unstructured.Unstructured, map[*v1alpha1.ApplicationSource]*apiclient.ManifestResponse, error) {
func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, error) {
ts := stats.NewTimingStats()
helmRepos, err := m.db.ListHelmRepositories(context.Background())
@@ -164,7 +164,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp
}
defer io.Close(conn)
manifestInfoMap := make(map[*v1alpha1.ApplicationSource]*apiclient.ManifestResponse)
manifestInfos := make([]*apiclient.ManifestResponse, 0)
targetObjs := make([]*unstructured.Unstructured, 0)
// Store the map of all sources having ref field into a map for applications with sources field
@@ -215,20 +215,14 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp
return nil, nil, err
}
// GenerateManifest can return empty ManifestResponse without error if app has multiple sources
// and if any of the source does not have path and chart field not specified.
// In that scenario, we continue to the next source
if app.Spec.HasMultipleSources() && len(manifestInfo.Manifests) == 0 {
continue
}
targetObj, err := unmarshalManifests(manifestInfo.Manifests)
if err != nil {
return nil, nil, err
}
targetObjs = append(targetObjs, targetObj...)
manifestInfoMap[&source] = manifestInfo
manifestInfos = append(manifestInfos, manifestInfo)
}
ts.AddCheckpoint("unmarshal_ms")
@@ -238,7 +232,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp
}
logCtx = logCtx.WithField("time_ms", time.Since(ts.StartTime).Milliseconds())
logCtx.Info("getRepoObjs stats")
return targetObjs, manifestInfoMap, nil
return targetObjs, manifestInfos, nil
}
func unmarshalManifests(manifests []string) ([]*unstructured.Unstructured, error) {
@@ -399,7 +393,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
var targetObjs []*unstructured.Unstructured
now := metav1.Now()
var manifestInfoMap map[*v1alpha1.ApplicationSource]*apiclient.ManifestResponse
var manifestInfos []*apiclient.ManifestResponse
if len(localManifests) == 0 {
// If the length of revisions is not same as the length of sources,
@@ -411,7 +405,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
}
}
targetObjs, manifestInfoMap, err = m.getRepoObjs(app, sources, appLabelKey, revisions, noCache, noRevisionCache, verifySignature, project)
targetObjs, manifestInfos, err = m.getRepoObjs(app, sources, appLabelKey, revisions, noCache, noRevisionCache, verifySignature, project)
if err != nil {
targetObjs = make([]*unstructured.Unstructured, 0)
conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now})
@@ -434,9 +428,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
}
}
// empty out manifestInfoMap
for as := range manifestInfoMap {
delete(manifestInfoMap, as)
}
manifestInfos = make([]*apiclient.ManifestResponse, 0)
}
ts.AddCheckpoint("git_ms")
@@ -471,7 +463,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
failedToLoadObjs = true
}
logCtx.Debugf("Retrieved lived manifests")
logCtx.Debugf("Retrieved live manifests")
// filter out all resources which are not permitted in the application project
for k, v := range liveObjByKey {
@@ -516,12 +508,12 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
}
manifestRevisions := make([]string, 0)
for _, manifestInfo := range manifestInfoMap {
for _, manifestInfo := range manifestInfos {
manifestRevisions = append(manifestRevisions, manifestInfo.Revision)
}
// restore comparison using cached diff result if previous comparison was performed for the same revision
revisionChanged := len(manifestInfoMap) != len(sources) || !reflect.DeepEqual(app.Status.Sync.Revisions, manifestRevisions)
revisionChanged := len(manifestInfos) != len(sources) || !reflect.DeepEqual(app.Status.Sync.Revisions, manifestRevisions)
specChanged := !reflect.DeepEqual(app.Status.Sync.ComparedTo, appv1.ComparedTo{Source: app.Spec.GetSource(), Destination: app.Spec.Destination, Sources: sources})
_, refreshRequested := app.IsRefreshRequested()
@@ -688,7 +680,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
// Git has already performed the signature verification via its GPG interface, and the result is available
// in the manifest info received from the repository server. We now need to form our opinion about the result
// and stop processing if we do not agree about the outcome.
for _, manifestInfo := range manifestInfoMap {
for _, manifestInfo := range manifestInfos {
if gpg.IsGPGEnabled() && verifySignature && manifestInfo != nil {
conditions = append(conditions, verifyGnuPGSignature(manifestInfo.Revision, project, manifestInfo)...)
}
@@ -705,11 +697,11 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
}
if hasMultipleSources {
for _, manifestInfo := range manifestInfoMap {
for _, manifestInfo := range manifestInfos {
compRes.appSourceTypes = append(compRes.appSourceTypes, appv1.ApplicationSourceType(manifestInfo.SourceType))
}
} else {
for _, manifestInfo := range manifestInfoMap {
for _, manifestInfo := range manifestInfos {
compRes.appSourceType = v1alpha1.ApplicationSourceType(manifestInfo.SourceType)
break
}

View File

@@ -233,6 +233,74 @@ func TestCompareAppStateExtraHook(t *testing.T) {
assert.Equal(t, 0, len(app.Status.Conditions))
}
// TestAppRevisions tests that revisions are properly propagated for a single source app
func TestAppRevisionsSingleSource(t *testing.T) {
obj1 := NewPod()
obj1.SetNamespace(test.FakeDestNamespace)
data := fakeData{
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{toJSON(t, obj1)},
Namespace: test.FakeDestNamespace,
Server: test.FakeClusterURL,
Revision: "abc123",
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
app := newFakeApp()
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, app.Spec.HasMultipleSources())
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.NotEmpty(t, compRes.syncStatus.Revision)
assert.Len(t, compRes.syncStatus.Revisions, 0)
}
// TestAppRevisions tests that revisions are properly propagated for a multi source app
func TestAppRevisionsMultiSource(t *testing.T) {
obj1 := NewPod()
obj1.SetNamespace(test.FakeDestNamespace)
data := fakeData{
manifestResponses: []*apiclient.ManifestResponse{
{
Manifests: []string{toJSON(t, obj1)},
Namespace: test.FakeDestNamespace,
Server: test.FakeClusterURL,
Revision: "abc123",
},
{
Manifests: []string{toJSON(t, obj1)},
Namespace: test.FakeDestNamespace,
Server: test.FakeClusterURL,
Revision: "def456",
},
{
Manifests: []string{},
Namespace: test.FakeDestNamespace,
Server: test.FakeClusterURL,
Revision: "ghi789",
},
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
app := newFakeMultiSourceApp()
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, app.Spec.HasMultipleSources())
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.Empty(t, compRes.syncStatus.Revision)
assert.Len(t, compRes.syncStatus.Revisions, 3)
assert.Equal(t, "abc123", compRes.syncStatus.Revisions[0])
assert.Equal(t, "def456", compRes.syncStatus.Revisions[1])
assert.Equal(t, "ghi789", compRes.syncStatus.Revisions[2])
}
func toJSON(t *testing.T, obj *unstructured.Unstructured) string {
data, err := json.Marshal(obj)
assert.NoError(t, err)

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
docs/assets/extra_info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

View File

@@ -9,16 +9,6 @@ setTimeout(function() {
caret.innerHTML = "<i class='fa fa-caret-down dropdown-caret'></i>"
caret.classList.add('dropdown-caret')
div.querySelector('.rst-current-version').appendChild(caret);
div.querySelector('.rst-current-version').addEventListener('click', function() {
const classes = container.className.split(' ');
const index = classes.indexOf('shift-up');
if (index === -1) {
classes.push('shift-up');
} else {
classes.splice(index, 1);
}
container.className = classes.join(' ');
});
}
var CSSLink = document.createElement('link');

View File

@@ -28,7 +28,7 @@ telepresence intercept argocd-server --port 8080:http --env-file .envrc.remote #
* `--port` forwards traffic of remote port http to 8080 locally (use `--port 8080:https` if argocd-server terminates TLS)
* `--env-file` writes all the environment variables of the remote pod into a local file, the variables are also set on the subprocess of the `--run` command
With this, any traffic that hits your argocd-server service in the cluster (e.g through a LB / ingress) will be forwarded to your laptop on port 8080. So that you can now start argocd-server locally to debug or test new code. If you launch argocd-server using the environment variables in `.envrc.remote`, he is able to fetch all the configmaps, secrets and so one from the cluster and transparently connect to the other microservices so that no further configuration should be neccesary and he behaves exactly the same as in the cluster.
With this, any traffic that hits your argocd-server service in the cluster (e.g. through a LB / ingress) will be forwarded to your laptop on port 8080. So that you can now start argocd-server locally to debug or test new code. If you launch argocd-server using the environment variables in `.envrc.remote`, it is able to fetch all the configmaps, secrets and so on from the cluster and transparently connect to the other microservices so that no further configuration should be necessary, and it behaves exactly the same as in the cluster.
List current status of Telepresence using:
```shell

View File

@@ -9,12 +9,7 @@ To test:
```bash
make serve-docs
```
Check for broken external links:
```bash
make lint-docs
```
Once running, you can view your locally built documentation at [http://0.0.0.0:8000/](http://0.0.0.0:8000/).
## Deploying

View File

@@ -122,9 +122,9 @@ To terminate the sync, click on the "synchronisation" then "terminate":
![Synchronization](assets/synchronization-button.png) ![Terminate](assets/terminate-button.png)
## Why Is My App Out Of Sync Even After Syncing?
## Why Is My App `Out Of Sync` Even After Syncing?
Is some cases, the tool you use may conflict with Argo CD by adding the `app.kubernetes.io/instance` label. E.g. using
In some cases, the tool you use may conflict with Argo CD by adding the `app.kubernetes.io/instance` label. E.g. using
Kustomize common labels feature.
Argo CD automatically sets the `app.kubernetes.io/instance` label and uses it to determine which resources form the app.
@@ -142,7 +142,7 @@ The default polling interval is 3 minutes (180 seconds).
You can change the setting by updating the `timeout.reconciliation` value in the [argocd-cm](https://github.com/argoproj/argo-cd/blob/2d6ce088acd4fb29271ffb6f6023dbb27594d59b/docs/operator-manual/argocd-cm.yaml#L279-L282) config map. If there are any Git changes, ArgoCD will only update applications with the [auto-sync setting](user-guide/auto_sync.md) enabled. If you set it to `0` then Argo CD will stop polling Git repositories automatically and you can only use alternative methods such as [webhooks](operator-manual/webhook.md) and/or manual syncs for deploying applications.
## Why Are My Resource Limits Out Of Sync?
## Why Are My Resource Limits `Out Of Sync`?
Kubernetes has normalized your resource limits when they are applied, and then Argo CD has then compared the version in
your generated manifests to the normalized one is Kubernetes - they won't match.
@@ -157,7 +157,7 @@ E.g.
To fix this use diffing
customizations [settings](./user-guide/diffing.md#known-kubernetes-types-in-crds-resource-limits-volume-mounts-etc).
## How Do I Fix "invalid cookie, longer than max length 4093"?
## How Do I Fix `invalid cookie, longer than max length 4093`?
Argo CD uses a JWT as the auth token. You likely are part of many groups and have gone over the 4KB limit which is set
for cookies. You can get the list of groups by opening "developer tools -> network"
@@ -224,4 +224,38 @@ resource.customizations.health.bitnami.com_SealedSecret: |
hs.status = "Healthy"
hs.message = "Controller doesn't report resource status"
return hs
```
```
## How do I fix `The order in patch list … doesn't match $setElementOrder list: …`?
An application may trigger a sync error labeled a `ComparisonError` with a message like:
> The order in patch list: [map[name:**KEY_BC** value:150] map[name:**KEY_BC** value:500] map[name:**KEY_BD** value:250] map[name:**KEY_BD** value:500] map[name:KEY_BI value:something]] doesn't match $setElementOrder list: [map[name:KEY_AA] map[name:KEY_AB] map[name:KEY_AC] map[name:KEY_AD] map[name:KEY_AE] map[name:KEY_AF] map[name:KEY_AG] map[name:KEY_AH] map[name:KEY_AI] map[name:KEY_AJ] map[name:KEY_AK] map[name:KEY_AL] map[name:KEY_AM] map[name:KEY_AN] map[name:KEY_AO] map[name:KEY_AP] map[name:KEY_AQ] map[name:KEY_AR] map[name:KEY_AS] map[name:KEY_AT] map[name:KEY_AU] map[name:KEY_AV] map[name:KEY_AW] map[name:KEY_AX] map[name:KEY_AY] map[name:KEY_AZ] map[name:KEY_BA] map[name:KEY_BB] map[name:**KEY_BC**] map[name:**KEY_BD**] map[name:KEY_BE] map[name:KEY_BF] map[name:KEY_BG] map[name:KEY_BH] map[name:KEY_BI] map[name:**KEY_BC**] map[name:**KEY_BD**]]
There are two parts to the message:
1. `The order in patch list: [`
This identifies values for items, especially items that appear multiple times:
> map[name:**KEY_BC** value:150] map[name:**KEY_BC** value:500] map[name:**KEY_BD** value:250] map[name:**KEY_BD** value:500] map[name:KEY_BI value:something]
You'll want to identify the keys that are duplicated -- you can focus on the first part, as each duplicated key will appear, once for each of its value with its value in the first list. The second list is really just
`]`
2. `doesn't match $setElementOrder list: [`
This includes all of the keys. It's included for debugging purposes -- you don't need to pay much attention to it. It will give you a hint about the precise location in the list for the duplicated keys:
> map[name:KEY_AA] map[name:KEY_AB] map[name:KEY_AC] map[name:KEY_AD] map[name:KEY_AE] map[name:KEY_AF] map[name:KEY_AG] map[name:KEY_AH] map[name:KEY_AI] map[name:KEY_AJ] map[name:KEY_AK] map[name:KEY_AL] map[name:KEY_AM] map[name:KEY_AN] map[name:KEY_AO] map[name:KEY_AP] map[name:KEY_AQ] map[name:KEY_AR] map[name:KEY_AS] map[name:KEY_AT] map[name:KEY_AU] map[name:KEY_AV] map[name:KEY_AW] map[name:KEY_AX] map[name:KEY_AY] map[name:KEY_AZ] map[name:KEY_BA] map[name:KEY_BB] map[name:**KEY_BC**] map[name:**KEY_BD**] map[name:KEY_BE] map[name:KEY_BF] map[name:KEY_BG] map[name:KEY_BH] map[name:KEY_BI] map[name:**KEY_BC**] map[name:**KEY_BD**]
`]`
In this case, the duplicated keys have been **emphasized** to help you identify the problematic keys. Many editors have the ability to highlight all instances of a string, using such an editor can help with such problems.
The most common instance of this error is with `env:` fields for `containers`.
!!! note "Dynamic applications"
It's possible that your application is being generated by a tool in which case the duplication might not be evident within the scope of a single file. If you have trouble debugging this problem, consider filing a ticket to the owner of the generator tool asking them to improve its validation and error reporting.

View File

@@ -81,7 +81,7 @@ in your Argo CD installation namespace. You can simply retrieve this password
using the `argocd` CLI:
```bash
argocd admin initial-password
argocd admin initial-password -n argocd
```
!!! warning

View File

@@ -24,7 +24,7 @@ This feature can only be enabled and used when your Argo CD is installed as a cl
### Switch resource tracking method
Also, while technically not necessary, it is strongly suggested that you switch the application tracking method from the default `label` setting to either `annotation` or `annotation+label`. The reasonsing for this is, that application names will be a composite of the namespace's name and the name of the `Application`, and this can easily exceed the 63 characters length limit imposed on label values. Annotations have a notably greater length limit.
Also, while technically not necessary, it is strongly suggested that you switch the application tracking method from the default `label` setting to either `annotation` or `annotation+label`. The reasoning for this is, that application names will be a composite of the namespace's name and the name of the `Application`, and this can easily exceed the 63 characters length limit imposed on label values. Annotations have a notably greater length limit.
To enable annotation based resource tracking, refer to the documentation about [resource tracking methods](../../user-guide/resource_tracking/)
@@ -71,6 +71,8 @@ We supply a `ClusterRole` and `ClusterRoleBinding` suitable for this purpose in
kubectl apply -f examples/k8s-rbac/argocd-server-applications/
```
`argocd-notifications-controller-rbac-clusterrole.yaml` and `argocd-notifications-controller-rbac-clusterrolebinding.yaml` are used to support notifications controller to notify apps in all namespaces.
!!! note
At some later point in time, we may make this cluster role part of the default installation manifests.

View File

@@ -6,7 +6,10 @@ metadata:
namespace: argocd
# Add this finalizer ONLY if you want these to cascade delete.
finalizers:
# The default behaviour is foreground cascading deletion
- resources-finalizer.argocd.argoproj.io
# Alternatively, you can use background cascading deletion
# - resources-finalizer.argocd.argoproj.io/background
# Add labels to your application object.
labels:
name: guestbook
@@ -114,9 +117,7 @@ spec:
# plugin specific config
plugin:
# NOTE: this field is deprecated in v2.5 and must be removed to use sidecar-based plugins.
# 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
# If the plugin is defined as a sidecar and name is not passed, the plugin will be automatically matched with the
# Application according to the plugin's discovery rules.
name: mypluginname
# environment variables passed to the plugin
@@ -148,7 +149,12 @@ spec:
# name: in-cluster
# The namespace will only be set for namespace-scoped resources that have not set a value for .metadata.namespace
namespace: guestbook
# Extra information to show in the Argo CD Application details tab
info:
- name: 'Example:'
value: 'https://example.com'
# Sync policy
syncPolicy:
automated: # automated sync by default retries failed attempts 5 times with following delays between attempts ( 5s, 10s, 20s, 40s, 80s ); retry controlled using `retry` field.
@@ -160,6 +166,7 @@ spec:
- CreateNamespace=true # Namespace Auto-Creation ensures that namespace specified as the application destination exists in the destination cluster.
- PrunePropagationPolicy=foreground # Supported policies are background, foreground and orphan.
- PruneLast=true # Allow the ability for resource pruning to happen as a final, implicit wave of a sync operation
- RespectIgnoreDifferences=true # When syncing changes, respect fields ignored by the ignoreDifferences configuration
managedNamespaceMetadata: # Sets the metadata for the application namespace. Only valid if CreateNamespace=true (see above), otherwise it's a no-op.
labels: # The labels to set on the application namespace
any: label
@@ -178,18 +185,24 @@ spec:
maxDuration: 3m # the maximum amount of time allowed for the backoff strategy
# Will ignore differences between live and desired states during the diff. Note that these configurations are not
# used during the sync process.
# used during the sync process unless the `RespectIgnoreDifferences=true` sync option is enabled.
ignoreDifferences:
# for the specified json pointers
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas
- kind: ConfigMap
jqPathExpressions:
- '.data["config.yaml"].auth'
# for the specified managedFields managers
- group: "*"
kind: "*"
managedFieldsManagers:
- kube-controller-manager
# Name and namespace are optional. If specified, they must match exactly, these are not glob patterns.
name: my-deployment
namespace: my-namespace
# RevisionHistoryLimit limits the number of items kept in the application's revision history, which is used for
# informational purposes as well as for rollbacks to previous versions. This should only be changed in exceptional

View File

@@ -110,7 +110,7 @@ spec:
server: https://kubernetes.default.svc
namespace: '{{path.basename}}'
```
(*The full example can be found [here](https://github.com/argoproj/argo-cd/tree/master/examples/applicationset/git-generator-directory/excludes).*)
(*The full example can be found [here](https://github.com/argoproj/argo-cd/tree/master/applicationset/examples/git-generator-directory/excludes).*)
This example excludes the `exclude-helm-guestbook` directory from the list of directories scanned for this `ApplicationSet` resource.
@@ -153,7 +153,7 @@ Or, a shorter way (using [path.Match](https://golang.org/pkg/path/#Match) syntax
```yaml
- path: /d/*
- path: /d/[f|g]
- path: /d/[fg]
exclude: true
```

View File

@@ -0,0 +1,43 @@
# Post Selector all generators
The Selector allows to post-filter based on generated values using the kubernetes common labelSelector format. In the example, the list generator generates a set of two application which then filter by the key value to only select the `env` with value `staging`:
## Example: List generator + Post Selector
```yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- list:
elements:
- cluster: engineering-dev
url: https://kubernetes.default.svc
env: staging
- cluster: engineering-prod
url: https://kubernetes.default.svc
env: prod
selector:
matchLabels:
env: staging
template:
metadata:
name: '{{cluster}}-guestbook'
spec:
project: default
source:
repoURL: https://github.com/argoproj-labs/applicationset.git
targetRevision: HEAD
path: examples/list-generator/guestbook/{{cluster}}
destination:
server: '{{url}}'
namespace: guestbook
```
The List generator + Post Selector generates a single set of parameters:
```yaml
- cluster: engineering-dev
url: https://kubernetes.default.svc
env: staging
```

View File

@@ -6,7 +6,7 @@ Generators are primarily based on the data source that they use to generate the
As of this writing there are eight generators:
- [List generator](Generators-List.md): The List generator allows you to target Argo CD Applications to clusters based on a fixed list of cluster name/URL values.
- [List generator](Generators-List.md): The List generator allows you to target Argo CD Applications to clusters based on a fixed list of any chosen key/value element pairs.
- [Cluster generator](Generators-Cluster.md): The Cluster generator allows you to target Argo CD Applications to clusters, based on the list of clusters defined within (and managed by) Argo CD (which includes automatically responding to cluster addition/removal events from Argo CD).
- [Git generator](Generators-Git.md): The Git generator allows you to create Applications based on files within a Git repository, or based on the directory structure of a Git repository.
- [Matrix generator](Generators-Matrix.md): The Matrix generator may be used to combine the generated parameters of two separate generators.
@@ -15,4 +15,6 @@ As of this writing there are eight generators:
- [Pull Request generator](Generators-Pull-Request.md): The Pull Request generator uses the API of an SCMaaS provider (eg GitHub) to automatically discover open pull requests within an repository.
- [Cluster Decision Resource generator](Generators-Cluster-Decision-Resource.md): The Cluster Decision Resource generator is used to interface with Kubernetes custom resources that use custom resource-specific logic to decide which set of Argo CD clusters to deploy to.
All generators can be filtered by using the [Post Selector](Generators-Post-Selector.md)
If you are new to generators, begin with the **List** and **Cluster** generators. For more advanced use cases, see the documentation for the remaining generators above.

View File

@@ -87,6 +87,10 @@ By activating Go Templating, `{{ .path }}` becomes an object. Therefore, some ch
generators' templating:
- `{{ path }}` becomes `{{ .path.path }}`
- `{{ path.basename }}` becomes `{{ .path.basename }}`
- `{{ path.basenameNormalized }}` becomes `{{ .path.basenameNormalized }}`
- `{{ path.filename }}` becomes `{{ .path.filename }}`
- `{{ path.filenameNormalized }}` becomes `{{ .path.filenameNormalized }}`
- `{{ path[n] }}` becomes `{{ index .path.segments n }}`
Here is an example:

View File

@@ -15,7 +15,7 @@ As an experimental feature, progressive syncs must be explicitly enabled, in one
1. Pass `--enable-progressive-syncs` to the ApplicationSet controller args.
1. Set `ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS=true` in the ApplicationSet controller environment variables.
1. Set `applicationsetcontroller.enable.progressive.syncs: true` in the Argo CD ConfigMap.
1. Set `applicationsetcontroller.enable.progressive.syncs: true` in the Argo CD `argocd-cmd-params-cm` ConfigMap.
## Strategies
@@ -34,7 +34,7 @@ When the ApplicationSet changes, the changes will be applied to each group of Ap
* Application groups are selected using their labels and `matchExpressions`.
* All `matchExpressions` must be true for an Application to be selected (multiple expressions match with AND behavior).
* The `In` and `NotIn` operators must match at least one value to be considered true (OR behavior).
* The `NotIn` operatorn has priority in the event that both a `NotIn` and `In` operator produce a match.
* The `NotIn` operator has priority in the event that both a `NotIn` and `In` operator produce a match.
* All Applications in each group must become Healthy before the ApplicationSet controller will proceed to update the next group of Applications.
* The number of simultaneous Application updates in a group will not exceed its `maxUpdate` parameter (default is 100%, unbounded).
* RollingSync will capture external changes outside the ApplicationSet resource, since it relies on watching the OutOfSync status of the managed Applications.

View File

@@ -7,7 +7,7 @@ metadata:
name: argocd-ssh-known-hosts-cm
data:
ssh_known_hosts: |
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf

View File

@@ -54,7 +54,7 @@ spec:
command: [sh]
args: [-c, 'echo "Initializing..."']
# The generate command runs in the Application source directory each time manifests are generated. Standard output
# must be ONLY valid YAML manifests. A non-zero exit code will fail manifest generation.
# must be ONLY valid Kubernetes Objects in either YAML or JSON. A non-zero exit code will fail manifest generation.
# Error output will be sent to the UI, so avoid printing sensitive information (such as secrets).
generate:
command: [sh, -c]
@@ -67,8 +67,8 @@ spec:
# Only one of fileName, find.glob, or find.command should be specified. If multiple are specified then only the
# first (in that order) is evaluated.
discover:
# fileName is a glob pattern (https://pkg.go.dev/path/filepath#Glob) that is applied to the repository's root
# directory (not the Application source directory). If there is a match, this plugin may be used for the repository.
# fileName is a glob pattern (https://pkg.go.dev/path/filepath#Glob) that is applied to the Application's source
# directory. If there is a match, this plugin may be used for the Application.
fileName: "./subdir/s*.yaml"
find:
# This does the same thing as fileName, but it supports double-start (nested directory) glob patterns.
@@ -123,7 +123,7 @@ spec:
While the ConfigManagementPlugin _looks like_ a Kubernetes object, it is not actually a custom resource.
It only follows kubernetes-style spec conventions.
The `generate` command must print a valid YAML stream to stdout. Both `init` and `generate` commands are executed inside the application source directory.
The `generate` command must print a valid Kubernetes YAML or JSON object stream to stdout. Both `init` and `generate` commands are executed inside the application source directory.
The `discover.fileName` is used as [glob](https://pkg.go.dev/path/filepath#Glob) pattern to determine whether an
application repository is supported by the plugin or not.
@@ -420,7 +420,7 @@ data:
init: # Optional command to initialize application source directory
command: ["sample command"]
args: ["sample args"]
generate: # Command to generate manifests YAML
generate: # Command to generate Kubernetes Objects in either YAML or JSON
command: ["sample command"]
args: ["sample args"]
lockRepo: true # Defaults to false. See below.
@@ -437,7 +437,7 @@ spec:
init: # Optional command to initialize application source directory
command: ["sample command"]
args: ["sample args"]
generate: # Command to generate manifests YAML
generate: # Command to generate Kubernetes Objects in either YAML or JSON
command: ["sample command"]
args: ["sample args"]
```

View File

@@ -77,7 +77,7 @@ spec:
```
!!! warning
By default, deleting an application will not perform a cascade delete, which would delete its resources. You must add the finalizer if you want this behaviour - which you may well not want.
Without the `resources-finalizer.argocd.argoproj.io` finalizer, deleting an application will not delete the resources it manages. To perform a cascading delete, you must add the finalizer. See [App Deletion](../user-guide/app_deletion.md#about-the-deletion-finalizer).
```yaml
metadata:
@@ -98,7 +98,7 @@ The AppProject CRD is the Kubernetes resource object representing a logical grou
It is defined by the following key pieces of information:
* `sourceRepos` reference to the repositories that applications within the project can pull manifests from.
* `destinations` reference to clusters and namespaces that applications within the project can deploy into (don't use the `name` field, only the `server` field is matched).
* `destinations` reference to clusters and namespaces that applications within the project can deploy into.
* `roles` list of entities with definitions of their access to resources within the project.
!!!warning "Projects which can deploy to the Argo CD namespace grant admin access"
@@ -416,9 +416,25 @@ data:
### SSH known host public keys
If you are connecting repositories via SSH, Argo CD will need to know the SSH known hosts public key of the repository servers. You can manage the SSH known hosts data in the ConfigMap named `argocd-ssh-known-hosts-cm`. This ConfigMap contains a single key/value pair, with `ssh_known_hosts` as the key and the actual public keys of the SSH servers as data. As opposed to TLS configuration, the public key(s) of each single repository server Argo CD will connect via SSH must be configured, otherwise the connections to the repository will fail. There is no fallback. The data can be copied from any existing `ssh_known_hosts` file, or from the output of the `ssh-keyscan` utility. The basic format is `<servername> <keydata>`, one entry per line.
If you are configuring repositories to use SSH, Argo CD will need to know their SSH public keys. In order for Argo CD to connect via SSH the public key(s) for each repository server must be pre-configured in Argo CD (unlike TLS configuration), otherwise the connections to the repository will fail.
An example ConfigMap object:
You can manage the SSH known hosts data in the `argocd-ssh-known-hosts-cm` ConfigMap. This ConfigMap contains a single entry, `ssh_known_hosts`, with the public keys of the SSH servers as its value. The value can be filled in from any existing `ssh_known_hosts` file, or from the output of the `ssh-keyscan` utility (which is part of OpenSSH's client package). The basic format is `<server_name> <keytype> <base64-encoded_key>`, one entry per line.
Here is an example of running `ssh-keyscan`:
```bash
$ for host in bitbucket.org github.com gitlab.com ssh.dev.azure.com vs-ssh.visualstudio.com ; do ssh-keyscan $host 2> /dev/null ; done
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
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
```
Here is an example `ConfigMap` object using the output from `ssh-keyscan` above:
```yaml
apiVersion: v1
@@ -431,7 +447,7 @@ metadata:
app.kubernetes.io/part-of: argocd
data:
ssh_known_hosts: |
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf

View File

@@ -19,7 +19,7 @@ The configuration for Deep Links is present in `argocd-cm` as `<location>.links`
Each link in the list has five subfields :
1. `title` : title/tag that will be displayed in the UI corresponding to that link
2. `url` : the actual URL where the deep link will redirect to, this field can be templated to use data from the
corresponing application, project or resource objects (depending on where it is located). This uses [text/template](pkg.go.dev/text/template) pkg for templating
corresponding application, project or resource objects (depending on where it is located). This uses [text/template](pkg.go.dev/text/template) pkg for templating
3. `description` (optional) : a description for what the deep link is about
4. `icon.class` (optional) : a font-awesome icon class to be used when displaying the links in dropdown menus
5. `if` (optional) : a conditional statement that results in either `true` or `false`, it also has access to the same
@@ -60,4 +60,4 @@ An example `argocd-cm.yaml` file with deep links and their variations :
- url: https://mycompany.splunk.com?search={{.metadata.namespace}}
title: Splunk
if: kind == "Pod" || kind == "Deployment"
```
```

View File

@@ -15,13 +15,13 @@ export VERSION=v1.0.1
Export to a backup:
```bash
docker run -v ~/.kube:/home/argocd/.kube --rm argoproj/argocd:$VERSION argocd admin export > backup.yaml
docker run -v ~/.kube:/home/argocd/.kube --rm quay.io/argoproj/argocd:$VERSION argocd admin export > backup.yaml
```
Import from a backup:
```bash
docker run -i -v ~/.kube:/home/argocd/.kube --rm argoproj/argocd:$VERSION argocd admin import - < backup.yaml
docker run -i -v ~/.kube:/home/argocd/.kube --rm quay.io/argoproj/argocd:$VERSION argocd admin import - < backup.yaml
```
!!! note

View File

@@ -5,7 +5,7 @@ Argo CD provides built-in health assessment for several standard Kubernetes type
surfaced to the overall Application health status as a whole. The following checks are made for
specific types of kubernetes resources:
### Deployment, ReplicaSet, StatefulSet DaemonSet
### Deployment, ReplicaSet, StatefulSet, DaemonSet
* Observed generation is equal to desired generation.
* Number of **updated** replicas equals the number of desired replicas.
@@ -114,12 +114,13 @@ In order to prevent duplication of the custom health check for potentially multi
```yaml
resource.customizations: |
*.aws.crossplane.io/*:
"*.aws.crossplane.io/*":
health.lua: |
...
```
!!!important
Please note the required quotes in the resource customization health section, if the wildcard starts with `*`.
The `obj` is a global variable which contains the resource. The script must return an object with status and optional message field.
The custom health check might return one of the following health statuses:

View File

@@ -1,10 +1,8 @@
# High Availability
Argo CD is largely stateless, all data is persisted as Kubernetes objects, which in turn is stored in Kubernetes' etcd. Redis is only used as a throw-away cache and can be lost. When lost, it will be rebuilt without loss of service.
Argo CD is largely stateless. All data is persisted as Kubernetes objects, which in turn is stored in Kubernetes' etcd. Redis is only used as a throw-away cache and can be lost. When lost, it will be rebuilt without loss of service.
A set of HA manifests are provided for users who wish to run Argo CD in a highly available manner. This runs more containers, and runs Redis in HA mode.
[Manifests ⧉](https://github.com/argoproj/argo-cd/tree/master/manifests)
A set of [HA manifests](https://github.com/argoproj/argo-cd/tree/master/manifests/ha) are provided for users who wish to run Argo CD in a highly available manner. This runs more containers, and runs Redis in HA mode.
> **NOTE:** The HA installation will require at least three different nodes due to pod anti-affinity roles in the
> specs. Additionally, IPv6 only clusters are not supported.
@@ -17,11 +15,11 @@ A set of HA manifests are provided for users who wish to run Argo CD in a highly
The `argocd-repo-server` is responsible for cloning Git repository, keeping it up to date and generating manifests using the appropriate tool.
* `argocd-repo-server` fork/exec config management tool to generate manifests. The fork can fail due to lack of memory and limit on the number of OS threads.
The `--parallelismlimit` flag controls how many manifests generations are running concurrently and allows avoiding OOM kills.
* `argocd-repo-server` fork/exec config management tool to generate manifests. The fork can fail due to lack of memory or limit on the number of OS threads.
The `--parallelismlimit` flag controls how many manifests generations are running concurrently and helps avoid OOM kills.
* the `argocd-repo-server` ensures that repository is in the clean state during the manifest generation using config management tools such as Kustomize, Helm
or custom plugin. As a result Git repositories with multiple applications might be affect repository server performance.
or custom plugin. As a result Git repositories with multiple applications might affect repository server performance.
Read [Monorepo Scaling Considerations](#monorepo-scaling-considerations) for more information.
* `argocd-repo-server` clones repository into `/tmp` ( of path specified in `TMPDIR` env variable ). Pod might run out of disk space if have too many repository
@@ -30,7 +28,7 @@ or repositories has a lot of files. To avoid this problem mount persistent volum
* `argocd-repo-server` `git ls-remote` to resolve ambiguous revision such as `HEAD`, branch or tag name. This operation is happening pretty frequently
and might fail. To avoid failed syncs use `ARGOCD_GIT_ATTEMPTS_COUNT` environment variable to retry failed requests.
* `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` 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 the 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 that this will negate the benefits 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. The value should be in Go time duration string format, for example, `2m30s`.
@@ -188,4 +186,4 @@ spec:
targetRevision: HEAD
path: my-application
# ...
```
```

View File

@@ -538,15 +538,15 @@ spec:
- secretName: secret-yourdomain-com
rules:
- host: argocd.yourdomain.com
http:
paths:
- pathType: ImplementationSpecific
path: "/*" # "*" is needed. Without this, the UI Javascript and CSS will not load properly
backend:
service:
name: argocd-server
port:
number: 80
http:
paths:
- pathType: ImplementationSpecific
path: "/*" # "*" is needed. Without this, the UI Javascript and CSS will not load properly
backend:
service:
name: argocd-server
port:
number: 80
```
If you use the version `1.21.3-gke.1600` or later, you should use the following Ingress resource:
@@ -563,15 +563,15 @@ spec:
- secretName: secret-yourdomain-com
rules:
- host: argocd.yourdomain.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: argocd-server
port:
number: 80
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: argocd-server
port:
number: 80
```
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

@@ -74,7 +74,7 @@ kind: Kustomization
namespace: argocd
resources:
- https://raw.githubusercontent.com/argoproj/argo-cd/v2.0.4/manifests/ha/install.yaml
- github.com/argoproj/argo-cd/manifests/ha/base?ref=v2.6.2
```
## Helm

View File

@@ -17,8 +17,9 @@ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/st
* Add Email username and password token to `argocd-notifications-secret` secret
```bash
export EMAIL_USER=<your-username>
export PASSWORD=<your-password>
EMAIL_USER=<your-username>
PASSWORD=<your-password>
kubectl apply -n argocd -f - << EOF
apiVersion: v1
kind: Secret

View File

@@ -58,15 +58,19 @@ metadata:
![](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:
repoURLPath: "{{.app.spec.source.repoURL}}"
revisionPath: "{{.app.status.operationState.syncResult.revision}}"
status:
state: success
label: "continuous-delivery/{{.app.metadata.name}}"
targetURL: "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
```
**Notes**:
- If the message is set to 140 characters or more, it will be truncated.
- If `github.repoURLPath` and `github.revisionPath` are same as above, they can be omitted.

View File

@@ -86,3 +86,13 @@ spec:
clusters:
- in-cluster
- cluster1
# By default, apps may sync to any cluster specified under the `destinations` field, even if they are not
# scoped to this project. Set the following field to `true` to restrict apps in this cluster to only clusters
# scoped to this project.
permitOnlyProjectScopedClusters: false
# When using Applications-in-any-namespace, this field determines which namespaces this AppProject permits
# Applications to reside in. Details: https://argo-cd.readthedocs.io/en/stable/operator-manual/app-any-namespace/
sourceNamespaces:
- "argocd-apps-*"

View File

@@ -55,6 +55,13 @@ corresponds to the `action` path `action/extensions/DaemonSet/restart`. You can
also use glob patterns in the action path: `action/*` (or regex patterns if you have
[enabled the `regex` match mode](https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/argocd-rbac-cm.yaml)).
If the resource is not under a group (for examples, Pods or ConfigMaps), then omit the group name from your RBAC
configuration:
```csv
p, example-user, applications, action//Pod/maintenance-off, default/*, allow
```
#### The `exec` resource
`exec` is a special resource. When enabled with the `create` action, this privilege allows a user to `exec` into Pods via
@@ -64,7 +71,7 @@ See [Web-based Terminal](web_based_terminal.md) for more info.
#### The `applicationsets` resource
[ApplicationSets](applicationset) provide a declarative way to automatically create/update/delete Applications.
[ApplicationSets](applicationset/index.md) provide a declarative way to automatically create/update/delete Applications.
Granting `applicationsets, create` effectively grants the ability to create Applications. While it doesn't allow the
user to create Applications directly, they can create Applications via an ApplicationSet.

View File

@@ -15,7 +15,9 @@ argocd-repo-server [flags]
```
--allow-oob-symlinks Allow out-of-bounds symlinks in repositories (not recommended)
--default-cache-expiration duration Cache expiration default (default 24h0m0s)
--disable-helm-manifest-max-extracted-size Disable maximum size of helm manifest archives when extracted
--disable-tls Disable TLS on the gRPC endpoint
--helm-manifest-max-extracted-size string Maximum size of helm manifest archives when extracted (default "1G")
-h, --help help for argocd-repo-server
--logformat string Set the logging format. One of: text|json (default "text")
--loglevel string Set the logging level. One of: debug|info|warn|error (default "info")

View File

@@ -1,5 +1,26 @@
# v2.3 to 2.4
## Known Issues
### Broken `project` filter before 2.4.27
Argo CD 2.4.0 introduced a breaking API change, renaming the `project` filter to `projects`.
#### Impact to API clients
A similar issue applies to other API clients which communicate with the Argo CD API server via its REST API. If the
client uses the `project` field to filter projects, the filter will not be applied. **The failing project filter could
have detrimental consequences if, for example, you rely on it to list Applications to be deleted.**
#### Impact to CLI clients
CLI clients older that v2.4.0 rely on client-side filtering and are not impacted by this bug.
#### How to fix the problem
Upgrade to Argo CD >=2.4.27, >=2.5.15, or >=2.6.6. This version of Argo CD will accept both `project` and `projects` as
valid filters.
## KSonnet support is removed
Ksonnet was deprecated in [2019](https://github.com/ksonnet/ksonnet/pull/914/files) and is no longer maintained.

View File

@@ -1,5 +1,57 @@
# v2.4 to 2.5
## Known Issues
### Broken `project` filter before 2.5.15
Argo CD 2.4.0 introduced a breaking API change, renaming the `project` filter to `projects`.
#### Impact to API clients
A similar issue applies to other API clients which communicate with the Argo CD API server via its REST API. If the
client uses the `project` field to filter projects, the filter will not be applied. **The failing project filter could
have detrimental consequences if, for example, you rely on it to list Applications to be deleted.**
#### Impact to CLI clients
CLI clients older that v2.4.0 rely on client-side filtering and are not impacted by this bug.
#### How to fix the problem
Upgrade to Argo CD >=2.4.27, >=2.5.15, or >=2.6.6. This version of Argo CD will accept both `project` and `projects` as
valid filters.
### Broken matrix-nested git files generator in 2.5.14
Argo CD 2.5.14 introduced a bug in the matrix-nested git files generator. The bug only applies when the git files
generator is the second generator nested under a matrix. For example:
```yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- matrix:
generators:
- clusters: {}
- git:
repoURL: https://git.example.com/org/repo.git
revision: HEAD
files:
- path: "defaults/*.yaml"
template:
# ...
```
The nested git files generator will produce no parameters, causing the matrix generator to also produce no parameters.
This will cause the ApplicationSet to produce no Applications. If the ApplicationSet controller is
[configured with the ability to delete applications](https://argo-cd.readthedocs.io/en/latest/operator-manual/applicationset/Controlling-Resource-Modification/),
it will delete all Applications which were previously created by the ApplicationSet.
To avoid this issue, upgrade directly to >=2.5.15 or >= 2.6.6.
## Configure RBAC to account for new `applicationsets` resource
2.5 introduces a new `applicationsets` [RBAC resource](https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/#rbac-resources-and-actions).
@@ -132,3 +184,21 @@ This note is just for clarity. No action is required.
We [expected](../upgrading/2.3-2.4.md#enable-logs-rbac-enforcement) to enable logs RBAC enforcement by default in 2.5.
We have decided not to do that in the 2.x series due to disruption for users of [Project Roles](../../user-guide/projects.md#project-roles).
## `argocd app create` for old CLI versions fails with API version >=2.5.16
Starting with Argo CD 2.5.16, the API returns `PermissionDenied` instead of `NotFound` for Application `GET` requests if
the Application does not exist.
The Argo CD CLI before versions starting with version 2.5.0-rc1 and before versions 2.5.16 and 2.6.7 does a `GET`
request before the `POST` request in `argocd app create`. The command does not gracefully handle the `PermissionDenied`
response and will therefore fail to create/update the Application.
To solve the issue, upgrade the CLI to at least 2.5.16, or 2.6.7.
CLIs older than 2.5.0-rc1 are unaffected.
## Golang upgrade in 2.5.20
In 2.5.20, we upgrade the Golang version used to build Argo CD from 1.18 to 1.19. If you use Argo CD as a library, you
may need to upgrade your Go version.

View File

@@ -1,5 +1,57 @@
# v2.5 to 2.6
## Known Issues
### Broken `project` filter before 2.6.6
Argo CD 2.4.0 introduced a breaking API change, renaming the `project` filter to `projects`.
#### Impact to API clients
A similar issue applies to other API clients which communicate with the Argo CD API server via its REST API. If the
client uses the `project` field to filter projects, the filter will not be applied. **The failing project filter could
have detrimental consequences if, for example, you rely on it to list Applications to be deleted.**
#### Impact to CLI clients
CLI clients older that v2.4.0 rely on client-side filtering and are not impacted by this bug.
#### How to fix the problem
Upgrade to Argo CD >=2.4.27, >=2.5.15, or >=2.6.6. This version of Argo CD will accept both `project` and `projects` as
valid filters.
### Broken matrix-nested git files generator in 2.6.5
Argo CD 2.6.5 introduced a bug in the matrix-nested git files generator. The bug only applies when the git files
generator is the second generator nested under a matrix. For example:
```yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- matrix:
generators:
- clusters: {}
- git:
repoURL: https://git.example.com/org/repo.git
revision: HEAD
files:
- path: "defaults/*.yaml"
template:
# ...
```
The nested git files generator will produce no parameters, causing the matrix generator to also produce no parameters.
This will cause the ApplicationSet to produce no Applications. If the ApplicationSet controller is
[configured with the ability to delete applications](https://argo-cd.readthedocs.io/en/latest/operator-manual/applicationset/Controlling-Resource-Modification/),
it will delete all Applications which were previously created by the ApplicationSet.
To avoid this issue, upgrade directly to >=2.5.15 or >= 2.6.6.
## ApplicationSets: `^` behavior change in Sprig's semver functions
Argo CD 2.5 introduced [Go templating in ApplicationSets](https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/GoTemplate/). Go templates have access to the Sprig function library.
@@ -29,3 +81,17 @@ name. Argo CD v2.6 introduces support for specifying sidecar plugins by name.
Removal of argocd-cm plugin support has been delayed until 2.7 to provide a transition time for users who need to
specify plugins by name.
## `argocd app create` for old CLI versions fails with API version >=2.6.7
Starting with Argo CD 2.6.7, the API returns `PermissionDenied` instead of `NotFound` for Application `GET` requests if
the Application does not exist.
The Argo CD CLI before versions starting with version 2.5.0-rc1 and before versions 2.5.16 and 2.6.7 does a `GET`
request before the `POST` request in `argocd app create`. The command does not gracefully handle the `PermissionDenied`
response and will therefore fail to create/update the Application.
To solve the issue, upgrade the CLI to at least 2.5.16, or 2.6.7.
CLIs older than 2.5.0-rc1 are unaffected.

View File

@@ -303,7 +303,7 @@ data:
clientSecret: $oidc.okta.clientSecret
# Optional list of allowed aud claims. If omitted or empty, defaults to the clientID value above (and the
# cliCientID, if that is also specified). If you specify a list and want the clientID to be allowed, you must
# cliClientID, if that is also specified). If you specify a list and want the clientID to be allowed, you must
# explicitly include it in the list.
# Token verification will pass if any of the token's audiences matches any of the audiences in this list.
allowedAudiences:

View File

@@ -94,8 +94,9 @@ data:
```
Make sure that:
- __issuer__ ends with the correct realm (in this example _master_)
- __issuer__ on Keycloak releases older than version 17 the URL must include /auth (in this expample /auth/realms/master)
- __issuer__ on Keycloak releases older than version 17 the URL must include /auth (in this example /auth/realms/master)
- __clientID__ is set to the Client ID you configured in Keycloak
- __clientSecret__ points to the right key you created in the _argocd-secret_ Secret
- __requestedScopes__ contains the _groups_ claim if you didn't add it to the Default scopes

View File

@@ -19,7 +19,7 @@ metadata:
spec:
accessTokenSkewMillis: 120000
accessTokenTimeToLive: 1200000
authChainName: LoginService
authChainName: login-service
clientId: argocd
codeLastMileKeyName: lastmile-oidc
codeTokenSkewMilis: 60000

View File

@@ -11,5 +11,6 @@ Before effectively using Argo CD, it is necessary to understand the underlying t
* Depending on how you plan to template your applications:
* [Kustomize](https://kustomize.io)
* [Helm](https://helm.sh)
* If you're integrating with Jenkins:
* [Jenkins User Guide](https://jenkins.io)
* If you're integrating with a CI tool:
* [GitHub Actions Documentation](https://docs.github.com/en/actions)
* [Jenkins User Guide](https://www.jenkins.io/doc/book/)

View File

@@ -0,0 +1,26 @@
# Annotations and Labels used by Argo CD
## Annotations
| Annotation key | Target resource(es) | Possible values | Description |
|--------------------------------------------|---------------------|---------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| argocd.argoproj.io/application-set-refresh | ApplicationSet | `"true"` | Added when an ApplicationSet is requested to be refreshed by a webhook. The ApplicationSet controller will remove this annotation at the end of reconciliation. |
| argocd.argoproj.io/compare-options | any | [see compare options docs](compare-options.md) | Configures how an app's current state is compared to its desired state. |
| argocd.argoproj.io/hook | any | [see resource hooks docs](resource_hooks.md) | Used to configure [resource hooks](resource_hooks.md). |
| argocd.argoproj.io/hook-delete-policy | any | [see resource hooks docs](resource_hooks.md#hook-deletion-policies) | Used to set a [resource hook's deletion policy](resource_hooks.md#hook-deletion-policies). |
| argocd.argoproj.io/manifest-generate-paths | Application | [see scaling docs](../operator-manual/high_availability.md#webhook-and-manifest-paths-annotation) | Used to avoid unnecessary Application refreshes, especially in mono-repos. |
| argocd.argoproj.io/refresh | Application | `normal`, `hard` | Indicates that app needs to be refreshed. Removed by application controller after app is refreshed. Value `"hard"` means manifest cache and target cluster state cache should be invalidated before refresh. |
| argocd.argoproj.io/skip-reconcile | Application | `"true"` | Indicates to the Argo CD application controller that the Application should not be reconciled. See the [skip reconcile documentation](skip_reconcile.md) for use cases. |
| argocd.argoproj.io/sync-options | any | [see sync options docs](sync-options.md) | Provides a variety of settings to determine how an Application's resources are synced. |
| argocd.argoproj.io/sync-wave | any | [see sync waves docs](sync-waves.md) | |
| argocd.argoproj.io/tracking-id | any | any | Used by Argo CD to track resources it manages. See [resource tracking docs](resource_tracking.md) for details. |
| link.argocd.argoproj.io/{some link name} | any | An http(s) URL | Adds a link to the Argo CD UI for the resource. See [external URL docs](external-url.md) for details. |
| pref.argocd.argoproj.io/default-pod-sort | Application | [see UI customization docs](../operator-manual/ui-customization.md) | Sets the Application's default grouping mechanism. |
| pref.argocd.argoproj.io/default-view | Application | [see UI customization docs](../operator-manual/ui-customization.md) | Sets the Application's default view mode (e.g. "tree" or "list") |
## Labels
| Label key | Target resource(es) | Possible values | Description |
|--------------------------------|---------------------|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| argocd.argoproj.io/instance | Application | any | Recommended tracking label to [avoid conflicts with other tools which use `app.kubernetes.io/instance`](../faq.md#why-is-my-app-out-of-sync-even-after-syncing. |
| argocd.argoproj.io/secret-type | Secret | `cluster`, `repository`, `repo-creds` | Identifies certain types of Secrets used by Argo CD. See the [Declarative Setup docs](../operator-manual/declarative-setup.md) for details. |

View File

@@ -22,11 +22,12 @@ or
argocd app delete APPNAME
```
# Deletion Using `kubectl`
## Deletion Using `kubectl`
To perform a non-cascade delete:
To perform a non-cascade delete, make sure the finalizer is unset and then delete the app:
```bash
kubectl patch app APPNAME -p '{"metadata": {"finalizers": null}}' --type merge
kubectl delete app APPNAME
```
@@ -37,16 +38,23 @@ kubectl patch app APPNAME -p '{"metadata": {"finalizers": ["resources-finalizer
kubectl delete app APPNAME
```
# About The Deletion Finalizer
## About The Deletion Finalizer
```yaml
metadata:
finalizers:
# The default behaviour is foreground cascading deletion
- resources-finalizer.argocd.argoproj.io
# Alternatively, you can use background cascading deletion
# - resources-finalizer.argocd.argoproj.io/background
```
When deleting an Application with this finalizer, the Argo CD application controller will perform a cascading delete of the Application's resources.
Adding the finalizer enables cascading deletes when implementing [the App of Apps pattern](../operator-manual/cluster-bootstrapping.md#cascading-deletion).
The default propagation policy for cascading deletion is [foreground cascading deletion](https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion).
ArgoCD performs [background cascading deletion](https://kubernetes.io/docs/concepts/architecture/garbage-collection/#background-deletion) when `resources-finalizer.argocd.argoproj.io/background` is set.
When you invoke `argocd app delete` with `--cascade`, the finalizer is added automatically.
You can set the propagation policy with `--propagation-policy <foreground|background>`.

View File

@@ -48,40 +48,4 @@ Within ApplicationSet there exist other more powerful generators in addition to
To learn more about the ApplicationSet controller, check out [ApplicationSet documentation](../operator-manual/applicationset/index.md) to install the ApplicationSet controller alongside Argo CD.
**Note:** Starting `v2.3` of Argo CD, we don't need to install ApplicationSet Controller separately. It would be instead as part of Argo CD installation.
#### Post Selector all generators
The Selector allows to post-filter based on generated values using the kubernetes common labelSelector format. In the example, the list generator generates a set of two application which then filter by the key value to only select the `env` with value `staging`:
```yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- list:
elements:
- cluster: engineering-dev
url: https://kubernetes.default.svc
env: staging
- cluster: engineering-prod
url: https://kubernetes.default.svc
env: prod
selector:
matchLabels:
env: staging
template:
metadata:
name: '{{cluster}}-guestbook'
spec:
project: default
source:
repoURL: https://github.com/argoproj-labs/applicationset.git
targetRevision: HEAD
path: examples/list-generator/guestbook/{{cluster}}
destination:
server: '{{url}}'
namespace: guestbook
```
**Note:** Starting `v2.3` of Argo CD, we don't need to install ApplicationSet Controller separately. It would be instead as part of Argo CD installation.

View File

@@ -25,6 +25,7 @@ argocd admin dashboard [flags]
--password string Password for basic authentication to the API server
--port int Listen on given port (default 8080)
--proxy-url string If provided, this URL will be used to connect via proxy
--redis-compress string Enable this if the application controller is configured with redis compression enabled. (possible values: none, gzip) (default "none")
--request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0")
--tls-server-name string If provided, this name will be used to validate server certificate. If this is not provided, hostname used to contact the server is used.
--token string Bearer token for authentication to the API server

View File

@@ -60,14 +60,23 @@ To ignore fields owned by specific managers defined in your live resources:
```yaml
spec:
ignoreDifferences:
- group: *
kind: *
- group: "*"
kind: "*"
managedFieldsManagers:
- kube-controller-manager
```
The above configuration will ignore differences from all fields owned by `kube-controller-manager` for all resources belonging to this application.
If you have a slash `/` in your pointer path, you can use the `~1` character. For example:
```yaml
spec:
ignoreDifferences:
- kind: Node
jsonPointers: /metadata/labels/node-role.kubernetes.io~1worker
```
## System-Level Configuration
The comparison of resources with well-known issues can be customized at a system level. Ignored differences can be configured for a specified group and kind

View File

@@ -0,0 +1,28 @@
# Add extra Application info
You can add additional information to an Application on your ArgoCD dashboard.
If you wish to add clickable links, see [Add external URL](https://argo-cd.readthedocs.io/en/stable/user-guide/external-url/).
This is done by providing the 'info' field a key-value in your Application manifest.
Example:
```yaml
project: argo-demo
source:
repoURL: 'https://demo'
path: argo-demo
destination:
server: https://demo
namespace: argo-demo
info:
- name: Example:
value: >-
https://example.com
```
![External link](../assets/extra_info-1.png)
The additional information will be visible on the ArgoCD Application details page.
![External link](../assets/extra_info.png)
![External link](../assets/extra_info-2.png)

View File

@@ -33,9 +33,11 @@ flag. The flag can be repeated to support multiple values files:
argocd app set helm-guestbook --values values-production.yaml
```
!!! note
Values files must be in the same git repository as the Helm chart. The files can be in a different
location in which case it can be accessed using a relative path relative to the root directory of
the Helm chart.
Before `v2.6` of Argo CD, Values files must be in the same git repository as the Helm
chart. The files can be in a different location in which case it can be accessed using
a relative path relative to the root directory of the Helm chart.
As of `v2.6`, values files can be sourced from a separate repository than the Helm chart
by taking advantage of [multiple sources for Applications](./multiple_sources.md#helm-value-files-from-external-git-repository).
In the declarative syntax:
@@ -46,6 +48,29 @@ source:
- values-production.yaml
```
## Values
Argo CD supports the equivalent of a values file directly in the Application manifest using the `source.helm.values` key.
```
source:
helm:
values: |
ingress:
enabled: true
path: /
hosts:
- mydomain.example.com
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
labels: {}
tls:
- secretName: mydomain-tls
hosts:
- mydomain.example.com
```
## Helm Parameters
Helm has the ability to set parameter values, which override any values in
@@ -113,11 +138,14 @@ Argo CD supports many (most?) Helm hooks by mapping the Helm annotations onto Ar
| `helm.sh/hook: test-success` | Not supported. No equivalent in Argo CD. |
| `helm.sh/hook: test-failure` | Not supported. No equivalent in Argo CD. |
| `helm.sh/hook-delete-policy` | Supported. See also `argocd.argoproj.io/hook-delete-policy`). |
| `helm.sh/hook-delete-timeout` | No supported. Never used in Helm stable |
| `helm.sh/hook-delete-timeout` | Not supported. Never used in Helm stable |
| `helm.sh/hook-weight` | Supported as equivalent to `argocd.argoproj.io/sync-wave`. |
Unsupported hooks are ignored. In Argo CD, hooks are created by using `kubectl apply`, rather than `kubectl create`. This means that if the hook is named and already exists, it will not change unless you have annotated it with `before-hook-creation`.
!!! warning "Helm hooks + ArgoCD hooks"
If you define some Argo CD hooks in addition to the Helm ones, the Helm hooks will be ignored.
!!! warning "'install' vs 'upgrade' vs 'sync'"
Argo CD cannot know if it is running a first-time "install" or an "upgrade" - every operation is a "sync'. This means that, by default, apps that have `pre-install` and `pre-upgrade` will have those hooks run at the same time.

View File

@@ -303,7 +303,7 @@ You can list all configured SSH known host entries using the `argocd cert list`
```bash
$ argocd cert list --cert-type ssh
HOSTNAME TYPE SUBTYPE FINGERPRINT/SUBJECT
bitbucket.org ssh ssh-rsa SHA256:zzXQOXSRBEiUtuE8AikJYKwbHaxvSc0ojez9YXaGp1A
bitbucket.org ssh ssh-rsa SHA256:46OSHA1Rmj8E8ERTC6xkNcmGOw9oFxYr0WF6zWW8l1E
github.com ssh ssh-rsa SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8
gitlab.com ssh ecdsa-sha2-nistp256 SHA256:HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUrliXFzSnUw
gitlab.com ssh ssh-ed25519 SHA256:eUXGGm1YGsMAS7vkcx6JOJdOGHPem5gQp4taiCfCLB8

View File

@@ -321,7 +321,7 @@ stringData:
All the examples above talk about Git repositories, but the same principles apply to clusters as well.
With cluster-scoped clusters we can also restrict projects to only allow applications whose destinations belong to the
With project-scoped clusters we can also restrict projects to only allow applications whose destinations belong to the
same project. The default behavior allows for applications to be installed onto clusters which are not a part of the same
project, as the example below demonstrates:

View File

@@ -0,0 +1,11 @@
This folder contains example RBAC for Kubernetes to allow the Argo CD API
Server (`argocd-server`) to perform CRUD operations on `Application` CRs
in all namespaces on the cluster.
Applying the `ClusterRole` and `ClusterRoleBinding` grant the Argo CD API
server read and write permissions cluster-wide, which may not be what you
want. Handle with care.
Only apply these if you have installed Argo CD into the default namespace
`argocd`. Otherwise, you need to edit the cluster role binding to bind to
the service account in the correct namespace.

View File

@@ -0,0 +1,19 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: argocd-notifications-controller-cluster-apps
app.kubernetes.io/part-of: argocd
app.kubernetes.io/component: notifications-controller
name: argocd-notifications-controller-cluster-apps
rules:
- apiGroups:
- "argoproj.io"
resources:
- "applications"
verbs:
- get
- list
- watch
- update
- patch

View File

@@ -0,0 +1,16 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/name: argocd-notifications-controller-cluster-apps
app.kubernetes.io/part-of: argocd
app.kubernetes.io/component: notifications-controller
name: argocd-notifications-controller-cluster-apps
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: argocd-notifications-controller-cluster-apps
subjects:
- kind: ServiceAccount
name: argocd-notifications-controller
namespace: argocd

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