Compare commits

..

199 Commits

Author SHA1 Message Date
argo-bot
41f54aa556 Bump version to 2.4.12 2022-09-16 00:26:31 +00:00
argo-bot
540fe1b762 Bump version to 2.4.12 2022-09-16 00:26:22 +00:00
Michael Crenshaw
66ebec630a docs: decision about logs RBAC enforcement in release notes for 2.4 (#10564)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-09-15 14:42:25 -04:00
msvechla
a6b5aa2766 fix: add skip-test-tls flag to optionally skip testing for tls (#9679) (#10484)
* feat: add skip-test-tls flag to optionally skip testing for tls, fixes #9679

Signed-off-by: msvechla <m.svechla@gmail.com>

* docs: update cli documentation

Signed-off-by: msvechla <m.svechla@gmail.com>

Signed-off-by: msvechla <m.svechla@gmail.com>
2022-09-15 11:59:08 -04:00
Minchao
1ac264e9a1 docs: update description of policy.csv example in rbac.md (#10565)
Signed-off-by: Minchao <minchao.220@gmail.com>

Signed-off-by: Minchao <minchao.220@gmail.com>
2022-09-15 08:11:47 -04:00
Greg Knoblauch
128a261513 docs: Fix Broken Link in Getting Started Docs (#10585)
* Fix Broken Link

Signed-off-by: Greg Knoblauch <knoblauch.greg@gmail.com>

* Update docs/getting_started.md

Co-authored-by: asingh <11219262+ashutosh16@users.noreply.github.com>
Signed-off-by: Greg Knoblauch <knoblauch.greg@gmail.com>

Signed-off-by: Greg Knoblauch <knoblauch.greg@gmail.com>
Co-authored-by: asingh <11219262+ashutosh16@users.noreply.github.com>
2022-09-15 08:08:44 -04:00
Gerald Roncajolo
8552cc3f07 fix: update deploymentConfig's healthcheck to wait for replicationController to be Available (#10462)
* update deploymentConfig's healthcheck to wait for replicationController to be available

Signed-off-by: Roncajolo Gerald <groncajolo@softwaymedical.fr>

* Add Softway Medical to users

Signed-off-by: Roncajolo Gerald <groncajolo@softwaymedical.fr>

Signed-off-by: Roncajolo Gerald <groncajolo@softwaymedical.fr>
2022-09-14 07:21:28 +00:00
Mickaël Canévet
cb05b8fb4a docs: remove duplicate word in user-management doc (#10546)
Signed-off-by: Mickaël Canévet <mickael.canevet@jellysmack.com>

Signed-off-by: Mickaël Canévet <mickael.canevet@jellysmack.com>
2022-09-09 11:24:12 -04:00
asingh
2ca18ab5fe fix: hide terminal on the non-pod resource kind (#9980) (#10556)
Signed-off-by: ashutosh16 <11219262+ashutosh16@users.noreply.github.com>

Signed-off-by: ashutosh16 <11219262+ashutosh16@users.noreply.github.com>
2022-09-09 11:23:32 -04:00
rishabh625
e8d2d3a7e0 fix: added github and gitlab response mock and replaced external calls (#9305)
* Added mock for gitlab and github for Unit test

Signed-off-by: rishabh625 <rishabhmishra625@gmail.com>

* Added missing mock endpoint

Signed-off-by: rishabh625 <rishabhmishra625@gmail.com>

* removed println and aserted for 1 master branch

Signed-off-by: rishabh625 <rishabhmishra625@gmail.com>

* removed auth header assertion

Signed-off-by: rishabh625 <rishabhmishra625@gmail.com>

* procfile to run binaries instead go run

Signed-off-by: rishabh625 <rishabhmishra625@gmail.com>

* procfile to run binaries instead go run

Signed-off-by: rishabh625 <rishabhmishra625@gmail.com>

* reverted unintentional testdata change

Signed-off-by: rishabh625 <rishabhmishra625@gmail.com>

* Added test for branch do not exists

Signed-off-by: rishabh625 <rishabhmishra625@gmail.com>
2022-09-06 11:37:33 -04:00
Michael Crenshaw
6d348ce4a1 test: fix flaky gitea tests (#10354)
* test: fix flaky gitea tests

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

* embed test data

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

Signed-off-by: CI <michael@crenshaw.dev>
2022-09-06 09:55:27 -04:00
rishabh625
3c2683dfe9 fix: Added mock for gitea response in appset PR,SCM generator (#9400)
* fix: Added mock for gitea response

Signed-off-by: rishabh625 <rishabhmishra625@gmail.com>

* applied reviewers comment

Signed-off-by: rishabh625 <rishabhmishra625@gmail.com>
2022-09-06 09:55:05 -04:00
Jesse Suen
8aa4df6f17 fix: appset controller should preserve argocd refresh annotation (#10510)
Signed-off-by: Jesse Suen <jesse@akuity.io>

Signed-off-by: Jesse Suen <jesse@akuity.io>
2022-09-06 08:53:00 -04:00
Takumi Sue
7db5c5c589 fix: invalid error handling (#10384) (#10385)
os.IsNotExist only supports errors returned by the os package

Signed-off-by: mikutas <23391543+mikutas@users.noreply.github.com>

Signed-off-by: mikutas <23391543+mikutas@users.noreply.github.com>
2022-09-06 08:52:14 -04:00
argo-bot
3d9e9f2f95 Bump version to 2.4.11 2022-08-22 08:58:21 +00:00
argo-bot
ca7d83f645 Bump version to 2.4.11 2022-08-22 08:58:04 +00:00
jannfis
e59f4889a4 Pin gitops-engine to v0.7.3
Signed-off-by: jannfis <jann@mistrust.net>
2022-08-22 08:27:03 +00:00
jannfis
fea6197af4 fix: Correctly assume cluster-scoped resources to be self-referenced (#10390)
Signed-off-by: jannfis <jann@mistrust.net>

Signed-off-by: jannfis <jann@mistrust.net>
2022-08-18 20:38:10 +00:00
Xijun Dai
5b576acf5d docs: fix typo in upgrade notes (#10377)
Signed-off-by: Xijun Dai <daixijun1990@gmail.com>

Signed-off-by: Xijun Dai <daixijun1990@gmail.com>
2022-08-18 10:22:36 -04:00
argo-bot
2ccc17afcb Bump version to 2.4.10 2022-08-17 20:48:21 +00:00
argo-bot
e7521ed7b8 Bump version to 2.4.10 2022-08-17 20:48:17 +00:00
Michael Crenshaw
f83bed0d4b fix: missing actions (#10327) (#10359)
Signed-off-by: CI <michael@crenshaw.dev>

Signed-off-by: CI <michael@crenshaw.dev>
2022-08-17 16:33:07 -04:00
JesseBot
88274b6870 docs: Add "Create Namespace" to sync options doc (#3490) (#10326)
* Add create namespace to the sync options doc

Signed-off-by: JesseBot <jessebot@linux.com>

* Update docs/user-guide/sync-options.md

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

Signed-off-by: JesseBot <jessebot@linux.com>
Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
2022-08-17 15:12:09 -04:00
jsmcnair
431ee12282 docs: Document safe concurrent processing of sidecar CMP (#10336)
Signed-off-by: jsmcnair <john.mcnair@yellowdog.co>

Signed-off-by: jsmcnair <john.mcnair@yellowdog.co>
2022-08-15 16:06:56 -04:00
Tadayuki Onishi
3b17121d44 fix: Suppressed ssh scheme url warn log (#9836)
* Fixed ssh scheme warn log degrade by #8508
Signed-off-by: kenchan0130 <tt.tanishi100@gmail.com>

* Expanded repository type getCAPath testing
Signed-off-by: kenchan0130 <tt.tanishi100@gmail.com>
2022-08-15 12:19:01 -04:00
Michael Crenshaw
f071b29b5f fix: respect ARGOCD_GIT_MODULES_ENABLED in the appset controller (#10285) (#10287)
* fix: respect ARGOCD_GIT_MODULES_ENABLED in the appset controller (#10285)

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

* remove duplicate line

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

Signed-off-by: CI <michael@crenshaw.dev>
2022-08-12 14:47:02 -04:00
Michael Crenshaw
5ed749e827 docs: clusterResources in declarative cluster config (#10219)
* docs: clusterResources in declarative cluster config

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

* add article

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

Signed-off-by: CI <michael@crenshaw.dev>
2022-08-11 13:50:12 -04:00
argo-bot
1ba9008536 Bump version to 2.4.9 2022-08-11 15:08:32 +00:00
argo-bot
2b873f0b3a Bump version to 2.4.9 2022-08-11 15:08:25 +00:00
Michael Crenshaw
3fdb6ae960 docs: fix version reference for logs UI fix (#10245)
Signed-off-by: CI <michael@crenshaw.dev>
2022-08-09 17:27:27 -04:00
Brandon High
d40ebce7b3 docs: Document ignoreAggregatedRoles setting (#10206)
Signed-off-by: Brandon High <highb@users.noreply.github.com>
2022-08-09 12:05:01 -04:00
César M. Cristóbal
d945e9f256 docs: fix microsoft user management mapping role (#10251)
Signed-off-by: CI <michael@crenshaw.dev>
2022-08-09 10:17:18 -04:00
Sverre Boschman
fb75ada4c2 docs(applicationset): fix layout matrix/merge generator restrictions (#10246)
Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>

Signed-off-by: Sverre Boschman <1142569+sboschman@users.noreply.github.com>
2022-08-09 10:08:15 -04:00
Kerwood
05c9ba27e3 fix: Drop all references to exec unless the feature is enabled (#9920) (#10187)
* fix:  Drop all references to exec unless the feature is enabled #9920

Signed-off-by: Patrick Kerwood <patrick@kerwood.dk>

* fixed tslint issues

Signed-off-by: Patrick Kerwood <patrick@kerwood.dk>
2022-08-08 16:33:10 -04:00
reggie-k
77c972d27e fix: UI part for logs RBAC - do not display the logs tab when no RBAC in place (#7211) (#9828)
* show logs tab only upon explicit rbac allow policy

Signed-off-by: reggie-k <reginakagan@gmail.com>

* 2.4.7 docs edit

Signed-off-by: reggie-k <reginakagan@gmail.com>
2022-08-08 16:31:11 -04:00
jannfis
7e0ee5c449 fix: Ignore non-self-referencing resources while pruning (#10198)
* fix: Ignore non-self-referencing resources while pruning

Signed-off-by: jannfis <jann@mistrust.net>
2022-08-08 17:44:12 +00:00
Sahdev Zala
164284e329 docs: correct the api field description for the GitLab example (#10081)
The api field description for the GitLab example seems mistakenly
copied from the GitHub example.

Signed-off-by: Sahdev Zala <spzala@us.ibm.com>
2022-08-05 15:24:53 -04:00
Renaud Guérin
ac2c1618b2 docs: Use ConfigMap to disable TLS (#10106)
* docs: Use ConfigMap to disable TLS

Signed-off-by: Renaud Guerin <renaud@renaudguerin.net>

* Fix typo

Signed-off-by: Renaud Guerin <renaud@renaudguerin.net>
2022-08-04 17:00:15 -04:00
my-git9
4ee796604a docs: improve Installation.md (#10173)
Signed-off-by: xin.li <xin.li@daocloud.io>
2022-08-04 10:23:20 -04:00
Yves Richard
118d4d3c58 docs: fix kustomize namePrefix misconception in application.yaml (#10162)
* Update docs/operator-manual/application.yaml

- Removed comment about what namePrefix does. (i.e. it does not add a prefix to the image)
- Added examples of other supported transformers. (based on looking at the source code)
- Added link to the kustomize docs where the transormers are described in more detail.

* Update kustomize casing to be consistent

Signed-off-by: whyvez <yves@premise.com>
2022-08-03 14:40:10 -04:00
Mohamed Iflan
912fe33009 docs: Fixed indentation Error (#10123)
* Fixed indentation Error

Signed-off-by: iflan7744 <iflan_mohamed@yahoo.com>

* Fixed indentation Error for top-level data key

Signed-off-by: iflan7744 <iflan_mohamed@yahoo.com>

Co-authored-by: iflan7744 <iflan_mohamed@yahoo.com>
Signed-off-by: CI <michael@crenshaw.dev>
2022-08-01 10:40:08 -04:00
argo-bot
844f79eb9d Bump version to 2.4.8 2022-07-29 16:47:18 +00:00
argo-bot
ecfa0da491 Bump version to 2.4.8 2022-07-29 16:47:13 +00:00
Alexander Matyushentsev
fac8466e86 fix: extensions is not loading for ConfigMap/Pods (#10010)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-07-28 12:50:06 -07:00
Alexander Matyushentsev
ac34ff23c4 feat: support application level extensions (#9923)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-07-28 12:50:03 -07:00
Alexander Matyushentsev
a85d88d479 feat: support multiple extensions per resource group/kind (#9834)
* feat: support multiple extensions per resource group/kind

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

* apply reviewers suggestions

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

* apply reviewer notes: stream extension files one by one

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

* wrap errors

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

* skip symlinks

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-07-28 12:50:00 -07:00
dependabot[bot]
40075da70c chore(deps): bump moment from 2.29.3 to 2.29.4 in /ui (#9897)
Bumps [moment](https://github.com/moment/moment) from 2.29.3 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.3...2.29.4)

Signed-off-by: CI <michael@crenshaw.dev>
---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-28 15:37:25 -04:00
Snyk bot
779e383f64 fix: upgrade moment from 2.29.2 to 2.29.3 (#9330)
Snyk has created this PR to upgrade moment from 2.29.2 to 2.29.3.

See this package in npm:


See this project in Snyk:
https://app.snyk.io/org/argoproj/project/d2931792-eef9-4d7c-b9d6-c0cbd2bd4dbe?utm_source=github&utm_medium=referral&page=upgrade-pr
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-28 15:36:47 -04:00
Michael Crenshaw
3e523dbab7 fix: skip redirect url validation when it's the base href (#10058) (#10116)
* fix: skip redirect url validation when it's the base href (#10058)

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

nicer way of doing it

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

* fix missin arg

Signed-off-by: CI <michael@crenshaw.dev>
2022-07-27 16:38:05 -04:00
Michael Crenshaw
4df892fecf docs: add OpenSSH breaking change notes (#10104)
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-27 15:26:49 -04:00
Michael Crenshaw
670a1756d7 fix: avoid CVE-2022-28948 (#10093)
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-27 15:03:09 -04:00
Michael Crenshaw
5721f559f0 chore: update parse-url (#10101)
* chore: upgrade parse-url

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

* edit a generated file, because that's smart

Signed-off-by: CI <michael@crenshaw.dev>
2022-07-27 14:57:06 -04:00
Sahdev Zala
e23178a8d1 docs: add api field example in the appset security doc (#10087)
It seems like most of the work for the mentioned issue below is done
under the PR #9466 but from the issue description, it's probably
worth to mention the example as added here.

Related #9352

Signed-off-by: Sahdev Zala <spzala@us.ibm.com>
2022-07-26 09:15:31 -04:00
Hyeonmin Park
918e5eadf4 fix: Set HOST_ARCH for yarn build from platform (#10018)
Signed-off-by: Hyeonmin Park <hyeonmin.park@kennysoft.kr>
2022-07-25 12:27:29 -04:00
34FathomBelow
55de2b9dab chore: update redis to 7.0.4 avoid CVE-2022-30065 (#10059)
Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
2022-07-20 17:11:44 -04:00
Ashutosh
c48004f944 docs: add argocd-server grpc metric usage (#10007)
Signed-off-by: Ashutosh <mail.ashutosh8@gmail.com>

Co-authored-by: Ashutosh <mail.ashutosh8@gmail.com>
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-20 14:58:32 -04:00
Michael Crenshaw
f7b6a38041 chore: upgrade Dex to 2.32.0 (#10036) (#10042)
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-20 10:45:24 -04:00
Michael Crenshaw
91eb9925ef chore: update redis to avoid CVE-2022-2097 (#10031)
* chore: update redis to avoid CVE-2022-2097

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

* codegen

Signed-off-by: CI <michael@crenshaw.dev>
2022-07-20 10:38:36 -04:00
34FathomBelow
6190964899 chore: update haproxy to 2.0.29 for redis-ha (#10045)
Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
2022-07-19 15:05:40 -04:00
argo-bot
81630e6d50 Bump version to 2.4.7 2022-07-18 21:07:45 +00:00
argo-bot
e31fdb6105 Bump version to 2.4.7 2022-07-18 21:07:38 +00:00
Michael Crenshaw
2e194b1087 chore: upgrade parse-url to avoid SNYK-JS-PARSEURL-2936249 (#9826)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-07-18 14:13:15 -04:00
Jim Wright
cec5799d97 Support files in argocd.argoproj.io/manifest-generate-paths annotation (#9908)
Signed-off-by: Jim Wright <jmwri93@gmail.com>
2022-07-18 11:02:26 -04:00
Michael Crenshaw
7ab2ba361c docs: use quotes to emphasize that ConfigMap value is a string (#9995)
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-16 12:21:39 -04:00
Michael Crenshaw
1d5e15c600 fix: terminal websocket write lock to avoid races (#10011)
* fix: protect terminal WriteMessage with a lock

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

* give write its own lock

Signed-off-by: CI <michael@crenshaw.dev>
2022-07-15 21:43:38 -04:00
Michael Crenshaw
f4f52212ba docs: document directory app include/exclude fields (#9997)
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-15 21:42:58 -04:00
Michael Crenshaw
507c669259 docs: simplify Docker toolchain docs (#9966) (#10006)
* docs: simplify Docker toolchain docs (#9966)

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

* to be or not to be

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

* pin dependencies to avoid absurdity

Signed-off-by: CI <michael@crenshaw.dev>
2022-07-15 11:51:48 -04:00
Soumya Ghosh Dastidar
993459aebc fix: updated all a tags to Link tags in app summary (#9777)
* fix: updated all a tags to Link tags

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

* fix: revert external links to a tags

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

* fix: linting

Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
2022-07-15 10:17:53 -04:00
rishabh625
3293aa0bb7 fix: e2e test to use func from clusterauth instead creating one with old logic (#9989)
Signed-off-by: rishabh625 <rishabhmishra625@gmail.com>
2022-07-15 09:22:34 -04:00
Hyeonmin Park
aafb6ce0a3 fix: add missing download CLI tool URL response for ppc64le, s390x (#9983)
Signed-off-by: Hyeonmin Park <hyeonmin.park@kennysoft.kr>
2022-07-15 08:55:35 -04:00
Kostis (Codefresh)
d3d490632d docs: supported versions (#9876)
* docs: supported versions

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

* docs: supported versions feedback

Signed-off-by: Kostis Kapelonis <kostis@codefresh.io>
2022-07-13 11:09:39 -04:00
argo-bot
a48bca03c7 Bump version to 2.4.6 2022-07-12 22:19:23 +00:00
argo-bot
6930ceb414 Bump version to 2.4.6 2022-07-12 22:19:14 +00:00
CI
01b7a73922 chore: fix build error
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-12 16:46:39 -04:00
taksenov
ff2d9b918d docs: fix typo in Generators-Git.md (#9949)
`ApplictionSet` --> `ApplicationSet`
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-12 16:29:03 -04:00
Jake
cea91ce935 docs: add terminal documentation (#9948)
Signed-off-by: notfromstatefarm <86763948+notfromstatefarm@users.noreply.github.com>
2022-07-12 16:28:24 -04:00
Michael Crenshaw
51b73096f5 fix: 'unexpected reserved bits' breaking web terminal (#9605) (#9895)
* fix: 'unexpected reserved bits' breaking web terminal (#9605)

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

* make things more like they were originally, since the mutex fixes the problem

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

* fix typo, don't pass around a pointer when it isn't necessary

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

* apply suggestions

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-07-12 16:28:01 -04:00
Yuan Tang
2c166dac97 feat: Treat connection reset as a retryable error (#9739)
Signed-off-by: Yuan Tang <terrytangyuan@gmail.com>
2022-07-12 16:25:08 -04:00
jannfis
16c015f0cb test: Use dedicated multi-arch workloads in e2e tests (#9921)
* test: Use dedicated multi-arch workloads in e2e tests

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

* Use correct tag

Signed-off-by: jannfis <jann@mistrust.net>
2022-07-12 16:24:41 -04:00
Xiao Yang
7ca60cb957 fix: argocd login just hangs on 2.4.0 #9679 (#9935)
Signed-off-by: Xiao Yang <muma.378@163.com>

Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-12 16:24:23 -04:00
Jake
d0c80ee0bb fix: CMP manifest generation fails with ENHANCE_YOUR_CALM if over 40s (#9922)
* fix: CMP manifest generation fails with ENHANCE_YOUR_CALM if over 40s

Signed-off-by: notfromstatefarm <86763948+notfromstatefarm@users.noreply.github.com>

* fix timeouts across all gRPC servers

Signed-off-by: notfromstatefarm <86763948+notfromstatefarm@users.noreply.github.com>

* use common consts

Signed-off-by: notfromstatefarm <86763948+notfromstatefarm@users.noreply.github.com>
2022-07-12 16:24:00 -04:00
yongguangl
9f1a33865a fix: NotAfter is not set when ValidFor is set (#9911)
Signed-off-by: yongguangl <1363186473@qq.com>
2022-07-12 16:21:21 -04:00
Hyeonmin Park
f09c84f30a fix: add missing download CLI tool link for ppc64le, s390x (#9649)
Signed-off-by: Hyeonmin Park <hyeonmin.park@kennysoft.kr>
2022-07-12 16:21:03 -04:00
jannfis
f7f7493e9f fix: Check tracking annotation for being self-referencing (#9791)
* fix: Check tracking annotation for being self-referencing

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

* Tweak isManagedLiveObj() logic

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

* Rename isManagedLiveResource to isSelfReferencedObj

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

* Add e2e test

Signed-off-by: jannfis <jann@mistrust.net>
2022-07-12 16:20:21 -04:00
jannfis
c1ddb53d29 fix: Make change of tracking method work at runtime (#9820)
* fix: Make change of tracking method work at runtime

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

* GetAppName() will figure tracking label or annotation on its own

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

* Correct test comments and add another test

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

* Add a read lock before getting cache settings

Signed-off-by: jannfis <jann@mistrust.net>
2022-07-12 16:19:41 -04:00
Shunki
e04288482d fix: argo-cd git submodule is using SSH auth instead of HTTPs (#3118) (#9821)
* fix: argo-cd git submodule is using SSH auth instead of HTTPs (#3118)

Signed-off-by: shunki-fujita <shunki-fujita@cybozu.co.jp>

* Add submodule functions and unit tests
Signed-off-by: shunki-fujita <shunki-fujita@cybozu.co.jp>
2022-07-12 16:16:48 -04:00
YaytayAtWork
1f3e1ec803 #9429: Adding blank line so list is formatted correctly. (#9880)
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-12 16:14:05 -04:00
Jake
c3423e8df3 docs: small fix for plugin stream filtering (#9871)
Signed-off-by: notfromstatefarm <86763948+notfromstatefarm@users.noreply.github.com>
2022-07-12 16:13:45 -04:00
Didrik Finnøy
5ef48c1123 docs: Document the possibility of rendering Helm charts with Kustomize (#9841)
* Update kustomize.md

Resolves  #7835.

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

* Removed unnecessary command flag from example. Minor text edits.

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

* spelling

Signed-off-by: Didrik Finnøy <djfinnoy@protonmail.com>
2022-07-12 16:13:22 -04:00
YaytayAtWork
e3ae286e2d docs: getting started notes on self-signed cert (#9429) (#9784)
* Fix #9429: A couple of notes in the docs to explain that the default certificate is insecure.

Signed-off-by: Jim Talbut <jim.talbut@groupgti.com>

* Fixes #9429: More verbose, but complete, text for Getting Started.

Signed-off-by: Jim Talbut <jim.talbut@groupgti.com>
2022-07-12 16:12:41 -04:00
Michael Crenshaw
7abf6713b4 test: check for error messages from CI env (#9953)
test: check for error messages from CI env (#9953)

Signed-off-by: CI <michael@crenshaw.dev>
2022-07-12 15:31:44 -04:00
argo-bot
0232073ccf Bump version to 2.4.5 2022-07-12 16:08:04 +00:00
argo-bot
860d8fd7e1 Bump version to 2.4.5 2022-07-12 16:07:57 +00:00
Michael Crenshaw
147ff80543 Merge pull request from GHSA-7943-82jg-wmw5
* add tests to demonstrate issue

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

more

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

docs

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

settings tests

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

tests for OIDC handlers, consolidating test helpers

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

consolidate

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

consolidate

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

docs

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

* fix log message

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-07-12 08:46:13 -04:00
Michael Crenshaw
3800a1e49d Merge pull request from GHSA-pmjg-52h9-72qv
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

formatting

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

fixes from comments

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

fix test

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-07-12 08:45:22 -04:00
argo-bot
fe80bdcfdc Bump version to 2.4.4 2022-07-07 06:57:43 +00:00
argo-bot
94c09dff59 Bump version to 2.4.4 2022-07-07 06:57:37 +00:00
jannfis
3d9e4d439e test: Remove circular symlinks from testdata (#9886)
* test: Remove circular symlinks from testdata

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

* Another test case

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

* Use defer for changing back to original workdir

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

* Abort the test on error in defer

Signed-off-by: jannfis <jann@mistrust.net>
2022-07-06 19:18:51 +00:00
noah
4a955e25a0 docs: custom secret must be labeled (#9835)
As far as I can tell, this isn't explicitly documented anywhere (some docs mentioned this label in reference to ConfigMaps) I only figure it out by looking at the code.
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-07-01 15:55:34 -04:00
noah
4f99f251bf fix: missing path segments for git file generator (#9839)
* fix: missing path segments for git file generator

given the path:

  /one/two/file.yaml

This change adds the params:

path[1]=two
path.filename=file.yaml
path.filenameNormalized

The use case is for symmetry with other generators (e.g., merge with a directory generator using the key path[1]). As no existing parameter values are changed it should be non-breaking.

Signed-off-by: Noah Perks Sloan <noah@hackedu.io>

* fix: expose all path elements for directory generator

This makes it consistent with the files generator and removes un-intuitive behavior without any breaking change.

docs: clarify - can use either baseName or nth path element
docs: use "directory", like the name of the generator, where "folder" was mentioned
Signed-off-by: Noah Perks Sloan <noah@hackedu.io>
2022-07-01 15:54:15 -04:00
Alexander Matyushentsev
fd418cec0d fix: make sure api server informer does not stop after setting change (#9842)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-06-30 15:30:33 -07:00
Xiao Yang
dc291a629f fix: support resource logs and exec (#9833)
Signed-off-by: Xiao Yang <muma.378@163.com>
2022-06-30 09:07:00 -04:00
Paulo Coelho
e23a1c6026 docs: update archlinux install with official package (#9718)
Signed-off-by: Paulo Coelho <prscoelho@protonmail.com>
2022-06-29 16:38:21 -04:00
Chris Reilly
aee88c6452 docs: explain rightmost git generator path parameter behavior (#9799)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-29 16:31:15 -04:00
KevinSnyderCodes
3f111cc640 git: prune any deleted refs before fetching (#9504)
* git: prune any deleted refers before fetching

This commit modifies `nativeGitClient.Fetch()` to call `git remote prune origin` before fetching refs.

In some cases, an old branch may exist that conflicts with the name of a new branch. The old branch will have been deleted from `origin` but still exist locally in the `argocd-repo-server`.

Example: an old branch `feature/foo` conflicts with a new branch `feature/foo/bar`

In these cases, syncing an application results in the error:

```
rpc error: code = Internal desc = Failed to fetch default: `git fetch origin --tags --force` failed exit status 1: error: cannot lock ref 'refs/remotes/origin/feature/foo/bar': 'refs/remotes/origin/feature/foo' exists; cannot create 'refs/remotes/origin/feature/foo/bar' From https://github.com/org/repo ! [new branch] feature/foo/bar -> origin/feature/foo/bar (unable to update local ref) error: some local refs could not be updated; try running 'git remote prune origin' to remove any old, conflicting branches
```

Adding `git remote prune origin` before fetching, as recommended by the error message, should fix this issue.

The current workaround is to restart the `argocd-repo-server` which should flush the local repository folder. This works when Argo CD is installed using the Helm chart.

Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com>

* fix: added extra protection to syncing app with replace (#9187)

* fix: added extra protection to syncing app with replace

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

* Code clean up

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

* Updated logic for isAppOfAppsPattern

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

* Updated text strings as per comment

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

* Fixed lint issue

Signed-off-by: ciiay <yicai@redhat.com>
Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com>

* chore: Simplified GetRepoHTTPClient function (#9396)

* chore: Simplified GetRepoHTTPClient function

Signed-off-by: ls0f <lovedboy.tk@qq.com>

* simplified code and improve unit test coverage

Signed-off-by: ls0f <lovedboy.tk@qq.com>
Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com>

* Only prune if fetch error message indicates that it is worthwhile, add unit tests

Confirmed that `Test_nativeGitClient_Fetch_Prune` fails without the bug fix, succeeds with it.

Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com>

* fix: avoid k8s call before authorization for terminal endpoint (#9434)

* fix: avoid k8s API call before authorization in k8s endpoint

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

* check for bad project

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

* lint

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

* more logging

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

* handle 404, return 500 instead of 400 for other errors

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

* use user input

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

* refactor validation

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

* fix tests

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

* fixes, tests

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com>

* Match against "try running 'git remote prune origin'"

Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com>

Co-authored-by: Yi Cai <yicai@redhat.com>
Co-authored-by: ls0f <lovedboy.tk@qq.com>
Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-29 16:28:51 -04:00
Jake
596038fc0f fix: configurable CMP tar exclusions (#9675) (#9789)
* feat: configurable CMP tar exclusions

Signed-off-by: notfromstatefarm <86763948+notfromstatefarm@users.noreply.github.com>

* rename cmp to plugin

Signed-off-by: notfromstatefarm <86763948+notfromstatefarm@users.noreply.github.com>

* add test for tar stream exclusions

Signed-off-by: notfromstatefarm <86763948+notfromstatefarm@users.noreply.github.com>

* fix tests

Signed-off-by: notfromstatefarm <86763948+notfromstatefarm@users.noreply.github.com>

* update cmp guide

Signed-off-by: notfromstatefarm <86763948+notfromstatefarm@users.noreply.github.com>

* fully parameterize

Signed-off-by: notfromstatefarm <86763948+notfromstatefarm@users.noreply.github.com>
2022-06-29 16:27:41 -04:00
argo-bot
471685feae Bump version to 2.4.3 2022-06-27 20:53:14 +00:00
argo-bot
42e1f29117 Bump version to 2.4.3 2022-06-27 20:53:07 +00:00
Michael Crenshaw
c089f9a5e5 fix: respect OIDC providers' supported token signing algorithms (#9433) (#9761)
* fix: respect OIDC providers' supported token signing algorithms (#9433)

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

* go mod tidy

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-27 16:32:35 -04:00
TomHellier
1dc5e6aaf9 fix: websockets for terminal not working on subPath (#9795)
Signed-off-by: Tom Hellier <me@tomhellier.com>
2022-06-27 13:26:11 -07:00
Alexander Matyushentsev
82726fcbcf fix: avoid closing and re-opening port of api server settings change (#9778)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-06-24 10:17:20 -07:00
Nicolas Fillot
e715e085aa [ArgoCD] Fixing webhook typo in case of error in GetManifests (#9671)
Signed-off-by: Nicolas Fillot <nfillot@weborama.com>

Co-authored-by: Nicolas Fillot <nfillot@weborama.com>
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-23 09:27:15 -04:00
Michael Crenshaw
7db5ab71b0 fix: overrides should not appear in the manifest cache key (#9601)
* fix: overrides should not appear in the manifest cache key

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

* fix Helm regression

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

* fix test

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

* fix test again

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-22 09:24:29 -04:00
argo-bot
c6d0c8baaa Bump version to 2.4.2 2022-06-21 20:32:13 +00:00
argo-bot
2115bf7746 Bump version to 2.4.2 2022-06-21 20:32:08 +00:00
Yaakov Selkowitz
0a2520f511 test/remote: Allow override of base image (#9734)
ubuntu:22.04 bumped the ppc64el baseline to POWER9, rendering this
unusable on existing POWER8 systems.  This allows customization similar
to the top-level Dockerfile.

Signed-off-by: Yaakov Selkowitz <yselkowi@redhat.com>
2022-06-21 15:24:13 -04:00
Soumya Ghosh Dastidar
211e9f6127 fix: updated config file permission requirements for windows (#9732)
* fix: reduced config file permission restriction on windows

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

* fix: updated localconfig tests to check error

Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
2022-06-21 15:09:48 -04:00
hritikch24
792e278080 Update sync-options.md (#9687)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-21 14:49:10 -04:00
Michael Crenshaw
93bf321002 fix: project filter (#9651) (#9709)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-21 14:39:34 -04:00
Joren Zandstra
48c2e0bf21 fix broken symlink in Dockerfile (#9674)
Signed-off-by: Joren Zandstra <jorenzandstra@yahoo.com>
2022-06-21 14:39:26 -04:00
Soumya Ghosh Dastidar
b4b893ca1c fix: updated baseHRefRegex to perform lazy match (#9724)
* fix: updated baseHRefRegex to perform lazy match

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

* feat: added unit tests for replaceBaseHRef

Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
2022-06-21 10:39:12 -07:00
argo-bot
52e6025f8b Bump version to 2.4.1 2022-06-21 16:27:47 +00:00
argo-bot
b121b89c81 Bump version to 2.4.1 2022-06-21 16:27:40 +00:00
Michael Crenshaw
12149c0710 chore: fix docs gen
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-21 10:34:03 -04:00
Michael Crenshaw
9d67469428 Merge pull request from GHSA-jhqp-vf4w-rpwq
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

defer instead of multiple close calls

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

oops

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

don't count jsonnet against max

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

fix codegen

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

add caveat about 300x ratio

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

fix versions

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

fix tests/lint

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-21 09:40:36 -04:00
Michael Crenshaw
04c3053964 Merge pull request from GHSA-q4w5-4gq2-98vm
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

fix tests/lint

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-21 09:39:56 -04:00
Michael Crenshaw
17f7f4f462 Merge pull request from GHSA-2m7h-86qq-fp4v
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

fix references

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

use long enough state param for oauth2

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

typo

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

more entropy

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

fix tests

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

fix tests/lint

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-21 09:39:01 -04:00
Michael Crenshaw
8bc3ef690d Merge pull request from GHSA-h4w9-6x78-8vrj
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

fix tests/lint

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-21 09:36:38 -04:00
Michael Crenshaw
8fe9a58c21 test: directory app manifest generation (#9503)
* test: directory app manifest generation

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

* git doesn't support empty dirs

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-14 16:12:12 -04:00
Leonardo Luz Almeida
269c61a9c8 chore: Implement tests to validate aws auth retry (#9627)
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-06-14 10:11:38 -04:00
Leonardo Luz Almeida
9a08c123f9 chore: Implement a retry in aws auth command (#9618)
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-06-14 10:10:43 -04:00
jannfis
971f0f1ff1 test: Remove temp directories from repo server tests (#9501)
Signed-off-by: jannfis <jann@mistrust.net>
2022-06-13 15:42:29 -04:00
jannfis
1ae2f97b05 test: Make context tests idempodent (#9502)
Signed-off-by: jannfis <jann@mistrust.net>
2022-06-13 15:41:55 -04:00
Michael Crenshaw
bb26cc207b test: fix plugin var test for OSX (#9590)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-13 15:37:00 -04:00
Christian Hernandez
77d3dcdc62 Update Generators-Git.md (#9632)
Document how to deploy from the root of the git repository

Signed-off-by: Christian Hernandez <christian@codefresh.io>
2022-06-13 10:57:28 -04:00
Hari Sekhon
f414a8e985 docs: added environment variables documentation (#8680)
* added environment variables page

Signed-off-by: Hari Sekhon <harisekhon@gmail.com>

* added Environment Variables page to User Guide

Signed-off-by: Hari Sekhon <harisekhon@gmail.com>

* reformatted table cells as multiline for clarity

Signed-off-by: Hari Sekhon <harisekhon@gmail.com>

* fixed typo

Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-13 10:38:39 -04:00
argo-bot
91aefabc5b Bump version to 2.4.0 2022-06-10 17:13:43 +00:00
argo-bot
56b8e2f356 Bump version to 2.4.0 2022-06-10 17:13:30 +00:00
Michael Crenshaw
101477a638 docs: document OpenSSH upgrade (#9598) (#9615)
docs: document OpenSSH upgrade (#9598) (#9615)

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-09 15:59:59 -07:00
Alexander Matyushentsev
9bf7d1b95b fix: change repo-server command to expand 'ARGOCD_REDIS_SERVICE' env variable (#9628)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-06-09 15:59:54 -07:00
Daniel Helfand
da8e7b9697 fix: use serviceaccount name instead of struct (#9614) (#9617)
* fix: use serviceaccount name instead of struct

Signed-off-by: Daniel Helfand <helfand.4@gmail.com>

* fix: change name of param from sa to serviceAccount

Signed-off-by: Daniel Helfand <helfand.4@gmail.com>
2022-06-08 16:20:29 -04:00
Daniel Helfand
eb183dcde1 fix: create serviceaccount token for v1.24 clusters (#9546)
* fix: create serviceaccount token for v1.24 clusters

Signed-off-by: Daniel Helfand <helfand.4@gmail.com>

* change create to get in err

Signed-off-by: Daniel Helfand <helfand.4@gmail.com>
2022-06-08 14:01:25 -04:00
Michael Crenshaw
ccecc693c2 docs: document argocd cluster add behavior for 1.24 clusters (#9611)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-08 13:54:38 -04:00
Yaakov Selkowitz
dc1d4b060d chore: Fix working directory for remote e2e test image (#9600)
Commit cc6c625401 changed a RUN mkdir
command into a WORKDIR, which also affected the entrypoint.  This
triggered an error in goreman which looks for Procfile (which is
installed here in the root directory) in the working directory.

Since COPY creates any missing directories in the destination path,
there is no need for a separate step to create it.  This change leaves
WORKDIR as the default (the root directory) as before.

Signed-off-by: Yaakov Selkowitz <yselkowi@redhat.com>
2022-06-07 17:31:33 +00:00
Michael Crenshaw
512233806c chore: fix long socket path breaking test on osx (#9391)
* chore: fix long socket path breaking test on osx

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

* comment

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

* simplify

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

* simplify

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-06 17:48:42 -04:00
argo-bot
b84dd8bbfa Bump version to 2.4.0-rc5 2022-06-06 19:03:38 +00:00
argo-bot
e6f37d7245 Bump version to 2.4.0-rc5 2022-06-06 19:03:30 +00:00
Michael Crenshaw
57bac9ac75 chore: update changelog
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-06 14:59:46 -04:00
34FathomBelow
3034183791 chore: upgrade base image to ubuntu:20.04 (#9551)
Signed-off-by: douhunt <douhunt@protonmail.com>

Co-authored-by: douhunt <douhunt@protonmail.com>
Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-06 14:52:10 -04:00
34FathomBelow
26c87b3f16 chore upgrade base image for test containers Ubuntu:22.04 (#9563)
Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
2022-06-06 14:52:02 -04:00
34FathomBelow
bd8d26d444 chore: update Kex-Algorithms (#9561)
* chore: update Kex-Algorithms

Signed-off-by: douhunt <douhunt@protonmail.com>

* sorted kex-algorithms

Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>

Co-authored-by: douhunt <douhunt@protonmail.com>
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-06 14:51:54 -04:00
Michael Crenshaw
a6c58748cd fix: missing Helm params (#9565) (#9566)
* fix: missing Helm params

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

* use absolute paths, fix tests

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

* fix race in test

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-04 20:17:12 -04:00
Bjorn Stange
46af59e258 docs: fix cm typo (#9577)
Signed-off-by: Bjorn Stange <bjorn.stange@expel.io>
2022-06-03 13:21:08 -04:00
Alexander Matyushentsev
867660a709 chore: remove obsolete repo-server unit test (#9559)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-06-03 09:30:57 -04:00
margueritepd
b1addf5bf1 docs: document action RBAC action and application resource path (#8413)
Signed-off-by: Marguerite des Trois Maisons <marguerite+github@pagerduty.com>

Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-02 17:51:08 -04:00
Pierre Crégut
0a9d1607e2 feat: Add plugin call variables to sidecar plugin discovery (#9273) (#9319)
* fix: do not export repo-server environment to sidecar (#9393)

getPluginEnvs is both used for local plugins and sidecar plugins. For the later
do not include the environement variables of the repo-server in the supplied
variables.

Fixes: #9393
Signed-off-by: Pierre Crégut <pierre.cregut@orange.com>

* feat: Add plugin call variables to sidecar plugin discovery (#9273)

Gives access to variables declared in the call of the plugin in the application
manifest to the discover command run on the CMP server.

Variables are prefixed with ARGOCD_ENV_ to avoid security issues (plugin call
overiding important variables).

Fixes #9273

Signed-off-by: Pierre Crégut <pierre.cregut@orange.com>
2022-06-02 17:50:29 -04:00
Michael Crenshaw
09fc32e6cb docs: document plugin prefixed env vars (#9548)
* docs: document plugin prefixed env vars

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

* restructure, clarify env vars from main container behavior

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

* grammer

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

* grammer

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

* no link - the cert is bad

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

* fixes

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-06-02 15:46:50 -04:00
argo-bot
1be9296e6c Bump version to 2.4.0-rc4 2022-06-01 22:49:24 +00:00
argo-bot
76fad02f4a Bump version to 2.4.0-rc4 2022-06-01 22:49:15 +00:00
Alexander Matyushentsev
2f8eb04b84 fix: web terminal due to query parameters name mismatch (#9560)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-06-01 14:39:32 -07:00
argo-bot
66aa0e6e01 Bump version to 2.4.0-rc3 2022-05-31 19:24:04 +00:00
argo-bot
955270eb0d Bump version to 2.4.0-rc3 2022-05-31 19:23:57 +00:00
Michael Crenshaw
225a0af9f7 docs: security warning for plugins (#9547)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-31 11:49:36 -07:00
Leonardo Luz Almeida
5191cd077c chore: Improve application logs adding message context (#9435)
* chore: Improve application logs adding message context

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

* fix bug returning error incorrectly

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

* Fix unit-test and avoid api breaking change

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

* Fix test

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

* Fix e2e test

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

* Fix e2e test

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

* small fix

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

* Address review comments

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-05-31 14:19:02 -04:00
Leonardo Luz Almeida
c6b928c830 fix: Ignore diff with schema (#9170) 2022-05-31 10:27:32 -07:00
Michael Crenshaw
4e73b3c7ee docs: document new repo-server ServiceAccount (#9484)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-31 12:28:38 -04:00
Michael Crenshaw
708c9e79b9 fix: avoid k8s call before authorization for terminal endpoint (#9434)
* fix: avoid k8s API call before authorization in k8s endpoint

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

* check for bad project

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

* lint

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

* more logging

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

* handle 404, return 500 instead of 400 for other errors

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

* use user input

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

* refactor validation

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

* fix tests

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

* fixes, tests

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-31 12:18:25 -04:00
ls0f
da2c249814 receiveFile memory optimization: do not use bytes.buffer but write directly to file (#9415)
Signed-off-by: ls0f <lovedboy.tk@qq.com>
2022-05-31 12:17:39 -04:00
smcavallo
c27cf3f95e feat: support pod exec terminal logging (#9385)
* feat: support pod exec terminal logging
Signed-off-by: smcavallo <smcavallo@hotmail.com>

* enhanced validation and logging when resource not found
Signed-off-by: smcavallo <smcavallo@hotmail.com>

* fix lint
Signed-off-by: smcavallo <smcavallo@hotmail.com>

* log warning when pod or container not found
Signed-off-by: smcavallo <smcavallo@hotmail.com>

* go/log-injection fixes
Signed-off-by: smcavallo <smcavallo@hotmail.com>

* log levels and lowercase message
Signed-off-by: smcavallo <smcavallo@hotmail.com>
2022-05-31 12:17:01 -04:00
Daniel Helfand
dbd3ce3133 docs: add applicationset and notifications controllers to running locally instructions (#9517)
Signed-off-by: Daniel Helfand <helfand.4@gmail.com>

Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-31 12:11:53 -04:00
Pavel Savchenko
58062c45de docs: Update 2.3 notes - mention helm chart (#9512)
the helm chart values should be copied as-is into the `notifications` section of the argo-cd chart

Signed-off-by: Pavel Savchenko <asfaltboy@gmail.com>
2022-05-31 12:11:35 -04:00
reggie-k
3c61070411 docs: logs RBAC known UI issue section (#9479)
* updated changelog and upgrade instructions to contain know UI issue with logs rbac

Signed-off-by: reggie-k <reginakagan@gmail.com>

* updated changelog and upgrade instructions to contain know UI issue with logs rbac

Signed-off-by: reggie-k <reginakagan@gmail.com>
2022-05-31 12:11:09 -04:00
Michael Crenshaw
697fc77379 docs: more appset security docs (#9466)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-31 12:10:40 -04:00
Michael Crenshaw
6655a22b0a docs: plugins need their own writeable tmp volume (#9389)
* docs: plugin needs temp dir

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

* revert temp changes

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

* fix version number

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

* update upgrade instructions

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

* simplify

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-31 12:07:56 -04:00
Michael Crenshaw
0d109279a8 docs: fix PR generators list (#9387)
* docs: fix PR generators list

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

* grammar

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-31 12:07:32 -04:00
neosu
4c1e1e0ad6 Fixes: #9364 (#9367)
In the #8929, the project parameter had changed to projects.

5f5d7aa59b/server/application/application.proto (L23)
Signed-off-by: neosu <neo@neobaran.com>
2022-05-30 19:19:27 -07:00
Michael Crenshaw
078cfe130b fix: test race (#9469)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-24 08:15:41 -07:00
Michael Crenshaw
cd098638f8 fix: lint (#9444)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-24 08:15:27 -07:00
Dan Garfield
2826a9215d refactor: Update notification engine (#9386)
refactor: Update notification engine  (#9386)

Signed-off-by: todaywasawesome <dan@codefresh.io>
2022-05-23 23:50:45 -07:00
Alexander Matyushentsev
13bef3a831 fix: api server should dynamically enabled terminal handler (#9497)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-05-23 23:49:56 -07:00
Alexander Matyushentsev
c6f80377a8 fix: Undefined cluster in UI when app is referencing cluster by name (#9493)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-05-23 22:52:34 -07:00
Alexander Matyushentsev
a8a451a84b fix: make more proto fields optional (#9490)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-05-23 13:46:15 -07:00
argo-bot
cd5b2af358 Bump version to 2.4.0-rc2 2022-05-18 12:32:45 +00:00
argo-bot
f6f9fa2cd6 Bump version to 2.4.0-rc2 2022-05-18 12:32:41 +00:00
jannfis
c7749ca67e Merge pull request from GHSA-r642-gv9p-2wjj
Signed-off-by: jannfis <jann@mistrust.net>

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

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

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

* chore: use t.TempDir for simpler tests

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

* address comments

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

Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-18 13:06:31 +02:00
Saumeya Katyal
c4182aedc7 fix: update filter combo-box icon color (#9416)
Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2022-05-16 14:26:56 +00:00
Saumeya Katyal
e4404372af fix: favorite icon and overlapping app title (#9130)
Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2022-05-16 14:26:35 +00:00
Leonardo Luz Almeida
12140f8152 chore: Improve otel grpc traces adding span correlation (#9371)
* chore: Improve otel grpc traces adding span correlation

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

* Create a tracer for argocd controller

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

* Update controller command doc

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

* Instrument cmp-client

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

* Add otlp config as part of configmaps

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

* update manifests

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-05-13 15:13:43 -04:00
Chetan Banavikalmutt
6cfd394445 fix: ListResourceActions() returns duplicate actions (#9360)
Signed-off-by: Chetan Banavikalmutt <chetanrns1997@gmail.com>
2022-05-13 15:09:33 -04:00
Michael Crenshaw
1998b016c0 docs: clarify Role/ClusterRole uses for exec feature (#9354)
* docs: clarify Role/ClusterRole uses for exec feature

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

* fix missed `get`s

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-12 11:14:10 -04:00
Michael Crenshaw
74bc1731f9 feat(manifests): Add service account for repo server (#9301) (#9355)
Signed-off-by: Hao Xin <haoxinst@gmail.com>
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>

Co-authored-by: Hao Xin <haoxinst@qq.com>
2022-05-11 13:28:13 -04:00
Michael Crenshaw
bb28b3c697 docs: logs RBAC upgrate notes (#9345) (#9356)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-05-10 20:38:25 -04:00
Regina Scott
0ee9993369 fix: grouped node titles no longer wrap (#9340)
Signed-off-by: Regina Scott <rescott@redhat.com>
2022-05-09 19:34:14 -04:00
argo-bot
d8f845a126 Bump version to 2.4.0-rc1 2022-05-06 23:10:53 +00:00
argo-bot
5901b46785 Bump version to 2.4.0-rc1 2022-05-06 23:10:45 +00:00
David J. M. Karlsen
88542a616f feat: Add cli support for additional linux based architectures, s390x + ppc64le (#8991)
feat: Add cli support for additional linux based architectures, s390x + ppc64le (#8991)

Signed-off-by: David J. M. Karlsen <david@davidkarlsen.com>

* add more architectures for linux

Signed-off-by: David J. M. Karlsen <david@davidkarlsen.com>

* drop aix arch as it won't compile

Signed-off-by: David J. M. Karlsen <david@davidkarlsen.com>

Co-authored-by: Michael Crenshaw <michael@crenshaw.dev>
Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-05-06 16:10:03 -07:00
Alexander Matyushentsev
cbe4f1b92e chore: add linux/s390x,linux/ppc64le platforms to release workflow (#9324)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-05-06 16:09:59 -07:00
966 changed files with 21510 additions and 124138 deletions

View File

@@ -1,19 +0,0 @@
---
name: Security log
about: Propose adding security-related logs or tagging existing logs with security fields
title: "seclog: [Event Description]"
labels: security-log
assignees: notfromstatefarm
---
# Event to be logged
Specify the event that needs to be logged or existing logs that need to be tagged.
# Proposed level
What security level should these events be logged under? Refer to https://argo-cd.readthedocs.io/en/latest/operator-manual/security/#security-field for more info.
# Common Weakness Enumeration
Is there an associated [CWE](https://cwe.mitre.org/) that could be tagged as well?

View File

@@ -18,18 +18,15 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
check-go:
name: Ensure Go modules synchronicity
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Download all Go modules
@@ -42,12 +39,12 @@ jobs:
build-go:
name: Build & cache Go code
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Restore go build cache
@@ -62,27 +59,24 @@ jobs:
run: make build-local
lint-go:
permissions:
contents: read # for actions/checkout to fetch code
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
name: Lint Go code
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.46.2
version: v1.45.2
args: --timeout 10m --exclude SA5011 --verbose
test-go:
name: Run unit tests for Go packages
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs:
- build-go
env:
@@ -92,11 +86,11 @@ jobs:
- name: Create checkout directory
run: mkdir -p ~/go/src/github.com/argoproj
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Create symlink in GOPATH
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Install required packages
@@ -145,7 +139,7 @@ jobs:
test-go-race:
name: Run unit tests with -race, for Go packages
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs:
- build-go
env:
@@ -155,11 +149,11 @@ jobs:
- name: Create checkout directory
run: mkdir -p ~/go/src/github.com/argoproj
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Create symlink in GOPATH
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Install required packages
@@ -203,12 +197,12 @@ jobs:
codegen:
name: Check changes to generated code
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Create symlink in GOPATH
@@ -247,10 +241,10 @@ jobs:
build-ui:
name: Build, test & lint UI code
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup NodeJS
uses: actions/setup-node@v1
with:
@@ -279,7 +273,7 @@ jobs:
analyze:
name: Process & analyze test artifacts
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs:
- test-go
- build-ui
@@ -287,7 +281,7 @@ jobs:
sonar_secret: ${{ secrets.SONAR_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Restore node dependency cache
@@ -345,10 +339,10 @@ jobs:
test-e2e:
name: Run end-to-end tests
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
strategy:
matrix:
k3s-version: [v1.24.3, v1.23.3, v1.22.6]
k3s-version: [v1.23.3, v1.22.6, v1.21.2]
needs:
- build-go
env:
@@ -360,15 +354,14 @@ jobs:
ARGOCD_E2E_K3S: "true"
ARGOCD_IN_CI: "true"
ARGOCD_E2E_APISERVER_PORT: "8088"
ARGOCD_APPLICATION_NAMESPACES: "argocd-e2e-external"
ARGOCD_SERVER: "127.0.0.1:8088"
GITHUB_TOKEN: ${{ secrets.E2E_TEST_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: GH actions workaround - Kill XSP4 process
@@ -412,9 +405,9 @@ jobs:
git config --global user.email "john.doe@example.com"
- name: Pull Docker image required for tests
run: |
docker pull ghcr.io/dexidp/dex:v2.35.3-distroless
docker pull quay.io/dexidp/dex:v2.25.0
docker pull argoproj/argo-cd-ci-builder:v1.0.0
docker pull redis:7.0.5-alpine
docker pull redis:7.0.4-alpine
- name: Create target directory for binaries in the build-process
run: |
mkdir -p dist

View File

@@ -13,27 +13,20 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
CodeQL-Build:
permissions:
actions: read # for github/codeql-action/init to get workflow details
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/autobuild to send a status report
if: github.repository == 'argoproj/argo-cd'
# CodeQL runs on ubuntu-latest and windows-latest
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
@@ -41,7 +34,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -55,4 +48,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v1

View File

@@ -16,19 +16,14 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
publish:
permissions:
contents: write # for git to push upgrade commit if not already deployed
if: github.repository == 'argoproj/argo-cd'
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
env:
GOPATH: /home/runner/work/argo-cd/argo-cd
steps:
- uses: actions/setup-go@v3
- uses: actions/setup-go@v1
with:
go-version: ${{ env.GOLANG_VERSION }}
- uses: actions/checkout@master
@@ -52,8 +47,39 @@ jobs:
DOCKER_TOKEN: ${{ secrets.RELEASE_QUAY_TOKEN }}
# build
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/setup-qemu-action@v1
- uses: docker/setup-buildx-action@v1
- name: Setup cache for argocd-ui docker layer
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-single-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-single-buildx
- name: Build cache for argocd-ui stage
uses: docker/build-push-action@v2
with:
context: ./src/github.com/argoproj/argo-cd
target: argocd-ui
push: false
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
if: github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'test-arm-image')
- name: Run non-container Snyk scans
if: github.event_name == 'push'
working-directory: ./src/github.com/argoproj/argo-cd
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
run: |
npm install -g snyk
# Run with high threshold to fail build.
snyk test --org=argoproj --all-projects --exclude=docs,site --severity-threshold=high --policy-path=.snyk
snyk iac test manifests/install.yaml --org=argoproj --severity-threshold=high --policy-path=.snyk
- run: |
IMAGE_PLATFORMS=linux/amd64
if [[ "${{ github.event_name }}" == "push" || "${{ contains(github.event.pull_request.labels.*.name, 'test-arm-image') }}" == "true" ]]
@@ -62,25 +88,27 @@ jobs:
fi
echo "Building image for platforms: $IMAGE_PLATFORMS"
docker buildx build --platform $IMAGE_PLATFORMS --push="${{ github.event_name == 'push' }}" \
--cache-from "type=local,src=/tmp/.buildx-cache" \
-t ghcr.io/argoproj/argocd:${{ steps.image.outputs.tag }} \
-t quay.io/argoproj/argocd:latest .
working-directory: ./src/github.com/argoproj/argo-cd
# sign container images
- name: Install cosign
uses: sigstore/cosign-installer@main
with:
cosign-release: 'v1.13.0'
- name: Sign Argo CD latest image
run: |
cosign sign --key env://COSIGN_PRIVATE_KEY quay.io/argoproj/argocd:latest
# Displays the public key to share.
cosign public-key --key env://COSIGN_PRIVATE_KEY
- name: Run container Snyk scan
if: github.event_name == 'push'
working-directory: ./src/github.com/argoproj/argo-cd
env:
COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}}
COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}}
if: ${{ github.event_name == 'push' }}
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
run: |
snyk container test quay.io/argoproj/argocd:latest --org=argoproj --file=Dockerfile --severity-threshold=high
# Temp fix
# https://github.com/docker/build-push-action/issues/252
# https://github.com/moby/buildkit/issues/1896
- name: Clean up build cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
if: github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'test-arm-image')
# deploy
- run: git clone "https://$TOKEN@github.com/argoproj/argoproj-deployments"

View File

@@ -14,16 +14,11 @@ on:
env:
GOLANG_VERSION: '1.18'
permissions:
contents: read
jobs:
prepare-release:
permissions:
contents: write # To push changes to release branch
name: Perform automatic release on trigger ${{ github.ref }}
if: github.repository == 'argoproj/argo-cd'
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
env:
# The name of the tag as supplied by the GitHub event
SOURCE_TAG: ${{ github.ref }}
@@ -43,7 +38,7 @@ jobs:
GIT_EMAIL: argoproj@gmail.com
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
@@ -147,7 +142,7 @@ jobs:
echo "RELEASE_NOTES=${RELEASE_NOTES}" >> $GITHUB_ENV
- name: Setup Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v2
with:
go-version: ${{ env.GOLANG_VERSION }}
@@ -200,8 +195,8 @@ jobs:
docker login --username "${DOCKER_USERNAME}" --password "${DOCKER_TOKEN}"
if: ${{ env.DRY_RUN != 'true' }}
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/setup-qemu-action@v1
- uses: docker/setup-buildx-action@v1
- name: Build and push Docker image for release
run: |
set -ue
@@ -214,22 +209,6 @@ jobs:
./dist/argocd-linux-amd64 version --client
if: ${{ env.DRY_RUN != 'true' }}
- name: Install cosign
uses: sigstore/cosign-installer@main
with:
cosign-release: 'v1.13.0'
- name: Sign Argo CD container images and assets
run: |
cosign sign --key env://COSIGN_PRIVATE_KEY ${IMAGE_NAMESPACE}/argocd:v${TARGET_VERSION}
cosign sign-blob --key env://COSIGN_PRIVATE_KEY ./dist/argocd-${TARGET_VERSION}-checksums.txt > ./dist/argocd-${TARGET_VERSION}-checksums.sig
# Retrieves the public key to release as an asset
cosign public-key --key env://COSIGN_PRIVATE_KEY > ./dist/argocd-cosign.pub
env:
COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}}
COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}}
if: ${{ env.DRY_RUN != 'true' }}
- name: Read release notes file
id: release-notes
uses: juliangruber/read-file-action@v1
@@ -286,14 +265,6 @@ jobs:
cd /tmp && tar -zcf sbom.tar.gz *.spdx
if: ${{ env.DRY_RUN != 'true' }}
- name: Sign sbom
run: |
cosign sign-blob --key env://COSIGN_PRIVATE_KEY /tmp/sbom.tar.gz > /tmp/sbom.tar.gz.sig
env:
COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}}
COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}}
if: ${{ env.DRY_RUN != 'true' }}
- name: Create GitHub release
uses: softprops/action-gh-release@v1
env:
@@ -303,12 +274,10 @@ jobs:
tag_name: ${{ env.RELEASE_TAG }}
draft: ${{ env.DRAFT_RELEASE }}
prerelease: ${{ env.PRE_RELEASE }}
generate_release_notes: true
body: ${{ steps.release-notes.outputs.content }} # Pre-pended to the generated notes
body: ${{ steps.release-notes.outputs.content }}
files: |
dist/argocd-*
/tmp/sbom.tar.gz
/tmp/sbom.tar.gz.sig
if: ${{ env.DRY_RUN != 'true' }}
- name: Update homebrew formula

View File

@@ -1,36 +0,0 @@
name: Snyk report update
on:
workflow_dispatch: {}
schedule:
- cron: '0 0 * * 0' # midnight every Sunday
permissions:
contents: read
jobs:
snyk-report:
permissions:
contents: write
pull-requests: write
if: github.repository == 'argoproj/argo-cd'
name: Update Snyk report in the docs directory
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Build reports
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
run: |
make snyk-report
pr_branch="snyk-update-$(echo $RANDOM | md5sum | head -c 20)"
git checkout -b "$pr_branch"
git config --global user.email 'ci@argoproj.com'
git config --global user.name 'CI'
git add docs/snyk
git commit -m "[Bot] Update Snyk reports" --signoff
git push --set-upstream origin "$pr_branch"
gh pr create -B master -H "$pr_branch" --title '[Bot] docs: Update Snyk report' --body ''

1
.gitignore vendored
View File

@@ -17,7 +17,6 @@ test-results
node_modules/
.kube/
./test/cmp/*.sock
.envrc.remote
# ignore built binaries
cmd/argocd/argocd

6
.gitpod.Dockerfile vendored
View File

@@ -5,15 +5,13 @@ USER root
RUN curl -o /usr/local/bin/kubectl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" && \
chmod +x /usr/local/bin/kubectl
RUN curl -L https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.3.1/kubebuilder_2.3.1_$(go env GOOS)_$(go env GOARCH).tar.gz | \
RUN curl -L https://go.kubebuilder.io/dl/2.3.1/$(go env GOOS)/$(go env GOARCH) | \
tar -xz -C /tmp/ && mv /tmp/kubebuilder_2.3.1_$(go env GOOS)_$(go env GOARCH) /usr/local/kubebuilder
ENV GOCACHE=/go-build-cache
RUN apt-get install redis-server -y
RUN go install github.com/mattn/goreman@latest
USER gitpod
ENV ARGOCD_REDIS_LOCAL=true
ENV KUBECONFIG=/tmp/kubeconfig
ENV KUBECONFIG=/tmp/kubeconfig

18
.snyk
View File

@@ -18,23 +18,5 @@ ignore:
- '*':
reason: >-
Code is only run client-side. No risk of directory traversal.
SNYK-GOLANG-GITHUBCOMEMICKLEIGORESTFUL-2435653:
- '*':
reason: >-
Argo CD uses go-restful as a transitive dependency of kube-openapi. kube-openapi is used to generate openapi
specs. We do not use go-restul at runtime and are therefore not vulnerable to this CORS misconfiguration
issue in go-restful.
SNYK-JS-FORMIDABLE-2838956:
- '*':
reason: >-
Code is only run client-side. No risk of arbitrary file upload.
SNYK-JS-PARSEPATH-2936439:
- '*':
reason: >-
The issue is that, for specific URLs, parse-path may incorrectly identify the "resource" (domain name)
portion. For example, in "http://127.0.0.1#@example.com", it identifies "example.com" as the "resource".
We use parse-path on the client side, but permissions for git URLs are checked server-side. This is a
potential usability issue, but it is not a security issue.
patch: {}

View File

@@ -1,185 +1,14 @@
# Changelog
## v2.4.8 (2022-07-29)
## v2.4.0 (Unreleased)
### Bug fixes
- feat: support application level extensions (#9923)
- feat: support multiple extensions per resource group/kind (#9834)
- fix: extensions is not loading for ConfigMap/Pods (#10010)
- fix: upgrade moment from 2.29.2 to 2.29.3 (#9330)
- fix: skip redirect url validation when it's the base href (#10058) (#10116)
- fix: avoid CVE-2022-28948 (#10093)
- fix: Set HOST_ARCH for yarn build from platform (#10018)
### Other changes
- chore(deps): bump moment from 2.29.3 to 2.29.4 in /ui (#9897)
- docs: add OpenSSH breaking change notes (#10104)
- chore: update parse-url (#10101)
- docs: add api field example in the appset security doc (#10087)
- chore: update redis to 7.0.4 avoid CVE-2022-30065 (#10059)
- docs: add argocd-server grpc metric usage (#10007)
- chore: upgrade Dex to 2.32.0 (#10036) (#10042)
- chore: update redis to avoid CVE-2022-2097 (#10031)
- chore: update haproxy to 2.0.29 for redis-ha (#10045)
## v2.4.7 (2022-07-18)
### Bug fixes
fix: Support files in argocd.argoproj.io/manifest-generate-paths annotation (#9908)
fix: terminal websocket write lock to avoid races (#10011)
fix: updated all a tags to Link tags in app summary (#9777)
fix: e2e test to use func from clusterauth instead creating one with old logic (#9989)
fix: add missing download CLI tool URL response for ppc64le, s390x (#9983)
### Other
chore: upgrade parse-url to avoid SNYK-JS-PARSEURL-2936249 (#9826)
docs: use quotes to emphasize that ConfigMap value is a string (#9995)
docs: document directory app include/exclude fields (#9997)
docs: simplify Docker toolchain docs (#9966) (#10006)
docs: supported versions (#9876)
## v2.4.6 (2022-07-12)
### Features
* feat: Treat connection reset as a retryable error (#9739)
### Bug fixes
* fix: 'unexpected reserved bits' breaking web terminal (#9605) (#9895)
* fix: argocd login just hangs on 2.4.0 #9679 (#9935)
* fix: CMP manifest generation fails with ENHANCE_YOUR_CALM if over 40s (#9922)
* fix: NotAfter is not set when ValidFor is set (#9911)
* fix: add missing download CLI tool link for ppc64le, s390x (#9649)
* fix: Check tracking annotation for being self-referencing (#9791)
* fix: Make change of tracking method work at runtime (#9820)
* fix: argo-cd git submodule is using SSH auth instead of HTTPs (#3118) (#9821)
### Other
* docs: fix typo in Generators-Git.md (#9949)
* docs: add terminal documentation (#9948)
* test: Use dedicated multi-arch workloads in e2e tests (#9921)
* docs: Adding blank line so list is formatted correctly (#9880)
* docs: small fix for plugin stream filtering (#9871)
* docs: Document the possibility of rendering Helm charts with Kustomize (#9841)
* docs: getting started notes on self-signed cert (#9429) (#9784)
* test: check for error messages from CI env (#9953)
## v2.4.5 (2022-07-12)
### Security fixes
* HIGH: Certificate verification is skipped for connections to OIDC providers ([GHSA-7943-82jg-wmw5](https://github.com/argoproj/argo-cd/security/advisories/GHSA-7943-82jg-wmw5))
* LOW: A leaked API server encryption key can allow XSS for SSO users ([GHSA-pmjg-52h9-72qv](https://github.com/argoproj/argo-cd/security/advisories/GHSA-pmjg-52h9-72qv))
### Potentially-breaking changes
The fix for GHSA-7943-82jg-wmw5 enables TLS certificate validation by default for connections to OIDC providers. If
connections to your OIDC provider fails validation, SSO will be broken for your Argo CD instance. You should test 2.4.5
before upgrading it to production. From the new documentation:
> By default, all connections made by the API server to OIDC providers (either external providers or the bundled Dex
> instance) must pass certificate validation. These connections occur when getting the OIDC provider's well-known
> configuration, when getting the OIDC provider's keys, and when exchanging an authorization code or verifying an ID
> token as part of an OIDC login flow.
>
> Disabling certificate verification might make sense if:
> * You are using the bundled Dex instance **and** your Argo CD instance has TLS configured with a self-signed certificate
> **and** you understand and accept the risks of skipping OIDC provider cert verification.
> * You are using an external OIDC provider **and** that provider uses an invalid certificate **and** you cannot solve
> the problem by setting `oidcConfig.rootCA` **and** you understand and accept the risks of skipping OIDC provider cert
> verification.
>
> If either of those two applies, then you can disable OIDC provider certificate verification by setting
> `oidc.tls.insecure.skip.verify` to `"true"` in the `argocd-cm` ConfigMap.
### Bug fixes
* fix: webhook typo in case of error in GetManifests (#9671)
## v2.4.4 (2022-07-07)
### Bug fixes
- fix: missing path segments for git file generator (#9839)
- fix: make sure api server informer does not stop after setting change (#9842)
- fix: support resource logs and exec (#9833)
- fix: configurable CMP tar exclusions (#9675) (#9789)
- fix: prune any deleted refs before fetching (#9504)
### Other
- test: Remove circular symlinks from testdata (#9886)
- docs: custom secret must be labeled (#9835)
- docs: update archlinux install with official package (#9718)
- docs: explain rightmost git generator path parameter behavior (#9799)
## v2.4.3 (2022-06-27)
### Bug fixes
- fix: respect OIDC providers' supported token signing algorithms (#9433) (#9761)
- fix websockets for terminal not working on subPath (#9795)
- fix: avoid closing and re-opening port of api server settings change (#9778)
- fix: [ArgoCD] Fixing webhook typo in case of error in GetManifests (#9671)
- fix: overrides should not appear in the manifest cache key (#9601)
## v2.4.2 (2022-06-21)
### Bug fixes
* fix: project filter (#9651) (#9709)
* fix: broken symlink in Dockerfile (#9674)
* fix: updated baseHRefRegex to perform lazy match (#9724)
* fix: updated config file permission requirements for windows (#9666)
### Other
* docs: Update sync-options.md (#9687)
* test/remote: Allow override of base image (#9734)
## v2.4.1 (2022-06-21)
### Security fixes
* CRITICAL: External URLs for Deployments can include javascript ([GHSA-h4w9-6x78-8vrj](https://github.com/argoproj/argo-cd/security/advisories/GHSA-h4w9-6x78-8vrj))
* HIGH: Insecure entropy in PKCE/Oauth2/OIDC params ([GHSA-2m7h-86qq-fp4v](https://github.com/argoproj/argo-cd/security/advisories/GHSA-2m7h-86qq-fp4v))
* MODERATE: DoS through large directory app manifest files ([GHSA-jhqp-vf4w-rpwq](https://github.com/argoproj/argo-cd/security/advisories/GHSA-jhqp-vf4w-rpwq))
* MODERATE: Symlink following allows leaking out-of-bounds YAML files from Argo CD repo-server ([GHSA-q4w5-4gq2-98vm](https://github.com/argoproj/argo-cd/security/advisories/GHSA-q4w5-4gq2-98vm))
### Potentially-breaking changes
From the [GHSA-2m7h-86qq-fp4v](https://github.com/argoproj/argo-cd/security/advisories/GHSA-2m7h-86qq-fp4v) description:
> The patch introduces a new `reposerver.max.combined.directory.manifests.size` config parameter, which you should tune before upgrading in production. It caps the maximum total file size of .yaml/.yml/.json files in directory-type (raw manifest) Applications. The default max is 10M per Application. This max is designed to keep any single app from consuming more than 3G of memory in the repo-server (manifests consume more space in memory than on disk). The 300x ratio assumes a maliciously-crafted manifest file. If you only want to protect against accidental excessive memory use, it is probably safe to use a smaller ratio.
>
> If your organization uses directory-type Applications with very many manifests or very large manifests then check the size of those manifests and tune the config parameter before deploying this change to production. When testing, make sure to do a "hard refresh" in either the CLI or UI to test your directory-type App. That will make sure you're using the new max logic instead of relying on cached manifest responses from Redis.
### Other
* test: directory app manifest generation (#9503)
* chore: Implement tests to validate aws auth retry (#9627)
* chore: Implement a retry in aws auth command (#9618)
* test: Remove temp directories from repo server tests (#9501)
* test: Make context tests idempodent (#9502)
* test: fix plugin var test for OSX (#9590)
* docs: Document how to deploy from the root of the git repository (#9632)
* docs: added environment variables documentation (#8680)
## v2.4.0 (2022-06-10)
### Web Terminal In Argo CD UI
### Web Terminal In Argo CD UI
Feature enables engineers to start a shell in the running application container without leaving the web interface. Just find the required Kubernetes
Pod using the Application Details page, click on it and select the Terminal tab. The shell starts automatically and enables you to execute the required
commands, and helps to troubleshoot the application state.
### Access Control For Pod Logs & Web Terminal
### Access Control For Pod Logs & Web Terminal
Argo CD is used to manage the critical infrastructure of multiple organizations, which makes security the top priority of the project. We've listened to
your feedback and introduced additional access control settings that control access to Kubernetes Pod logs and the new Web Terminal feature.
@@ -197,12 +26,12 @@ Upon pressing the "LOGS" tab in pod view by users who don't have an explicit all
The new feature allows emitting richer telemetry data that might make identifying performance bottlenecks easier. The new feature is available for argocd-server
and argocd-repo-server components and can be enabled using the --otlp-address flag.
### Power PC and IBM Z Support
### Power PC and IBM Z Support
The list of supported architectures has been expanded, and now includes IBM Z (s390x) and PowerPC (ppc64le). Starting with the v2.4 release the official quay.io
repository is going to have images for amd64, arm64, ppc64le, and s390x architectures.
### Other Notable Changes
### Other Notable Changes
Overall v2.4 release includes more than 300 hundred commits from nearly 90 contributors. Here is a short sample of the contributions:
@@ -211,116 +40,6 @@ Overall v2.4 release includes more than 300 hundred commits from nearly 90 contr
* Secured Redis connection
* ApplicationSet Gitea support
## v2.3.7 (2022-07-29)
### Notes
This is mainly a security related release and updates compatibility with Kubernetes 1.24.
**Attention:** The base image for 2.3.x reached end-of-life on July 14, 2022. This release upgraded the base image to Ubuntu 22.04 LTS. The change should have no effect on the majority of users. But if any of your git providers only supports now-deprecated key hash algorithms, then Application syncing might break. See the [2.2-to-2.3 upgrade notes](https://argo-cd.readthedocs.io/en/latest/operator-manual/upgrading/2.2-2.3/#support-for-private-repo-ssh-keys-using-the-sha-1-signature-hash-algorithm-is-removed-in-237) for details and workaround instructions.
### Bug fixes
- fix: skip redirect url validation when it's the base href (#10058) (#10116)
- fix: upgrade moment from 2.29.2 to 2.29.3 (#9330)
- fix: avoid CVE-2022-28948 (#10093)
- fix: use serviceaccount name instead of struct (#9614)
- fix: create serviceaccount token for v1.24 clusters (#9546)
### Other changes
- test: Remove cluster e2e tests not intended for release-2.3
- test: Remove circular symlinks from testdata (#9886)
- chore(deps): bump moment from 2.29.3 to 2.29.4 in /ui (#9897)
- chore: upgrade moment to latest version to fix CVE (#9005)
- chore: move dependencies to dev dependencies (#8541)
- docs: add OpenSSH breaking change notes (#10104)
- chore: update parse-url (#10101)
- chore: upgrade base image to 22.04 (#10103)
- docs: simplify Docker toolchain docs (#9966) (#10006)
- chore: update redis to 6.2.7 avoid CVE-2022-30065/CVE-2022-2097 (#10062)
- chore: upgrade Dex to 2.32.0 (#10036) (#10042)
- chore: update haproxy to 2.0.29 for redis-ha (#10045)
- test: check for error messages from CI env (#9953)
## v2.3.6 (2022-07-12)
### Security fixes
* HIGH: Certificate verification is skipped for connections to OIDC providers ([GHSA-7943-82jg-wmw5](https://github.com/argoproj/argo-cd/security/advisories/GHSA-7943-82jg-wmw5))
* LOW: A leaked API server encryption key can allow XSS for SSO users ([GHSA-pmjg-52h9-72qv](https://github.com/argoproj/argo-cd/security/advisories/GHSA-pmjg-52h9-72qv))
### Potentially-breaking changes
The fix for GHSA-7943-82jg-wmw5 enables TLS certificate validation by default for connections to OIDC providers. If
connections to your OIDC provider fails validation, SSO will be broken for your Argo CD instance. You should test 2.3.6
before upgrading it to production. From the new documentation:
> By default, all connections made by the API server to OIDC providers (either external providers or the bundled Dex
> instance) must pass certificate validation. These connections occur when getting the OIDC provider's well-known
> configuration, when getting the OIDC provider's keys, and when exchanging an authorization code or verifying an ID
> token as part of an OIDC login flow.
>
> Disabling certificate verification might make sense if:
> * You are using the bundled Dex instance **and** your Argo CD instance has TLS configured with a self-signed certificate
> **and** you understand and accept the risks of skipping OIDC provider cert verification.
> * You are using an external OIDC provider **and** that provider uses an invalid certificate **and** you cannot solve
> the problem by setting `oidcConfig.rootCA` **and** you understand and accept the risks of skipping OIDC provider cert
> verification.
>
> If either of those two applies, then you can disable OIDC provider certificate verification by setting
> `oidc.tls.insecure.skip.verify` to `"true"` in the `argocd-cm` ConfigMap.
### Bug fixes
* fix: webhook typo in case of error in GetManifests (#9671)
## v2.3.5 (2022-06-21)
### Security fixes
* CRITICAL: External URLs for Deployments can include javascript ([GHSA-h4w9-6x78-8vrj](https://github.com/argoproj/argo-cd/security/advisories/GHSA-h4w9-6x78-8vrj))
* HIGH: Insecure entropy in PKCE/Oauth2/OIDC params ([GHSA-2m7h-86qq-fp4v](https://github.com/argoproj/argo-cd/security/advisories/GHSA-2m7h-86qq-fp4v))
* MODERATE: DoS through large directory app manifest files ([GHSA-jhqp-vf4w-rpwq](https://github.com/argoproj/argo-cd/security/advisories/GHSA-jhqp-vf4w-rpwq))
* MODERATE: Symlink following allows leaking out-of-bounds YAML files from Argo CD repo-server ([GHSA-q4w5-4gq2-98vm](https://github.com/argoproj/argo-cd/security/advisories/GHSA-q4w5-4gq2-98vm))
### Potentially-breaking changes
From the [GHSA-2m7h-86qq-fp4v](https://github.com/argoproj/argo-cd/security/advisories/GHSA-2m7h-86qq-fp4v) description:
> The patch introduces a new `reposerver.max.combined.directory.manifests.size` config parameter, which you should tune before upgrading in production. It caps the maximum total file size of .yaml/.yml/.json files in directory-type (raw manifest) Applications. The default max is 10M per Application. This max is designed to keep any single app from consuming more than 3G of memory in the repo-server (manifests consume more space in memory than on disk). The 300x ratio assumes a maliciously-crafted manifest file. If you only want to protect against accidental excessive memory use, it is probably safe to use a smaller ratio.
>
> If your organization uses directory-type Applications with very many manifests or very large manifests then check the size of those manifests and tune the config parameter before deploying this change to production. When testing, make sure to do a "hard refresh" in either the CLI or UI to test your directory-type App. That will make sure you're using the new max logic instead of relying on cached manifest responses from Redis.
### Bug fixes
* fix: missing Helm params (#9565) (#9566)
### Other
* test: directory app manifest generation (#9503)
* chore: eliminate go-mpatch dependency (#9045)
* chore: Make unit tests run on platforms other than amd64 (#8995)
* chore: remove obsolete repo-server unit test (#9559)
* chore: update golangci-lint (#8988)
* fix: test race (#9469)
* chore: upgrade golangci-lint to v1.46.2 (#9448)
* test: fix ErrorContains (#9445)
## v2.3.4 (2022-05-18)
### Security fixes
- CRITICAL: Argo CD will trust invalid JWT claims if anonymous access is enabled (https://github.com/argoproj/argo-cd/security/advisories/GHSA-r642-gv9p-2wjj)
- LOW: Login screen allows message spoofing if SSO is enabled (https://github.com/argoproj/argo-cd/security/advisories/GHSA-xmg8-99r8-jc2j)
- MODERATE: Symlink following allows leaking out-of-bound manifests and JSON files from Argo CD repo-server (https://github.com/argoproj/argo-cd/security/advisories/GHSA-6gcg-hp2x-q54h)
### Bug Fixes
- fix: Fix docs build error (#8895)
- fix: fix broken monaco editor collapse icons (#8709)
- chore: upgrade to go 1.17.8 (#8866) (#9004)
- fix: allow cli/ui to follow logs (#8987) (#9065)
## v2.3.3 (2022-03-29)
@@ -462,174 +181,6 @@ Both bundled Helm and Kustomize binaries have been upgraded to the latest versio
- refactor: Introduce 'byClusterName' secret index to speedup cluster server URL lookup (#8133)
- refactor: Move project filtering to server side (#8102)
## v2.2.12 (2022-07-29)
### Notes
This is mainly a security related release and updates compatibility with Kubernetes 1.24.
**Attention:** The base image for 2.2.x reached end-of-life on January 20, 2022. This release upgraded the base image to Ubuntu 22.04 LTS. The change should have no effect on the majority of users. But if any of your git providers only supports now-deprecated key hash algorithms, then Application syncing might break. See the [2.1-to-2.2 upgrade notes](https://argo-cd.readthedocs.io/en/latest/operator-manual/upgrading/2.1-2.2/#support-for-private-repo-ssh-keys-using-the-sha-1-signature-hash-algorithm-is-removed-in-2212) for details and workaround instructions.
### Bug fixes
- fix: create serviceaccount token for v1.24 clusters (#9546)
- fix: upgrade moment from 2.29.2 to 2.29.3 (#9330)
- fix: avoid CVE-2022-28948 (#10093)
### Other changes
- chore: Remove deprecated K8s versions from test matrix
- chore: Go mod tidy
- test: Remove circular symlinks from testdata (#9886)
- test: Fix e2e tests for release-2.2 branch
- chore: bump redoc vesion to avoid CVE-2021-23820 (#8604)
- chore(deps): bump moment from 2.29.3 to 2.29.4 in /ui (#9897)
- chore: upgrade moment to latest version to fix CVE (#9005)
- chore: move dependencies to dev dependencies (#8541)
- docs: add OpenSSH breaking change notes (#10104)
- chore: update parse-url (#10101)
- chore: fix codegen
- chore: fix codegen
- chore: upgrade base image to 22.04 (#10105)
- docs: simplify Docker toolchain docs (#9966) (#10006)
- chore: update redis to 6.2.7 avoid CVE-2022-30065/CVE-2022-2097 (#10068)
- chore: upgrade Dex to 2.32.0 (#10036) (#10042)
- chore: update haproxy to 2.0.29 for redis-ha (#10045)
- test: check for error messages from CI env (#9953)
## v2.2.11 (2022-07-12)
### Security fixes
* HIGH: Certificate verification is skipped for connections to OIDC providers ([GHSA-7943-82jg-wmw5](https://github.com/argoproj/argo-cd/security/advisories/GHSA-7943-82jg-wmw5))
* LOW: A leaked API server encryption key can allow XSS for SSO users ([GHSA-pmjg-52h9-72qv](https://github.com/argoproj/argo-cd/security/advisories/GHSA-pmjg-52h9-72qv))
### Potentially-breaking changes
The fix for GHSA-7943-82jg-wmw5 enables TLS certificate validation by default for connections to OIDC providers. If
connections to your OIDC provider fails validation, SSO will be broken for your Argo CD instance. You should test 2.2.11
before upgrading it to production. From the new documentation:
> By default, all connections made by the API server to OIDC providers (either external providers or the bundled Dex
> instance) must pass certificate validation. These connections occur when getting the OIDC provider's well-known
> configuration, when getting the OIDC provider's keys, and when exchanging an authorization code or verifying an ID
> token as part of an OIDC login flow.
>
> Disabling certificate verification might make sense if:
> * You are using the bundled Dex instance **and** your Argo CD instance has TLS configured with a self-signed certificate
> **and** you understand and accept the risks of skipping OIDC provider cert verification.
> * You are using an external OIDC provider **and** that provider uses an invalid certificate **and** you cannot solve
> the problem by setting `oidcConfig.rootCA` **and** you understand and accept the risks of skipping OIDC provider cert
> verification.
>
> If either of those two applies, then you can disable OIDC provider certificate verification by setting
> `oidc.tls.insecure.skip.verify` to `"true"` in the `argocd-cm` ConfigMap.
### Features
* feat: enable specifying root ca for oidc (#6712)
### Bug fixes
* fix: webhook typo in case of error in GetManifests (#9671)
## v2.2.10 (2022-06-21)
### Security fixes
* CRITICAL: External URLs for Deployments can include javascript ([GHSA-h4w9-6x78-8vrj](https://github.com/argoproj/argo-cd/security/advisories/GHSA-h4w9-6x78-8vrj))
* HIGH: Insecure entropy in PKCE/Oauth2/OIDC params ([GHSA-2m7h-86qq-fp4v](https://github.com/argoproj/argo-cd/security/advisories/GHSA-2m7h-86qq-fp4v))
* MODERATE: DoS through large directory app manifest files ([GHSA-jhqp-vf4w-rpwq](https://github.com/argoproj/argo-cd/security/advisories/GHSA-jhqp-vf4w-rpwq))
* MODERATE: Symlink following allows leaking out-of-bounds YAML files from Argo CD repo-server ([GHSA-q4w5-4gq2-98vm](https://github.com/argoproj/argo-cd/security/advisories/GHSA-q4w5-4gq2-98vm))
### Potentially-breaking changes
From the [GHSA-2m7h-86qq-fp4v](https://github.com/argoproj/argo-cd/security/advisories/GHSA-2m7h-86qq-fp4v) description:
> The patch introduces a new `reposerver.max.combined.directory.manifests.size` config parameter, which you should tune before upgrading in production. It caps the maximum total file size of .yaml/.yml/.json files in directory-type (raw manifest) Applications. The default max is 10M per Application. This max is designed to keep any single app from consuming more than 3G of memory in the repo-server (manifests consume more space in memory than on disk). The 300x ratio assumes a maliciously-crafted manifest file. If you only want to protect against accidental excessive memory use, it is probably safe to use a smaller ratio.
>
> If your organization uses directory-type Applications with very many manifests or very large manifests then check the size of those manifests and tune the config parameter before deploying this change to production. When testing, make sure to do a "hard refresh" in either the CLI or UI to test your directory-type App. That will make sure you're using the new max logic instead of relying on cached manifest responses from Redis.
### Bug fixes
* fix: missing Helm params (#9565) (#9566)
### Other
* test: directory app manifest generation (#9503)
* test: fix erroneous test change
* chore: eliminate go-mpatch dependency (#9045)
* chore: Make unit tests run on platforms other than amd64 (#8995)
* chore: remove obsolete repo-server unit test (#9559)
* chore: upgrade golangci-lint to v1.46.2 (#9448)
* chore: update golangci-lint (#8988)
## v2.2.9 (2022-05-18)
### Notes
This is a security release. We urge all users of the 2.2.z branch to update as soon as possible. Please refer to the _Security fixes_ section below for more details.
### Security fixes
- CRITICAL: Argo CD will trust invalid JWT claims if anonymous access is enabled (https://github.com/argoproj/argo-cd/security/advisories/GHSA-r642-gv9p-2wjj)
- LOW: Login screen allows message spoofing if SSO is enabled (https://github.com/argoproj/argo-cd/security/advisories/GHSA-xmg8-99r8-jc2j)
- MODERATE: Symlink following allows leaking out-of-bound manifests and JSON files from Argo CD repo-server (https://github.com/argoproj/argo-cd/security/advisories/GHSA-6gcg-hp2x-q54h)
## v2.2.8 (2022-03-22)
### Special notes
This release contains the fix for a security issue with critical severity. We recommend users on the 2.2 release branch to update to this release as soon as possible.
More information can be found in the related
[security advisory](https://github.com/argoproj/argo-cd/security/advisories/GHSA-2f5v-8r3f-8pww).
### Changes
As part of the security fix, the Argo CD UI no longer automatically presents child resources of allow-listed resources unless the child resources are also allow-listed. For example, Pods are not going to show up if only Deployment is added to the allow-list.
If you have [projects](https://argo-cd.readthedocs.io/en/stable/user-guide/projects/) configured with allow-lists, make sure the allow-lists include all the resources you want users to be able to view/manage through the UI. For example, if your project allows `Deployments`, you would add `ReplicaSets` and `Pods`.
#### Bug Fixes
- fix: application resource APIs must enforce project restrictions
## v2.2.7 (2022-03-08)
### Bug Fixes
- fix: correct jsonnet paths resolution (#8721)
## v2.2.6 (2022-03-06)
### Bug Fixes
- fix: prevent file traversal using helm file values param and application details api (#8606)
- fix!: enforce app create/update privileges when getting repo details (#8558)
- feat: support custom helm values file schemes (#8535)
## v2.2.5 (2022-02-04)
- fix: Resolve symlinked value files correctly (#8387)
## v2.2.4 (2022-02-03)
### Special notes
This release contains the fix for a security issue with high severity. We recommend users on the 2.2 release branch to update to this release as soon as possible.
More information can be found in the related
[security advisory](https://github.com/argoproj/argo-cd/security/advisories/GHSA-63qx-x74g-jcr7)
### Bug Fixes
- fix: Prevent value files outside repository root
### Other changes
- chore: upgrade dex to v2.30.2 (backport of #8237) (#8257)
## v2.2.3 (2022-01-18)
- fix: Application exist panic when execute api call (#8188)
@@ -687,117 +238,6 @@ as there are no conflicts with other Kubernetes tools, and you can easily instal
* Cluster name support in project destinations (#7198)
* around 30 more features and a total of 84 bug fixes
## v2.1.16 (2022-06-21)
### Security fixes
* CRITICAL: External URLs for Deployments can include javascript ([GHSA-h4w9-6x78-8vrj](https://github.com/argoproj/argo-cd/security/advisories/GHSA-h4w9-6x78-8vrj))
* HIGH: Insecure entropy in PKCE/Oauth2/OIDC params ([GHSA-2m7h-86qq-fp4v](https://github.com/argoproj/argo-cd/security/advisories/GHSA-2m7h-86qq-fp4v))
* MODERATE: DoS through large directory app manifest files ([GHSA-jhqp-vf4w-rpwq](https://github.com/argoproj/argo-cd/security/advisories/GHSA-jhqp-vf4w-rpwq))
* MODERATE: Symlink following allows leaking out-of-bounds YAML files from Argo CD repo-server ([GHSA-q4w5-4gq2-98vm](https://github.com/argoproj/argo-cd/security/advisories/GHSA-q4w5-4gq2-98vm))
**Note:** This will be the last security fix release in the 2.1.x series. Please [upgrade to a newer minor version](https://argo-cd.readthedocs.io/en/latest/operator-manual/upgrading/overview/) to continue to get security fixes.
### Potentially-breaking changes
From the [GHSA-2m7h-86qq-fp4v](https://github.com/argoproj/argo-cd/security/advisories/GHSA-2m7h-86qq-fp4v) description:
> The patch introduces a new `reposerver.max.combined.directory.manifests.size` config parameter, which you should tune before upgrading in production. It caps the maximum total file size of .yaml/.yml/.json files in directory-type (raw manifest) Applications. The default max is 10M per Application. This max is designed to keep any single app from consuming more than 3G of memory in the repo-server (manifests consume more space in memory than on disk). The 300x ratio assumes a maliciously-crafted manifest file. If you only want to protect against accidental excessive memory use, it is probably safe to use a smaller ratio.
>
> If your organization uses directory-type Applications with very many manifests or very large manifests then check the size of those manifests and tune the config parameter before deploying this change to production. When testing, make sure to do a "hard refresh" in either the CLI or UI to test your directory-type App. That will make sure you're using the new max logic instead of relying on cached manifest responses from Redis.
### Bug fixes
* fix: missing Helm params (#9565) (#9566)
### Other
* test: directory app manifest generation (#9503)
* test: fix erroneous test change
* chore: eliminate go-mpatch dependency (#9045)
* chore: Make unit tests run on platforms other than amd64 (#8995)
* chore: remove obsolete repo-server unit test (#9559)
* chore: upgrade golangci-lint to v1.46.2 (#9448)
* chore: update golangci-lint (#8988)
* test: fix ErrorContains (#9445)
## v2.1.15 (2022-05-18)
### Notes
This is a security release. We urge all users of the 2.1.z branch to update as soon as possible. Please refer to the _Security fixes_ section below for more details.
### Security fixes
- CRITICAL: Argo CD will trust invalid JWT claims if anonymous access is enabled (https://github.com/argoproj/argo-cd/security/advisories/GHSA-r642-gv9p-2wjj)
- LOW: Login screen allows message spoofing if SSO is enabled (https://github.com/argoproj/argo-cd/security/advisories/GHSA-xmg8-99r8-jc2j)
- MODERATE: Symlink following allows leaking out-of-bound manifests and JSON files from Argo CD repo-server (https://github.com/argoproj/argo-cd/security/advisories/GHSA-6gcg-hp2x-q54h)
## v2.1.14 (2022-03-22)
### Special notes
This release contains the fix for a security issue with critical severity. We recommend users on the 2.1 release branch to update to this release as soon as possible.
More information can be found in the related
[security advisory](https://github.com/argoproj/argo-cd/security/advisories/GHSA-2f5v-8r3f-8pww).
### Changes
As part of the security fix, the Argo CD UI no longer automatically presents child resources of allow-listed resources unless the child resources are also allow-listed. For example, Pods are not going to show up if only Deployment is added to the allow-list.
If you have [projects](https://argo-cd.readthedocs.io/en/stable/user-guide/projects/) configured with allow-lists, make sure the allow-lists include all the resources you want users to be able to view/manage through the UI. For example, if your project allows `Deployments`, you would add `ReplicaSets` and `Pods`.
#### Bug Fixes
- fix: application resource APIs must enforce project restrictions
## v2.1.13 (2022-03-22)
Unused release number.
## v2.1.12 (2022-03-08)
### Bug Fixes
- fix: correct jsonnet paths resolution (#8721)
## v2.1.11 (2022-03-06)
### Bug Fixes
- fix: prevent file traversal using helm file values param and application details api (#8606)
- fix!: enforce app create/update privileges when getting repo details (#8558)
- feat: support custom helm values file schemes (#8535)
## v2.1.10 (2022-02-04)
### Bug Fixes
- fix: Resolve symlinked value files correctly (#8387)
## v2.1.9 (2022-02-03)
### Special notes
This release contains the fix for a security issue with high severity. We recommend users on the 2.1 release branch to update to this release as soon as possible.
More information can be found in the related
[security advisory](https://github.com/argoproj/argo-cd/security/advisories/GHSA-63qx-x74g-jcr7)
### Bug Fixes
- fix: Prevent value files outside repository root
## v2.1.8 (2021-12-13)
### Bug Fixes
- fix: issue with keepalive (#7861)
- fix nil pointer dereference error (#7905)
- fix: env vars to tune cluster cache were broken (#7779)
- fix: upgraded gitops engine to v0.4.2 (fixes #7561)
## v2.1.7 (2021-12-14)
- fix: issue with keepalive (#7861)
@@ -1008,7 +448,7 @@ resources, you will have to adapt your cluster resources allow lists to explicit
## v1.8.4 (2021-02-05)
- feat: set X-XSS-Protection while serving static content (#5412)
- fix: version info should be available if anonymous access is enabled (#5422)
- fix: version info should be avaialble if anonymous access is enabled (#5422)
- fix: disable jwt claim audience validation #5381 (#5413)
- fix: /api/version should not return tools version for unauthenticated requests (#5415)
- fix: account tokens should be rejected if required capability is disabled (#5414)

View File

@@ -38,11 +38,10 @@ FROM $BASE_IMAGE AS argocd-base
USER root
ENV ARGOCD_USER_ID=999
ENV DEBIAN_FRONTEND=noninteractive
RUN groupadd -g $ARGOCD_USER_ID argocd && \
useradd -r -u $ARGOCD_USER_ID -g argocd argocd && \
RUN groupadd -g 999 argocd && \
useradd -r -u 999 -g argocd argocd && \
mkdir -p /home/argocd && \
chown argocd:0 /home/argocd && \
chmod g=u /home/argocd && \
@@ -75,7 +74,7 @@ RUN mkdir -p tls && \
ENV USER=argocd
USER $ARGOCD_USER_ID
USER 999
WORKDIR /home/argocd
####################################################################################################
@@ -129,4 +128,4 @@ RUN ln -s /usr/local/bin/argocd /usr/local/bin/argocd-server && \
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-applicationset-controller && \
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-k8s-auth
USER $ARGOCD_USER_ID
USER 999

View File

@@ -25,7 +25,7 @@ DOCKER_WORKDIR?=/go/src/github.com/argoproj/argo-cd
ARGOCD_PROCFILE?=Procfile
# Strict mode has been disabled in latest versions of mkdocs-material.
# Strict mode has been disabled in latest versions of mkdocs-material.
# Thus pointing to the older image of mkdocs-material matching the version used by argo-cd.
MKDOCS_DOCKER_IMAGE?=squidfunk/mkdocs-material:4.1.1
MKDOCS_RUN_ARGS?=
@@ -47,7 +47,7 @@ ARGOCD_E2E_DEX_PORT?=5556
ARGOCD_E2E_YARN_HOST?=localhost
ARGOCD_E2E_DISABLE_AUTH?=
ARGOCD_E2E_TEST_TIMEOUT?=45m
ARGOCD_E2E_TEST_TIMEOUT?=30m
ARGOCD_IN_CI?=false
ARGOCD_TEST_E2E?=true
@@ -81,8 +81,6 @@ define run-in-test-server
-e ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} \
-e ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} \
-e ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} \
-e ARGOCD_APPLICATION_NAMESPACES \
-e GITHUB_TOKEN \
-v ${DOCKER_SRC_MOUNT} \
-v ${GOPATH}/pkg/mod:/go/pkg/mod${VOLUME_MOUNT} \
-v ${GOCACHE}:/tmp/go-build-cache${VOLUME_MOUNT} \
@@ -104,7 +102,6 @@ define run-in-test-client
-e HOME=/home/user \
-e GOPATH=/go \
-e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) \
-e GITHUB_TOKEN \
-e GOCACHE=/tmp/go-build-cache \
-e ARGOCD_LINT_GOGC=$(ARGOCD_LINT_GOGC) \
-v ${DOCKER_SRC_MOUNT} \
@@ -117,9 +114,9 @@ define run-in-test-client
bash -c "$(1)"
endef
#
#
define exec-in-test-server
docker exec -it -u $(shell id -u):$(shell id -g) -e ARGOCD_E2E_RECORD=$(ARGOCD_E2E_RECORD) -e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) argocd-test-server $(1)
docker exec -it -u $(shell id -u):$(shell id -g) -e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) argocd-test-server $(1)
endef
PATH:=$(PATH):$(PWD)/hack
@@ -208,7 +205,7 @@ clientgen: ensure-gopath
.PHONY: clidocsgen
clidocsgen: ensure-gopath
go run tools/cmd-docs/main.go
go run tools/cmd-docs/main.go
.PHONY: codegen-local
@@ -243,10 +240,8 @@ release-cli: clean-debug build-ui
.PHONY: test-tools-image
test-tools-image:
ifndef SKIP_TEST_TOOLS_IMAGE
docker build --build-arg UID=$(shell id -u) -t $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE) -f test/container/Dockerfile .
docker tag $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE) $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE):$(TEST_TOOLS_TAG)
endif
.PHONY: manifests-local
manifests-local:
@@ -286,7 +281,7 @@ ifeq ($(DEV_IMAGE), true)
# the dist directory is under .dockerignore.
IMAGE_TAG="dev-$(shell git describe --always --dirty)"
image: build-ui
DOCKER_BUILDKIT=1 docker build --platform=linux/amd64 -t argocd-base --target argocd-base .
DOCKER_BUILDKIT=1 docker build -t argocd-base --target argocd-base .
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd ./cmd
ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-server
ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-application-controller
@@ -294,7 +289,7 @@ image: build-ui
ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-cmp-server
ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-dex
cp Dockerfile.dev dist
DOCKER_BUILDKIT=1 docker build --platform=linux/amd64 -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) -f dist/Dockerfile.dev dist
docker build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) -f dist/Dockerfile.dev dist
else
image:
DOCKER_BUILDKIT=1 docker build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) .
@@ -342,7 +337,7 @@ lint-local:
golangci-lint --version
# NOTE: If you get a "Killed" OOM message, try reducing the value of GOGC
# See https://github.com/golangci/golangci-lint#memory-usage-of-golangci-lint
GOGC=$(ARGOCD_LINT_GOGC) GOMAXPROCS=2 golangci-lint run --fix --verbose --timeout 3000s
GOGC=$(ARGOCD_LINT_GOGC) GOMAXPROCS=2 golangci-lint run --fix --verbose --timeout 300s
.PHONY: lint-ui
lint-ui: test-tools-image
@@ -406,7 +401,7 @@ test-e2e:
test-e2e-local: cli-local
# NO_PROXY ensures all tests don't go out through a proxy if one is configured on the test system
export GO111MODULE=off
ARGOCD_E2E_RECORD=${ARGOCD_E2E_RECORD} ARGOCD_GPG_ENABLED=true NO_PROXY=* ./hack/test.sh -timeout $(ARGOCD_E2E_TEST_TIMEOUT) -v ./test/e2e
ARGOCD_GPG_ENABLED=true NO_PROXY=* ./hack/test.sh -timeout $(ARGOCD_E2E_TEST_TIMEOUT) -v ./test/e2e
# Spawns a shell in the test server container for debugging purposes
debug-test-server: test-tools-image
@@ -427,7 +422,6 @@ start-e2e: test-tools-image
.PHONY: start-e2e-local
start-e2e-local: mod-vendor-local dep-ui-local cli-local
kubectl create ns argocd-e2e || true
kubectl create ns argocd-e2e-external || true
kubectl config set-context --current --namespace=argocd-e2e
kustomize build test/manifests/base | kubectl apply -f -
kubectl apply -f https://raw.githubusercontent.com/open-cluster-management/api/a6845f2ebcb186ec26b832f60c988537a58f3859/cluster/v1alpha1/0000_04_clusters.open-cluster-management.io_placementdecisions.crd.yaml
@@ -448,14 +442,13 @@ start-e2e-local: mod-vendor-local dep-ui-local cli-local
ARGOCD_ZJWT_FEATURE_FLAG=always \
ARGOCD_IN_CI=$(ARGOCD_IN_CI) \
BIN_MODE=$(ARGOCD_BIN_MODE) \
ARGOCD_APPLICATION_NAMESPACES=argocd-e2e-external \
ARGOCD_E2E_TEST=true \
goreman -f $(ARGOCD_PROCFILE) start ${ARGOCD_START}
# Cleans VSCode debug.test files from sub-dirs to prevent them from being included in by golang embed
.PHONY: clean-debug
clean-debug:
-find ${CURRENT_DIR} -name debug.test -exec rm -f {} +
-find ${CURRENT_DIR} -name debug.test | xargs rm -f
.PHONY: clean
clean: clean-debug
@@ -468,7 +461,7 @@ start: test-tools-image
# Starts a local instance of ArgoCD
.PHONY: start-local
start-local: mod-vendor-local dep-ui-local cli-local
start-local: mod-vendor-local dep-ui-local
# check we can connect to Docker to start Redis
killall goreman || true
kubectl create ns argocd || true
@@ -480,7 +473,6 @@ start-local: mod-vendor-local dep-ui-local cli-local
ARGOCD_IN_CI=false \
ARGOCD_GPG_ENABLED=$(ARGOCD_GPG_ENABLED) \
ARGOCD_E2E_TEST=false \
ARGOCD_APPLICATION_NAMESPACES=$(ARGOCD_APPLICATION_NAMESPACES) \
goreman -f $(ARGOCD_PROCFILE) start ${ARGOCD_START}
# Run goreman start with exclude option , provide exclude env variable with list of services
@@ -576,16 +568,4 @@ applicationset-controller:
.PHONY: checksums
checksums:
sha256sum ./dist/$(BIN_NAME)-* | awk -F './dist/' '{print $$1 $$2}' > ./dist/$(BIN_NAME)-$(TARGET_VERSION)-checksums.txt
.PHONY: snyk-container-tests
snyk-container-tests:
./hack/snyk-container-tests.sh
.PHONY: snyk-non-container-tests
snyk-non-container-tests:
./hack/snyk-non-container-tests.sh
.PHONY: snyk-report
snyk-report:
./hack/snyk-report.sh $(target_branch)
for f in ./dist/$(BIN_NAME)-*; do openssl dgst -sha256 "$$f" | awk ' { print $$2 }' > "$$f".sha256 ; done

View File

@@ -1,7 +1,7 @@
controller: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''}"
api-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''}"
dex: sh -c "ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/v2/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:$(grep "image: ghcr.io/dexidp/dex" manifests/base/dex/argocd-dex-server-deployment.yaml | cut -d':' -f3) dex serve /dex.yaml"
redis: bash -c "if [ \"$ARGOCD_REDIS_LOCAL\" == 'true' ]; then redis-server --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; else docker run --rm --name argocd-redis -i -p ${ARGOCD_E2E_REDIS_PORT:-6379}:${ARGOCD_E2E_REDIS_PORT:-6379} redis:$(grep "image: redis" manifests/base/redis/argocd-redis-deployment.yaml | cut -d':' -f3) --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; fi"
controller: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --otlp-address=${ARGOCD_OTLP_ADDRESS}"
api-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --otlp-address=${ARGOCD_OTLP_ADDRESS}"
dex: sh -c "ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/v2/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:v2.30.2 dex serve /dex.yaml"
redis: bash -c "if [ \"$ARGOCD_REDIS_LOCAL\" == 'true' ]; then redis-server --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; else docker run --rm --name argocd-redis -i -p ${ARGOCD_E2E_REDIS_PORT:-6379}:${ARGOCD_E2E_REDIS_PORT:-6379} redis:7.0.0-alpine --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; fi"
repo-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-repo-server ARGOCD_GPG_ENABLED=${ARGOCD_GPG_ENABLED:-false} $COMMAND --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --otlp-address=${ARGOCD_OTLP_ADDRESS}"
cmp-server: [ "$ARGOCD_E2E_TEST" == 'true' ] && exit 0 || [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_BINARY_NAME=argocd-cmp-server ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} $COMMAND --config-dir-path ./test/cmp --loglevel debug --otlp-address=${ARGOCD_OTLP_ADDRESS}"
ui: sh -c 'cd ui && ${ARGOCD_E2E_YARN_CMD:-yarn} start'

View File

@@ -1,5 +1,4 @@
[![Integration tests](https://github.com/argoproj/argo-cd/workflows/Integration%20tests/badge.svg?branch=master)](https://github.com/argoproj/argo-cd/actions?query=workflow%3A%22Integration+tests%22) [![slack](https://img.shields.io/badge/slack-argoproj-brightgreen.svg?logo=slack)](https://argoproj.github.io/community/join-slack) [![codecov](https://codecov.io/gh/argoproj/argo-cd/branch/master/graph/badge.svg)](https://codecov.io/gh/argoproj/argo-cd) [![Release Version](https://img.shields.io/github/v/release/argoproj/argo-cd?label=argo-cd)](https://github.com/argoproj/argo-cd/releases/latest) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/4486/badge)](https://bestpractices.coreinfrastructure.org/projects/4486) [![Twitter Follow](https://img.shields.io/twitter/follow/argoproj?style=social)](https://twitter.com/argoproj)
[![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/argo-cd)](https://artifacthub.io/packages/helm/argo/argo-cd)
# Argo CD - Declarative Continuous Delivery for Kubernetes

View File

@@ -1,7 +1,6 @@
## Who uses Argo CD?
As the Argo Community grows, we'd like to keep track of our users. Please send a
PR with your organization name if you are using Argo CD.
As the Argo Community grows, we'd like to keep track of our users. Please send a PR with your organization name if you are using Argo CD.
Currently, the following organizations are **officially** using Argo CD:
@@ -9,7 +8,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [3Rein](https://www.3rein.com/)
1. [7shifts](https://www.7shifts.com/)
1. [Adevinta](https://www.adevinta.com/)
1. [Adfinis](https://adfinis.com)
1. [Adventure](https://jp.adventurekk.com/)
1. [Akuity](https://akuity.io/)
1. [Alibaba Group](https://www.alibabagroup.com/)
@@ -19,7 +17,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Ant Group](https://www.antgroup.com/)
1. [AppDirect](https://www.appdirect.com)
1. [Arctiq Inc.](https://www.arctiq.ca)
1. [ARZ Allgemeines Rechenzentrum GmbH](https://www.arz.at/)
1. [ARZ Allgemeines Rechenzentrum GmbH ](https://www.arz.at/)
1. [Axual B.V.](https://axual.com)
1. [Baloise](https://www.baloise.com)
1. [BCDevExchange DevOps Platform](https://bcdevexchange.org/DevOpsPlatform)
@@ -31,13 +29,11 @@ Currently, the following organizations are **officially** using Argo CD:
1. [BMW Group](https://www.bmwgroup.com/)
1. [Boozt](https://www.booztgroup.com/)
1. [Boticario](https://www.boticario.com.br/)
1. [Bulder Bank](https://bulderbank.no)
1. [Camptocamp](https://camptocamp.com)
1. [Capital One](https://www.capitalone.com)
1. [CARFAX](https://www.carfax.com)
1. [Casavo](https://casavo.com)
1. [Celonis](https://www.celonis.com/)
1. [CERN](https://home.cern/)
1. [Chargetrip](https://chargetrip.com)
1. [Chime](https://www.chime.com)
1. [Cisco ET&I](https://eti.cisco.com/)
@@ -45,7 +41,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Codefresh](https://www.codefresh.io/)
1. [Codility](https://www.codility.com/)
1. [Commonbond](https://commonbond.co/)
1. [Coralogix](https://coralogix.com/)
1. [CROZ d.o.o.](https://croz.net/)
1. [Crédit Agricole CIB](https://www.ca-cib.com)
1. [CyberAgent](https://www.cyberagent.co.jp/en/)
@@ -53,43 +48,32 @@ Currently, the following organizations are **officially** using Argo CD:
1. [D2iQ](https://www.d2iq.com)
1. [Datarisk](https://www.datarisk.io/)
1. [Deloitte](https://www.deloitte.com/)
1. [Deutsche Telekom AG](https://telekom.com)
1. [Devopsi - Poland Software/DevOps Consulting](https://devopsi.pl/)
1. [Devtron Labs](https://github.com/devtron-labs/devtron)
1. [EDF Renewables](https://www.edf-re.com/)
1. [edX](https://edx.org)
1. [Elastic](https://elastic.co/)
1. [Electronic Arts Inc.](https://www.ea.com)
1. [Elementor](https://elementor.com/)
1. [Electronic Arts Inc. ](https://www.ea.com)
1. [Elium](https://www.elium.com)
1. [END.](https://www.endclothing.com/)
1. [Energisme](https://energisme.com/)
1. [enigmo](https://enigmo.co.jp/)
1. [Faro](https://www.faro.com/)
1. [Fave](https://myfave.com)
1. [Flip](https://flip.id)
1. [Fonoa](https://www.fonoa.com/)
1. [freee](https://corp.freee.co.jp/en/company/)
1. [Freshop, Inc](https://www.freshop.com/)
1. [Future PLC](https://www.futureplc.com/)
1. [G DATA CyberDefense AG](https://www.gdata-software.com/)
1. [Garner](https://www.garnercorp.com)
1. [Generali Deutschland AG](https://www.generali.de/)
2. [Gepardec](https://gepardec.com/)
1. [Gitpod](https://www.gitpod.io)
1. [Gllue](https://gllue.com)
1. [gloat](https://gloat.com/)
1. [GLOBIS](https://globis.com)
1. [Glovo](https://www.glovoapp.com)
1. [GMETRI](https://gmetri.com/)
1. [Gojek](https://www.gojek.io/)
1. [Greenpass](https://www.greenpass.com.br/)
1. [Gridfuse](https://gridfuse.com/)
1. [Grupo MasMovil](https://grupomasmovil.com/en/)
1. [Handelsbanken](https://www.handelsbanken.se)
1. [Healy](https://www.healyworld.net)
1. [Helio](https://helio.exchange)
1. [Hetki](https://hetki.ai)
1. [hipages](https://hipages.com.au/)
1. [Hiya](https://hiya.com)
1. [Honestbank](https://honestbank.com)
@@ -103,7 +87,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Joblift](https://joblift.com/)
1. [JovianX](https://www.jovianx.com/)
1. [Kaltura](https://corp.kaltura.com/)
1. [Kandji](https://www.kandji.io/)
1. [KarrotPay](https://www.daangnpay.com/)
1. [Karrot](https://www.daangn.com/)
1. [Kasa](https://kasa.co.kr/)
@@ -113,13 +96,10 @@ Currently, the following organizations are **officially** using Argo CD:
1. [KintoHub](https://www.kintohub.com/)
1. [KompiTech GmbH](https://www.kompitech.com/)
1. [KubeSphere](https://github.com/kubesphere)
1. [Kurly](https://www.kurly.com/)
1. [LexisNexis](https://www.lexisnexis.com/)
1. [Lian Chu Securities](https://lczq.com)
1. [Lightricks](https://www.lightricks.com/)
1. [LINE](https://linecorp.com/en/)
1. [Lytt](https://www.lytt.co/)
1. [Magic Leap](https://www.magicleap.com/)
1. [Majid Al Futtaim](https://www.majidalfuttaim.com/)
1. [Major League Baseball](https://mlb.com)
1. [Mambu](https://www.mambu.com/)
@@ -127,7 +107,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Mattermost](https://www.mattermost.com)
1. [Max Kelsen](https://www.maxkelsen.com/)
1. [MeDirect](https://medirect.com.mt/)
1. [Meican](https://meican.com/)
1. [Metanet](http://www.metanet.co.kr/en/)
1. [MindSpore](https://mindspore.cn)
1. [Mirantis](https://mirantis.com/)
@@ -137,12 +116,10 @@ Currently, the following organizations are **officially** using Argo CD:
1. [MOO Print](https://www.moo.com/)
1. [MTN Group](https://www.mtn.com/)
1. [Natura &Co](https://naturaeco.com/)
1. [Nethopper](https://nethopper.io)
1. [New Relic](https://newrelic.com/)
1. [Nextdoor](https://nextdoor.com/)
1. [Nikkei](https://www.nikkei.co.jp/nikkeiinfo/en/)
1. [Nitro](https://gonitro.com)
1. [OCCMundial](https://occ.com.mx)
1. [Octadesk](https://octadesk.com)
1. [omegaUp](https://omegaUp.com)
1. [openEuler](https://openeuler.org)
@@ -150,29 +127,22 @@ Currently, the following organizations are **officially** using Argo CD:
1. [openLooKeng](https://openlookeng.io)
1. [OpenSaaS Studio](https://opensaas.studio)
1. [Opensurvey](https://www.opensurvey.co.kr/)
1. [OpsVerse](https://opsverse.io)
1. [Optoro](https://www.optoro.com/)
1. [Orbital Insight](https://orbitalinsight.com/)
1. [p3r](https://www.p3r.one/)
1. [Packlink](https://www.packlink.com/)
1. [Pandosearch](https://www.pandosearch.com/en/home)
1. [PagerDuty](https://www.pagerduty.com/)
1. [PayPay](https://paypay.ne.jp/)
1. [Peloton Interactive](https://www.onepeloton.com/)
1. [Pipefy](https://www.pipefy.com/)
1. [Pismo](https://pismo.io/)
1. [Polarpoint.io](https://polarpoint.io)
1. [Preferred Networks](https://preferred.jp/en/)
1. [Productboard](https://www.productboard.com/)
1. [Prudential](https://prudential.com.sg)
1. [PUBG](https://www.pubg.com)
1. [Qonto](https://qonto.com)
1. [QuintoAndar](https://quintoandar.com.br)
1. [Quipper](https://www.quipper.com/)
1. [RapidAPI](https://www.rapidapi.com/)
1. [Recreation.gov](https://www.recreation.gov/)
1. [Red Hat](https://www.redhat.com/)
1. [reev.com](https://www.reev.com/)
1. [RightRev](https://rightrev.com/)
1. [Rise](https://www.risecard.eu/)
1. [Riskified](https://www.riskified.com/)
@@ -187,11 +157,8 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Smilee.io](https://smilee.io)
1. [Snapp](https://snapp.ir/)
1. [Snyk](https://snyk.io/)
1. [Softway Medical](https://www.softwaymedical.fr/)
1. [South China Morning Post (SCMP)](https://www.scmp.com/)
1. [Speee](https://speee.jp/)
1. [Spendesk](https://spendesk.com/)
1. [Splunk](https://splunk.com/)
1. [Spores Labs](https://spores.app)
1. [Stuart](https://stuart.com/)
1. [Sumo Logic](https://sumologic.com/)
@@ -203,7 +170,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [TableCheck](https://tablecheck.com/)
1. [Tailor Brands](https://www.tailorbrands.com)
1. [Tamkeen Technologies](https://tamkeentech.sa/)
1. [Techcombank](https://www.techcombank.com.vn/trang-chu)
1. [Technacy](https://www.technacy.it/)
1. [Tesla](https://tesla.com/)
1. [ThousandEyes](https://www.thousandeyes.com/)
@@ -211,7 +177,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Tiger Analytics](https://www.tigeranalytics.com/)
1. [Tigera](https://www.tigera.io/)
1. [Toss](https://toss.im/en)
1. [Trendyol](https://www.trendyol.com/)
1. [tru.ID](https://tru.id)
1. [Twilio SendGrid](https://sendgrid.com)
1. [tZERO](https://www.tzero.com/)
@@ -228,7 +193,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Walkbase](https://www.walkbase.com/)
1. [Webstores](https://www.webstores.nl)
1. [Wehkamp](https://www.wehkamp.nl/)
1. [WeMaintain](https://www.wemaintain.com/)
1. [WeMo Scooter](https://www.wemoscooter.com/)
1. [Whitehat Berlin](https://whitehat.berlin) by Guido Maria Serra +Fenaroli
1. [Witick](https://witick.io/)
@@ -240,3 +204,5 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Yubo](https://www.yubo.live/)
1. [Zimpler](https://www.zimpler.com/)
1. [ZOZO](https://corp.zozo.com/)
1. [Trendyol](https://www.trendyol.com/)
1. [RapidAPI](https://www.rapidapi.com/)

View File

@@ -1 +1 @@
2.5.0
2.4.12

View File

@@ -19,6 +19,7 @@ import (
"fmt"
"time"
"github.com/go-logr/logr"
log "github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
apierr "k8s.io/apimachinery/pkg/api/errors"
@@ -36,11 +37,11 @@ import (
"github.com/argoproj/argo-cd/v2/applicationset/generators"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/util/db"
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
argoutil "github.com/argoproj/argo-cd/v2/util/argo"
"github.com/argoproj/argo-cd/v2/util/db"
)
const (
@@ -61,6 +62,7 @@ var (
// ApplicationSetReconciler reconciles a ApplicationSet object
type ApplicationSetReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
Recorder record.EventRecorder
Generators map[string]generators.Generator
@@ -75,14 +77,15 @@ type ApplicationSetReconciler struct {
// +kubebuilder:rbac:groups=argoproj.io,resources=applicationsets/status,verbs=get;update;patch
func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logCtx := log.WithField("applicationset", req.NamespacedName)
_ = r.Log.WithValues("applicationset", req.NamespacedName)
_ = log.WithField("applicationset", req.NamespacedName)
var applicationSetInfo argov1alpha1.ApplicationSet
var applicationSetInfo argoprojiov1alpha1.ApplicationSet
parametersGenerated := false
if err := r.Get(ctx, req.NamespacedName, &applicationSetInfo); err != nil {
if client.IgnoreNotFound(err) != nil {
logCtx.WithError(err).Infof("unable to get ApplicationSet: '%v' ", err)
log.WithError(err).Infof("unable to get ApplicationSet: '%v' ", err)
}
return ctrl.Result{}, client.IgnoreNotFound(err)
}
@@ -93,17 +96,17 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
}
// Log a warning if there are unrecognized generators
_ = utils.CheckInvalidGenerators(&applicationSetInfo)
utils.CheckInvalidGenerators(&applicationSetInfo)
// desiredApplications is the main list of all expected Applications from all generators in this appset.
desiredApplications, applicationSetReason, err := r.generateApplications(applicationSetInfo)
if err != nil {
_ = r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionErrorOccurred,
Message: err.Error(),
Reason: string(applicationSetReason),
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusTrue,
}, parametersGenerated,
)
return ctrl.Result{}, err
@@ -120,15 +123,15 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
//
// Changes to watched resources will cause this to be reconciled sooner than
// the RequeueAfter time.
logCtx.Errorf("error occurred during application validation: %s", err.Error())
log.Errorf("error occurred during application validation: %s", err.Error())
_ = r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionErrorOccurred,
Message: err.Error(),
Reason: argov1alpha1.ApplicationSetReasonApplicationValidationError,
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
Reason: argoprojiov1alpha1.ApplicationSetReasonApplicationValidationError,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusTrue,
}, parametersGenerated,
)
return ctrl.Result{RequeueAfter: ReconcileRequeueOnValidationError}, nil
@@ -145,7 +148,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
var message string
for _, v := range validateErrors {
message = v.Error()
logCtx.Errorf("validation error found during application validation: %s", message)
log.Errorf("validation error found during application validation: %s", message)
}
if len(validateErrors) > 1 {
// Only the last message gets added to the appset status, to keep the size reasonable.
@@ -153,11 +156,11 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
}
_ = r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionErrorOccurred,
Message: message,
Reason: argov1alpha1.ApplicationSetReasonApplicationValidationError,
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
Reason: argoprojiov1alpha1.ApplicationSetReasonApplicationValidationError,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusTrue,
}, parametersGenerated,
)
}
@@ -167,11 +170,11 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
if err != nil {
_ = r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionErrorOccurred,
Message: err.Error(),
Reason: argov1alpha1.ApplicationSetReasonUpdateApplicationError,
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
Reason: argoprojiov1alpha1.ApplicationSetReasonUpdateApplicationError,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusTrue,
}, parametersGenerated,
)
return ctrl.Result{}, err
@@ -181,11 +184,11 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
if err != nil {
_ = r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionErrorOccurred,
Message: err.Error(),
Reason: argov1alpha1.ApplicationSetReasonCreateApplicationError,
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
Reason: argoprojiov1alpha1.ApplicationSetReasonCreateApplicationError,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusTrue,
}, parametersGenerated,
)
return ctrl.Result{}, err
@@ -197,11 +200,11 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
if err != nil {
_ = r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionResourcesUpToDate,
argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionResourcesUpToDate,
Message: err.Error(),
Reason: argov1alpha1.ApplicationSetReasonDeleteApplicationError,
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
Reason: argoprojiov1alpha1.ApplicationSetReasonDeleteApplicationError,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusTrue,
}, parametersGenerated,
)
return ctrl.Result{}, err
@@ -212,14 +215,14 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
delete(applicationSetInfo.Annotations, common.AnnotationApplicationSetRefresh)
err := r.Client.Update(ctx, &applicationSetInfo)
if err != nil {
logCtx.Warnf("error occurred while updating ApplicationSet: %v", err)
log.Warnf("error occurred while updating ApplicationSet: %v", err)
_ = r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionErrorOccurred,
Message: err.Error(),
Reason: argov1alpha1.ApplicationSetReasonRefreshApplicationError,
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
Reason: argoprojiov1alpha1.ApplicationSetReasonRefreshApplicationError,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusTrue,
}, parametersGenerated,
)
return ctrl.Result{}, err
@@ -227,16 +230,16 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
}
requeueAfter := r.getMinRequeueAfter(&applicationSetInfo)
logCtx.WithField("requeueAfter", requeueAfter).Info("end reconcile")
log.WithField("requeueAfter", requeueAfter).Info("end reconcile")
if len(validateErrors) == 0 {
if err := r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionResourcesUpToDate,
argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionResourcesUpToDate,
Message: "All applications have been generated successfully",
Reason: argov1alpha1.ApplicationSetReasonApplicationSetUpToDate,
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
Reason: argoprojiov1alpha1.ApplicationSetReasonApplicationSetUpToDate,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusTrue,
}, parametersGenerated,
); err != nil {
return ctrl.Result{}, err
@@ -248,67 +251,67 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
}, nil
}
func getParametersGeneratedCondition(parametersGenerated bool, message string) argov1alpha1.ApplicationSetCondition {
var paramtersGeneratedCondition argov1alpha1.ApplicationSetCondition
func getParametersGeneratedCondition(parametersGenerated bool, message string) argoprojiov1alpha1.ApplicationSetCondition {
var paramtersGeneratedCondition argoprojiov1alpha1.ApplicationSetCondition
if parametersGenerated {
paramtersGeneratedCondition = argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionParametersGenerated,
paramtersGeneratedCondition = argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionParametersGenerated,
Message: "Successfully generated parameters for all Applications",
Reason: argov1alpha1.ApplicationSetReasonParametersGenerated,
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
Reason: argoprojiov1alpha1.ApplicationSetReasonParametersGenerated,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusTrue,
}
} else {
paramtersGeneratedCondition = argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionParametersGenerated,
paramtersGeneratedCondition = argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionParametersGenerated,
Message: message,
Reason: argov1alpha1.ApplicationSetReasonErrorOccurred,
Status: argov1alpha1.ApplicationSetConditionStatusFalse,
Reason: argoprojiov1alpha1.ApplicationSetReasonErrorOccurred,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusFalse,
}
}
return paramtersGeneratedCondition
}
func getResourceUpToDateCondition(errorOccurred bool, message string, reason string) argov1alpha1.ApplicationSetCondition {
var resourceUpToDateCondition argov1alpha1.ApplicationSetCondition
func getResourceUpToDateCondition(errorOccurred bool, message string, reason string) argoprojiov1alpha1.ApplicationSetCondition {
var resourceUpToDateCondition argoprojiov1alpha1.ApplicationSetCondition
if errorOccurred {
resourceUpToDateCondition = argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionResourcesUpToDate,
resourceUpToDateCondition = argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionResourcesUpToDate,
Message: message,
Reason: reason,
Status: argov1alpha1.ApplicationSetConditionStatusFalse,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusFalse,
}
} else {
resourceUpToDateCondition = argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionResourcesUpToDate,
resourceUpToDateCondition = argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionResourcesUpToDate,
Message: "ApplicationSet up to date",
Reason: argov1alpha1.ApplicationSetReasonApplicationSetUpToDate,
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
Reason: argoprojiov1alpha1.ApplicationSetReasonApplicationSetUpToDate,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusTrue,
}
}
return resourceUpToDateCondition
}
func (r *ApplicationSetReconciler) setApplicationSetStatusCondition(ctx context.Context, applicationSet *argov1alpha1.ApplicationSet, condition argov1alpha1.ApplicationSetCondition, paramtersGenerated bool) error {
func (r *ApplicationSetReconciler) setApplicationSetStatusCondition(ctx context.Context, applicationSet *argoprojiov1alpha1.ApplicationSet, condition argoprojiov1alpha1.ApplicationSetCondition, paramtersGenerated bool) error {
// check if error occurred during reconcile process
errOccurred := condition.Type == argov1alpha1.ApplicationSetConditionErrorOccurred
errOccurred := condition.Type == argoprojiov1alpha1.ApplicationSetConditionErrorOccurred
var errOccurredCondition argov1alpha1.ApplicationSetCondition
var errOccurredCondition argoprojiov1alpha1.ApplicationSetCondition
if errOccurred {
errOccurredCondition = condition
} else {
errOccurredCondition = argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
errOccurredCondition = argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionErrorOccurred,
Message: "Successfully generated parameters for all Applications",
Reason: argov1alpha1.ApplicationSetReasonApplicationSetUpToDate,
Status: argov1alpha1.ApplicationSetConditionStatusFalse,
Reason: argoprojiov1alpha1.ApplicationSetReasonApplicationSetUpToDate,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusFalse,
}
}
paramtersGeneratedCondition := getParametersGeneratedCondition(paramtersGenerated, condition.Message)
resourceUpToDateCondition := getResourceUpToDateCondition(errOccurred, condition.Message, condition.Reason)
newConditions := []argov1alpha1.ApplicationSetCondition{errOccurredCondition, paramtersGeneratedCondition, resourceUpToDateCondition}
newConditions := []argoprojiov1alpha1.ApplicationSetCondition{errOccurredCondition, paramtersGeneratedCondition, resourceUpToDateCondition}
needToUpdateConditions := false
for _, condition := range newConditions {
@@ -320,10 +323,10 @@ func (r *ApplicationSetReconciler) setApplicationSetStatusCondition(ctx context.
}
}
}
evaluatedTypes := map[argov1alpha1.ApplicationSetConditionType]bool{
argov1alpha1.ApplicationSetConditionErrorOccurred: true,
argov1alpha1.ApplicationSetConditionParametersGenerated: true,
argov1alpha1.ApplicationSetConditionResourcesUpToDate: true,
evaluatedTypes := map[argoprojiov1alpha1.ApplicationSetConditionType]bool{
argoprojiov1alpha1.ApplicationSetConditionErrorOccurred: true,
argoprojiov1alpha1.ApplicationSetConditionParametersGenerated: true,
argoprojiov1alpha1.ApplicationSetConditionResourcesUpToDate: true,
}
if needToUpdateConditions || len(applicationSet.Status.Conditions) < 3 {
@@ -352,7 +355,7 @@ func (r *ApplicationSetReconciler) setApplicationSetStatusCondition(ctx context.
// validateGeneratedApplications uses the Argo CD validation functions to verify the correctness of the
// generated applications.
func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Context, desiredApplications []argov1alpha1.Application, applicationSetInfo argov1alpha1.ApplicationSet, namespace string) (map[int]error, error) {
func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Context, desiredApplications []argov1alpha1.Application, applicationSetInfo argoprojiov1alpha1.ApplicationSet, namespace string) (map[int]error, error) {
errorsByIndex := map[int]error{}
namesSet := map[string]bool{}
for i, app := range desiredApplications {
@@ -392,7 +395,7 @@ func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Con
return errorsByIndex, nil
}
func (r *ApplicationSetReconciler) getMinRequeueAfter(applicationSetInfo *argov1alpha1.ApplicationSet) time.Duration {
func (r *ApplicationSetReconciler) getMinRequeueAfter(applicationSetInfo *argoprojiov1alpha1.ApplicationSet) time.Duration {
var res time.Duration
for _, requestedGenerator := range applicationSetInfo.Spec.Generators {
@@ -412,7 +415,7 @@ func (r *ApplicationSetReconciler) getMinRequeueAfter(applicationSetInfo *argov1
return res
}
func getTempApplication(applicationSetTemplate argov1alpha1.ApplicationSetTemplate) *argov1alpha1.Application {
func getTempApplication(applicationSetTemplate argoprojiov1alpha1.ApplicationSetTemplate) *argov1alpha1.Application {
var tmplApplication argov1alpha1.Application
tmplApplication.Annotations = applicationSetTemplate.Annotations
tmplApplication.Labels = applicationSetTemplate.Labels
@@ -424,20 +427,20 @@ func getTempApplication(applicationSetTemplate argov1alpha1.ApplicationSetTempla
return &tmplApplication
}
func (r *ApplicationSetReconciler) generateApplications(applicationSetInfo argov1alpha1.ApplicationSet) ([]argov1alpha1.Application, argov1alpha1.ApplicationSetReasonType, error) {
func (r *ApplicationSetReconciler) generateApplications(applicationSetInfo argoprojiov1alpha1.ApplicationSet) ([]argov1alpha1.Application, argoprojiov1alpha1.ApplicationSetReasonType, error) {
var res []argov1alpha1.Application
var firstError error
var applicationSetReason argov1alpha1.ApplicationSetReasonType
var applicationSetReason argoprojiov1alpha1.ApplicationSetReasonType
for _, requestedGenerator := range applicationSetInfo.Spec.Generators {
t, err := generators.Transform(requestedGenerator, r.Generators, applicationSetInfo.Spec.Template, &applicationSetInfo, map[string]interface{}{})
t, err := generators.Transform(requestedGenerator, r.Generators, applicationSetInfo.Spec.Template, &applicationSetInfo)
if err != nil {
log.WithError(err).WithField("generator", requestedGenerator).
Error("error generating application from params")
if firstError == nil {
firstError = err
applicationSetReason = argov1alpha1.ApplicationSetReasonApplicationParamsGenerationError
applicationSetReason = argoprojiov1alpha1.ApplicationSetReasonApplicationParamsGenerationError
}
continue
}
@@ -446,14 +449,14 @@ func (r *ApplicationSetReconciler) generateApplications(applicationSetInfo argov
tmplApplication := getTempApplication(a.Template)
for _, p := range a.Params {
app, err := r.Renderer.RenderTemplateParams(tmplApplication, applicationSetInfo.Spec.SyncPolicy, p, applicationSetInfo.Spec.GoTemplate)
app, err := r.Renderer.RenderTemplateParams(tmplApplication, applicationSetInfo.Spec.SyncPolicy, p)
if err != nil {
log.WithError(err).WithField("params", a.Params).WithField("generator", requestedGenerator).
Error("error generating application from params")
if firstError == nil {
firstError = err
applicationSetReason = argov1alpha1.ApplicationSetReasonRenderTemplateParamsError
applicationSetReason = argoprojiov1alpha1.ApplicationSetReasonRenderTemplateParamsError
}
continue
}
@@ -477,18 +480,18 @@ func (r *ApplicationSetReconciler) SetupWithManager(mgr ctrl.Manager) error {
return nil
}
// ...make sure it's a application set...
if owner.APIVersion != argov1alpha1.SchemeGroupVersion.String() || owner.Kind != "ApplicationSet" {
if owner.APIVersion != argoprojiov1alpha1.GroupVersion.String() || owner.Kind != "ApplicationSet" {
return nil
}
// ...and if so, return it
return []string{owner.Name}
}); err != nil {
return fmt.Errorf("error setting up with manager: %w", err)
return err
}
return ctrl.NewControllerManagedBy(mgr).
For(&argov1alpha1.ApplicationSet{}).
For(&argoprojiov1alpha1.ApplicationSet{}).
Owns(&argov1alpha1.Application{}).
Watches(
&source.Kind{Type: &corev1.Secret{}},
@@ -504,7 +507,7 @@ func (r *ApplicationSetReconciler) SetupWithManager(mgr ctrl.Manager) error {
// - For new applications, it will call create
// - For existing application, it will call update
// The function also adds owner reference to all applications, and uses it to delete them.
func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error {
func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context, applicationSet argoprojiov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error {
var firstError error
// Creates or updates the application in appList
@@ -562,12 +565,12 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context,
// createInCluster will filter from the desiredApplications only the application that needs to be created
// Then it will call createOrUpdateInCluster to do the actual create
func (r *ApplicationSetReconciler) createInCluster(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error {
func (r *ApplicationSetReconciler) createInCluster(ctx context.Context, applicationSet argoprojiov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error {
var createApps []argov1alpha1.Application
current, err := r.getCurrentApplications(ctx, applicationSet)
if err != nil {
return fmt.Errorf("error getting current applications: %w", err)
return err
}
m := make(map[string]bool) // Will holds the app names that are current in the cluster
@@ -588,7 +591,7 @@ func (r *ApplicationSetReconciler) createInCluster(ctx context.Context, applicat
return r.createOrUpdateInCluster(ctx, applicationSet, createApps)
}
func (r *ApplicationSetReconciler) getCurrentApplications(_ context.Context, applicationSet argov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error) {
func (r *ApplicationSetReconciler) getCurrentApplications(_ context.Context, applicationSet argoprojiov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error) {
// TODO: Should this use the context param?
var current argov1alpha1.ApplicationList
err := r.Client.List(context.Background(), &current, client.MatchingFields{".metadata.controller": applicationSet.Name})
@@ -602,19 +605,19 @@ func (r *ApplicationSetReconciler) getCurrentApplications(_ context.Context, app
// deleteInCluster will delete Applications that are currently on the cluster, but not in appList.
// The function must be called after all generators had been called and generated applications
func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error {
func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, applicationSet argoprojiov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error {
// settingsMgr := settings.NewSettingsManager(context.TODO(), r.KubeClientset, applicationSet.Namespace)
// argoDB := db.NewDB(applicationSet.Namespace, settingsMgr, r.KubeClientset)
// clusterList, err := argoDB.ListClusters(ctx)
clusterList, err := utils.ListClusters(ctx, r.KubeClientset, applicationSet.Namespace)
if err != nil {
return fmt.Errorf("error listing clusters: %w", err)
return err
}
// Save current applications to be able to delete the ones that are not in appList
current, err := r.getCurrentApplications(ctx, applicationSet)
if err != nil {
return fmt.Errorf("error getting current applications: %w", err)
return err
}
m := make(map[string]bool) // Will holds the app names in appList for the deletion process
@@ -657,7 +660,7 @@ func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, applicat
}
// removeFinalizerOnInvalidDestination removes the Argo CD resources finalizer if the application contains an invalid target (eg missing cluster)
func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, app *argov1alpha1.Application, clusterList *argov1alpha1.ClusterList, appLog *log.Entry) error {
func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx context.Context, applicationSet argoprojiov1alpha1.ApplicationSet, app *argov1alpha1.Application, clusterList *argov1alpha1.ClusterList, appLog *log.Entry) error {
// Only check if the finalizers need to be removed IF there are finalizers to remove
if len(app.Finalizers) == 0 {
@@ -718,7 +721,7 @@ func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx conte
err := r.Client.Update(ctx, app, &client.UpdateOptions{})
if err != nil {
return fmt.Errorf("error updating finalizers: %w", err)
return err
}
}
}

View File

@@ -26,9 +26,9 @@ import (
"github.com/argoproj/argo-cd/v2/applicationset/generators"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/fake"
dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks"
)
@@ -37,30 +37,30 @@ type generatorMock struct {
mock.Mock
}
func (g *generatorMock) GetTemplate(appSetGenerator *argov1alpha1.ApplicationSetGenerator) *argov1alpha1.ApplicationSetTemplate {
func (g *generatorMock) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate {
args := g.Called(appSetGenerator)
return args.Get(0).(*argov1alpha1.ApplicationSetTemplate)
return args.Get(0).(*argoprojiov1alpha1.ApplicationSetTemplate)
}
func (g *generatorMock) GenerateParams(appSetGenerator *argov1alpha1.ApplicationSetGenerator, _ *argov1alpha1.ApplicationSet) ([]map[string]interface{}, error) {
func (g *generatorMock) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, _ *argoprojiov1alpha1.ApplicationSet) ([]map[string]string, error) {
args := g.Called(appSetGenerator)
return args.Get(0).([]map[string]interface{}), args.Error(1)
return args.Get(0).([]map[string]string), args.Error(1)
}
type rendererMock struct {
mock.Mock
}
func (g *generatorMock) GetRequeueAfter(appSetGenerator *argov1alpha1.ApplicationSetGenerator) time.Duration {
func (g *generatorMock) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration {
args := g.Called(appSetGenerator)
return args.Get(0).(time.Duration)
}
func (r *rendererMock) RenderTemplateParams(tmpl *argov1alpha1.Application, syncPolicy *argov1alpha1.ApplicationSetSyncPolicy, params map[string]interface{}, useGoTemplate bool) (*argov1alpha1.Application, error) {
args := r.Called(tmpl, params, useGoTemplate)
func (r *rendererMock) RenderTemplateParams(tmpl *argov1alpha1.Application, syncPolicy *argoprojiov1alpha1.ApplicationSetSyncPolicy, params map[string]string) (*argov1alpha1.Application, error) {
args := r.Called(tmpl, params)
if args.Error(1) != nil {
return nil, args.Error(1)
@@ -72,7 +72,7 @@ func (r *rendererMock) RenderTemplateParams(tmpl *argov1alpha1.Application, sync
func TestExtractApplications(t *testing.T) {
scheme := runtime.NewScheme()
err := argov1alpha1.AddToScheme(scheme)
err := argoprojiov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = argov1alpha1.AddToScheme(scheme)
@@ -80,8 +80,8 @@ func TestExtractApplications(t *testing.T) {
for _, c := range []struct {
name string
params []map[string]interface{}
template argov1alpha1.ApplicationSetTemplate
params []map[string]string
template argoprojiov1alpha1.ApplicationSetTemplate
generateParamsError error
rendererError error
expectErr bool
@@ -89,9 +89,9 @@ func TestExtractApplications(t *testing.T) {
}{
{
name: "Generate two applications",
params: []map[string]interface{}{{"name": "app1"}, {"name": "app2"}},
template: argov1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{
params: []map[string]string{{"name": "app1"}, {"name": "app2"}},
template: argoprojiov1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: argoprojiov1alpha1.ApplicationSetTemplateMeta{
Name: "name",
Namespace: "namespace",
Labels: map[string]string{"label_name": "label_value"},
@@ -108,9 +108,9 @@ func TestExtractApplications(t *testing.T) {
},
{
name: "Handles error from the render",
params: []map[string]interface{}{{"name": "app1"}, {"name": "app2"}},
template: argov1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{
params: []map[string]string{{"name": "app1"}, {"name": "app2"}},
template: argoprojiov1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: argoprojiov1alpha1.ApplicationSetTemplateMeta{
Name: "name",
Namespace: "namespace",
Labels: map[string]string{"label_name": "label_value"},
@@ -131,7 +131,7 @@ func TestExtractApplications(t *testing.T) {
t.Run(cc.name, func(t *testing.T) {
appSet := &argov1alpha1.ApplicationSet{
appSet := &argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
@@ -141,15 +141,15 @@ func TestExtractApplications(t *testing.T) {
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(appSet).Build()
generatorMock := generatorMock{}
generator := argov1alpha1.ApplicationSetGenerator{
List: &argov1alpha1.ListGenerator{},
generator := argoprojiov1alpha1.ApplicationSetGenerator{
List: &argoprojiov1alpha1.ListGenerator{},
}
generatorMock.On("GenerateParams", &generator).
Return(cc.params, cc.generateParamsError)
generatorMock.On("GetTemplate", &generator).
Return(&argov1alpha1.ApplicationSetTemplate{})
Return(&argoprojiov1alpha1.ApplicationSetTemplate{})
rendererMock := rendererMock{}
@@ -159,10 +159,10 @@ func TestExtractApplications(t *testing.T) {
for _, p := range cc.params {
if cc.rendererError != nil {
rendererMock.On("RenderTemplateParams", getTempApplication(cc.template), p, false).
rendererMock.On("RenderTemplateParams", getTempApplication(cc.template), p).
Return(nil, cc.rendererError)
} else {
rendererMock.On("RenderTemplateParams", getTempApplication(cc.template), p, false).
rendererMock.On("RenderTemplateParams", getTempApplication(cc.template), p).
Return(&app, nil)
expectedApps = append(expectedApps, app)
}
@@ -180,13 +180,13 @@ func TestExtractApplications(t *testing.T) {
KubeClientset: kubefake.NewSimpleClientset(),
}
got, reason, err := r.generateApplications(argov1alpha1.ApplicationSet{
got, reason, err := r.generateApplications(argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{generator},
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{generator},
Template: cc.template,
},
})
@@ -211,39 +211,39 @@ func TestExtractApplications(t *testing.T) {
func TestMergeTemplateApplications(t *testing.T) {
scheme := runtime.NewScheme()
_ = argov1alpha1.AddToScheme(scheme)
_ = argoprojiov1alpha1.AddToScheme(scheme)
_ = argov1alpha1.AddToScheme(scheme)
client := fake.NewClientBuilder().WithScheme(scheme).Build()
for _, c := range []struct {
name string
params []map[string]interface{}
template argov1alpha1.ApplicationSetTemplate
overrideTemplate argov1alpha1.ApplicationSetTemplate
expectedMerged argov1alpha1.ApplicationSetTemplate
params []map[string]string
template argoprojiov1alpha1.ApplicationSetTemplate
overrideTemplate argoprojiov1alpha1.ApplicationSetTemplate
expectedMerged argoprojiov1alpha1.ApplicationSetTemplate
expectedApps []argov1alpha1.Application
}{
{
name: "Generate app",
params: []map[string]interface{}{{"name": "app1"}},
template: argov1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{
params: []map[string]string{{"name": "app1"}},
template: argoprojiov1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: argoprojiov1alpha1.ApplicationSetTemplateMeta{
Name: "name",
Namespace: "namespace",
Labels: map[string]string{"label_name": "label_value"},
},
Spec: argov1alpha1.ApplicationSpec{},
},
overrideTemplate: argov1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{
overrideTemplate: argoprojiov1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: argoprojiov1alpha1.ApplicationSetTemplateMeta{
Name: "test",
Labels: map[string]string{"foo": "bar"},
},
Spec: argov1alpha1.ApplicationSpec{},
},
expectedMerged: argov1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{
expectedMerged: argoprojiov1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: argoprojiov1alpha1.ApplicationSetTemplateMeta{
Name: "test",
Namespace: "namespace",
Labels: map[string]string{"label_name": "label_value", "foo": "bar"},
@@ -267,8 +267,8 @@ func TestMergeTemplateApplications(t *testing.T) {
t.Run(cc.name, func(t *testing.T) {
generatorMock := generatorMock{}
generator := argov1alpha1.ApplicationSetGenerator{
List: &argov1alpha1.ListGenerator{},
generator := argoprojiov1alpha1.ApplicationSetGenerator{
List: &argoprojiov1alpha1.ListGenerator{},
}
generatorMock.On("GenerateParams", &generator).
@@ -279,7 +279,7 @@ func TestMergeTemplateApplications(t *testing.T) {
rendererMock := rendererMock{}
rendererMock.On("RenderTemplateParams", getTempApplication(cc.expectedMerged), cc.params[0], false).
rendererMock.On("RenderTemplateParams", getTempApplication(cc.expectedMerged), cc.params[0]).
Return(&cc.expectedApps[0], nil)
r := ApplicationSetReconciler{
@@ -293,13 +293,13 @@ func TestMergeTemplateApplications(t *testing.T) {
KubeClientset: kubefake.NewSimpleClientset(),
}
got, _, _ := r.generateApplications(argov1alpha1.ApplicationSet{
got, _, _ := r.generateApplications(argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{generator},
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{generator},
Template: cc.template,
},
},
@@ -314,7 +314,7 @@ func TestMergeTemplateApplications(t *testing.T) {
func TestCreateOrUpdateInCluster(t *testing.T) {
scheme := runtime.NewScheme()
err := argov1alpha1.AddToScheme(scheme)
err := argoprojiov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = argov1alpha1.AddToScheme(scheme)
@@ -324,7 +324,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
// name is human-readable test name
name string
// appSet is the ApplicationSet we are generating resources for
appSet argov1alpha1.ApplicationSet
appSet argoprojiov1alpha1.ApplicationSet
// existingApps are the apps that already exist on the cluster
existingApps []argov1alpha1.Application
// desiredApps are the generated apps to create/update
@@ -334,7 +334,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
}{
{
name: "Create an app that doesn't exist",
appSet: argov1alpha1.ApplicationSet{
appSet: argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
@@ -364,13 +364,13 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
},
{
name: "Update an existing app with a different project name",
appSet: argov1alpha1.ApplicationSet{
appSet: argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Template: argov1alpha1.ApplicationSetTemplate{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Template: argoprojiov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
},
@@ -422,13 +422,13 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
},
{
name: "Create a new app and check it doesn't replace the existing app",
appSet: argov1alpha1.ApplicationSet{
appSet: argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Template: argov1alpha1.ApplicationSetTemplate{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Template: argoprojiov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
},
@@ -480,13 +480,13 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
},
{
name: "Ensure that labels and annotations are added (via update) into an exiting application",
appSet: argov1alpha1.ApplicationSet{
appSet: argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Template: argov1alpha1.ApplicationSetTemplate{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Template: argoprojiov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
},
@@ -542,13 +542,13 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
},
{
name: "Ensure that labels and annotations are removed from an existing app",
appSet: argov1alpha1.ApplicationSet{
appSet: argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Template: argov1alpha1.ApplicationSetTemplate{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Template: argoprojiov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
},
@@ -601,14 +601,14 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
},
},
{
name: "Ensure that status and operation fields are not overridden by an update, when removing labels/annotations",
appSet: argov1alpha1.ApplicationSet{
name: "Ensure that status and operation fields are not overriden by an update, when removing labels/annotations",
appSet: argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Template: argov1alpha1.ApplicationSetTemplate{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Template: argoprojiov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
},
@@ -673,14 +673,14 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
},
},
{
name: "Ensure that status and operation fields are not overridden by an update, when removing labels/annotations and adding other fields",
appSet: argov1alpha1.ApplicationSet{
name: "Ensure that status and operation fields are not overriden by an update, when removing labels/annotations and adding other fields",
appSet: argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Template: argov1alpha1.ApplicationSetTemplate{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Template: argoprojiov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
Source: argov1alpha1.ApplicationSource{Path: "path", TargetRevision: "revision", RepoURL: "repoURL"},
@@ -754,13 +754,13 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
},
{
name: "Ensure that argocd notifications state and refresh annotation is preserved from an existing app",
appSet: argov1alpha1.ApplicationSet{
appSet: argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Template: argov1alpha1.ApplicationSetTemplate{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Template: argoprojiov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
},
@@ -861,7 +861,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
func TestRemoveFinalizerOnInvalidDestination_FinalizerTypes(t *testing.T) {
scheme := runtime.NewScheme()
err := argov1alpha1.AddToScheme(scheme)
err := argoprojiov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = argov1alpha1.AddToScheme(scheme)
@@ -896,13 +896,13 @@ func TestRemoveFinalizerOnInvalidDestination_FinalizerTypes(t *testing.T) {
} {
t.Run(c.name, func(t *testing.T) {
appSet := argov1alpha1.ApplicationSet{
appSet := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Template: argov1alpha1.ApplicationSetTemplate{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Template: argoprojiov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
},
@@ -985,7 +985,7 @@ func TestRemoveFinalizerOnInvalidDestination_FinalizerTypes(t *testing.T) {
func TestRemoveFinalizerOnInvalidDestination_DestinationTypes(t *testing.T) {
scheme := runtime.NewScheme()
err := argov1alpha1.AddToScheme(scheme)
err := argoprojiov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = argov1alpha1.AddToScheme(scheme)
@@ -1058,13 +1058,13 @@ func TestRemoveFinalizerOnInvalidDestination_DestinationTypes(t *testing.T) {
t.Run(c.name, func(t *testing.T) {
appSet := argov1alpha1.ApplicationSet{
appSet := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Template: argov1alpha1.ApplicationSetTemplate{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Template: argoprojiov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
},
@@ -1144,20 +1144,20 @@ func TestRemoveFinalizerOnInvalidDestination_DestinationTypes(t *testing.T) {
func TestCreateApplications(t *testing.T) {
scheme := runtime.NewScheme()
err := argov1alpha1.AddToScheme(scheme)
err := argoprojiov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = argov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
for _, c := range []struct {
appSet argov1alpha1.ApplicationSet
appSet argoprojiov1alpha1.ApplicationSet
existsApps []argov1alpha1.Application
apps []argov1alpha1.Application
expected []argov1alpha1.Application
}{
{
appSet: argov1alpha1.ApplicationSet{
appSet: argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
@@ -1186,13 +1186,13 @@ func TestCreateApplications(t *testing.T) {
},
},
{
appSet: argov1alpha1.ApplicationSet{
appSet: argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Template: argov1alpha1.ApplicationSetTemplate{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Template: argoprojiov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
},
@@ -1243,13 +1243,13 @@ func TestCreateApplications(t *testing.T) {
},
},
{
appSet: argov1alpha1.ApplicationSet{
appSet: argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Template: argov1alpha1.ApplicationSetTemplate{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Template: argoprojiov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
},
@@ -1337,14 +1337,14 @@ func TestCreateApplications(t *testing.T) {
func TestDeleteInCluster(t *testing.T) {
scheme := runtime.NewScheme()
err := argov1alpha1.AddToScheme(scheme)
err := argoprojiov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = argov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
for _, c := range []struct {
// appSet is the application set on which the delete function is called
appSet argov1alpha1.ApplicationSet
appSet argoprojiov1alpha1.ApplicationSet
// existingApps is the current state of Applications on the cluster
existingApps []argov1alpha1.Application
// desireApps is the apps generated by the generator that we wish to keep alive
@@ -1355,13 +1355,13 @@ func TestDeleteInCluster(t *testing.T) {
notExpected []argov1alpha1.Application
}{
{
appSet: argov1alpha1.ApplicationSet{
appSet: argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Template: argov1alpha1.ApplicationSetTemplate{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Template: argoprojiov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
},
@@ -1491,17 +1491,17 @@ func TestDeleteInCluster(t *testing.T) {
func TestGetMinRequeueAfter(t *testing.T) {
scheme := runtime.NewScheme()
err := argov1alpha1.AddToScheme(scheme)
err := argoprojiov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = argov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
client := fake.NewClientBuilder().WithScheme(scheme).Build()
generator := argov1alpha1.ApplicationSetGenerator{
List: &argov1alpha1.ListGenerator{},
Git: &argov1alpha1.GitGenerator{},
Clusters: &argov1alpha1.ClusterGenerator{},
generator := argoprojiov1alpha1.ApplicationSetGenerator{
List: &argoprojiov1alpha1.ListGenerator{},
Git: &argoprojiov1alpha1.GitGenerator{},
Clusters: &argoprojiov1alpha1.ClusterGenerator{},
}
generatorMock0 := generatorMock{}
@@ -1527,9 +1527,9 @@ func TestGetMinRequeueAfter(t *testing.T) {
},
}
got := r.getMinRequeueAfter(&argov1alpha1.ApplicationSet{
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{generator},
got := r.getMinRequeueAfter(&argoprojiov1alpha1.ApplicationSet{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{generator},
},
})
@@ -1539,7 +1539,7 @@ func TestGetMinRequeueAfter(t *testing.T) {
func TestValidateGeneratedApplications(t *testing.T) {
scheme := runtime.NewScheme()
err := argov1alpha1.AddToScheme(scheme)
err := argoprojiov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = argov1alpha1.AddToScheme(scheme)
@@ -1739,7 +1739,7 @@ func TestValidateGeneratedApplications(t *testing.T) {
KubeClientset: kubeclientset,
}
appSetInfo := argov1alpha1.ApplicationSet{}
appSetInfo := argoprojiov1alpha1.ApplicationSet{}
validationErrors, _ := r.validateGeneratedApplications(context.TODO(), cc.apps, appSetInfo, "namespace")
var errorMessages []string
@@ -1777,7 +1777,7 @@ func TestValidateGeneratedApplications(t *testing.T) {
func TestReconcilerValidationErrorBehaviour(t *testing.T) {
scheme := runtime.NewScheme()
err := argov1alpha1.AddToScheme(scheme)
err := argoprojiov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = argov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
@@ -1786,16 +1786,15 @@ func TestReconcilerValidationErrorBehaviour(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "argocd"},
Spec: argov1alpha1.AppProjectSpec{SourceRepos: []string{"*"}, Destinations: []argov1alpha1.ApplicationDestination{{Namespace: "*", Server: "https://good-cluster"}}},
}
appSet := argov1alpha1.ApplicationSet{
appSet := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
GoTemplate: true,
Generators: []argov1alpha1.ApplicationSetGenerator{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{
{
List: &argov1alpha1.ListGenerator{
List: &argoprojiov1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{{
Raw: []byte(`{"cluster": "good-cluster","url": "https://good-cluster"}`),
}, {
@@ -1804,15 +1803,15 @@ func TestReconcilerValidationErrorBehaviour(t *testing.T) {
},
},
},
Template: argov1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{
Name: "{{.cluster}}",
Template: argoprojiov1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: argoprojiov1alpha1.ApplicationSetTemplateMeta{
Name: "{{cluster}}",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSpec{
Source: argov1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argocd-example-apps", Path: "guestbook"},
Project: "default",
Destination: argov1alpha1.ApplicationDestination{Server: "{{.url}}"},
Destination: argov1alpha1.ApplicationDestination{Server: "{{url}}"},
},
},
},
@@ -1832,6 +1831,7 @@ func TestReconcilerValidationErrorBehaviour(t *testing.T) {
}}, nil)
r := ApplicationSetReconciler{
Log: ctrl.Log.WithName("controllers").WithName("ApplicationSet"),
Client: client,
Scheme: scheme,
Renderer: &utils.Render{},
@@ -1871,33 +1871,33 @@ func TestReconcilerValidationErrorBehaviour(t *testing.T) {
func TestSetApplicationSetStatusCondition(t *testing.T) {
scheme := runtime.NewScheme()
err := argov1alpha1.AddToScheme(scheme)
err := argoprojiov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = argov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
appSet := argov1alpha1.ApplicationSet{
appSet := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
{List: &argov1alpha1.ListGenerator{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{
{List: &argoprojiov1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{{
Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`),
}},
}},
},
Template: argov1alpha1.ApplicationSetTemplate{},
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
},
}
appCondition := argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionResourcesUpToDate,
appCondition := argoprojiov1alpha1.ApplicationSetCondition{
Type: argoprojiov1alpha1.ApplicationSetConditionResourcesUpToDate,
Message: "All applications have been generated successfully",
Reason: argov1alpha1.ApplicationSetReasonApplicationSetUpToDate,
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
Reason: argoprojiov1alpha1.ApplicationSetReasonApplicationSetUpToDate,
Status: argoprojiov1alpha1.ApplicationSetConditionStatusTrue,
}
kubeclientset := kubefake.NewSimpleClientset([]runtime.Object{}...)
@@ -1907,6 +1907,7 @@ func TestSetApplicationSetStatusCondition(t *testing.T) {
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).Build()
r := ApplicationSetReconciler{
Log: ctrl.Log.WithName("controllers").WithName("ApplicationSet"),
Client: client,
Scheme: scheme,
Renderer: &utils.Render{},

View File

@@ -12,7 +12,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/event"
"github.com/argoproj/argo-cd/v2/applicationset/generators"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
// clusterSecretEventHandler is used when watching Secrets to check if they are ArgoCD Cluster Secrets, and if so

View File

@@ -15,12 +15,13 @@ import (
"github.com/argoproj/argo-cd/v2/applicationset/generators"
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
func TestClusterEventHandler(t *testing.T) {
scheme := runtime.NewScheme()
err := argov1alpha1.AddToScheme(scheme)
err := argoprojiov1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = argov1alpha1.AddToScheme(scheme)
@@ -28,13 +29,13 @@ func TestClusterEventHandler(t *testing.T) {
tests := []struct {
name string
items []argov1alpha1.ApplicationSet
items []argoprojiov1alpha1.ApplicationSet
secret corev1.Secret
expectedRequests []ctrl.Request
}{
{
name: "no application sets should mean no requests",
items: []argov1alpha1.ApplicationSet{},
items: []argoprojiov1alpha1.ApplicationSet{},
secret: corev1.Secret{
ObjectMeta: v1.ObjectMeta{
Namespace: "argocd",
@@ -48,16 +49,16 @@ func TestClusterEventHandler(t *testing.T) {
},
{
name: "a cluster generator should produce a request",
items: []argov1alpha1.ApplicationSet{
items: []argoprojiov1alpha1.ApplicationSet{
{
ObjectMeta: v1.ObjectMeta{
Name: "my-app-set",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{
{
Clusters: &argov1alpha1.ClusterGenerator{},
Clusters: &argoprojiov1alpha1.ClusterGenerator{},
},
},
},
@@ -78,16 +79,16 @@ func TestClusterEventHandler(t *testing.T) {
},
{
name: "multiple cluster generators should produce multiple requests",
items: []argov1alpha1.ApplicationSet{
items: []argoprojiov1alpha1.ApplicationSet{
{
ObjectMeta: v1.ObjectMeta{
Name: "my-app-set",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{
{
Clusters: &argov1alpha1.ClusterGenerator{},
Clusters: &argoprojiov1alpha1.ClusterGenerator{},
},
},
},
@@ -97,10 +98,10 @@ func TestClusterEventHandler(t *testing.T) {
Name: "my-app-set2",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{
{
Clusters: &argov1alpha1.ClusterGenerator{},
Clusters: &argoprojiov1alpha1.ClusterGenerator{},
},
},
},
@@ -122,16 +123,16 @@ func TestClusterEventHandler(t *testing.T) {
},
{
name: "non-cluster generator should not match",
items: []argov1alpha1.ApplicationSet{
items: []argoprojiov1alpha1.ApplicationSet{
{
ObjectMeta: v1.ObjectMeta{
Name: "my-app-set",
Namespace: "another-namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{
{
Clusters: &argov1alpha1.ClusterGenerator{},
Clusters: &argoprojiov1alpha1.ClusterGenerator{},
},
},
},
@@ -141,10 +142,10 @@ func TestClusterEventHandler(t *testing.T) {
Name: "app-set-non-cluster",
Namespace: "argocd",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{
{
List: &argov1alpha1.ListGenerator{},
List: &argoprojiov1alpha1.ListGenerator{},
},
},
},
@@ -166,16 +167,16 @@ func TestClusterEventHandler(t *testing.T) {
{
name: "non-argo cd secret should not match",
items: []argov1alpha1.ApplicationSet{
items: []argoprojiov1alpha1.ApplicationSet{
{
ObjectMeta: v1.ObjectMeta{
Name: "my-app-set",
Namespace: "another-namespace",
},
Spec: argov1alpha1.ApplicationSetSpec{
Generators: []argov1alpha1.ApplicationSetGenerator{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{
{
Clusters: &argov1alpha1.ClusterGenerator{},
Clusters: &argoprojiov1alpha1.ClusterGenerator{},
},
},
},
@@ -195,7 +196,7 @@ func TestClusterEventHandler(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
appSetList := argov1alpha1.ApplicationSetList{
appSetList := argoprojiov1alpha1.ApplicationSetList{
Items: test.items,
}

View File

@@ -1,19 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- clusters: {}
template:
metadata:
name: '{{name}}-guestbook'
spec:
project: "default"
source:
repoURL: https://github.com/argoproj/argocd-example-apps/
targetRevision: HEAD
path: guestbook
destination:
server: '{{server}}'
namespace: guestbook

View File

@@ -3,12 +3,11 @@ kind: ApplicationSet
metadata:
name: guestbook
spec:
goTemplate: true
generators:
- clusters: {}
template:
metadata:
name: '{{.name}}-guestbook'
name: '{{name}}-guestbook'
spec:
project: "default"
source:
@@ -16,5 +15,5 @@ spec:
targetRevision: HEAD
path: guestbook
destination:
server: '{{.server}}'
server: '{{server}}'
namespace: guestbook

View File

@@ -1,27 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: book-import
spec:
generators:
- clusterDecisionResource:
configMapRef: ocm-placement
name: test-placement
requeueAfterSeconds: 30
template:
metadata:
name: '{{clusterName}}-book-import'
spec:
project: "default"
source:
repoURL: https://github.com/open-cluster-management/application-samples.git
targetRevision: HEAD
path: book-import
destination:
name: '{{clusterName}}'
namespace: bookimport
syncPolicy:
automated:
prune: true
syncOptions:
- CreateNamespace=true

View File

@@ -3,7 +3,6 @@ kind: ApplicationSet
metadata:
name: book-import
spec:
goTemplate: true
generators:
- clusterDecisionResource:
configMapRef: ocm-placement
@@ -11,7 +10,7 @@ spec:
requeueAfterSeconds: 30
template:
metadata:
name: '{{.clusterName}}-book-import'
name: '{{clusterName}}-book-import'
spec:
project: "default"
source:
@@ -19,7 +18,7 @@ spec:
targetRevision: HEAD
path: book-import
destination:
name: '{{.clusterName}}'
name: '{{clusterName}}'
namespace: bookimport
syncPolicy:
automated:

View File

@@ -1,22 +0,0 @@
# This is an example of a typical ApplicationSet which uses the cluster generator.
# An ApplicationSet is comprised with two stanzas:
# - spec.generator - producer of a list of values supplied as arguments to an app template
# - spec.template - an application template, which has been parameterized
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- clusters: {}
template:
metadata:
name: '{{name}}-guestbook'
spec:
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
chart: guestbook
destination:
server: '{{server}}'
namespace: guestbook

View File

@@ -7,17 +7,16 @@ kind: ApplicationSet
metadata:
name: guestbook
spec:
goTemplate: true
generators:
- clusters: {}
template:
metadata:
name: '{{.name}}-guestbook'
name: '{{name}}-guestbook'
spec:
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
chart: guestbook
destination:
server: '{{.server}}'
server: '{{server}}'
namespace: guestbook

View File

@@ -19,15 +19,15 @@ spec:
project: default
template:
metadata:
name: '{{.name}}-guestbook'
name: '{{name}}-guestbook'
labels:
environment: '{{.metadata.labels.environment}}'
environment: '{{metadata.labels.environment}}'
spec:
project: '{{.values.project}}'
project: '{{values.project}}'
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
chart: guestbook
destination:
server: '{{.server}}'
server: '{{server}}'
namespace: guestbook

View File

@@ -1,44 +0,0 @@
# This example demonstrates the git directory generator, which produces an items list
# based on discovery of directories in a git repo matching a specified pattern.
# Git generators automatically provide {{path}} and {{path.basename}} as available
# variables to the app template.
#
# Suppose the following git directory structure (note the use of different config tools):
#
# cluster-deployments
# └── add-ons
# ├── argo-rollouts
# │   ├── all.yaml
# │   └── kustomization.yaml
# ├── argo-workflows
# │   └── install.yaml
# ├── grafana
# │   ├── Chart.yaml
# │   └── values.yaml
# └── prometheus-operator
# ├── Chart.yaml
# └── values.yaml
#
# The following ApplicationSet would produce four applications (in different namespaces),
# using the directory basename as both the namespace and application name.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-addons
spec:
generators:
- git:
repoURL: https://github.com/infra-team/cluster-deployments.git
directories:
- path: add-ons/*
template:
metadata:
name: '{{path.basename}}'
spec:
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
path: '{{path}}'
destination:
server: http://kubernetes.default.svc
namespace: '{{path.basename}}'

View File

@@ -26,7 +26,6 @@ kind: ApplicationSet
metadata:
name: cluster-addons
spec:
goTemplate: true
generators:
- git:
repoURL: https://github.com/infra-team/cluster-deployments.git
@@ -34,12 +33,12 @@ spec:
- path: add-ons/*
template:
metadata:
name: '{{.path.basename}}'
name: '{{path.basename}}'
spec:
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
path: '{{.path.path}}'
path: '{{path}}'
destination:
server: http://kubernetes.default.svc
namespace: '{{.path.basename}}'
namespace: '{{path.basename}}'

View File

@@ -1,55 +0,0 @@
# This example demonstrates a git file generator which traverses the directory structure of a git
# repository to discover items based on a filename convention. For each file discovered, the
# contents of the discovered files themselves, act as the set of inputs to the app template.
#
# Suppose the following git directory structure:
#
# cluster-deployments
# ├── apps
# │ └── guestbook
# │ └── install.yaml
# └── cluster-config
# ├── engineering
# │ ├── dev
# │ │ └── config.json
# │ └── prod
# │ └── config.json
# └── finance
# ├── dev
# │ └── config.json
# └── prod
# └── config.json
#
# The discovered files (e.g. config.json) files can be any structured data supplied to the
# generated application. e.g.:
# {
# "aws_account": "123456",
# "asset_id": "11223344"
# "cluster": {
# "owner": "Jesse_Suen@intuit.com",
# "name": "engineering-dev",
# "address": "http://1.2.3.4"
# }
# }
#
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- git:
repoURL: https://github.com/infra-team/cluster-deployments.git
files:
- path: "**/config.json"
template:
metadata:
name: '{{cluster.name}}-guestbook'
spec:
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
path: apps/guestbook
destination:
server: '{{cluster.address}}'
namespace: guestbook

View File

@@ -37,7 +37,6 @@ kind: ApplicationSet
metadata:
name: guestbook
spec:
goTemplate: true
generators:
- git:
repoURL: https://github.com/infra-team/cluster-deployments.git
@@ -45,12 +44,12 @@ spec:
- path: "**/config.json"
template:
metadata:
name: '{{.cluster.name}}-guestbook'
name: '{{cluster.name}}-guestbook'
spec:
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
path: apps/guestbook
destination:
server: '{{.cluster.address}}'
server: '{{cluster.address}}'
namespace: guestbook

View File

@@ -1,68 +0,0 @@
# This example demonstrates a git file generator which produces its items based on one or
# more files referenced in a git repo. The referenced files would contain a json/yaml list of
# arbitrary structured objects. Each item of the list would become a set of parameters to a
# generated application.
#
# Suppose the following git directory structure:
#
# cluster-deployments
# ├── apps
# │ └── guestbook
# │ ├── v1.0
# │ │ └── install.yaml
# │ └── v2.0
# │ └── install.yaml
# └── config
# └── clusters.json
#
# In this example, the `clusters.json` file is json list of structured data:
# [
# {
# "account": "123456",
# "asset_id": "11223344",
# "cluster": {
# "owner": "Jesse_Suen@intuit.com",
# "name": "engineering-dev",
# "address": "http://1.2.3.4"
# },
# "appVersions": {
# "prometheus-operator": "v0.38",
# "guestbook": "v2.0"
# }
# },
# {
# "account": "456789",
# "asset_id": "55667788",
# "cluster": {
# "owner": "Alexander_Matyushentsev@intuit.com",
# "name": "engineering-prod",
# "address": "http://2.4.6.8"
# },
# "appVersions": {
# "prometheus-operator": "v0.38",
# "guestbook": "v1.0"
# }
# }
# ]
#
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- git:
repoURL: https://github.com/infra-team/cluster-deployments.git
files:
- path: config/clusters.json
template:
metadata:
name: '{{cluster.name}}-guestbook'
spec:
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
path: apps/guestbook/{{appVersions.guestbook}}
destination:
server: http://kubernetes.default.svc
namespace: guestbook

View File

@@ -50,7 +50,6 @@ kind: ApplicationSet
metadata:
name: guestbook
spec:
goTemplate: true
generators:
- git:
repoURL: https://github.com/infra-team/cluster-deployments.git
@@ -58,12 +57,12 @@ spec:
- path: config/clusters.json
template:
metadata:
name: '{{.cluster.name}}-guestbook'
name: '{{cluster.name}}-guestbook'
spec:
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
path: apps/guestbook/{{.appVersions.guestbook}}
path: apps/guestbook/{{appVersions.guestbook}}
destination:
server: http://kubernetes.default.svc
namespace: guestbook

View File

@@ -1,33 +0,0 @@
# The list generator specifies a literal list of argument values to the app spec template.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- list:
elements:
- cluster: engineering-dev
url: https://1.2.3.4
values:
project: dev
- cluster: engineering-prod
url: https://2.4.6.8
values:
project: prod
- cluster: finance-preprod
url: https://9.8.7.6
values:
project: preprod
template:
metadata:
name: '{{cluster}}-guestbook'
spec:
project: '{{values.project}}'
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
path: guestbook/{{cluster}}
destination:
server: '{{url}}'
namespace: guestbook

View File

@@ -4,7 +4,6 @@ kind: ApplicationSet
metadata:
name: guestbook
spec:
goTemplate: true
generators:
- list:
elements:
@@ -22,13 +21,13 @@ spec:
project: preprod
template:
metadata:
name: '{{.cluster}}-guestbook'
name: '{{cluster}}-guestbook'
spec:
project: '{{.values.project}}'
project: '{{values.project}}'
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
path: guestbook/{{.cluster}}
path: guestbook/{{cluster}}
destination:
server: '{{.url}}'
server: '{{url}}'
namespace: guestbook

View File

@@ -1,48 +0,0 @@
# App templates can also be defined as part of the generator's template stanza. Sometimes it is
# useful to do this in order to override the spec.template stanza, and when simple string
# parameterization are insufficient. In the below examples, the generators[].XXX.template is
# a partial definition, which overrides/patch the default template.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- list:
elements:
- cluster: engineering-dev
url: https://1.2.3.4
template:
metadata: {}
spec:
project: "project"
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
path: '{{cluster}}-override'
destination: {}
- list:
elements:
- cluster: engineering-prod
url: https://1.2.3.4
template:
metadata: {}
spec:
project: "project2"
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
path: '{{cluster}}-override2'
destination: {}
template:
metadata:
name: '{{cluster}}-guestbook'
spec:
project: "project"
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
path: guestbook/{{cluster}}
destination:
server: '{{url}}'
namespace: guestbook

View File

@@ -7,7 +7,6 @@ kind: ApplicationSet
metadata:
name: guestbook
spec:
goTemplate: true
generators:
- list:
elements:
@@ -19,7 +18,7 @@ spec:
project: "project"
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
path: '{{.cluster}}-override'
path: '{{cluster}}-override'
destination: {}
- list:
@@ -32,18 +31,18 @@ spec:
project: "project2"
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
path: '{{.cluster}}-override2'
path: '{{cluster}}-override2'
destination: {}
template:
metadata:
name: '{{.cluster}}-guestbook'
name: '{{cluster}}-guestbook'
spec:
project: "project"
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
path: guestbook/{{.cluster}}
path: guestbook/{{cluster}}
destination:
server: '{{.url}}'
server: '{{url}}'
namespace: guestbook

View File

@@ -1,6 +1,6 @@
#namePrefix: kustomize-
resources:
- https://github.com/argoproj/argo-workflows/releases/download/v3.4.0/namespace-install.yaml
- namespace-install.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

View File

@@ -0,0 +1,417 @@
# This is an auto-generated file. DO NOT EDIT
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: clusterworkflowtemplates.argoproj.io
spec:
group: argoproj.io
names:
kind: ClusterWorkflowTemplate
listKind: ClusterWorkflowTemplateList
plural: clusterworkflowtemplates
shortNames:
- clusterwftmpl
- cwft
singular: clusterworkflowtemplate
scope: Cluster
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: cronworkflows.argoproj.io
spec:
group: argoproj.io
names:
kind: CronWorkflow
listKind: CronWorkflowList
plural: cronworkflows
shortNames:
- cwf
- cronwf
singular: cronworkflow
scope: Namespaced
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: workfloweventbindings.argoproj.io
spec:
group: argoproj.io
names:
kind: WorkflowEventBinding
listKind: WorkflowEventBindingList
plural: workfloweventbindings
shortNames:
- wfeb
singular: workfloweventbinding
scope: Namespaced
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: workflows.argoproj.io
spec:
additionalPrinterColumns:
- JSONPath: .status.phase
description: Status of the workflow
name: Status
type: string
- JSONPath: .status.startedAt
description: When the workflow was started
format: date-time
name: Age
type: date
group: argoproj.io
names:
kind: Workflow
listKind: WorkflowList
plural: workflows
shortNames:
- wf
singular: workflow
scope: Namespaced
subresources: {}
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: workflowtemplates.argoproj.io
spec:
group: argoproj.io
names:
kind: WorkflowTemplate
listKind: WorkflowTemplateList
plural: workflowtemplates
shortNames:
- wftmpl
singular: workflowtemplate
scope: Namespaced
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: argo
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: argo-server
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: argo-role
rules:
- apiGroups:
- ""
resources:
- pods
- pods/exec
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- watch
- list
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- create
- delete
- get
- apiGroups:
- argoproj.io
resources:
- workflows
- workflows/finalizers
verbs:
- get
- list
- watch
- update
- patch
- delete
- create
- apiGroups:
- argoproj.io
resources:
- workflowtemplates
- workflowtemplates/finalizers
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- get
- list
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- apiGroups:
- argoproj.io
resources:
- cronworkflows
- cronworkflows/finalizers
verbs:
- get
- list
- watch
- update
- patch
- delete
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- policy
resources:
- poddisruptionbudgets
verbs:
- create
- get
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: argo-server-role
rules:
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- watch
- list
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- create
- apiGroups:
- ""
resources:
- pods
- pods/exec
- pods/log
verbs:
- get
- list
- watch
- delete
- apiGroups:
- ""
resources:
- events
verbs:
- watch
- create
- patch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- get
- list
- apiGroups:
- argoproj.io
resources:
- workflows
- workfloweventbindings
- workflowtemplates
- cronworkflows
- cronworkflows/finalizers
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: argo-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: argo-role
subjects:
- kind: ServiceAccount
name: argo
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: argo-server-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: argo-server-role
subjects:
- kind: ServiceAccount
name: argo-server
---
apiVersion: v1
kind: ConfigMap
metadata:
name: workflow-controller-configmap
---
apiVersion: v1
kind: Service
metadata:
name: argo-server
spec:
ports:
- name: web
port: 2746
targetPort: 2746
selector:
app: argo-server
---
apiVersion: v1
kind: Service
metadata:
name: workflow-controller-metrics
spec:
ports:
- name: metrics
port: 9090
protocol: TCP
targetPort: 9090
selector:
app: workflow-controller
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: argo-server
spec:
selector:
matchLabels:
app: argo-server
template:
metadata:
labels:
app: argo-server
spec:
containers:
- args:
- server
- --namespaced
image: argoproj/argocli:v2.12.5
name: argo-server
ports:
- containerPort: 2746
name: web
readinessProbe:
httpGet:
path: /
port: 2746
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 20
volumeMounts:
- mountPath: /tmp
name: tmp
nodeSelector:
kubernetes.io/os: linux
securityContext:
runAsNonRoot: true
serviceAccountName: argo-server
volumes:
- emptyDir: {}
name: tmp
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: workflow-controller
spec:
selector:
matchLabels:
app: workflow-controller
template:
metadata:
labels:
app: workflow-controller
spec:
containers:
- args:
- --configmap
- workflow-controller-configmap
- --executor-image
- argoproj/argoexec:v2.12.5
- --namespaced
command:
- workflow-controller
image: argoproj/workflow-controller:v2.12.5
livenessProbe:
httpGet:
path: /metrics
port: metrics
initialDelaySeconds: 30
periodSeconds: 30
name: workflow-controller
ports:
- containerPort: 9090
name: metrics
nodeSelector:
kubernetes.io/os: linux
securityContext:
runAsNonRoot: true
serviceAccountName: argo

View File

@@ -11,4 +11,4 @@ version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
appVersion: "1.0"
appVersion: "1.0"

View File

@@ -1,4 +1,4 @@
dependencies:
- name: kube-prometheus-stack
version: 40.5.0
version: 9.4.10
repository: https://prometheus-community.github.io/helm-charts

View File

@@ -1,6 +1,6 @@
#namePrefix: kustomize-
resources:
- https://github.com/argoproj/argo-workflows/releases/download/v3.4.0/namespace-install.yaml
- namespace-install.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

View File

@@ -0,0 +1,417 @@
# This is an auto-generated file. DO NOT EDIT
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: clusterworkflowtemplates.argoproj.io
spec:
group: argoproj.io
names:
kind: ClusterWorkflowTemplate
listKind: ClusterWorkflowTemplateList
plural: clusterworkflowtemplates
shortNames:
- clusterwftmpl
- cwft
singular: clusterworkflowtemplate
scope: Cluster
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: cronworkflows.argoproj.io
spec:
group: argoproj.io
names:
kind: CronWorkflow
listKind: CronWorkflowList
plural: cronworkflows
shortNames:
- cwf
- cronwf
singular: cronworkflow
scope: Namespaced
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: workfloweventbindings.argoproj.io
spec:
group: argoproj.io
names:
kind: WorkflowEventBinding
listKind: WorkflowEventBindingList
plural: workfloweventbindings
shortNames:
- wfeb
singular: workfloweventbinding
scope: Namespaced
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: workflows.argoproj.io
spec:
additionalPrinterColumns:
- JSONPath: .status.phase
description: Status of the workflow
name: Status
type: string
- JSONPath: .status.startedAt
description: When the workflow was started
format: date-time
name: Age
type: date
group: argoproj.io
names:
kind: Workflow
listKind: WorkflowList
plural: workflows
shortNames:
- wf
singular: workflow
scope: Namespaced
subresources: {}
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: workflowtemplates.argoproj.io
spec:
group: argoproj.io
names:
kind: WorkflowTemplate
listKind: WorkflowTemplateList
plural: workflowtemplates
shortNames:
- wftmpl
singular: workflowtemplate
scope: Namespaced
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: argo
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: argo-server
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: argo-role
rules:
- apiGroups:
- ""
resources:
- pods
- pods/exec
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- watch
- list
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- create
- delete
- get
- apiGroups:
- argoproj.io
resources:
- workflows
- workflows/finalizers
verbs:
- get
- list
- watch
- update
- patch
- delete
- create
- apiGroups:
- argoproj.io
resources:
- workflowtemplates
- workflowtemplates/finalizers
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- get
- list
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- apiGroups:
- argoproj.io
resources:
- cronworkflows
- cronworkflows/finalizers
verbs:
- get
- list
- watch
- update
- patch
- delete
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- policy
resources:
- poddisruptionbudgets
verbs:
- create
- get
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: argo-server-role
rules:
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- watch
- list
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- create
- apiGroups:
- ""
resources:
- pods
- pods/exec
- pods/log
verbs:
- get
- list
- watch
- delete
- apiGroups:
- ""
resources:
- events
verbs:
- watch
- create
- patch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- get
- list
- apiGroups:
- argoproj.io
resources:
- workflows
- workfloweventbindings
- workflowtemplates
- cronworkflows
- cronworkflows/finalizers
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: argo-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: argo-role
subjects:
- kind: ServiceAccount
name: argo
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: argo-server-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: argo-server-role
subjects:
- kind: ServiceAccount
name: argo-server
---
apiVersion: v1
kind: ConfigMap
metadata:
name: workflow-controller-configmap
---
apiVersion: v1
kind: Service
metadata:
name: argo-server
spec:
ports:
- name: web
port: 2746
targetPort: 2746
selector:
app: argo-server
---
apiVersion: v1
kind: Service
metadata:
name: workflow-controller-metrics
spec:
ports:
- name: metrics
port: 9090
protocol: TCP
targetPort: 9090
selector:
app: workflow-controller
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: argo-server
spec:
selector:
matchLabels:
app: argo-server
template:
metadata:
labels:
app: argo-server
spec:
containers:
- args:
- server
- --namespaced
image: argoproj/argocli:v2.12.5
name: argo-server
ports:
- containerPort: 2746
name: web
readinessProbe:
httpGet:
path: /
port: 2746
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 20
volumeMounts:
- mountPath: /tmp
name: tmp
nodeSelector:
kubernetes.io/os: linux
securityContext:
runAsNonRoot: true
serviceAccountName: argo-server
volumes:
- emptyDir: {}
name: tmp
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: workflow-controller
spec:
selector:
matchLabels:
app: workflow-controller
template:
metadata:
labels:
app: workflow-controller
spec:
containers:
- args:
- --configmap
- workflow-controller-configmap
- --executor-image
- argoproj/argoexec:v2.12.5
- --namespaced
command:
- workflow-controller
image: argoproj/workflow-controller:v2.12.5
livenessProbe:
httpGet:
path: /metrics
port: metrics
initialDelaySeconds: 30
periodSeconds: 30
name: workflow-controller
ports:
- containerPort: 9090
name: metrics
nodeSelector:
kubernetes.io/os: linux
securityContext:
runAsNonRoot: true
serviceAccountName: argo

View File

@@ -1,14 +1 @@
apiVersion: v2
name: helm-prometheus-operator
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
appVersion: "1.0"

View File

@@ -1,4 +1,4 @@
dependencies:
- name: kube-prometheus-stack
version: 40.5.0
version: 9.4.10
repository: https://prometheus-community.github.io/helm-charts

View File

@@ -1,29 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-addons
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/argoproj/argo-cd.git
revision: HEAD
directories:
- path: applicationset/examples/git-generator-directory/excludes/cluster-addons/*
- exclude: true
path: applicationset/examples/git-generator-directory/excludes/cluster-addons/exclude-helm-guestbook
template:
metadata:
name: '{{path.basename}}'
spec:
project: "my-project"
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{path.basename}}'
syncPolicy:
syncOptions:
- CreateNamespace=true

View File

@@ -2,9 +2,7 @@ apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-addons
namespace: argocd
spec:
goTemplate: true
generators:
- git:
repoURL: https://github.com/argoproj/argo-cd.git
@@ -15,16 +13,13 @@ spec:
path: applicationset/examples/git-generator-directory/excludes/cluster-addons/exclude-helm-guestbook
template:
metadata:
name: '{{.path.basename}}'
name: '{{path.basename}}'
spec:
project: "my-project"
project: default
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: '{{.path}}'
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{.path.basename}}'
syncPolicy:
syncOptions:
- CreateNamespace=true
namespace: '{{path.basename}}'

View File

@@ -1,27 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-addons
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/argoproj/argo-cd.git
revision: HEAD
directories:
- path: applicationset/examples/git-generator-directory/cluster-addons/*
template:
metadata:
name: '{{path.basename}}'
spec:
project: "my-project"
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{path.basename}}'
syncPolicy:
syncOptions:
- CreateNamespace=true

View File

@@ -2,9 +2,7 @@ apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-addons
namespace: argocd
spec:
goTemplate: true
generators:
- git:
repoURL: https://github.com/argoproj/argo-cd.git
@@ -13,16 +11,13 @@ spec:
- path: applicationset/examples/git-generator-directory/cluster-addons/*
template:
metadata:
name: '{{.path.basename}}'
name: '{{path.basename}}'
spec:
project: "my-project"
project: default
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: '{{.path.path}}'
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{.path.basename}}'
syncPolicy:
syncOptions:
- CreateNamespace=true
namespace: '{{path.basename}}'

View File

@@ -1,24 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- git:
repoURL: https://github.com/argoproj/argo-cd.git
revision: HEAD
files:
- path: "applicationset/examples/git-generator-files-discovery/cluster-config/**/config.json"
template:
metadata:
name: '{{cluster.name}}-guestbook'
spec:
project: default
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: "applicationset/examples/git-generator-files-discovery/apps/guestbook"
destination:
server: https://kubernetes.default.svc
#server: '{{cluster.address}}'
namespace: guestbook

View File

@@ -3,7 +3,6 @@ kind: ApplicationSet
metadata:
name: guestbook
spec:
goTemplate: true
generators:
- git:
repoURL: https://github.com/argoproj/argo-cd.git
@@ -12,7 +11,7 @@ spec:
- path: "applicationset/examples/git-generator-files-discovery/cluster-config/**/config.json"
template:
metadata:
name: '{{.cluster.name}}-guestbook'
name: '{{cluster.name}}-guestbook'
spec:
project: default
source:
@@ -21,5 +20,5 @@ spec:
path: "applicationset/examples/git-generator-files-discovery/apps/guestbook"
destination:
server: https://kubernetes.default.svc
#server: '{{.cluster.address}}'
#server: '{{cluster.address}}'
namespace: guestbook

View File

@@ -1,24 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- list:
elements:
- cluster: engineering-dev
url: https://kubernetes.default.svc
- cluster: engineering-prod
url: https://kubernetes.default.svc
template:
metadata:
name: '{{cluster}}-guestbook'
spec:
project: default
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: applicationset/examples/list-generator/guestbook/{{cluster}}
destination:
server: '{{url}}'
namespace: guestbook

View File

@@ -3,7 +3,6 @@ kind: ApplicationSet
metadata:
name: guestbook
spec:
goTemplate: true
generators:
- list:
elements:
@@ -13,13 +12,13 @@ spec:
url: https://kubernetes.default.svc
template:
metadata:
name: '{{.cluster}}-guestbook'
name: '{{cluster}}-guestbook'
spec:
project: default
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: applicationset/examples/list-generator/guestbook/{{.cluster}}
path: applicationset/examples/list-generator/guestbook/{{cluster}}
destination:
server: '{{.url}}'
server: '{{url}}'
namespace: guestbook

View File

@@ -1,33 +0,0 @@
# This example demonstrates the combining of the git generator with a cluster generator
# The expected output would be an application per git directory and a cluster (application_count = git directory * clusters)
#
#
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-git
spec:
generators:
- matrix:
generators:
- git:
repoURL: https://github.com/argoproj/argo-cd.git
revision: HEAD
directories:
- path: applicationset/examples/matrix/cluster-addons/*
- clusters:
selector:
matchLabels:
argocd.argoproj.io/secret-type: cluster
template:
metadata:
name: '{{path.basename}}-{{name}}'
spec:
project: '{{metadata.labels.environment}}'
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: '{{path}}'
destination:
server: '{{server}}'
namespace: '{{path.basename}}'

View File

@@ -7,7 +7,6 @@ kind: ApplicationSet
metadata:
name: cluster-git
spec:
goTemplate: true
generators:
- matrix:
generators:
@@ -22,13 +21,13 @@ spec:
argocd.argoproj.io/secret-type: cluster
template:
metadata:
name: '{{.path.basename}}-{{.name}}'
name: '{{path.basename}}-{{name}}'
spec:
project: '{{.metadata.labels.environment}}'
project: '{{metadata.labels.environment}}'
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: '{{.path.path}}'
path: '{{path}}'
destination:
server: '{{.server}}'
namespace: '{{.path.basename}}'
server: '{{server}}'
namespace: '{{path.basename}}'

View File

@@ -1,39 +0,0 @@
# This example demonstrates the combining of the git generator with a list generator
# The expected output would be an application per git directory and a list entry (application_count = git directory * list entries)
#
#
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: list-git
spec:
generators:
- matrix:
generators:
- git:
repoURL: https://github.com/argoproj/argo-cd.git
revision: HEAD
directories:
- path: applicationset/examples/matrix/cluster-addons/*
- list:
elements:
- cluster: engineering-dev
url: https://1.2.3.4
values:
project: dev
- cluster: engineering-prod
url: https://2.4.6.8
values:
project: prod
template:
metadata:
name: '{{path.basename}}-{{cluster}}'
spec:
project: '{{values.project}}'
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: '{{path}}'
destination:
server: '{{url}}'
namespace: '{{path.basename}}'

View File

@@ -7,7 +7,6 @@ kind: ApplicationSet
metadata:
name: list-git
spec:
goTemplate: true
generators:
- matrix:
generators:
@@ -28,13 +27,13 @@ spec:
project: prod
template:
metadata:
name: '{{.path.basename}}-{{.cluster}}'
name: '{{path.basename}}-{{cluster}}'
spec:
project: '{{.values.project}}'
project: '{{values.project}}'
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: '{{.path.path}}'
path: '{{path}}'
destination:
server: '{{.url}}'
namespace: '{{.path.basename}}'
server: '{{url}}'
namespace: '{{path.basename}}'

View File

@@ -1,37 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: list-and-list
namespace: argocd
spec:
generators:
- matrix:
generators:
- list:
elements:
- cluster: engineering-dev
url: https://kubernetes.default.svc
values:
project: default
- cluster: engineering-prod
url: https://kubernetes.default.svc
values:
project: default
- list:
elements:
- values:
suffix: '1'
- values:
suffix: '2'
template:
metadata:
name: '{{cluster}}-{{values.suffix}}'
spec:
project: '{{values.project}}'
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: '{{path}}'
destination:
server: '{{url}}'
namespace: '{{path.basename}}'

View File

@@ -4,7 +4,6 @@ metadata:
name: list-and-list
namespace: argocd
spec:
goTemplate: true
generators:
- matrix:
generators:
@@ -26,13 +25,13 @@ spec:
suffix: '2'
template:
metadata:
name: '{{.cluster}}-{{.values.suffix}}'
name: '{{cluster}}-{{values.suffix}}'
spec:
project: '{{.values.project}}'
project: '{{values.project}}'
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: '{{.path.path}}'
path: '{{path}}'
destination:
server: '{{.url}}'
namespace: '{{.path.basename}}'
server: '{{url}}'
namespace: '{{path.basename}}'

View File

@@ -1,67 +0,0 @@
# The matrix generator can contain other combination-type generators (matrix and union). But nested matrix and union
# generators cannot contain further-nested matrix or union generators.
#
# The generators are evaluated from most-nested to least-nested. In this case:
# 1. The union generator joins two lists to make 3 parameter sets.
# 2. The inner matrix generator takes the cartesian product of the two lists to make 4 parameters sets.
# 3. The outer matrix generator takes the cartesian product of the 3 union and the 4 inner matrix parameter sets to
# make 3*4=12 final parameter sets.
# 4. The 12 final parameter sets are evaluated against the top-level template to generate 12 Applications.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: matrix-and-union-in-matrix
spec:
generators:
- matrix:
generators:
- union:
mergeKeys:
- cluster
generators:
- list:
elements:
- cluster: engineering-dev
url: https://kubernetes.default.svc
values:
project: default
- cluster: engineering-prod
url: https://kubernetes.default.svc
values:
project: default
- list:
elements:
- cluster: engineering-dev
url: https://kubernetes.default.svc
values:
project: default
- cluster: engineering-test
url: https://kubernetes.default.svc
values:
project: default
- matrix:
generators:
- list:
elements:
- values:
suffix: '1'
- values:
suffix: '2'
- list:
elements:
- values:
prefix: 'first'
- values:
prefix: 'second'
template:
metadata:
name: '{{values.prefix}}-{{cluster}}-{{values.suffix}}'
spec:
project: '{{values.project}}'
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: '{{path}}'
destination:
server: '{{url}}'
namespace: '{{path.basename}}'

View File

@@ -12,7 +12,6 @@ kind: ApplicationSet
metadata:
name: matrix-and-union-in-matrix
spec:
goTemplate: true
generators:
- matrix:
generators:
@@ -56,13 +55,13 @@ spec:
prefix: 'second'
template:
metadata:
name: '{{.values.prefix}}-{{.cluster}}-{{.values.suffix}}'
name: '{{values.prefix}}-{{cluster}}-{{values.suffix}}'
spec:
project: '{{.values.project}}'
project: '{{values.project}}'
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: '{{.path.path}}'
path: '{{path}}'
destination:
server: '{{.url}}'
namespace: '{{.path.basename}}'
server: '{{url}}'
namespace: '{{path.basename}}'

View File

@@ -1,44 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: merge-clusters-and-list
spec:
generators:
- merge:
mergeKeys:
- server
generators:
- clusters:
values:
kafka: 'true'
redis: 'false'
# For clusters with a specific label, enable Kafka.
- clusters:
selector:
matchLabels:
use-kafka: 'false'
values:
kafka: 'false'
# For a specific cluster, enable Redis.
- list:
elements:
- server: https://some-specific-cluster
values.redis: 'true'
template:
metadata:
name: '{{name}}'
spec:
project: default
source:
repoURL: https://github.com/argoproj/argocd-example-apps/
targetRevision: HEAD
path: helm-guestbook
helm:
parameters:
- name: kafka
value: '{{values.kafka}}'
- name: redis
value: '{{values.redis}}'
destination:
server: '{{server}}'
namespace: default

View File

@@ -3,7 +3,6 @@ kind: ApplicationSet
metadata:
name: merge-clusters-and-list
spec:
goTemplate: true
generators:
- merge:
mergeKeys:
@@ -27,7 +26,7 @@ spec:
values.redis: 'true'
template:
metadata:
name: '{{.name}}'
name: '{{name}}'
spec:
project: default
source:
@@ -37,9 +36,9 @@ spec:
helm:
parameters:
- name: kafka
value: '{{.values.kafka}}'
value: '{{values.kafka}}'
- name: redis
value: '{{.values.redis}}'
value: '{{values.redis}}'
destination:
server: '{{.server}}'
server: '{{server}}'
namespace: default

View File

@@ -1,43 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: merge-two-matrixes
spec:
generators:
- merge:
mergeKeys:
- server
- environment
generators:
- matrix:
generators:
- clusters:
values:
replicaCount: '2'
- list:
elements:
- environment: staging
namespace: guestbook-non-prod
- environment: prod
namespace: guestbook
- list:
elements:
- server: https://kubernetes.default.svc
environment: staging
values.replicaCount: '1'
template:
metadata:
name: '{{name}}-guestbook-{{environment}}'
spec:
project: default
source:
repoURL: https://github.com/argoproj/argocd-example-apps/
targetRevision: HEAD
path: helm-guestbook
helm:
parameters:
- name: replicaCount
value: '{{values.replicaCount}}'
destination:
server: '{{server}}'
namespace: '{{namespace}}'

View File

@@ -3,7 +3,6 @@ kind: ApplicationSet
metadata:
name: merge-two-matrixes
spec:
goTemplate: true
generators:
- merge:
mergeKeys:
@@ -28,7 +27,7 @@ spec:
values.replicaCount: '1'
template:
metadata:
name: '{{.name}}-guestbook-{{.environment}}'
name: '{{name}}-guestbook-{{environment}}'
spec:
project: default
source:
@@ -38,7 +37,7 @@ spec:
helm:
parameters:
- name: replicaCount
value: '{{.values.replicaCount}}'
value: '{{values.replicaCount}}'
destination:
server: '{{.server}}'
namespace: '{{.namespace}}'
server: '{{server}}'
namespace: '{{namespace}}'

View File

@@ -1,40 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: myapp
spec:
generators:
- pullRequest:
github:
# The GitHub organization or user.
owner: myorg
# The Github repository
repo: myrepo
# For GitHub Enterprise. (optional)
api: https://git.example.com/
# Reference to a Secret containing an access token. (optional)
tokenRef:
secretName: github-token
key: token
# Labels is used to filter the PRs that you want to target. (optional)
labels:
- preview
template:
metadata:
name: 'myapp-{{ branch }}-{{ number }}'
spec:
source:
repoURL: 'https://github.com/myorg/myrepo.git'
targetRevision: '{{ head_sha }}'
path: helm-guestbook
helm:
parameters:
- name: "image.tag"
value: "pull-{{ head_sha }}"
project: default
destination:
server: https://kubernetes.default.svc
namespace: "{{ branch }}-{{ number }}"
syncPolicy:
syncOptions:
- CreateNamespace=true

View File

@@ -3,7 +3,6 @@ kind: ApplicationSet
metadata:
name: myapp
spec:
goTemplate: true
generators:
- pullRequest:
github:
@@ -22,20 +21,20 @@ spec:
- preview
template:
metadata:
name: 'myapp-{{ .branch }}-{{ .number }}'
name: 'myapp-{{ branch }}-{{ number }}'
spec:
source:
repoURL: 'https://github.com/myorg/myrepo.git'
targetRevision: '{{ .head_sha }}'
targetRevision: '{{ head_sha }}'
path: helm-guestbook
helm:
parameters:
- name: "image.tag"
value: "pull-{{ .head_sha }}"
value: "pull-{{ head_sha }}"
project: default
destination:
server: https://kubernetes.default.svc
namespace: "{{ .branch }}-{{ .number }}"
namespace: "{{ branch }}-{{ number }}"
syncPolicy:
syncOptions:
- CreateNamespace=true

View File

@@ -1,24 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- scmProvider:
github:
organization: argoproj
cloneProtocol: https
filters:
- repositoryMatch: example-apps
template:
metadata:
name: '{{ repository }}-guestbook'
spec:
project: "default"
source:
repoURL: '{{ url }}'
targetRevision: '{{ branch }}'
path: guestbook
destination:
server: https://kubernetes.default.svc
namespace: guestbook

View File

@@ -3,7 +3,6 @@ kind: ApplicationSet
metadata:
name: guestbook
spec:
goTemplate: true
generators:
- scmProvider:
github:
@@ -13,12 +12,12 @@ spec:
- repositoryMatch: example-apps
template:
metadata:
name: '{{ .repository }}-guestbook'
name: '{{ repository }}-guestbook'
spec:
project: "default"
source:
repoURL: '{{ .url }}'
targetRevision: '{{ .branch }}'
repoURL: '{{ url }}'
targetRevision: '{{ branch }}'
path: guestbook
destination:
server: https://kubernetes.default.svc

View File

@@ -1,36 +0,0 @@
# App templates can also be defined as part of the generator's template stanza. Sometimes it is
# useful to do this in order to override the spec.template stanza, and when simple string
# parameterization are insufficient. In the below examples, the generators[].XXX.template is
# a partial definition, which overrides/patch the default template.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
generators:
- list:
elements:
- cluster: engineering-dev
url: https://kubernetes.default.svc
template:
metadata: {}
spec:
project: "default"
source:
targetRevision: HEAD
repoURL: https://github.com/argoproj/argo-cd.git
path: 'applicationset/examples/template-override/{{cluster}}-override'
destination: {}
template:
metadata:
name: '{{cluster}}-guestbook'
spec:
project: "default"
source:
repoURL: https://github.com/argoproj/argo-cd.git
targetRevision: HEAD
path: applicationset/examples/template-override/default
destination:
server: '{{url}}'
namespace: guestbook

View File

@@ -7,7 +7,6 @@ kind: ApplicationSet
metadata:
name: guestbook
spec:
goTemplate: true
generators:
- list:
elements:
@@ -20,12 +19,12 @@ spec:
source:
targetRevision: HEAD
repoURL: https://github.com/argoproj/argo-cd.git
path: 'applicationset/examples/template-override/{{.cluster}}-override'
path: 'applicationset/examples/template-override/{{cluster}}-override'
destination: {}
template:
metadata:
name: '{{.cluster}}-guestbook'
name: '{{cluster}}-guestbook'
spec:
project: "default"
source:
@@ -33,5 +32,5 @@ spec:
targetRevision: HEAD
path: applicationset/examples/template-override/default
destination:
server: '{{.url}}'
server: '{{url}}'
namespace: guestbook

View File

@@ -3,6 +3,8 @@ package generators
import (
"context"
"fmt"
"regexp"
"strings"
"time"
log "github.com/sirupsen/logrus"
@@ -15,7 +17,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
argoappsetv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoappsetv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
const (
@@ -35,8 +37,6 @@ type ClusterGenerator struct {
settingsManager *settings.SettingsManager
}
var render = &utils.Render{}
func NewClusterGenerator(c client.Client, ctx context.Context, clientset kubernetes.Interface, namespace string) Generator {
settingsManager := settings.NewSettingsManager(ctx, clientset, namespace)
@@ -60,7 +60,7 @@ func (g *ClusterGenerator) GetTemplate(appSetGenerator *argoappsetv1alpha1.Appli
}
func (g *ClusterGenerator) GenerateParams(
appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator, appSet *argoappsetv1alpha1.ApplicationSet) ([]map[string]interface{}, error) {
appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator, _ *argoappsetv1alpha1.ApplicationSet) ([]map[string]string, error) {
if appSetGenerator == nil {
return nil, EmptyAppSetGeneratorError
@@ -89,7 +89,7 @@ func (g *ClusterGenerator) GenerateParams(
return nil, err
}
res := []map[string]interface{}{}
res := []map[string]string{}
secretsFound := []corev1.Secret{}
@@ -102,102 +102,43 @@ func (g *ClusterGenerator) GenerateParams(
} else if !ignoreLocalClusters {
// If there is no secret for the cluster, it's the local cluster, so handle it here.
params := map[string]interface{}{}
params := map[string]string{}
params["name"] = cluster.Name
params["nameNormalized"] = cluster.Name
params["server"] = cluster.Server
err = appendTemplatedValues(appSetGenerator.Clusters.Values, params, appSet)
if err != nil {
return nil, err
for key, value := range appSetGenerator.Clusters.Values {
params[fmt.Sprintf("values.%s", key)] = value
}
res = append(res, params)
log.WithField("cluster", "local cluster").Info("matched local cluster")
res = append(res, params)
}
}
// For each matching cluster secret (non-local clusters only)
for _, cluster := range secretsFound {
params := map[string]interface{}{}
params := map[string]string{}
params["name"] = string(cluster.Data["name"])
params["nameNormalized"] = utils.SanitizeName(string(cluster.Data["name"]))
params["nameNormalized"] = sanitizeName(string(cluster.Data["name"]))
params["server"] = string(cluster.Data["server"])
if appSet.Spec.GoTemplate {
meta := map[string]interface{}{}
if len(cluster.ObjectMeta.Annotations) > 0 {
meta["annotations"] = cluster.ObjectMeta.Annotations
}
if len(cluster.ObjectMeta.Labels) > 0 {
meta["labels"] = cluster.ObjectMeta.Labels
}
params["metadata"] = meta
} else {
for key, value := range cluster.ObjectMeta.Annotations {
params[fmt.Sprintf("metadata.annotations.%s", key)] = value
}
for key, value := range cluster.ObjectMeta.Labels {
params[fmt.Sprintf("metadata.labels.%s", key)] = value
}
for key, value := range cluster.ObjectMeta.Annotations {
params[fmt.Sprintf("metadata.annotations.%s", key)] = value
}
err = appendTemplatedValues(appSetGenerator.Clusters.Values, params, appSet)
if err != nil {
return nil, err
for key, value := range cluster.ObjectMeta.Labels {
params[fmt.Sprintf("metadata.labels.%s", key)] = value
}
for key, value := range appSetGenerator.Clusters.Values {
params[fmt.Sprintf("values.%s", key)] = value
}
log.WithField("cluster", cluster.Name).Info("matched cluster secret")
res = append(res, params)
log.WithField("cluster", cluster.Name).Info("matched cluster secret")
}
return res, nil
}
func appendTemplatedValues(clusterValues map[string]string, params map[string]interface{}, appSet *argoappsetv1alpha1.ApplicationSet) error {
// We create a local map to ensure that we do not fall victim to a billion-laughs attack. We iterate through the
// cluster values map and only replace values in said map if it has already been whitelisted in the params map.
// Once we iterate through all the cluster values we can then safely merge the `tmp` map into the main params map.
tmp := map[string]interface{}{}
for key, value := range clusterValues {
result, err := replaceTemplatedString(value, params, appSet)
if err != nil {
return fmt.Errorf("error replacing templated String: %w", err)
}
if appSet.Spec.GoTemplate {
if tmp["values"] == nil {
tmp["values"] = map[string]string{}
}
tmp["values"].(map[string]string)[key] = result
} else {
tmp[fmt.Sprintf("values.%s", key)] = result
}
}
for key, value := range tmp {
params[key] = value
}
return nil
}
func replaceTemplatedString(value string, params map[string]interface{}, appSet *argoappsetv1alpha1.ApplicationSet) (string, error) {
replacedTmplStr, err := render.Replace(value, params, appSet.Spec.GoTemplate)
if err != nil {
return "", err
}
return replacedTmplStr, nil
}
func (g *ClusterGenerator) getSecretsByClusterName(appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator) (map[string]corev1.Secret, error) {
// List all Clusters:
clusterSecretList := &corev1.SecretList{}
@@ -224,3 +165,20 @@ func (g *ClusterGenerator) getSecretsByClusterName(appSetGenerator *argoappsetv1
return res, nil
}
// sanitize the name in accordance with the below rules
// 1. contain no more than 253 characters
// 2. contain only lowercase alphanumeric characters, '-' or '.'
// 3. start and end with an alphanumeric character
func sanitizeName(name string) string {
invalidDNSNameChars := regexp.MustCompile("[^-a-z0-9.]")
maxDNSNameLength := 253
name = strings.ToLower(name)
name = invalidDNSNameChars.ReplaceAllString(name, "-")
if len(name) > maxDNSNameLength {
name = name[:maxDNSNameLength]
}
return strings.Trim(name, "-.")
}

View File

@@ -3,7 +3,6 @@ package generators
import (
"context"
"fmt"
"testing"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -11,10 +10,11 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"testing"
kubefake "k8s.io/client-go/kubernetes/fake"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoappsetv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
"github.com/stretchr/testify/assert"
)
@@ -86,7 +86,7 @@ func TestGenerateParams(t *testing.T) {
name string
selector metav1.LabelSelector
values map[string]string
expected []map[string]interface{}
expected []map[string]string
// clientError is true if a k8s client error should be simulated
clientError bool
expectedError error
@@ -94,23 +94,15 @@ func TestGenerateParams(t *testing.T) {
{
name: "no label selector",
selector: metav1.LabelSelector{},
values: map[string]string{
"lol1": "lol",
"lol2": "{{values.lol1}}{{values.lol1}}",
"lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}",
"foo": "bar",
"bar": "{{ metadata.annotations.foo.argoproj.io }}",
"bat": "{{ metadata.labels.environment }}",
"aaa": "{{ server }}",
"no-op": "{{ this-does-not-exist }}",
}, expected: []map[string]interface{}{
{"values.lol1": "lol", "values.lol2": "{{values.lol1}}{{values.lol1}}", "values.lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}", "values.foo": "bar", "values.bar": "production", "values.no-op": "{{ this-does-not-exist }}", "values.bat": "production", "values.aaa": "https://production-01.example.com", "name": "production_01/west", "nameNormalized": "production-01-west", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar",
values: nil,
expected: []map[string]string{
{"name": "production_01/west", "nameNormalized": "production-01-west", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar",
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production"},
{"values.lol1": "lol", "values.lol2": "{{values.lol1}}{{values.lol1}}", "values.lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}", "values.foo": "bar", "values.bar": "staging", "values.no-op": "{{ this-does-not-exist }}", "values.bat": "staging", "values.aaa": "https://staging-01.example.com", "name": "staging-01", "nameNormalized": "staging-01", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org": "foo",
{"name": "staging-01", "nameNormalized": "staging-01", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org": "foo",
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging"},
{"values.lol1": "lol", "values.lol2": "{{values.lol1}}{{values.lol1}}", "values.lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}", "values.foo": "bar", "values.bar": "{{ metadata.annotations.foo.argoproj.io }}", "values.no-op": "{{ this-does-not-exist }}", "values.bat": "{{ metadata.labels.environment }}", "values.aaa": "https://kubernetes.default.svc", "nameNormalized": "in-cluster", "name": "in-cluster", "server": "https://kubernetes.default.svc"},
{"name": "in-cluster", "server": "https://kubernetes.default.svc"},
},
clientError: false,
expectedError: nil,
@@ -123,7 +115,7 @@ func TestGenerateParams(t *testing.T) {
},
},
values: nil,
expected: []map[string]interface{}{
expected: []map[string]string{
{"name": "production_01/west", "nameNormalized": "production-01-west", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar",
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production"},
@@ -143,7 +135,7 @@ func TestGenerateParams(t *testing.T) {
values: map[string]string{
"foo": "bar",
},
expected: []map[string]interface{}{
expected: []map[string]string{
{"values.foo": "bar", "name": "production_01/west", "nameNormalized": "production-01-west", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar",
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production"},
},
@@ -167,7 +159,7 @@ func TestGenerateParams(t *testing.T) {
values: map[string]string{
"foo": "bar",
},
expected: []map[string]interface{}{
expected: []map[string]string{
{"values.foo": "bar", "name": "staging-01", "nameNormalized": "staging-01", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org": "foo",
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging"},
{"values.foo": "bar", "name": "production_01/west", "nameNormalized": "production-01-west", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar",
@@ -196,7 +188,7 @@ func TestGenerateParams(t *testing.T) {
values: map[string]string{
"name": "baz",
},
expected: []map[string]interface{}{
expected: []map[string]string{
{"values.name": "baz", "name": "staging-01", "nameNormalized": "staging-01", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org": "foo",
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging"},
},
@@ -233,395 +225,12 @@ func TestGenerateParams(t *testing.T) {
var clusterGenerator = NewClusterGenerator(cl, context.Background(), appClientset, "namespace")
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
},
Spec: argoprojiov1alpha1.ApplicationSetSpec{},
}
got, err := clusterGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
Clusters: &argoprojiov1alpha1.ClusterGenerator{
got, err := clusterGenerator.GenerateParams(&argoappsetv1alpha1.ApplicationSetGenerator{
Clusters: &argoappsetv1alpha1.ClusterGenerator{
Selector: testCase.selector,
Values: testCase.values,
},
}, &applicationSetInfo)
if testCase.expectedError != nil {
assert.EqualError(t, err, testCase.expectedError.Error())
} else {
assert.NoError(t, err)
assert.ElementsMatch(t, testCase.expected, got)
}
})
}
}
func TestGenerateParamsGoTemplate(t *testing.T) {
clusters := []client.Object{
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "staging-01",
Namespace: "namespace",
Labels: map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "staging",
"org": "foo",
},
Annotations: map[string]string{
"foo.argoproj.io": "staging",
},
},
Data: map[string][]byte{
"config": []byte("{}"),
"name": []byte("staging-01"),
"server": []byte("https://staging-01.example.com"),
},
Type: corev1.SecretType("Opaque"),
},
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "production-01",
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("production_01/west"),
"server": []byte("https://production-01.example.com"),
},
Type: corev1.SecretType("Opaque"),
},
}
testCases := []struct {
name string
selector metav1.LabelSelector
values map[string]string
expected []map[string]interface{}
// clientError is true if a k8s client error should be simulated
clientError bool
expectedError error
}{
{
name: "no label selector",
selector: metav1.LabelSelector{},
values: map[string]string{
"lol1": "lol",
"lol2": "{{ .values.lol1 }}{{ .values.lol1 }}",
"lol3": "{{ .values.lol2 }}{{ .values.lol2 }}{{ .values.lol2 }}",
"foo": "bar",
"bar": "{{ if not (empty .metadata) }}{{index .metadata.annotations \"foo.argoproj.io\" }}{{ end }}",
"bat": "{{ if not (empty .metadata) }}{{.metadata.labels.environment}}{{ end }}",
"aaa": "{{ .server }}",
"no-op": "{{ .thisDoesNotExist }}",
}, expected: []map[string]interface{}{
{
"name": "production_01/west",
"nameNormalized": "production-01-west",
"server": "https://production-01.example.com",
"metadata": map[string]interface{}{
"labels": map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "production",
"org": "bar",
},
"annotations": map[string]string{
"foo.argoproj.io": "production",
},
},
"values": map[string]string{
"lol1": "lol",
"lol2": "<no value><no value>",
"lol3": "<no value><no value><no value>",
"foo": "bar",
"bar": "production",
"bat": "production",
"aaa": "https://production-01.example.com",
"no-op": "<no value>",
},
},
{
"name": "staging-01",
"nameNormalized": "staging-01",
"server": "https://staging-01.example.com",
"metadata": map[string]interface{}{
"labels": map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "staging",
"org": "foo",
},
"annotations": map[string]string{
"foo.argoproj.io": "staging",
},
},
"values": map[string]string{
"lol1": "lol",
"lol2": "<no value><no value>",
"lol3": "<no value><no value><no value>",
"foo": "bar",
"bar": "staging",
"bat": "staging",
"aaa": "https://staging-01.example.com",
"no-op": "<no value>",
},
},
{
"nameNormalized": "in-cluster",
"name": "in-cluster",
"server": "https://kubernetes.default.svc",
"values": map[string]string{
"lol1": "lol",
"lol2": "<no value><no value>",
"lol3": "<no value><no value><no value>",
"foo": "bar",
"bar": "",
"bat": "",
"aaa": "https://kubernetes.default.svc",
"no-op": "<no value>",
},
},
},
clientError: false,
expectedError: nil,
},
{
name: "secret type label selector",
selector: metav1.LabelSelector{
MatchLabels: map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
},
},
values: nil,
expected: []map[string]interface{}{
{
"name": "production_01/west",
"nameNormalized": "production-01-west",
"server": "https://production-01.example.com",
"metadata": map[string]interface{}{
"labels": map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "production",
"org": "bar",
},
"annotations": map[string]string{
"foo.argoproj.io": "production",
},
},
},
{
"name": "staging-01",
"nameNormalized": "staging-01",
"server": "https://staging-01.example.com",
"metadata": map[string]interface{}{
"labels": map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "staging",
"org": "foo",
},
"annotations": map[string]string{
"foo.argoproj.io": "staging",
},
},
},
},
clientError: false,
expectedError: nil,
},
{
name: "production-only",
selector: metav1.LabelSelector{
MatchLabels: map[string]string{
"environment": "production",
},
},
values: map[string]string{
"foo": "bar",
},
expected: []map[string]interface{}{
{
"name": "production_01/west",
"nameNormalized": "production-01-west",
"server": "https://production-01.example.com",
"metadata": map[string]interface{}{
"labels": map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "production",
"org": "bar",
},
"annotations": map[string]string{
"foo.argoproj.io": "production",
},
},
"values": map[string]string{
"foo": "bar",
},
},
},
clientError: false,
expectedError: nil,
},
{
name: "production or staging",
selector: metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "environment",
Operator: "In",
Values: []string{
"production",
"staging",
},
},
},
},
values: map[string]string{
"foo": "bar",
},
expected: []map[string]interface{}{
{
"name": "production_01/west",
"nameNormalized": "production-01-west",
"server": "https://production-01.example.com",
"metadata": map[string]interface{}{
"labels": map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "production",
"org": "bar",
},
"annotations": map[string]string{
"foo.argoproj.io": "production",
},
},
"values": map[string]string{
"foo": "bar",
},
},
{
"name": "staging-01",
"nameNormalized": "staging-01",
"server": "https://staging-01.example.com",
"metadata": map[string]interface{}{
"labels": map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "staging",
"org": "foo",
},
"annotations": map[string]string{
"foo.argoproj.io": "staging",
},
},
"values": map[string]string{
"foo": "bar",
},
},
},
clientError: false,
expectedError: nil,
},
{
name: "production or staging with match labels",
selector: metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "environment",
Operator: "In",
Values: []string{
"production",
"staging",
},
},
},
MatchLabels: map[string]string{
"org": "foo",
},
},
values: map[string]string{
"name": "baz",
},
expected: []map[string]interface{}{
{
"name": "staging-01",
"nameNormalized": "staging-01",
"server": "https://staging-01.example.com",
"metadata": map[string]interface{}{
"labels": map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "staging",
"org": "foo",
},
"annotations": map[string]string{
"foo.argoproj.io": "staging",
},
},
"values": map[string]string{
"name": "baz",
},
},
},
clientError: false,
expectedError: nil,
},
{
name: "simulate client error",
selector: metav1.LabelSelector{},
values: nil,
expected: nil,
clientError: true,
expectedError: fmt.Errorf("could not list Secrets"),
},
}
// convert []client.Object to []runtime.Object, for use by kubefake package
runtimeClusters := []runtime.Object{}
for _, clientCluster := range clusters {
runtimeClusters = append(runtimeClusters, clientCluster)
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
appClientset := kubefake.NewSimpleClientset(runtimeClusters...)
fakeClient := fake.NewClientBuilder().WithObjects(clusters...).Build()
cl := &possiblyErroringFakeCtrlRuntimeClient{
fakeClient,
testCase.clientError,
}
var clusterGenerator = NewClusterGenerator(cl, context.Background(), appClientset, "namespace")
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
},
Spec: argoprojiov1alpha1.ApplicationSetSpec{
GoTemplate: true,
},
}
got, err := clusterGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
Clusters: &argoprojiov1alpha1.ClusterGenerator{
Selector: testCase.selector,
Values: testCase.values,
},
}, &applicationSetInfo)
}, nil)
if testCase.expectedError != nil {
assert.EqualError(t, err, testCase.expectedError.Error())
@@ -636,10 +245,10 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
func TestSanitizeClusterName(t *testing.T) {
t.Run("valid DNS-1123 subdomain name", func(t *testing.T) {
assert.Equal(t, "cluster-name", utils.SanitizeName("cluster-name"))
assert.Equal(t, "cluster-name", sanitizeName("cluster-name"))
})
t.Run("invalid DNS-1123 subdomain name", func(t *testing.T) {
invalidName := "-.--CLUSTER/name -./.-"
assert.Equal(t, "cluster-name", utils.SanitizeName(invalidName))
assert.Equal(t, "cluster-name", sanitizeName(invalidName))
})
}

View File

@@ -17,7 +17,7 @@ import (
"k8s.io/client-go/kubernetes"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
var _ Generator = (*DuckTypeGenerator)(nil)
@@ -60,7 +60,7 @@ func (g *DuckTypeGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.Appl
return &appSetGenerator.ClusterDecisionResource.Template
}
func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) {
func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, _ *argoprojiov1alpha1.ApplicationSet) ([]map[string]string, error) {
if appSetGenerator == nil {
return nil, EmptyAppSetGeneratorError
@@ -152,7 +152,7 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A
}
res := []map[string]interface{}{}
res := []map[string]string{}
clusterDecisions := []interface{}{}
// Build the decision slice
@@ -178,7 +178,7 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A
for _, cluster := range clusterDecisions {
// generated instance of cluster params
params := map[string]interface{}{}
params := map[string]string{}
log.Infof("cluster: %v", cluster)
matchValue := cluster.(map[string]interface{})[matchKey]
@@ -215,14 +215,7 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A
}
for key, value := range appSetGenerator.ClusterDecisionResource.Values {
if appSet.Spec.GoTemplate {
if params["values"] == nil {
params["values"] = map[string]string{}
}
params["values"].(map[string]string)[key] = value
} else {
params[fmt.Sprintf("values.%s", key)] = value
}
params[fmt.Sprintf("values.%s", key)] = value
}
res = append(res, params)

View File

@@ -14,7 +14,7 @@ import (
kubefake "k8s.io/client-go/kubernetes/fake"
"sigs.k8s.io/controller-runtime/pkg/client"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
"testing"
)
@@ -149,7 +149,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
labelSelector metav1.LabelSelector
resource *unstructured.Unstructured
values map[string]string
expected []map[string]interface{}
expected []map[string]string
expectedError error
}{
{
@@ -157,7 +157,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
resourceName: "",
resource: duckType,
values: nil,
expected: []map[string]interface{}{},
expected: []map[string]string{},
expectedError: fmt.Errorf("There is a problem with the definition of the ClusterDecisionResource generator"),
},
/*** This does not work with the FAKE runtime client, fieldSelectors are broken.
@@ -175,7 +175,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
resourceName: resourceName,
resource: duckType,
values: nil,
expected: []map[string]interface{}{
expected: []map[string]string{
{"clusterName": "production-01", "name": "production-01", "server": "https://production-01.example.com"},
{"clusterName": "staging-01", "name": "staging-01", "server": "https://staging-01.example.com"},
@@ -189,7 +189,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
values: map[string]string{
"foo": "bar",
},
expected: []map[string]interface{}{
expected: []map[string]string{
{"clusterName": "production-01", "values.foo": "bar", "name": "production-01", "server": "https://production-01.example.com"},
},
expectedError: nil,
@@ -217,7 +217,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
labelSelector: metav1.LabelSelector{MatchLabels: map[string]string{"duck": "all-species"}},
resource: duckType,
values: nil,
expected: []map[string]interface{}{
expected: []map[string]string{
{"clusterName": "production-01", "name": "production-01", "server": "https://production-01.example.com"},
{"clusterName": "staging-01", "name": "staging-01", "server": "https://staging-01.example.com"},
@@ -232,7 +232,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
values: map[string]string{
"foo": "bar",
},
expected: []map[string]interface{}{
expected: []map[string]string{
{"clusterName": "production-01", "values.foo": "bar", "name": "production-01", "server": "https://production-01.example.com"},
},
expectedError: nil,
@@ -249,7 +249,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
}},
resource: duckType,
values: nil,
expected: []map[string]interface{}{
expected: []map[string]string{
{"clusterName": "production-01", "name": "production-01", "server": "https://production-01.example.com"},
{"clusterName": "staging-01", "name": "staging-01", "server": "https://staging-01.example.com"},
@@ -295,13 +295,6 @@ func TestGenerateParamsForDuckType(t *testing.T) {
var duckTypeGenerator = NewDuckTypeGenerator(context.Background(), fakeDynClient, appClientset, "namespace")
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
},
Spec: argoprojiov1alpha1.ApplicationSetSpec{},
}
got, err := duckTypeGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
ClusterDecisionResource: &argoprojiov1alpha1.DuckTypeGenerator{
ConfigMapRef: "my-configmap",
@@ -309,307 +302,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
LabelSelector: testCase.labelSelector,
Values: testCase.values,
},
}, &applicationSetInfo)
if testCase.expectedError != nil {
assert.EqualError(t, err, testCase.expectedError.Error())
} else {
assert.NoError(t, err)
assert.ElementsMatch(t, testCase.expected, got)
}
})
}
}
func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
clusters := []client.Object{
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "staging-01",
Namespace: "namespace",
Labels: map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "staging",
"org": "foo",
},
Annotations: map[string]string{
"foo.argoproj.io": "staging",
},
},
Data: map[string][]byte{
"config": []byte("{}"),
"name": []byte("staging-01"),
"server": []byte("https://staging-01.example.com"),
},
Type: corev1.SecretType("Opaque"),
},
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "production-01",
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("production-01"),
"server": []byte("https://production-01.example.com"),
},
Type: corev1.SecretType("Opaque"),
},
}
duckType := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": resourceApiVersion,
"kind": "Duck",
"metadata": map[string]interface{}{
"name": resourceName,
"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",
},
},
},
},
}
duckTypeProdOnly := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": resourceApiVersion,
"kind": "Duck",
"metadata": map[string]interface{}{
"name": resourceName,
"namespace": "namespace",
"labels": map[string]interface{}{"duck": "spotted"},
},
"status": map[string]interface{}{
"decisions": []interface{}{
map[string]interface{}{
"clusterName": "production-01",
},
},
},
},
}
duckTypeEmpty := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": resourceApiVersion,
"kind": "Duck",
"metadata": map[string]interface{}{
"name": resourceName,
"namespace": "namespace",
"labels": map[string]interface{}{"duck": "canvasback"},
},
"status": map[string]interface{}{},
},
}
configMap := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "my-configmap",
Namespace: "namespace",
},
Data: map[string]string{
"apiVersion": resourceApiVersion,
"kind": resourceKind,
"statusListKey": "decisions",
"matchKey": "clusterName",
},
}
testCases := []struct {
name string
configMapRef string
resourceName string
labelSelector metav1.LabelSelector
resource *unstructured.Unstructured
values map[string]string
expected []map[string]interface{}
expectedError error
}{
{
name: "no duck resource",
resourceName: "",
resource: duckType,
values: nil,
expected: []map[string]interface{}{},
expectedError: fmt.Errorf("There is a problem with the definition of the ClusterDecisionResource generator"),
},
/*** This does not work with the FAKE runtime client, fieldSelectors are broken.
{
name: "invalid name for duck resource",
resourceName: resourceName + "-different",
resource: duckType,
values: nil,
expected: []map[string]string{},
expectedError: fmt.Errorf("duck.mallard.io \"quak\" not found"),
},
***/
{
name: "duck type generator resourceName",
resourceName: resourceName,
resource: duckType,
values: nil,
expected: []map[string]interface{}{
{"clusterName": "production-01", "name": "production-01", "server": "https://production-01.example.com"},
{"clusterName": "staging-01", "name": "staging-01", "server": "https://staging-01.example.com"},
},
expectedError: nil,
},
{
name: "production-only",
resourceName: resourceName,
resource: duckTypeProdOnly,
values: map[string]string{
"foo": "bar",
},
expected: []map[string]interface{}{
{"clusterName": "production-01", "values": map[string]string{"foo": "bar"}, "name": "production-01", "server": "https://production-01.example.com"},
},
expectedError: nil,
},
{
name: "duck type empty status",
resourceName: resourceName,
resource: duckTypeEmpty,
values: nil,
expected: nil,
expectedError: nil,
},
{
name: "duck type empty status labelSelector.matchLabels",
resourceName: "",
labelSelector: metav1.LabelSelector{MatchLabels: map[string]string{"duck": "canvasback"}},
resource: duckTypeEmpty,
values: nil,
expected: nil,
expectedError: nil,
},
{
name: "duck type generator labelSelector.matchLabels",
resourceName: "",
labelSelector: metav1.LabelSelector{MatchLabels: map[string]string{"duck": "all-species"}},
resource: duckType,
values: nil,
expected: []map[string]interface{}{
{"clusterName": "production-01", "name": "production-01", "server": "https://production-01.example.com"},
{"clusterName": "staging-01", "name": "staging-01", "server": "https://staging-01.example.com"},
},
expectedError: nil,
},
{
name: "production-only labelSelector.matchLabels",
resourceName: "",
resource: duckTypeProdOnly,
labelSelector: metav1.LabelSelector{MatchLabels: map[string]string{"duck": "spotted"}},
values: map[string]string{
"foo": "bar",
},
expected: []map[string]interface{}{
{"clusterName": "production-01", "values": map[string]string{"foo": "bar"}, "name": "production-01", "server": "https://production-01.example.com"},
},
expectedError: nil,
},
{
name: "duck type generator labelSelector.matchExpressions",
resourceName: "",
labelSelector: metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "duck",
Operator: "In",
Values: []string{"all-species", "marbled"},
},
}},
resource: duckType,
values: nil,
expected: []map[string]interface{}{
{"clusterName": "production-01", "name": "production-01", "server": "https://production-01.example.com"},
{"clusterName": "staging-01", "name": "staging-01", "server": "https://staging-01.example.com"},
},
expectedError: nil,
},
{
name: "duck type generator resourceName and labelSelector.matchExpressions",
resourceName: resourceName,
labelSelector: metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "duck",
Operator: "In",
Values: []string{"all-species", "marbled"},
},
}},
resource: duckType,
values: nil,
expected: nil,
expectedError: fmt.Errorf("There is a problem with the definition of the ClusterDecisionResource generator"),
},
}
// convert []client.Object to []runtime.Object, for use by kubefake package
runtimeClusters := []runtime.Object{}
for _, clientCluster := range clusters {
runtimeClusters = append(runtimeClusters, clientCluster)
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
appClientset := kubefake.NewSimpleClientset(append(runtimeClusters, configMap)...)
gvrToListKind := map[schema.GroupVersionResource]string{{
Group: "mallard.io",
Version: "v1",
Resource: "ducks",
}: "DuckList"}
fakeDynClient := dynfake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), gvrToListKind, testCase.resource)
var duckTypeGenerator = NewDuckTypeGenerator(context.Background(), fakeDynClient, appClientset, "namespace")
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
},
Spec: argoprojiov1alpha1.ApplicationSetSpec{
GoTemplate: true,
},
}
got, err := duckTypeGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
ClusterDecisionResource: &argoprojiov1alpha1.DuckTypeGenerator{
ConfigMapRef: "my-configmap",
Name: testCase.resourceName,
LabelSelector: testCase.labelSelector,
Values: testCase.values,
},
}, &applicationSetInfo)
}, nil)
if testCase.expectedError != nil {
assert.EqualError(t, err, testCase.expectedError.Error())

View File

@@ -1,40 +1,23 @@
package generators
import (
"fmt"
"encoding/json"
"reflect"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/imdario/mergo"
log "github.com/sirupsen/logrus"
)
const (
selectorKey = "Selector"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
type TransformResult struct {
Params []map[string]interface{}
Params []map[string]string
Template argoprojiov1alpha1.ApplicationSetTemplate
}
//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)
if err != nil {
return nil, fmt.Errorf("error parsing label selector: %w", err)
}
func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, allGenerators map[string]Generator, baseTemplate argoprojiov1alpha1.ApplicationSetTemplate, appSet *argoprojiov1alpha1.ApplicationSet) ([]TransformResult, error) {
res := []TransformResult{}
var firstError error
interpolatedGenerator := requestedGenerator.DeepCopy()
generators := GetRelevantGenerators(&requestedGenerator, allGenerators)
for _, g := range generators {
@@ -48,20 +31,8 @@ func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, al
}
continue
}
var params []map[string]interface{}
if len(genParams) != 0 {
tempInterpolatedGenerator, err := InterpolateGenerator(&requestedGenerator, genParams, appSet.Spec.GoTemplate)
interpolatedGenerator = &tempInterpolatedGenerator
if err != nil {
log.WithError(err).WithField("genParams", genParams).
Error("error interpolating params for generator")
if firstError == nil {
firstError = err
}
continue
}
}
params, err = g.GenerateParams(interpolatedGenerator, appSet)
params, err := g.GenerateParams(&requestedGenerator, appSet)
if err != nil {
log.WithError(err).WithField("generator", g).
Error("error generating params")
@@ -70,34 +41,16 @@ func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, al
}
continue
}
var filterParams []map[string]interface{}
for _, param := range params {
if requestedGenerator.Selector != nil && !selector.Matches(labels.Set(keepOnlyStringValues(param))) {
continue
}
filterParams = append(filterParams, param)
}
res = append(res, TransformResult{
Params: filterParams,
Params: params,
Template: mergedTemplate,
})
}
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 {
@@ -109,13 +62,9 @@ func GetRelevantGenerators(requestedGenerator *argoprojiov1alpha1.ApplicationSet
if !field.CanInterface() {
continue
}
name := v.Type().Field(i).Name
if name == selectorKey {
continue
}
if !reflect.ValueOf(field.Interface()).IsNil() {
res = append(res, generators[name])
res = append(res, generators[v.Type().Field(i).Name])
}
}
@@ -123,6 +72,7 @@ func GetRelevantGenerators(requestedGenerator *argoprojiov1alpha1.ApplicationSet
}
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)
dest := g.GetTemplate(requestedGenerator).DeepCopy()
@@ -131,28 +81,3 @@ 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
// "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)
if err != nil {
log.WithError(err).WithField("interpolatedGeneratorString", replacedTmplStr).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

@@ -1,267 +0,0 @@
package generators
import (
"context"
"testing"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/stretchr/testify/mock"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
kubefake "k8s.io/client-go/kubernetes/fake"
crtclient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
)
func TestMatchValues(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.foo": "bar"}},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var listGenerator = NewListGenerator()
var data = map[string]Generator{
"List": listGenerator,
}
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
},
Spec: argoprojiov1alpha1.ApplicationSetSpec{},
}
results, err := Transform(argoprojiov1alpha1.ApplicationSetGenerator{
Selector: testCase.selector,
List: &argoprojiov1alpha1.ListGenerator{
Elements: testCase.elements,
Template: emptyTemplate(),
}},
data,
emptyTemplate(),
&applicationSetInfo, nil)
assert.NoError(t, err)
assert.ElementsMatch(t, testCase.expected, results[0].Params)
})
}
}
func emptyTemplate() argoprojiov1alpha1.ApplicationSetTemplate {
return argoprojiov1alpha1.ApplicationSetTemplate{
Spec: argov1alpha1.ApplicationSpec{
Project: "project",
},
}
}
func getMockClusterGenerator() Generator {
clusters := []crtclient.Object{
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "staging-01",
Namespace: "namespace",
Labels: map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "staging",
"org": "foo",
},
Annotations: map[string]string{
"foo.argoproj.io": "staging",
},
},
Data: map[string][]byte{
"config": []byte("{}"),
"name": []byte("staging-01"),
"server": []byte("https://staging-01.example.com"),
},
Type: corev1.SecretType("Opaque"),
},
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "production-01",
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("production_01/west"),
"server": []byte("https://production-01.example.com"),
},
Type: corev1.SecretType("Opaque"),
},
}
runtimeClusters := []runtime.Object{}
appClientset := kubefake.NewSimpleClientset(runtimeClusters...)
fakeClient := fake.NewClientBuilder().WithObjects(clusters...).Build()
return NewClusterGenerator(fakeClient, context.Background(), appClientset, "namespace")
}
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)
var gitGenerator = NewGitGenerator(argoCDServiceMock)
return gitGenerator
}
func TestGetRelevantGenerators(t *testing.T) {
testGenerators := map[string]Generator{
"Clusters": getMockClusterGenerator(),
"Git": getMockGitGenerator(),
}
testGenerators["Matrix"] = NewMatrixGenerator(testGenerators)
testGenerators["Merge"] = NewMergeGenerator(testGenerators)
testGenerators["List"] = NewListGenerator()
requestedGenerator := &argoprojiov1alpha1.ApplicationSetGenerator{
List: &argoprojiov1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
}}
relevantGenerators := GetRelevantGenerators(requestedGenerator, testGenerators)
assert.Len(t, relevantGenerators, 1)
assert.IsType(t, &ListGenerator{}, relevantGenerators[0])
requestedGenerator = &argoprojiov1alpha1.ApplicationSetGenerator{
Clusters: &argoprojiov1alpha1.ClusterGenerator{
Selector: metav1.LabelSelector{},
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
Values: nil,
},
}
relevantGenerators = GetRelevantGenerators(requestedGenerator, testGenerators)
assert.Len(t, relevantGenerators, 1)
assert.IsType(t, &ClusterGenerator{}, relevantGenerators[0])
requestedGenerator = &argoprojiov1alpha1.ApplicationSetGenerator{
Git: &argoprojiov1alpha1.GitGenerator{
RepoURL: "",
Directories: nil,
Files: nil,
Revision: "",
RequeueAfterSeconds: nil,
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
},
}
relevantGenerators = GetRelevantGenerators(requestedGenerator, testGenerators)
assert.Len(t, relevantGenerators, 1)
assert.IsType(t, &GitGenerator{}, relevantGenerators[0])
}
func TestInterpolateGenerator(t *testing.T) {
requestedGenerator := &argoprojiov1alpha1.ApplicationSetGenerator{
Clusters: &argoprojiov1alpha1.ClusterGenerator{
Selector: metav1.LabelSelector{
MatchLabels: map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"path-basename": "{{path.basename}}",
"path-zero": "{{path[0]}}",
"path-full": "{{path}}",
}},
},
}
gitGeneratorParams := map[string]interface{}{
"path": "p1/p2/app3",
"path.basename": "app3",
"path[0]": "p1",
"path[1]": "p2",
"path.basenameNormalized": "app3",
}
interpolatedGenerator, err := InterpolateGenerator(requestedGenerator, gitGeneratorParams, false)
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),
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
},
}
clusterGeneratorParams := map[string]interface{}{
"name": "production_01/west", "server": "https://production-01.example.com",
}
interpolatedGenerator, err = InterpolateGenerator(requestedGenerator, clusterGeneratorParams, true)
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)
}

View File

@@ -14,8 +14,7 @@ import (
"sigs.k8s.io/yaml"
"github.com/argoproj/argo-cd/v2/applicationset/services"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
var _ Generator = (*GitGenerator)(nil)
@@ -46,7 +45,7 @@ func (g *GitGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Appli
return DefaultRequeueAfterSeconds
}
func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) {
func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, _ *argoprojiov1alpha1.ApplicationSet) ([]map[string]string, error) {
if appSetGenerator == nil {
return nil, EmptyAppSetGeneratorError
@@ -57,11 +56,11 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
}
var err error
var res []map[string]interface{}
var res []map[string]string
if appSetGenerator.Git.Directories != nil {
res, err = g.generateParamsForGitDirectories(appSetGenerator, appSet.Spec.GoTemplate)
res, err = g.generateParamsForGitDirectories(appSetGenerator)
} else if appSetGenerator.Git.Files != nil {
res, err = g.generateParamsForGitFiles(appSetGenerator, appSet.Spec.GoTemplate)
res, err = g.generateParamsForGitFiles(appSetGenerator)
} else {
return nil, EmptyAppSetGeneratorError
}
@@ -72,7 +71,7 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
return res, nil
}
func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool) ([]map[string]interface{}, error) {
func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) ([]map[string]string, error) {
// Directories, not files
allPaths, err := g.repos.GetDirectories(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision)
@@ -89,12 +88,12 @@ func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoproj
requestedApps := g.filterApps(appSetGenerator.Git.Directories, allPaths)
res := g.generateParamsFromApps(requestedApps, appSetGenerator, useGoTemplate)
res := g.generateParamsFromApps(requestedApps, appSetGenerator)
return res, nil
}
func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool) ([]map[string]interface{}, error) {
func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) ([]map[string]string, error) {
// Get all files that match the requested path string, removing duplicates
allFiles := make(map[string][]byte)
@@ -117,11 +116,11 @@ func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1al
sort.Strings(allPaths)
// Generate params from each path, and return
res := []map[string]interface{}{}
res := []map[string]string{}
for _, path := range allPaths {
// A JSON / YAML file path can contain multiple sets of parameters (ie it is an array)
paramsArray, err := g.generateParamsFromGitFile(path, allFiles[path], useGoTemplate)
paramsArray, err := g.generateParamsFromGitFile(path, allFiles[path])
if err != nil {
return nil, fmt.Errorf("unable to process file '%s': %v", path, err)
}
@@ -133,7 +132,7 @@ func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1al
return res, nil
}
func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []byte, useGoTemplate bool) ([]map[string]interface{}, error) {
func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []byte) ([]map[string]string, error) {
objectsFound := []map[string]interface{}{}
// First, we attempt to parse as an array
@@ -148,46 +147,29 @@ func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []
objectsFound = append(objectsFound, singleObj)
}
res := []map[string]interface{}{}
res := []map[string]string{}
// Flatten all objects found, and return them
for _, objectFound := range objectsFound {
params := map[string]interface{}{}
if useGoTemplate {
for k, v := range objectFound {
params[k] = v
}
paramPath := map[string]interface{}{}
paramPath["path"] = path.Dir(filePath)
paramPath["basename"] = path.Base(paramPath["path"].(string))
paramPath["filename"] = path.Base(filePath)
paramPath["basenameNormalized"] = utils.SanitizeName(path.Base(paramPath["path"].(string)))
paramPath["filenameNormalized"] = utils.SanitizeName(path.Base(paramPath["filename"].(string)))
paramPath["segments"] = strings.Split(paramPath["path"].(string), "/")
params["path"] = paramPath
} else {
flat, err := flatten.Flatten(objectFound, "", flatten.DotStyle)
if err != nil {
return nil, err
}
for k, v := range flat {
params[k] = fmt.Sprintf("%v", v)
}
params["path"] = path.Dir(filePath)
params["path.basename"] = path.Base(params["path"].(string))
params["path.filename"] = path.Base(filePath)
params["path.basenameNormalized"] = utils.SanitizeName(path.Base(params["path"].(string)))
params["path.filenameNormalized"] = utils.SanitizeName(path.Base(params["path.filename"].(string)))
for k, v := range strings.Split(params["path"].(string), "/") {
if len(v) > 0 {
params["path["+strconv.Itoa(k)+"]"] = v
}
flat, err := flatten.Flatten(objectFound, "", flatten.DotStyle)
if err != nil {
return nil, err
}
params := map[string]string{}
for k, v := range flat {
params[k] = fmt.Sprintf("%v", v)
}
params["path"] = path.Dir(filePath)
params["path.basename"] = path.Base(params["path"])
params["path.filename"] = path.Base(filePath)
params["path.basenameNormalized"] = sanitizeName(path.Base(params["path"]))
params["path.filenameNormalized"] = sanitizeName(path.Base(params["path.filename"]))
for k, v := range strings.Split(params["path"], "/") {
if len(v) > 0 {
params["path["+strconv.Itoa(k)+"]"] = v
}
}
res = append(res, params)
}
@@ -223,32 +205,21 @@ func (g *GitGenerator) filterApps(Directories []argoprojiov1alpha1.GitDirectoryG
return res
}
func (g *GitGenerator) generateParamsFromApps(requestedApps []string, _ *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool) []map[string]interface{} {
// TODO: At some point, the applicationSetGenerator param should be used
func (g *GitGenerator) generateParamsFromApps(requestedApps []string, _ *argoprojiov1alpha1.ApplicationSetGenerator) []map[string]string {
// TODO: At some point, the appicationSetGenerator param should be used
res := make([]map[string]interface{}, len(requestedApps))
res := make([]map[string]string, len(requestedApps))
for i, a := range requestedApps {
params := make(map[string]interface{}, 5)
if useGoTemplate {
paramPath := map[string]interface{}{}
paramPath["path"] = a
paramPath["basename"] = path.Base(a)
paramPath["basenameNormalized"] = utils.SanitizeName(path.Base(a))
paramPath["segments"] = strings.Split(paramPath["path"].(string), "/")
params["path"] = paramPath
} else {
params["path"] = a
params["path.basename"] = path.Base(a)
params["path.basenameNormalized"] = utils.SanitizeName(path.Base(a))
for k, v := range strings.Split(params["path"].(string), "/") {
if len(v) > 0 {
params["path["+strconv.Itoa(k)+"]"] = v
}
params := make(map[string]string, 2)
params["path"] = a
params["path.basename"] = path.Base(a)
params["path.basenameNormalized"] = sanitizeName(path.Base(a))
for k, v := range strings.Split(params["path"], "/") {
if len(v) > 0 {
params["path["+strconv.Itoa(k)+"]"] = v
}
}
res[i] = params
}

View File

@@ -9,7 +9,7 @@ import (
"github.com/stretchr/testify/mock"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
// type clientSet struct {
@@ -51,11 +51,11 @@ func Test_generateParamsFromGitFile(t *testing.T) {
params, err := (*GitGenerator)(nil).generateParamsFromGitFile("path/dir/file_name.yaml", []byte(`
foo:
bar: baz
`), false)
`))
if err != nil {
t.Fatal(err)
}
assert.Equal(t, []map[string]interface{}{
assert.Equal(t, []map[string]string{
{
"foo.bar": "baz",
"path": "path/dir",
@@ -69,34 +69,6 @@ foo:
}, params)
}
func Test_generateParamsFromGitFileGoTemplate(t *testing.T) {
params, err := (*GitGenerator)(nil).generateParamsFromGitFile("path/dir/file_name.yaml", []byte(`
foo:
bar: baz
`), true)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, []map[string]interface{}{
{
"foo": map[string]interface{}{
"bar": "baz",
},
"path": map[string]interface{}{
"path": "path/dir",
"basename": "dir",
"filename": "file_name.yaml",
"basenameNormalized": "dir",
"filenameNormalized": "file-name.yaml",
"segments": []string{
"path",
"dir",
},
},
},
}, params)
}
func TestGitGenerateParamsFromDirectories(t *testing.T) {
cases := []struct {
@@ -104,7 +76,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
directories []argoprojiov1alpha1.GitDirectoryGeneratorItem
repoApps []string
repoError error
expected []map[string]interface{}
expected []map[string]string
expectedError error
}{
{
@@ -117,7 +89,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
"p1/app4",
},
repoError: nil,
expected: []map[string]interface{}{
expected: []map[string]string{
{"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "path[0]": "app1"},
{"path": "app2", "path.basename": "app2", "path.basenameNormalized": "app2", "path[0]": "app2"},
{"path": "app_3", "path.basename": "app_3", "path.basenameNormalized": "app-3", "path[0]": "app_3"},
@@ -134,7 +106,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
"p1/p2/p3/app4",
},
repoError: nil,
expected: []map[string]interface{}{
expected: []map[string]string{
{"path": "p1/app2", "path.basename": "app2", "path[0]": "p1", "path[1]": "app2", "path.basenameNormalized": "app2"},
{"path": "p1/p2/app3", "path.basename": "app3", "path[0]": "p1", "path[1]": "p2", "path[2]": "app3", "path.basenameNormalized": "app3"},
},
@@ -151,7 +123,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
"p2/app3",
},
repoError: nil,
expected: []map[string]interface{}{
expected: []map[string]string{
{"path": "app1", "path.basename": "app1", "path[0]": "app1", "path.basenameNormalized": "app1"},
{"path": "app2", "path.basename": "app2", "path[0]": "app2", "path.basenameNormalized": "app2"},
{"path": "p2/app3", "path.basename": "app3", "path[0]": "p2", "path[1]": "app3", "path.basenameNormalized": "app3"},
@@ -169,7 +141,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
"p2/app3",
},
repoError: nil,
expected: []map[string]interface{}{
expected: []map[string]string{
{"path": "app1", "path.basename": "app1", "path[0]": "app1", "path.basenameNormalized": "app1"},
{"path": "app2", "path.basename": "app2", "path[0]": "app2", "path.basenameNormalized": "app2"},
{"path": "p2/app3", "path.basename": "app3", "path[0]": "p2", "path[1]": "app3", "path.basenameNormalized": "app3"},
@@ -181,7 +153,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
repoApps: []string{},
repoError: nil,
expected: []map[string]interface{}{},
expected: []map[string]string{},
expectedError: nil,
},
{
@@ -189,7 +161,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
repoApps: []string{},
repoError: fmt.Errorf("error"),
expected: []map[string]interface{}{},
expected: []map[string]string{},
expectedError: fmt.Errorf("error"),
},
}
@@ -220,250 +192,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
},
}
got, err := gitGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo)
if testCaseCopy.expectedError != nil {
assert.EqualError(t, err, testCaseCopy.expectedError.Error())
} else {
assert.NoError(t, err)
assert.Equal(t, testCaseCopy.expected, got)
}
argoCDServiceMock.mock.AssertExpectations(t)
})
}
}
func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) {
cases := []struct {
name string
directories []argoprojiov1alpha1.GitDirectoryGeneratorItem
repoApps []string
repoError error
expected []map[string]interface{}
expectedError error
}{
{
name: "happy flow - created apps",
directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
repoApps: []string{
"app1",
"app2",
"app_3",
"p1/app4",
},
repoError: nil,
expected: []map[string]interface{}{
{
"path": map[string]interface{}{
"path": "app1",
"basename": "app1",
"basenameNormalized": "app1",
"segments": []string{
"app1",
},
},
},
{
"path": map[string]interface{}{
"path": "app2",
"basename": "app2",
"basenameNormalized": "app2",
"segments": []string{
"app2",
},
},
},
{
"path": map[string]interface{}{
"path": "app_3",
"basename": "app_3",
"basenameNormalized": "app-3",
"segments": []string{
"app_3",
},
},
},
},
expectedError: nil,
},
{
name: "It filters application according to the paths",
directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "p1/*"}, {Path: "p1/*/*"}},
repoApps: []string{
"app1",
"p1/app2",
"p1/p2/app3",
"p1/p2/p3/app4",
},
repoError: nil,
expected: []map[string]interface{}{
{
"path": map[string]interface{}{
"path": "p1/app2",
"basename": "app2",
"basenameNormalized": "app2",
"segments": []string{
"p1",
"app2",
},
},
},
{
"path": map[string]interface{}{
"path": "p1/p2/app3",
"basename": "app3",
"basenameNormalized": "app3",
"segments": []string{
"p1",
"p2",
"app3",
},
},
},
},
expectedError: nil,
},
{
name: "It filters application according to the paths with Exclude",
directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "p1/*", Exclude: true}, {Path: "*"}, {Path: "*/*"}},
repoApps: []string{
"app1",
"app2",
"p1/app2",
"p1/app3",
"p2/app3",
},
repoError: nil,
expected: []map[string]interface{}{
{
"path": map[string]interface{}{
"path": "app1",
"basename": "app1",
"basenameNormalized": "app1",
"segments": []string{
"app1",
},
},
},
{
"path": map[string]interface{}{
"path": "app2",
"basename": "app2",
"basenameNormalized": "app2",
"segments": []string{
"app2",
},
},
},
{
"path": map[string]interface{}{
"path": "p2/app3",
"basename": "app3",
"basenameNormalized": "app3",
"segments": []string{
"p2",
"app3",
},
},
},
},
expectedError: nil,
},
{
name: "Expecting same exclude behavior with different order",
directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}, {Path: "*/*"}, {Path: "p1/*", Exclude: true}},
repoApps: []string{
"app1",
"app2",
"p1/app2",
"p1/app3",
"p2/app3",
},
repoError: nil,
expected: []map[string]interface{}{
{
"path": map[string]interface{}{
"path": "app1",
"basename": "app1",
"basenameNormalized": "app1",
"segments": []string{
"app1",
},
},
},
{
"path": map[string]interface{}{
"path": "app2",
"basename": "app2",
"basenameNormalized": "app2",
"segments": []string{
"app2",
},
},
},
{
"path": map[string]interface{}{
"path": "p2/app3",
"basename": "app3",
"basenameNormalized": "app3",
"segments": []string{
"p2",
"app3",
},
},
},
},
expectedError: nil,
},
{
name: "handles empty response from repo server",
directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
repoApps: []string{},
repoError: nil,
expected: []map[string]interface{}{},
expectedError: nil,
},
{
name: "handles error from repo server",
directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
repoApps: []string{},
repoError: fmt.Errorf("error"),
expected: []map[string]interface{}{},
expectedError: fmt.Errorf("error"),
},
}
for _, testCase := range cases {
testCaseCopy := testCase
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}}
argoCDServiceMock.mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
var gitGenerator = NewGitGenerator(argoCDServiceMock)
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
},
Spec: argoprojiov1alpha1.ApplicationSetSpec{
GoTemplate: true,
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{
Git: &argoprojiov1alpha1.GitGenerator{
RepoURL: "RepoURL",
Revision: "Revision",
Directories: testCaseCopy.directories,
},
}},
},
}
got, err := gitGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo)
got, err := gitGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], nil)
if testCaseCopy.expectedError != nil {
assert.EqualError(t, err, testCaseCopy.expectedError.Error())
@@ -488,7 +217,7 @@ func TestGitGenerateParamsFromFiles(t *testing.T) {
repoFileContents map[string][]byte
// if repoPathsError is non-nil, the call to GetPaths(...) will return this error value
repoPathsError error
expected []map[string]interface{}
expected []map[string]string
expectedError error
}{
{
@@ -519,7 +248,7 @@ func TestGitGenerateParamsFromFiles(t *testing.T) {
}`),
},
repoPathsError: nil,
expected: []map[string]interface{}{
expected: []map[string]string{
{
"cluster.owner": "john.doe@example.com",
"cluster.name": "production",
@@ -556,7 +285,7 @@ func TestGitGenerateParamsFromFiles(t *testing.T) {
files: []argoprojiov1alpha1.GitFileGeneratorItem{{Path: "**/config.json"}},
repoFileContents: map[string][]byte{},
repoPathsError: fmt.Errorf("paths error"),
expected: []map[string]interface{}{},
expected: []map[string]string{},
expectedError: fmt.Errorf("paths error"),
},
{
@@ -566,7 +295,7 @@ func TestGitGenerateParamsFromFiles(t *testing.T) {
"cluster-config/production/config.json": []byte(`invalid json file`),
},
repoPathsError: nil,
expected: []map[string]interface{}{},
expected: []map[string]string{},
expectedError: fmt.Errorf("unable to process file 'cluster-config/production/config.json': unable to parse file: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}"),
},
{
@@ -595,7 +324,7 @@ func TestGitGenerateParamsFromFiles(t *testing.T) {
]`),
},
repoPathsError: nil,
expected: []map[string]interface{}{
expected: []map[string]string{
{
"cluster.owner": "john.doe@example.com",
"cluster.name": "production",
@@ -647,7 +376,7 @@ cluster:
`),
},
repoPathsError: nil,
expected: []map[string]interface{}{
expected: []map[string]string{
{
"cluster.owner": "john.doe@example.com",
"cluster.name": "production",
@@ -695,7 +424,7 @@ cluster:
address: https://kubernetes.default.svc`),
},
repoPathsError: nil,
expected: []map[string]interface{}{
expected: []map[string]string{
{
"cluster.owner": "john.doe@example.com",
"cluster.name": "production",
@@ -752,357 +481,7 @@ cluster:
},
}
got, err := gitGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo)
fmt.Println(got, err)
if testCaseCopy.expectedError != nil {
assert.EqualError(t, err, testCaseCopy.expectedError.Error())
} else {
assert.NoError(t, err)
assert.ElementsMatch(t, testCaseCopy.expected, got)
}
argoCDServiceMock.mock.AssertExpectations(t)
})
}
}
func TestGitGenerateParamsFromFilesGoTemplate(t *testing.T) {
cases := []struct {
name string
// files is the list of paths/globs to match
files []argoprojiov1alpha1.GitFileGeneratorItem
// repoFileContents maps repo path to the literal contents of that path
repoFileContents map[string][]byte
// if repoPathsError is non-nil, the call to GetPaths(...) will return this error value
repoPathsError error
expected []map[string]interface{}
expectedError error
}{
{
name: "happy flow: create params from git files",
files: []argoprojiov1alpha1.GitFileGeneratorItem{{Path: "**/config.json"}},
repoFileContents: map[string][]byte{
"cluster-config/production/config.json": []byte(`{
"cluster": {
"owner": "john.doe@example.com",
"name": "production",
"address": "https://kubernetes.default.svc"
},
"key1": "val1",
"key2": {
"key2_1": "val2_1",
"key2_2": {
"key2_2_1": "val2_2_1"
}
},
"key3": 123
}`),
"cluster-config/staging/config.json": []byte(`{
"cluster": {
"owner": "foo.bar@example.com",
"name": "staging",
"address": "https://kubernetes.default.svc"
}
}`),
},
repoPathsError: nil,
expected: []map[string]interface{}{
{
"cluster": map[string]interface{}{
"owner": "john.doe@example.com",
"name": "production",
"address": "https://kubernetes.default.svc",
},
"key1": "val1",
"key2": map[string]interface{}{
"key2_1": "val2_1",
"key2_2": map[string]interface{}{
"key2_2_1": "val2_2_1",
},
},
"key3": float64(123),
"path": map[string]interface{}{
"path": "cluster-config/production",
"basename": "production",
"filename": "config.json",
"basenameNormalized": "production",
"filenameNormalized": "config.json",
"segments": []string{
"cluster-config",
"production",
},
},
},
{
"cluster": map[string]interface{}{
"owner": "foo.bar@example.com",
"name": "staging",
"address": "https://kubernetes.default.svc",
},
"path": map[string]interface{}{
"path": "cluster-config/staging",
"basename": "staging",
"filename": "config.json",
"basenameNormalized": "staging",
"filenameNormalized": "config.json",
"segments": []string{
"cluster-config",
"staging",
},
},
},
},
expectedError: nil,
},
{
name: "handles error during getting repo paths",
files: []argoprojiov1alpha1.GitFileGeneratorItem{{Path: "**/config.json"}},
repoFileContents: map[string][]byte{},
repoPathsError: fmt.Errorf("paths error"),
expected: []map[string]interface{}{},
expectedError: fmt.Errorf("paths error"),
},
{
name: "test invalid JSON file returns error",
files: []argoprojiov1alpha1.GitFileGeneratorItem{{Path: "**/config.json"}},
repoFileContents: map[string][]byte{
"cluster-config/production/config.json": []byte(`invalid json file`),
},
repoPathsError: nil,
expected: []map[string]interface{}{},
expectedError: fmt.Errorf("unable to process file 'cluster-config/production/config.json': unable to parse file: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}"),
},
{
name: "test JSON array",
files: []argoprojiov1alpha1.GitFileGeneratorItem{{Path: "**/config.json"}},
repoFileContents: map[string][]byte{
"cluster-config/production/config.json": []byte(`
[
{
"cluster": {
"owner": "john.doe@example.com",
"name": "production",
"address": "https://kubernetes.default.svc",
"inner": {
"one" : "two"
}
}
},
{
"cluster": {
"owner": "john.doe@example.com",
"name": "staging",
"address": "https://kubernetes.default.svc"
}
}
]`),
},
repoPathsError: nil,
expected: []map[string]interface{}{
{
"cluster": map[string]interface{}{
"owner": "john.doe@example.com",
"name": "production",
"address": "https://kubernetes.default.svc",
"inner": map[string]interface{}{
"one": "two",
},
},
"path": map[string]interface{}{
"path": "cluster-config/production",
"basename": "production",
"filename": "config.json",
"basenameNormalized": "production",
"filenameNormalized": "config.json",
"segments": []string{
"cluster-config",
"production",
},
},
},
{
"cluster": map[string]interface{}{
"owner": "john.doe@example.com",
"name": "staging",
"address": "https://kubernetes.default.svc",
},
"path": map[string]interface{}{
"path": "cluster-config/production",
"basename": "production",
"filename": "config.json",
"basenameNormalized": "production",
"filenameNormalized": "config.json",
"segments": []string{
"cluster-config",
"production",
},
},
},
},
expectedError: nil,
},
{
name: "Test YAML flow",
files: []argoprojiov1alpha1.GitFileGeneratorItem{{Path: "**/config.yaml"}},
repoFileContents: map[string][]byte{
"cluster-config/production/config.yaml": []byte(`
cluster:
owner: john.doe@example.com
name: production
address: https://kubernetes.default.svc
key1: val1
key2:
key2_1: val2_1
key2_2:
key2_2_1: val2_2_1
`),
"cluster-config/staging/config.yaml": []byte(`
cluster:
owner: foo.bar@example.com
name: staging
address: https://kubernetes.default.svc
`),
},
repoPathsError: nil,
expected: []map[string]interface{}{
{
"cluster": map[string]interface{}{
"owner": "john.doe@example.com",
"name": "production",
"address": "https://kubernetes.default.svc",
},
"key1": "val1",
"key2": map[string]interface{}{
"key2_1": "val2_1",
"key2_2": map[string]interface{}{
"key2_2_1": "val2_2_1",
},
},
"path": map[string]interface{}{
"path": "cluster-config/production",
"basename": "production",
"filename": "config.yaml",
"basenameNormalized": "production",
"filenameNormalized": "config.yaml",
"segments": []string{
"cluster-config",
"production",
},
},
},
{
"cluster": map[string]interface{}{
"owner": "foo.bar@example.com",
"name": "staging",
"address": "https://kubernetes.default.svc",
},
"path": map[string]interface{}{
"path": "cluster-config/staging",
"basename": "staging",
"filename": "config.yaml",
"basenameNormalized": "staging",
"filenameNormalized": "config.yaml",
"segments": []string{
"cluster-config",
"staging",
},
},
},
},
expectedError: nil,
},
{
name: "test YAML array",
files: []argoprojiov1alpha1.GitFileGeneratorItem{{Path: "**/config.yaml"}},
repoFileContents: map[string][]byte{
"cluster-config/production/config.yaml": []byte(`
- cluster:
owner: john.doe@example.com
name: production
address: https://kubernetes.default.svc
inner:
one: two
- cluster:
owner: john.doe@example.com
name: staging
address: https://kubernetes.default.svc`),
},
repoPathsError: nil,
expected: []map[string]interface{}{
{
"cluster": map[string]interface{}{
"owner": "john.doe@example.com",
"name": "production",
"address": "https://kubernetes.default.svc",
"inner": map[string]interface{}{
"one": "two",
},
},
"path": map[string]interface{}{
"path": "cluster-config/production",
"basename": "production",
"filename": "config.yaml",
"basenameNormalized": "production",
"filenameNormalized": "config.yaml",
"segments": []string{
"cluster-config",
"production",
},
},
},
{
"cluster": map[string]interface{}{
"owner": "john.doe@example.com",
"name": "staging",
"address": "https://kubernetes.default.svc",
},
"path": map[string]interface{}{
"path": "cluster-config/production",
"basename": "production",
"filename": "config.yaml",
"basenameNormalized": "production",
"filenameNormalized": "config.yaml",
"segments": []string{
"cluster-config",
"production",
},
},
},
},
expectedError: nil,
},
}
for _, testCase := range cases {
testCaseCopy := testCase
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).
Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError)
var gitGenerator = NewGitGenerator(argoCDServiceMock)
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
},
Spec: argoprojiov1alpha1.ApplicationSetSpec{
GoTemplate: true,
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{
Git: &argoprojiov1alpha1.GitGenerator{
RepoURL: "RepoURL",
Revision: "Revision",
Files: testCaseCopy.files,
},
}},
},
}
got, err := gitGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo)
got, err := gitGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], nil)
fmt.Println(got, err)
if testCaseCopy.expectedError != nil {
@@ -1115,4 +494,5 @@ cluster:
argoCDServiceMock.mock.AssertExpectations(t)
})
}
}

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"time"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
// Generator defines the interface implemented by all ApplicationSet generators.
@@ -12,9 +12,9 @@ type Generator interface {
// GenerateParams interprets the ApplicationSet and generates all relevant parameters for the application template.
// The expected / desired list of parameters is returned, it then will be render and reconciled
// against the current state of the Applications in the cluster.
GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error)
GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) ([]map[string]string, error)
// GetRequeueAfter is the generator can controller the next reconciled loop
// GetRequeueAfter is the the generator can controller the next reconciled loop
// In case there is more then one generator the time will be the minimum of the times.
// In case NoRequeueAfter is empty, it will be ignored
GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"time"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
var _ Generator = (*ListGenerator)(nil)
@@ -26,7 +26,7 @@ func (g *ListGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.Applicat
return &appSetGenerator.List.Template
}
func (g *ListGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) {
func (g *ListGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, _ *argoprojiov1alpha1.ApplicationSet) ([]map[string]string, error) {
if appSetGenerator == nil {
return nil, EmptyAppSetGeneratorError
}
@@ -35,42 +35,39 @@ func (g *ListGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Appli
return nil, EmptyAppSetGeneratorError
}
res := make([]map[string]interface{}, len(appSetGenerator.List.Elements))
res := make([]map[string]string, len(appSetGenerator.List.Elements))
for i, tmpItem := range appSetGenerator.List.Elements {
params := map[string]interface{}{}
params := map[string]string{}
var element map[string]interface{}
err := json.Unmarshal(tmpItem.Raw, &element)
if err != nil {
return nil, fmt.Errorf("error unmarshling list element %v", err)
}
if appSet.Spec.GoTemplate {
res[i] = element
} else {
for key, value := range element {
if key == "values" {
values, ok := (value).(map[string]interface{})
if !ok {
return nil, fmt.Errorf("error parsing values map")
}
for k, v := range values {
value, ok := v.(string)
if !ok {
return nil, fmt.Errorf("error parsing value as string %v", err)
}
params[fmt.Sprintf("values.%s", k)] = value
}
} else {
v, ok := value.(string)
for key, value := range element {
if key == "values" {
values, ok := (value).(map[string]interface{})
if !ok {
return nil, fmt.Errorf("error parsing values map")
}
for k, v := range values {
value, ok := v.(string)
if !ok {
return nil, fmt.Errorf("error parsing value as string %v", err)
}
params[key] = v
params[fmt.Sprintf("values.%s", k)] = value
}
res[i] = params
} else {
v, ok := value.(string)
if !ok {
return nil, fmt.Errorf("error parsing value as string %v", err)
}
params[key] = v
}
}
res[i] = params
}
return res, nil

View File

@@ -5,22 +5,21 @@ import (
"github.com/stretchr/testify/assert"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
func TestGenerateListParams(t *testing.T) {
testCases := []struct {
elements []apiextensionsv1.JSON
expected []map[string]interface{}
expected []map[string]string
}{
{
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}},
expected: []map[string]string{{"cluster": "cluster", "url": "url"}},
}, {
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url", "values.foo": "bar"}},
expected: []map[string]string{{"cluster": "cluster", "url": "url", "values.foo": "bar"}},
},
}
@@ -28,57 +27,13 @@ func TestGenerateListParams(t *testing.T) {
var listGenerator = NewListGenerator()
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
},
Spec: argoprojiov1alpha1.ApplicationSetSpec{},
}
got, err := listGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
List: &argoprojiov1alpha1.ListGenerator{
Elements: testCase.elements,
}}, &applicationSetInfo)
}}, nil)
assert.NoError(t, err)
assert.ElementsMatch(t, testCase.expected, got)
}
}
func TestGenerateListParamsGoTemplate(t *testing.T) {
testCases := []struct {
elements []apiextensionsv1.JSON
expected []map[string]interface{}
}{
{
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}},
}, {
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url", "values": map[string]interface{}{"foo": "bar"}}},
},
}
for _, testCase := range testCases {
var listGenerator = NewListGenerator()
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
},
Spec: argoprojiov1alpha1.ApplicationSetSpec{
GoTemplate: true,
},
}
got, err := listGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
List: &argoprojiov1alpha1.ListGenerator{
Elements: testCase.elements,
}}, &applicationSetInfo)
assert.NoError(t, err)
assert.ElementsMatch(t, testCase.expected, got)
}
}

View File

@@ -4,10 +4,8 @@ import (
"fmt"
"time"
"github.com/imdario/mergo"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
var _ Generator = (*MatrixGenerator)(nil)
@@ -30,7 +28,7 @@ func NewMatrixGenerator(supportedGenerators map[string]Generator) Generator {
return m
}
func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) {
func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]string, error) {
if appSetGenerator.Matrix == nil {
return nil, EmptyAppSetGeneratorError
@@ -44,42 +42,31 @@ func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.App
return nil, ErrMoreThanTwoGenerators
}
res := []map[string]interface{}{}
res := []map[string]string{}
g0, err := m.getParams(appSetGenerator.Matrix.Generators[0], appSet, nil)
g0, err := m.getParams(appSetGenerator.Matrix.Generators[0], appSet)
if err != nil {
return nil, err
}
g1, err := m.getParams(appSetGenerator.Matrix.Generators[1], appSet)
if err != nil {
return nil, err
}
for _, a := range g0 {
g1, err := m.getParams(appSetGenerator.Matrix.Generators[1], appSet, a)
if err != nil {
return nil, fmt.Errorf("failed to get params for second generator in the matrix generator: %w", err)
}
for _, b := range g1 {
if appSet.Spec.GoTemplate {
tmp := map[string]interface{}{}
if err := mergo.Merge(&tmp, a); err != nil {
return nil, fmt.Errorf("failed to merge params from the first generator in the matrix generator with temp map: %w", err)
}
if err := mergo.Merge(&tmp, b); err != nil {
return nil, fmt.Errorf("failed to merge params from the first generator in the matrix generator with the second: %w", err)
}
res = append(res, tmp)
} else {
val, err := utils.CombineStringMaps(a, b)
if err != nil {
return nil, fmt.Errorf("failed to combine string maps with merging params for the matrix generator: %w", err)
}
res = append(res, utils.ConvertToMapStringInterface(val))
for _, a := range g0 {
for _, b := range g1 {
val, err := utils.CombineStringMaps(a, b)
if err != nil {
return nil, err
}
res = append(res, val)
}
}
return res, nil
}
func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet, params map[string]interface{}) ([]map[string]interface{}, error) {
func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]string, 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.
@@ -114,12 +101,10 @@ func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Appli
PullRequest: appSetBaseGenerator.PullRequest,
Matrix: matrix,
Merge: mergeGenerator,
Selector: appSetBaseGenerator.Selector,
},
m.supportedGenerators,
argoprojiov1alpha1.ApplicationSetTemplate{},
appSet,
params)
appSet)
if err != nil {
return nil, fmt.Errorf("child generator returned an error on parameter generation: %v", err)

View File

@@ -1,22 +1,14 @@
package generators
import (
"context"
"testing"
"time"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
kubefake "k8s.io/client-go/kubernetes/fake"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
func TestMatrixGenerate(t *testing.T) {
@@ -35,7 +27,7 @@ func TestMatrixGenerate(t *testing.T) {
name string
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
expectedErr error
expected []map[string]interface{}
expected []map[string]string
}{
{
name: "happy flow - generate params",
@@ -47,7 +39,7 @@ func TestMatrixGenerate(t *testing.T) {
List: listGenerator,
},
},
expected: []map[string]interface{}{
expected: []map[string]string{
{"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "cluster": "Cluster", "url": "Url"},
{"path": "app2", "path.basename": "app2", "path.basenameNormalized": "app2", "cluster": "Cluster", "url": "Url"},
},
@@ -72,7 +64,7 @@ func TestMatrixGenerate(t *testing.T) {
},
},
},
expected: []map[string]interface{}{
expected: []map[string]string{
{"a": "1", "b": "1"},
{"a": "1", "b": "2"},
{"a": "2", "b": "1"},
@@ -135,13 +127,8 @@ func TestMatrixGenerate(t *testing.T) {
testCaseCopy := testCase // Since tests may run in parallel
t.Run(testCaseCopy.name, func(t *testing.T) {
genMock := &generatorMock{}
appSet := &argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
},
Spec: argoprojiov1alpha1.ApplicationSetSpec{},
}
mock := &generatorMock{}
appSet := &argoprojiov1alpha1.ApplicationSet{}
for _, g := range testCaseCopy.baseGenerators {
@@ -149,7 +136,7 @@ func TestMatrixGenerate(t *testing.T) {
Git: g.Git,
List: g.List,
}
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet).Return([]map[string]interface{}{
mock.On("GenerateParams", &gitGeneratorSpec, appSet).Return([]map[string]string{
{
"path": "app1",
"path.basename": "app1",
@@ -162,13 +149,13 @@ func TestMatrixGenerate(t *testing.T) {
},
}, nil)
genMock.On("GetTemplate", &gitGeneratorSpec).
mock.On("GetTemplate", &gitGeneratorSpec).
Return(&argoprojiov1alpha1.ApplicationSetTemplate{})
}
var matrixGenerator = NewMatrixGenerator(
map[string]Generator{
"Git": genMock,
"Git": mock,
"List": &ListGenerator{},
},
)
@@ -181,202 +168,7 @@ func TestMatrixGenerate(t *testing.T) {
}, appSet)
if testCaseCopy.expectedErr != nil {
assert.ErrorIs(t, err, testCaseCopy.expectedErr)
} else {
assert.NoError(t, err)
assert.Equal(t, testCaseCopy.expected, got)
}
})
}
}
func TestMatrixGenerateGoTemplate(t *testing.T) {
gitGenerator := &argoprojiov1alpha1.GitGenerator{
RepoURL: "RepoURL",
Revision: "Revision",
Directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
}
listGenerator := &argoprojiov1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "Cluster","url": "Url"}`)}},
}
testCases := []struct {
name string
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
expectedErr error
expected []map[string]interface{}
}{
{
name: "happy flow - generate params",
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
{
Git: gitGenerator,
},
{
List: listGenerator,
},
},
expected: []map[string]interface{}{
{
"path": map[string]string{
"path": "app1",
"basename": "app1",
"basenameNormalized": "app1",
},
"cluster": "Cluster",
"url": "Url",
},
{
"path": map[string]string{
"path": "app2",
"basename": "app2",
"basenameNormalized": "app2",
},
"cluster": "Cluster",
"url": "Url",
},
},
},
{
name: "happy flow - generate params from two lists",
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
{
List: &argoprojiov1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{
{Raw: []byte(`{"a": "1"}`)},
{Raw: []byte(`{"a": "2"}`)},
},
},
},
{
List: &argoprojiov1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{
{Raw: []byte(`{"b": "1"}`)},
{Raw: []byte(`{"b": "2"}`)},
},
},
},
},
expected: []map[string]interface{}{
{"a": "1", "b": "1"},
{"a": "1", "b": "2"},
{"a": "2", "b": "1"},
{"a": "2", "b": "2"},
},
},
{
name: "returns error if there is less than two base generators",
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
{
Git: gitGenerator,
},
},
expectedErr: ErrLessThanTwoGenerators,
},
{
name: "returns error if there is more than two base generators",
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
{
List: listGenerator,
},
{
List: listGenerator,
},
{
List: listGenerator,
},
},
expectedErr: ErrMoreThanTwoGenerators,
},
{
name: "returns error if there is more than one inner generator in the first base generator",
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
{
Git: gitGenerator,
List: listGenerator,
},
{
Git: gitGenerator,
},
},
expectedErr: ErrMoreThenOneInnerGenerators,
},
{
name: "returns error if there is more than one inner generator in the second base generator",
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
{
List: listGenerator,
},
{
Git: gitGenerator,
List: listGenerator,
},
},
expectedErr: ErrMoreThenOneInnerGenerators,
},
}
for _, testCase := range testCases {
testCaseCopy := testCase // Since tests may run in parallel
t.Run(testCaseCopy.name, func(t *testing.T) {
genMock := &generatorMock{}
appSet := &argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
},
Spec: argoprojiov1alpha1.ApplicationSetSpec{
GoTemplate: true,
},
}
for _, g := range testCaseCopy.baseGenerators {
gitGeneratorSpec := argoprojiov1alpha1.ApplicationSetGenerator{
Git: g.Git,
List: g.List,
}
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet).Return([]map[string]interface{}{
{
"path": map[string]string{
"path": "app1",
"basename": "app1",
"basenameNormalized": "app1",
},
},
{
"path": map[string]string{
"path": "app2",
"basename": "app2",
"basenameNormalized": "app2",
},
},
}, nil)
genMock.On("GetTemplate", &gitGeneratorSpec).
Return(&argoprojiov1alpha1.ApplicationSetTemplate{})
}
var matrixGenerator = NewMatrixGenerator(
map[string]Generator{
"Git": genMock,
"List": &ListGenerator{},
},
)
got, err := matrixGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
Matrix: &argoprojiov1alpha1.MatrixGenerator{
Generators: testCaseCopy.baseGenerators,
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
},
}, appSet)
if testCaseCopy.expectedErr != nil {
assert.ErrorIs(t, err, testCaseCopy.expectedErr)
assert.EqualError(t, err, testCaseCopy.expectedErr.Error())
} else {
assert.NoError(t, err)
assert.Equal(t, testCaseCopy.expected, got)
@@ -468,344 +260,6 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
}
}
func TestInterpolatedMatrixGenerate(t *testing.T) {
interpolatedGitGenerator := &argoprojiov1alpha1.GitGenerator{
RepoURL: "RepoURL",
Revision: "Revision",
Files: []argoprojiov1alpha1.GitFileGeneratorItem{
{Path: "examples/git-generator-files-discovery/cluster-config/dev/config.json"},
{Path: "examples/git-generator-files-discovery/cluster-config/prod/config.json"},
},
}
interpolatedClusterGenerator := &argoprojiov1alpha1.ClusterGenerator{
Selector: metav1.LabelSelector{
MatchLabels: map[string]string{"environment": "{{path.basename}}"},
MatchExpressions: nil,
},
}
testCases := []struct {
name string
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
expectedErr error
expected []map[string]interface{}
clientError bool
}{
{
name: "happy flow - generate interpolated params",
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
{
Git: interpolatedGitGenerator,
},
{
Clusters: interpolatedClusterGenerator,
},
},
expected: []map[string]interface{}{
{"path": "examples/git-generator-files-discovery/cluster-config/dev/config.json", "path.basename": "dev", "path.basenameNormalized": "dev", "name": "dev-01", "nameNormalized": "dev-01", "server": "https://dev-01.example.com", "metadata.labels.environment": "dev", "metadata.labels.argocd.argoproj.io/secret-type": "cluster"},
{"path": "examples/git-generator-files-discovery/cluster-config/prod/config.json", "path.basename": "prod", "path.basenameNormalized": "prod", "name": "prod-01", "nameNormalized": "prod-01", "server": "https://prod-01.example.com", "metadata.labels.environment": "prod", "metadata.labels.argocd.argoproj.io/secret-type": "cluster"},
},
clientError: false,
},
}
clusters := []client.Object{
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "dev-01",
Namespace: "namespace",
Labels: map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "dev",
},
},
Data: map[string][]byte{
"config": []byte("{}"),
"name": []byte("dev-01"),
"server": []byte("https://dev-01.example.com"),
},
Type: corev1.SecretType("Opaque"),
},
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "prod-01",
Namespace: "namespace",
Labels: map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "prod",
},
},
Data: map[string][]byte{
"config": []byte("{}"),
"name": []byte("prod-01"),
"server": []byte("https://prod-01.example.com"),
},
Type: corev1.SecretType("Opaque"),
},
}
// convert []client.Object to []runtime.Object, for use by kubefake package
runtimeClusters := []runtime.Object{}
for _, clientCluster := range clusters {
runtimeClusters = append(runtimeClusters, clientCluster)
}
for _, testCase := range testCases {
testCaseCopy := testCase // Since tests may run in parallel
t.Run(testCaseCopy.name, func(t *testing.T) {
genMock := &generatorMock{}
appSet := &argoprojiov1alpha1.ApplicationSet{}
appClientset := kubefake.NewSimpleClientset(runtimeClusters...)
fakeClient := fake.NewClientBuilder().WithObjects(clusters...).Build()
cl := &possiblyErroringFakeCtrlRuntimeClient{
fakeClient,
testCase.clientError,
}
var clusterGenerator = NewClusterGenerator(cl, context.Background(), appClientset, "namespace")
for _, g := range testCaseCopy.baseGenerators {
gitGeneratorSpec := argoprojiov1alpha1.ApplicationSetGenerator{
Git: g.Git,
Clusters: g.Clusters,
}
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet).Return([]map[string]interface{}{
{
"path": "examples/git-generator-files-discovery/cluster-config/dev/config.json",
"path.basename": "dev",
"path.basenameNormalized": "dev",
},
{
"path": "examples/git-generator-files-discovery/cluster-config/prod/config.json",
"path.basename": "prod",
"path.basenameNormalized": "prod",
},
}, nil)
genMock.On("GetTemplate", &gitGeneratorSpec).
Return(&argoprojiov1alpha1.ApplicationSetTemplate{})
}
var matrixGenerator = NewMatrixGenerator(
map[string]Generator{
"Git": genMock,
"Clusters": clusterGenerator,
},
)
got, err := matrixGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
Matrix: &argoprojiov1alpha1.MatrixGenerator{
Generators: testCaseCopy.baseGenerators,
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
},
}, appSet)
if testCaseCopy.expectedErr != nil {
assert.ErrorIs(t, err, testCaseCopy.expectedErr)
} else {
assert.NoError(t, err)
assert.Equal(t, testCaseCopy.expected, got)
}
})
}
}
func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
interpolatedGitGenerator := &argoprojiov1alpha1.GitGenerator{
RepoURL: "RepoURL",
Revision: "Revision",
Files: []argoprojiov1alpha1.GitFileGeneratorItem{
{Path: "examples/git-generator-files-discovery/cluster-config/dev/config.json"},
{Path: "examples/git-generator-files-discovery/cluster-config/prod/config.json"},
},
}
interpolatedClusterGenerator := &argoprojiov1alpha1.ClusterGenerator{
Selector: metav1.LabelSelector{
MatchLabels: map[string]string{"environment": "{{.path.basename}}"},
MatchExpressions: nil,
},
}
testCases := []struct {
name string
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
expectedErr error
expected []map[string]interface{}
clientError bool
}{
{
name: "happy flow - generate interpolated params",
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
{
Git: interpolatedGitGenerator,
},
{
Clusters: interpolatedClusterGenerator,
},
},
expected: []map[string]interface{}{
{
"path": map[string]string{
"path": "examples/git-generator-files-discovery/cluster-config/dev/config.json",
"basename": "dev",
"basenameNormalized": "dev",
},
"name": "dev-01",
"nameNormalized": "dev-01",
"server": "https://dev-01.example.com",
"metadata": map[string]interface{}{
"labels": map[string]string{
"environment": "dev",
"argocd.argoproj.io/secret-type": "cluster",
},
},
},
{
"path": map[string]string{
"path": "examples/git-generator-files-discovery/cluster-config/prod/config.json",
"basename": "prod",
"basenameNormalized": "prod",
},
"name": "prod-01",
"nameNormalized": "prod-01",
"server": "https://prod-01.example.com",
"metadata": map[string]interface{}{
"labels": map[string]string{
"environment": "prod",
"argocd.argoproj.io/secret-type": "cluster",
},
},
},
},
clientError: false,
},
}
clusters := []client.Object{
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "dev-01",
Namespace: "namespace",
Labels: map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "dev",
},
},
Data: map[string][]byte{
"config": []byte("{}"),
"name": []byte("dev-01"),
"server": []byte("https://dev-01.example.com"),
},
Type: corev1.SecretType("Opaque"),
},
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "prod-01",
Namespace: "namespace",
Labels: map[string]string{
"argocd.argoproj.io/secret-type": "cluster",
"environment": "prod",
},
},
Data: map[string][]byte{
"config": []byte("{}"),
"name": []byte("prod-01"),
"server": []byte("https://prod-01.example.com"),
},
Type: corev1.SecretType("Opaque"),
},
}
// convert []client.Object to []runtime.Object, for use by kubefake package
runtimeClusters := []runtime.Object{}
for _, clientCluster := range clusters {
runtimeClusters = append(runtimeClusters, clientCluster)
}
for _, testCase := range testCases {
testCaseCopy := testCase // Since tests may run in parallel
t.Run(testCaseCopy.name, func(t *testing.T) {
genMock := &generatorMock{}
appSet := &argoprojiov1alpha1.ApplicationSet{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
GoTemplate: true,
},
}
appClientset := kubefake.NewSimpleClientset(runtimeClusters...)
fakeClient := fake.NewClientBuilder().WithObjects(clusters...).Build()
cl := &possiblyErroringFakeCtrlRuntimeClient{
fakeClient,
testCase.clientError,
}
var clusterGenerator = NewClusterGenerator(cl, context.Background(), appClientset, "namespace")
for _, g := range testCaseCopy.baseGenerators {
gitGeneratorSpec := argoprojiov1alpha1.ApplicationSetGenerator{
Git: g.Git,
Clusters: g.Clusters,
}
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet).Return([]map[string]interface{}{
{
"path": map[string]string{
"path": "examples/git-generator-files-discovery/cluster-config/dev/config.json",
"basename": "dev",
"basenameNormalized": "dev",
},
},
{
"path": map[string]string{
"path": "examples/git-generator-files-discovery/cluster-config/prod/config.json",
"basename": "prod",
"basenameNormalized": "prod",
},
},
}, nil)
genMock.On("GetTemplate", &gitGeneratorSpec).
Return(&argoprojiov1alpha1.ApplicationSetTemplate{})
}
var matrixGenerator = NewMatrixGenerator(
map[string]Generator{
"Git": genMock,
"Clusters": clusterGenerator,
},
)
got, err := matrixGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
Matrix: &argoprojiov1alpha1.MatrixGenerator{
Generators: testCaseCopy.baseGenerators,
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
},
}, appSet)
if testCaseCopy.expectedErr != nil {
assert.ErrorIs(t, err, testCaseCopy.expectedErr)
} else {
assert.NoError(t, err)
assert.Equal(t, testCaseCopy.expected, got)
}
})
}
}
type generatorMock struct {
mock.Mock
}
@@ -816,10 +270,10 @@ func (g *generatorMock) GetTemplate(appSetGenerator *argoprojiov1alpha1.Applicat
return args.Get(0).(*argoprojiov1alpha1.ApplicationSetTemplate)
}
func (g *generatorMock) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) {
func (g *generatorMock) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]string, error) {
args := g.Called(appSetGenerator, appSet)
return args.Get(0).([]map[string]interface{}), args.Error(1)
return args.Get(0).([]map[string]string), args.Error(1)
}
func (g *generatorMock) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration {

View File

@@ -5,10 +5,8 @@ import (
"fmt"
"time"
"github.com/imdario/mergo"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
var _ Generator = (*MergeGenerator)(nil)
@@ -34,8 +32,8 @@ func NewMergeGenerator(supportedGenerators map[string]Generator) Generator {
// getParamSetsForAllGenerators generates params for each child generator in a MergeGenerator. Param sets are returned
// in slices ordered according to the order of the given generators.
func (m *MergeGenerator) getParamSetsForAllGenerators(generators []argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([][]map[string]interface{}, error) {
var paramSets [][]map[string]interface{}
func (m *MergeGenerator) getParamSetsForAllGenerators(generators []argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([][]map[string]string, error) {
var paramSets [][]map[string]string
for _, generator := range generators {
generatorParamSets, err := m.getParams(generator, appSet)
if err != nil {
@@ -48,7 +46,7 @@ func (m *MergeGenerator) getParamSetsForAllGenerators(generators []argoprojiov1a
}
// GenerateParams gets the params produced by the MergeGenerator.
func (m *MergeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) {
func (m *MergeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]string, error) {
if appSetGenerator.Merge == nil {
return nil, EmptyAppSetGeneratorError
}
@@ -75,24 +73,16 @@ func (m *MergeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Appl
for mergeKeyValue, baseParamSet := range baseParamSetsByMergeKey {
if overrideParamSet, exists := paramSetsByMergeKey[mergeKeyValue]; exists {
if appSet.Spec.GoTemplate {
if err := mergo.Merge(&baseParamSet, overrideParamSet, mergo.WithOverride); err != nil {
return nil, fmt.Errorf("failed to merge base param set with override param set: %w", err)
}
baseParamSetsByMergeKey[mergeKeyValue] = baseParamSet
} else {
overriddenParamSet, err := utils.CombineStringMapsAllowDuplicates(baseParamSet, overrideParamSet)
if err != nil {
return nil, err
}
baseParamSetsByMergeKey[mergeKeyValue] = utils.ConvertToMapStringInterface(overriddenParamSet)
overriddenParamSet, err := utils.CombineStringMapsAllowDuplicates(baseParamSet, overrideParamSet)
if err != nil {
return nil, err
}
baseParamSetsByMergeKey[mergeKeyValue] = overriddenParamSet
}
}
}
mergedParamSets := make([]map[string]interface{}, len(baseParamSetsByMergeKey))
mergedParamSets := make([]map[string]string, len(baseParamSetsByMergeKey))
var i = 0
for _, mergedParamSet := range baseParamSetsByMergeKey {
mergedParamSets[i] = mergedParamSet
@@ -105,7 +95,7 @@ func (m *MergeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Appl
// getParamSetsByMergeKey converts the given list of parameter sets to a map of parameter sets where the key is the
// unique key of the parameter set as determined by the given mergeKeys. If any two parameter sets share the same merge
// key, getParamSetsByMergeKey will throw NonUniqueParamSets.
func getParamSetsByMergeKey(mergeKeys []string, paramSets []map[string]interface{}) (map[string]map[string]interface{}, error) {
func getParamSetsByMergeKey(mergeKeys []string, paramSets []map[string]string) (map[string]map[string]string, error) {
if len(mergeKeys) < 1 {
return nil, ErrNoMergeKeys
}
@@ -115,9 +105,9 @@ func getParamSetsByMergeKey(mergeKeys []string, paramSets []map[string]interface
deDuplicatedMergeKeys[mergeKey] = false
}
paramSetsByMergeKey := make(map[string]map[string]interface{}, len(paramSets))
paramSetsByMergeKey := make(map[string]map[string]string, len(paramSets))
for _, paramSet := range paramSets {
paramSetKey := make(map[string]interface{})
paramSetKey := make(map[string]string)
for mergeKey := range deDuplicatedMergeKeys {
paramSetKey[mergeKey] = paramSet[mergeKey]
}
@@ -136,7 +126,7 @@ 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) {
func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]string, error) {
var matrix *argoprojiov1alpha1.MatrixGenerator
if appSetBaseGenerator.Matrix != nil {
@@ -170,12 +160,10 @@ func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Applic
PullRequest: appSetBaseGenerator.PullRequest,
Matrix: matrix,
Merge: mergeGenerator,
Selector: appSetBaseGenerator.Selector,
},
m.supportedGenerators,
argoprojiov1alpha1.ApplicationSetTemplate{},
appSet,
map[string]interface{}{})
appSet)
if err != nil {
return nil, fmt.Errorf("child generator returned an error on parameter generation: %v", err)

View File

@@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/assert"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
func getNestedListGenerator(json string) *argoprojiov1alpha1.ApplicationSetNestedGenerator {
@@ -35,7 +35,7 @@ func getTerminalListGeneratorMultiple(jsons []string) argoprojiov1alpha1.Applica
return generator
}
func listOfMapsToSet(maps []map[string]interface{}) (map[string]bool, error) {
func listOfMapsToSet(maps []map[string]string) (map[string]bool, error) {
set := make(map[string]bool, len(maps))
for _, paramMap := range maps {
paramMapAsJson, err := json.Marshal(paramMap)
@@ -55,7 +55,7 @@ func TestMergeGenerate(t *testing.T) {
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
mergeKeys []string
expectedErr error
expected []map[string]interface{}
expected []map[string]string
}{
{
name: "no generators",
@@ -79,7 +79,7 @@ func TestMergeGenerate(t *testing.T) {
*getNestedListGenerator(`{"a": "3_1","b": "different","c": "3_3"}`), // gets ignored because its merge key value isn't in the base params set
},
mergeKeys: []string{"b"},
expected: []map[string]interface{}{
expected: []map[string]string{
{"a": "2_1", "b": "same", "c": "1_3"},
},
},
@@ -90,7 +90,7 @@ func TestMergeGenerate(t *testing.T) {
*getNestedListGenerator(`{"a": "a"}`),
},
mergeKeys: []string{"b"},
expected: []map[string]interface{}{
expected: []map[string]string{
{"a": "a"},
},
},
@@ -101,7 +101,7 @@ func TestMergeGenerate(t *testing.T) {
*getNestedListGenerator(`{"b": "b"}`),
},
mergeKeys: []string{"b"},
expected: []map[string]interface{}{
expected: []map[string]string{
{"a": "a"},
},
},
@@ -119,7 +119,7 @@ func TestMergeGenerate(t *testing.T) {
*getNestedListGenerator(`{"a": "1", "b": "1", "c": "added"}`),
},
mergeKeys: []string{"a", "b"},
expected: []map[string]interface{}{
expected: []map[string]string{
{"a": "1", "b": "1", "c": "added"},
{"a": "1", "b": "2"},
{"a": "2", "b": "1"},
@@ -141,7 +141,7 @@ func TestMergeGenerate(t *testing.T) {
*getNestedListGenerator(`{"a": "1", "b": "3", "d": "added"}`),
},
mergeKeys: []string{"a", "b"},
expected: []map[string]interface{}{
expected: []map[string]string{
{"a": "1", "b": "3", "c": "added", "d": "added"},
{"a": "2", "b": "2"},
},
@@ -213,9 +213,9 @@ func TestParamSetsAreUniqueByMergeKeys(t *testing.T) {
testCases := []struct {
name string
mergeKeys []string
paramSets []map[string]interface{}
paramSets []map[string]string
expectedErr error
expected map[string]map[string]interface{}
expected map[string]map[string]string
}{
{
name: "no merge keys",
@@ -225,37 +225,28 @@ func TestParamSetsAreUniqueByMergeKeys(t *testing.T) {
{
name: "no paramSets",
mergeKeys: []string{"key"},
expected: make(map[string]map[string]interface{}),
expected: make(map[string]map[string]string),
},
{
name: "simple key, unique paramSets",
mergeKeys: []string{"key"},
paramSets: []map[string]interface{}{{"key": "a"}, {"key": "b"}},
expected: map[string]map[string]interface{}{
paramSets: []map[string]string{{"key": "a"}, {"key": "b"}},
expected: map[string]map[string]string{
`{"key":"a"}`: {"key": "a"},
`{"key":"b"}`: {"key": "b"},
},
},
{
name: "simple key object, unique paramSets",
mergeKeys: []string{"key"},
paramSets: []map[string]interface{}{{"key": map[string]interface{}{"hello": "world"}}, {"key": "b"}},
expected: map[string]map[string]interface{}{
`{"key":{"hello":"world"}}`: {"key": map[string]interface{}{"hello": "world"}},
`{"key":"b"}`: {"key": "b"},
},
},
{
name: "simple key, non-unique paramSets",
mergeKeys: []string{"key"},
paramSets: []map[string]interface{}{{"key": "a"}, {"key": "b"}, {"key": "b"}},
paramSets: []map[string]string{{"key": "a"}, {"key": "b"}, {"key": "b"}},
expectedErr: fmt.Errorf("%w. Duplicate key was %s", ErrNonUniqueParamSets, `{"key":"b"}`),
},
{
name: "simple key, duplicated key name, unique paramSets",
mergeKeys: []string{"key", "key"},
paramSets: []map[string]interface{}{{"key": "a"}, {"key": "b"}},
expected: map[string]map[string]interface{}{
paramSets: []map[string]string{{"key": "a"}, {"key": "b"}},
expected: map[string]map[string]string{
`{"key":"a"}`: {"key": "a"},
`{"key":"b"}`: {"key": "b"},
},
@@ -263,46 +254,32 @@ func TestParamSetsAreUniqueByMergeKeys(t *testing.T) {
{
name: "simple key, duplicated key name, non-unique paramSets",
mergeKeys: []string{"key", "key"},
paramSets: []map[string]interface{}{{"key": "a"}, {"key": "b"}, {"key": "b"}},
paramSets: []map[string]string{{"key": "a"}, {"key": "b"}, {"key": "b"}},
expectedErr: fmt.Errorf("%w. Duplicate key was %s", ErrNonUniqueParamSets, `{"key":"b"}`),
},
{
name: "compound key, unique paramSets",
mergeKeys: []string{"key1", "key2"},
paramSets: []map[string]interface{}{
paramSets: []map[string]string{
{"key1": "a", "key2": "a"},
{"key1": "a", "key2": "b"},
{"key1": "b", "key2": "a"},
},
expected: map[string]map[string]interface{}{
expected: map[string]map[string]string{
`{"key1":"a","key2":"a"}`: {"key1": "a", "key2": "a"},
`{"key1":"a","key2":"b"}`: {"key1": "a", "key2": "b"},
`{"key1":"b","key2":"a"}`: {"key1": "b", "key2": "a"},
},
},
{
name: "compound key object, unique paramSets",
mergeKeys: []string{"key1", "key2"},
paramSets: []map[string]interface{}{
{"key1": "a", "key2": map[string]interface{}{"hello": "world"}},
{"key1": "a", "key2": "b"},
{"key1": "b", "key2": "a"},
},
expected: map[string]map[string]interface{}{
`{"key1":"a","key2":{"hello":"world"}}`: {"key1": "a", "key2": map[string]interface{}{"hello": "world"}},
`{"key1":"a","key2":"b"}`: {"key1": "a", "key2": "b"},
`{"key1":"b","key2":"a"}`: {"key1": "b", "key2": "a"},
},
},
{
name: "compound key, duplicate key names, unique paramSets",
mergeKeys: []string{"key1", "key1", "key2"},
paramSets: []map[string]interface{}{
paramSets: []map[string]string{
{"key1": "a", "key2": "a"},
{"key1": "a", "key2": "b"},
{"key1": "b", "key2": "a"},
},
expected: map[string]map[string]interface{}{
expected: map[string]map[string]string{
`{"key1":"a","key2":"a"}`: {"key1": "a", "key2": "a"},
`{"key1":"a","key2":"b"}`: {"key1": "a", "key2": "b"},
`{"key1":"b","key2":"a"}`: {"key1": "b", "key2": "a"},
@@ -311,7 +288,7 @@ func TestParamSetsAreUniqueByMergeKeys(t *testing.T) {
{
name: "compound key, non-unique paramSets",
mergeKeys: []string{"key1", "key2"},
paramSets: []map[string]interface{}{
paramSets: []map[string]string{
{"key1": "a", "key2": "a"},
{"key1": "a", "key2": "a"},
{"key1": "b", "key2": "a"},
@@ -321,7 +298,7 @@ func TestParamSetsAreUniqueByMergeKeys(t *testing.T) {
{
name: "compound key, duplicate key names, non-unique paramSets",
mergeKeys: []string{"key1", "key1", "key2"},
paramSets: []map[string]interface{}{
paramSets: []map[string]string{
{"key1": "a", "key2": "a"},
{"key1": "a", "key2": "a"},
{"key1": "b", "key2": "a"},

View File

@@ -9,11 +9,9 @@ import (
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/gosimple/slug"
"github.com/argoproj/argo-cd/v2/applicationset/services/pull_request"
pullrequest "github.com/argoproj/argo-cd/v2/applicationset/services/pull_request"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
var _ Generator = (*PullRequestGenerator)(nil)
@@ -25,13 +23,11 @@ const (
type PullRequestGenerator struct {
client client.Client
selectServiceProviderFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error)
auth SCMAuthProviders
}
func NewPullRequestGenerator(client client.Client, auth SCMAuthProviders) Generator {
func NewPullRequestGenerator(client client.Client) Generator {
g := &PullRequestGenerator{
client: client,
auth: auth,
}
g.selectServiceProviderFunc = g.selectServiceProvider
return g
@@ -51,7 +47,7 @@ func (g *PullRequestGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.A
return &appSetGenerator.PullRequest.Template
}
func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) {
func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) ([]map[string]string, error) {
if appSetGenerator == nil {
return nil, EmptyAppSetGeneratorError
}
@@ -70,32 +66,12 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
if err != nil {
return nil, fmt.Errorf("error listing repos: %v", err)
}
params := make([]map[string]interface{}, 0, len(pulls))
// In order to follow the DNS label standard as defined in RFC 1123,
// we need to limit the 'branch' to 50 to give room to append/suffix-ing it
// with 13 more characters. Also, there is the need to clean it as recommended
// here https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names
slug.MaxLength = 50
// Converting underscores to dashes
slug.CustomSub = map[string]string{
"_": "-",
}
var shortSHALength int
params := make([]map[string]string, 0, len(pulls))
for _, pull := range pulls {
shortSHALength = 8
if len(pull.HeadSHA) < 8 {
shortSHALength = len(pull.HeadSHA)
}
params = append(params, map[string]interface{}{
"number": strconv.Itoa(pull.Number),
"branch": pull.Branch,
"branch_slug": slug.Make(pull.Branch),
"head_sha": pull.HeadSHA,
"head_short_sha": pull.HeadSHA[:shortSHALength],
params = append(params, map[string]string{
"number": strconv.Itoa(pull.Number),
"branch": pull.Branch,
"head_sha": pull.HeadSHA,
})
}
return params, nil
@@ -104,15 +80,12 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
// selectServiceProvider selects the provider to get pull requests from the configuration
func (g *PullRequestGenerator) selectServiceProvider(ctx context.Context, generatorConfig *argoprojiov1alpha1.PullRequestGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
if generatorConfig.Github != nil {
return g.github(ctx, generatorConfig.Github, applicationSetInfo)
}
if generatorConfig.GitLab != nil {
providerConfig := generatorConfig.GitLab
providerConfig := generatorConfig.Github
token, err := g.getSecretRef(ctx, providerConfig.TokenRef, applicationSetInfo.Namespace)
if err != nil {
return nil, fmt.Errorf("error fetching Secret token: %v", err)
}
return pullrequest.NewGitLabService(ctx, token, providerConfig.API, providerConfig.Project, providerConfig.Labels, providerConfig.PullRequestState)
return pullrequest.NewGithubService(ctx, token, providerConfig.API, providerConfig.Owner, providerConfig.Repo, providerConfig.Labels)
}
if generatorConfig.Gitea != nil {
providerConfig := generatorConfig.Gitea
@@ -137,24 +110,6 @@ func (g *PullRequestGenerator) selectServiceProvider(ctx context.Context, genera
return nil, fmt.Errorf("no Pull Request provider implementation configured")
}
func (g *PullRequestGenerator) github(ctx context.Context, cfg *argoprojiov1alpha1.PullRequestGeneratorGithub, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
// use an app if it was configured
if cfg.AppSecretName != "" {
auth, err := g.auth.GitHubApps.GetAuthSecret(ctx, cfg.AppSecretName)
if err != nil {
return nil, fmt.Errorf("error getting GitHub App secret: %v", err)
}
return pullrequest.NewGithubAppService(*auth, cfg.API, cfg.Owner, cfg.Repo, cfg.Labels)
}
// always default to token, even if not set (public access)
token, err := g.getSecretRef(ctx, cfg.TokenRef, applicationSetInfo.Namespace)
if err != nil {
return nil, fmt.Errorf("error fetching Secret token: %v", err)
}
return pullrequest.NewGithubService(ctx, token, cfg.API, cfg.Owner, cfg.Repo, cfg.Labels)
}
// getSecretRef gets the value of the key for the specified Secret resource.
func (g *PullRequestGenerator) getSecretRef(ctx context.Context, ref *argoprojiov1alpha1.SecretRef, namespace string) (string, error) {
if ref == nil {

View File

@@ -11,14 +11,14 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client/fake"
pullrequest "github.com/argoproj/argo-cd/v2/applicationset/services/pull_request"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
func TestPullRequestGithubGenerateParams(t *testing.T) {
ctx := context.Background()
cases := []struct {
selectFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error)
expected []map[string]interface{}
expected []map[string]string
expectedErr error
}{
{
@@ -35,63 +35,11 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
nil,
)
},
expected: []map[string]interface{}{
expected: []map[string]string{
{
"number": "1",
"branch": "branch1",
"branch_slug": "branch1",
"head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958",
"head_short_sha": "089d92cb",
},
},
expectedErr: nil,
},
{
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
return pullrequest.NewFakeService(
ctx,
[]*pullrequest.PullRequest{
&pullrequest.PullRequest{
Number: 2,
Branch: "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
HeadSHA: "9b34ff5bd418e57d58891eb0aa0728043ca1e8be",
},
},
nil,
)
},
expected: []map[string]interface{}{
{
"number": "2",
"branch": "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
"branch_slug": "feat-areally-long-pull-request-name-to-test-argo",
"head_sha": "9b34ff5bd418e57d58891eb0aa0728043ca1e8be",
"head_short_sha": "9b34ff5b",
},
},
expectedErr: nil,
},
{
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
return pullrequest.NewFakeService(
ctx,
[]*pullrequest.PullRequest{
&pullrequest.PullRequest{
Number: 1,
Branch: "a-very-short-sha",
HeadSHA: "abcd",
},
},
nil,
)
},
expected: []map[string]interface{}{
{
"number": "1",
"branch": "a-very-short-sha",
"branch_slug": "a-very-short-sha",
"head_sha": "abcd",
"head_short_sha": "abcd",
"number": "1",
"branch": "branch1",
"head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958",
},
},
expectedErr: nil,
@@ -116,7 +64,6 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
generatorConfig := argoprojiov1alpha1.ApplicationSetGenerator{
PullRequest: &argoprojiov1alpha1.PullRequestGenerator{},
}
got, gotErr := gen.GenerateParams(&generatorConfig, nil)
assert.Equal(t, c.expectedErr, gotErr)
assert.ElementsMatch(t, c.expected, got)

View File

@@ -9,10 +9,8 @@ import (
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/argoproj/argo-cd/v2/applicationset/services/github_app_auth"
"github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
var _ Generator = (*SCMProviderGenerator)(nil)
@@ -25,23 +23,10 @@ type SCMProviderGenerator struct {
client client.Client
// Testing hooks.
overrideProvider scm_provider.SCMProviderService
SCMAuthProviders
}
type SCMAuthProviders struct {
GitHubApps github_app_auth.Credentials
}
func NewSCMProviderGenerator(client client.Client, providers SCMAuthProviders) Generator {
return &SCMProviderGenerator{
client: client,
SCMAuthProviders: providers,
}
}
// Testing generator
func NewTestSCMProviderGenerator(overrideProvider scm_provider.SCMProviderService) Generator {
return &SCMProviderGenerator{overrideProvider: overrideProvider}
func NewSCMProviderGenerator(client client.Client) Generator {
return &SCMProviderGenerator{client: client}
}
func (g *SCMProviderGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration {
@@ -58,7 +43,7 @@ func (g *SCMProviderGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.A
return &appSetGenerator.SCMProvider.Template
}
func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) {
func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) ([]map[string]string, error) {
if appSetGenerator == nil {
return nil, EmptyAppSetGeneratorError
}
@@ -75,10 +60,13 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
if g.overrideProvider != nil {
provider = g.overrideProvider
} else if providerConfig.Github != nil {
var err error
provider, err = g.githubProvider(ctx, providerConfig.Github, applicationSetInfo)
token, err := g.getSecretRef(ctx, providerConfig.Github.TokenRef, applicationSetInfo.Namespace)
if err != nil {
return nil, fmt.Errorf("scm provider: %w", err)
return nil, fmt.Errorf("error fetching Github token: %v", err)
}
provider, err = scm_provider.NewGithubProvider(ctx, providerConfig.Github.Organization, token, providerConfig.Github.API, providerConfig.Github.AllBranches)
if err != nil {
return nil, fmt.Errorf("error initializing Github service: %v", err)
}
} else if providerConfig.Gitlab != nil {
token, err := g.getSecretRef(ctx, providerConfig.Gitlab.TokenRef, applicationSetInfo.Namespace)
@@ -113,15 +101,6 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
if scmError != nil {
return nil, fmt.Errorf("error initializing Bitbucket Server service: %v", scmError)
}
} else if providerConfig.AzureDevOps != nil {
token, err := g.getSecretRef(ctx, providerConfig.AzureDevOps.AccessTokenRef, applicationSetInfo.Namespace)
if err != nil {
return nil, fmt.Errorf("error fetching Azure Devops access token: %v", err)
}
provider, err = scm_provider.NewAzureDevOpsProvider(ctx, token, providerConfig.AzureDevOps.Organization, providerConfig.AzureDevOps.API, providerConfig.AzureDevOps.TeamProject, providerConfig.AzureDevOps.AllBranches)
if err != nil {
return nil, fmt.Errorf("error initializing Azure Devops service: %v", err)
}
} else {
return nil, fmt.Errorf("no SCM provider implementation configured")
}
@@ -131,23 +110,15 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
if err != nil {
return nil, fmt.Errorf("error listing repos: %v", err)
}
params := make([]map[string]interface{}, 0, len(repos))
var shortSHALength int
params := make([]map[string]string, 0, len(repos))
for _, repo := range repos {
shortSHALength = 8
if len(repo.SHA) < 8 {
shortSHALength = len(repo.SHA)
}
params = append(params, map[string]interface{}{
"organization": repo.Organization,
"repository": repo.Repository,
"url": repo.URL,
"branch": repo.Branch,
"sha": repo.SHA,
"short_sha": repo.SHA[:shortSHALength],
"labels": strings.Join(repo.Labels, ","),
"branchNormalized": utils.SanitizeName(repo.Branch),
params = append(params, map[string]string{
"organization": repo.Organization,
"repository": repo.Repository,
"url": repo.URL,
"branch": repo.Branch,
"sha": repo.SHA,
"labels": strings.Join(repo.Labels, ","),
})
}
return params, nil
@@ -175,25 +146,3 @@ func (g *SCMProviderGenerator) getSecretRef(ctx context.Context, ref *argoprojio
}
return string(tokenBytes), nil
}
func (g *SCMProviderGenerator) githubProvider(ctx context.Context, github *argoprojiov1alpha1.SCMProviderGeneratorGithub, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) (scm_provider.SCMProviderService, error) {
if github.AppSecretName != "" {
auth, err := g.GitHubApps.GetAuthSecret(ctx, github.AppSecretName)
if err != nil {
return nil, fmt.Errorf("error fetching Github app secret: %v", err)
}
return scm_provider.NewGithubAppProviderFor(
*auth,
github.Organization,
github.API,
github.AllBranches,
)
}
token, err := g.getSecretRef(ctx, github.TokenRef, applicationSetInfo.Namespace)
if err != nil {
return nil, fmt.Errorf("error fetching Github token: %v", err)
}
return scm_provider.NewGithubProvider(ctx, github.Organization, token, github.API, github.AllBranches)
}

View File

@@ -10,7 +10,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
func TestSCMProviderGetSecretRef(t *testing.T) {
@@ -87,7 +87,7 @@ func TestSCMProviderGenerateParams(t *testing.T) {
Repository: "repo1",
URL: "git@github.com:myorg/repo1.git",
Branch: "main",
SHA: "0bc57212c3cbbec69d20b34c507284bd300def5b",
SHA: "abcd1234",
Labels: []string{"prod", "staging"},
},
{
@@ -95,7 +95,7 @@ func TestSCMProviderGenerateParams(t *testing.T) {
Repository: "repo2",
URL: "git@github.com:myorg/repo2.git",
Branch: "main",
SHA: "59d0",
SHA: "00000000",
},
},
}
@@ -109,9 +109,7 @@ func TestSCMProviderGenerateParams(t *testing.T) {
assert.Equal(t, "repo1", params[0]["repository"])
assert.Equal(t, "git@github.com:myorg/repo1.git", params[0]["url"])
assert.Equal(t, "main", params[0]["branch"])
assert.Equal(t, "0bc57212c3cbbec69d20b34c507284bd300def5b", params[0]["sha"])
assert.Equal(t, "0bc57212", params[0]["short_sha"])
assert.Equal(t, "59d0", params[1]["short_sha"])
assert.Equal(t, "abcd1234", params[0]["sha"])
assert.Equal(t, "prod,staging", params[0]["labels"])
assert.Equal(t, "repo2", params[1]["repository"])
}

View File

@@ -1,19 +0,0 @@
package github_app_auth
import "context"
// Authentication has the authentication information required to access the GitHub API and repositories.
type Authentication struct {
// Id specifies the ID of the GitHub app used to access the repo
Id int64
// InstallationId specifies the installation ID of the GitHub App used to access the repo
InstallationId int64
// EnterpriseBaseURL specifies the base URL of GitHub Enterprise installation. If empty will default to https://api.github.com
EnterpriseBaseURL string
// PrivateKey in PEM format.
PrivateKey string
}
type Credentials interface {
GetAuthSecret(ctx context.Context, secretName string) (*Authentication, error)
}

View File

@@ -1,33 +0,0 @@
package github_app
import (
"fmt"
"net/http"
"github.com/bradleyfalzon/ghinstallation/v2"
"github.com/google/go-github/v35/github"
"github.com/argoproj/argo-cd/v2/applicationset/services/github_app_auth"
)
// Client builds a github client for the given app authentication.
func Client(g github_app_auth.Authentication, url string) (*github.Client, error) {
rt, err := ghinstallation.New(http.DefaultTransport, g.Id, g.InstallationId, []byte(g.PrivateKey))
if err != nil {
return nil, fmt.Errorf("failed to create github app install: %w", err)
}
if url == "" {
url = g.EnterpriseBaseURL
}
var client *github.Client
httpClient := http.Client{Transport: rt}
if url == "" {
client = github.NewClient(&httpClient)
} else {
client, err = github.NewEnterpriseClient(url, url, &httpClient)
if err != nil {
return nil, fmt.Errorf("failed to create github enterprise client: %w", err)
}
}
return client, nil
}

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
"github.com/stretchr/testify/assert"
)

View File

@@ -1,89 +0,0 @@
[
{
"id": 35385049,
"iid": 15442,
"project_id": 278964,
"title": "Draft: Use structured logging for DB load balancer",
"description": "",
"state": "opened",
"created_at": "2019-08-20T10:58:54.413Z",
"updated_at": "2019-08-20T12:01:49.849Z",
"merged_by": null,
"merged_at": null,
"closed_by": null,
"closed_at": null,
"target_branch": "master",
"source_branch": "use-structured-logging-for-db-load-balancer",
"user_notes_count": 1,
"upvotes": 0,
"downvotes": 0,
"assignee": {
"id": 4088036,
"name": "Hordur Freyr Yngvason",
"username": "hfyngvason",
"state": "active",
"avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4088036/avatar.png",
"web_url": "https://gitlab.com/hfyngvason"
},
"author": {
"id": 4088036,
"name": "Hordur Freyr Yngvason",
"username": "hfyngvason",
"state": "active",
"avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4088036/avatar.png",
"web_url": "https://gitlab.com/hfyngvason"
},
"assignees": [
{
"id": 4088036,
"name": "Hordur Freyr Yngvason",
"username": "hfyngvason",
"state": "active",
"avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4088036/avatar.png",
"web_url": "https://gitlab.com/hfyngvason"
}
],
"reviewers": [
{
"id": 2535118,
"name": "Thong Kuah",
"username": "tkuah",
"state": "active",
"avatar_url": "https://secure.gravatar.com/avatar/f7b51bdd49a4914d29504d7ff4c3f7b9?s=80&d=identicon",
"web_url": "https://gitlab.com/tkuah"
}
],
"source_project_id": 278964,
"target_project_id": 278964,
"labels": [
"backend",
"backstage",
"database",
"database::review pending",
"group::autodevops and kubernetes"
],
"work_in_progress": true,
"milestone": null,
"merge_when_pipeline_succeeds": false,
"merge_status": "can_be_merged",
"sha": "2fc4e8b972ff3208ec63b6143e34ad67ff343ad7",
"merge_commit_sha": null,
"discussion_locked": null,
"should_remove_source_branch": null,
"force_remove_source_branch": true,
"reference": "!15442",
"web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15442",
"time_stats": {
"time_estimate": 0,
"total_time_spent": 0,
"human_time_estimate": null,
"human_total_time_spent": null
},
"squash": true,
"task_completion_status": {
"count": 12,
"completed_count": 0
},
"approvals_before_merge": 1
}
]

View File

@@ -58,7 +58,7 @@ func (g *GithubService) List(ctx context.Context) ([]*PullRequest, error) {
for {
pulls, resp, err := g.client.PullRequests.List(ctx, g.owner, g.repo, opts)
if err != nil {
return nil, fmt.Errorf("error listing pull requests for %s/%s: %w", g.owner, g.repo, err)
return nil, fmt.Errorf("error listing pull requests for %s/%s: %v", g.owner, g.repo, err)
}
for _, pull := range pulls {
if !containLabels(g.labels, pull.Labels) {

View File

@@ -1,19 +0,0 @@
package pull_request
import (
"github.com/argoproj/argo-cd/v2/applicationset/services/github_app_auth"
"github.com/argoproj/argo-cd/v2/applicationset/services/internal/github_app"
)
func NewGithubAppService(g github_app_auth.Authentication, url, owner, repo string, labels []string) (PullRequestService, error) {
client, err := github_app.Client(g, url)
if err != nil {
return nil, err
}
return &GithubService{
client: client,
owner: owner,
repo: repo,
labels: labels,
}, nil
}

View File

@@ -1,83 +0,0 @@
package pull_request
import (
"context"
"fmt"
"os"
gitlab "github.com/xanzy/go-gitlab"
)
type GitLabService struct {
client *gitlab.Client
project string
labels []string
pullRequestState string
}
var _ PullRequestService = (*GitLabService)(nil)
func NewGitLabService(ctx context.Context, token, url, project string, labels []string, pullRequestState string) (PullRequestService, error) {
var clientOptionFns []gitlab.ClientOptionFunc
// Set a custom Gitlab base URL if one is provided
if url != "" {
clientOptionFns = append(clientOptionFns, gitlab.WithBaseURL(url))
}
if token == "" {
token = os.Getenv("GITLAB_TOKEN")
}
client, err := gitlab.NewClient(token, clientOptionFns...)
if err != nil {
return nil, fmt.Errorf("error creating Gitlab client: %v", err)
}
return &GitLabService{
client: client,
project: project,
labels: labels,
pullRequestState: pullRequestState,
}, nil
}
func (g *GitLabService) List(ctx context.Context) ([]*PullRequest, error) {
// Filter the merge requests on labels, if they are specified.
var labels *gitlab.Labels
if len(g.labels) > 0 {
labels = (*gitlab.Labels)(&g.labels)
}
opts := &gitlab.ListProjectMergeRequestsOptions{
ListOptions: gitlab.ListOptions{
PerPage: 100,
},
Labels: labels,
}
if g.pullRequestState != "" {
opts.State = &g.pullRequestState
}
pullRequests := []*PullRequest{}
for {
mrs, resp, err := g.client.MergeRequests.ListProjectMergeRequests(g.project, opts)
if err != nil {
return nil, fmt.Errorf("error listing merge requests for project '%s': %v", g.project, err)
}
for _, mr := range mrs {
pullRequests = append(pullRequests, &PullRequest{
Number: mr.IID,
Branch: mr.SourceBranch,
HeadSHA: mr.SHA,
})
}
if resp.NextPage == 0 {
break
}
opts.Page = resp.NextPage
}
return pullRequests, nil
}

View File

@@ -1,122 +0,0 @@
package pull_request
import (
"context"
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
func writeMRListResponse(t *testing.T, w io.Writer) {
f, err := os.Open("fixtures/gitlab_mr_list_response.json")
if err != nil {
t.Fatalf("error opening fixture file: %v", err)
}
if _, err = io.Copy(w, f); err != nil {
t.Fatalf("error writing response: %v", err)
}
}
func TestGitLabServiceCustomBaseURL(t *testing.T) {
mux := http.NewServeMux()
server := httptest.NewServer(mux)
defer server.Close()
path := "/api/v4/projects/278964/merge_requests"
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, path+"?per_page=100", r.URL.RequestURI())
writeMRListResponse(t, w)
})
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", nil, "")
assert.NoError(t, err)
_, err = svc.List(context.Background())
assert.NoError(t, err)
}
func TestGitLabServiceToken(t *testing.T) {
mux := http.NewServeMux()
server := httptest.NewServer(mux)
defer server.Close()
path := "/api/v4/projects/278964/merge_requests"
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "token-123", r.Header.Get("Private-Token"))
writeMRListResponse(t, w)
})
svc, err := NewGitLabService(context.Background(), "token-123", server.URL, "278964", nil, "")
assert.NoError(t, err)
_, err = svc.List(context.Background())
assert.NoError(t, err)
}
func TestList(t *testing.T) {
mux := http.NewServeMux()
server := httptest.NewServer(mux)
defer server.Close()
path := "/api/v4/projects/278964/merge_requests"
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, path+"?per_page=100", r.URL.RequestURI())
writeMRListResponse(t, w)
})
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{}, "")
assert.NoError(t, err)
prs, err := svc.List(context.Background())
assert.NoError(t, err)
assert.Len(t, prs, 1)
assert.Equal(t, prs[0].Number, 15442)
assert.Equal(t, prs[0].Branch, "use-structured-logging-for-db-load-balancer")
assert.Equal(t, prs[0].HeadSHA, "2fc4e8b972ff3208ec63b6143e34ad67ff343ad7")
}
func TestListWithLabels(t *testing.T) {
mux := http.NewServeMux()
server := httptest.NewServer(mux)
defer server.Close()
path := "/api/v4/projects/278964/merge_requests"
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, path+"?labels=feature%2Cready&per_page=100", r.URL.RequestURI())
writeMRListResponse(t, w)
})
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{"feature", "ready"}, "")
assert.NoError(t, err)
_, err = svc.List(context.Background())
assert.NoError(t, err)
}
func TestListWithState(t *testing.T) {
mux := http.NewServeMux()
server := httptest.NewServer(mux)
defer server.Close()
path := "/api/v4/projects/278964/merge_requests"
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, path+"?per_page=100&state=opened", r.URL.RequestURI())
writeMRListResponse(t, w)
})
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{}, "opened")
assert.NoError(t, err)
_, err = svc.List(context.Background())
assert.NoError(t, err)
}

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"regexp"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
)
func compileFilters(filters []argoprojiov1alpha1.PullRequestGeneratorFilter) ([]*Filter, error) {

View File

@@ -4,7 +4,7 @@ import (
"context"
"testing"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
"github.com/stretchr/testify/assert"
)

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