Compare commits

..

65 Commits

Author SHA1 Message Date
argo-bot
148d8da7a9 Bump version to 2.5.2 2022-11-07 16:29:42 +00:00
argo-bot
f13bb9e2e9 Bump version to 2.5.2 2022-11-07 16:29:35 +00:00
Chris Lewis
1e6a4c6128 docs: Add Contributor's Quickstart Page (#11108)
* First Draft

* Update docs/contributors_quickstart.md

Co-authored-by: ChanJong Na <cjna@umich.edu>
Signed-off-by: ctlewis <lewisengineer@gmail.com>

* Update docs/contributors_quickstart.md

Co-authored-by: Dan Garfield <dan@codefresh.io>
Signed-off-by: ctlewis <lewisengineer@gmail.com>

* Update docs/contributors_quickstart.md

Co-authored-by: Moshe Shitrit <moshe@s5t.dev>
Signed-off-by: ctlewis <lewisengineer@gmail.com>

* Update docs/contributors_quickstart.md

Co-authored-by: Jason Poley <jason.poley@gmail.com>
Signed-off-by: ctlewis <lewisengineer@gmail.com>

* Update docs/contributors_quickstart.md

Co-authored-by: Moshe Shitrit <moshe@s5t.dev>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

* Update docs/contributors_quickstart.md

Co-authored-by: Garima Negi <garima.negy@gmail.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

* tweaks

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

* undo temporary change

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

* Add sign off

Signed-off-by: Chris Lewis <clewis@powercosts.com>

* Update docs/developer-guide/contributors-quickstart.md

Co-authored-by: Angela Wilson <84730053+awilson-payit@users.noreply.github.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

* Update docs/developer-guide/contributors-quickstart.md

Co-authored-by: Andre Marcelo-Tanner <andre@enthropia.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

Signed-off-by: ctlewis <lewisengineer@gmail.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: Chris Lewis <clewis@powercosts.com>
Co-authored-by: Chris Lewis <clewis@powercosts.com>
Co-authored-by: ChanJong Na <cjna@umich.edu>
Co-authored-by: Dan Garfield <dan@codefresh.io>
Co-authored-by: Moshe Shitrit <moshe@s5t.dev>
Co-authored-by: Jason Poley <jason.poley@gmail.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Garima Negi <garima.negy@gmail.com>
Co-authored-by: Angela Wilson <84730053+awilson-payit@users.noreply.github.com>
Co-authored-by: Andre Marcelo-Tanner <andre@enthropia.com>
2022-11-04 20:22:09 -04:00
Michael Crenshaw
2873aa43f4 docs: debugging CMPs (#11142)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-11-04 10:46:33 -04:00
Michael Crenshaw
e7b4256474 docs: add Dockerfile example for plugin (#11130)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-11-04 09:04:34 -04:00
Michael Crenshaw
b0b8353e26 docs: document metadata access for go-templated cluster generator (#10929)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-11-04 09:03:59 -04:00
balajisa
2848ca2607 docs(user-guide): Add doc for import argocd packages (#11041) (#11096)
* Add doc for argocd pkg import

Signed-off-by: balajisa09 <balajisa09@gmail.com>

* Update docs/user-guide/import.md

Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: balajisa <50614674+balajisa09@users.noreply.github.com>

* Add detailed solution

Signed-off-by: balajisa09 <balajisa09@gmail.com>

* Update suggestions

Signed-off-by: balajisa09 <balajisa09@gmail.com>

* Update docs/user-guide/import.md

Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: balajisa <50614674+balajisa09@users.noreply.github.com>

* Update docs/user-guide/import.md

Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: balajisa <50614674+balajisa09@users.noreply.github.com>

* Update docs/user-guide/import.md

Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: balajisa <50614674+balajisa09@users.noreply.github.com>

* Update docs/user-guide/import.md

Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: balajisa <50614674+balajisa09@users.noreply.github.com>

* Update docs/user-guide/import.md

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

* fix code block

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

Signed-off-by: balajisa09 <balajisa09@gmail.com>
Signed-off-by: balajisa <50614674+balajisa09@users.noreply.github.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: balajisa09 <balajisa09@gmail.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-11-04 08:43:54 -04:00
Michael Crenshaw
9b7445cb18 fix: templating keys in ApplicationSet (#11076) (#11163)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-11-03 19:51:02 -04:00
Leonardo Luz Almeida
9b2cdc2ccf fix: handle apiGroup updates in resource-tracking (#11012)
* fix: handle apiGroup updates in resource-tracking

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

* Fix test

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

* change the fix approach by inspecting tracking id from the config

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

* add unit-test to validate the scenario

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

* fix test lint

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

* review fixes

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

* Reword godocs for clarity

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

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-11-03 15:02:33 -04:00
Justin Marquis
301b80b512 fix: upgrade redis-ha chart to 4.22.3, redis regression (#11176)
* chore: upgrade redis-ha chart to 4.22.3, redis regression

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

* fix manifest

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

* fix missing cidr

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

* fix typo

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

* fix typo

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

Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
2022-11-03 15:01:18 -04:00
argo-bot
504da424c2 Bump version to 2.5.1 2022-11-01 21:01:33 +00:00
argo-bot
24cc8578fd Bump version to 2.5.1 2022-11-01 21:01:24 +00:00
argo-bot
b895da4577 Bump version to 2.5.0 2022-10-25 14:23:02 +00:00
argo-bot
5a62dbd336 Bump version to 2.5.0 2022-10-25 14:22:54 +00:00
Michael Crenshaw
c7a0978271 chore: don't generate release notes
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-25 10:22:08 -04:00
Chromo-residuum-opec
872e1f2f5a docs: fix 'bellow' typos (#11038)
Signed-off-by: backfire-monism-net <development.0extl@simplelogin.com>

Signed-off-by: backfire-monism-net <development.0extl@simplelogin.com>
2022-10-22 20:11:53 -04:00
Michael Crenshaw
fe565dc2d9 chore: fix CI (#11022)
* chore: fix CI

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

* no more set global

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

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-21 11:21:13 -04:00
Michael Crenshaw
1b65c3f330 chore: fix e2e (#11005)
* chore: fix e2e

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

* more config

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

* global

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

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-21 11:20:32 -04:00
Alex Eftimie
fdd2e982c5 docs: mention that OCI helm does not support version ranges (#11026)
* docs: mention that OCI helm does not support version ranges

Signed-off-by: Alex Eftimie <alex.eftimie@getyourguide.com>

* Apply suggestions from code review

Signed-off-by: Alex Eftimie <alex.eftimie@getyourguide.com>

Signed-off-by: Alex Eftimie <alex.eftimie@getyourguide.com>
2022-10-21 11:18:35 -04:00
Allex
49235d5525 fix: Update custom health check for kiali.io/Kiali (#10995)
With Kiali v1.57.1 an additional status condition was added:
```
    - lastTransitionTime: '2022-10-14T11:56:24Z'
      message: ''
      reason: ''
      status: 'False'
      type: Failure
```

Based on the discussion in https://github.com/kiali/kiali/issues/5560 this should not lead to a degraded health state.

This will no longer return Degraded as a catch-all and use the `type` and `status` fields of the condition to determine the CR health.

Signed-off-by: Allex Veldman <allexveldman+github@gmail.com>

Signed-off-by: Allex Veldman <allexveldman+github@gmail.com>
2022-10-19 12:17:24 -04:00
Michael Crenshaw
0cf224c958 chore: upgrade actions/checkout to v3, i.e. Node.js 16 (#10947)
* chore: updgrade actions/checkout to v3, i.e. Node.js 16

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

* more node 12

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

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-19 10:32:33 -04:00
34FathomBelow
664224fe14 chore: release signature of sbom (#10969)
Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>

Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
2022-10-18 15:39:41 -04:00
Jessie Teng
351cab4c2a fix: Resource list in sync page msg style#10887 (#10970)
* fix: Resource list in sync page msg style#10887

Signed-off-by: Teng, Jessie <yilin.teng@fmr.com>

* fix: Resource list in sync page msg style#10887

Signed-off-by: Teng, Jessie <yilin.teng@fmr.com>

* fix: Resource list in sync page msg style#10887

Signed-off-by: Teng, Jessie <yilin.teng@fmr.com>

* fix: Resource list in sync page msg style#10887

Signed-off-by: Teng, Jessie <yilin.teng@fmr.com>

Signed-off-by: Teng, Jessie <yilin.teng@fmr.com>
2022-10-18 14:01:44 -04:00
argo-bot
c615c8a56d Bump version to 2.5.0-rc3 2022-10-17 17:34:56 +00:00
argo-bot
048275cb93 Bump version to 2.5.0-rc3 2022-10-17 17:34:48 +00:00
34FathomBelow
df8f70aac8 chore: sign checksums file for release binaries (#10963)
Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>

Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
2022-10-17 13:03:50 -04:00
Michael Crenshaw
40ce041aa7 fix: upgrade Helm to avoid disk use issue (#8773) (#10937)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-17 12:44:36 -04:00
34FathomBelow
68df7d8dda chore: implement signed images (#10925)
* consolidate checksums into one file

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

* sign container images

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

* sign container images

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

* remove id-token permissions

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

Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
2022-10-17 12:37:44 -04:00
Michael Crenshaw
d9004fc748 chore: upgrade dex to v2.35.3 to avoid CVE-2022-27665 (#10939)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-17 12:30:27 -04:00
34FathomBelow
84680ba0ff docs: release signature verification (#10967)
* chore: release signature documentation

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

* fixed typos

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

* fixed requested changes

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

Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
2022-10-17 11:49:00 -04:00
Aiman Fatima
9f5111d474 fix: Display pointer on labels for resource names in sync panel (#10959)
Signed-off-by: Aiman Fatima <aimanfatimadl@gmail.com>

Signed-off-by: Aiman Fatima <aimanfatimadl@gmail.com>
2022-10-17 09:30:24 -04:00
Chris Davis
cd3ce58df4 fix: Use os.PathSeparator instead of hard-coded string to resolve local file paths (#10945) (#10946)
fix: Use os.PathSeparator instead of hard-coded string to resolve local file paths (#10945) (#10946)
2022-10-14 13:53:54 -07:00
Mayursinh Sarvaiya
39f9565e34 feat(ui): notification subscriptions edit field #10310 (#10839)
* feat(ui): notification subscriptions edit field

> this new field is just an abstraction of relevant annotations

Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com>

* fix: codeql regex issue

Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com>

Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com>
2022-10-14 13:07:33 -07:00
Alexander Matyushentsev
2d9f13d0bb fix: Resource list loading slowly due to Sync Wave sorting (#10932)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-10-13 17:49:15 -07:00
Michael Crenshaw
b735c00761 docs: appset PR generator docs fixes (#10567)
* docs: appset PR generator docs fixes

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

* oh, that field is actually a thing

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

Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-12 11:30:41 -04:00
Michael Crenshaw
aae9a24cbd docs: add link to 2.4-2.5 upgrade guide (#10808)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-12 11:29:41 -04:00
Michael Crenshaw
dde489db1c docs: more docs for directory apps (#10879)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-12 11:19:28 -04:00
Michael Crenshaw
d0b20b06dc docs: clarify how default RBAC policy works (#10896)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-12 11:17:00 -04:00
karengineering
2ccb96086f fix: add applicationsets to RBAC policy (#10810) (#10891)
Signed-off-by: Karengineering <49111213+karengineering@users.noreply.github.com>

Signed-off-by: Karengineering <49111213+karengineering@users.noreply.github.com>
2022-10-11 17:01:13 -04:00
argo-bot
ba4c562508 Bump version to 2.5.0-rc2 2022-10-11 19:01:45 +00:00
argo-bot
701b3403c5 Bump version to 2.5.0-rc2 2022-10-11 19:01:38 +00:00
Michael Crenshaw
f927aaeddd chore: add script to generate release notes (#10806)
* chore: add script to generate release notes

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

* newlines look bad in the release markdown rendering on GitHub

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

* use diff instead of comp

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

* use auto-generated docs

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

* pre-pended, not appended

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

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-11 14:54:49 -04:00
Mayursinh Sarvaiya
e0ffec8a63 fix(ui): sync option label doesn't check corresponding box (#10863) (#10876)
* fix(ui): sync option label doesn't check corresponding box

Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com>

* fix: lint

Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com>

Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com>
2022-10-10 14:52:29 -04:00
Nir Shtein
a04d634fba fix: clicking HEAD in bitbucket leads to a 404 page (#10862)
* Wrap error objects to include context

Signed-off-by: Nir Shtein <89006520+nirsht@users.noreply.github.com>

* fix: duplicate source namespace validation (#10853)

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

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

* Fix CR

Signed-off-by: Nir Shtein <89006520+nirsht@users.noreply.github.com>

* Change 'branch' to 'src' when building url path

Signed-off-by: Nir Shtein <89006520+nirsht@users.noreply.github.com>

* Revert "Fix CR"

This reverts commit 4b92408412.

Signed-off-by: Nir Shtein <89006520+nirsht@users.noreply.github.com>

* Revert "Wrap error objects to include context"

This reverts commit d1789bd271.

Signed-off-by: Nir Shtein <89006520+nirsht@users.noreply.github.com>

Signed-off-by: Nir Shtein <89006520+nirsht@users.noreply.github.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-09 12:11:03 -04:00
Sakshi Jain
0b076c13a0 fix: added css to change cursor to pointer on hover (#10864) (#10867)
* added css to change cursor to pointer on hover

Signed-off-by: Sakshi <sakshi.jain7597@gmail.com>

* moved cursor change to only label and input

Signed-off-by: Sakshi <sakshi.jain7597@gmail.com>

Signed-off-by: Sakshi <sakshi.jain7597@gmail.com>
2022-10-09 12:05:23 -04:00
Michael Crenshaw
d33981ffa2 docs: more versioned docs fixes (#10342)
* docs: remove more version notes - rely on docs versioning

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

* missed some things

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

Signed-off-by: CI <michael@crenshaw.dev>
2022-10-08 15:09:07 -04:00
toyamagu
2b62aa7d92 docs: fix examples for ArgoCD ApplicationSet Git Generator (#10857)
* Doc: ArgoCD ApplicationSet Git directory

Signed-off-by: toyamagu <toyamagu2021@gmail.com>

* Docs: use "my-project" rather than default project

Signed-off-by: toyamagu <toyamagu2021@gmail.com>

Signed-off-by: toyamagu <toyamagu2021@gmail.com>
2022-10-08 14:44:55 -04:00
Michael Crenshaw
dfbcf757b9 fix: duplicate source namespace validation (#10853)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-08 14:31:47 -04:00
Michael Crenshaw
d5feafc654 docs: remove unused plugin config fields (#10304)
* docs: remove unused plugin config fields

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

* fix codegen

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

Signed-off-by: CI <michael@crenshaw.dev>
2022-10-07 19:44:15 -04:00
Tsubasa Nagasawa
f47a5f90c2 fix: applicationset controller should respect logging flags (#10513)
* Align logging setup with other controllers

Signed-off-by: toVersus <toversus2357@gmail.com>

Signed-off-by: toVersus <toversus2357@gmail.com>
2022-10-07 17:34:35 -04:00
Thijs van Tol
faa01bb6f9 fix: show revision in badge when param is true (#10545)
* fix: show revision in badge when param is true

Signed-off-by: Thijs van Tol <43065692+thijsvtol@users.noreply.github.com>

* Update badge.go

Signed-off-by: Thijs van Tol <43065692+thijsvtol@users.noreply.github.com>

* Update badge.go

Signed-off-by: Thijs van Tol <43065692+thijsvtol@users.noreply.github.com>

* pr feedback

Signed-off-by: Thijs van Tol <43065692+thijsvtol@users.noreply.github.com>

Signed-off-by: Thijs van Tol <43065692+thijsvtol@users.noreply.github.com>
2022-10-07 17:13:38 -04:00
Matt Morrison
1e1a744604 fix: consider destination cluster name when validating destinations (#10594)
Signed-off-by: Matt Morrison <matt.morrison@zapier.com>

Signed-off-by: Matt Morrison <matt.morrison@zapier.com>
2022-10-07 16:37:37 -04:00
Minchao
aca9ed2030 docs: fix advice about preferred version in high availability (#10619)
* docs: fix advice about preferred version in high availability

Signed-off-by: Minchao <minchao.220@gmail.com>

* Update docs/operator-manual/high_availability.md

Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: Minchao <minchao.220@gmail.com>

Signed-off-by: Minchao <minchao.220@gmail.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2022-10-07 16:11:33 -04:00
Lars Kellogg-Stedman
b83554fca8 docs: Correct grammar issues in docs on manifest path annotations (#10776)
The "Webhook and Manifest Paths Annotation" section of the documentation
contained a number of grammar and spelling issues as well as what appeared
to be some unintentionally pasted text.

This commit attempts to address these issues.

Signed-off-by: Lars Kellogg-Stedman <lars@oddbit.com>

Signed-off-by: Lars Kellogg-Stedman <lars@oddbit.com>
2022-10-07 15:33:50 -04:00
Denis Krivenko
3275337a26 fix: Add missing statuses to MinIO Tenant health check (#10815)
Signed-off-by: dnskr <dnskrv88@gmail.com>

Signed-off-by: dnskr <dnskrv88@gmail.com>
2022-10-07 15:03:59 -04:00
Eddie Knight
89b6fe01a6 chore: Added recommended permissions to github actions workflows (#10812)
* Added recommended permissions to 4 of 5 workflows

Signed-off-by: Eddie Knight <iv.eddieknight@gmail.com>

* Added release.yaml permissions... might need to add pagages:write

Signed-off-by: Eddie Knight <iv.eddieknight@gmail.com>

* Updated inline comments

Signed-off-by: Eddie Knight <iv.eddieknight@gmail.com>

Signed-off-by: Eddie Knight <iv.eddieknight@gmail.com>
2022-10-07 14:41:59 -04:00
jannfis
1fe1a0060b fix: Unbreak app refresh from panel list (#10825)
Signed-off-by: jannfis <jann@mistrust.net>

Signed-off-by: jannfis <jann@mistrust.net>
2022-10-07 11:53:07 -04:00
Richard Jennings
de72cb1686 fix: add applicationset to crds generated by gen-crd-spec (#10833)
* add applicationset to crds generated

Signed-off-by: Richard Jennings <richardjennings@gmail.com>

* update applicationset crd

Signed-off-by: Richard Jennings <richardjennings@gmail.com>

* remove description from applicationset crd

Signed-off-by: Richard Jennings <richardjennings@gmail.com>

Signed-off-by: Richard Jennings <richardjennings@gmail.com>
2022-10-07 10:52:38 -04:00
Leonardo Luz Almeida
2e24cdc7ea docs: Add example about how to patch with SSA syncs (#10829)
* docs: Add example about how to patch with SSA syncs

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

* docs: minor fixes

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

Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2022-10-06 15:43:49 -04:00
jannfis
ebf367497b fix(ui): Don't jump back to tiles view on app deletion (#8764) (#10826)
Signed-off-by: jannfis <jann@mistrust.net>

Signed-off-by: jannfis <jann@mistrust.net>
2022-10-06 14:07:18 -04:00
rumstead
277c6adaf1 docs: Update link to resource customizations (#10827) (#10828)
Signed-off-by: rumstead <37445536+rumstead@users.noreply.github.com>

Signed-off-by: rumstead <37445536+rumstead@users.noreply.github.com>
2022-10-06 12:04:21 -04:00
Abhishek Veeramalla
20ce840a2d chore: update Server-Side Apply docs for patching of existing rresources (#10822)
Signed-off-by: iam-veeramalla <abhishek.veeramalla@gmail.com>

Signed-off-by: iam-veeramalla <abhishek.veeramalla@gmail.com>
2022-10-06 11:17:28 -04:00
Remington Breeze
20776419d8 fix: Add filter icon to help users find filters (#10809)
* fix: add clear indicator that filters are now in sidebar

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

* address code review

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

Signed-off-by: Remington Breeze <remington@breeze.software>
2022-10-05 16:52:17 -07:00
argo-bot
2bf51f401d Bump version to 2.5.0-rc1 2022-10-05 16:59:55 +00:00
argo-bot
6a4468ce6b Bump version to 2.5.0-rc1 2022-10-05 16:59:47 +00:00
593 changed files with 20551 additions and 98426 deletions

View File

@@ -1,32 +0,0 @@
---
name: Argo CD Release
about: Used by our Release Champion to track progress of a minor release
title: 'Argo CD Release vX.X'
labels: 'release'
assignees: ''
---
Target RC1 date: ___. __, ____
Target GA date: ___. __, ____
- [ ] Create new section in the [Release Planning doc](https://docs.google.com/document/d/1trJIomcgXcfvLw0aYnERrFWfPjQOfYMDJOCh1S8nMBc/edit?usp=sharing)
- [ ] Schedule a Release Planning meeting roughly two weeks before the scheduled Release freeze date by adding it to the community calendar (or delegate this task to someone with write access to the community calendar)
- [ ] Include Zoom link in the invite
- [ ] Post in #argo-cd and #argo-contributors one week before the meeting
- [ ] Post again one hour before the meeting
- [ ] At the meeting, remove issues/PRs from the project's column for that release which have not been “claimed” by at least one Approver (add it to the next column if Approver requests that)
- [ ] 1wk before feature freeze post in #argo-contributors that PRs must be merged by DD-MM-YYYY to be included in the release - ask approvers to drop items from milestone they cant merge
- [ ] At least two days before RC1 date, draft RC blog post and submit it for review (or delegate this task)
- [ ] Cut RC1 (or delegate this task to an Approver and coordinate timing)
- [ ] Create new release branch
- [ ] Add the release branch to ReadTheDocs
- [ ] Confirm that tweet and blog post are ready
- [ ] Trigger the release
- [ ] After the release is finished, publish tweet and blog post
- [ ] Post in #argo-cd and #argo-announcements with lots of emojis announcing the release and requesting help testing
- [ ] Monitor support channels for issues, cherry-picking bugfixes and docs fixes as appropriate (or delegate this task to an Approver and coordinate timing)
- [ ] At release date, evaluate if any bugs justify delaying the release. If not, cut the release (or delegate this task to an Approver and coordinate timing)
- [ ] If unreleased changes are on the release branch for {current minor version minus 3}, cut a final patch release for that series (or delegate this task to an Approver and coordinate timing)
- [ ] After the release, post in #argo-cd that the {current minor version minus 3} has reached EOL (example: https://cloud-native.slack.com/archives/C01TSERG0KZ/p1667336234059729)
- [ ] (For the next release champion) Review the [items scheduled for the next release](https://github.com/orgs/argoproj/projects/25). If any item does not have an assignee who can commit to finish the feature, move it to the next release.
- [ ] (For the next release champion) Schedule a time mid-way through the release cycle to review items again.

View File

@@ -1,18 +0,0 @@
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
ignore:
- dependency-name: k8s.io/*
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "npm"
directory: "/ui/"
schedule:
interval: "daily"

View File

@@ -27,9 +27,9 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@v3
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@v3
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Download all Go modules
@@ -45,13 +45,13 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@v3
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@v3
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Restore go build cache
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
uses: actions/cache@v1
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -69,13 +69,13 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@v3
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@v3
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Run golangci-lint
uses: golangci/golangci-lint-action@0ad9a0988b3973e851ab0a07adf248ec2e100376 # v3.3.1
uses: golangci/golangci-lint-action@v3
with:
version: v1.46.2
args: --timeout 10m --exclude SA5011 --verbose
@@ -92,11 +92,11 @@ jobs:
- name: Create checkout directory
run: mkdir -p ~/go/src/github.com/argoproj
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@v3
- name: Create symlink in GOPATH
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@v3
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Install required packages
@@ -116,7 +116,7 @@ jobs:
run: |
echo "/usr/local/bin" >> $GITHUB_PATH
- name: Restore go build cache
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
uses: actions/cache@v1
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -133,12 +133,12 @@ jobs:
- name: Run all unit tests
run: make test-local
- name: Generate code coverage artifacts
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
uses: actions/upload-artifact@v2
with:
name: code-coverage
path: coverage.out
- name: Generate test results artifacts
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
uses: actions/upload-artifact@v2
with:
name: test-results
path: test-results/
@@ -155,11 +155,11 @@ jobs:
- name: Create checkout directory
run: mkdir -p ~/go/src/github.com/argoproj
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@v3
- name: Create symlink in GOPATH
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@v3
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Install required packages
@@ -179,7 +179,7 @@ jobs:
run: |
echo "/usr/local/bin" >> $GITHUB_PATH
- name: Restore go build cache
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
uses: actions/cache@v1
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -196,7 +196,7 @@ jobs:
- name: Run all unit tests
run: make test-race-local
- name: Generate test results artifacts
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
uses: actions/upload-artifact@v2
with:
name: race-results
path: test-results/
@@ -206,9 +206,9 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@v3
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@v3
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Create symlink in GOPATH
@@ -250,14 +250,14 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@v3
- name: Setup NodeJS
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
uses: actions/setup-node@v1
with:
node-version: '12.18.4'
- name: Restore node dependency cache
id: cache-dependencies
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
uses: actions/cache@v1
with:
path: ui/node_modules
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
@@ -287,12 +287,12 @@ jobs:
sonar_secret: ${{ secrets.SONAR_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Restore node dependency cache
id: cache-dependencies
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
uses: actions/cache@v1
with:
path: ui/node_modules
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
@@ -303,16 +303,16 @@ jobs:
run: |
mkdir -p test-results
- name: Get code coverage artifiact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@v2
with:
name: code-coverage
- name: Get test result artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
uses: actions/download-artifact@v2
with:
name: test-results
path: test-results
- name: Upload code coverage information to codecov.io
uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1
uses: codecov/codecov-action@v1
with:
file: coverage.out
- name: Perform static code analysis using SonarCloud
@@ -348,7 +348,7 @@ jobs:
runs-on: ubuntu-22.04
strategy:
matrix:
k3s-version: [v1.26.0, v1.25.4, v1.24.3, v1.23.3]
k3s-version: [v1.24.3, v1.23.3, v1.22.6]
needs:
- build-go
env:
@@ -366,9 +366,9 @@ jobs:
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@v3
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@v3
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: GH actions workaround - Kill XSP4 process
@@ -386,7 +386,7 @@ jobs:
sudo chown runner $HOME/.kube/config
kubectl version
- name: Restore go build cache
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
uses: actions/cache@v1
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -412,9 +412,9 @@ jobs:
git config --global user.email "john.doe@example.com"
- name: Pull Docker image required for tests
run: |
docker pull ghcr.io/dexidp/dex:v2.35.3
docker pull ghcr.io/dexidp/dex:v2.35.3-distroless
docker pull argoproj/argo-cd-ci-builder:v1.0.0
docker pull redis:7.0.7-alpine
docker pull redis:7.0.5-alpine
- name: Create target directory for binaries in the build-process
run: |
mkdir -p dist
@@ -442,7 +442,7 @@ jobs:
set -x
make test-e2e-local
- name: Upload e2e-server logs
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
uses: actions/upload-artifact@v2
with:
name: e2e-server-k8s${{ matrix.k3s-version }}.log
path: /tmp/e2e-server.log

View File

@@ -29,11 +29,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@8aff97f12c99086bdb92ff62ae06dbbcdf07941b # v2.1.33
uses: github/codeql-action/init@v2
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
@@ -41,7 +41,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@8aff97f12c99086bdb92ff62ae06dbbcdf07941b # v2.1.33
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -55,4 +55,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@8aff97f12c99086bdb92ff62ae06dbbcdf07941b # v2.1.33
uses: github/codeql-action/analyze@v2

View File

@@ -23,38 +23,37 @@ jobs:
publish:
permissions:
contents: write # for git to push upgrade commit if not already deployed
packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags
if: github.repository == 'argoproj/argo-cd'
runs-on: ubuntu-22.04
env:
GOPATH: /home/runner/work/argo-cd/argo-cd
steps:
- uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
- uses: actions/setup-go@v3
with:
go-version: ${{ env.GOLANG_VERSION }}
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
- uses: actions/checkout@master
with:
path: src/github.com/argoproj/argo-cd
# get image tag
- run: echo "tag=$(cat ./VERSION)-${GITHUB_SHA::8}" >> $GITHUB_OUTPUT
- run: echo ::set-output name=tag::$(cat ./VERSION)-${GITHUB_SHA::8}
working-directory: ./src/github.com/argoproj/argo-cd
id: image
# login
- run: |
docker login ghcr.io --username $USERNAME --password-stdin <<< "$PASSWORD"
docker login quay.io --username "$DOCKER_USERNAME" --password-stdin <<< "$DOCKER_TOKEN"
docker login ghcr.io --username $USERNAME --password $PASSWORD
docker login quay.io --username "${DOCKER_USERNAME}" --password "${DOCKER_TOKEN}"
if: github.event_name == 'push'
env:
USERNAME: ${{ github.actor }}
PASSWORD: ${{ secrets.GITHUB_TOKEN }}
USERNAME: ${{ secrets.USERNAME }}
PASSWORD: ${{ secrets.TOKEN }}
DOCKER_USERNAME: ${{ secrets.RELEASE_QUAY_USERNAME }}
DOCKER_TOKEN: ${{ secrets.RELEASE_QUAY_TOKEN }}
# build
- uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0
- uses: docker/setup-buildx-action@15c905b16b06416d2086efa066dd8e3a35cc7f98 # v2.4.0
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- run: |
IMAGE_PLATFORMS=linux/amd64
if [[ "${{ github.event_name }}" == "push" || "${{ contains(github.event.pull_request.labels.*.name, 'test-arm-image') }}" == "true" ]]
@@ -62,27 +61,20 @@ jobs:
IMAGE_PLATFORMS=linux/amd64,linux/arm64,linux/s390x,linux/ppc64le
fi
echo "Building image for platforms: $IMAGE_PLATFORMS"
docker buildx build --platform $IMAGE_PLATFORMS --sbom=false --provenance=false --push="${{ github.event_name == 'push' }}" \
-t ghcr.io/argoproj/argo-cd/argocd:${{ steps.image.outputs.tag }} \
docker buildx build --platform $IMAGE_PLATFORMS --push="${{ github.event_name == 'push' }}" \
-t ghcr.io/argoproj/argocd:${{ steps.image.outputs.tag }} \
-t quay.io/argoproj/argocd:latest .
working-directory: ./src/github.com/argoproj/argo-cd
# sign container images
- name: Install cosign
uses: sigstore/cosign-installer@9becc617647dfa20ae7b1151972e9b3a2c338a2b # v2.8.1
uses: sigstore/cosign-installer@main
with:
cosign-release: 'v1.13.1'
- name: Install crane to get digest of image
uses: imjasonh/setup-crane@e82f1b9a8007d399333baba4d75915558e9fb6a4
- name: Get digest of image
run: |
echo "IMAGE_DIGEST=$(crane digest quay.io/argoproj/argocd:latest)" >> $GITHUB_ENV
cosign-release: 'v1.13.0'
- name: Sign Argo CD latest image
run: |
cosign sign --key env://COSIGN_PRIVATE_KEY quay.io/argoproj/argocd@${{ env.IMAGE_DIGEST }}
cosign sign --key env://COSIGN_PRIVATE_KEY quay.io/argoproj/argocd:latest
# Displays the public key to share.
cosign public-key --key env://COSIGN_PRIVATE_KEY
env:
@@ -96,7 +88,7 @@ jobs:
env:
TOKEN: ${{ secrets.TOKEN }}
- run: |
docker run -u $(id -u):$(id -g) -v $(pwd):/src -w /src --rm -t ghcr.io/argoproj/argo-cd/argocd:${{ steps.image.outputs.tag }} kustomize edit set image quay.io/argoproj/argocd=ghcr.io/argoproj/argo-cd/argocd:${{ steps.image.outputs.tag }}
docker run -u $(id -u):$(id -g) -v $(pwd):/src -w /src --rm -t ghcr.io/argoproj/argocd:${{ steps.image.outputs.tag }} kustomize edit set image quay.io/argoproj/argocd=ghcr.io/argoproj/argocd:${{ steps.image.outputs.tag }}
git config --global user.email 'ci@argoproj.com'
git config --global user.name 'CI'
git diff --exit-code && echo 'Already deployed' || (git commit -am 'Upgrade argocd to ${{ steps.image.outputs.tag }}' && git push)

View File

@@ -1,41 +0,0 @@
name: "Lint PR"
on:
pull_request_target:
types:
- opened
- edited
- synchronize
# IMPORTANT: No checkout actions, scripts, or builds should be added to this workflow. Permissions should always be used
# with extreme caution.
permissions:
contents: read
# PR updates can happen in quick succession leading to this
# workflow being trigger a number of times. This limits it
# to one run per PR.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
main:
permissions:
pull-requests: read # for amannn/action-semantic-pull-request to analyze PRs
statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR
name: Validate PR title
runs-on: ubuntu-latest
steps:
# IMPORTANT: Carefully review changes when updating this action. Using the pull_request_target event requires caution.
- uses: amannn/action-semantic-pull-request@01d5fd8a8ebb9aafe902c40c53f0f4744f7381eb # v5.0.2
with:
types: |
feat
fix
docs
test
ci
chore
[Bot] docs
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -12,7 +12,7 @@ on:
- "!release-v0*"
env:
GOLANG_VERSION: '1.18'
GOLANG_VERSION: '1.18'
permissions:
contents: read
@@ -43,7 +43,7 @@ jobs:
GIT_EMAIL: argoproj@gmail.com
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@v3
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
@@ -147,7 +147,7 @@ jobs:
echo "RELEASE_NOTES=${RELEASE_NOTES}" >> $GITHUB_ENV
- name: Setup Golang
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@v3
with:
go-version: ${{ env.GOLANG_VERSION }}
@@ -195,19 +195,19 @@ jobs:
QUAY_TOKEN: ${{ secrets.RELEASE_QUAY_TOKEN }}
run: |
set -ue
docker login quay.io --username "${QUAY_USERNAME}" --password-stdin <<< "${QUAY_TOKEN}"
docker login quay.io --username "${QUAY_USERNAME}" --password "${QUAY_TOKEN}"
# Remove the following when Docker Hub is gone
docker login --username "${DOCKER_USERNAME}" --password-stdin <<< "${DOCKER_TOKEN}"
docker login --username "${DOCKER_USERNAME}" --password "${DOCKER_TOKEN}"
if: ${{ env.DRY_RUN != 'true' }}
- uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0
- uses: docker/setup-buildx-action@15c905b16b06416d2086efa066dd8e3a35cc7f98 # v2.4.0
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- name: Build and push Docker image for release
run: |
set -ue
git clean -fd
mkdir -p dist/
docker buildx build --platform linux/amd64,linux/arm64,linux/s390x,linux/ppc64le --sbom=false --provenance=false --push -t ${IMAGE_NAMESPACE}/argocd:v${TARGET_VERSION} -t argoproj/argocd:v${TARGET_VERSION} .
docker buildx build --platform linux/amd64,linux/arm64,linux/s390x,linux/ppc64le --push -t ${IMAGE_NAMESPACE}/argocd:v${TARGET_VERSION} -t argoproj/argocd:v${TARGET_VERSION} .
make release-cli
make checksums
chmod +x ./dist/argocd-linux-amd64
@@ -215,20 +215,13 @@ jobs:
if: ${{ env.DRY_RUN != 'true' }}
- name: Install cosign
uses: sigstore/cosign-installer@9becc617647dfa20ae7b1151972e9b3a2c338a2b # v2.8.1
uses: sigstore/cosign-installer@main
with:
cosign-release: 'v1.13.1'
- name: Install crane to get digest of image
uses: imjasonh/setup-crane@e82f1b9a8007d399333baba4d75915558e9fb6a4
- name: Get digest of image
run: |
echo "IMAGE_DIGEST=$(crane digest quay.io/argoproj/argocd:v${TARGET_VERSION})" >> $GITHUB_ENV
cosign-release: 'v1.13.0'
- name: Sign Argo CD container images and assets
run: |
cosign sign --key env://COSIGN_PRIVATE_KEY ${IMAGE_NAMESPACE}/argocd@${{ env.IMAGE_DIGEST }}
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
@@ -239,7 +232,7 @@ jobs:
- name: Read release notes file
id: release-notes
uses: juliangruber/read-file-action@02bbba9876a8f870efd4ad64e3b9088d3fb94d4b # v1.1.6
uses: juliangruber/read-file-action@v1
with:
path: ${{ env.RELEASE_NOTES }}
@@ -250,7 +243,7 @@ jobs:
git push origin ${RELEASE_TAG}
- name: Dry run GitHub release
uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e # v1.1.4
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
id: create_release
@@ -271,7 +264,7 @@ jobs:
SIGS_BOM_VERSION: v0.2.1
# comma delimited list of project relative folders to inspect for package
# managers (gomod, yarn, npm).
PROJECT_FOLDERS: ".,./ui"
PROJECT_FOLDERS: ".,./ui"
# full qualified name of the docker image to be inspected
DOCKER_IMAGE: ${{env.IMAGE_NAMESPACE}}/argocd:v${{env.TARGET_VERSION}}
run: |
@@ -302,7 +295,7 @@ jobs:
if: ${{ env.DRY_RUN != 'true' }}
- name: Create GitHub release
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -320,7 +313,7 @@ jobs:
- name: Update homebrew formula
env:
HOMEBREW_TOKEN: ${{ secrets.RELEASE_HOMEBREW_TOKEN }}
uses: dawidd6/action-homebrew-bump-formula@02e79d9da43d79efa846d73695b6052cbbdbf48a # v3.8.3
uses: dawidd6/action-homebrew-bump-formula@v3
with:
token: ${{env.HOMEBREW_TOKEN}}
formula: argocd

View File

@@ -1,6 +1,5 @@
name: Snyk report update
on:
workflow_dispatch: {}
schedule:
- cron: '0 0 * * 0' # midnight every Sunday
@@ -10,27 +9,23 @@ permissions:
jobs:
snyk-report:
permissions:
contents: write
pull-requests: write
contents: write # To push snyk reports
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@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
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] docs: 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 ''
git add docs/snyk/index.md
git add docs/snyk/*/*.html
git commit -m "[Bot] Update Snyk reports"
git push

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

View File

@@ -36,8 +36,6 @@ RUN ./install.sh helm-linux && \
####################################################################################################
FROM $BASE_IMAGE AS argocd-base
LABEL org.opencontainers.image.source="https://github.com/argoproj/argo-cd"
USER root
ENV ARGOCD_USER_ID=999

View File

@@ -64,20 +64,13 @@ else
DOCKER_SRC_MOUNT="$(PWD):/go/src/github.com/argoproj/argo-cd$(VOLUME_MOUNT)"
endif
# User and group IDs to map to the test container
CONTAINER_UID=$(shell id -u)
CONTAINER_GID=$(shell id -g)
# Set SUDO to sudo to run privileged commands with sudo
SUDO?=
# Runs any command in the argocd-test-utils container in server mode
# Server mode container will start with uid 0 and drop privileges during runtime
define run-in-test-server
$(SUDO) docker run --rm -it \
docker run --rm -it \
--name argocd-test-server \
-u $(CONTAINER_UID):$(CONTAINER_GID) \
-e USER_ID=$(CONTAINER_UID) \
-u $(shell id -u):$(shell id -g) \
-e USER_ID=$(shell id -u) \
-e HOME=/home/user \
-e GOPATH=/go \
-e GOCACHE=/tmp/go-build-cache \
@@ -105,9 +98,9 @@ endef
# Runs any command in the argocd-test-utils container in client mode
define run-in-test-client
$(SUDO) docker run --rm -it \
docker run --rm -it \
--name argocd-test-client \
-u $(CONTAINER_UID):$(CONTAINER_GID) \
-u $(shell id -u):$(shell id -g) \
-e HOME=/home/user \
-e GOPATH=/go \
-e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) \
@@ -126,7 +119,7 @@ endef
#
define exec-in-test-server
$(SUDO) docker exec -it -u $(CONTAINER_UID):$(CONTAINER_GID) -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_RECORD=$(ARGOCD_E2E_RECORD) -e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) argocd-test-server $(1)
endef
PATH:=$(PATH):$(PWD)/hack
@@ -251,8 +244,8 @@ release-cli: clean-debug build-ui
.PHONY: test-tools-image
test-tools-image:
ifndef SKIP_TEST_TOOLS_IMAGE
$(SUDO) docker build --build-arg UID=$(CONTAINER_UID) -t $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE) -f test/container/Dockerfile .
$(SUDO) docker tag $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE) $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE):$(TEST_TOOLS_TAG)
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
@@ -333,7 +326,7 @@ mod-vendor: test-tools-image
mod-vendor-local: mod-download-local
go mod vendor
# Deprecated - replace by install-tools-local
# Deprecated - replace by install-local-tools
.PHONY: install-lint-tools
install-lint-tools:
./hack/install.sh lint-tools
@@ -519,7 +512,7 @@ build-docs-local:
.PHONY: build-docs
build-docs:
docker run ${MKDOCS_RUN_ARGS} --rm -it -v ${CURRENT_DIR}:/docs --entrypoint "" ${MKDOCS_DOCKER_IMAGE} sh -c 'pip install -r docs/requirements.txt; mkdocs build'
docker run ${MKDOCS_RUN_ARGS} --rm -it -p 8000:8000 -v ${CURRENT_DIR}:/docs ${MKDOCS_DOCKER_IMAGE} build
.PHONY: serve-docs-local
serve-docs-local:
@@ -527,7 +520,7 @@ serve-docs-local:
.PHONY: serve-docs
serve-docs:
docker run ${MKDOCS_RUN_ARGS} --rm -it -p 8000:8000 -v ${CURRENT_DIR}/site:/site -w /site --entrypoint "" ${MKDOCS_DOCKER_IMAGE} python3 -m http.server --bind 0.0.0.0 8000
docker run ${MKDOCS_RUN_ARGS} --rm -it -p 8000:8000 -v ${CURRENT_DIR}:/docs ${MKDOCS_DOCKER_IMAGE} serve -a 0.0.0.0:8000
# Verify that kubectl can connect to your K8s cluster from Docker

2
OWNERS
View File

@@ -27,5 +27,3 @@ reviewers:
- wanghong230
- ciiay
- saumeya
- zachaller
- 34fathombelow

View File

@@ -1,16 +1,4 @@
**Releases:**
[![Release Version](https://img.shields.io/github/v/release/argoproj/argo-cd?label=argo-cd)](https://github.com/argoproj/argo-cd/releases/latest)
[![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/argo-cd)](https://artifacthub.io/packages/helm/argo/argo-cd)
**Code:**
[![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)
[![codecov](https://codecov.io/gh/argoproj/argo-cd/branch/master/graph/badge.svg)](https://codecov.io/gh/argoproj/argo-cd)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/4486/badge)](https://bestpractices.coreinfrastructure.org/projects/4486)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fargoproj%2Fargo-cd.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fargoproj%2Fargo-cd?ref=badge_shield)
**Social:**
[![Twitter Follow](https://img.shields.io/twitter/follow/argoproj?style=social)](https://twitter.com/argoproj)
[![Slack](https://img.shields.io/badge/slack-argoproj-brightgreen.svg?logo=slack)](https://argoproj.github.io/community/join-slack)
[![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)
# Argo CD - Declarative Continuous Delivery for Kubernetes

View File

@@ -1,7 +1,7 @@
# Defined below are the security contacts for this repo.
#
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
# INSTRUCTIONS AT https://github.com/argoproj/argo-cd/security/policy
# INSTRUCTIONS AT https://argo-cd.readthedocs.io/en/latest/security_considerations/#reporting-vulnerabilities
alexmt
edlee2121

View File

@@ -11,11 +11,9 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Adevinta](https://www.adevinta.com/)
1. [Adfinis](https://adfinis.com)
1. [Adventure](https://jp.adventurekk.com/)
1. [AirQo](https://airqo.net/)
1. [Akuity](https://akuity.io/)
1. [Alibaba Group](https://www.alibabagroup.com/)
1. [Allianz Direct](https://www.allianzdirect.de/)
1. [Amadeus IT Group](https://amadeus.com/)
1. [Ambassador Labs](https://www.getambassador.io/)
1. [ANSTO - Australian Synchrotron](https://www.synchrotron.org.au/)
1. [Ant Group](https://www.antgroup.com/)
@@ -31,21 +29,18 @@ Currently, the following organizations are **officially** using Argo CD:
1. [BigPanda](https://bigpanda.io)
1. [BioBox Analytics](https://biobox.io)
1. [BMW Group](https://www.bmwgroup.com/)
1. [PT Boer Technology (Btech)](https://btech.id/)
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. [CARFAX Europe](https://www.carfax.eu)
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/)
1. [Cloud Scale](https://cloudscaleinc.com/)
1. [Cobalt](https://www.cobalt.io/)
1. [Codefresh](https://www.codefresh.io/)
1. [Codility](https://www.codility.com/)
@@ -58,11 +53,8 @@ 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. [Divistant](https://divistant.com)
1. [Doximity](https://www.doximity.com/)
1. [EDF Renewables](https://www.edf-re.com/)
1. [edX](https://edx.org)
1. [Elastic](https://elastic.co/)
@@ -72,7 +64,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [END.](https://www.endclothing.com/)
1. [Energisme](https://energisme.com/)
1. [enigmo](https://enigmo.co.jp/)
1. [Envoy](https://envoy.com/)
1. [Faro](https://www.faro.com/)
1. [Fave](https://myfave.com)
1. [Flip](https://flip.id)
@@ -83,8 +74,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [G DATA CyberDefense AG](https://www.gdata-software.com/)
1. [Garner](https://www.garnercorp.com)
1. [Generali Deutschland AG](https://www.generali.de/)
1. [Gepardec](https://gepardec.com/)
1. [GetYourGuide](https://www.getyourguide.com/)
1. [Gitpod](https://www.gitpod.io)
1. [Gllue](https://gllue.com)
1. [gloat](https://gloat.com/)
@@ -106,7 +95,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Ibotta](https://home.ibotta.com)
1. [IITS-Consulting](https://iits-consulting.de)
1. [imaware](https://imaware.health)
1. [Indeed](https://indeed.com)
1. [Index Exchange](https://www.indexexchange.com/)
1. [InsideBoard](https://www.insideboard.com)
1. [Intuit](https://www.intuit.com/)
@@ -126,7 +114,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Kurly](https://www.kurly.com/)
1. [LexisNexis](https://www.lexisnexis.com/)
1. [Lian Chu Securities](https://lczq.com)
1. [Liatrio](https://www.liatrio.com)
1. [Lightricks](https://www.lightricks.com/)
1. [LINE](https://linecorp.com/en/)
1. [Lytt](https://www.lytt.co/)
@@ -139,7 +126,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Max Kelsen](https://www.maxkelsen.com/)
1. [MeDirect](https://medirect.com.mt/)
1. [Meican](https://meican.com/)
1. [Mercedes-Benz Tech Innovation](https://www.mercedes-benz-techinnovation.com/)
1. [Metanet](http://www.metanet.co.kr/en/)
1. [MindSpore](https://mindspore.cn)
1. [Mirantis](https://mirantis.com/)
@@ -154,17 +140,14 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Nextdoor](https://nextdoor.com/)
1. [Nikkei](https://www.nikkei.co.jp/nikkeiinfo/en/)
1. [Nitro](https://gonitro.com)
1. [Objective](https://www.objective.com.br/)
1. [OCCMundial](https://occ.com.mx)
1. [Octadesk](https://octadesk.com)
1. [omegaUp](https://omegaUp.com)
1. [Omni](https://omni.se/)
1. [openEuler](https://openeuler.org)
1. [openGauss](https://opengauss.org/)
1. [openLooKeng](https://openlookeng.io)
1. [OpenSaaS Studio](https://opensaas.studio)
1. [Opensurvey](https://www.opensurvey.co.kr/)
1. [OpsMx](https://opsmx.io)
1. [OpsVerse](https://opsverse.io)
1. [Optoro](https://www.optoro.com/)
1. [Orbital Insight](https://orbitalinsight.com/)
@@ -172,15 +155,11 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Packlink](https://www.packlink.com/)
1. [Pandosearch](https://www.pandosearch.com/en/home)
1. [PagerDuty](https://www.pagerduty.com/)
1. [Patreon](https://www.patreon.com/)
1. [PayPay](https://paypay.ne.jp/)
1. [Peloton Interactive](https://www.onepeloton.com/)
1. [Pigment](https://www.gopigment.com/)
1. [Pipefy](https://www.pipefy.com/)
1. [Pismo](https://pismo.io/)
1. [Platform9 Systems](https://platform9.com/)
1. [Polarpoint.io](https://polarpoint.io)
1. [PostFinance](https://github.com/postfinance)
1. [Preferred Networks](https://preferred.jp/en/)
1. [Productboard](https://www.productboard.com/)
1. [Prudential](https://prudential.com.sg)
@@ -200,13 +179,10 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Saildrone](https://www.saildrone.com/)
1. [Saloodo! GmbH](https://www.saloodo.com)
1. [Sap Labs](http://sap.com)
1. [Sauce Labs](https://saucelabs.com/)
1. [Schwarz IT](https://jobs.schwarz/it-mission)
1. [SI Analytics](https://si-analytics.ai)
1. [Skit](https://skit.ai/)
1. [Skyscanner](https://www.skyscanner.net/)
1. [Smilee.io](https://smilee.io)
1. [Smood.ch](https://www.smood.ch/)
1. [Snapp](https://snapp.ir/)
1. [Snyk](https://snyk.io/)
1. [Softway Medical](https://www.softwaymedical.fr/)
@@ -235,7 +211,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Toss](https://toss.im/en)
1. [Trendyol](https://www.trendyol.com/)
1. [tru.ID](https://tru.id)
1. [Trusting Social](https://trustingsocial.com/)
1. [Twilio SendGrid](https://sendgrid.com)
1. [tZERO](https://www.tzero.com/)
1. [UBIO](https://ub.io/)
@@ -244,11 +219,9 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Unifonic Inc](https://www.unifonic.com/)
1. [Universidad Mesoamericana](https://www.umes.edu.gt/)
1. [Viaduct](https://www.viaduct.ai/)
1. [Vinted](https://vinted.com/)
1. [Virtuo](https://www.govirtuo.com/)
1. [VISITS Technologies](https://visits.world/en)
1. [Volvo Cars](https://www.volvocars.com/)
1. [Voyager Digital](https://www.investvoyager.com/)
1. [VSHN - The DevOps Company](https://vshn.ch/)
1. [Walkbase](https://www.walkbase.com/)
1. [Webstores](https://www.webstores.nl)
@@ -257,7 +230,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [WeMo Scooter](https://www.wemoscooter.com/)
1. [Whitehat Berlin](https://whitehat.berlin) by Guido Maria Serra +Fenaroli
1. [Witick](https://witick.io/)
1. [Wolffun Game](https://www.wolffungame.com/)
1. [WooliesX](https://wooliesx.com.au/)
1. [Woolworths Group](https://www.woolworthsgroup.com.au/)
1. [WSpot](https://www.wspot.com.br/)

View File

@@ -1 +1 @@
2.6.0
2.5.2

View File

@@ -25,7 +25,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/record"
ctrl "sigs.k8s.io/controller-runtime"
@@ -70,8 +69,6 @@ type ApplicationSetReconciler struct {
KubeClientset kubernetes.Interface
utils.Policy
utils.Renderer
EnableProgressiveSyncs bool
}
// +kubebuilder:rbac:groups=argoproj.io,resources=applicationsets,verbs=get;list;watch;create;update;patch;delete
@@ -137,27 +134,6 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
return ctrl.Result{RequeueAfter: ReconcileRequeueOnValidationError}, nil
}
// appMap is a name->app collection of Applications in this ApplicationSet.
appMap := map[string]argov1alpha1.Application{}
// appSyncMap tracks which apps will be synced during this reconciliation.
appSyncMap := map[string]bool{}
if r.EnableProgressiveSyncs && applicationSetInfo.Spec.Strategy != nil {
applications, err := r.getCurrentApplications(ctx, applicationSetInfo)
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed to get current applications for application set: %w", err)
}
for _, app := range applications {
appMap[app.Name] = app
}
appSyncMap, err = r.performProgressiveSyncs(ctx, applicationSetInfo, applications, desiredApplications, appMap)
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed to perform progressive sync reconciliation for application set: %w", err)
}
}
var validApps []argov1alpha1.Application
for i := range desiredApplications {
if validateErrors[i] == nil {
@@ -186,26 +162,6 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
)
}
if r.EnableProgressiveSyncs {
// trigger appropriate application syncs if RollingSync strategy is enabled
if progressiveSyncsStrategyEnabled(&applicationSetInfo, "RollingSync") {
validApps, err = r.syncValidApplications(ctx, &applicationSetInfo, appSyncMap, appMap, validApps)
if err != nil {
_ = r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
Message: err.Error(),
Reason: argov1alpha1.ApplicationSetReasonSyncApplicationError,
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
}, parametersGenerated,
)
return ctrl.Result{}, err
}
}
}
if r.Policy.Update() {
err = r.createOrUpdateInCluster(ctx, applicationSetInfo, validApps)
if err != nil {
@@ -528,7 +484,7 @@ func (r *ApplicationSetReconciler) SetupWithManager(mgr ctrl.Manager) error {
// ...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).
@@ -572,11 +528,6 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context,
// Copy only the Application/ObjectMeta fields that are significant, from the generatedApp
found.Spec = generatedApp.Spec
// allow setting the Operation field to trigger a sync operation on an Application
if generatedApp.Operation != nil {
found.Operation = generatedApp.Operation
}
// Preserve specially treated argo cd annotations:
// * https://github.com/argoproj/applicationset/issues/180
// * https://github.com/argoproj/argo-cd/issues/10500
@@ -616,7 +567,7 @@ func (r *ApplicationSetReconciler) createInCluster(ctx context.Context, applicat
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
@@ -657,13 +608,13 @@ func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, applicat
// 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
@@ -767,7 +718,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
}
}
}
@@ -775,541 +726,4 @@ func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx conte
return nil
}
func (r *ApplicationSetReconciler) performProgressiveSyncs(ctx context.Context, appset argov1alpha1.ApplicationSet, applications []argov1alpha1.Application, desiredApplications []argov1alpha1.Application, appMap map[string]argov1alpha1.Application) (map[string]bool, error) {
appDependencyList, appStepMap, err := r.buildAppDependencyList(ctx, appset, desiredApplications)
if err != nil {
return nil, fmt.Errorf("failed to build app dependency list: %w", err)
}
_, err = r.updateApplicationSetApplicationStatus(ctx, &appset, applications, appStepMap)
if err != nil {
return nil, fmt.Errorf("failed to update applicationset app status: %w", err)
}
log.Infof("ApplicationSet %v step list:", appset.Name)
for i, step := range appDependencyList {
log.Infof("step %v: %+v", i+1, step)
}
appSyncMap, err := r.buildAppSyncMap(ctx, appset, appDependencyList, appMap)
if err != nil {
return nil, fmt.Errorf("failed to build app sync map: %w", err)
}
log.Infof("Application allowed to sync before maxUpdate?: %+v", appSyncMap)
_, err = r.updateApplicationSetApplicationStatusProgress(ctx, &appset, appSyncMap, appStepMap, appMap)
if err != nil {
return nil, fmt.Errorf("failed to update applicationset application status progress: %w", err)
}
_, err = r.updateApplicationSetApplicationStatusConditions(ctx, &appset)
if err != nil {
return nil, fmt.Errorf("failed to update applicationset application status conditions: %w", err)
}
return appSyncMap, nil
}
// this list tracks which Applications belong to each RollingUpdate step
func (r *ApplicationSetReconciler) buildAppDependencyList(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, applications []argov1alpha1.Application) ([][]string, map[string]int, error) {
if applicationSet.Spec.Strategy == nil || applicationSet.Spec.Strategy.Type == "" || applicationSet.Spec.Strategy.Type == "AllAtOnce" {
return [][]string{}, map[string]int{}, nil
}
steps := []argov1alpha1.ApplicationSetRolloutStep{}
if progressiveSyncsStrategyEnabled(&applicationSet, "RollingSync") {
steps = applicationSet.Spec.Strategy.RollingSync.Steps
}
appDependencyList := make([][]string, 0)
for range steps {
appDependencyList = append(appDependencyList, make([]string, 0))
}
appStepMap := map[string]int{}
// use applicationLabelSelectors to filter generated Applications into steps and status by name
for _, app := range applications {
for i, step := range steps {
selected := true // default to true, assuming the current Application is a match for the given step matchExpression
allNotInMatched := true // needed to support correct AND behavior between multiple NotIn MatchExpressions
notInUsed := false // since we default to allNotInMatched == true, track whether a NotIn expression was actually used
for _, matchExpression := range step.MatchExpressions {
if matchExpression.Operator == "In" {
if val, ok := app.Labels[matchExpression.Key]; ok {
valueMatched := labelMatchedExpression(val, matchExpression)
if !valueMatched { // none of the matchExpression values was a match with the Application'ss labels
selected = false
break
}
} else {
selected = false // no matching label key with In means this Application will not be included in the current step
break
}
} else if matchExpression.Operator == "NotIn" {
notInUsed = true // a NotIn selector was used in this matchExpression
if val, ok := app.Labels[matchExpression.Key]; ok {
valueMatched := labelMatchedExpression(val, matchExpression)
if !valueMatched { // none of the matchExpression values was a match with the Application's labels
allNotInMatched = false
}
} else {
allNotInMatched = false // no matching label key with NotIn means this Application may still be included in the current step
}
} else { // handle invalid operator selection
log.Warnf("skipping AppSet rollingUpdate step Application selection for %q, invalid matchExpression operator provided: %q ", applicationSet.Name, matchExpression.Operator)
selected = false
break
}
}
if notInUsed && allNotInMatched { // check if all NotIn Expressions matched, if so exclude this Application
selected = false
}
if selected {
appDependencyList[i] = append(appDependencyList[i], app.Name)
if val, ok := appStepMap[app.Name]; ok {
log.Warnf("AppSet '%v' has a invalid matchExpression that selects Application '%v' label twice, in steps %v and %v", applicationSet.Name, app.Name, val+1, i+1)
} else {
appStepMap[app.Name] = i
}
}
}
}
return appDependencyList, appStepMap, nil
}
func labelMatchedExpression(val string, matchExpression argov1alpha1.ApplicationMatchExpression) bool {
valueMatched := false
for _, value := range matchExpression.Values {
if val == value {
valueMatched = true
break
}
}
return valueMatched
}
// this map is used to determine which stage of Applications are ready to be updated in the reconciler loop
func (r *ApplicationSetReconciler) buildAppSyncMap(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, appDependencyList [][]string, appMap map[string]argov1alpha1.Application) (map[string]bool, error) {
appSyncMap := map[string]bool{}
syncEnabled := true
// healthy stages and the first non-healthy stage should have sync enabled
// every stage after should have sync disabled
for i := range appDependencyList {
// set the syncEnabled boolean for every Application in the current step
for _, appName := range appDependencyList[i] {
appSyncMap[appName] = syncEnabled
}
// detect if we need to halt before progressing to the next step
for _, appName := range appDependencyList[i] {
idx := findApplicationStatusIndex(applicationSet.Status.ApplicationStatus, appName)
if idx == -1 {
// no Application status found, likely because the Application is being newly created
syncEnabled = false
break
}
appStatus := applicationSet.Status.ApplicationStatus[idx]
if app, ok := appMap[appName]; ok {
syncEnabled = appSyncEnabledForNextStep(&applicationSet, app, appStatus)
if !syncEnabled {
break
}
} else {
// application name not found in the list of applications managed by this ApplicationSet, maybe because it's being deleted
syncEnabled = false
break
}
}
}
return appSyncMap, nil
}
func appSyncEnabledForNextStep(appset *argov1alpha1.ApplicationSet, app argov1alpha1.Application, appStatus argov1alpha1.ApplicationSetApplicationStatus) bool {
if progressiveSyncsStrategyEnabled(appset, "RollingSync") {
// we still need to complete the current step if the Application is not yet Healthy or there are still pending Application changes
return isApplicationHealthy(app) && appStatus.Status == "Healthy"
}
return true
}
func progressiveSyncsStrategyEnabled(appset *argov1alpha1.ApplicationSet, strategyType string) bool {
if appset.Spec.Strategy == nil || appset.Spec.Strategy.Type != strategyType {
return false
}
if strategyType == "RollingSync" && appset.Spec.Strategy.RollingSync == nil {
return false
}
return true
}
func isApplicationHealthy(app argov1alpha1.Application) bool {
healthStatusString, syncStatusString, operationPhaseString := statusStrings(app)
if healthStatusString == "Healthy" && syncStatusString != "OutOfSync" && (operationPhaseString == "Succeeded" || operationPhaseString == "") {
return true
}
return false
}
func statusStrings(app argov1alpha1.Application) (string, string, string) {
healthStatusString := string(app.Status.Health.Status)
syncStatusString := string(app.Status.Sync.Status)
operationPhaseString := ""
if app.Status.OperationState != nil {
operationPhaseString = string(app.Status.OperationState.Phase)
}
return healthStatusString, syncStatusString, operationPhaseString
}
// check the status of each Application's status and promote Applications to the next status if needed
func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx context.Context, applicationSet *argov1alpha1.ApplicationSet, applications []argov1alpha1.Application, appStepMap map[string]int) ([]argov1alpha1.ApplicationSetApplicationStatus, error) {
now := metav1.Now()
appStatuses := make([]argov1alpha1.ApplicationSetApplicationStatus, 0, len(applications))
for _, app := range applications {
healthStatusString, syncStatusString, operationPhaseString := statusStrings(app)
idx := findApplicationStatusIndex(applicationSet.Status.ApplicationStatus, app.Name)
currentAppStatus := argov1alpha1.ApplicationSetApplicationStatus{}
if idx == -1 {
// AppStatus not found, set default status of "Waiting"
currentAppStatus = argov1alpha1.ApplicationSetApplicationStatus{
Application: app.Name,
LastTransitionTime: &now,
Message: "No Application status found, defaulting status to Waiting.",
Status: "Waiting",
Step: fmt.Sprint(appStepMap[app.Name] + 1),
}
} else {
// we have an existing AppStatus
currentAppStatus = applicationSet.Status.ApplicationStatus[idx]
}
appOutdated := false
if progressiveSyncsStrategyEnabled(applicationSet, "RollingSync") {
appOutdated = syncStatusString == "OutOfSync"
}
if appOutdated && currentAppStatus.Status != "Waiting" && currentAppStatus.Status != "Pending" {
log.Infof("Application %v is outdated, updating its ApplicationSet status to Waiting", app.Name)
currentAppStatus.LastTransitionTime = &now
currentAppStatus.Status = "Waiting"
currentAppStatus.Message = "Application has pending changes, setting status to Waiting."
currentAppStatus.Step = fmt.Sprint(appStepMap[currentAppStatus.Application] + 1)
}
if currentAppStatus.Status == "Pending" {
if operationPhaseString == "Succeeded" && app.Status.OperationState.StartedAt.After(currentAppStatus.LastTransitionTime.Time) {
log.Infof("Application %v has completed a sync successfully, updating its ApplicationSet status to Progressing", app.Name)
currentAppStatus.LastTransitionTime = &now
currentAppStatus.Status = "Progressing"
currentAppStatus.Message = "Application resource completed a sync successfully, updating status from Pending to Progressing."
currentAppStatus.Step = fmt.Sprint(appStepMap[currentAppStatus.Application] + 1)
} else if operationPhaseString == "Running" || healthStatusString == "Progressing" {
log.Infof("Application %v has entered Progressing status, updating its ApplicationSet status to Progressing", app.Name)
currentAppStatus.LastTransitionTime = &now
currentAppStatus.Status = "Progressing"
currentAppStatus.Message = "Application resource became Progressing, updating status from Pending to Progressing."
currentAppStatus.Step = fmt.Sprint(appStepMap[currentAppStatus.Application] + 1)
}
}
if currentAppStatus.Status == "Waiting" && isApplicationHealthy(app) {
log.Infof("Application %v is already synced and healthy, updating its ApplicationSet status to Healthy", app.Name)
currentAppStatus.LastTransitionTime = &now
currentAppStatus.Status = healthStatusString
currentAppStatus.Message = "Application resource is already Healthy, updating status from Waiting to Healthy."
currentAppStatus.Step = fmt.Sprint(appStepMap[currentAppStatus.Application] + 1)
}
if currentAppStatus.Status == "Progressing" && isApplicationHealthy(app) {
log.Infof("Application %v has completed Progressing status, updating its ApplicationSet status to Healthy", app.Name)
currentAppStatus.LastTransitionTime = &now
currentAppStatus.Status = healthStatusString
currentAppStatus.Message = "Application resource became Healthy, updating status from Progressing to Healthy."
currentAppStatus.Step = fmt.Sprint(appStepMap[currentAppStatus.Application] + 1)
}
appStatuses = append(appStatuses, currentAppStatus)
}
err := r.setAppSetApplicationStatus(ctx, applicationSet, appStatuses)
if err != nil {
return nil, fmt.Errorf("failed to set AppSet application statuses: %w", err)
}
return appStatuses, nil
}
// check Applications that are in Waiting status and promote them to Pending if needed
func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress(ctx context.Context, applicationSet *argov1alpha1.ApplicationSet, appSyncMap map[string]bool, appStepMap map[string]int, appMap map[string]argov1alpha1.Application) ([]argov1alpha1.ApplicationSetApplicationStatus, error) {
now := metav1.Now()
appStatuses := make([]argov1alpha1.ApplicationSetApplicationStatus, 0, len(applicationSet.Status.ApplicationStatus))
// if we have no RollingUpdate steps, clear out the existing ApplicationStatus entries
if applicationSet.Spec.Strategy != nil && applicationSet.Spec.Strategy.Type != "" && applicationSet.Spec.Strategy.Type != "AllAtOnce" {
updateCountMap := []int{}
totalCountMap := []int{}
length := 0
if progressiveSyncsStrategyEnabled(applicationSet, "RollingSync") {
length = len(applicationSet.Spec.Strategy.RollingSync.Steps)
}
for s := 0; s < length; s++ {
updateCountMap = append(updateCountMap, 0)
totalCountMap = append(totalCountMap, 0)
}
// populate updateCountMap with counts of existing Pending and Progressing Applications
for _, appStatus := range applicationSet.Status.ApplicationStatus {
totalCountMap[appStepMap[appStatus.Application]] += 1
if progressiveSyncsStrategyEnabled(applicationSet, "RollingSync") {
if appStatus.Status == "Pending" || appStatus.Status == "Progressing" {
updateCountMap[appStepMap[appStatus.Application]] += 1
}
}
}
for _, appStatus := range applicationSet.Status.ApplicationStatus {
maxUpdateAllowed := true
maxUpdate := &intstr.IntOrString{}
if progressiveSyncsStrategyEnabled(applicationSet, "RollingSync") {
maxUpdate = applicationSet.Spec.Strategy.RollingSync.Steps[appStepMap[appStatus.Application]].MaxUpdate
}
// by default allow all applications to update if maxUpdate is unset
if maxUpdate != nil {
maxUpdateVal, err := intstr.GetScaledValueFromIntOrPercent(maxUpdate, totalCountMap[appStepMap[appStatus.Application]], false)
if err != nil {
log.Warnf("AppSet '%v' has a invalid maxUpdate value '%+v', ignoring maxUpdate logic for this step: %v", applicationSet.Name, maxUpdate, err)
}
// ensure that percentage values greater than 0% always result in at least 1 Application being selected
if maxUpdate.Type == intstr.String && maxUpdate.StrVal != "0%" && maxUpdateVal < 1 {
maxUpdateVal = 1
}
if updateCountMap[appStepMap[appStatus.Application]] >= maxUpdateVal {
maxUpdateAllowed = false
log.Infof("Application %v is not allowed to update yet, %v/%v Applications already updating in step %v in AppSet %v", appStatus.Application, updateCountMap[appStepMap[appStatus.Application]], maxUpdateVal, appStepMap[appStatus.Application]+1, applicationSet.Name)
}
}
if appStatus.Status == "Waiting" && appSyncMap[appStatus.Application] && maxUpdateAllowed {
log.Infof("Application %v moved to Pending status, watching for the Application to start Progressing", appStatus.Application)
appStatus.LastTransitionTime = &now
appStatus.Status = "Pending"
appStatus.Message = "Application moved to Pending status, watching for the Application resource to start Progressing."
appStatus.Step = fmt.Sprint(appStepMap[appStatus.Application] + 1)
updateCountMap[appStepMap[appStatus.Application]] += 1
}
appStatuses = append(appStatuses, appStatus)
}
}
err := r.setAppSetApplicationStatus(ctx, applicationSet, appStatuses)
if err != nil {
return nil, fmt.Errorf("failed to set AppSet app status: %w", err)
}
return appStatuses, nil
}
func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusConditions(ctx context.Context, applicationSet *argov1alpha1.ApplicationSet) ([]argov1alpha1.ApplicationSetCondition, error) {
appSetProgressing := false
for _, appStatus := range applicationSet.Status.ApplicationStatus {
if appStatus.Status != "Healthy" {
appSetProgressing = true
break
}
}
appSetConditionProgressing := false
for _, appSetCondition := range applicationSet.Status.Conditions {
if appSetCondition.Type == argov1alpha1.ApplicationSetConditionRolloutProgressing && appSetCondition.Status == argov1alpha1.ApplicationSetConditionStatusTrue {
appSetConditionProgressing = true
break
}
}
if appSetProgressing && !appSetConditionProgressing {
_ = r.setApplicationSetStatusCondition(ctx,
applicationSet,
argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionRolloutProgressing,
Message: "ApplicationSet Rollout Rollout started",
Reason: argov1alpha1.ApplicationSetReasonApplicationSetModified,
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
}, false,
)
} else if !appSetProgressing && appSetConditionProgressing {
_ = r.setApplicationSetStatusCondition(ctx,
applicationSet,
argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionRolloutProgressing,
Message: "ApplicationSet Rollout Rollout complete",
Reason: argov1alpha1.ApplicationSetReasonApplicationSetRolloutComplete,
Status: argov1alpha1.ApplicationSetConditionStatusFalse,
}, false,
)
}
return applicationSet.Status.Conditions, nil
}
func findApplicationStatusIndex(appStatuses []argov1alpha1.ApplicationSetApplicationStatus, application string) int {
for i := range appStatuses {
if appStatuses[i].Application == application {
return i
}
}
return -1
}
// setApplicationSetApplicationStatus updates the ApplicatonSet's status field
// with any new/changed Application statuses.
func (r *ApplicationSetReconciler) setAppSetApplicationStatus(ctx context.Context, applicationSet *argov1alpha1.ApplicationSet, applicationStatuses []argov1alpha1.ApplicationSetApplicationStatus) error {
needToUpdateStatus := false
for i := range applicationStatuses {
appStatus := applicationStatuses[i]
idx := findApplicationStatusIndex(applicationSet.Status.ApplicationStatus, appStatus.Application)
if idx == -1 {
needToUpdateStatus = true
break
}
currentStatus := applicationSet.Status.ApplicationStatus[idx]
if currentStatus.Message != appStatus.Message || currentStatus.Status != appStatus.Status {
needToUpdateStatus = true
break
}
}
if needToUpdateStatus {
// fetch updated Application Set object before updating it
namespacedName := types.NamespacedName{Namespace: applicationSet.Namespace, Name: applicationSet.Name}
if err := r.Get(ctx, namespacedName, applicationSet); err != nil {
if client.IgnoreNotFound(err) != nil {
return nil
}
return fmt.Errorf("error fetching updated application set: %v", err)
}
for i := range applicationStatuses {
applicationSet.Status.SetApplicationStatus(applicationStatuses[i])
}
// Update the newly fetched object with new set of ApplicationStatus
err := r.Client.Status().Update(ctx, applicationSet)
if err != nil {
log.Errorf("unable to set application set status: %v", err)
return fmt.Errorf("unable to set application set status: %v", err)
}
if err := r.Get(ctx, namespacedName, applicationSet); err != nil {
if client.IgnoreNotFound(err) != nil {
return nil
}
return fmt.Errorf("error fetching updated application set: %v", err)
}
}
return nil
}
func (r *ApplicationSetReconciler) syncValidApplications(ctx context.Context, applicationSet *argov1alpha1.ApplicationSet, appSyncMap map[string]bool, appMap map[string]argov1alpha1.Application, validApps []argov1alpha1.Application) ([]argov1alpha1.Application, error) {
rolloutApps := []argov1alpha1.Application{}
for i := range validApps {
pruneEnabled := false
// ensure that Applications generated with RollingSync do not have an automated sync policy, since the AppSet controller will handle triggering the sync operation instead
if validApps[i].Spec.SyncPolicy != nil && validApps[i].Spec.SyncPolicy.Automated != nil {
pruneEnabled = validApps[i].Spec.SyncPolicy.Automated.Prune
validApps[i].Spec.SyncPolicy.Automated = nil
}
appSetStatusPending := false
idx := findApplicationStatusIndex(applicationSet.Status.ApplicationStatus, validApps[i].Name)
if idx > -1 && applicationSet.Status.ApplicationStatus[idx].Status == "Pending" {
// only trigger a sync for Applications that are in Pending status, since this is governed by maxUpdate
appSetStatusPending = true
}
// check appSyncMap to determine which Applications are ready to be updated and which should be skipped
if appSyncMap[validApps[i].Name] && appMap[validApps[i].Name].Status.Sync.Status == "OutOfSync" && appSetStatusPending {
log.Infof("triggering sync for application: %v, prune enabled: %v", validApps[i].Name, pruneEnabled)
validApps[i], _ = syncApplication(validApps[i], pruneEnabled)
}
rolloutApps = append(rolloutApps, validApps[i])
}
return rolloutApps, nil
}
// used by the RollingSync Progressive Sync strategy to trigger a sync of a particular Application resource
func syncApplication(application argov1alpha1.Application, prune bool) (argov1alpha1.Application, error) {
operation := argov1alpha1.Operation{
InitiatedBy: argov1alpha1.OperationInitiator{
Username: "applicationset-controller",
Automated: true,
},
Info: []*argov1alpha1.Info{
{
Name: "Reason",
Value: "ApplicationSet RollingSync triggered a sync of this Application resource.",
},
},
Sync: &argov1alpha1.SyncOperation{},
}
if application.Spec.SyncPolicy != nil {
if application.Spec.SyncPolicy.Retry != nil {
operation.Retry = *application.Spec.SyncPolicy.Retry
}
if application.Spec.SyncPolicy.SyncOptions != nil {
operation.Sync.SyncOptions = application.Spec.SyncPolicy.SyncOptions
}
operation.Sync.Prune = prune
}
application.Operation = &operation
return application, nil
}
var _ handler.EventHandler = &clusterSecretEventHandler{}

File diff suppressed because it is too large Load Diff

View File

@@ -23,8 +23,6 @@ spec:
template:
metadata:
name: 'myapp-{{ .branch }}-{{ .number }}'
labels:
key1: '{{ index .labels 0 }}'
spec:
source:
repoURL: 'https://github.com/myorg/myrepo.git'

View File

@@ -170,7 +170,7 @@ func appendTemplatedValues(clusterValues map[string]string, params map[string]in
result, err := replaceTemplatedString(value, params, appSet)
if err != nil {
return fmt.Errorf("error replacing templated String: %w", err)
return err
}
if appSet.Spec.GoTemplate {

View File

@@ -1,7 +1,6 @@
package generators
import (
"fmt"
"encoding/json"
"reflect"
@@ -29,7 +28,7 @@ type TransformResult struct {
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)
return nil, err
}
res := []TransformResult{}

View File

@@ -85,7 +85,6 @@ func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoproj
"total": len(allPaths),
"repoURL": appSetGenerator.Git.RepoURL,
"revision": appSetGenerator.Git.Revision,
"pathParamPrefix": appSetGenerator.Git.PathParamPrefix,
}).Info("applications result from the repo service")
requestedApps := g.filterApps(appSetGenerator.Git.Directories, allPaths)
@@ -122,7 +121,7 @@ func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1al
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, appSetGenerator.Git.PathParamPrefix)
paramsArray, err := g.generateParamsFromGitFile(path, allFiles[path], useGoTemplate)
if err != nil {
return nil, fmt.Errorf("unable to process file '%s': %v", path, err)
}
@@ -134,7 +133,7 @@ func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1al
return res, nil
}
func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []byte, useGoTemplate bool, pathParamPrefix string) ([]map[string]interface{}, error) {
func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []byte, useGoTemplate bool) ([]map[string]interface{}, error) {
objectsFound := []map[string]interface{}{}
// First, we attempt to parse as an array
@@ -168,11 +167,7 @@ func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []
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), "/")
if pathParamPrefix != "" {
params[pathParamPrefix] = map[string]interface{}{"path": paramPath}
} else {
params["path"] = paramPath
}
params["path"] = paramPath
} else {
flat, err := flatten.Flatten(objectFound, "", flatten.DotStyle)
if err != nil {
@@ -181,18 +176,14 @@ func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []
for k, v := range flat {
params[k] = fmt.Sprintf("%v", v)
}
pathParamName := "path"
if pathParamPrefix != "" {
pathParamName = pathParamPrefix+"."+pathParamName
}
params[pathParamName] = path.Dir(filePath)
params[pathParamName+".basename"] = path.Base(params[pathParamName].(string))
params[pathParamName+".filename"] = path.Base(filePath)
params[pathParamName+".basenameNormalized"] = utils.SanitizeName(path.Base(params[pathParamName].(string)))
params[pathParamName+".filenameNormalized"] = utils.SanitizeName(path.Base(params[pathParamName+".filename"].(string)))
for k, v := range strings.Split(params[pathParamName].(string), "/") {
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[pathParamName+"["+strconv.Itoa(k)+"]"] = v
params["path["+strconv.Itoa(k)+"]"] = v
}
}
}
@@ -201,6 +192,7 @@ func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []
}
return res, nil
}
func (g *GitGenerator) filterApps(Directories []argoprojiov1alpha1.GitDirectoryGeneratorItem, allPaths []string) []string {
@@ -231,7 +223,9 @@ func (g *GitGenerator) filterApps(Directories []argoprojiov1alpha1.GitDirectoryG
return res
}
func (g *GitGenerator) generateParamsFromApps(requestedApps []string, appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool) []map[string]interface{} {
func (g *GitGenerator) generateParamsFromApps(requestedApps []string, _ *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool) []map[string]interface{} {
// TODO: At some point, the applicationSetGenerator param should be used
res := make([]map[string]interface{}, len(requestedApps))
for i, a := range requestedApps {
@@ -243,22 +237,14 @@ func (g *GitGenerator) generateParamsFromApps(requestedApps []string, appSetGene
paramPath["basename"] = path.Base(a)
paramPath["basenameNormalized"] = utils.SanitizeName(path.Base(a))
paramPath["segments"] = strings.Split(paramPath["path"].(string), "/")
if appSetGenerator.Git.PathParamPrefix != "" {
params[appSetGenerator.Git.PathParamPrefix] = map[string]interface{}{"path": paramPath}
} else {
params["path"] = paramPath
}
params["path"] = paramPath
} else {
pathParamName := "path"
if appSetGenerator.Git.PathParamPrefix != "" {
pathParamName = appSetGenerator.Git.PathParamPrefix+"."+pathParamName
}
params[pathParamName] = a
params[pathParamName+".basename"] = path.Base(a)
params[pathParamName+".basenameNormalized"] = utils.SanitizeName(path.Base(a))
for k, v := range strings.Split(params[pathParamName].(string), "/") {
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[pathParamName+"["+strconv.Itoa(k)+"]"] = v
params["path["+strconv.Itoa(k)+"]"] = v
}
}
}

View File

@@ -51,7 +51,7 @@ func Test_generateParamsFromGitFile(t *testing.T) {
params, err := (*GitGenerator)(nil).generateParamsFromGitFile("path/dir/file_name.yaml", []byte(`
foo:
bar: baz
`), false, "")
`), false)
if err != nil {
t.Fatal(err)
}
@@ -69,33 +69,11 @@ foo:
}, params)
}
func Test_generatePrefixedParamsFromGitFile(t *testing.T) {
params, err := (*GitGenerator)(nil).generateParamsFromGitFile("path/dir/file_name.yaml", []byte(`
foo:
bar: baz
`), false, "myRepo")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, []map[string]interface{}{
{
"foo.bar": "baz",
"myRepo.path": "path/dir",
"myRepo.path.basename": "dir",
"myRepo.path.filename": "file_name.yaml",
"myRepo.path.basenameNormalized": "dir",
"myRepo.path.filenameNormalized": "file-name.yaml",
"myRepo.path[0]": "path",
"myRepo.path[1]": "dir",
},
}, params)
}
func Test_generateParamsFromGitFileGoTemplate(t *testing.T) {
params, err := (*GitGenerator)(nil).generateParamsFromGitFile("path/dir/file_name.yaml", []byte(`
foo:
bar: baz
`), true, "")
`), true)
if err != nil {
t.Fatal(err)
}
@@ -119,46 +97,15 @@ foo:
}, params)
}
func Test_generatePrefixedParamsFromGitFileGoTemplate(t *testing.T) {
params, err := (*GitGenerator)(nil).generateParamsFromGitFile("path/dir/file_name.yaml", []byte(`
foo:
bar: baz
`), true, "myRepo")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, []map[string]interface{}{
{
"foo": map[string]interface{}{
"bar": "baz",
},
"myRepo": map[string]interface{}{
"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 {
name string
directories []argoprojiov1alpha1.GitDirectoryGeneratorItem
pathParamPrefix string
repoApps []string
repoError error
expected []map[string]interface{}
expectedError error
name string
directories []argoprojiov1alpha1.GitDirectoryGeneratorItem
repoApps []string
repoError error
expected []map[string]interface{}
expectedError error
}{
{
name: "happy flow - created apps",
@@ -177,24 +124,6 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
},
expectedError: nil,
},
{
name: "It prefixes path parameters with PathParamPrefix",
directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
pathParamPrefix: "myRepo",
repoApps: []string{
"app1",
"app2",
"app_3",
"p1/app4",
},
repoError: nil,
expected: []map[string]interface{}{
{"myRepo.path": "app1", "myRepo.path.basename": "app1", "myRepo.path.basenameNormalized": "app1", "myRepo.path[0]": "app1"},
{"myRepo.path": "app2", "myRepo.path.basename": "app2", "myRepo.path.basenameNormalized": "app2", "myRepo.path[0]": "app2"},
{"myRepo.path": "app_3", "myRepo.path.basename": "app_3", "myRepo.path.basenameNormalized": "app-3", "myRepo.path[0]": "app_3"},
},
expectedError: nil,
},
{
name: "It filters application according to the paths",
directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "p1/*"}, {Path: "p1/*/*"}},
@@ -283,10 +212,9 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
Spec: argoprojiov1alpha1.ApplicationSetSpec{
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{
Git: &argoprojiov1alpha1.GitGenerator{
RepoURL: "RepoURL",
Revision: "Revision",
Directories: testCaseCopy.directories,
PathParamPrefix: testCaseCopy.pathParamPrefix,
RepoURL: "RepoURL",
Revision: "Revision",
Directories: testCaseCopy.directories,
},
}},
},
@@ -309,13 +237,12 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) {
cases := []struct {
name string
directories []argoprojiov1alpha1.GitDirectoryGeneratorItem
pathParamPrefix string
repoApps []string
repoError error
expected []map[string]interface{}
expectedError error
name string
directories []argoprojiov1alpha1.GitDirectoryGeneratorItem
repoApps []string
repoError error
expected []map[string]interface{}
expectedError error
}{
{
name: "happy flow - created apps",
@@ -361,57 +288,6 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) {
},
expectedError: nil,
},
{
name: "It prefixes path parameters with PathParamPrefix",
directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
pathParamPrefix: "myRepo",
repoApps: []string{
"app1",
"app2",
"app_3",
"p1/app4",
},
repoError: nil,
expected: []map[string]interface{}{
{
"myRepo": map[string]interface{}{
"path": map[string]interface{}{
"path": "app1",
"basename": "app1",
"basenameNormalized": "app1",
"segments": []string{
"app1",
},
},
},
},
{
"myRepo": map[string]interface{}{
"path": map[string]interface{}{
"path": "app2",
"basename": "app2",
"basenameNormalized": "app2",
"segments": []string{
"app2",
},
},
},
},
{
"myRepo": map[string]interface{}{
"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/*/*"}},
@@ -579,10 +455,9 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) {
GoTemplate: true,
Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{
Git: &argoprojiov1alpha1.GitGenerator{
RepoURL: "RepoURL",
Revision: "Revision",
Directories: testCaseCopy.directories,
PathParamPrefix: testCaseCopy.pathParamPrefix,
RepoURL: "RepoURL",
Revision: "Revision",
Directories: testCaseCopy.directories,
},
}},
},

View File

@@ -144,10 +144,9 @@ func (m *MatrixGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Ap
for _, r := range appSetGenerator.Matrix.Generators {
base := &argoprojiov1alpha1.ApplicationSetGenerator{
List: r.List,
Clusters: r.Clusters,
Git: r.Git,
PullRequest: r.PullRequest,
List: r.List,
Clusters: r.Clusters,
Git: r.Git,
}
generators := GetRelevantGenerators(base, m.supportedGenerators)

View File

@@ -399,8 +399,6 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "Cluster","url": "Url"}`)}},
}
pullRequestGenerator := &argoprojiov1alpha1.PullRequestGenerator{}
testCases := []struct {
name string
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
@@ -433,31 +431,6 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
gitGetRequeueAfter: time.Duration(1),
expected: time.Duration(1),
},
{
name: "returns the minimal time for pull request",
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
{
Git: gitGenerator,
},
{
PullRequest: pullRequestGenerator,
},
},
gitGetRequeueAfter: time.Duration(15 * time.Second),
expected: time.Duration(15 * time.Second),
},
{
name: "returns the default time if no requeueAfterSeconds is provided",
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
{
Git: gitGenerator,
},
{
PullRequest: pullRequestGenerator,
},
},
expected: time.Duration(30 * time.Minute),
},
}
for _, testCase := range testCases {
@@ -468,18 +441,16 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
for _, g := range testCaseCopy.baseGenerators {
gitGeneratorSpec := argoprojiov1alpha1.ApplicationSetGenerator{
Git: g.Git,
List: g.List,
PullRequest: g.PullRequest,
Git: g.Git,
List: g.List,
}
mock.On("GetRequeueAfter", &gitGeneratorSpec).Return(testCaseCopy.gitGetRequeueAfter, nil)
}
var matrixGenerator = NewMatrixGenerator(
map[string]Generator{
"Git": mock,
"List": &ListGenerator{},
"PullRequest": &PullRequestGenerator{},
"Git": mock,
"List": &ListGenerator{},
},
)

View File

@@ -90,19 +90,13 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
shortSHALength = len(pull.HeadSHA)
}
paramMap := map[string]interface{}{
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],
}
// PR lables will only be supported for Go Template appsets, since fasttemplate will be deprecated.
if applicationSetInfo != nil && applicationSetInfo.Spec.GoTemplate {
paramMap["labels"] = pull.Labels
}
params = append(params, paramMap)
})
}
return params, nil
}

View File

@@ -17,10 +17,9 @@ import (
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{}
expectedErr error
applicationSet argoprojiov1alpha1.ApplicationSet
selectFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error)
expected []map[string]interface{}
expectedErr error
}{
{
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
@@ -108,71 +107,6 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
expected: nil,
expectedErr: fmt.Errorf("error listing repos: fake error"),
},
{
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
return pullrequest.NewFakeService(
ctx,
[]*pullrequest.PullRequest{
&pullrequest.PullRequest{
Number: 1,
Branch: "branch1",
HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958",
Labels: []string{"preview"},
},
},
nil,
)
},
expected: []map[string]interface{}{
{
"number": "1",
"branch": "branch1",
"branch_slug": "branch1",
"head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958",
"head_short_sha": "089d92cb",
"labels": []string{"preview"},
},
},
expectedErr: nil,
applicationSet: argoprojiov1alpha1.ApplicationSet{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
// Application set is using Go Template.
GoTemplate: true,
},
},
},
{
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
return pullrequest.NewFakeService(
ctx,
[]*pullrequest.PullRequest{
&pullrequest.PullRequest{
Number: 1,
Branch: "branch1",
HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958",
Labels: []string{"preview"},
},
},
nil,
)
},
expected: []map[string]interface{}{
{
"number": "1",
"branch": "branch1",
"branch_slug": "branch1",
"head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958",
"head_short_sha": "089d92cb",
},
},
expectedErr: nil,
applicationSet: argoprojiov1alpha1.ApplicationSet{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
// Application set is using fasttemplate.
GoTemplate: false,
},
},
},
}
for _, c := range cases {
@@ -183,7 +117,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
PullRequest: &argoprojiov1alpha1.PullRequestGenerator{},
}
got, gotErr := gen.GenerateParams(&generatorConfig, &c.applicationSet)
got, gotErr := gen.GenerateParams(&generatorConfig, nil)
assert.Equal(t, c.expectedErr, gotErr)
assert.ElementsMatch(t, c.expected, got)
}

View File

@@ -122,15 +122,6 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
if err != nil {
return nil, fmt.Errorf("error initializing Azure Devops service: %v", err)
}
} else if providerConfig.Bitbucket != nil {
appPassword, err := g.getSecretRef(ctx, providerConfig.Bitbucket.AppPasswordRef, applicationSetInfo.Namespace)
if err != nil {
return nil, fmt.Errorf("error fetching Bitbucket cloud appPassword: %v", err)
}
provider, err = scm_provider.NewBitBucketCloudProvider(ctx, providerConfig.Bitbucket.Owner, providerConfig.Bitbucket.User, appPassword, providerConfig.Bitbucket.AllBranches)
if err != nil {
return nil, fmt.Errorf("error initializing Bitbucket cloud service: %v", err)
}
} else {
return nil, fmt.Errorf("no SCM provider implementation configured")
}

View File

@@ -20,12 +20,10 @@ func Client(g github_app_auth.Authentication, url string) (*github.Client, error
url = g.EnterpriseBaseURL
}
var client *github.Client
httpClient := http.Client{Transport: rt}
if url == "" {
httpClient := http.Client{Transport: rt}
client = github.NewClient(&httpClient)
} else {
rt.BaseURL = url
httpClient := http.Client{Transport: rt}
client, err = github.NewEnterpriseClient(url, url, &httpClient)
if err != nil {
return nil, fmt.Errorf("failed to create github enterprise client: %w", err)

View File

@@ -69,7 +69,6 @@ func (b *BitbucketService) List(_ context.Context) ([]*PullRequest, error) {
Number: pull.ID,
Branch: pull.FromRef.DisplayID, // ID: refs/heads/main DisplayID: main
HeadSHA: pull.FromRef.LatestCommit, // This is not defined in the official docs, but works in practice
Labels: []string{}, // Not supported by library
})
}

View File

@@ -122,19 +122,16 @@ func TestListPullRequestPagination(t *testing.T) {
Number: 101,
Branch: "feature-101",
HeadSHA: "ab3cf2e4d1517c83e720d2585b9402dbef71f992",
Labels: []string{},
}, *pullRequests[0])
assert.Equal(t, PullRequest{
Number: 102,
Branch: "feature-102",
HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992",
Labels: []string{},
}, *pullRequests[1])
assert.Equal(t, PullRequest{
Number: 200,
Branch: "feature-200",
HeadSHA: "cb3cf2e4d1517c83e720d2585b9402dbef71f992",
Labels: []string{},
}, *pullRequests[2])
}
@@ -287,13 +284,11 @@ func TestListPullRequestBranchMatch(t *testing.T) {
Number: 101,
Branch: "feature-101",
HeadSHA: "ab3cf2e4d1517c83e720d2585b9402dbef71f992",
Labels: []string{},
}, *pullRequests[0])
assert.Equal(t, PullRequest{
Number: 102,
Branch: "feature-102",
HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992",
Labels: []string{},
}, *pullRequests[1])
regexp = `.*2$`
@@ -310,7 +305,6 @@ func TestListPullRequestBranchMatch(t *testing.T) {
Number: 102,
Branch: "feature-102",
HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992",
Labels: []string{},
}, *pullRequests[0])
regexp = `[\d{2}`

View File

@@ -57,17 +57,7 @@ func (g *GiteaService) List(ctx context.Context) ([]*PullRequest, error) {
Number: int(pr.Index),
Branch: pr.Head.Ref,
HeadSHA: pr.Head.Sha,
Labels: getGiteaPRLabelNames(pr.Labels),
})
}
return list, nil
}
// Get the Gitea pull request label names.
func getGiteaPRLabelNames(giteaLabels []*gitea.Label) []string {
var labelNames []string
for _, giteaLabel := range giteaLabels {
labelNames = append(labelNames, giteaLabel.Name)
}
return labelNames
}

View File

@@ -8,7 +8,6 @@ import (
"net/http/httptest"
"testing"
"code.gitea.io/sdk/gitea"
"github.com/stretchr/testify/assert"
)
@@ -258,32 +257,3 @@ func TestGiteaList(t *testing.T) {
assert.Equal(t, prs[0].Branch, "test")
assert.Equal(t, prs[0].HeadSHA, "7bbaf62d92ddfafd9cc8b340c619abaec32bc09f")
}
func TestGetGiteaPRLabelNames(t *testing.T) {
Tests := []struct {
Name string
PullLabels []*gitea.Label
ExpectedResult []string
}{
{
Name: "PR has labels",
PullLabels: []*gitea.Label{
&gitea.Label{Name: "label1"},
&gitea.Label{Name: "label2"},
&gitea.Label{Name: "label3"},
},
ExpectedResult: []string{"label1", "label2", "label3"},
},
{
Name: "PR does not have labels",
PullLabels: []*gitea.Label{},
ExpectedResult: nil,
},
}
for _, test := range Tests {
t.Run(test.Name, func(t *testing.T) {
labels := getGiteaPRLabelNames(test.PullLabels)
assert.Equal(t, test.ExpectedResult, labels)
})
}
}

View File

@@ -68,7 +68,6 @@ func (g *GithubService) List(ctx context.Context) ([]*PullRequest, error) {
Number: *pull.Number,
Branch: *pull.Head.Ref,
HeadSHA: *pull.Head.SHA,
Labels: getGithubPRLabelNames(pull.Labels),
})
}
if resp.NextPage == 0 {
@@ -98,12 +97,3 @@ func containLabels(expectedLabels []string, gotLabels []*github.Label) bool {
}
return true
}
// Get the Github pull request label names.
func getGithubPRLabelNames(gitHubLabels []*github.Label) []string {
var labelNames []string
for _, gitHubLabel := range gitHubLabels {
labelNames = append(labelNames, *gitHubLabel.Name)
}
return labelNames
}

View File

@@ -4,7 +4,6 @@ import (
"testing"
"github.com/google/go-github/v35/github"
"github.com/stretchr/testify/assert"
)
func toPtr(s string) *string {
@@ -58,32 +57,3 @@ func TestContainLabels(t *testing.T) {
})
}
}
func TestGetGitHubPRLabelNames(t *testing.T) {
Tests := []struct {
Name string
PullLabels []*github.Label
ExpectedResult []string
}{
{
Name: "PR has labels",
PullLabels: []*github.Label{
&github.Label{Name: toPtr("label1")},
&github.Label{Name: toPtr("label2")},
&github.Label{Name: toPtr("label3")},
},
ExpectedResult: []string{"label1", "label2", "label3"},
},
{
Name: "PR does not have labels",
PullLabels: []*github.Label{},
ExpectedResult: nil,
},
}
for _, test := range Tests {
t.Run(test.Name, func(t *testing.T) {
labels := getGithubPRLabelNames(test.PullLabels)
assert.Equal(t, test.ExpectedResult, labels)
})
}
}

View File

@@ -72,7 +72,6 @@ func (g *GitLabService) List(ctx context.Context) ([]*PullRequest, error) {
Number: mr.IID,
Branch: mr.SourceBranch,
HeadSHA: mr.SHA,
Labels: mr.Labels,
})
}
if resp.NextPage == 0 {

View File

@@ -12,8 +12,6 @@ type PullRequest struct {
Branch string
// HeadSHA is the SHA of the HEAD from which the pull request originated.
HeadSHA string
// Labels of the pull request.
Labels []string
}
type PullRequestService interface {

View File

@@ -85,12 +85,12 @@ func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revi
gitRepoClient, err := git.NewClient(repo.Repo, repo.GetGitCreds(a.storecreds), repo.IsInsecure(), repo.IsLFSEnabled(), repo.Proxy)
if err != nil {
return nil, fmt.Errorf("error creating a new git client: %w", err)
return nil, err
}
err = checkoutRepo(gitRepoClient, revision, a.submoduleEnabled)
if err != nil {
return nil, fmt.Errorf("error while checking out repo: %w", err)
return nil, err
}
filteredPaths := []string{}
@@ -99,7 +99,7 @@ func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revi
if err := filepath.Walk(repoRoot, func(path string, info os.FileInfo, fnErr error) error {
if fnErr != nil {
return fmt.Errorf("error walking the file tree: %w", fnErr)
return fnErr
}
if !info.IsDir() { // Skip files: directories only
return nil
@@ -112,7 +112,7 @@ func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revi
relativePath, err := filepath.Rel(repoRoot, path)
if err != nil {
return fmt.Errorf("error constructing relative repo path: %w", err)
return err
}
if relativePath == "." { // Exclude '.' from results

View File

@@ -35,7 +35,7 @@ func NewGiteaProvider(ctx context.Context, owner, token, url string, allBranches
}
client, err := gitea.NewClient(url, gitea.SetToken(token), gitea.SetHTTPClient(httpClient))
if err != nil {
return nil, fmt.Errorf("error creating a new gitea client: %w", err)
return nil, err
}
return &GiteaProvider{
client: client,

View File

@@ -88,7 +88,7 @@ func CreateOrUpdate(ctx context.Context, c client.Client, obj client.Object, f c
// mutate wraps a MutateFn and applies validation to its result
func mutate(f controllerutil.MutateFn, key client.ObjectKey, obj client.Object) error {
if err := f(); err != nil {
return fmt.Errorf("error while wrapping using MutateFn: %w", err)
return err
}
if newKey := client.ObjectKeyFromObject(obj); key != newKey {
return fmt.Errorf("MutateFn cannot mutate object name and/or object namespace")

View File

@@ -11,7 +11,6 @@ var Policies = map[string]Policy{
"sync": &SyncPolicy{},
"create-only": &CreateOnlyPolicy{},
"create-update": &CreateUpdatePolicy{},
"create-delete": &CreateDeletePolicy{},
}
type SyncPolicy struct{}
@@ -43,13 +42,3 @@ func (p *CreateOnlyPolicy) Update() bool {
func (p *CreateOnlyPolicy) Delete() bool {
return false
}
type CreateDeletePolicy struct{}
func (p *CreateDeletePolicy) Update() bool {
return false
}
func (p *CreateDeletePolicy) Delete() bool {
return true
}

View File

@@ -12,7 +12,7 @@ import (
"text/template"
"unsafe"
"github.com/Masterminds/sprig/v3"
"github.com/Masterminds/sprig"
"github.com/valyala/fasttemplate"
log "github.com/sirupsen/logrus"

View File

@@ -41,7 +41,7 @@ func TestRenderTemplateParams(t *testing.T) {
Namespace: "default",
},
Spec: argoappsv1.ApplicationSpec{
Source: &argoappsv1.ApplicationSource{
Source: argoappsv1.ApplicationSource{
Path: "",
RepoURL: "",
TargetRevision: "",
@@ -220,7 +220,7 @@ func TestRenderTemplateParamsGoTemplate(t *testing.T) {
Namespace: "default",
},
Spec: argoappsv1.ApplicationSpec{
Source: &argoappsv1.ApplicationSource{
Source: argoappsv1.ApplicationSource{
Path: "",
RepoURL: "",
TargetRevision: "",
@@ -511,7 +511,7 @@ func TestRenderTemplateParamsFinalizers(t *testing.T) {
emptyApplication := &argoappsv1.Application{
Spec: argoappsv1.ApplicationSpec{
Source: &argoappsv1.ApplicationSource{
Source: argoappsv1.ApplicationSource{
Path: "",
RepoURL: "",
TargetRevision: "",

4
argocd-cosign.pub Normal file
View File

@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEesHEB7vX5Y2RxXypjMy1nI1z7iRG
JI9/gt/sYqzpsa65aaNP4npM43DDxoIy/MQBo9s/mxGxmA+8UXeDpVC9vw==
-----END PUBLIC KEY-----

View File

@@ -735,42 +735,6 @@
}
}
},
"/api/v1/applications/{name}/links": {
"get": {
"tags": [
"ApplicationService"
],
"summary": "ListLinks returns the list of all application deep links",
"operationId": "ApplicationService_ListLinks",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
},
{
"type": "string",
"name": "namespace",
"in": "query"
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/applicationLinksResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
}
}
},
"/api/v1/applications/{name}/logs": {
"get": {
"tags": [
@@ -1421,67 +1385,6 @@
}
}
},
"/api/v1/applications/{name}/resource/links": {
"get": {
"tags": [
"ApplicationService"
],
"summary": "ListResourceLinks returns the list of all resource deep links",
"operationId": "ApplicationService_ListResourceLinks",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
},
{
"type": "string",
"name": "namespace",
"in": "query"
},
{
"type": "string",
"name": "resourceName",
"in": "query"
},
{
"type": "string",
"name": "version",
"in": "query"
},
{
"type": "string",
"name": "group",
"in": "query"
},
{
"type": "string",
"name": "kind",
"in": "query"
},
{
"type": "string",
"name": "appNamespace",
"in": "query"
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/applicationLinksResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
}
}
},
"/api/v1/applications/{name}/revisions/{revision}/metadata": {
"get": {
"tags": [
@@ -2657,37 +2560,6 @@
}
}
},
"/api/v1/projects/{name}/links": {
"get": {
"tags": [
"ProjectService"
],
"summary": "ListLinks returns all deep links for the particular project",
"operationId": "ProjectService_ListLinks",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/applicationLinksResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
}
}
},
"/api/v1/projects/{name}/syncwindows": {
"get": {
"tags": [
@@ -3424,18 +3296,6 @@
"description": "Reference between project and repository that allow you automatically to be added as item inside SourceRepos project entity.",
"name": "project",
"in": "query"
},
{
"type": "string",
"description": "Google Cloud Platform service account key.",
"name": "gcpServiceAccountKey",
"in": "query"
},
{
"type": "boolean",
"description": "Whether to force HTTP basic auth.",
"name": "forceHttpBasicAuth",
"in": "query"
}
],
"responses": {
@@ -3594,29 +3454,6 @@
}
}
},
"/api/v1/settings/plugins": {
"get": {
"tags": [
"SettingsService"
],
"summary": "Get returns Argo CD plugins",
"operationId": "SettingsService_GetPlugins",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/clusterSettingsPluginsResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
}
}
},
"/api/v1/stream/applications": {
"get": {
"tags": [
@@ -4063,34 +3900,6 @@
}
}
},
"applicationLinkInfo": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"iconClass": {
"type": "string"
},
"title": {
"type": "string"
},
"url": {
"type": "string"
}
}
},
"applicationLinksResponse": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/applicationLinkInfo"
}
}
}
},
"applicationLogEntry": {
"type": "object",
"properties": {
@@ -4288,9 +4097,6 @@
"appLabelKey": {
"type": "string"
},
"appsInAnyNamespaceEnabled": {
"type": "boolean"
},
"configManagementPlugins": {
"type": "array",
"items": {
@@ -4371,17 +4177,6 @@
}
}
},
"clusterSettingsPluginsResponse": {
"type": "object",
"properties": {
"plugins": {
"type": "array",
"items": {
"$ref": "#/definitions/clusterPlugin"
}
}
}
},
"gpgkeyGnuPGPublicKeyCreateResponse": {
"type": "object",
"title": "Response to a public key creation request",
@@ -4402,24 +4197,6 @@
"type": "object",
"title": "Generic (empty) response for GPG public key CRUD requests"
},
"intstrIntOrString": {
"description": "+protobuf=true\n+protobuf.options.(gogoproto.goproto_stringer)=false\n+k8s:openapi-gen=true",
"type": "object",
"title": "IntOrString is a type that can hold an int32 or a string. When used in\nJSON or YAML marshalling and unmarshalling, it produces or consumes the\ninner type. This allows you to have, for example, a JSON field that can\naccept a name or number.\nTODO: Rename to Int32OrString",
"properties": {
"intVal": {
"type": "integer",
"format": "int32"
},
"strVal": {
"type": "string"
},
"type": {
"type": "string",
"format": "int64"
}
}
},
"notificationService": {
"type": "object",
"properties": {
@@ -4728,65 +4505,6 @@
}
}
},
"repositoryParameterAnnouncement": {
"type": "object",
"properties": {
"array": {
"description": "array is the default value of the parameter if the parameter is an array.",
"type": "array",
"items": {
"type": "string"
}
},
"collectionType": {
"description": "collectionType is the type of value this parameter holds - either a single value (a string) or a collection\n(array or map). If collectionType is set, only the field with that type will be used. If collectionType is not\nset, `string` is the default. If collectionType is set to an invalid value, a validation error is thrown.",
"type": "string"
},
"itemType": {
"description": "itemType determines the primitive data type represented by the parameter. Parameters are always encoded as\nstrings, but this field lets them be interpreted as other primitive types.",
"type": "string"
},
"map": {
"description": "map is the default value of the parameter if the parameter is a map.",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"name": {
"description": "name is the name identifying a parameter.",
"type": "string"
},
"required": {
"description": "required defines if this given parameter is mandatory.",
"type": "boolean"
},
"string": {
"description": "string is the default value of the parameter if the parameter is a string.",
"type": "string"
},
"title": {
"description": "title is a human-readable text of the parameter name.",
"type": "string"
},
"tooltip": {
"description": "tooltip is a human-readable description of the parameter.",
"type": "string"
}
}
},
"repositoryPluginAppSpec": {
"type": "object",
"title": "PluginAppSpec contains details about a plugin-type Application",
"properties": {
"parametersAnnouncement": {
"type": "array",
"items": {
"$ref": "#/definitions/repositoryParameterAnnouncement"
}
}
}
},
"repositoryRefs": {
"type": "object",
"title": "A subset of the repository's named refs",
@@ -4833,9 +4551,6 @@
"kustomize": {
"$ref": "#/definitions/repositoryKustomizeAppSpec"
},
"plugin": {
"$ref": "#/definitions/repositoryPluginAppSpec"
},
"type": {
"type": "string"
}
@@ -5658,23 +5373,6 @@
}
}
},
"v1alpha1ApplicationMatchExpression": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"values": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"v1alpha1ApplicationSet": {
"type": "object",
"title": "ApplicationSet is a set of Application resources\n+genclient\n+genclient:noStatus\n+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object\n+kubebuilder:resource:path=applicationsets,shortName=appset;appsets\n+kubebuilder:subresource:status",
@@ -5690,31 +5388,6 @@
}
}
},
"v1alpha1ApplicationSetApplicationStatus": {
"type": "object",
"title": "ApplicationSetApplicationStatus contains details about each Application managed by the ApplicationSet",
"properties": {
"application": {
"type": "string",
"title": "Application contains the name of the Application resource"
},
"lastTransitionTime": {
"$ref": "#/definitions/v1Time"
},
"message": {
"type": "string",
"title": "Message contains human-readable message indicating details about the status"
},
"status": {
"type": "string",
"title": "Status contains the AppSet's perceived status of the managed Application resource: (Waiting, Pending, Progressing, Healthy)"
},
"step": {
"type": "string",
"title": "Step tracks which step this Application should be updated in"
}
}
},
"v1alpha1ApplicationSetCondition": {
"type": "object",
"title": "ApplicationSetCondition contains details about an applicationset condition, which is usally an error or warning",
@@ -5821,31 +5494,6 @@
}
}
},
"v1alpha1ApplicationSetRolloutStep": {
"type": "object",
"properties": {
"matchExpressions": {
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1ApplicationMatchExpression"
}
},
"maxUpdate": {
"$ref": "#/definitions/intstrIntOrString"
}
}
},
"v1alpha1ApplicationSetRolloutStrategy": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1ApplicationSetRolloutStep"
}
}
}
},
"v1alpha1ApplicationSetSpec": {
"description": "ApplicationSetSpec represents a class of application set state.",
"type": "object",
@@ -5859,9 +5507,6 @@
"goTemplate": {
"type": "boolean"
},
"strategy": {
"$ref": "#/definitions/v1alpha1ApplicationSetStrategy"
},
"syncPolicy": {
"$ref": "#/definitions/v1alpha1ApplicationSetSyncPolicy"
},
@@ -5874,12 +5519,6 @@
"type": "object",
"title": "ApplicationSetStatus defines the observed state of ApplicationSet",
"properties": {
"applicationStatus": {
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1ApplicationSetApplicationStatus"
}
},
"conditions": {
"type": "array",
"title": "INSERT ADDITIONAL STATUS FIELD - define observed state of cluster\nImportant: Run \"make\" to regenerate code after modifying this file",
@@ -5889,18 +5528,6 @@
}
}
},
"v1alpha1ApplicationSetStrategy": {
"description": "ApplicationSetStrategy configures how generated Applications are updated in sequence.",
"type": "object",
"properties": {
"rollingSync": {
"$ref": "#/definitions/v1alpha1ApplicationSetRolloutStrategy"
},
"type": {
"type": "string"
}
}
},
"v1alpha1ApplicationSetSyncPolicy": {
"description": "ApplicationSetSyncPolicy configures how generated Applications will relate to their\nApplicationSet.",
"type": "object",
@@ -5977,10 +5604,6 @@
"plugin": {
"$ref": "#/definitions/v1alpha1ApplicationSourcePlugin"
},
"ref": {
"description": "Ref is reference to another source within sources field. This field will not be used if used with a `source` tag.",
"type": "string"
},
"repoURL": {
"type": "string",
"title": "RepoURL is the URL to the repository (Git or Helm) that contains the application manifests"
@@ -6149,39 +5772,6 @@
},
"name": {
"type": "string"
},
"parameters": {
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1ApplicationSourcePluginParameter"
}
}
}
},
"v1alpha1ApplicationSourcePluginParameter": {
"type": "object",
"properties": {
"array": {
"description": "Array is the value of an array type parameter.",
"type": "array",
"items": {
"type": "string"
}
},
"map": {
"description": "Map is the value of a map type parameter.",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"name": {
"description": "Name is the name identifying a parameter.",
"type": "string"
},
"string": {
"description": "String_ is the value of a string type parameter.",
"type": "string"
}
}
},
@@ -6218,13 +5808,6 @@
"source": {
"$ref": "#/definitions/v1alpha1ApplicationSource"
},
"sources": {
"type": "array",
"title": "Sources is a reference to the location of the application's manifests or chart",
"items": {
"$ref": "#/definitions/v1alpha1ApplicationSource"
}
},
"syncPolicy": {
"$ref": "#/definitions/v1alpha1SyncPolicy"
}
@@ -6275,13 +5858,6 @@
"type": "string",
"title": "SourceType specifies the type of this application"
},
"sourceTypes": {
"type": "array",
"title": "SourceTypes specifies the type of the sources included in the application",
"items": {
"type": "string"
}
},
"summary": {
"$ref": "#/definitions/v1alpha1ApplicationSummary"
},
@@ -6579,13 +6155,6 @@
},
"source": {
"$ref": "#/definitions/v1alpha1ApplicationSource"
},
"sources": {
"type": "array",
"title": "Sources is a reference to the application's multiple sources used for comparison",
"items": {
"$ref": "#/definitions/v1alpha1ApplicationSource"
}
}
}
},
@@ -6720,9 +6289,6 @@
"$ref": "#/definitions/v1alpha1GitFileGeneratorItem"
}
},
"pathParamPrefix": {
"type": "string"
},
"repoURL": {
"type": "string"
},
@@ -6978,23 +6544,6 @@
}
}
},
"v1alpha1ManagedNamespaceMetadata": {
"type": "object",
"properties": {
"annotations": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"labels": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
},
"v1alpha1MatrixGenerator": {
"description": "MatrixGenerator generates the cartesian product of two sets of parameters. The parameters are defined by two nested\ngenerators.",
"type": "object",
@@ -7348,14 +6897,6 @@
"type": "boolean",
"title": "EnableOCI specifies whether helm-oci support should be enabled for this repo"
},
"forceHttpBasicAuth": {
"type": "boolean",
"title": "ForceHttpBasicAuth specifies whether Argo CD should attempt to force basic auth for HTTP connections"
},
"gcpServiceAccountKey": {
"type": "string",
"title": "GCPServiceAccountKey specifies the service account key in JSON format to be used for getting credentials to Google Cloud Source repos"
},
"githubAppEnterpriseBaseUrl": {
"type": "string",
"title": "GithubAppEnterpriseBaseURL specifies the GitHub API URL for GitHub app authentication. If empty will default to https://api.github.com"
@@ -7378,10 +6919,6 @@
"type": "string",
"title": "Password for authenticating at the repo server"
},
"proxy": {
"type": "string",
"title": "Proxy specifies the HTTP/HTTPS proxy used to access repos at the repo server"
},
"sshPrivateKey": {
"type": "string",
"title": "SSHPrivateKey contains the private key data for authenticating at the repo server using SSH (only Git repos)"
@@ -7438,14 +6975,6 @@
"type": "boolean",
"title": "EnableOCI specifies whether helm-oci support should be enabled for this repo"
},
"forceHttpBasicAuth": {
"type": "boolean",
"title": "ForceHttpBasicAuth specifies whether Argo CD should attempt to force basic auth for HTTP connections"
},
"gcpServiceAccountKey": {
"type": "string",
"title": "GCPServiceAccountKey specifies the service account key in JSON format to be used for getting credentials to Google Cloud Source repos"
},
"githubAppEnterpriseBaseUrl": {
"type": "string",
"title": "GithubAppEnterpriseBaseURL specifies the base URL of GitHub Enterprise installation. If empty will default to https://api.github.com"
@@ -7936,22 +7465,8 @@
"type": "string",
"title": "Revision holds the revision the sync was performed against"
},
"revisions": {
"type": "array",
"title": "Revisions holds the revision of each source in sources field the sync was performed against",
"items": {
"type": "string"
}
},
"source": {
"$ref": "#/definitions/v1alpha1ApplicationSource"
},
"sources": {
"type": "array",
"title": "Sources is a reference to the application sources used for the sync operation",
"items": {
"$ref": "#/definitions/v1alpha1ApplicationSource"
}
}
}
},
@@ -7967,8 +7482,8 @@
"$ref": "#/definitions/v1Time"
},
"message": {
"description": "Message contains the message associated with the revision, most likely the commit message.",
"type": "string"
"type": "string",
"title": "Message contains the message associated with the revision, most likely the commit message.\nThe message is truncated to the first newline or 64 characters (which ever comes first)"
},
"signatureInfo": {
"description": "SignatureInfo contains a hint on the signer if the revision was signed with GPG, and signature verification is enabled.",
@@ -8252,23 +7767,9 @@
"description": "Revision is the revision (Git) or chart version (Helm) which to sync the application to\nIf omitted, will use the revision specified in app spec.",
"type": "string"
},
"revisions": {
"description": "Revisions is the list of revision (Git) or chart version (Helm) which to sync each source in sources field for the application to\nIf omitted, will use the revision specified in app spec.",
"type": "array",
"items": {
"type": "string"
}
},
"source": {
"$ref": "#/definitions/v1alpha1ApplicationSource"
},
"sources": {
"type": "array",
"title": "Sources overrides the source definition set in the application.\nThis is typically set in a Rollback operation and is nil during a Sync operation",
"items": {
"$ref": "#/definitions/v1alpha1ApplicationSource"
}
},
"syncOptions": {
"type": "array",
"title": "SyncOptions provide per-sync sync-options, e.g. Validate=false",
@@ -8314,22 +7815,8 @@
"type": "string",
"title": "Revision holds the revision this sync operation was performed to"
},
"revisions": {
"type": "array",
"title": "Revisions holds the revision this sync operation was performed for respective indexed source in sources field",
"items": {
"type": "string"
}
},
"source": {
"$ref": "#/definitions/v1alpha1ApplicationSource"
},
"sources": {
"type": "array",
"title": "Source records the application source information of the sync, used for comparing auto-sync",
"items": {
"$ref": "#/definitions/v1alpha1ApplicationSource"
}
}
}
},
@@ -8340,9 +7827,6 @@
"automated": {
"$ref": "#/definitions/v1alpha1SyncPolicyAutomated"
},
"managedNamespaceMetadata": {
"$ref": "#/definitions/v1alpha1ManagedNamespaceMetadata"
},
"retry": {
"$ref": "#/definitions/v1alpha1RetryStrategy"
},
@@ -8384,13 +7868,6 @@
"type": "string",
"title": "Revision contains information about the revision the comparison has been performed to"
},
"revisions": {
"type": "array",
"title": "Revisions contains information about the revisions of multiple sources the comparison has been performed to",
"items": {
"type": "string"
}
},
"status": {
"type": "string",
"title": "Status is the sync state of the comparison"

View File

@@ -39,24 +39,23 @@ import (
argosettings "github.com/argoproj/argo-cd/v2/util/settings"
)
// TODO: load this using Cobra.
// TODO: load this using Cobra. https://github.com/argoproj/argo-cd/issues/10157
func getSubmoduleEnabled() bool {
return env.ParseBoolFromEnv(common.EnvGitSubmoduleEnabled, true)
}
func NewCommand() *cobra.Command {
var (
clientConfig clientcmd.ClientConfig
metricsAddr string
probeBindAddr string
webhookAddr string
enableLeaderElection bool
namespace string
argocdRepoServer string
policy string
debugLog bool
dryRun bool
enableProgressiveSyncs bool
clientConfig clientcmd.ClientConfig
metricsAddr string
probeBindAddr string
webhookAddr string
enableLeaderElection bool
namespace string
argocdRepoServer string
policy string
debugLog bool
dryRun bool
)
scheme := runtime.NewScheme()
_ = clientgoscheme.AddToScheme(scheme)
@@ -90,7 +89,7 @@ func NewCommand() *cobra.Command {
policyObj, exists := utils.Policies[policy]
if !exists {
log.Info("Policy value can be: sync, create-only, create-update, create-delete")
log.Info("Policy value can be: sync, create-only, create-update")
os.Exit(1)
}
@@ -169,16 +168,15 @@ func NewCommand() *cobra.Command {
go func() { errors.CheckError(askPassServer.Run(askpass.SocketPath)) }()
if err = (&controllers.ApplicationSetReconciler{
Generators: topLevelGenerators,
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("applicationset-controller"),
Renderer: &utils.Render{},
Policy: policyObj,
ArgoAppClientset: appSetConfig,
KubeClientset: k8sClient,
ArgoDB: argoCDDB,
EnableProgressiveSyncs: enableProgressiveSyncs,
Generators: topLevelGenerators,
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("applicationset-controller"),
Renderer: &utils.Render{},
Policy: policyObj,
ArgoAppClientset: appSetConfig,
KubeClientset: k8sClient,
ArgoDB: argoCDDB,
}).SetupWithManager(mgr); err != nil {
log.Error(err, "unable to create controller", "controller", "ApplicationSet")
os.Exit(1)
@@ -197,17 +195,16 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
command.Flags().StringVar(&probeBindAddr, "probe-addr", ":8081", "The address the probe endpoint binds to.")
command.Flags().StringVar(&webhookAddr, "webhook-addr", ":7000", "The address the webhook endpoint binds to.")
command.Flags().BoolVar(&enableLeaderElection, "enable-leader-election", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_LEADER_ELECTION", false),
command.Flags().BoolVar(&enableLeaderElection, "enable-leader-election", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
command.Flags().StringVar(&namespace, "namespace", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACE", ""), "Argo CD repo namespace (default: argocd)")
command.Flags().StringVar(&argocdRepoServer, "argocd-repo-server", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER", common.DefaultRepoServerAddr), "Argo CD repo server address")
command.Flags().StringVar(&policy, "policy", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_POLICY", "sync"), "Modify how application is synced between the generator and the cluster. Default is 'sync' (create & update & delete), options: 'create-only', 'create-update' (no deletion), 'create-delete' (no update)")
command.Flags().BoolVar(&debugLog, "debug", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG", false), "Print debug logs. Takes precedence over loglevel")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
command.Flags().BoolVar(&dryRun, "dry-run", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_DRY_RUN", false), "Enable dry run mode")
command.Flags().BoolVar(&enableProgressiveSyncs, "enable-progressive-syncs", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS", false), "Enable use of the experimental progressive syncs feature.")
command.Flags().StringVar(&namespace, "namespace", "", "Argo CD repo namespace (default: argocd)")
command.Flags().StringVar(&argocdRepoServer, "argocd-repo-server", "argocd-repo-server:8081", "Argo CD repo server address")
command.Flags().StringVar(&policy, "policy", "sync", "Modify how application is synced between the generator and the cluster. Default is 'sync' (create & update & delete), options: 'create-only', 'create-update' (no deletion)")
command.Flags().BoolVar(&debugLog, "debug", false, "Print debug logs. Takes precedence over loglevel")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", "text", "Set the logging format. One of: text|json")
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")
command.Flags().BoolVar(&dryRun, "dry-run", false, "Enable dry run mode")
return &command
}

View File

@@ -156,7 +156,7 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&logLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")
command.Flags().StringVar(&logFormat, "logformat", "text", "Set the logging format. One of: text|json")
command.Flags().IntVar(&metricsPort, "metrics-port", defaultMetricsPort, "Metrics port")
command.Flags().StringVar(&argocdRepoServer, "argocd-repo-server", common.DefaultRepoServerAddr, "Argo CD repo server address")
command.Flags().StringVar(&argocdRepoServer, "argocd-repo-server", "argocd-repo-server:8081", "Argo CD repo server address")
command.Flags().BoolVar(&argocdRepoServerPlaintext, "argocd-repo-server-plaintext", false, "Use a plaintext client (non-TLS) to connect to repository server")
command.Flags().BoolVar(&argocdRepoServerStrictTLS, "argocd-repo-server-strict-tls", false, "Perform strict validation of TLS certificates when connecting to repo server")
command.Flags().StringVar(&configMapName, "config-map-name", "argocd-notifications-cm", "Set notifications ConfigMap name")

View File

@@ -71,7 +71,6 @@ func NewCommand() *cobra.Command {
dexServerStrictTLS bool
staticAssetsDir string
applicationNamespaces []string
enableProxyExtension bool
)
var command = &cobra.Command{
Use: cliName,
@@ -185,7 +184,6 @@ func NewCommand() *cobra.Command {
RedisClient: redisClient,
StaticAssetsDir: staticAssetsDir,
ApplicationNamespaces: applicationNamespaces,
EnableProxyExtension: enableProxyExtension,
}
stats.RegisterStackDumper()
@@ -237,7 +235,6 @@ func NewCommand() *cobra.Command {
command.Flags().BoolVar(&dexServerPlaintext, "dex-server-plaintext", env.ParseBoolFromEnv("ARGOCD_SERVER_DEX_SERVER_PLAINTEXT", false), "Use a plaintext client (non-TLS) to connect to dex server")
command.Flags().BoolVar(&dexServerStrictTLS, "dex-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_SERVER_DEX_SERVER_STRICT_TLS", false), "Perform strict validation of TLS certificates when connecting to dex server")
command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces where application resources can be managed in")
command.Flags().BoolVar(&enableProxyExtension, "enable-proxy-extension", env.ParseBoolFromEnv("ARGOCD_SERVER_ENABLE_PROXY_EXTENSION", false), "Enable Proxy Extension feature")
tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(command)
cacheSrc = servercache.AddCacheFlagsToCmd(command, func(client *redis.Client) {
redisClient = client

View File

@@ -44,7 +44,6 @@ func NewAccountCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
command.AddCommand(NewAccountGenerateTokenCommand(clientOpts))
command.AddCommand(NewAccountGetCommand(clientOpts))
command.AddCommand(NewAccountDeleteTokenCommand(clientOpts))
command.AddCommand(NewBcryptCmd())
return command
}

View File

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

View File

@@ -292,11 +292,11 @@ func saveToFile(err error, outputFormat string, result reconcileResults, outputP
switch outputFormat {
case "yaml":
if data, err = yaml.Marshal(result); err != nil {
return fmt.Errorf("error marshalling yaml: %w", err)
return err
}
case "json":
if data, err = json.Marshal(result); err != nil {
return fmt.Errorf("error marshalling json: %w", err)
return err
}
default:
return fmt.Errorf("format %s is not supported", outputFormat)
@@ -401,12 +401,7 @@ func reconcileApplications(
return nil, err
}
sources := make([]v1alpha1.ApplicationSource, 0)
revisions := make([]string, 0)
sources = append(sources, app.Spec.GetSource())
revisions = append(revisions, app.Spec.GetSource().TargetRevision)
res := appStateManager.CompareAppState(&app, proj, revisions, sources, false, false, nil, false)
res := appStateManager.CompareAppState(&app, proj, app.Spec.Source.TargetRevision, app.Spec.Source, false, false, nil)
items = append(items, appReconcileResult{
Name: app.Name,
Conditions: app.Status.Conditions,

View File

@@ -80,7 +80,6 @@ func TestGetReconcileResults_Refresh(t *testing.T) {
Namespace: "default",
},
Spec: v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{},
Project: "default",
Destination: v1alpha1.ApplicationDestination{
Server: v1alpha1.KubernetesInternalAPIServerAddr,

View File

@@ -221,11 +221,11 @@ func printStatsSummary(clusters []ClusterWithInfo) {
func runClusterNamespacesCommand(ctx context.Context, clientConfig clientcmd.ClientConfig, action func(appClient *versioned.Clientset, argoDB db.ArgoDB, clusters map[string][]string) error) error {
clientCfg, err := clientConfig.ClientConfig()
if err != nil {
return fmt.Errorf("error while creating client config: %w", err)
return err
}
namespace, _, err := clientConfig.Namespace()
if err != nil {
return fmt.Errorf("error while getting namespace from client config: %w", err)
return err
}
kubeClient := kubernetes.NewForConfigOrDie(clientCfg)
@@ -235,16 +235,17 @@ func runClusterNamespacesCommand(ctx context.Context, clientConfig clientcmd.Cli
argoDB := db.NewDB(namespace, settingsMgr, kubeClient)
clustersList, err := argoDB.ListClusters(ctx)
if err != nil {
return fmt.Errorf("error listing clusters: %w", err)
return err
}
appItems, err := appClient.ArgoprojV1alpha1().Applications(namespace).List(ctx, v1.ListOptions{})
if err != nil {
return fmt.Errorf("error listing application: %w", err)
return err
}
apps := appItems.Items
for i, app := range apps {
if err := argo.ValidateDestination(ctx, &app.Spec.Destination, argoDB); err != nil {
return fmt.Errorf("error validating application destination: %w", err)
err := argo.ValidateDestination(ctx, &app.Spec.Destination, argoDB)
if err != nil {
return err
}
apps[i] = app
}
@@ -265,7 +266,9 @@ func runClusterNamespacesCommand(ctx context.Context, clientConfig clientcmd.Cli
}
}
} else {
nsSet[app.Spec.Destination.Namespace] = true
if app.Spec.Destination.Server == cluster.Server {
nsSet[app.Spec.Destination.Namespace] = true
}
}
}
var namespaces []string
@@ -346,14 +349,15 @@ func NewClusterEnableNamespacedMode() *cobra.Command {
cluster, err := argoDB.GetCluster(ctx, server)
if err != nil {
return fmt.Errorf("error getting cluster from server: %w", err)
return err
}
cluster.Namespaces = namespaces
cluster.ClusterResources = clusterResources
fmt.Printf("Setting cluster %s namespaces to %v...", server, namespaces)
if !dryRun {
if _, err = argoDB.UpdateCluster(ctx, cluster); err != nil {
return fmt.Errorf("error updating cluster: %w", err)
_, err = argoDB.UpdateCluster(ctx, cluster)
if err != nil {
return err
}
fmt.Println("done")
} else {
@@ -401,7 +405,7 @@ func NewClusterDisableNamespacedMode() *cobra.Command {
cluster, err := argoDB.GetCluster(ctx, server)
if err != nil {
return fmt.Errorf("error getting cluster from server: %w", err)
return err
}
if len(cluster.Namespaces) == 0 {
@@ -411,8 +415,9 @@ func NewClusterDisableNamespacedMode() *cobra.Command {
cluster.Namespaces = nil
fmt.Printf("Disabling namespaced mode for cluster %s...", server)
if !dryRun {
if _, err = argoDB.UpdateCluster(ctx, cluster); err != nil {
return fmt.Errorf("error updating cluster: %w", err)
_, err = argoDB.UpdateCluster(ctx, cluster)
if err != nil {
return err
}
fmt.Println("done")
} else {

View File

@@ -43,7 +43,7 @@ func PrintResources(output string, out io.Writer, resources ...interface{}) erro
}
filteredResource, err := omitFields(resource)
if err != nil {
return fmt.Errorf("error omitting filtered fields from the resource: %w", err)
return err
}
resources[i] = filteredResource
}
@@ -56,14 +56,14 @@ func PrintResources(output string, out io.Writer, resources ...interface{}) erro
case "json":
jsonBytes, err := json.MarshalIndent(obj, "", " ")
if err != nil {
return fmt.Errorf("error marshaling json: %w", err)
return err
}
_, _ = fmt.Fprintln(out, string(jsonBytes))
case "yaml":
yamlBytes, err := yaml.Marshal(obj)
if err != nil {
return fmt.Errorf("error marshaling yaml: %w", err)
return err
}
// marshaled YAML already ends with the new line character
_, _ = fmt.Fprint(out, string(yamlBytes))

View File

@@ -1,46 +0,0 @@
package admin
import (
"context"
"fmt"
"github.com/spf13/cobra"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"github.com/argoproj/argo-cd/v2/util/cli"
"github.com/argoproj/argo-cd/v2/util/errors"
)
const initialPasswordSecretName = "argocd-initial-admin-secret"
// NewInitialPasswordCommand defines a new command to retrieve Argo CD initial password.
func NewInitialPasswordCommand() *cobra.Command {
var (
clientConfig clientcmd.ClientConfig
)
var command = cobra.Command{
Use: "initial-password",
Short: "Prints initial password to log in to Argo CD for the first time",
Run: func(c *cobra.Command, args []string) {
config, err := clientConfig.ClientConfig()
errors.CheckError(err)
namespace, _, err := clientConfig.Namespace()
errors.CheckError(err)
kubeClientset := kubernetes.NewForConfigOrDie(config)
secret, err := kubeClientset.CoreV1().Secrets(namespace).Get(context.Background(), initialPasswordSecretName, v1.GetOptions{})
errors.CheckError(err)
if initialPass, ok := secret.Data["password"]; ok {
fmt.Println(string(initialPass))
fmt.Println("\n This password must be only used for first time login. We strongly recommend you update the password using `argocd account update-password`.")
}
},
}
clientConfig = cli.AddKubectlFlagsToCmd(&command)
return &command
}

View File

@@ -33,7 +33,7 @@ func NewNotificationsCommand() *cobra.Command {
var argocdService service.Service
toolsCommand := cmd.NewToolsCommand(
"notifications",
"argocd admin notifications",
"notifications",
applications,
settings.GetFactorySettings(argocdService, "argocd-notifications-secret", "argocd-notifications-cm"), func(clientConfig clientcmd.ClientConfig) {
k8sCfg, err := clientConfig.ClientConfig()
@@ -64,7 +64,7 @@ func NewNotificationsCommand() *cobra.Command {
log.Fatalf("Failed to initialize Argo CD service: %v", err)
}
})
toolsCommand.PersistentFlags().StringVar(&argocdRepoServer, "argocd-repo-server", common.DefaultRepoServerAddr, "Argo CD repo server address")
toolsCommand.PersistentFlags().StringVar(&argocdRepoServer, "argocd-repo-server", "argocd-repo-server:8081", "Argo CD repo server address")
toolsCommand.PersistentFlags().BoolVar(&argocdRepoServerPlaintext, "argocd-repo-server-plaintext", false, "Use a plaintext client (non-TLS) to connect to repository server")
toolsCommand.PersistentFlags().BoolVar(&argocdRepoServerStrictTLS, "argocd-repo-server-strict-tls", false, "Perform strict validation of TLS certificates when connecting to repo server")
return toolsCommand

View File

@@ -106,13 +106,13 @@ func saveProject(ctx context.Context, updated v1alpha1.AppProject, orig v1alpha1
errors.CheckError(err)
live, err := kube.ToUnstructured(&orig)
if err != nil {
return fmt.Errorf("error converting project to unstructured: %w", err)
return err
}
_ = cli.PrintDiff(updated.Name, target, live)
if !dryRun {
_, err = projectsIf.Update(ctx, &updated, v1.UpdateOptions{})
if err != nil {
return fmt.Errorf("error while updating project: %w", err)
return err
}
}
return nil
@@ -188,7 +188,7 @@ func NewUpdatePolicyRuleCommand() *cobra.Command {
func updateProjects(ctx context.Context, projIf appclient.AppProjectInterface, projectGlob string, rolePattern string, action string, modification func(string, string) string, dryRun bool) error {
projects, err := projIf.List(ctx, v1.ListOptions{})
if err != nil {
return fmt.Errorf("error listing the projects: %w", err)
return err
}
for _, proj := range projects.Items {
if !globMatch(projectGlob, proj.Name) {
@@ -225,7 +225,7 @@ func updateProjects(ctx context.Context, projIf appclient.AppProjectInterface, p
if updated {
err = saveProject(ctx, proj, *origProj, projIf, dryRun)
if err != nil {
return fmt.Errorf("error saving the project: %w", err)
return err
}
}
}

View File

@@ -206,7 +206,7 @@ var validatorsByGroup = map[string]settingValidator{
}
ssoProvider = "Dex"
} else if general.OIDCConfigRAW != "" {
if err := settings.ValidateOIDCConfig(general.OIDCConfigRAW); err != nil {
if _, err := settings.UnmarshalOIDCConfig(general.OIDCConfigRAW); err != nil {
return "", fmt.Errorf("invalid oidc.config: %v", err)
}
ssoProvider = "OIDC"

View File

@@ -150,7 +150,7 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
c.HelpFunc()(c, args)
os.Exit(1)
}
if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" {
if app.Spec.Source.Plugin != nil && app.Spec.Source.Plugin.Name != "" {
log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning)
}
if appNamespace != "" {
@@ -294,7 +294,7 @@ func NewApplicationGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
})
errors.CheckError(err)
if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" {
if app.Spec.Source.Plugin != nil && app.Spec.Source.Plugin.Name != "" {
log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning)
}
@@ -440,16 +440,15 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
}
func printAppSummaryTable(app *argoappv1.Application, appURL string, windows *argoappv1.SyncWindows) {
source := app.Spec.GetSource()
fmt.Printf(printOpFmtStr, "Name:", app.QualifiedName())
fmt.Printf(printOpFmtStr, "Project:", app.Spec.GetProject())
fmt.Printf(printOpFmtStr, "Server:", getServer(app))
fmt.Printf(printOpFmtStr, "Namespace:", app.Spec.Destination.Namespace)
fmt.Printf(printOpFmtStr, "URL:", appURL)
fmt.Printf(printOpFmtStr, "Repo:", source.RepoURL)
fmt.Printf(printOpFmtStr, "Target:", source.TargetRevision)
fmt.Printf(printOpFmtStr, "Path:", source.Path)
printAppSourceDetails(&source)
fmt.Printf(printOpFmtStr, "Repo:", app.Spec.Source.RepoURL)
fmt.Printf(printOpFmtStr, "Target:", app.Spec.Source.TargetRevision)
fmt.Printf(printOpFmtStr, "Path:", app.Spec.Source.Path)
printAppSourceDetails(&app.Spec.Source)
var wds []string
var status string
var allow, deny, inactiveAllows bool
@@ -503,11 +502,11 @@ func printAppSummaryTable(app *argoappv1.Application, appURL string, windows *ar
syncStatusStr := string(app.Status.Sync.Status)
switch app.Status.Sync.Status {
case argoappv1.SyncStatusCodeSynced:
syncStatusStr += fmt.Sprintf(" to %s", app.Spec.GetSource().TargetRevision)
syncStatusStr += fmt.Sprintf(" to %s", app.Spec.Source.TargetRevision)
case argoappv1.SyncStatusCodeOutOfSync:
syncStatusStr += fmt.Sprintf(" from %s", app.Spec.GetSource().TargetRevision)
syncStatusStr += fmt.Sprintf(" from %s", app.Spec.Source.TargetRevision)
}
if !git.IsCommitSHA(app.Spec.GetSource().TargetRevision) && !git.IsTruncatedCommitSHA(app.Spec.GetSource().TargetRevision) && len(app.Status.Sync.Revision) > 7 {
if !git.IsCommitSHA(app.Spec.Source.TargetRevision) && !git.IsTruncatedCommitSHA(app.Spec.Source.TargetRevision) && len(app.Status.Sync.Revision) > 7 {
syncStatusStr += fmt.Sprintf(" (%s)", app.Status.Sync.Revision[0:7])
}
fmt.Printf(printOpFmtStr, "Sync Status:", syncStatusStr)
@@ -576,8 +575,8 @@ func truncateString(str string, num int) string {
// printParams prints parameters and overrides
func printParams(app *argoappv1.Application) {
if app.Spec.GetSource().Helm != nil {
printHelmParams(app.Spec.GetSource().Helm)
if app.Spec.Source.Helm != nil {
printHelmParams(app.Spec.Source.Helm)
}
}
@@ -625,7 +624,7 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName, AppNamespace: &appNs})
errors.CheckError(err)
if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" {
if app.Spec.Source.Plugin != nil && app.Spec.Source.Plugin.Name != "" {
log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning)
}
@@ -693,12 +692,11 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName, AppNamespace: &appNs})
errors.CheckError(err)
if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" {
if app.Spec.Source.Plugin != nil && app.Spec.Source.Plugin.Name != "" {
log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning)
}
source := app.Spec.GetSource()
updated, nothingToUnset := unset(&source, opts)
updated, nothingToUnset := unset(&app.Spec.Source, opts)
if nothingToUnset {
c.HelpFunc()(c, args)
os.Exit(1)
@@ -844,19 +842,18 @@ func getLocalObjects(ctx context.Context, app *argoappv1.Application, local, loc
func getLocalObjectsString(ctx context.Context, app *argoappv1.Application, local, localRepoRoot, appLabelKey, kubeVersion string, apiVersions []string, kustomizeOptions *argoappv1.KustomizeOptions,
configManagementPlugins []*argoappv1.ConfigManagementPlugin, trackingMethod string) []string {
source := app.Spec.GetSource()
res, err := repository.GenerateManifests(ctx, local, localRepoRoot, source.TargetRevision, &repoapiclient.ManifestRequest{
Repo: &argoappv1.Repository{Repo: source.RepoURL},
res, err := repository.GenerateManifests(ctx, local, localRepoRoot, app.Spec.Source.TargetRevision, &repoapiclient.ManifestRequest{
Repo: &argoappv1.Repository{Repo: app.Spec.Source.RepoURL},
AppLabelKey: appLabelKey,
AppName: app.Name,
Namespace: app.Spec.Destination.Namespace,
ApplicationSource: &source,
ApplicationSource: &app.Spec.Source,
KustomizeOptions: kustomizeOptions,
KubeVersion: kubeVersion,
ApiVersions: apiVersions,
Plugins: configManagementPlugins,
TrackingMethod: trackingMethod,
}, true, &git.NoopCredsStore{}, resource.MustParse("0"), nil)
}, true, &git.NoopCredsStore{}, resource.MustParse("0"))
errors.CheckError(err)
return res.Manifests
@@ -933,7 +930,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
})
errors.CheckError(err)
if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" {
if app.Spec.Source.Plugin != nil && app.Spec.Source.Plugin.Name != "" {
log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning)
}
@@ -967,7 +964,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
diffOption.serversideRes = res
} else {
fmt.Fprintf(os.Stderr, "Warning: local diff without --server-side-generate is deprecated and does not work with plugins. Server-side generation will be the default in v2.7.")
fmt.Fprintf(os.Stderr, "Warning: local diff without --server-side-generate is deprecated and does not work with plugins. Server-side generation will be the default in v2.6.")
conn, clusterIf := clientset.NewClusterClientOrDie()
defer argoio.Close(conn)
cluster, err := clusterIf.Get(ctx, &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server})
@@ -1250,7 +1247,7 @@ func printApplicationTable(apps []argoappv1.Application, output *string) {
formatConditionsSummary(app),
}
if *output == "wide" {
vals = append(vals, app.Spec.GetSource().RepoURL, app.Spec.GetSource().Path, app.Spec.GetSource().TargetRevision)
vals = append(vals, app.Spec.Source.RepoURL, app.Spec.Source.Path, app.Spec.Source.TargetRevision)
}
_, _ = fmt.Fprintf(w, fmtStr, vals...)
}
@@ -1303,7 +1300,7 @@ func NewApplicationListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
}
var appsWithDeprecatedPlugins []string
for _, app := range appList {
if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" {
if app.Spec.Source.Plugin != nil && app.Spec.Source.Plugin.Name != "" {
appsWithDeprecatedPlugins = append(appsWithDeprecatedPlugins, app.Name)
}
}
@@ -1376,7 +1373,6 @@ const (
resourceFieldCount = 3
resourceFieldNamespaceDelimiter = "/"
resourceFieldNameWithNamespaceCount = 2
resourceExcludeIndicator = "!"
)
// resource is GROUP:KIND:NAMESPACE/NAME or GROUP:KIND:NAME
@@ -1401,12 +1397,6 @@ func parseSelectedResources(resources []string) ([]*argoappv1.SyncOperationResou
}
for _, resource := range resources {
isExcluded := false
// check if the resource flag starts with a '!'
if strings.HasPrefix(resource, resourceExcludeIndicator) {
resource = strings.TrimPrefix(resource, resourceExcludeIndicator)
isExcluded = true
}
fields := strings.Split(resource, resourceFieldDelimiter)
if len(fields) != resourceFieldCount {
return nil, fmt.Errorf("Resource should have GROUP%sKIND%sNAME, but instead got: %s", resourceFieldDelimiter, resourceFieldDelimiter, resource)
@@ -1420,7 +1410,6 @@ func parseSelectedResources(resources []string) ([]*argoappv1.SyncOperationResou
Kind: fields[1],
Name: name,
Namespace: namespace,
Exclude: isExcluded,
})
}
return selectedResources, nil
@@ -1455,16 +1444,6 @@ func NewApplicationWaitCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
# Wait for multiple apps
argocd app wait my-app other-app
# Wait for apps by resource
# Resource should be formatted as GROUP:KIND:NAME. If no GROUP is specified then :KIND:NAME.
argocd app wait my-app --resource :Service:my-service
argocd app wait my-app --resource argoproj.io:Rollout:my-rollout
argocd app wait my-app --resource '!apps:Deployment:my-service'
argocd app wait my-app --resource apps:Deployment:my-service --resource :Service:my-service
argocd app wait my-app --resource '!*:Service:*'
# Specify namespace if the application has resources with the same name in different namespaces
argocd app wait my-app --resource argoproj.io:Rollout:my-namespace/my-rollout
# Wait for apps by label, in this example we waiting for apps that are children of another app (aka app-of-apps)
argocd app wait -l app.kubernetes.io/instance=my-app
argocd app wait -l app.kubernetes.io/instance!=my-app
@@ -1503,7 +1482,7 @@ func NewApplicationWaitCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
command.Flags().BoolVar(&watch.suspended, "suspended", false, "Wait for suspended")
command.Flags().BoolVar(&watch.degraded, "degraded", false, "Wait for degraded")
command.Flags().StringVarP(&selector, "selector", "l", "", "Wait for apps by label. Supports '=', '==', '!=', in, notin, exists & not exists. Matching apps must satisfy all of the specified label constraints.")
command.Flags().StringArrayVar(&resources, "resource", []string{}, fmt.Sprintf("Sync only specific resources as GROUP%[1]sKIND%[1]sNAME or %[2]sGROUP%[1]sKIND%[1]sNAME. Fields may be blank and '*' can be used. This option may be specified repeatedly", resourceFieldDelimiter, resourceExcludeIndicator))
command.Flags().StringArrayVar(&resources, "resource", []string{}, fmt.Sprintf("Sync only specific resources as GROUP%sKIND%sNAME. Fields may be blank. This option may be specified repeatedly", resourceFieldDelimiter, resourceFieldDelimiter))
command.Flags().BoolVar(&watch.operation, "operation", false, "Wait for pending operations")
command.Flags().UintVar(&timeout, "timeout", defaultCheckTimeoutSeconds, "Time out after this many seconds")
return command
@@ -1563,9 +1542,6 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
# Resource should be formatted as GROUP:KIND:NAME. If no GROUP is specified then :KIND:NAME
argocd app sync my-app --resource :Service:my-service
argocd app sync my-app --resource argoproj.io:Rollout:my-rollout
argocd app sync my-app --resource '!apps:Deployment:my-service'
argocd app sync my-app --resource apps:Deployment:my-service --resource :Service:my-service
argocd app sync my-app --resource '!*:Service:*'
# Specify namespace if the application has resources with the same name in different namespaces
argocd app sync my-app --resource argoproj.io:Rollout:my-namespace/my-rollout`,
Run: func(c *cobra.Command, args []string) {
@@ -1649,28 +1625,14 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
var localObjsStrings []string
diffOption := &DifferenceOption{}
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{
Name: &appName,
AppNamespace: &appNs,
})
errors.CheckError(err)
if app.Spec.HasMultipleSources() {
log.Fatal("argocd cli does not work on multi-source app")
return
}
// filters out only those resources that needs to be synced
filteredResources := filterAppResources(app, selectedResources)
// if resources are provided and no app resources match, then return error
if len(resources) > 0 && len(filteredResources) == 0 {
log.Fatalf("No matching app resources found for resource filter: %v", strings.Join(resources, ", "))
}
if local != "" {
if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" {
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{
Name: &appName,
AppNamespace: &appNs,
})
errors.CheckError(err)
if app.Spec.Source.Plugin != nil && app.Spec.Source.Plugin.Name != "" {
log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning)
}
@@ -1719,7 +1681,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
AppNamespace: &appNs,
DryRun: &dryRun,
Revision: &revision,
Resources: filteredResources,
Resources: selectedResources,
Prune: &prune,
Manifests: localObjsStrings,
Infos: getInfos(infos),
@@ -1747,7 +1709,13 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
}
}
if diffChanges {
if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" {
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{
Name: &appName,
AppNamespace: &appNs,
})
errors.CheckError(err)
if app.Spec.Source.Plugin != nil && app.Spec.Source.Plugin.Name != "" {
log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning)
}
@@ -1799,7 +1767,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
command.Flags().BoolVar(&dryRun, "dry-run", false, "Preview apply without affecting cluster")
command.Flags().BoolVar(&prune, "prune", false, "Allow deleting unexpected resources")
command.Flags().StringVar(&revision, "revision", "", "Sync to a specific revision. Preserves parameter overrides")
command.Flags().StringArrayVar(&resources, "resource", []string{}, fmt.Sprintf("Sync only specific resources as GROUP%[1]sKIND%[1]sNAME or %[2]sGROUP%[1]sKIND%[1]sNAME. Fields may be blank and '*' can be used. This option may be specified repeatedly", resourceFieldDelimiter, resourceExcludeIndicator))
command.Flags().StringArrayVar(&resources, "resource", []string{}, fmt.Sprintf("Sync only specific resources as GROUP%sKIND%sNAME. Fields may be blank. This option may be specified repeatedly", resourceFieldDelimiter, resourceFieldDelimiter))
command.Flags().StringVarP(&selector, "selector", "l", "", "Sync apps that match this label. Supports '=', '==', '!=', in, notin, exists & not exists. Matching apps must satisfy all of the specified label constraints.")
command.Flags().StringArrayVar(&labels, "label", []string{}, "Sync only specific resources with a label. This option may be specified repeatedly.")
command.Flags().UintVar(&timeout, "timeout", defaultCheckTimeoutSeconds, "Time out after this many seconds")
@@ -1924,9 +1892,15 @@ func getResourceStates(app *argoappv1.Application, selectedResources []*argoappv
}
// filter out not selected resources
if len(selectedResources) > 0 {
r := []argoappv1.SyncOperationResource{}
for _, res := range selectedResources {
if res != nil {
r = append(r, *res)
}
}
for i := len(states) - 1; i >= 0; i-- {
res := states[i]
if !argo.IncludeResource(res.Name, res.Namespace, schema.GroupVersionKind{Group: res.Group, Kind: res.Kind}, selectedResources) {
if !argo.ContainsSyncResource(res.Name, res.Namespace, schema.GroupVersionKind{Group: res.Group, Kind: res.Kind}, r) {
states = append(states[:i], states[i+1:]...)
}
}
@@ -1934,26 +1908,6 @@ func getResourceStates(app *argoappv1.Application, selectedResources []*argoappv
return states
}
// filterAppResources selects the app resources that match atleast one of the resource filters.
func filterAppResources(app *argoappv1.Application, selectedResources []*argoappv1.SyncOperationResource) []*argoappv1.SyncOperationResource {
var filteredResources []*argoappv1.SyncOperationResource
if app != nil && len(selectedResources) > 0 {
for i := range app.Status.Resources {
appResource := app.Status.Resources[i]
if (argo.IncludeResource(appResource.Name, appResource.Namespace,
schema.GroupVersionKind{Group: appResource.Group, Kind: appResource.Kind}, selectedResources)) {
filteredResources = append(filteredResources, &argoappv1.SyncOperationResource{
Group: appResource.Group,
Kind: appResource.Kind,
Name: appResource.Name,
Namespace: appResource.Namespace,
})
}
}
}
return filteredResources
}
func groupResourceStates(app *argoappv1.Application, selectedResources []*argoappv1.SyncOperationResource) map[string]*resourceState {
resStates := make(map[string]*resourceState)
for _, result := range getResourceStates(app, selectedResources) {
@@ -2133,9 +2087,8 @@ func setParameterOverrides(app *argoappv1.Application, parameters []string) {
if len(parameters) == 0 {
return
}
source := app.Spec.GetSource()
var sourceType argoappv1.ApplicationSourceType
if st, _ := source.ExplicitType(); st != nil {
if st, _ := app.Spec.Source.ExplicitType(); st != nil {
sourceType = *st
} else if app.Status.SourceType != "" {
sourceType = app.Status.SourceType
@@ -2147,8 +2100,8 @@ func setParameterOverrides(app *argoappv1.Application, parameters []string) {
switch sourceType {
case argoappv1.ApplicationSourceTypeHelm:
if source.Helm == nil {
source.Helm = &argoappv1.ApplicationSourceHelm{}
if app.Spec.Source.Helm == nil {
app.Spec.Source.Helm = &argoappv1.ApplicationSourceHelm{}
}
for _, p := range parameters {
newParam, err := argoappv1.NewHelmParameter(p, false)
@@ -2156,7 +2109,7 @@ func setParameterOverrides(app *argoappv1.Application, parameters []string) {
log.Error(err)
continue
}
source.Helm.AddParameter(*newParam)
app.Spec.Source.Helm.AddParameter(*newParam)
}
default:
log.Fatalf("Parameters can only be set against Helm applications")
@@ -2208,7 +2161,7 @@ func NewApplicationHistoryCommand(clientOpts *argocdclient.ClientOptions) *cobra
})
errors.CheckError(err)
if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" {
if app.Spec.Source.Plugin != nil && app.Spec.Source.Plugin.Name != "" {
log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning)
}
@@ -2272,7 +2225,7 @@ func NewApplicationRollbackCommand(clientOpts *argocdclient.ClientOptions) *cobr
})
errors.CheckError(err)
if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" {
if app.Spec.Source.Plugin != nil && app.Spec.Source.Plugin.Name != "" {
log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning)
}
@@ -2359,7 +2312,7 @@ func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cob
app, err := appIf.Get(context.Background(), &applicationpkg.ApplicationQuery{Name: &appName})
errors.CheckError(err)
if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" {
if app.Spec.Source.Plugin != nil && app.Spec.Source.Plugin.Name != "" {
log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning)
}
@@ -2462,7 +2415,7 @@ func NewApplicationEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
})
errors.CheckError(err)
if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" {
if app.Spec.Source.Plugin != nil && app.Spec.Source.Plugin.Name != "" {
log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning)
}
@@ -2474,12 +2427,12 @@ func NewApplicationEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
cli.InteractiveEdit(fmt.Sprintf("%s-*-edit.yaml", appName), appData, func(input []byte) error {
input, err = yaml.YAMLToJSON(input)
if err != nil {
return fmt.Errorf("error converting YAML to JSON: %w", err)
return err
}
updatedSpec := argoappv1.ApplicationSpec{}
err = json.Unmarshal(input, &updatedSpec)
if err != nil {
return fmt.Errorf("error unmarshaling input into application spec: %w", err)
return err
}
var appOpts cmdutil.AppOptions
@@ -2491,9 +2444,9 @@ func NewApplicationEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
AppNamespace: &appNs,
})
if err != nil {
return fmt.Errorf("failed to update application spec: %w", err)
return fmt.Errorf("Failed to update application spec:\n%v", err)
}
return nil
return err
})
},
}

View File

@@ -498,7 +498,7 @@ func TestPrintAppSummaryTable(t *testing.T) {
},
Project: "default",
Destination: v1alpha1.ApplicationDestination{Server: "local", Namespace: "argocd"},
Source: &v1alpha1.ApplicationSource{
Source: v1alpha1.ApplicationSource{
RepoURL: "test",
TargetRevision: "master",
Path: "/test",
@@ -604,7 +604,7 @@ func TestPrintParams(t *testing.T) {
output, _ := captureOutput(func() error {
app := &v1alpha1.Application{
Spec: v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{
Source: v1alpha1.ApplicationSource{
Helm: &v1alpha1.ApplicationSourceHelm{
Parameters: []v1alpha1.HelmParameter{
{
@@ -904,220 +904,11 @@ func Test_unset_nothingToUnset(t *testing.T) {
}
}
func TestFilterAppResources(t *testing.T) {
// App resources
var (
appReplicaSet1 = v1alpha1.ResourceStatus{
Group: "apps",
Kind: "ReplicaSet",
Namespace: "default",
Name: "replicaSet-name1",
}
appReplicaSet2 = v1alpha1.ResourceStatus{
Group: "apps",
Kind: "ReplicaSet",
Namespace: "default",
Name: "replicaSet-name2",
}
appJob = v1alpha1.ResourceStatus{
Group: "batch",
Kind: "Job",
Namespace: "default",
Name: "job-name",
}
appService1 = v1alpha1.ResourceStatus{
Group: "",
Kind: "Service",
Namespace: "default",
Name: "service-name1",
}
appService2 = v1alpha1.ResourceStatus{
Group: "",
Kind: "Service",
Namespace: "default",
Name: "service-name2",
}
appDeployment = v1alpha1.ResourceStatus{
Group: "apps",
Kind: "Deployment",
Namespace: "default",
Name: "deployment-name",
}
)
app := v1alpha1.Application{
Status: v1alpha1.ApplicationStatus{
Resources: []v1alpha1.ResourceStatus{
appReplicaSet1, appReplicaSet2, appJob, appService1, appService2, appDeployment},
},
}
// Resource filters
var (
blankValues = argoappv1.SyncOperationResource{
Group: "",
Kind: "",
Name: "",
Namespace: "",
Exclude: false}
// *:*:*
includeAllResources = argoappv1.SyncOperationResource{
Group: "*",
Kind: "*",
Name: "*",
Namespace: "",
Exclude: false}
// !*:*:*
excludeAllResources = argoappv1.SyncOperationResource{
Group: "*",
Kind: "*",
Name: "*",
Namespace: "",
Exclude: true}
// *:Service:*
includeAllServiceResources = argoappv1.SyncOperationResource{
Group: "*",
Kind: "Service",
Name: "*",
Namespace: "",
Exclude: false}
// !*:Service:*
excludeAllServiceResources = argoappv1.SyncOperationResource{
Group: "*",
Kind: "Service",
Name: "*",
Namespace: "",
Exclude: true}
// apps:ReplicaSet:replicaSet-name1
includeReplicaSet1Resource = argoappv1.SyncOperationResource{
Group: "apps",
Kind: "ReplicaSet",
Name: "replicaSet-name1",
Namespace: "",
Exclude: false}
// !apps:ReplicaSet:replicaSet-name2
excludeReplicaSet2Resource = argoappv1.SyncOperationResource{
Group: "apps",
Kind: "ReplicaSet",
Name: "replicaSet-name2",
Namespace: "",
Exclude: true}
)
// Filtered resources
var (
replicaSet1 = v1alpha1.SyncOperationResource{
Group: "apps",
Kind: "ReplicaSet",
Namespace: "default",
Name: "replicaSet-name1",
}
replicaSet2 = v1alpha1.SyncOperationResource{
Group: "apps",
Kind: "ReplicaSet",
Namespace: "default",
Name: "replicaSet-name2",
}
job = v1alpha1.SyncOperationResource{
Group: "batch",
Kind: "Job",
Namespace: "default",
Name: "job-name",
}
service1 = v1alpha1.SyncOperationResource{
Group: "",
Kind: "Service",
Namespace: "default",
Name: "service-name1",
}
service2 = v1alpha1.SyncOperationResource{
Group: "",
Kind: "Service",
Namespace: "default",
Name: "service-name2",
}
deployment = v1alpha1.SyncOperationResource{
Group: "apps",
Kind: "Deployment",
Namespace: "default",
Name: "deployment-name",
}
)
tests := []struct {
testName string
selectedResources []*argoappv1.SyncOperationResource
expectedResult []*argoappv1.SyncOperationResource
}{
//--resource apps:ReplicaSet:replicaSet-name1 --resource *:Service:*
{testName: "Include ReplicaSet replicaSet-name1 resouce and all service resources",
selectedResources: []*argoappv1.SyncOperationResource{&includeAllServiceResources, &includeReplicaSet1Resource},
expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1, &service1, &service2},
},
//--resource apps:ReplicaSet:replicaSet-name1 --resource !*:Service:*
{testName: "Include ReplicaSet replicaSet-name1 resouce and exclude all service resources",
selectedResources: []*argoappv1.SyncOperationResource{&excludeAllServiceResources, &includeReplicaSet1Resource},
expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &deployment},
},
// --resource !apps:ReplicaSet:replicaSet-name2 --resource !*:Service:*
{testName: "Exclude ReplicaSet replicaSet-name2 resouce and all service resources",
selectedResources: []*argoappv1.SyncOperationResource{&excludeReplicaSet2Resource, &excludeAllServiceResources},
expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &service1, &service2, &deployment},
},
// --resource !apps:ReplicaSet:replicaSet-name2
{testName: "Exclude ReplicaSet replicaSet-name2 resouce",
selectedResources: []*argoappv1.SyncOperationResource{&excludeReplicaSet2Resource},
expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1, &job, &service1, &service2, &deployment},
},
// --resource apps:ReplicaSet:replicaSet-name1
{testName: "Include ReplicaSet replicaSet-name1 resouce",
selectedResources: []*argoappv1.SyncOperationResource{&includeReplicaSet1Resource},
expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1},
},
// --resource !*:Service:*
{testName: "Exclude Service resouces",
selectedResources: []*argoappv1.SyncOperationResource{&excludeAllServiceResources},
expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &deployment},
},
// --resource *:Service:*
{testName: "Include Service resouces",
selectedResources: []*argoappv1.SyncOperationResource{&includeAllServiceResources},
expectedResult: []*argoappv1.SyncOperationResource{&service1, &service2},
},
// --resource !*:*:*
{testName: "Exclude all resouces",
selectedResources: []*argoappv1.SyncOperationResource{&excludeAllResources},
expectedResult: nil,
},
// --resource *:*:*
{testName: "Include all resouces",
selectedResources: []*argoappv1.SyncOperationResource{&includeAllResources},
expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &service1, &service2, &deployment},
},
{testName: "No Filters",
selectedResources: []*argoappv1.SyncOperationResource{&blankValues},
expectedResult: nil,
},
{testName: "Empty Filter",
selectedResources: []*argoappv1.SyncOperationResource{},
expectedResult: nil,
},
}
for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
filteredResources := filterAppResources(&app, test.selectedResources)
assert.Equal(t, test.expectedResult, filteredResources)
})
}
}
func TestParseSelectedResources(t *testing.T) {
resources := []string{"v1alpha:Application:test",
"v1alpha:Application:namespace/test",
"!v1alpha:Application:test",
"apps:Deployment:default/test",
"!*:*:*"}
resources := []string{"v1alpha:Application:test", "v1alpha:Application:namespace/test"}
operationResources, err := parseSelectedResources(resources)
assert.NoError(t, err)
assert.Len(t, operationResources, 5)
assert.Len(t, operationResources, 2)
assert.Equal(t, *operationResources[0], v1alpha1.SyncOperationResource{
Namespace: "",
Name: "test",
@@ -1130,27 +921,6 @@ func TestParseSelectedResources(t *testing.T) {
Kind: "Application",
Group: "v1alpha",
})
assert.Equal(t, *operationResources[2], v1alpha1.SyncOperationResource{
Namespace: "",
Name: "test",
Kind: "Application",
Group: "v1alpha",
Exclude: true,
})
assert.Equal(t, *operationResources[3], v1alpha1.SyncOperationResource{
Namespace: "default",
Name: "test",
Kind: "Deployment",
Group: "apps",
Exclude: false,
})
assert.Equal(t, *operationResources[4], v1alpha1.SyncOperationResource{
Namespace: "",
Name: "*",
Kind: "*",
Group: "*",
Exclude: true,
})
}
func TestParseSelectedResourcesIncorrect(t *testing.T) {
@@ -1215,7 +985,7 @@ func TestPrintApplicationTableWide(t *testing.T) {
Server: "http://localhost:8080",
Namespace: "default",
},
Source: &v1alpha1.ApplicationSource{
Source: v1alpha1.ApplicationSource{
RepoURL: "https://github.com/argoproj/argocd-example-apps",
Path: "guestbook",
TargetRevision: "123",
@@ -1491,7 +1261,7 @@ func testApp(name, project string, labels map[string]string, annotations map[str
Finalizers: finalizers,
},
Spec: argoappv1.ApplicationSpec{
Source: &argoappv1.ApplicationSource{
Source: argoappv1.ApplicationSource{
RepoURL: "https://github.com/argoproj/argocd-example-apps.git",
},
Project: project,

View File

@@ -95,7 +95,7 @@ func NewApplicationSetGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.
fmt.Println()
}
if showParams {
printHelmParams(appSet.Spec.Template.Spec.GetSource().Helm)
printHelmParams(appSet.Spec.Template.Spec.Source.Helm)
}
default:
errors.CheckError(fmt.Errorf("unknown output format: %s", output))
@@ -317,7 +317,7 @@ func printApplicationSetTable(apps []arogappsetv1.ApplicationSet, output *string
conditions,
}
if *output == "wide" {
vals = append(vals, app.Spec.Template.Spec.GetSource().RepoURL, app.Spec.Template.Spec.GetSource().Path, app.Spec.Template.Spec.GetSource().TargetRevision)
vals = append(vals, app.Spec.Template.Spec.Source.RepoURL, app.Spec.Template.Spec.Source.Path, app.Spec.Template.Spec.Source.TargetRevision)
}
_, _ = fmt.Fprintf(w, fmtStr, vals...)
}
@@ -333,15 +333,14 @@ func getServerForAppSet(appSet *arogappsetv1.ApplicationSet) string {
}
func printAppSetSummaryTable(appSet *arogappsetv1.ApplicationSet) {
source := appSet.Spec.Template.Spec.GetSource()
fmt.Printf(printOpFmtStr, "Name:", appSet.Name)
fmt.Printf(printOpFmtStr, "Project:", appSet.Spec.Template.Spec.GetProject())
fmt.Printf(printOpFmtStr, "Server:", getServerForAppSet(appSet))
fmt.Printf(printOpFmtStr, "Namespace:", appSet.Spec.Template.Spec.Destination.Namespace)
fmt.Printf(printOpFmtStr, "Repo:", source.RepoURL)
fmt.Printf(printOpFmtStr, "Target:", source.TargetRevision)
fmt.Printf(printOpFmtStr, "Path:", source.Path)
printAppSourceDetails(&source)
fmt.Printf(printOpFmtStr, "Repo:", appSet.Spec.Template.Spec.Source.RepoURL)
fmt.Printf(printOpFmtStr, "Target:", appSet.Spec.Template.Spec.Source.TargetRevision)
fmt.Printf(printOpFmtStr, "Path:", appSet.Spec.Template.Spec.Source.Path)
printAppSourceDetails(&appSet.Spec.Template.Spec.Source)
var syncPolicy string
if appSet.Spec.SyncPolicy != nil && appSet.Spec.Template.Spec.SyncPolicy.Automated != nil {

View File

@@ -1,36 +0,0 @@
package commands
import (
"fmt"
"log"
"github.com/spf13/cobra"
"golang.org/x/crypto/bcrypt"
)
// bcryptCmd represents the bcrypt command
func NewBcryptCmd() *cobra.Command {
var (
password string
)
var bcryptCmd = &cobra.Command{
Use: "bcrypt",
Short: "Generate bcrypt hash for the admin password",
Run: func(cmd *cobra.Command, args []string) {
bytePassword := []byte(password)
// Hashing the password
hash, err := bcrypt.GenerateFromPassword(bytePassword, bcrypt.DefaultCost)
if err != nil {
log.Fatalf("Failed to genarate bcrypt hash: %v", err)
}
fmt.Fprint(cmd.OutOrStdout(), string(hash))
},
}
bcryptCmd.Flags().StringVar(&password, "password", "", "Password for which bcrypt hash is generated")
err := bcryptCmd.MarkFlagRequired("password")
if err != nil {
return nil
}
return bcryptCmd
}

View File

@@ -1,22 +0,0 @@
package commands
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
"golang.org/x/crypto/bcrypt"
)
func TestGeneratePassword(t *testing.T) {
bcryptCmd := NewBcryptCmd()
bcryptCmd.SetArgs([]string{"--password", "abc"})
output := new(bytes.Buffer)
bcryptCmd.SetOutput(output)
err := bcryptCmd.Execute()
if err != nil {
return
}
err = bcrypt.CompareHashAndPassword(output.Bytes(), []byte("abc"))
assert.NoError(t, err)
}

View File

@@ -27,17 +27,6 @@ import (
"github.com/argoproj/argo-cd/v2/util/text/label"
)
const (
// type of the cluster ID is 'name'
clusterIdTypeName = "name"
// cluster field is 'name'
clusterFieldName = "name"
// cluster field is 'namespaces'
clusterFieldNamespaces = "namespaces"
// indicates managing all namespaces
allNamespaces = "*"
)
// NewClusterCommand returns a new instance of an `argocd cluster` command
func NewClusterCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clientcmd.PathOptions) *cobra.Command {
var command = &cobra.Command{
@@ -58,10 +47,7 @@ func NewClusterCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clientc
# Remove a target cluster context from ArgoCD
argocd cluster rm example-cluster
# Set a target cluster context from ArgoCD
argocd cluster set CLUSTER_NAME --name new-cluster-name --namespace '*'
argocd cluster set CLUSTER_NAME --name new-cluster-name --namespace namespace-one --namespace namespace-two`,
`,
}
command.AddCommand(NewClusterAddCommand(clientOpts, pathOpts))
@@ -69,7 +55,6 @@ func NewClusterCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clientc
command.AddCommand(NewClusterListCommand(clientOpts))
command.AddCommand(NewClusterRemoveCommand(clientOpts, pathOpts))
command.AddCommand(NewClusterRotateAuthCommand(clientOpts))
command.AddCommand(NewClusterSetCommand(clientOpts))
return command
}
@@ -200,72 +185,6 @@ func getRestConfig(pathOpts *clientcmd.PathOptions, ctxName string) (*rest.Confi
return conf, nil
}
// NewClusterSetCommand returns a new instance of an `argocd cluster set` command
func NewClusterSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
clusterOptions cmdutil.ClusterOptions
clusterName string
)
var command = &cobra.Command{
Use: "set NAME",
Short: "Set cluster information",
Example: ` # Set cluster information
argocd cluster set CLUSTER_NAME --name new-cluster-name --namespace '*'
argocd cluster set CLUSTER_NAME --name new-cluster-name --namespace namespace-one --namespace namespace-two`,
Run: func(c *cobra.Command, args []string) {
ctx := c.Context()
if len(args) != 1 {
c.HelpFunc()(c, args)
os.Exit(1)
}
// name of the cluster whose fields have to be updated.
clusterName = args[0]
conn, clusterIf := headless.NewClientOrDie(clientOpts, c).NewClusterClientOrDie()
defer io.Close(conn)
// checks the fields that needs to be updated
updatedFields := checkFieldsToUpdate(clusterOptions)
namespaces := clusterOptions.Namespaces
// check if all namespaces have to be considered
if len(namespaces) == 1 && strings.EqualFold(namespaces[0], allNamespaces) {
namespaces[0] = ""
}
if updatedFields != nil {
clusterUpdateRequest := clusterpkg.ClusterUpdateRequest{
Cluster: &argoappv1.Cluster{
Name: clusterOptions.Name,
Namespaces: namespaces,
},
UpdatedFields: updatedFields,
Id: &clusterpkg.ClusterID{
Type: clusterIdTypeName,
Value: clusterName,
},
}
_, err := clusterIf.Update(ctx, &clusterUpdateRequest)
errors.CheckError(err)
fmt.Printf("Cluster '%s' updated.\n", clusterName)
} else {
fmt.Print("Specify the cluster field to be updated.\n")
}
},
}
command.Flags().StringVar(&clusterOptions.Name, "name", "", "Overwrite the cluster name")
command.Flags().StringArrayVar(&clusterOptions.Namespaces, "namespace", nil, "List of namespaces which are allowed to manage. Specify '*' to manage all namespaces")
return command
}
// checkFieldsToUpdate returns the fields that needs to be updated
func checkFieldsToUpdate(clusterOptions cmdutil.ClusterOptions) []string {
var updatedFields []string
if clusterOptions.Name != "" {
updatedFields = append(updatedFields, clusterFieldName)
}
if clusterOptions.Namespaces != nil {
updatedFields = append(updatedFields, clusterFieldNamespaces)
}
return updatedFields
}
// NewClusterGetCommand returns a new instance of an `argocd cluster get` command
func NewClusterGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (

View File

@@ -22,13 +22,13 @@ func PrintResource(resource interface{}, output string) error {
case "json":
jsonBytes, err := json.MarshalIndent(resource, "", " ")
if err != nil {
return fmt.Errorf("unable to marshal resource to json: %w", err)
return err
}
fmt.Println(string(jsonBytes))
case "yaml":
yamlBytes, err := yaml.Marshal(resource)
if err != nil {
return fmt.Errorf("unable to marshal resource to yaml: %w", err)
return err
}
fmt.Print(string(yamlBytes))
default:
@@ -56,13 +56,13 @@ func PrintResourceList(resources interface{}, output string, single bool) error
case "json":
jsonBytes, err := json.MarshalIndent(resources, "", " ")
if err != nil {
return fmt.Errorf("unable to marshal resources to json: %w", err)
return err
}
fmt.Println(string(jsonBytes))
case "yaml":
yamlBytes, err := yaml.Marshal(resources)
if err != nil {
return fmt.Errorf("unable to marshal resources to yaml: %w", err)
return err
}
fmt.Print(string(yamlBytes))
default:

View File

@@ -146,7 +146,6 @@ __argocd_custom_func() {
;;
argocd_cluster_get | \
argocd_cluster_rm | \
argocd_cluster_set | \
argocd_login | \
argocd_cluster_add)
__argocd_list_servers

View File

@@ -202,18 +202,17 @@ func StartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOptions,
}
appstateCache := appstatecache.NewCache(cache.NewCache(&forwardCacheClient{namespace: namespace, context: ctxStr}), time.Hour)
srv := server.NewServer(ctx, server.ArgoCDServerOpts{
EnableGZip: false,
Namespace: namespace,
ListenPort: *port,
AppClientset: appClientset,
DisableAuth: true,
RedisClient: redis.NewClient(&redis.Options{Addr: mr.Addr()}),
Cache: servercache.NewCache(appstateCache, 0, 0, 0),
KubeClientset: kubeClientset,
Insecure: true,
ListenHost: *address,
RepoClientset: &forwardRepoClientset{namespace: namespace, context: ctxStr},
EnableProxyExtension: false,
EnableGZip: false,
Namespace: namespace,
ListenPort: *port,
AppClientset: appClientset,
DisableAuth: true,
RedisClient: redis.NewClient(&redis.Options{Addr: mr.Addr()}),
Cache: servercache.NewCache(appstateCache, 0, 0, 0),
KubeClientset: kubeClientset,
Insecure: true,
ListenHost: *address,
RepoClientset: &forwardRepoClientset{namespace: namespace, context: ctxStr},
})
srv.Init(ctx)

View File

@@ -12,7 +12,7 @@ import (
"strings"
"time"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/coreos/go-oidc"
"github.com/golang-jwt/jwt/v4"
log "github.com/sirupsen/logrus"
"github.com/skratchdot/open-golang/open"

View File

@@ -863,23 +863,23 @@ func NewProjectEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comman
cli.InteractiveEdit(fmt.Sprintf("%s-*-edit.yaml", projName), projData, func(input []byte) error {
input, err = yaml.YAMLToJSON(input)
if err != nil {
return fmt.Errorf("error converting YAML to JSON: %w", err)
return err
}
updatedSpec := v1alpha1.AppProjectSpec{}
err = json.Unmarshal(input, &updatedSpec)
if err != nil {
return fmt.Errorf("error unmarshaling input into application spec: %w", err)
return err
}
proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName})
if err != nil {
return fmt.Errorf("could not get project by project name: %w", err)
return err
}
proj.Spec = updatedSpec
_, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj})
if err != nil {
return fmt.Errorf("failed to update project:\n%w", err)
return fmt.Errorf("Failed to update project:\n%v", err)
}
return nil
return err
})
},
}

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"os"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/coreos/go-oidc"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"

View File

@@ -70,9 +70,6 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
# Add a private Git repository on GitHub Enterprise via GitHub App
argocd repo add https://ghe.example.com/repos/repo --github-app-id 1 --github-app-installation-id 2 --github-app-private-key-path test.private-key.pem --github-app-enterprise-base-url https://ghe.example.com/api/v3
# Add a private Git repository on Google Cloud Sources via GCP service account credentials
argocd repo add https://source.developers.google.com/p/my-google-cloud-project/r/my-repo --gcp-service-account-key-path service-account-key.json
`
var command = &cobra.Command{
@@ -138,17 +135,6 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
}
}
if repoOpts.GCPServiceAccountKeyPath != "" {
if git.IsHTTPSURL(repoOpts.Repo.Repo) {
gcpServiceAccountKey, err := os.ReadFile(repoOpts.GCPServiceAccountKeyPath)
errors.CheckError(err)
repoOpts.Repo.GCPServiceAccountKey = string(gcpServiceAccountKey)
} else {
err := fmt.Errorf("--gcp-service-account-key-path is only supported for HTTPS repositories")
errors.CheckError(err)
}
}
// Set repository connection properties only when creating repository, not
// when creating repository credentials.
// InsecureIgnoreHostKey is deprecated and only here for backwards compat
@@ -160,7 +146,6 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
repoOpts.Repo.GithubAppInstallationId = repoOpts.GithubAppInstallationId
repoOpts.Repo.GitHubAppEnterpriseBaseURL = repoOpts.GitHubAppEnterpriseBaseURL
repoOpts.Repo.Proxy = repoOpts.Proxy
repoOpts.Repo.ForceHttpBasicAuth = repoOpts.ForceHttpBasicAuth
if repoOpts.Repo.Type == "helm" && repoOpts.Repo.Name == "" {
errors.CheckError(fmt.Errorf("Must specify --name for repos of type 'helm'"))
@@ -199,8 +184,6 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
GithubAppEnterpriseBaseUrl: repoOpts.Repo.GitHubAppEnterpriseBaseURL,
Proxy: repoOpts.Proxy,
Project: repoOpts.Repo.Project,
GcpServiceAccountKey: repoOpts.Repo.GCPServiceAccountKey,
ForceHttpBasicAuth: repoOpts.Repo.ForceHttpBasicAuth,
}
_, err := repoIf.ValidateAccess(ctx, &repoAccessReq)
errors.CheckError(err)
@@ -311,7 +294,7 @@ func NewRepoListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
},
}
command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide|url")
command.Flags().StringVar(&refresh, "refresh", "", "Force a cache refresh on connection status , must be one of: 'hard'")
command.Flags().StringVar(&refresh, "refresh", "", "Force a cache refresh on connection status")
return command
}
@@ -362,6 +345,6 @@ func NewRepoGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
},
}
command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide|url")
command.Flags().StringVar(&refresh, "refresh", "", "Force a cache refresh on connection status , must be one of: 'hard'")
command.Flags().StringVar(&refresh, "refresh", "", "Force a cache refresh on connection status")
return command
}

View File

@@ -39,13 +39,12 @@ func NewRepoCredsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
// NewRepoCredsAddCommand returns a new instance of an `argocd repocreds add` command
func NewRepoCredsAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
repo appsv1.RepoCreds
upsert bool
sshPrivateKeyPath string
tlsClientCertPath string
tlsClientCertKeyPath string
githubAppPrivateKeyPath string
gcpServiceAccountKeyPath string
repo appsv1.RepoCreds
upsert bool
sshPrivateKeyPath string
tlsClientCertPath string
tlsClientCertKeyPath string
githubAppPrivateKeyPath string
)
// For better readability and easier formatting
@@ -63,9 +62,6 @@ func NewRepoCredsAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comma
# Add credentials with helm oci registry so that these oci registry urls do not need to be added as repos individually.
argocd repocreds add localhost:5000/myrepo --enable-oci --type helm
# Add credentials with GCP credentials for all repositories under https://source.developers.google.com/p/my-google-cloud-project/r/
argocd repocreds add https://source.developers.google.com/p/my-google-cloud-project/r/ --gcp-service-account-key-path service-account-key.json
`
var command = &cobra.Command{
@@ -131,18 +127,6 @@ func NewRepoCredsAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comma
}
}
// Specifying gcpServiceAccountKeyPath is only valid for HTTPS repositories
if gcpServiceAccountKeyPath != "" {
if git.IsHTTPSURL(repo.URL) {
gcpServiceAccountKey, err := os.ReadFile(gcpServiceAccountKeyPath)
errors.CheckError(err)
repo.GCPServiceAccountKey = string(gcpServiceAccountKey)
} else {
err := fmt.Errorf("--gcp-service-account-key-path is only supported for HTTPS repositories")
errors.CheckError(err)
}
}
conn, repoIf := headless.NewClientOrDie(clientOpts, c).NewRepoCredsClientOrDie()
defer io.Close(conn)
@@ -174,8 +158,6 @@ func NewRepoCredsAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comma
command.Flags().BoolVar(&upsert, "upsert", false, "Override an existing repository with the same name even if the spec differs")
command.Flags().BoolVar(&repo.EnableOCI, "enable-oci", false, "Specifies whether helm-oci support should be enabled for this repo")
command.Flags().StringVar(&repo.Type, "type", common.DefaultRepoType, "type of the repository, \"git\" or \"helm\"")
command.Flags().StringVar(&gcpServiceAccountKeyPath, "gcp-service-account-key-path", "", "service account key for the Google Cloud Platform")
command.Flags().BoolVar(&repo.ForceHttpBasicAuth, "force-http-basic-auth", false, "whether to force basic auth when connecting via HTTP")
return command
}

View File

@@ -41,7 +41,7 @@ func NewCommand() *cobra.Command {
}
command.AddCommand(NewCompletionCommand())
command.AddCommand(initialize.InitCommand(NewVersionCmd(&clientOpts, nil)))
command.AddCommand(initialize.InitCommand(NewVersionCmd(&clientOpts)))
command.AddCommand(initialize.InitCommand(NewClusterCommand(&clientOpts, pathOpts)))
command.AddCommand(initialize.InitCommand(NewApplicationCommand(&clientOpts)))
command.AddCommand(initialize.InitCommand(NewAppSetCommand(&clientOpts)))

View File

@@ -17,7 +17,7 @@ import (
)
// NewVersionCmd returns a new `version` command to be used as a sub-command to root
func NewVersionCmd(clientOpts *argocdclient.ClientOptions, serverVersion *version.VersionMessage) *cobra.Command {
func NewVersionCmd(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
short bool
client bool
@@ -54,12 +54,7 @@ func NewVersionCmd(clientOpts *argocdclient.ClientOptions, serverVersion *versio
}
if !client {
var sv *version.VersionMessage
if serverVersion == nil {
sv = getServerVersion(ctx, clientOpts, cmd)
} else {
sv = serverVersion
}
sv := getServerVersion(ctx, clientOpts, cmd)
if short {
v["server"] = map[string]string{"argocd-server": sv.Version}
@@ -73,13 +68,8 @@ func NewVersionCmd(clientOpts *argocdclient.ClientOptions, serverVersion *versio
case "wide", "short", "":
fmt.Fprint(cmd.OutOrStdout(), printClientVersion(&cv, short || (output == "short")))
if !client {
var sv *version.VersionMessage
if serverVersion == nil {
sv = getServerVersion(ctx, clientOpts, cmd)
} else {
sv = serverVersion
}
fmt.Fprint(cmd.OutOrStdout(), printServerVersion(sv, short || (output == "short")))
sv := getServerVersion(ctx, clientOpts, cmd)
printServerVersion(sv, short || (output == "short"))
}
default:
log.Fatalf("unknown output format: %s", output)
@@ -119,45 +109,44 @@ func printClientVersion(version *common.Version, short bool) string {
return output
}
func printServerVersion(version *version.VersionMessage, short bool) string {
output := fmt.Sprintf("%s: %s\n", "argocd-server", version.Version)
func printServerVersion(version *version.VersionMessage, short bool) {
fmt.Printf("%s: %s\n", "argocd-server", version.Version)
if short {
return output
return
}
if version.BuildDate != "" {
output += fmt.Sprintf(" BuildDate: %s\n", version.BuildDate)
fmt.Printf(" BuildDate: %s\n", version.BuildDate)
}
if version.GitCommit != "" {
output += fmt.Sprintf(" GitCommit: %s\n", version.GitCommit)
fmt.Printf(" GitCommit: %s\n", version.GitCommit)
}
if version.GitTreeState != "" {
output += fmt.Sprintf(" GitTreeState: %s\n", version.GitTreeState)
fmt.Printf(" GitTreeState: %s\n", version.GitTreeState)
}
if version.GitTag != "" {
output += fmt.Sprintf(" GitTag: %s\n", version.GitTag)
fmt.Printf(" GitTag: %s\n", version.GitTag)
}
if version.GoVersion != "" {
output += fmt.Sprintf(" GoVersion: %s\n", version.GoVersion)
fmt.Printf(" GoVersion: %s\n", version.GoVersion)
}
if version.Compiler != "" {
output += fmt.Sprintf(" Compiler: %s\n", version.Compiler)
fmt.Printf(" Compiler: %s\n", version.Compiler)
}
if version.Platform != "" {
output += fmt.Sprintf(" Platform: %s\n", version.Platform)
fmt.Printf(" Platform: %s\n", version.Platform)
}
if version.KustomizeVersion != "" {
output += fmt.Sprintf(" Kustomize Version: %s\n", version.KustomizeVersion)
fmt.Printf(" Kustomize Version: %s\n", version.KustomizeVersion)
}
if version.HelmVersion != "" {
output += fmt.Sprintf(" Helm Version: %s\n", version.HelmVersion)
fmt.Printf(" Helm Version: %s\n", version.HelmVersion)
}
if version.KubectlVersion != "" {
output += fmt.Sprintf(" Kubectl Version: %s\n", version.KubectlVersion)
fmt.Printf(" Kubectl Version: %s\n", version.KubectlVersion)
}
if version.JsonnetVersion != "" {
output += fmt.Sprintf(" Jsonnet Version: %s\n", version.JsonnetVersion)
fmt.Printf(" Jsonnet Version: %s\n", version.JsonnetVersion)
}
return output
}

View File

@@ -5,13 +5,12 @@ import (
"testing"
argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/version"
"github.com/stretchr/testify/assert"
)
func TestShortVersionClient(t *testing.T) {
func TestShortVersion(t *testing.T) {
buf := new(bytes.Buffer)
cmd := NewVersionCmd(&argocdclient.ClientOptions{}, nil)
cmd := NewVersionCmd(&argocdclient.ClientOptions{})
cmd.SetOutput(buf)
cmd.SetArgs([]string{"version", "--short", "--client"})
err := cmd.Execute()
@@ -21,17 +20,3 @@ func TestShortVersionClient(t *testing.T) {
output := buf.String()
assert.Equal(t, output, "argocd: v99.99.99+unknown\n")
}
func TestShortVersion(t *testing.T) {
serverVersion := &version.VersionMessage{Version: "v99.99.99+unknown"}
buf := new(bytes.Buffer)
cmd := NewVersionCmd(&argocdclient.ClientOptions{}, serverVersion)
cmd.SetOutput(buf)
cmd.SetArgs([]string{"argocd", "version", "--short"})
err := cmd.Execute()
if err != nil {
t.Fatal("Failed to execute short version command")
}
output := buf.String()
assert.Equal(t, output, "argocd: v99.99.99+unknown\nargocd-server: v99.99.99+unknown\n")
}

View File

@@ -138,26 +138,22 @@ func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap
}
flags.Visit(func(f *pflag.Flag) {
visited++
source := spec.GetSourcePtr()
if source == nil {
source = &argoappv1.ApplicationSource{}
}
switch f.Name {
case "repo":
source.RepoURL = appOpts.repoURL
spec.Source.RepoURL = appOpts.repoURL
case "path":
source.Path = appOpts.appPath
spec.Source.Path = appOpts.appPath
case "helm-chart":
source.Chart = appOpts.chart
spec.Source.Chart = appOpts.chart
case "revision":
source.TargetRevision = appOpts.revision
spec.Source.TargetRevision = appOpts.revision
case "revision-history-limit":
i := int64(appOpts.revisionHistoryLimit)
spec.RevisionHistoryLimit = &i
case "values":
setHelmOpt(source, helmOpts{valueFiles: appOpts.valuesFiles})
setHelmOpt(&spec.Source, helmOpts{valueFiles: appOpts.valuesFiles})
case "ignore-missing-value-files":
setHelmOpt(source, helmOpts{ignoreMissingValueFiles: appOpts.ignoreMissingValueFiles})
setHelmOpt(&spec.Source, helmOpts{ignoreMissingValueFiles: appOpts.ignoreMissingValueFiles})
case "values-literal-file":
var data []byte
@@ -169,41 +165,41 @@ func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap
data, err = config.ReadRemoteFile(appOpts.values)
}
errors.CheckError(err)
setHelmOpt(source, helmOpts{values: string(data)})
setHelmOpt(&spec.Source, helmOpts{values: string(data)})
case "release-name":
setHelmOpt(source, helmOpts{releaseName: appOpts.releaseName})
setHelmOpt(&spec.Source, helmOpts{releaseName: appOpts.releaseName})
case "helm-version":
setHelmOpt(source, helmOpts{version: appOpts.helmVersion})
setHelmOpt(&spec.Source, helmOpts{version: appOpts.helmVersion})
case "helm-pass-credentials":
setHelmOpt(source, helmOpts{passCredentials: appOpts.helmPassCredentials})
setHelmOpt(&spec.Source, helmOpts{passCredentials: appOpts.helmPassCredentials})
case "helm-set":
setHelmOpt(source, helmOpts{helmSets: appOpts.helmSets})
setHelmOpt(&spec.Source, helmOpts{helmSets: appOpts.helmSets})
case "helm-set-string":
setHelmOpt(source, helmOpts{helmSetStrings: appOpts.helmSetStrings})
setHelmOpt(&spec.Source, helmOpts{helmSetStrings: appOpts.helmSetStrings})
case "helm-set-file":
setHelmOpt(source, helmOpts{helmSetFiles: appOpts.helmSetFiles})
setHelmOpt(&spec.Source, helmOpts{helmSetFiles: appOpts.helmSetFiles})
case "helm-skip-crds":
setHelmOpt(source, helmOpts{skipCrds: appOpts.helmSkipCrds})
setHelmOpt(&spec.Source, helmOpts{skipCrds: appOpts.helmSkipCrds})
case "directory-recurse":
if source.Directory != nil {
source.Directory.Recurse = appOpts.directoryRecurse
if spec.Source.Directory != nil {
spec.Source.Directory.Recurse = appOpts.directoryRecurse
} else {
source.Directory = &argoappv1.ApplicationSourceDirectory{Recurse: appOpts.directoryRecurse}
spec.Source.Directory = &argoappv1.ApplicationSourceDirectory{Recurse: appOpts.directoryRecurse}
}
case "directory-exclude":
if source.Directory != nil {
source.Directory.Exclude = appOpts.directoryExclude
if spec.Source.Directory != nil {
spec.Source.Directory.Exclude = appOpts.directoryExclude
} else {
source.Directory = &argoappv1.ApplicationSourceDirectory{Exclude: appOpts.directoryExclude}
spec.Source.Directory = &argoappv1.ApplicationSourceDirectory{Exclude: appOpts.directoryExclude}
}
case "directory-include":
if source.Directory != nil {
source.Directory.Include = appOpts.directoryInclude
if spec.Source.Directory != nil {
spec.Source.Directory.Include = appOpts.directoryInclude
} else {
source.Directory = &argoappv1.ApplicationSourceDirectory{Include: appOpts.directoryInclude}
spec.Source.Directory = &argoappv1.ApplicationSourceDirectory{Include: appOpts.directoryInclude}
}
case "config-management-plugin":
source.Plugin = &argoappv1.ApplicationSourcePlugin{Name: appOpts.configManagementPlugin}
spec.Source.Plugin = &argoappv1.ApplicationSourcePlugin{Name: appOpts.configManagementPlugin}
case "dest-name":
spec.Destination.Name = appOpts.destName
case "dest-server":
@@ -213,37 +209,37 @@ func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap
case "project":
spec.Project = appOpts.project
case "nameprefix":
setKustomizeOpt(source, kustomizeOpts{namePrefix: appOpts.namePrefix})
setKustomizeOpt(&spec.Source, kustomizeOpts{namePrefix: appOpts.namePrefix})
case "namesuffix":
setKustomizeOpt(source, kustomizeOpts{nameSuffix: appOpts.nameSuffix})
setKustomizeOpt(&spec.Source, kustomizeOpts{nameSuffix: appOpts.nameSuffix})
case "kustomize-image":
setKustomizeOpt(source, kustomizeOpts{images: appOpts.kustomizeImages})
setKustomizeOpt(&spec.Source, kustomizeOpts{images: appOpts.kustomizeImages})
case "kustomize-version":
setKustomizeOpt(source, kustomizeOpts{version: appOpts.kustomizeVersion})
setKustomizeOpt(&spec.Source, kustomizeOpts{version: appOpts.kustomizeVersion})
case "kustomize-common-label":
parsedLabels, err := label.Parse(appOpts.kustomizeCommonLabels)
errors.CheckError(err)
setKustomizeOpt(source, kustomizeOpts{commonLabels: parsedLabels})
setKustomizeOpt(&spec.Source, kustomizeOpts{commonLabels: parsedLabels})
case "kustomize-common-annotation":
parsedAnnotations, err := label.Parse(appOpts.kustomizeCommonAnnotations)
errors.CheckError(err)
setKustomizeOpt(source, kustomizeOpts{commonAnnotations: parsedAnnotations})
setKustomizeOpt(&spec.Source, kustomizeOpts{commonAnnotations: parsedAnnotations})
case "kustomize-force-common-label":
setKustomizeOpt(source, kustomizeOpts{forceCommonLabels: appOpts.kustomizeForceCommonLabels})
setKustomizeOpt(&spec.Source, kustomizeOpts{forceCommonLabels: appOpts.kustomizeForceCommonLabels})
case "kustomize-force-common-annotation":
setKustomizeOpt(source, kustomizeOpts{forceCommonAnnotations: appOpts.kustomizeForceCommonAnnotations})
setKustomizeOpt(&spec.Source, kustomizeOpts{forceCommonAnnotations: appOpts.kustomizeForceCommonAnnotations})
case "jsonnet-tla-str":
setJsonnetOpt(source, appOpts.jsonnetTlaStr, false)
setJsonnetOpt(&spec.Source, appOpts.jsonnetTlaStr, false)
case "jsonnet-tla-code":
setJsonnetOpt(source, appOpts.jsonnetTlaCode, true)
setJsonnetOpt(&spec.Source, appOpts.jsonnetTlaCode, true)
case "jsonnet-ext-var-str":
setJsonnetOptExtVar(source, appOpts.jsonnetExtVarStr, false)
setJsonnetOptExtVar(&spec.Source, appOpts.jsonnetExtVarStr, false)
case "jsonnet-ext-var-code":
setJsonnetOptExtVar(source, appOpts.jsonnetExtVarCode, true)
setJsonnetOptExtVar(&spec.Source, appOpts.jsonnetExtVarCode, true)
case "jsonnet-libs":
setJsonnetOptLibs(source, appOpts.jsonnetLibs)
setJsonnetOptLibs(&spec.Source, appOpts.jsonnetLibs)
case "plugin-env":
setPluginOptEnvs(source, appOpts.pluginEnvs)
setPluginOptEnvs(&spec.Source, appOpts.pluginEnvs)
case "sync-policy":
switch appOpts.syncPolicy {
case "none":
@@ -300,7 +296,6 @@ func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap
log.Fatalf("Invalid sync-retry-limit [%d]", appOpts.retryLimit)
}
}
spec.Source = source
})
if flags.Changed("auto-prune") {
if spec.SyncPolicy == nil || spec.SyncPolicy.Automated == nil {
@@ -478,9 +473,8 @@ func SetParameterOverrides(app *argoappv1.Application, parameters []string) {
if len(parameters) == 0 {
return
}
source := app.Spec.GetSource()
var sourceType argoappv1.ApplicationSourceType
if st, _ := source.ExplicitType(); st != nil {
if st, _ := app.Spec.Source.ExplicitType(); st != nil {
sourceType = *st
} else if app.Status.SourceType != "" {
sourceType = app.Status.SourceType
@@ -492,8 +486,8 @@ func SetParameterOverrides(app *argoappv1.Application, parameters []string) {
switch sourceType {
case argoappv1.ApplicationSourceTypeHelm:
if source.Helm == nil {
source.Helm = &argoappv1.ApplicationSourceHelm{}
if app.Spec.Source.Helm == nil {
app.Spec.Source.Helm = &argoappv1.ApplicationSourceHelm{}
}
for _, p := range parameters {
newParam, err := argoappv1.NewHelmParameter(p, false)
@@ -501,7 +495,7 @@ func SetParameterOverrides(app *argoappv1.Application, parameters []string) {
log.Error(err)
continue
}
source.Helm.AddParameter(*newParam)
app.Spec.Source.Helm.AddParameter(*newParam)
}
default:
log.Fatalf("Parameters can only be set against Helm applications")
@@ -586,9 +580,6 @@ func constructAppsBaseOnName(appName string, labels, annotations, args []string,
Name: appName,
Namespace: appNs,
},
Spec: argoappv1.ApplicationSpec{
Source: &argoappv1.ApplicationSource{},
},
}
SetAppSpecOptions(flags, &app.Spec, &appOpts)
SetParameterOverrides(app, appOpts.Parameters)

View File

@@ -149,9 +149,7 @@ func (f *appOptionsFixture) SetFlag(key, value string) error {
func newAppOptionsFixture() *appOptionsFixture {
fixture := &appOptionsFixture{
spec: &v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{},
},
spec: &v1alpha1.ApplicationSpec{},
command: &cobra.Command{},
options: &AppOptions{},
}

View File

@@ -40,7 +40,7 @@ func readAppsetFromURI(fileURL string, appset *[]*argoprojiov1alpha1.Application
yml, err := readFilePayload()
if err != nil {
return fmt.Errorf("error reading file payload: %w", err)
return err
}
return readAppset(yml, appset)
@@ -49,18 +49,18 @@ func readAppsetFromURI(fileURL string, appset *[]*argoprojiov1alpha1.Application
func readAppset(yml []byte, appsets *[]*argoprojiov1alpha1.ApplicationSet) error {
yamls, err := kube.SplitYAMLToString(yml)
if err != nil {
return fmt.Errorf("error splitting YAML to string: %w", err)
return err
}
for _, yml := range yamls {
var appset argoprojiov1alpha1.ApplicationSet
err = config.Unmarshal([]byte(yml), &appset)
if err != nil {
return fmt.Errorf("error unmarshalling appset: %w", err)
return err
}
*appsets = append(*appsets, &appset)
}
// we reach here if there is no error found while reading the Application Set
return nil
return err
}

View File

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

View File

@@ -22,8 +22,6 @@ type RepoOptions struct {
GithubAppPrivateKeyPath string
GitHubAppEnterpriseBaseURL string
Proxy string
GCPServiceAccountKeyPath string
ForceHttpBasicAuth bool
}
func AddRepoFlags(command *cobra.Command, opts *RepoOptions) {
@@ -44,6 +42,4 @@ func AddRepoFlags(command *cobra.Command, opts *RepoOptions) {
command.Flags().StringVar(&opts.GithubAppPrivateKeyPath, "github-app-private-key-path", "", "private key of the GitHub Application")
command.Flags().StringVar(&opts.GitHubAppEnterpriseBaseURL, "github-app-enterprise-base-url", "", "base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3")
command.Flags().StringVar(&opts.Proxy, "proxy", "", "use proxy to access repository")
command.Flags().StringVar(&opts.GCPServiceAccountKeyPath, "gcp-service-account-key-path", "", "service account key for the Google Cloud Platform")
command.Flags().BoolVar(&opts.ForceHttpBasicAuth, "force-http-basic-auth", false, "whether to force use of basic auth when connecting repository via HTTP")
}

View File

@@ -6,7 +6,6 @@ package apiclient
import (
context "context"
fmt "fmt"
apiclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient"
proto "github.com/gogo/protobuf/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
@@ -318,7 +317,6 @@ func (m *ManifestResponse) GetSourceType() string {
type RepositoryResponse struct {
IsSupported bool `protobuf:"varint,1,opt,name=isSupported,proto3" json:"isSupported,omitempty"`
IsDiscoveryEnabled bool `protobuf:"varint,2,opt,name=isDiscoveryEnabled,proto3" json:"isDiscoveryEnabled,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -364,62 +362,6 @@ func (m *RepositoryResponse) GetIsSupported() bool {
return false
}
func (m *RepositoryResponse) GetIsDiscoveryEnabled() bool {
if m != nil {
return m.IsDiscoveryEnabled
}
return false
}
// ParametersAnnouncementResponse contains a list of announcements. This list represents all the parameters which a CMP
// is able to accept.
type ParametersAnnouncementResponse struct {
ParameterAnnouncements []*apiclient.ParameterAnnouncement `protobuf:"bytes,1,rep,name=parameterAnnouncements,proto3" json:"parameterAnnouncements,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ParametersAnnouncementResponse) Reset() { *m = ParametersAnnouncementResponse{} }
func (m *ParametersAnnouncementResponse) String() string { return proto.CompactTextString(m) }
func (*ParametersAnnouncementResponse) ProtoMessage() {}
func (*ParametersAnnouncementResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_b21875a7079a06ed, []int{5}
}
func (m *ParametersAnnouncementResponse) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *ParametersAnnouncementResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_ParametersAnnouncementResponse.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *ParametersAnnouncementResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ParametersAnnouncementResponse.Merge(m, src)
}
func (m *ParametersAnnouncementResponse) XXX_Size() int {
return m.Size()
}
func (m *ParametersAnnouncementResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ParametersAnnouncementResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ParametersAnnouncementResponse proto.InternalMessageInfo
func (m *ParametersAnnouncementResponse) GetParameterAnnouncements() []*apiclient.ParameterAnnouncement {
if m != nil {
return m.ParameterAnnouncements
}
return nil
}
type File struct {
Chunk []byte `protobuf:"bytes,1,opt,name=chunk,proto3" json:"chunk,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
@@ -431,7 +373,7 @@ func (m *File) Reset() { *m = File{} }
func (m *File) String() string { return proto.CompactTextString(m) }
func (*File) ProtoMessage() {}
func (*File) Descriptor() ([]byte, []int) {
return fileDescriptor_b21875a7079a06ed, []int{6}
return fileDescriptor_b21875a7079a06ed, []int{5}
}
func (m *File) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -473,50 +415,44 @@ func init() {
proto.RegisterType((*EnvEntry)(nil), "plugin.EnvEntry")
proto.RegisterType((*ManifestResponse)(nil), "plugin.ManifestResponse")
proto.RegisterType((*RepositoryResponse)(nil), "plugin.RepositoryResponse")
proto.RegisterType((*ParametersAnnouncementResponse)(nil), "plugin.ParametersAnnouncementResponse")
proto.RegisterType((*File)(nil), "plugin.File")
}
func init() { proto.RegisterFile("cmpserver/plugin/plugin.proto", fileDescriptor_b21875a7079a06ed) }
var fileDescriptor_b21875a7079a06ed = []byte{
// 576 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x94, 0xdd, 0x6e, 0x12, 0x4f,
0x14, 0xc0, 0xbb, 0x85, 0xb6, 0x70, 0x68, 0xf2, 0x27, 0x93, 0x7f, 0x74, 0x25, 0x2d, 0xe2, 0x5e,
0x18, 0x6e, 0x84, 0x04, 0xbd, 0x35, 0xb1, 0x55, 0x6c, 0xa3, 0xc1, 0x90, 0xa9, 0x37, 0x7a, 0x37,
0x1d, 0x0e, 0x30, 0x76, 0x77, 0x66, 0x9c, 0x99, 0xdd, 0x04, 0xbd, 0xf1, 0x3d, 0x7c, 0x00, 0x5f,
0xc5, 0x4b, 0x1f, 0xc1, 0xf4, 0x49, 0x0c, 0xb3, 0xbb, 0x40, 0x6c, 0x8b, 0x57, 0x7b, 0x3e, 0x7f,
0x7b, 0xbe, 0x32, 0x70, 0xcc, 0x13, 0x6d, 0xd1, 0x64, 0x68, 0xfa, 0x3a, 0x4e, 0x67, 0x42, 0x16,
0x9f, 0x9e, 0x36, 0xca, 0x29, 0xb2, 0x9f, 0x6b, 0xad, 0xe1, 0x4c, 0xb8, 0x79, 0x7a, 0xd9, 0xe3,
0x2a, 0xe9, 0x33, 0x33, 0x53, 0xda, 0xa8, 0x4f, 0x5e, 0x78, 0xc2, 0x27, 0xfd, 0x6c, 0xd0, 0x37,
0xa8, 0x55, 0x81, 0xf1, 0xa2, 0x70, 0xca, 0x2c, 0x36, 0xc4, 0x1c, 0x17, 0x7d, 0x0b, 0xa0, 0x79,
0xa2, 0xf5, 0x85, 0x33, 0xc8, 0x12, 0x8a, 0x9f, 0x53, 0xb4, 0x8e, 0x3c, 0x87, 0x5a, 0x82, 0x8e,
0x4d, 0x98, 0x63, 0x61, 0xd0, 0x09, 0xba, 0x8d, 0xc1, 0xc3, 0x5e, 0x51, 0xc4, 0x88, 0x49, 0x31,
0x45, 0xeb, 0x8a, 0xd0, 0x51, 0x11, 0x76, 0xbe, 0x43, 0x57, 0x29, 0x24, 0x82, 0xea, 0x54, 0xc4,
0x18, 0xee, 0xfa, 0xd4, 0xc3, 0x32, 0xf5, 0xb5, 0x88, 0xf1, 0x7c, 0x87, 0x7a, 0xdf, 0x69, 0x1d,
0x0e, 0x4c, 0x8e, 0x88, 0x7e, 0x04, 0x70, 0xff, 0x0e, 0x2c, 0x09, 0xe1, 0x80, 0x69, 0xfd, 0x8e,
0x25, 0xe8, 0x0b, 0xa9, 0xd3, 0x52, 0x25, 0x6d, 0x00, 0xa6, 0x35, 0xc5, 0x78, 0xcc, 0xdc, 0xdc,
0xff, 0xaa, 0x4e, 0x37, 0x2c, 0xa4, 0x05, 0x35, 0x3e, 0x47, 0x7e, 0x65, 0xd3, 0x24, 0xac, 0x78,
0xef, 0x4a, 0x27, 0x04, 0xaa, 0x56, 0x7c, 0xc1, 0xb0, 0xda, 0x09, 0xba, 0x15, 0xea, 0x65, 0x12,
0x41, 0x05, 0x65, 0x16, 0xee, 0x75, 0x2a, 0xdd, 0xc6, 0xa0, 0x59, 0xd6, 0x3c, 0x94, 0xd9, 0x50,
0x3a, 0xb3, 0xa0, 0x4b, 0x67, 0xf4, 0x0c, 0x6a, 0xa5, 0x61, 0xc9, 0x90, 0xeb, 0xb2, 0xbc, 0x4c,
0xfe, 0x87, 0xbd, 0x8c, 0xc5, 0x29, 0x16, 0xe5, 0xe4, 0x4a, 0x34, 0x86, 0xe6, 0xba, 0x3d, 0xab,
0x95, 0xb4, 0x48, 0x8e, 0xa0, 0x9e, 0x14, 0x36, 0x1b, 0x06, 0x9d, 0x4a, 0xb7, 0x4e, 0xd7, 0x86,
0x65, 0x6f, 0x56, 0xa5, 0x86, 0xe3, 0xfb, 0x85, 0x2e, 0x61, 0x1b, 0x96, 0x68, 0x0a, 0x84, 0xae,
0x16, 0xb9, 0x62, 0x76, 0xa0, 0x21, 0xec, 0x45, 0xaa, 0xb5, 0x32, 0x0e, 0x27, 0xbe, 0xb0, 0x1a,
0xdd, 0x34, 0x91, 0x1e, 0x10, 0x61, 0x5f, 0x09, 0xcb, 0x55, 0x86, 0x66, 0x31, 0x94, 0xec, 0x32,
0xc6, 0x89, 0xe7, 0xd7, 0xe8, 0x2d, 0x9e, 0xe8, 0x2b, 0xb4, 0xc7, 0xcc, 0xb0, 0x04, 0x1d, 0x1a,
0x7b, 0x22, 0xa5, 0x4a, 0x25, 0xc7, 0x04, 0xe5, 0xba, 0x8f, 0x0f, 0x70, 0x4f, 0x97, 0x11, 0x9b,
0x01, 0x79, 0x53, 0x8d, 0xc1, 0xa3, 0xde, 0xc6, 0xc5, 0x8d, 0x6f, 0x8b, 0xa4, 0x77, 0x00, 0xa2,
0x23, 0xa8, 0x2e, 0x2f, 0x66, 0x39, 0x54, 0x3e, 0x4f, 0xe5, 0x95, 0x6f, 0xe8, 0x90, 0xe6, 0xca,
0xe0, 0xfb, 0x2e, 0x1c, 0xbf, 0x54, 0x72, 0x2a, 0x66, 0x23, 0x26, 0xd9, 0xcc, 0xe7, 0x8c, 0xfd,
0xce, 0x2e, 0xd0, 0x64, 0x82, 0x23, 0x79, 0x03, 0xcd, 0x33, 0x94, 0x68, 0x98, 0xc3, 0x72, 0xfc,
0x24, 0x2c, 0xf7, 0xfa, 0xf7, 0xc9, 0xb7, 0xc2, 0x9b, 0x07, 0x9e, 0xb7, 0x18, 0xed, 0x74, 0x03,
0xf2, 0x16, 0xfe, 0x1b, 0x31, 0xc7, 0xe7, 0xeb, 0xa9, 0x6f, 0x41, 0xb5, 0x4a, 0xcf, 0xcd, 0x1d,
0x79, 0x18, 0x83, 0x07, 0x67, 0xe8, 0x6e, 0x1f, 0xec, 0x16, 0xec, 0xe3, 0xd2, 0xb3, 0x7d, 0x25,
0xcb, 0x5f, 0x9c, 0xbe, 0xf8, 0x79, 0xdd, 0x0e, 0x7e, 0x5d, 0xb7, 0x83, 0xdf, 0xd7, 0xed, 0xe0,
0xe3, 0xe0, 0x1f, 0x4f, 0xc5, 0xfa, 0xc1, 0x61, 0x5a, 0xf0, 0x58, 0xa0, 0x74, 0x97, 0xfb, 0xfe,
0x79, 0x78, 0xfa, 0x27, 0x00, 0x00, 0xff, 0xff, 0x23, 0x88, 0x8e, 0xd3, 0x8e, 0x04, 0x00, 0x00,
// 483 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x53, 0xd1, 0x8e, 0x12, 0x3d,
0x14, 0xa6, 0x3f, 0xec, 0x2e, 0x1c, 0x36, 0xf9, 0x49, 0x63, 0xe2, 0x84, 0xec, 0x22, 0x99, 0x2b,
0x6e, 0x84, 0x04, 0x8d, 0x77, 0x26, 0xba, 0x66, 0x75, 0xa3, 0xc1, 0x90, 0xe2, 0x95, 0x77, 0xdd,
0x72, 0x80, 0xba, 0x33, 0x6d, 0x6d, 0x3b, 0x93, 0xe0, 0x95, 0x6f, 0xe3, 0x2b, 0xf8, 0x08, 0x5e,
0xfa, 0x08, 0x86, 0x27, 0x31, 0x53, 0x66, 0x18, 0xe2, 0x46, 0xaf, 0x38, 0xdf, 0x77, 0xce, 0xf9,
0xf8, 0xbe, 0x4e, 0x0b, 0x97, 0x22, 0x35, 0x0e, 0x6d, 0x8e, 0x76, 0x62, 0x92, 0x6c, 0x2d, 0x55,
0xf9, 0x33, 0x36, 0x56, 0x7b, 0x4d, 0x4f, 0xf7, 0x28, 0xfe, 0x4a, 0xa0, 0xf7, 0xd2, 0x98, 0x85,
0xb7, 0xc8, 0x53, 0x86, 0x9f, 0x33, 0x74, 0x9e, 0x3e, 0x87, 0x76, 0x8a, 0x9e, 0x2f, 0xb9, 0xe7,
0x11, 0x19, 0x92, 0x51, 0x77, 0xfa, 0x68, 0x5c, 0x6e, 0xcf, 0xb8, 0x92, 0x2b, 0x74, 0xbe, 0x1c,
0x9d, 0x95, 0x63, 0x37, 0x0d, 0x76, 0x58, 0xa1, 0x31, 0xb4, 0x56, 0x32, 0xc1, 0xe8, 0xbf, 0xb0,
0x7a, 0x5e, 0xad, 0xbe, 0x96, 0x09, 0xde, 0x34, 0x58, 0xe8, 0x5d, 0x75, 0xe0, 0xcc, 0xee, 0x25,
0xe2, 0x6f, 0x04, 0x1e, 0xfe, 0x45, 0x96, 0x46, 0x70, 0xc6, 0x8d, 0x79, 0xcf, 0x53, 0x0c, 0x46,
0x3a, 0xac, 0x82, 0x74, 0x00, 0xc0, 0x8d, 0x61, 0x98, 0xcc, 0xb9, 0xdf, 0x84, 0xbf, 0xea, 0xb0,
0x23, 0x86, 0xf6, 0xa1, 0x2d, 0x36, 0x28, 0xee, 0x5c, 0x96, 0x46, 0xcd, 0xd0, 0x3d, 0x60, 0x4a,
0xa1, 0xe5, 0xe4, 0x17, 0x8c, 0x5a, 0x43, 0x32, 0x6a, 0xb2, 0x50, 0xd3, 0x18, 0x9a, 0xa8, 0xf2,
0xe8, 0x64, 0xd8, 0x1c, 0x75, 0xa7, 0xbd, 0xca, 0xf3, 0xb5, 0xca, 0xaf, 0x95, 0xb7, 0x5b, 0x56,
0x34, 0xe3, 0xa7, 0xd0, 0xae, 0x88, 0x42, 0x43, 0xd5, 0xb6, 0x42, 0x4d, 0x1f, 0xc0, 0x49, 0xce,
0x93, 0x0c, 0x4b, 0x3b, 0x7b, 0x10, 0xcf, 0xa1, 0x57, 0xc7, 0x73, 0x46, 0x2b, 0x87, 0xf4, 0x02,
0x3a, 0x69, 0xc9, 0xb9, 0x88, 0x0c, 0x9b, 0xa3, 0x0e, 0xab, 0x89, 0x22, 0x9b, 0xd3, 0x99, 0x15,
0xf8, 0x61, 0x6b, 0x2a, 0xb1, 0x23, 0x26, 0x7e, 0x06, 0x94, 0xa1, 0xd1, 0x4e, 0x7a, 0x6d, 0xb7,
0x07, 0xcd, 0x21, 0x74, 0xa5, 0x5b, 0x64, 0xc6, 0x68, 0xeb, 0x71, 0x19, 0x8c, 0xb5, 0xd9, 0x31,
0x15, 0x5f, 0x40, 0xab, 0xf8, 0x08, 0x85, 0x4f, 0xb1, 0xc9, 0xd4, 0x5d, 0x98, 0x39, 0x67, 0x7b,
0x30, 0xfd, 0x4e, 0xe0, 0xf2, 0x95, 0x56, 0x2b, 0xb9, 0x9e, 0x71, 0xc5, 0xd7, 0x98, 0xa2, 0xf2,
0xf3, 0x70, 0x0c, 0x0b, 0xb4, 0xb9, 0x14, 0x48, 0xdf, 0x42, 0xef, 0x0d, 0x2a, 0xb4, 0xdc, 0x63,
0x95, 0x88, 0x46, 0xd5, 0x51, 0xfd, 0x79, 0x8b, 0xfa, 0xd1, 0xfd, 0x3b, 0xb3, 0x77, 0x1a, 0x37,
0x46, 0x84, 0xbe, 0x83, 0xff, 0x67, 0xdc, 0x8b, 0x4d, 0x1d, 0xe4, 0x1f, 0x52, 0xfd, 0xaa, 0x73,
0x3f, 0x76, 0x21, 0x76, 0xf5, 0xe2, 0xc7, 0x6e, 0x40, 0x7e, 0xee, 0x06, 0xe4, 0xd7, 0x6e, 0x40,
0x3e, 0x4e, 0xd7, 0xd2, 0x6f, 0xb2, 0xdb, 0xb1, 0xd0, 0xe9, 0x84, 0xdb, 0xb5, 0x36, 0x56, 0x7f,
0x0a, 0xc5, 0x63, 0xb1, 0x9c, 0xe4, 0xd3, 0x49, 0xfd, 0x32, 0xb8, 0x91, 0x22, 0x91, 0xa8, 0xfc,
0xed, 0x69, 0x78, 0x16, 0x4f, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, 0x83, 0x01, 0x5e, 0x48, 0x37,
0x03, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -536,8 +472,6 @@ type ConfigManagementPluginServiceClient interface {
GenerateManifest(ctx context.Context, opts ...grpc.CallOption) (ConfigManagementPluginService_GenerateManifestClient, error)
// MatchRepository returns whether or not the given application is supported by the plugin
MatchRepository(ctx context.Context, opts ...grpc.CallOption) (ConfigManagementPluginService_MatchRepositoryClient, error)
// GetParametersAnnouncement gets a list of parameter announcements for the given app
GetParametersAnnouncement(ctx context.Context, opts ...grpc.CallOption) (ConfigManagementPluginService_GetParametersAnnouncementClient, error)
}
type configManagementPluginServiceClient struct {
@@ -616,40 +550,6 @@ func (x *configManagementPluginServiceMatchRepositoryClient) CloseAndRecv() (*Re
return m, nil
}
func (c *configManagementPluginServiceClient) GetParametersAnnouncement(ctx context.Context, opts ...grpc.CallOption) (ConfigManagementPluginService_GetParametersAnnouncementClient, error) {
stream, err := c.cc.NewStream(ctx, &_ConfigManagementPluginService_serviceDesc.Streams[2], "/plugin.ConfigManagementPluginService/GetParametersAnnouncement", opts...)
if err != nil {
return nil, err
}
x := &configManagementPluginServiceGetParametersAnnouncementClient{stream}
return x, nil
}
type ConfigManagementPluginService_GetParametersAnnouncementClient interface {
Send(*AppStreamRequest) error
CloseAndRecv() (*ParametersAnnouncementResponse, error)
grpc.ClientStream
}
type configManagementPluginServiceGetParametersAnnouncementClient struct {
grpc.ClientStream
}
func (x *configManagementPluginServiceGetParametersAnnouncementClient) Send(m *AppStreamRequest) error {
return x.ClientStream.SendMsg(m)
}
func (x *configManagementPluginServiceGetParametersAnnouncementClient) CloseAndRecv() (*ParametersAnnouncementResponse, error) {
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
m := new(ParametersAnnouncementResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// ConfigManagementPluginServiceServer is the server API for ConfigManagementPluginService service.
type ConfigManagementPluginServiceServer interface {
// GenerateManifests receive a stream containing a tgz archive with all required files necessary
@@ -657,8 +557,6 @@ type ConfigManagementPluginServiceServer interface {
GenerateManifest(ConfigManagementPluginService_GenerateManifestServer) error
// MatchRepository returns whether or not the given application is supported by the plugin
MatchRepository(ConfigManagementPluginService_MatchRepositoryServer) error
// GetParametersAnnouncement gets a list of parameter announcements for the given app
GetParametersAnnouncement(ConfigManagementPluginService_GetParametersAnnouncementServer) error
}
// UnimplementedConfigManagementPluginServiceServer can be embedded to have forward compatible implementations.
@@ -671,9 +569,6 @@ func (*UnimplementedConfigManagementPluginServiceServer) GenerateManifest(srv Co
func (*UnimplementedConfigManagementPluginServiceServer) MatchRepository(srv ConfigManagementPluginService_MatchRepositoryServer) error {
return status.Errorf(codes.Unimplemented, "method MatchRepository not implemented")
}
func (*UnimplementedConfigManagementPluginServiceServer) GetParametersAnnouncement(srv ConfigManagementPluginService_GetParametersAnnouncementServer) error {
return status.Errorf(codes.Unimplemented, "method GetParametersAnnouncement not implemented")
}
func RegisterConfigManagementPluginServiceServer(s *grpc.Server, srv ConfigManagementPluginServiceServer) {
s.RegisterService(&_ConfigManagementPluginService_serviceDesc, srv)
@@ -731,32 +626,6 @@ func (x *configManagementPluginServiceMatchRepositoryServer) Recv() (*AppStreamR
return m, nil
}
func _ConfigManagementPluginService_GetParametersAnnouncement_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(ConfigManagementPluginServiceServer).GetParametersAnnouncement(&configManagementPluginServiceGetParametersAnnouncementServer{stream})
}
type ConfigManagementPluginService_GetParametersAnnouncementServer interface {
SendAndClose(*ParametersAnnouncementResponse) error
Recv() (*AppStreamRequest, error)
grpc.ServerStream
}
type configManagementPluginServiceGetParametersAnnouncementServer struct {
grpc.ServerStream
}
func (x *configManagementPluginServiceGetParametersAnnouncementServer) SendAndClose(m *ParametersAnnouncementResponse) error {
return x.ServerStream.SendMsg(m)
}
func (x *configManagementPluginServiceGetParametersAnnouncementServer) Recv() (*AppStreamRequest, error) {
m := new(AppStreamRequest)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
var _ConfigManagementPluginService_serviceDesc = grpc.ServiceDesc{
ServiceName: "plugin.ConfigManagementPluginService",
HandlerType: (*ConfigManagementPluginServiceServer)(nil),
@@ -772,11 +641,6 @@ var _ConfigManagementPluginService_serviceDesc = grpc.ServiceDesc{
Handler: _ConfigManagementPluginService_MatchRepository_Handler,
ClientStreams: true,
},
{
StreamName: "GetParametersAnnouncement",
Handler: _ConfigManagementPluginService_GetParametersAnnouncement_Handler,
ClientStreams: true,
},
},
Metadata: "cmpserver/plugin/plugin.proto",
}
@@ -1034,16 +898,6 @@ func (m *RepositoryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if m.IsDiscoveryEnabled {
i--
if m.IsDiscoveryEnabled {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x10
}
if m.IsSupported {
i--
if m.IsSupported {
@@ -1057,47 +911,6 @@ func (m *RepositoryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *ParametersAnnouncementResponse) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ParametersAnnouncementResponse) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *ParametersAnnouncementResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.XXX_unrecognized != nil {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if len(m.ParameterAnnouncements) > 0 {
for iNdEx := len(m.ParameterAnnouncements) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.ParameterAnnouncements[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintPlugin(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
func (m *File) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -1266,27 +1079,6 @@ func (m *RepositoryResponse) Size() (n int) {
if m.IsSupported {
n += 2
}
if m.IsDiscoveryEnabled {
n += 2
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func (m *ParametersAnnouncementResponse) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if len(m.ParameterAnnouncements) > 0 {
for _, e := range m.ParameterAnnouncements {
l = e.Size()
n += 1 + l + sovPlugin(uint64(l))
}
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@@ -1915,111 +1707,6 @@ func (m *RepositoryResponse) Unmarshal(dAtA []byte) error {
}
}
m.IsSupported = bool(v != 0)
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field IsDiscoveryEnabled", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.IsDiscoveryEnabled = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipPlugin(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthPlugin
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *ParametersAnnouncementResponse) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ParametersAnnouncementResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ParametersAnnouncementResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ParameterAnnouncements", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthPlugin
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ParameterAnnouncements = append(m.ParameterAnnouncements, &apiclient.ParameterAnnouncement{})
if err := m.ParameterAnnouncements[len(m.ParameterAnnouncements)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipPlugin(dAtA[iNdEx:])

View File

@@ -7,7 +7,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
configUtil "github.com/argoproj/argo-cd/v2/util/config"
)
@@ -22,11 +21,10 @@ type PluginConfig struct {
}
type PluginConfigSpec struct {
Version string `json:"version"`
Init Command `json:"init,omitempty"`
Generate Command `json:"generate"`
Discover Discover `json:"discover"`
Parameters Parameters `yaml:"parameters"`
Version string `json:"version"`
Init Command `json:"init,omitempty"`
Generate Command `json:"generate"`
Discover Discover `json:"discover"`
}
//Discover holds find and fileName
@@ -47,17 +45,6 @@ type Find struct {
Glob string `json:"glob"`
}
// Parameters holds static and dynamic configurations
type Parameters struct {
Static []*apiclient.ParameterAnnouncement `yaml:"static"`
Dynamic Command `yaml:"dynamic"`
}
// Dynamic hold the dynamic announcements for CMP's
type Dynamic struct {
Command
}
func ReadPluginConfig(filePath string) (*PluginConfig, error) {
path := fmt.Sprintf("%s/%s", strings.TrimRight(filePath, "/"), common.PluginConfigFileName)
@@ -84,7 +71,9 @@ func ValidatePluginConfig(config PluginConfig) error {
if len(config.Spec.Generate.Command) == 0 {
return fmt.Errorf("invalid plugin configuration file. spec.generate command should be non-empty")
}
// discovery field is optional as apps can now specify plugin names directly
if config.Spec.Discover.Find.Glob == "" && len(config.Spec.Discover.Find.Command.Command) == 0 && config.Spec.Discover.FileName == "" {
return fmt.Errorf("invalid plugin configuration file. atleast one of discover.find.command or discover.find.glob or discover.fineName should be non-empty")
}
return nil
}

View File

@@ -3,7 +3,6 @@ package plugin
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"os"
@@ -14,9 +13,7 @@ import (
"github.com/argoproj/pkg/rand"
"github.com/argoproj/argo-cd/v2/cmpserver/apiclient"
"github.com/argoproj/argo-cd/v2/common"
repoclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/util/buffered_context"
"github.com/argoproj/argo-cd/v2/util/cmp"
"github.com/argoproj/argo-cd/v2/util/io/files"
@@ -24,6 +21,8 @@ import (
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/mattn/go-zglob"
log "github.com/sirupsen/logrus"
"github.com/argoproj/argo-cd/v2/cmpserver/apiclient"
)
// cmpTimeoutBuffer is the amount of time before the request deadline to timeout server-side work. It makes sure there's
@@ -46,14 +45,15 @@ func NewService(initConstants CMPServerInitConstants) *Service {
}
}
func (s *Service) Init(workDir string) error {
func (s *Service) Init() error {
workDir := common.GetCMPWorkDir()
err := os.RemoveAll(workDir)
if err != nil {
return fmt.Errorf("error removing workdir %q: %w", workDir, err)
return fmt.Errorf("error removing workdir %q: %s", workDir, err)
}
err = os.MkdirAll(workDir, 0700)
if err != nil {
return fmt.Errorf("error creating workdir %q: %w", workDir, err)
return fmt.Errorf("error creating workdir %q: %s", workDir, err)
}
return nil
}
@@ -143,50 +143,24 @@ func environ(envVars []*apiclient.EnvEntry) []string {
return environ
}
// getTempDirMustCleanup creates a temporary directory and returns a cleanup function.
func getTempDirMustCleanup(baseDir string) (workDir string, cleanup func(), err error) {
workDir, err = files.CreateTempDir(baseDir)
if err != nil {
return "", nil, fmt.Errorf("error creating temp dir: %w", err)
}
cleanup = func() {
if err := os.RemoveAll(workDir); err != nil {
log.WithFields(map[string]interface{}{
common.SecurityField: common.SecurityHigh,
common.SecurityCWEField: 459,
}).Errorf("Failed to clean up temp directory: %s", err)
}
}
return workDir, cleanup, nil
}
type Stream interface {
Recv() (*apiclient.AppStreamRequest, error)
Context() context.Context
}
type GenerateManifestStream interface {
Stream
SendAndClose(response *apiclient.ManifestResponse) error
}
// GenerateManifest runs generate command from plugin config file and returns generated manifest files
func (s *Service) GenerateManifest(stream apiclient.ConfigManagementPluginService_GenerateManifestServer) error {
return s.generateManifestGeneric(stream)
}
func (s *Service) generateManifestGeneric(stream GenerateManifestStream) error {
ctx, cancel := buffered_context.WithEarlierDeadline(stream.Context(), cmpTimeoutBuffer)
defer cancel()
workDir, cleanup, err := getTempDirMustCleanup(common.GetCMPWorkDir())
workDir, err := files.CreateTempDir(common.GetCMPWorkDir())
if err != nil {
return fmt.Errorf("error creating workdir for manifest generation: %w", err)
return fmt.Errorf("error creating temp dir: %s", err)
}
defer cleanup()
defer func() {
if err := os.RemoveAll(workDir); err != nil {
// we panic here as the workDir may contain sensitive information
panic(fmt.Sprintf("error removing generate manifest workdir: %s", err))
}
}()
metadata, err := cmp.ReceiveRepoStream(ctx, stream, workDir)
if err != nil {
return fmt.Errorf("generate manifest error receiving stream: %w", err)
return fmt.Errorf("generate manifest error receiving stream: %s", err)
}
appPath := filepath.Clean(filepath.Join(workDir, metadata.AppRelPath))
@@ -195,11 +169,11 @@ func (s *Service) generateManifestGeneric(stream GenerateManifestStream) error {
}
response, err := s.generateManifest(ctx, appPath, metadata.GetEnv())
if err != nil {
return fmt.Errorf("error generating manifests: %w", err)
return fmt.Errorf("error generating manifests: %s", err)
}
err = stream.SendAndClose(response)
if err != nil {
return fmt.Errorf("error sending manifest response: %w", err)
return fmt.Errorf("error sending manifest response: %s", err)
}
return nil
}
@@ -229,11 +203,6 @@ func (s *Service) generateManifest(ctx context.Context, appDir string, envEntrie
manifests, err := kube.SplitYAMLToString([]byte(out))
if err != nil {
sanitizedManifests := manifests
if len(sanitizedManifests) > 1000 {
sanitizedManifests = manifests[:1000]
}
log.Debugf("Failed to split generated manifests. Beginning of generated manifests: %q", sanitizedManifests)
return &apiclient.ManifestResponse{}, err
}
@@ -242,63 +211,58 @@ func (s *Service) generateManifest(ctx context.Context, appDir string, envEntrie
}, err
}
type MatchRepositoryStream interface {
Stream
SendAndClose(response *apiclient.RepositoryResponse) error
}
// MatchRepository receives the application stream and checks whether
// its repository type is supported by the config management plugin
// server.
// The checks are implemented in the following order:
// 1. If spec.Discover.FileName is provided it finds for a name match in Applications files
// 2. If spec.Discover.Find.Glob is provided if finds for a glob match in Applications files
// 3. Otherwise it runs the spec.Discover.Find.Command
//The checks are implemented in the following order:
// 1. If spec.Discover.FileName is provided it finds for a name match in Applications files
// 2. If spec.Discover.Find.Glob is provided if finds for a glob match in Applications files
// 3. Otherwise it runs the spec.Discover.Find.Command
func (s *Service) MatchRepository(stream apiclient.ConfigManagementPluginService_MatchRepositoryServer) error {
return s.matchRepositoryGeneric(stream)
}
func (s *Service) matchRepositoryGeneric(stream MatchRepositoryStream) error {
bufferedCtx, cancel := buffered_context.WithEarlierDeadline(stream.Context(), cmpTimeoutBuffer)
defer cancel()
workDir, cleanup, err := getTempDirMustCleanup(common.GetCMPWorkDir())
workDir, err := files.CreateTempDir(common.GetCMPWorkDir())
if err != nil {
return fmt.Errorf("error creating workdir for repository matching: %w", err)
return fmt.Errorf("error creating match repository workdir: %s", err)
}
defer cleanup()
defer func() {
if err := os.RemoveAll(workDir); err != nil {
// we panic here as the workDir may contain sensitive information
panic(fmt.Sprintf("error removing match repository workdir: %s", err))
}
}()
metadata, err := cmp.ReceiveRepoStream(bufferedCtx, stream, workDir)
if err != nil {
return fmt.Errorf("match repository error receiving stream: %w", err)
return fmt.Errorf("match repository error receiving stream: %s", err)
}
isSupported, isDiscoveryEnabled, err := s.matchRepository(bufferedCtx, workDir, metadata.GetEnv())
isSupported, err := s.matchRepository(bufferedCtx, workDir, metadata.GetEnv())
if err != nil {
return fmt.Errorf("match repository error: %w", err)
return fmt.Errorf("match repository error: %s", err)
}
repoResponse := &apiclient.RepositoryResponse{IsSupported: isSupported, IsDiscoveryEnabled: isDiscoveryEnabled}
repoResponse := &apiclient.RepositoryResponse{IsSupported: isSupported}
err = stream.SendAndClose(repoResponse)
if err != nil {
return fmt.Errorf("error sending match repository response: %w", err)
return fmt.Errorf("error sending match repository response: %s", err)
}
return nil
}
func (s *Service) matchRepository(ctx context.Context, workdir string, envEntries []*apiclient.EnvEntry) (isSupported bool, isDiscoveryEnabled bool, err error) {
func (s *Service) matchRepository(ctx context.Context, workdir string, envEntries []*apiclient.EnvEntry) (bool, error) {
config := s.initConstants.PluginConfig
if config.Spec.Discover.FileName != "" {
log.Debugf("config.Spec.Discover.FileName is provided")
pattern := filepath.Join(workdir, config.Spec.Discover.FileName)
matches, err := filepath.Glob(pattern)
if err != nil {
e := fmt.Errorf("error finding filename match for pattern %q: %w", pattern, err)
e := fmt.Errorf("error finding filename match for pattern %q: %s", pattern, err)
log.Debug(e)
return false, true, e
return false, e
}
return len(matches) > 0, true, nil
return len(matches) > 0, nil
}
if config.Spec.Discover.Find.Glob != "" {
@@ -308,86 +272,27 @@ func (s *Service) matchRepository(ctx context.Context, workdir string, envEntrie
// https://github.com/golang/go/issues/11862
matches, err := zglob.Glob(pattern)
if err != nil {
e := fmt.Errorf("error finding glob match for pattern %q: %w", pattern, err)
e := fmt.Errorf("error finding glob match for pattern %q: %s", pattern, err)
log.Debug(e)
return false, true, e
return false, e
}
return len(matches) > 0, true, nil
}
if len(config.Spec.Discover.Find.Command.Command) > 0 {
log.Debugf("Going to try runCommand.")
env := append(os.Environ(), environ(envEntries)...)
find, err := runCommand(ctx, config.Spec.Discover.Find.Command, workdir, env)
if err != nil {
return false, true, fmt.Errorf("error running find command: %w", err)
if len(matches) > 0 {
return true, nil
}
return find != "", true, nil
return false, nil
}
return false, false, nil
}
log.Debugf("Going to try runCommand.")
env := append(os.Environ(), environ(envEntries)...)
// ParametersAnnouncementStream defines an interface able to send/receive a stream of parameter announcements.
type ParametersAnnouncementStream interface {
Stream
SendAndClose(response *apiclient.ParametersAnnouncementResponse) error
}
// GetParametersAnnouncement gets parameter announcements for a given Application and repo contents.
func (s *Service) GetParametersAnnouncement(stream apiclient.ConfigManagementPluginService_GetParametersAnnouncementServer) error {
bufferedCtx, cancel := buffered_context.WithEarlierDeadline(stream.Context(), cmpTimeoutBuffer)
defer cancel()
workDir, cleanup, err := getTempDirMustCleanup(common.GetCMPWorkDir())
find, err := runCommand(ctx, config.Spec.Discover.Find.Command, workdir, env)
if err != nil {
return fmt.Errorf("error creating workdir for generating parameter announcements: %w", err)
}
defer cleanup()
metadata, err := cmp.ReceiveRepoStream(bufferedCtx, stream, workDir)
if err != nil {
return fmt.Errorf("parameters announcement error receiving stream: %w", err)
}
appPath := filepath.Clean(filepath.Join(workDir, metadata.AppRelPath))
if !strings.HasPrefix(appPath, workDir) {
return fmt.Errorf("illegal appPath: out of workDir bound")
return false, fmt.Errorf("error running find command: %s", err)
}
repoResponse, err := getParametersAnnouncement(bufferedCtx, appPath, s.initConstants.PluginConfig.Spec.Parameters.Static, s.initConstants.PluginConfig.Spec.Parameters.Dynamic)
if err != nil {
return fmt.Errorf("get parameters announcement error: %w", err)
if find != "" {
return true, nil
}
err = stream.SendAndClose(repoResponse)
if err != nil {
return fmt.Errorf("error sending parameters announcement response: %w", err)
}
return nil
}
func getParametersAnnouncement(ctx context.Context, appDir string, announcements []*repoclient.ParameterAnnouncement, command Command) (*apiclient.ParametersAnnouncementResponse, error) {
augmentedAnnouncements := announcements
if len(command.Command) > 0 {
stdout, err := runCommand(ctx, command, appDir, os.Environ())
if err != nil {
return nil, fmt.Errorf("error executing dynamic parameter output command: %w", err)
}
var dynamicParamAnnouncements []*repoclient.ParameterAnnouncement
err = json.Unmarshal([]byte(stdout), &dynamicParamAnnouncements)
if err != nil {
return nil, fmt.Errorf("error unmarshaling dynamic parameter output into ParametersAnnouncementResponse: %w", err)
}
// dynamic goes first, because static should take precedence by being later.
augmentedAnnouncements = append(dynamicParamAnnouncements, announcements...)
}
repoResponse := &apiclient.ParametersAnnouncementResponse{
ParameterAnnouncements: augmentedAnnouncements,
}
return repoResponse, nil
return false, nil
}

View File

@@ -3,8 +3,6 @@ option go_package = "github.com/argoproj/argo-cd/v2/cmpserver/apiclient";
package plugin;
import "github.com/argoproj/argo-cd/v2/reposerver/repository/repository.proto";
// AppStreamRequest is the request object used to send the application's
// files over a stream.
message AppStreamRequest {
@@ -44,13 +42,6 @@ message ManifestResponse {
message RepositoryResponse {
bool isSupported = 1;
bool isDiscoveryEnabled = 2;
}
// ParametersAnnouncementResponse contains a list of announcements. This list represents all the parameters which a CMP
// is able to accept.
message ParametersAnnouncementResponse {
repeated repository.ParameterAnnouncement parameterAnnouncements = 1;
}
message File {
@@ -67,8 +58,4 @@ service ConfigManagementPluginService {
// MatchRepository returns whether or not the given application is supported by the plugin
rpc MatchRepository(stream AppStreamRequest) returns (RepositoryResponse) {
}
// GetParametersAnnouncement gets a list of parameter announcements for the given app
rpc GetParametersAnnouncement(stream AppStreamRequest) returns (ParametersAnnouncementResponse) {
}
}

View File

@@ -1,27 +1,17 @@
package plugin
import (
"bytes"
"context"
"fmt"
"io"
"os"
"path"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/metadata"
"gopkg.in/yaml.v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/argoproj/argo-cd/v2/cmpserver/apiclient"
repoclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/test"
"github.com/argoproj/argo-cd/v2/util/cmp"
"github.com/argoproj/argo-cd/v2/util/tgzstream"
)
func newService(configFilePath string) (*Service, error) {
@@ -40,11 +30,6 @@ func newService(configFilePath string) (*Service, error) {
return service, nil
}
func (s *Service) WithGenerateCommand(command Command) *Service {
s.initConstants.PluginConfig.Spec.Generate = command
return s
}
type pluginOpt func(*CMPServerInitConstants)
func withDiscover(d Discover) pluginOpt {
@@ -99,12 +84,11 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, err := f.service.matchRepository(context.Background(), f.path, f.env)
// then
assert.NoError(t, err)
assert.True(t, match)
assert.True(t, discovery)
})
t.Run("will not match plugin by filename if file not found", func(t *testing.T) {
// given
@@ -114,25 +98,11 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, err := f.service.matchRepository(context.Background(), f.path, f.env)
// then
assert.NoError(t, err)
assert.False(t, match)
assert.True(t, discovery)
})
t.Run("will not match a pattern with a syntax error", func(t *testing.T) {
// given
d := Discover{
FileName: "[",
}
f := setup(t, withDiscover(d))
// when
_, _, err := f.service.matchRepository(context.Background(), f.path, f.env)
// then
assert.ErrorContains(t, err, "syntax error")
})
t.Run("will match plugin by glob", func(t *testing.T) {
// given
@@ -144,12 +114,11 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, err := f.service.matchRepository(context.Background(), f.path, f.env)
// then
assert.NoError(t, err)
assert.True(t, match)
assert.True(t, discovery)
})
t.Run("will not match plugin by glob if not found", func(t *testing.T) {
// given
@@ -161,27 +130,11 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, err := f.service.matchRepository(context.Background(), f.path, f.env)
// then
assert.NoError(t, err)
assert.False(t, match)
assert.True(t, discovery)
})
t.Run("will throw an error for a bad pattern", func(t *testing.T) {
// given
d := Discover{
Find: Find{
Glob: "does-not-exist",
},
}
f := setup(t, withDiscover(d))
// when
_, _, err := f.service.matchRepository(context.Background(), f.path, f.env)
// then
assert.ErrorContains(t, err, "error finding glob match for pattern")
})
t.Run("will match plugin by command when returns any output", func(t *testing.T) {
// given
@@ -195,12 +148,11 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, err := f.service.matchRepository(context.Background(), f.path, f.env)
// then
assert.NoError(t, err)
assert.True(t, match)
assert.True(t, discovery)
})
t.Run("will not match plugin by command when returns no output", func(t *testing.T) {
// given
@@ -214,11 +166,11 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, err := f.service.matchRepository(context.Background(), f.path, f.env)
// then
assert.NoError(t, err)
assert.False(t, match)
assert.True(t, discovery)
})
t.Run("will match plugin because env var defined", func(t *testing.T) {
// given
@@ -232,12 +184,11 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, err := f.service.matchRepository(context.Background(), f.path, f.env)
// then
assert.NoError(t, err)
assert.True(t, match)
assert.True(t, discovery)
})
t.Run("will not match plugin because no env var defined", func(t *testing.T) {
// given
@@ -252,12 +203,11 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, err := f.service.matchRepository(context.Background(), f.path, f.env)
// then
assert.NoError(t, err)
assert.False(t, match)
assert.True(t, discovery)
})
t.Run("will not match plugin by command when command fails", func(t *testing.T) {
// given
@@ -271,25 +221,11 @@ func TestMatchRepository(t *testing.T) {
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
match, err := f.service.matchRepository(context.Background(), f.path, f.env)
// then
assert.Error(t, err)
assert.False(t, match)
assert.True(t, discovery)
})
t.Run("will not match plugin as discovery is not set", func(t *testing.T) {
// given
d := Discover{}
f := setup(t, withDiscover(d))
// when
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
// then
assert.NoError(t, err)
assert.False(t, match)
assert.False(t, discovery)
})
}
@@ -302,49 +238,17 @@ func Test_Negative_ConfigFile_DoesnotExist(t *testing.T) {
func TestGenerateManifest(t *testing.T) {
configFilePath := "./testdata/kustomize/config"
t.Run("successful generate", func(t *testing.T) {
service, err := newService(configFilePath)
require.NoError(t, err)
res1, err := service.generateManifest(context.Background(), "testdata/kustomize", nil)
require.NoError(t, err)
require.NotNil(t, res1)
expectedOutput := "{\"apiVersion\":\"v1\",\"data\":{\"foo\":\"bar\"},\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"my-map\"}}"
if res1 != nil {
require.Equal(t, expectedOutput, res1.Manifests[0])
}
})
t.Run("bad generate command", func(t *testing.T) {
service, err := newService(configFilePath)
require.NoError(t, err)
service.WithGenerateCommand(Command{Command: []string{"bad-command"}})
res, err := service.generateManifest(context.Background(), "testdata/kustomize", nil)
assert.ErrorContains(t, err, "executable file not found")
assert.Nil(t, res.Manifests)
})
t.Run("bad yaml output", func(t *testing.T) {
service, err := newService(configFilePath)
require.NoError(t, err)
service.WithGenerateCommand(Command{Command: []string{"echo", "invalid yaml: }"}})
res, err := service.generateManifest(context.Background(), "testdata/kustomize", nil)
assert.ErrorContains(t, err, "failed to unmarshal manifest")
assert.Nil(t, res.Manifests)
})
}
func TestGenerateManifest_deadline_exceeded(t *testing.T) {
configFilePath := "./testdata/kustomize/config"
service, err := newService(configFilePath)
require.NoError(t, err)
expiredCtx, cancel := context.WithTimeout(context.Background(), time.Second*0)
defer cancel()
_, err = service.generateManifest(expiredCtx, "", nil)
assert.ErrorContains(t, err, "context deadline exceeded")
res1, err := service.generateManifest(context.Background(), "", nil)
require.NoError(t, err)
require.NotNil(t, res1)
expectedOutput := "{\"apiVersion\":\"v1\",\"data\":{\"foo\":\"bar\"},\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"my-map\"}}"
if res1 != nil {
require.Equal(t, expectedOutput, res1.Manifests[0])
}
}
// TestRunCommandContextTimeout makes sure the command dies at timeout rather than sleeping past the timeout.
@@ -362,388 +266,3 @@ func TestRunCommandContextTimeout(t *testing.T) {
assert.Error(t, err) // The command should time out, causing an error.
assert.Less(t, after.Sub(before), 1*time.Second)
}
func TestRunCommandEmptyCommand(t *testing.T) {
_, err := runCommand(context.Background(), Command{}, "", nil)
assert.ErrorContains(t, err, "Command is empty")
}
func Test_getParametersAnnouncement_empty_command(t *testing.T) {
staticYAML := `
- name: static-a
- name: static-b
`
static := &[]*repoclient.ParameterAnnouncement{}
err := yaml.Unmarshal([]byte(staticYAML), static)
require.NoError(t, err)
command := Command{
Command: []string{"echo"},
Args: []string{`[]`},
}
res, err := getParametersAnnouncement(context.Background(), "", *static, command)
require.NoError(t, err)
assert.Equal(t, []*repoclient.ParameterAnnouncement{{Name: "static-a"}, {Name: "static-b"}}, res.ParameterAnnouncements)
}
func Test_getParametersAnnouncement_no_command(t *testing.T) {
staticYAML := `
- name: static-a
- name: static-b
`
static := &[]*repoclient.ParameterAnnouncement{}
err := yaml.Unmarshal([]byte(staticYAML), static)
require.NoError(t, err)
command := Command{}
res, err := getParametersAnnouncement(context.Background(), "", *static, command)
require.NoError(t, err)
assert.Equal(t, []*repoclient.ParameterAnnouncement{{Name: "static-a"}, {Name: "static-b"}}, res.ParameterAnnouncements)
}
func Test_getParametersAnnouncement_static_and_dynamic(t *testing.T) {
staticYAML := `
- name: static-a
- name: static-b
`
static := &[]*repoclient.ParameterAnnouncement{}
err := yaml.Unmarshal([]byte(staticYAML), static)
require.NoError(t, err)
command := Command{
Command: []string{"echo"},
Args: []string{`[{"name": "dynamic-a"}, {"name": "dynamic-b"}]`},
}
res, err := getParametersAnnouncement(context.Background(), "", *static, command)
require.NoError(t, err)
expected := []*repoclient.ParameterAnnouncement{
{Name: "dynamic-a"},
{Name: "dynamic-b"},
{Name: "static-a"},
{Name: "static-b"},
}
assert.Equal(t, expected, res.ParameterAnnouncements)
}
func Test_getParametersAnnouncement_invalid_json(t *testing.T) {
command := Command{
Command: []string{"echo"},
Args: []string{`[`},
}
_, err := getParametersAnnouncement(context.Background(), "", []*repoclient.ParameterAnnouncement{}, command)
assert.Error(t, err)
assert.Contains(t, err.Error(), "unexpected end of JSON input")
}
func Test_getParametersAnnouncement_bad_command(t *testing.T) {
command := Command{
Command: []string{"exit"},
Args: []string{"1"},
}
_, err := getParametersAnnouncement(context.Background(), "", []*repoclient.ParameterAnnouncement{}, command)
assert.Error(t, err)
assert.Contains(t, err.Error(), "error executing dynamic parameter output command")
}
func Test_getTempDirMustCleanup(t *testing.T) {
tempDir := t.TempDir()
// Induce a directory create error to verify error handling.
err := os.Chmod(tempDir, 0000)
require.NoError(t, err)
_, _, err = getTempDirMustCleanup(path.Join(tempDir, "test"))
assert.ErrorContains(t, err, "error creating temp dir")
err = os.Chmod(tempDir, 0700)
require.NoError(t, err)
workDir, cleanup, err := getTempDirMustCleanup(tempDir)
require.NoError(t, err)
require.DirExists(t, workDir)
cleanup()
assert.NoDirExists(t, workDir)
}
func TestService_Init(t *testing.T) {
// Set up a base directory containing a test directory and a test file.
tempDir := t.TempDir()
workDir := path.Join(tempDir, "workDir")
err := os.MkdirAll(workDir, 0700)
require.NoError(t, err)
testfile := path.Join(workDir, "testfile")
file, err := os.Create(testfile)
require.NoError(t, err)
err = file.Close()
require.NoError(t, err)
// Make the base directory read-only so Init's cleanup fails.
err = os.Chmod(tempDir, 0000)
require.NoError(t, err)
s := NewService(CMPServerInitConstants{PluginConfig: PluginConfig{}})
err = s.Init(workDir)
assert.ErrorContains(t, err, "error removing workdir", "Init must throw an error if it can't remove the work directory")
// Make the base directory writable so Init's cleanup succeeds.
err = os.Chmod(tempDir, 0700)
require.NoError(t, err)
err = s.Init(workDir)
assert.NoError(t, err)
assert.DirExists(t, workDir)
assert.NoFileExists(t, testfile)
}
func TestEnviron(t *testing.T) {
t.Run("empty environ", func(t *testing.T) {
env := environ([]*apiclient.EnvEntry{})
assert.Nil(t, env)
})
t.Run("env vars with empty names or values", func(t *testing.T) {
env := environ([]*apiclient.EnvEntry{
{Value: "test"},
{Name: "test"},
})
assert.Nil(t, env)
})
t.Run("proper env vars", func(t *testing.T) {
env := environ([]*apiclient.EnvEntry{
{Name: "name1", Value: "value1"},
{Name: "name2", Value: "value2"},
})
assert.Equal(t, []string{"name1=value1", "name2=value2"}, env)
})
}
type MockGenerateManifestStream struct {
metadataSent bool
fileSent bool
metadataRequest *apiclient.AppStreamRequest
fileRequest *apiclient.AppStreamRequest
response *apiclient.ManifestResponse
}
func NewMockGenerateManifestStream(repoPath, appPath string, env []string) (*MockGenerateManifestStream, error) {
tgz, mr, err := cmp.GetCompressedRepoAndMetadata(repoPath, appPath, env, nil, nil)
if err != nil {
return nil, err
}
defer tgzstream.CloseAndDelete(tgz)
tgzBuffer := bytes.NewBuffer(nil)
_, err = io.Copy(tgzBuffer, tgz)
if err != nil {
return nil, fmt.Errorf("failed to copy manifest targz to a byte buffer: %w", err)
}
return &MockGenerateManifestStream{
metadataRequest: mr,
fileRequest: cmp.AppFileRequest(tgzBuffer.Bytes()),
}, nil
}
func (m *MockGenerateManifestStream) SendAndClose(response *apiclient.ManifestResponse) error {
m.response = response
return nil
}
func (m *MockGenerateManifestStream) Recv() (*apiclient.AppStreamRequest, error) {
if !m.metadataSent {
m.metadataSent = true
return m.metadataRequest, nil
}
if !m.fileSent {
m.fileSent = true
return m.fileRequest, nil
}
return nil, io.EOF
}
func (m *MockGenerateManifestStream) Context() context.Context {
return context.Background()
}
func TestService_GenerateManifest(t *testing.T) {
configFilePath := "./testdata/kustomize/config"
service, err := newService(configFilePath)
require.NoError(t, err)
t.Run("successful generate", func(t *testing.T) {
s, err := NewMockGenerateManifestStream("./testdata/kustomize", "./testdata/kustomize", nil)
require.NoError(t, err)
err = service.generateManifestGeneric(s)
require.NoError(t, err)
require.NotNil(t, s.response)
assert.Equal(t, []string{"{\"apiVersion\":\"v1\",\"data\":{\"foo\":\"bar\"},\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"my-map\"}}"}, s.response.Manifests)
})
t.Run("out-of-bounds app path", func(t *testing.T) {
s, err := NewMockGenerateManifestStream("./testdata/kustomize", "./testdata/kustomize", nil)
require.NoError(t, err)
// set a malicious app path on the metadata
s.metadataRequest.Request.(*apiclient.AppStreamRequest_Metadata).Metadata.AppRelPath = "../out-of-bounds"
err = service.generateManifestGeneric(s)
require.ErrorContains(t, err, "illegal appPath")
assert.Nil(t, s.response)
})
}
type MockMatchRepositoryStream struct {
metadataSent bool
fileSent bool
metadataRequest *apiclient.AppStreamRequest
fileRequest *apiclient.AppStreamRequest
response *apiclient.RepositoryResponse
}
func NewMockMatchRepositoryStream(repoPath, appPath string, env []string) (*MockMatchRepositoryStream, error) {
tgz, mr, err := cmp.GetCompressedRepoAndMetadata(repoPath, appPath, env, nil, nil)
if err != nil {
return nil, err
}
defer tgzstream.CloseAndDelete(tgz)
tgzBuffer := bytes.NewBuffer(nil)
_, err = io.Copy(tgzBuffer, tgz)
if err != nil {
return nil, fmt.Errorf("failed to copy manifest targz to a byte buffer: %w", err)
}
return &MockMatchRepositoryStream{
metadataRequest: mr,
fileRequest: cmp.AppFileRequest(tgzBuffer.Bytes()),
}, nil
}
func (m *MockMatchRepositoryStream) SendAndClose(response *apiclient.RepositoryResponse) error {
m.response = response
return nil
}
func (m *MockMatchRepositoryStream) Recv() (*apiclient.AppStreamRequest, error) {
if !m.metadataSent {
m.metadataSent = true
return m.metadataRequest, nil
}
if !m.fileSent {
m.fileSent = true
return m.fileRequest, nil
}
return nil, io.EOF
}
func (m *MockMatchRepositoryStream) Context() context.Context {
return context.Background()
}
func TestService_MatchRepository(t *testing.T) {
configFilePath := "./testdata/kustomize/config"
service, err := newService(configFilePath)
require.NoError(t, err)
t.Run("supported app", func(t *testing.T) {
s, err := NewMockMatchRepositoryStream("./testdata/kustomize", "./testdata/kustomize", nil)
require.NoError(t, err)
err = service.matchRepositoryGeneric(s)
require.NoError(t, err)
require.NotNil(t, s.response)
assert.True(t, s.response.IsSupported)
})
t.Run("unsupported app", func(t *testing.T) {
s, err := NewMockMatchRepositoryStream("./testdata/ksonnet", "./testdata/ksonnet", nil)
require.NoError(t, err)
err = service.matchRepositoryGeneric(s)
require.NoError(t, err)
require.NotNil(t, s.response)
assert.False(t, s.response.IsSupported)
})
}
type MockParametersAnnouncementStream struct {
metadataSent bool
fileSent bool
metadataRequest *apiclient.AppStreamRequest
fileRequest *apiclient.AppStreamRequest
response *apiclient.ParametersAnnouncementResponse
}
func NewMockParametersAnnouncementStream(repoPath, appPath string, env []string) (*MockParametersAnnouncementStream, error) {
tgz, mr, err := cmp.GetCompressedRepoAndMetadata(repoPath, appPath, env, nil, nil)
if err != nil {
return nil, err
}
defer tgzstream.CloseAndDelete(tgz)
tgzBuffer := bytes.NewBuffer(nil)
_, err = io.Copy(tgzBuffer, tgz)
if err != nil {
return nil, fmt.Errorf("failed to copy manifest targz to a byte buffer: %w", err)
}
return &MockParametersAnnouncementStream{
metadataRequest: mr,
fileRequest: cmp.AppFileRequest(tgzBuffer.Bytes()),
}, nil
}
func (m *MockParametersAnnouncementStream) SendAndClose(response *apiclient.ParametersAnnouncementResponse) error {
m.response = response
return nil
}
func (m *MockParametersAnnouncementStream) Recv() (*apiclient.AppStreamRequest, error) {
if !m.metadataSent {
m.metadataSent = true
return m.metadataRequest, nil
}
if !m.fileSent {
m.fileSent = true
return m.fileRequest, nil
}
return nil, io.EOF
}
func (m *MockParametersAnnouncementStream) SetHeader(metadata.MD) error {
return nil
}
func (m *MockParametersAnnouncementStream) SendHeader(metadata.MD) error {
return nil
}
func (m *MockParametersAnnouncementStream) SetTrailer(metadata.MD) {}
func (m *MockParametersAnnouncementStream) Context() context.Context {
return context.Background()
}
func (m *MockParametersAnnouncementStream) SendMsg(interface{}) error {
return nil
}
func (m *MockParametersAnnouncementStream) RecvMsg(interface{}) error {
return nil
}
func TestService_GetParametersAnnouncement(t *testing.T) {
configFilePath := "./testdata/kustomize/config"
service, err := newService(configFilePath)
require.NoError(t, err)
t.Run("successful response", func(t *testing.T) {
s, err := NewMockParametersAnnouncementStream("./testdata/kustomize", "./testdata/kustomize", nil)
require.NoError(t, err)
err = service.GetParametersAnnouncement(s)
require.NoError(t, err)
require.NotNil(t, s.response)
require.Len(t, s.response.ParameterAnnouncements, 1)
assert.Equal(t, repoclient.ParameterAnnouncement{Name: "test-param", String_: "test-value"}, *s.response.ParameterAnnouncements[0])
})
t.Run("out of bounds app", func(t *testing.T) {
s, err := NewMockParametersAnnouncementStream("./testdata/kustomize", "./testdata/kustomize", nil)
require.NoError(t, err)
// set a malicious app path on the metadata
s.metadataRequest.Request.(*apiclient.AppStreamRequest_Metadata).Metadata.AppRelPath = "../out-of-bounds"
err = service.GetParametersAnnouncement(s)
require.ErrorContains(t, err, "illegal appPath")
require.Nil(t, s.response)
})
}

View File

@@ -7,12 +7,8 @@ spec:
init:
command: [kustomize, version]
generate:
command: [sh, -c, "kustomize build"]
command: [sh, -c, "cd testdata/kustomize && kustomize build"]
discover:
find:
command: [sh, -c, find . -name kustomization.yaml]
glob: "**/kustomization.yaml"
parameters:
static:
- name: test-param
string: test-value
glob: "**/*/kustomization.yaml"

View File

@@ -108,7 +108,7 @@ func (a *ArgoCDCMPServer) CreateGRPC() (*grpc.Server, error) {
return true, nil
}))
pluginService := plugin.NewService(a.initConstants)
err := pluginService.Init(common.GetCMPWorkDir())
err := pluginService.Init()
if err != nil {
return nil, fmt.Errorf("error initializing plugin service: %s", err)
}

View File

@@ -1,7 +1,6 @@
package common
import (
"errors"
"os"
"path/filepath"
"strconv"
@@ -317,8 +316,3 @@ const (
SecurityMedium = 2 // Could indicate malicious events, but has a high likelihood of being user/system error (i.e. access denied)
SecurityLow = 1 // Unexceptional entries (i.e. successful access logs)
)
// Common error messages
const TokenVerificationError = "failed to verify the token"
var TokenVerificationErr = errors.New(TokenVerificationError)

View File

@@ -335,7 +335,7 @@ func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]b
}
if !ctrl.canProcessApp(obj) {
// Don't force refresh app if app belongs to a different controller shard or is outside the allowed namespaces.
// Don't force refresh app if app belongs to a different controller shard
continue
}
@@ -415,32 +415,33 @@ func isKnownOrphanedResourceExclusion(key kube.ResourceKey, proj *appv1.AppProje
func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managedResources []*appv1.ResourceDiff) (*appv1.ApplicationTree, error) {
nodes := make([]appv1.ResourceNode, 0)
proj, err := ctrl.getAppProj(a)
if err != nil {
return nil, fmt.Errorf("failed to get project: %w", err)
return nil, err
}
orphanedNodesMap := make(map[kube.ResourceKey]appv1.ResourceNode)
warnOrphaned := true
if proj.Spec.OrphanedResources != nil {
orphanedNodesMap, err = ctrl.stateCache.GetNamespaceTopLevelResources(a.Spec.Destination.Server, a.Spec.Destination.Namespace)
if err != nil {
return nil, fmt.Errorf("failed to get namespace top-level resources: %w", err)
return nil, err
}
warnOrphaned = proj.Spec.OrphanedResources.IsWarn()
}
for i := range managedResources {
managedResource := managedResources[i]
delete(orphanedNodesMap, kube.NewResourceKey(managedResource.Group, managedResource.Kind, managedResource.Namespace, managedResource.Name))
var live = &unstructured.Unstructured{}
err := json.Unmarshal([]byte(managedResource.LiveState), &live)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal live state of managed resources: %w", err)
return nil, err
}
var target = &unstructured.Unstructured{}
err = json.Unmarshal([]byte(managedResource.TargetState), &target)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal target state of managed resources: %w", err)
return nil, err
}
if live == nil {
@@ -456,11 +457,7 @@ func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managed
} else {
err := ctrl.stateCache.IterateHierarchy(a.Spec.Destination.Server, kube.GetResourceKey(live), func(child appv1.ResourceNode, appName string) bool {
permitted, _ := proj.IsResourcePermitted(schema.GroupKind{Group: child.ResourceRef.Group, Kind: child.ResourceRef.Kind}, child.Namespace, a.Spec.Destination, func(project string) ([]*appv1.Cluster, error) {
clusters, err := ctrl.db.GetProjectClusters(context.TODO(), project)
if err != nil {
return nil, fmt.Errorf("failed to get project clusters: %w", err)
}
return clusters, nil
return ctrl.db.GetProjectClusters(context.TODO(), project)
})
if !permitted {
return false
@@ -469,7 +466,7 @@ func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managed
return true
})
if err != nil {
return nil, fmt.Errorf("failed to iterate resource hierarchy: %w", err)
return nil, err
}
}
}
@@ -518,7 +515,7 @@ func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managed
hosts, err := ctrl.getAppHosts(a, nodes)
if err != nil {
return nil, fmt.Errorf("failed to get app hosts: %w", err)
return nil, err
}
return &appv1.ApplicationTree{Nodes: nodes, OrphanedNodes: orphanedNodes, Hosts: hosts}, nil
}
@@ -754,7 +751,6 @@ func (ctrl *ApplicationController) Run(ctx context.Context, statusProcessors int
// needs to be the qualified name of the application, i.e. <namespace>/<name>.
func (ctrl *ApplicationController) requestAppRefresh(appName string, compareWith *CompareWith, after *time.Duration) {
key := ctrl.toAppKey(appName)
if compareWith != nil && after != nil {
ctrl.appComparisonTypeRefreshQueue.AddAfter(fmt.Sprintf("%s/%d", key, compareWith), *after)
} else {
@@ -911,7 +907,7 @@ func (ctrl *ApplicationController) processProjectQueueItem() (processNext bool)
func (ctrl *ApplicationController) finalizeProjectDeletion(proj *appv1.AppProject) error {
apps, err := ctrl.appLister.Applications(ctrl.namespace).List(labels.Everything())
if err != nil {
return fmt.Errorf("error listing applications: %w", err)
return err
}
appsCount := 0
for i := range apps {
@@ -1081,7 +1077,7 @@ func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Applic
func (ctrl *ApplicationController) removeCascadeFinalizer(app *appv1.Application) error {
_, err := ctrl.getAppProj(app)
if err != nil {
return fmt.Errorf("error getting project: %w", err)
return err
}
app.UnSetCascadedDeletion()
var patch []byte
@@ -1260,12 +1256,12 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
}
patchJSON, err := json.Marshal(patch)
if err != nil {
return fmt.Errorf("error marshaling json: %w", err)
return err
}
if app.Status.OperationState != nil && app.Status.OperationState.FinishedAt != nil && state.FinishedAt == nil {
patchJSON, err = jsonpatch.MergeMergePatches(patchJSON, []byte(`{"status": {"operationState": {"finishedAt": null}}}`))
if err != nil {
return fmt.Errorf("error merging operation state patch: %w", err)
return err
}
}
@@ -1276,7 +1272,7 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
if apierr.IsNotFound(err) {
return nil
}
return fmt.Errorf("error patching application with operation state: %w", err)
return err
}
log.Infof("updated '%s' operation (phase: %s)", app.QualifiedName(), state.Phase)
if state.Phase.Completed() {
@@ -1317,6 +1313,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
}
ctrl.appRefreshQueue.Done(appKey)
}()
obj, exists, err := ctrl.appInformer.GetIndexer().GetByKey(appKey.(string))
if err != nil {
log.Errorf("Failed to get application '%s' from informer index: %+v", appKey, err)
@@ -1337,9 +1334,9 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
if !needRefresh {
return
}
app := origApp.DeepCopy()
logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()})
startTime := time.Now()
defer func() {
reconcileDuration := time.Since(startTime)
@@ -1360,7 +1357,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
} else {
var tree *appv1.ApplicationTree
if tree, err = ctrl.getResourceTree(app, managedResources); err == nil {
app.Status.Summary = tree.GetSummary(app)
app.Status.Summary = tree.GetSummary()
if err := ctrl.cache.SetAppResourcesTree(app.InstanceName(ctrl.namespace), tree); err != nil {
logCtx.Errorf("Failed to cache resources tree: %v", err)
return
@@ -1392,38 +1389,15 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
localManifests = opState.Operation.Sync.Manifests
}
revisions := make([]string, 0)
sources := make([]appv1.ApplicationSource, 0)
hasMultipleSources := app.Spec.HasMultipleSources()
// If we have multiple sources, we use all the sources under `sources` field and ignore source under `source` field.
// else we use the source under the source field.
if hasMultipleSources {
for _, source := range app.Spec.Sources {
// We do not perform any filtering of duplicate sources.
// Argo CD will apply and update the resources generated from the sources automatically
// based on the order in which manifests were generated
sources = append(sources, source)
revisions = append(revisions, source.TargetRevision)
}
if comparisonLevel == CompareWithRecent {
revisions = app.Status.Sync.Revisions
}
} else {
revision := app.Spec.GetSource().TargetRevision
if comparisonLevel == CompareWithRecent {
revision = app.Status.Sync.Revision
}
revisions = append(revisions, revision)
sources = append(sources, app.Spec.GetSource())
revision := app.Spec.Source.TargetRevision
if comparisonLevel == CompareWithRecent {
revision = app.Status.Sync.Revision
}
now := metav1.Now()
compareResult := ctrl.appStateManager.CompareAppState(app, project, revisions, sources,
compareResult := ctrl.appStateManager.CompareAppState(app, project, revision, app.Spec.Source,
refreshType == appv1.RefreshTypeHard,
comparisonLevel == CompareWithLatestForceResolve, localManifests, hasMultipleSources)
comparisonLevel == CompareWithLatestForceResolve, localManifests)
for k, v := range compareResult.timings {
logCtx = logCtx.WithField(k, v.Milliseconds())
}
@@ -1434,7 +1408,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
if err != nil {
logCtx.Errorf("Failed to cache app resources: %v", err)
} else {
app.Status.Summary = tree.GetSummary(app)
app.Status.Summary = tree.GetSummary()
}
if project.Spec.SyncWindows.Matches(app).CanSync(false) {
@@ -1464,7 +1438,6 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
return resourceStatusKey(app.Status.Resources[i]) < resourceStatusKey(app.Status.Resources[j])
})
app.Status.SourceType = compareResult.appSourceType
app.Status.SourceTypes = compareResult.appSourceTypes
ctrl.persistAppStatus(origApp, &app.Status)
return
}
@@ -1490,34 +1463,27 @@ func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application,
// user requested app refresh.
refreshType = requestedType
reason = fmt.Sprintf("%s refresh requested", refreshType)
} else {
if app.Spec.HasMultipleSources() {
if (len(app.Spec.Sources) != len(app.Status.Sync.ComparedTo.Sources)) || !reflect.DeepEqual(app.Spec.Sources, app.Status.Sync.ComparedTo.Sources) {
reason = "atleast one of the spec.sources differs"
compareWith = CompareWithLatestForceResolve
}
} else if !app.Spec.Source.Equals(app.Status.Sync.ComparedTo.Source) {
reason = "spec.source differs"
compareWith = CompareWithLatestForceResolve
} else if hardExpired || softExpired {
// The commented line below mysteriously crashes if app.Status.ReconciledAt is nil
// reason = fmt.Sprintf("comparison expired. reconciledAt: %v, expiry: %v", app.Status.ReconciledAt, statusRefreshTimeout)
//TODO: find existing Golang bug or create a new one
reconciledAtStr := "never"
if app.Status.ReconciledAt != nil {
reconciledAtStr = app.Status.ReconciledAt.String()
}
reason = fmt.Sprintf("comparison expired, requesting refresh. reconciledAt: %v, expiry: %v", reconciledAtStr, statusRefreshTimeout)
if hardExpired {
reason = fmt.Sprintf("comparison expired, requesting hard refresh. reconciledAt: %v, expiry: %v", reconciledAtStr, statusHardRefreshTimeout)
refreshType = appv1.RefreshTypeHard
}
} else if !app.Spec.Destination.Equals(app.Status.Sync.ComparedTo.Destination) {
reason = "spec.destination differs"
} else if requested, level := ctrl.isRefreshRequested(app.QualifiedName()); requested {
compareWith = level
reason = "controller refresh requested"
} else if !app.Spec.Source.Equals(app.Status.Sync.ComparedTo.Source) {
reason = "spec.source differs"
compareWith = CompareWithLatestForceResolve
} else if hardExpired || softExpired {
// The commented line below mysteriously crashes if app.Status.ReconciledAt is nil
// reason = fmt.Sprintf("comparison expired. reconciledAt: %v, expiry: %v", app.Status.ReconciledAt, statusRefreshTimeout)
//TODO: find existing Golang bug or create a new one
reconciledAtStr := "never"
if app.Status.ReconciledAt != nil {
reconciledAtStr = app.Status.ReconciledAt.String()
}
reason = fmt.Sprintf("comparison expired, requesting refresh. reconciledAt: %v, expiry: %v", reconciledAtStr, statusRefreshTimeout)
if hardExpired {
reason = fmt.Sprintf("comparison expired, requesting hard refresh. reconciledAt: %v, expiry: %v", reconciledAtStr, statusHardRefreshTimeout)
refreshType = appv1.RefreshTypeHard
}
} else if !app.Spec.Destination.Equals(app.Status.Sync.ComparedTo.Destination) {
reason = "spec.destination differs"
} else if requested, level := ctrl.isRefreshRequested(app.QualifiedName()); requested {
compareWith = level
reason = "controller refresh requested"
}
if reason != "" {
@@ -1531,7 +1497,17 @@ func (ctrl *ApplicationController) refreshAppConditions(app *appv1.Application)
errorConditions := make([]appv1.ApplicationCondition, 0)
proj, err := ctrl.getAppProj(app)
if err != nil {
errorConditions = append(errorConditions, ctrl.projectErrorToCondition(err, app))
if apierr.IsNotFound(err) {
errorConditions = append(errorConditions, appv1.ApplicationCondition{
Type: appv1.ApplicationConditionInvalidSpecError,
Message: fmt.Sprintf("Application referencing project %s which does not exist", app.Spec.Project),
})
} else {
errorConditions = append(errorConditions, appv1.ApplicationCondition{
Type: appv1.ApplicationConditionUnknownError,
Message: err.Error(),
})
}
} else {
specConditions, err := argo.ValidatePermissions(context.Background(), &app.Spec, proj, ctrl.db)
if err != nil {
@@ -1554,9 +1530,7 @@ func (ctrl *ApplicationController) refreshAppConditions(app *appv1.Application)
func (ctrl *ApplicationController) normalizeApplication(orig, app *appv1.Application) {
logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()})
app.Spec = *argo.NormalizeApplicationSpec(&app.Spec)
patch, modified, err := diff.CreateTwoWayMergePatch(orig, app, appv1.Application{})
if err != nil {
logCtx.Errorf("error constructing app spec patch: %v", err)
} else if modified {
@@ -1600,6 +1574,7 @@ func (ctrl *ApplicationController) persistAppStatus(orig *appv1.Application, new
logCtx.Infof("No status changes. Skipping patch")
return
}
logCtx.Debugf("patch: %s", string(patch))
appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(orig.Namespace)
_, err = appClient.Patch(context.Background(), orig.Name, types.MergePatchType, patch, metav1.PatchOptions{})
if err != nil {
@@ -1615,7 +1590,6 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
return nil
}
logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()})
if app.Operation != nil {
logCtx.Infof("Skipping auto-sync: another operation is in progress")
return nil
@@ -1647,15 +1621,13 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
}
desiredCommitSHA := syncStatus.Revision
desiredCommitSHAsMS := syncStatus.Revisions
alreadyAttempted, attemptPhase := alreadyAttemptedSync(app, desiredCommitSHA, desiredCommitSHAsMS, app.Spec.HasMultipleSources())
alreadyAttempted, attemptPhase := alreadyAttemptedSync(app, desiredCommitSHA)
selfHeal := app.Spec.SyncPolicy.Automated.SelfHeal
op := appv1.Operation{
Sync: &appv1.SyncOperation{
Revision: desiredCommitSHA,
Prune: app.Spec.SyncPolicy.Automated.Prune,
SyncOptions: app.Spec.SyncPolicy.SyncOptions,
Revisions: desiredCommitSHAsMS,
},
InitiatedBy: appv1.OperationInitiator{Automated: true},
Retry: appv1.RetryStrategy{Limit: 5},
@@ -1707,6 +1679,7 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
return &appv1.ApplicationCondition{Type: appv1.ApplicationConditionSyncError, Message: message}
}
}
appIf := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace)
_, err := argo.SetAppOperation(appIf, app.Name, &op)
if err != nil {
@@ -1721,41 +1694,20 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
// alreadyAttemptedSync returns whether or not the most recent sync was performed against the
// commitSHA and with the same app source config which are currently set in the app
func alreadyAttemptedSync(app *appv1.Application, commitSHA string, commitSHAsMS []string, hasMultipleSources bool) (bool, synccommon.OperationPhase) {
func alreadyAttemptedSync(app *appv1.Application, commitSHA string) (bool, synccommon.OperationPhase) {
if app.Status.OperationState == nil || app.Status.OperationState.Operation.Sync == nil || app.Status.OperationState.SyncResult == nil {
return false, ""
}
if hasMultipleSources {
if !reflect.DeepEqual(app.Status.OperationState.SyncResult.Revisions, commitSHAsMS) {
return false, ""
}
} else {
if app.Status.OperationState.SyncResult.Revision != commitSHA {
return false, ""
}
}
if hasMultipleSources {
// Ignore differences in target revision, since we already just verified commitSHAs are equal,
// and we do not want to trigger auto-sync due to things like HEAD != master
specSources := app.Spec.Sources.DeepCopy()
syncSources := app.Status.OperationState.SyncResult.Sources.DeepCopy()
for _, source := range specSources {
source.TargetRevision = ""
}
for _, source := range syncSources {
source.TargetRevision = ""
}
return reflect.DeepEqual(app.Spec.Sources, app.Status.OperationState.SyncResult.Sources), app.Status.OperationState.Phase
} else {
// Ignore differences in target revision, since we already just verified commitSHAs are equal,
// and we do not want to trigger auto-sync due to things like HEAD != master
specSource := app.Spec.Source.DeepCopy()
specSource.TargetRevision = ""
syncResSource := app.Status.OperationState.SyncResult.Source.DeepCopy()
syncResSource.TargetRevision = ""
return reflect.DeepEqual(app.Spec.GetSource(), app.Status.OperationState.SyncResult.Source), app.Status.OperationState.Phase
if app.Status.OperationState.SyncResult.Revision != commitSHA {
return false, ""
}
// Ignore differences in target revision, since we already just verified commitSHAs are equal,
// and we do not want to trigger auto-sync due to things like HEAD != master
specSource := app.Spec.Source.DeepCopy()
specSource.TargetRevision = ""
syncResSource := app.Status.OperationState.SyncResult.Source.DeepCopy()
syncResSource.TargetRevision = ""
return reflect.DeepEqual(app.Spec.Source, app.Status.OperationState.SyncResult.Source), app.Status.OperationState.Phase
}
func (ctrl *ApplicationController) shouldSelfHeal(app *appv1.Application) (bool, time.Duration) {
@@ -1777,13 +1729,6 @@ func (ctrl *ApplicationController) canProcessApp(obj interface{}) bool {
if !ok {
return false
}
// Only process given app if it exists in a watched namespace, or in the
// control plane's namespace.
if app.Namespace != ctrl.namespace && !glob.MatchStringInList(ctrl.applicationNamespaces, app.Namespace, false) {
return false
}
if ctrl.clusterFilter != nil {
cluster, err := ctrl.db.GetCluster(context.Background(), app.Spec.Destination.Server)
if err != nil {
@@ -1792,6 +1737,12 @@ func (ctrl *ApplicationController) canProcessApp(obj interface{}) bool {
return ctrl.clusterFilter(cluster)
}
// Only process given app if it exists in a watched namespace, or in the
// control plane's namespace.
if app.Namespace != ctrl.namespace && !glob.MatchStringInList(ctrl.applicationNamespaces, app.Namespace, false) {
return false
}
return true
}
@@ -1847,7 +1798,7 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar
// If the application is not allowed to use the project,
// log an error.
if _, err := ctrl.getAppProj(app); err != nil {
ctrl.setAppCondition(app, ctrl.projectErrorToCondition(err, app))
ctrl.setAppCondition(app, appv1.ApplicationCondition{Type: appv1.ApplicationConditionUnknownError, Message: err.Error()})
}
}
@@ -1918,19 +1869,6 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar
return informer, lister
}
func (ctrl *ApplicationController) projectErrorToCondition(err error, app *appv1.Application) appv1.ApplicationCondition {
var condition appv1.ApplicationCondition
if apierr.IsNotFound(err) {
condition = appv1.ApplicationCondition{
Type: appv1.ApplicationConditionInvalidSpecError,
Message: fmt.Sprintf("Application referencing project %s which does not exist", app.Spec.Project),
}
} else {
condition = appv1.ApplicationCondition{Type: appv1.ApplicationConditionUnknownError, Message: err.Error()}
}
return condition
}
func (ctrl *ApplicationController) RegisterClusterSecretUpdater(ctx context.Context) {
updater := NewClusterInfoUpdater(ctrl.stateCache, ctrl.db, ctrl.appLister.Applications(""), ctrl.cache, ctrl.clusterFilter, ctrl.getAppProj, ctrl.namespace)
go updater.Run(ctx)

View File

@@ -865,7 +865,7 @@ func TestNeedRefreshAppStatus(t *testing.T) {
app.Status.Sync = argoappv1.SyncStatus{
Status: argoappv1.SyncStatusCodeSynced,
ComparedTo: argoappv1.ComparedTo{
Source: app.Spec.GetSource(),
Source: app.Spec.Source,
Destination: app.Spec.Destination,
},
}
@@ -909,7 +909,7 @@ func TestNeedRefreshAppStatus(t *testing.T) {
app.Status.Sync = argoappv1.SyncStatus{
Status: argoappv1.SyncStatusCodeSynced,
ComparedTo: argoappv1.ComparedTo{
Source: app.Spec.GetSource(),
Source: app.Spec.Source,
Destination: app.Spec.Destination,
},
}
@@ -1012,7 +1012,7 @@ func TestUpdateReconciledAt(t *testing.T) {
app := newFakeApp()
reconciledAt := metav1.NewTime(time.Now().Add(-1 * time.Second))
app.Status = argoappv1.ApplicationStatus{ReconciledAt: &reconciledAt}
app.Status.Sync = argoappv1.SyncStatus{ComparedTo: argoappv1.ComparedTo{Source: app.Spec.GetSource(), Destination: app.Spec.Destination}}
app.Status.Sync = argoappv1.SyncStatus{ComparedTo: argoappv1.ComparedTo{Source: app.Spec.Source, Destination: app.Spec.Destination}}
ctrl := newFakeController(&fakeData{
apps: []runtime.Object{app, &defaultProj},
manifestResponse: &apiclient.ManifestResponse{
@@ -1068,34 +1068,6 @@ func TestUpdateReconciledAt(t *testing.T) {
}
func TestProjectErrorToCondition(t *testing.T) {
app := newFakeApp()
app.Spec.Project = "wrong project"
ctrl := newFakeController(&fakeData{
apps: []runtime.Object{app, &defaultProj},
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{},
Namespace: test.FakeDestNamespace,
Server: test.FakeClusterURL,
Revision: "abc123",
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
})
key, _ := cache.MetaNamespaceKeyFunc(app)
ctrl.appRefreshQueue.Add(key)
ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil)
ctrl.processAppRefreshQueueItem()
obj, ok, err := ctrl.appInformer.GetIndexer().GetByKey(key)
assert.True(t, ok)
assert.NoError(t, err)
updatedApp := obj.(*argoappv1.Application)
assert.Equal(t, argoappv1.ApplicationConditionInvalidSpecError, updatedApp.Status.Conditions[0].Type)
assert.Equal(t, "Application referencing project wrong project which does not exist", updatedApp.Status.Conditions[0].Message)
assert.Equal(t, argoappv1.ApplicationConditionInvalidSpecError, updatedApp.Status.Conditions[0].Type)
}
func TestFinalizeProjectDeletion_HasApplications(t *testing.T) {
app := newFakeApp()
proj := &argoappv1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: test.FakeArgoCDNamespace}}
@@ -1373,31 +1345,3 @@ func TestToAppKey(t *testing.T) {
})
}
}
func Test_canProcessApp(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}})
ctrl.applicationNamespaces = []string{"good"}
t.Run("without cluster filter, good namespace", func(t *testing.T) {
app.Namespace = "good"
canProcess := ctrl.canProcessApp(app)
assert.True(t, canProcess)
})
t.Run("without cluster filter, bad namespace", func(t *testing.T) {
app.Namespace = "bad"
canProcess := ctrl.canProcessApp(app)
assert.False(t, canProcess)
})
t.Run("with cluster filter, good namespace", func(t *testing.T) {
app.Namespace = "good"
ctrl.clusterFilter = func(_ *argoappv1.Cluster) bool { return true }
canProcess := ctrl.canProcessApp(app)
assert.True(t, canProcess)
})
t.Run("with cluster filter, bad namespace", func(t *testing.T) {
app.Namespace = "bad"
ctrl.clusterFilter = func(_ *argoappv1.Cluster) bool { return true }
canProcess := ctrl.canProcessApp(app)
assert.False(t, canProcess)
})
}

View File

@@ -220,10 +220,10 @@ func asResourceNode(r *clustercache.Resource) appv1.ResourceNode {
gv = schema.GroupVersion{}
}
parentRefs := make([]appv1.ResourceRef, len(r.OwnerRefs))
for i, ownerRef := range r.OwnerRefs {
for _, ownerRef := range r.OwnerRefs {
ownerGvk := schema.FromAPIVersionAndKind(ownerRef.APIVersion, ownerRef.Kind)
ownerKey := kube.NewResourceKey(ownerGvk.Group, ownerRef.Kind, r.Ref.Namespace, ownerRef.Name)
parentRefs[i] = appv1.ResourceRef{Name: ownerRef.Name, Kind: ownerKey.Kind, Namespace: r.Ref.Namespace, Group: ownerKey.Group, UID: string(ownerRef.UID)}
parentRefs[0] = appv1.ResourceRef{Name: ownerRef.Name, Kind: ownerKey.Kind, Namespace: r.Ref.Namespace, Group: ownerKey.Group, UID: string(ownerRef.UID)}
}
var resHealth *appv1.HealthStatus
resourceInfo := resInfo(r)
@@ -382,18 +382,13 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
cluster, err := c.db.GetCluster(context.Background(), server)
if err != nil {
return nil, fmt.Errorf("error getting cluster: %w", err)
return nil, err
}
if !c.canHandleCluster(cluster) {
return nil, fmt.Errorf("controller is configured to ignore cluster %s", cluster.Server)
}
resourceCustomLabels, err := c.settingsMgr.GetResourceCustomLabels()
if err != nil {
return nil, fmt.Errorf("error getting custom label: %w", err)
}
clusterCacheOpts := []clustercache.UpdateSettingsFunc{
clustercache.SetListSemaphore(semaphore.NewWeighted(clusterCacheListSemaphoreSize)),
clustercache.SetListPageSize(clusterCacheListPageSize),
@@ -405,7 +400,7 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
clustercache.SetClusterResources(cluster.ClusterResources),
clustercache.SetPopulateResourceInfoHandler(func(un *unstructured.Unstructured, isRoot bool) (interface{}, bool) {
res := &ResourceInfo{}
populateNodeInfo(un, res, resourceCustomLabels)
populateNodeInfo(un, res)
c.lock.RLock()
cacheSettings := c.cacheSettings
c.lock.RUnlock()
@@ -461,11 +456,11 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
func (c *liveStateCache) getSyncedCluster(server string) (clustercache.ClusterCache, error) {
clusterCache, err := c.getCluster(server)
if err != nil {
return nil, fmt.Errorf("error getting cluster: %w", err)
return nil, err
}
err = clusterCache.EnsureSynced()
if err != nil {
return nil, fmt.Errorf("error synchronizing cache state : %w", err)
return nil, err
}
return clusterCache, nil
}
@@ -599,7 +594,7 @@ func (c *liveStateCache) watchSettings(ctx context.Context) {
func (c *liveStateCache) Init() error {
cacheSettings, err := c.loadCacheSettings()
if err != nil {
return fmt.Errorf("error loading cache settings: %w", err)
return err
}
c.cacheSettings = *cacheSettings
return nil

View File

@@ -6,12 +6,11 @@ import (
"net/url"
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/api/core/v1"
apierr "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/stretchr/testify/assert"
"github.com/argoproj/gitops-engine/pkg/cache"
"github.com/argoproj/gitops-engine/pkg/cache/mocks"
"github.com/stretchr/testify/mock"
@@ -154,51 +153,3 @@ func TestIsRetryableError(t *testing.T) {
assert.True(t, isRetryableError(connectionReset))
})
}
func Test_asResourceNode_owner_refs(t *testing.T) {
resNode := asResourceNode(&cache.Resource{
ResourceVersion: "",
Ref: v1.ObjectReference{
APIVersion: "v1",
},
OwnerRefs: []metav1.OwnerReference{
{
APIVersion: "v1",
Kind: "ConfigMap",
Name: "cm-1",
},
{
APIVersion: "v1",
Kind: "ConfigMap",
Name: "cm-2",
},
},
CreationTimestamp: nil,
Info: nil,
Resource: nil,
})
expected := appv1.ResourceNode{
ResourceRef: appv1.ResourceRef{
Version: "v1",
},
ParentRefs: []appv1.ResourceRef{
{
Group: "",
Kind: "ConfigMap",
Name: "cm-1",
},
{
Group: "",
Kind: "ConfigMap",
Name: "cm-2",
},
},
Info: nil,
NetworkingInfo: nil,
ResourceVersion: "",
Images: nil,
Health: nil,
CreatedAt: nil,
}
assert.Equal(t, expected, resNode)
}

View File

@@ -19,21 +19,12 @@ import (
"github.com/argoproj/argo-cd/v2/util/resource"
)
func populateNodeInfo(un *unstructured.Unstructured, res *ResourceInfo, customLabels []string) {
func populateNodeInfo(un *unstructured.Unstructured, res *ResourceInfo) {
gvk := un.GroupVersionKind()
revision := resource.GetRevision(un)
if revision > 0 {
res.Info = append(res.Info, v1alpha1.InfoItem{Name: "Revision", Value: fmt.Sprintf("Rev:%v", revision)})
}
if len(customLabels) > 0 {
if labels := un.GetLabels(); labels != nil {
for _, customLabel := range customLabels {
if value, ok := labels[customLabel]; ok {
res.Info = append(res.Info, v1alpha1.InfoItem{Name: customLabel, Value: value})
}
}
}
}
switch gvk.Group {
case "":
switch gvk.Kind {

View File

@@ -271,7 +271,7 @@ func TestGetPodInfo(t *testing.T) {
`)
info := &ResourceInfo{}
populateNodeInfo(pod, info, []string{})
populateNodeInfo(pod, info)
assert.Equal(t, []v1alpha1.InfoItem{
{Name: "Node", Value: "minikube"},
{Name: "Containers", Value: "0/1"},
@@ -302,7 +302,7 @@ status:
`)
info := &ResourceInfo{}
populateNodeInfo(node, info, []string{})
populateNodeInfo(node, info)
assert.Equal(t, &NodeInfo{
Name: "minikube",
Capacity: v1.ResourceList{v1.ResourceMemory: resource.MustParse("6091320Ki"), v1.ResourceCPU: resource.MustParse("6")},
@@ -312,7 +312,7 @@ status:
func TestGetServiceInfo(t *testing.T) {
info := &ResourceInfo{}
populateNodeInfo(testService, info, []string{})
populateNodeInfo(testService, info)
assert.Equal(t, 0, len(info.Info))
assert.Equal(t, &v1alpha1.ResourceNetworkingInfo{
TargetLabels: map[string]string{"app": "guestbook"},
@@ -322,7 +322,7 @@ func TestGetServiceInfo(t *testing.T) {
func TestGetLinkAnnotatedServiceInfo(t *testing.T) {
info := &ResourceInfo{}
populateNodeInfo(testLinkAnnotatedService, info, []string{})
populateNodeInfo(testLinkAnnotatedService, info)
assert.Equal(t, 0, len(info.Info))
assert.Equal(t, &v1alpha1.ResourceNetworkingInfo{
TargetLabels: map[string]string{"app": "guestbook"},
@@ -333,7 +333,7 @@ func TestGetLinkAnnotatedServiceInfo(t *testing.T) {
func TestGetIstioVirtualServiceInfo(t *testing.T) {
info := &ResourceInfo{}
populateNodeInfo(testIstioVirtualService, info, []string{})
populateNodeInfo(testIstioVirtualService, info)
assert.Equal(t, 0, len(info.Info))
require.NotNil(t, info.NetworkingInfo)
require.NotNil(t, info.NetworkingInfo.TargetRefs)
@@ -363,7 +363,7 @@ func TestGetIngressInfo(t *testing.T) {
}
for _, tc := range tests {
info := &ResourceInfo{}
populateNodeInfo(tc.Ingress, info, []string{})
populateNodeInfo(tc.Ingress, info)
assert.Equal(t, 0, len(info.Info))
sort.Slice(info.NetworkingInfo.TargetRefs, func(i, j int) bool {
return strings.Compare(info.NetworkingInfo.TargetRefs[j].Name, info.NetworkingInfo.TargetRefs[i].Name) < 0
@@ -388,7 +388,7 @@ func TestGetIngressInfo(t *testing.T) {
func TestGetLinkAnnotatedIngressInfo(t *testing.T) {
info := &ResourceInfo{}
populateNodeInfo(testLinkAnnotatedIngress, info, []string{})
populateNodeInfo(testLinkAnnotatedIngress, info)
assert.Equal(t, 0, len(info.Info))
sort.Slice(info.NetworkingInfo.TargetRefs, func(i, j int) bool {
return strings.Compare(info.NetworkingInfo.TargetRefs[j].Name, info.NetworkingInfo.TargetRefs[i].Name) < 0
@@ -412,7 +412,7 @@ func TestGetLinkAnnotatedIngressInfo(t *testing.T) {
func TestGetIngressInfoWildCardPath(t *testing.T) {
info := &ResourceInfo{}
populateNodeInfo(testIngressWildCardPath, info, []string{})
populateNodeInfo(testIngressWildCardPath, info)
assert.Equal(t, 0, len(info.Info))
sort.Slice(info.NetworkingInfo.TargetRefs, func(i, j int) bool {
return strings.Compare(info.NetworkingInfo.TargetRefs[j].Name, info.NetworkingInfo.TargetRefs[i].Name) < 0
@@ -436,7 +436,7 @@ func TestGetIngressInfoWildCardPath(t *testing.T) {
func TestGetIngressInfoWithoutTls(t *testing.T) {
info := &ResourceInfo{}
populateNodeInfo(testIngressWithoutTls, info, []string{})
populateNodeInfo(testIngressWithoutTls, info)
assert.Equal(t, 0, len(info.Info))
sort.Slice(info.NetworkingInfo.TargetRefs, func(i, j int) bool {
return strings.Compare(info.NetworkingInfo.TargetRefs[j].Name, info.NetworkingInfo.TargetRefs[i].Name) < 0
@@ -481,7 +481,7 @@ func TestGetIngressInfoWithHost(t *testing.T) {
- ip: 107.178.210.11`)
info := &ResourceInfo{}
populateNodeInfo(ingress, info, []string{})
populateNodeInfo(ingress, info)
assert.Equal(t, &v1alpha1.ResourceNetworkingInfo{
Ingress: []v1.LoadBalancerIngress{{IP: "107.178.210.11"}},
@@ -514,7 +514,7 @@ func TestGetIngressInfoNoHost(t *testing.T) {
`)
info := &ResourceInfo{}
populateNodeInfo(ingress, info, []string{})
populateNodeInfo(ingress, info)
assert.Equal(t, &v1alpha1.ResourceNetworkingInfo{
TargetRefs: []v1alpha1.ResourceRef{{
@@ -549,7 +549,7 @@ func TestExternalUrlWithSubPath(t *testing.T) {
- ip: 107.178.210.11`)
info := &ResourceInfo{}
populateNodeInfo(ingress, info, []string{})
populateNodeInfo(ingress, info)
expectedExternalUrls := []string{"https://107.178.210.11/my/sub/path/"}
assert.Equal(t, expectedExternalUrls, info.NetworkingInfo.ExternalURLs)
@@ -585,7 +585,7 @@ func TestExternalUrlWithMultipleSubPaths(t *testing.T) {
- ip: 107.178.210.11`)
info := &ResourceInfo{}
populateNodeInfo(ingress, info, []string{})
populateNodeInfo(ingress, info)
expectedExternalUrls := []string{"https://helm-guestbook.com/my/sub/path/", "https://helm-guestbook.com/my/sub/path/2", "https://helm-guestbook.com"}
actualURLs := info.NetworkingInfo.ExternalURLs
@@ -615,7 +615,7 @@ func TestExternalUrlWithNoSubPath(t *testing.T) {
- ip: 107.178.210.11`)
info := &ResourceInfo{}
populateNodeInfo(ingress, info, []string{})
populateNodeInfo(ingress, info)
expectedExternalUrls := []string{"https://107.178.210.11"}
assert.Equal(t, expectedExternalUrls, info.NetworkingInfo.ExternalURLs)
@@ -643,54 +643,8 @@ func TestExternalUrlWithNetworkingApi(t *testing.T) {
- ip: 107.178.210.11`)
info := &ResourceInfo{}
populateNodeInfo(ingress, info, []string{})
populateNodeInfo(ingress, info)
expectedExternalUrls := []string{"https://107.178.210.11"}
assert.Equal(t, expectedExternalUrls, info.NetworkingInfo.ExternalURLs)
}
func TestCustomLabel(t *testing.T) {
configmap := strToUnstructured(`
apiVersion: v1
kind: ConfigMap
metadata:
name: cm`)
info := &ResourceInfo{}
populateNodeInfo(configmap, info, []string{"my-label"})
assert.Equal(t, 0, len(info.Info))
configmap = strToUnstructured(`
apiVersion: v1
kind: ConfigMap
metadata:
name: cm
labels:
my-label: value`)
info = &ResourceInfo{}
populateNodeInfo(configmap, info, []string{"my-label", "other-label"})
assert.Equal(t, 1, len(info.Info))
assert.Equal(t, "my-label", info.Info[0].Name)
assert.Equal(t, "value", info.Info[0].Value)
configmap = strToUnstructured(`
apiVersion: v1
kind: ConfigMap
metadata:
name: cm
labels:
my-label: value
other-label: value2`)
info = &ResourceInfo{}
populateNodeInfo(configmap, info, []string{"my-label", "other-label"})
assert.Equal(t, 2, len(info.Info))
assert.Equal(t, "my-label", info.Info[0].Name)
assert.Equal(t, "value", info.Info[0].Value)
assert.Equal(t, "other-label", info.Info[1].Name)
assert.Equal(t, "value2", info.Info[1].Value)
}

View File

@@ -3,7 +3,7 @@ package controller
import (
"context"
"time"
"fmt"
"github.com/argoproj/gitops-engine/pkg/cache"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
log "github.com/sirupsen/logrus"
@@ -93,7 +93,7 @@ func (c *clusterInfoUpdater) updateClusters() {
func (c *clusterInfoUpdater) updateClusterInfo(cluster appv1.Cluster, info *cache.ClusterInfo) error {
apps, err := c.appLister.List(labels.Everything())
if err != nil {
return fmt.Errorf("error while fetching the apps list: %w", err)
return err
}
var appCount int64
for _, a := range apps {
@@ -117,7 +117,7 @@ func (c *clusterInfoUpdater) updateClusterInfo(cluster appv1.Cluster, info *cach
}
if info != nil {
clusterInfo.ServerVersion = info.K8SVersion
clusterInfo.APIVersions = argo.APIResourcesToStrings(info.APIResources, true)
clusterInfo.APIVersions = argo.APIResourcesToStrings(info.APIResources, false)
if info.LastCacheSyncTime == nil {
clusterInfo.ConnectionState.Status = appv1.ConnectionStatusUnknown
} else if info.SyncError == nil {

View File

@@ -41,30 +41,27 @@ func setApplicationHealth(resources []managedResource, statuses []appv1.Resource
savedErr = err
}
}
if healthStatus != nil {
if persistResourceHealth {
resHealth := appv1.HealthStatus{Status: healthStatus.Status, Message: healthStatus.Message}
statuses[i].Health = &resHealth
} else {
statuses[i].Health = nil
}
if healthStatus == nil {
continue
}
// Is health status is missing but resource has not built-in/custom health check then it should not affect parent app health
if _, hasOverride := healthOverrides[lua.GetConfigMapKey(gvk)]; healthStatus.Status == health.HealthStatusMissing && !hasOverride && health.GetHealthCheckFunc(gvk) == nil {
continue
}
if persistResourceHealth {
resHealth := appv1.HealthStatus{Status: healthStatus.Status, Message: healthStatus.Message}
statuses[i].Health = &resHealth
} else {
statuses[i].Health = nil
}
// Missing or Unknown health status of child Argo CD app should not affect parent
if res.Kind == application.ApplicationKind && res.Group == application.Group && (healthStatus.Status == health.HealthStatusMissing || healthStatus.Status == health.HealthStatusUnknown) {
continue
}
// Is health status is missing but resource has not built-in/custom health check then it should not affect parent app health
if _, hasOverride := healthOverrides[lua.GetConfigMapKey(gvk)]; healthStatus.Status == health.HealthStatusMissing && !hasOverride && health.GetHealthCheckFunc(gvk) == nil {
continue
}
// Missing or Unknown health status of child Argo CD app should not affect parent
if res.Kind == application.ApplicationKind && res.Group == application.Group && (healthStatus.Status == health.HealthStatusMissing || healthStatus.Status == health.HealthStatusUnknown) {
continue
}
if health.IsWorse(appHealth.Status, healthStatus.Status) {
appHealth.Status = healthStatus.Status
if health.IsWorse(appHealth.Status, healthStatus.Status) {
appHealth.Status = healthStatus.Status
}
}
}
if persistResourceHealth {

View File

@@ -13,7 +13,7 @@ import (
"github.com/argoproj/gitops-engine/pkg/health"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/robfig/cron/v3"
"github.com/robfig/cron"
log "github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/labels"
@@ -193,10 +193,7 @@ func NewMetricsServer(addr string, appLister applister.ApplicationLister, appFil
redisRequestCounter: redisRequestCounter,
redisRequestHistogram: redisRequestHistogram,
hostname: hostname,
// This cron is used to expire the metrics cache.
// Currently clearing the metrics cache is logging and deleting from the map
// so there is no possibility of panic, but we will add a chain to keep robfig/cron v1 behavior.
cron: cron.New(cron.WithChain(cron.Recover(cron.PrintfLogger(log.StandardLogger())))),
cron: cron.New(),
}, nil
}
@@ -284,7 +281,7 @@ func (m *MetricsServer) SetExpiration(cacheExpiration time.Duration) error {
return errors.New("Expiration is already set")
}
_, err := m.cron.AddFunc(fmt.Sprintf("@every %s", cacheExpiration), func() {
err := m.cron.AddFunc(fmt.Sprintf("@every %s", cacheExpiration), func() {
log.Infof("Reset Prometheus metrics based on existing expiration '%v'", cacheExpiration)
m.syncCounter.Reset()
m.kubectlExecCounter.Reset()
@@ -381,7 +378,7 @@ func (c *appCollector) collectApps(ch chan<- prometheus.Metric, app *argoappv1.A
healthStatus = health.HealthStatusUnknown
}
addGauge(descAppInfo, 1, git.NormalizeGitURL(app.Spec.GetSource().RepoURL), app.Spec.Destination.Server, app.Spec.Destination.Namespace, string(syncStatus), string(healthStatus), operation)
addGauge(descAppInfo, 1, git.NormalizeGitURL(app.Spec.Source.RepoURL), app.Spec.Destination.Server, app.Spec.Destination.Namespace, string(syncStatus), string(healthStatus), operation)
if len(c.appLabels) > 0 {
labelValues := []string{}

View File

@@ -62,7 +62,7 @@ type managedResource struct {
// AppStateManager defines methods which allow to compare application spec and actual application state.
type AppStateManager interface {
CompareAppState(app *v1alpha1.Application, project *appv1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localObjects []string, hasMultipleSources bool) *comparisonResult
CompareAppState(app *v1alpha1.Application, project *appv1.AppProject, revision string, source v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localObjects []string) *comparisonResult
SyncAppState(app *v1alpha1.Application, state *v1alpha1.OperationState)
}
@@ -75,8 +75,6 @@ type comparisonResult struct {
reconciliationResult sync.ReconciliationResult
diffConfig argodiff.DiffConfig
appSourceType v1alpha1.ApplicationSourceType
// appSourceTypes stores the SourceType for each application source under sources field
appSourceTypes []v1alpha1.ApplicationSourceType
// timings maps phases of comparison to the duration it took to complete (for statistical purposes)
timings map[string]time.Duration
diffResultList *diff.DiffResultList
@@ -107,8 +105,7 @@ type appStateManager struct {
persistResourceHealth bool
}
func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject) ([]*unstructured.Unstructured, map[*v1alpha1.ApplicationSource]*apiclient.ManifestResponse, error) {
func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1.ApplicationSource, appLabelKey, revision string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject) ([]*unstructured.Unstructured, *apiclient.ManifestResponse, error) {
ts := stats.NewTimingStats()
helmRepos, err := m.db.ListHelmRepositories(context.Background())
if err != nil {
@@ -118,7 +115,11 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp
if err != nil {
return nil, nil, err
}
ts.AddCheckpoint("helm_ms")
repo, err := m.db.GetRepository(context.Background(), source.RepoURL)
if err != nil {
return nil, nil, err
}
ts.AddCheckpoint("repo_ms")
helmRepositoryCredentials, err := m.db.GetAllHelmRepositoryCredentials(context.Background())
if err != nil {
@@ -128,6 +129,15 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp
if err != nil {
return nil, nil, err
}
conn, repoClient, err := m.repoClientset.NewRepoServerClient()
if err != nil {
return nil, nil, err
}
defer io.Close(conn)
if revision == "" {
revision = source.TargetRevision
}
plugins, err := m.settingsMgr.GetConfigManagementPlugins()
if err != nil {
@@ -148,87 +158,48 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp
return nil, nil, err
}
helmOptions, err := m.settingsMgr.GetHelmSettings()
kustomizeOptions, err := kustomizeSettings.GetOptions(app.Spec.Source)
if err != nil {
return nil, nil, err
}
helmOptions, err := m.settingsMgr.GetHelmSettings()
if err != nil {
return nil, nil, err
}
ts.AddCheckpoint("build_options_ms")
serverVersion, apiResources, err := m.liveStateCache.GetVersionsInfo(app.Spec.Destination.Server)
if err != nil {
return nil, nil, err
}
conn, repoClient, err := m.repoClientset.NewRepoServerClient()
ts.AddCheckpoint("version_ms")
manifestInfo, err := repoClient.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
Repo: repo,
Repos: permittedHelmRepos,
Revision: revision,
NoCache: noCache,
NoRevisionCache: noRevisionCache,
AppLabelKey: appLabelKey,
AppName: app.InstanceName(m.namespace),
Namespace: app.Spec.Destination.Namespace,
ApplicationSource: &source,
Plugins: tools,
KustomizeOptions: kustomizeOptions,
KubeVersion: serverVersion,
ApiVersions: argo.APIResourcesToStrings(apiResources, true),
VerifySignature: verifySignature,
HelmRepoCreds: permittedHelmCredentials,
TrackingMethod: string(argo.GetTrackingMethod(m.settingsMgr)),
EnabledSourceTypes: enabledSourceTypes,
HelmOptions: helmOptions,
})
if err != nil {
return nil, nil, err
}
defer io.Close(conn)
targetObjs, err := unmarshalManifests(manifestInfo.Manifests)
manifestInfoMap := make(map[*v1alpha1.ApplicationSource]*apiclient.ManifestResponse)
targetObjs := make([]*unstructured.Unstructured, 0)
// Store the map of all sources having ref field into a map for applications with sources field
refSources, err := argo.GetRefSources(context.Background(), app.Spec, m.db)
if err != nil {
return nil, nil, fmt.Errorf("failed to get ref sources: %v", err)
}
for i, source := range sources {
if len(revisions) < len(sources) || revisions[i] == "" {
revisions[i] = source.TargetRevision
}
ts.AddCheckpoint("helm_ms")
repo, err := m.db.GetRepository(context.Background(), source.RepoURL)
if err != nil {
return nil, nil, err
}
kustomizeOptions, err := kustomizeSettings.GetOptions(source)
if err != nil {
return nil, nil, err
}
ts.AddCheckpoint("version_ms")
log.Debugf("Generating Manifest for source %s revision %s", source, revisions[i])
manifestInfo, err := repoClient.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
Repo: repo,
Repos: permittedHelmRepos,
Revision: revisions[i],
NoCache: noCache,
NoRevisionCache: noRevisionCache,
AppLabelKey: appLabelKey,
AppName: app.InstanceName(m.namespace),
Namespace: app.Spec.Destination.Namespace,
ApplicationSource: &source,
Plugins: tools,
KustomizeOptions: kustomizeOptions,
KubeVersion: serverVersion,
ApiVersions: argo.APIResourcesToStrings(apiResources, true),
VerifySignature: verifySignature,
HelmRepoCreds: permittedHelmCredentials,
TrackingMethod: string(argo.GetTrackingMethod(m.settingsMgr)),
EnabledSourceTypes: enabledSourceTypes,
HelmOptions: helmOptions,
HasMultipleSources: app.Spec.HasMultipleSources(),
RefSources: refSources,
})
if err != nil {
return nil, nil, err
}
// GenerateManifest can return empty ManifestResponse without error if app has multiple sources
// and if any of the source does not have path and chart field not specified.
// In that scenario, we continue to the next source
if app.Spec.HasMultipleSources() && len(manifestInfo.Manifests) == 0 {
continue
}
targetObj, err := unmarshalManifests(manifestInfo.Manifests)
if err != nil {
return nil, nil, err
}
targetObjs = append(targetObjs, targetObj...)
manifestInfoMap[&source] = manifestInfo
return nil, nil, err
}
ts.AddCheckpoint("unmarshal_ms")
@@ -238,7 +209,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp
}
logCtx = logCtx.WithField("time_ms", time.Since(ts.StartTime).Milliseconds())
logCtx.Info("getRepoObjs stats")
return targetObjs, manifestInfoMap, nil
return targetObjs, manifestInfo, nil
}
func unmarshalManifests(manifests []string) ([]*unstructured.Unstructured, error) {
@@ -354,7 +325,7 @@ func verifyGnuPGSignature(revision string, project *appv1.AppProject, manifestIn
// CompareAppState compares application git state to the live app state, using the specified
// revision and supplied source. If revision or overrides are empty, then compares against
// revision and overrides in the app spec.
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *appv1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localManifests []string, hasMultipleSources bool) *comparisonResult {
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *appv1.AppProject, revision string, source v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localManifests []string) *comparisonResult {
ts := stats.NewTimingStats()
appLabelKey, resourceOverrides, resFilter, err := m.getComparisonSettings()
@@ -362,24 +333,12 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
// return unknown comparison result if basic comparison settings cannot be loaded
if err != nil {
if hasMultipleSources {
return &comparisonResult{
syncStatus: &v1alpha1.SyncStatus{
ComparedTo: appv1.ComparedTo{Destination: app.Spec.Destination, Sources: sources},
Status: appv1.SyncStatusCodeUnknown,
Revisions: revisions,
},
healthStatus: &appv1.HealthStatus{Status: health.HealthStatusUnknown},
}
} else {
return &comparisonResult{
syncStatus: &v1alpha1.SyncStatus{
ComparedTo: appv1.ComparedTo{Source: sources[0], Destination: app.Spec.Destination},
Status: appv1.SyncStatusCodeUnknown,
Revision: revisions[0],
},
healthStatus: &appv1.HealthStatus{Status: health.HealthStatusUnknown},
}
return &comparisonResult{
syncStatus: &v1alpha1.SyncStatus{
ComparedTo: appv1.ComparedTo{Source: source, Destination: app.Spec.Destination},
Status: appv1.SyncStatusCodeUnknown,
},
healthStatus: &appv1.HealthStatus{Status: health.HealthStatusUnknown},
}
}
@@ -397,21 +356,11 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
logCtx.Infof("Comparing app state (cluster: %s, namespace: %s)", app.Spec.Destination.Server, app.Spec.Destination.Namespace)
var targetObjs []*unstructured.Unstructured
var manifestInfo *apiclient.ManifestResponse
now := metav1.Now()
var manifestInfoMap map[*v1alpha1.ApplicationSource]*apiclient.ManifestResponse
if len(localManifests) == 0 {
// If the length of revisions is not same as the length of sources,
// we take the revisions from the sources directly for all the sources.
if len(revisions) != len(sources) {
revisions = make([]string, 0)
for _, source := range sources {
revisions = append(revisions, source.TargetRevision)
}
}
targetObjs, manifestInfoMap, err = m.getRepoObjs(app, sources, appLabelKey, revisions, noCache, noRevisionCache, verifySignature, project)
targetObjs, manifestInfo, err = m.getRepoObjs(app, source, appLabelKey, revision, noCache, noRevisionCache, verifySignature, project)
if err != nil {
targetObjs = make([]*unstructured.Unstructured, 0)
conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now})
@@ -433,10 +382,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
failedToLoadObjs = true
}
}
// empty out manifestInfoMap
for as := range manifestInfoMap {
delete(manifestInfoMap, as)
}
manifestInfo = nil
}
ts.AddCheckpoint("git_ms")
@@ -470,7 +416,6 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now})
failedToLoadObjs = true
}
logCtx.Debugf("Retrieved lived manifests")
// filter out all resources which are not permitted in the application project
@@ -514,16 +459,10 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
log.Warnf("Could not get compare options from ConfigMap (assuming defaults): %v", err)
compareOptions = settings.GetDefaultDiffOptions()
}
manifestRevisions := make([]string, 0)
for _, manifestInfo := range manifestInfoMap {
manifestRevisions = append(manifestRevisions, manifestInfo.Revision)
}
// restore comparison using cached diff result if previous comparison was performed for the same revision
revisionChanged := len(manifestInfoMap) != len(sources) || !reflect.DeepEqual(app.Status.Sync.Revisions, manifestRevisions)
specChanged := !reflect.DeepEqual(app.Status.Sync.ComparedTo, appv1.ComparedTo{Source: app.Spec.GetSource(), Destination: app.Spec.Destination, Sources: sources})
revisionChanged := manifestInfo == nil || app.Status.Sync.Revision != manifestInfo.Revision
specChanged := !reflect.DeepEqual(app.Status.Sync.ComparedTo, appv1.ComparedTo{Source: app.Spec.Source, Destination: app.Spec.Destination})
_, refreshRequested := app.IsRefreshRequested()
noCache = noCache || refreshRequested || app.Status.Expired(m.statusRefreshTimeout) || specChanged || revisionChanged
@@ -652,32 +591,16 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
if failedToLoadObjs {
syncCode = v1alpha1.SyncStatusCodeUnknown
}
var revision string
if !hasMultipleSources && len(manifestRevisions) > 0 {
revision = manifestRevisions[0]
syncStatus := v1alpha1.SyncStatus{
ComparedTo: appv1.ComparedTo{
Source: source,
Destination: app.Spec.Destination,
},
Status: syncCode,
}
var syncStatus v1alpha1.SyncStatus
if hasMultipleSources {
syncStatus = v1alpha1.SyncStatus{
ComparedTo: appv1.ComparedTo{
Destination: app.Spec.Destination,
Sources: sources,
},
Status: syncCode,
Revisions: manifestRevisions,
}
} else {
syncStatus = v1alpha1.SyncStatus{
ComparedTo: appv1.ComparedTo{
Destination: app.Spec.Destination,
Source: app.Spec.GetSource(),
},
Status: syncCode,
Revision: revision,
}
if manifestInfo != nil {
syncStatus.Revision = manifestInfo.Revision
}
ts.AddCheckpoint("sync_ms")
healthStatus, err := setApplicationHealth(managedResources, resourceSummaries, resourceOverrides, app, m.persistResourceHealth)
@@ -688,10 +611,8 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
// Git has already performed the signature verification via its GPG interface, and the result is available
// in the manifest info received from the repository server. We now need to form our opinion about the result
// and stop processing if we do not agree about the outcome.
for _, manifestInfo := range manifestInfoMap {
if gpg.IsGPGEnabled() && verifySignature && manifestInfo != nil {
conditions = append(conditions, verifyGnuPGSignature(manifestInfo.Revision, project, manifestInfo)...)
}
if gpg.IsGPGEnabled() && verifySignature && manifestInfo != nil {
conditions = append(conditions, verifyGnuPGSignature(revision, project, manifestInfo)...)
}
compRes := comparisonResult{
@@ -703,18 +624,9 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
diffConfig: diffConfig,
diffResultList: diffResults,
}
if hasMultipleSources {
for _, manifestInfo := range manifestInfoMap {
compRes.appSourceTypes = append(compRes.appSourceTypes, appv1.ApplicationSourceType(manifestInfo.SourceType))
}
} else {
for _, manifestInfo := range manifestInfoMap {
compRes.appSourceType = v1alpha1.ApplicationSourceType(manifestInfo.SourceType)
break
}
if manifestInfo != nil {
compRes.appSourceType = v1alpha1.ApplicationSourceType(manifestInfo.SourceType)
}
app.Status.SetConditions(conditions, map[appv1.ApplicationConditionType]bool{
appv1.ApplicationConditionComparisonError: true,
appv1.ApplicationConditionSharedResourceWarning: true,
@@ -726,29 +638,18 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
return &compRes
}
func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, revisions []string, sources []v1alpha1.ApplicationSource, hasMultipleSources bool, startedAt metav1.Time) error {
func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, startedAt metav1.Time) error {
var nextID int64
if len(app.Status.History) > 0 {
nextID = app.Status.History.LastRevisionHistory().ID + 1
}
if hasMultipleSources {
app.Status.History = append(app.Status.History, v1alpha1.RevisionHistory{
DeployedAt: metav1.NewTime(time.Now().UTC()),
DeployStartedAt: &startedAt,
ID: nextID,
Sources: sources,
Revisions: revisions,
})
} else {
app.Status.History = append(app.Status.History, v1alpha1.RevisionHistory{
Revision: revision,
DeployedAt: metav1.NewTime(time.Now().UTC()),
DeployStartedAt: &startedAt,
ID: nextID,
Source: source,
})
}
app.Status.History = append(app.Status.History, v1alpha1.RevisionHistory{
Revision: revision,
DeployedAt: metav1.NewTime(time.Now().UTC()),
DeployStartedAt: &startedAt,
ID: nextID,
Source: source,
})
app.Status.History = app.Status.History.Trunc(app.Spec.GetRevisionHistoryLimit())
@@ -758,7 +659,7 @@ func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revi
},
})
if err != nil {
return fmt.Errorf("error marshaling revision history patch: %w", err)
return err
}
_, err = m.appclientset.ArgoprojV1alpha1().Applications(app.Namespace).Patch(context.Background(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{})
return err

View File

@@ -38,11 +38,7 @@ func TestCompareAppStateEmpty(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, "", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
@@ -65,11 +61,7 @@ func TestCompareAppStateMissing(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, "", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.Equal(t, argoappv1.SyncStatusCodeOutOfSync, compRes.syncStatus.Status)
@@ -96,11 +88,7 @@ func TestCompareAppStateExtra(t *testing.T) {
},
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, "", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.Equal(t, argoappv1.SyncStatusCodeOutOfSync, compRes.syncStatus.Status)
assert.Equal(t, 1, len(compRes.resources))
@@ -126,11 +114,7 @@ func TestCompareAppStateHook(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, "", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
assert.Equal(t, 0, len(compRes.resources))
@@ -157,11 +141,7 @@ func TestCompareAppStateSkipHook(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, "", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
assert.Equal(t, 1, len(compRes.resources))
@@ -187,11 +167,7 @@ func TestCompareAppStateCompareOptionIgnoreExtraneous(t *testing.T) {
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, "", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
@@ -219,11 +195,7 @@ func TestCompareAppStateExtraHook(t *testing.T) {
},
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, "", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
@@ -266,11 +238,7 @@ func TestCompareAppStateDuplicatedNamespacedResources(t *testing.T) {
},
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, "", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.Equal(t, 1, len(app.Status.Conditions))
@@ -321,11 +289,7 @@ func TestSetHealth(t *testing.T) {
},
})
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, "", app.Spec.Source, false, false, nil)
assert.Equal(t, health.HealthStatusHealthy, compRes.healthStatus.Status)
}
@@ -357,11 +321,7 @@ func TestSetHealthSelfReferencedApp(t *testing.T) {
},
})
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, "", app.Spec.Source, false, false, nil)
assert.Equal(t, health.HealthStatusHealthy, compRes.healthStatus.Status)
}
@@ -431,11 +391,7 @@ func TestReturnUnknownComparisonStateOnSettingLoadError(t *testing.T) {
},
})
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, "", app.Spec.Source, false, false, nil)
assert.Equal(t, health.HealthStatusUnknown, compRes.healthStatus.Status)
assert.Equal(t, argoappv1.SyncStatusCodeUnknown, compRes.syncStatus.Status)
@@ -482,7 +438,7 @@ func Test_appStateManager_persistRevisionHistory(t *testing.T) {
app.Spec.RevisionHistoryLimit = &i
}
addHistory := func() {
err := manager.persistRevisionHistory(app, "my-revision", argoappv1.ApplicationSource{}, []string{}, []argoappv1.ApplicationSource{}, false, metav1.Time{})
err := manager.persistRevisionHistory(app, "my-revision", argoappv1.ApplicationSource{}, metav1.Time{})
assert.NoError(t, err)
}
addHistory()
@@ -518,7 +474,7 @@ func Test_appStateManager_persistRevisionHistory(t *testing.T) {
assert.Len(t, app.Status.History, 9)
metav1NowTime := metav1.NewTime(time.Now())
err := manager.persistRevisionHistory(app, "my-revision", argoappv1.ApplicationSource{}, []string{}, []argoappv1.ApplicationSource{}, false, metav1NowTime)
err := manager.persistRevisionHistory(app, "my-revision", argoappv1.ApplicationSource{}, metav1NowTime)
assert.NoError(t, err)
assert.Equal(t, app.Status.History.LastRevisionHistory().DeployStartedAt, &metav1NowTime)
}
@@ -572,11 +528,7 @@ func TestSignedResponseNoSignatureRequired(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, "", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
@@ -598,11 +550,7 @@ func TestSignedResponseNoSignatureRequired(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, "", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
@@ -631,11 +579,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "")
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, "", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
@@ -657,11 +601,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "abc123")
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, "abc123", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
@@ -683,11 +623,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "abc123")
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, "abc123", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
@@ -709,11 +645,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "abc123")
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, "abc123", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
@@ -738,11 +670,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
ctrl := newFakeController(&data)
testProj := signedProj
testProj.Spec.SignatureKeys[0].KeyID = "4AEE18F83AFDEB24"
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "abc123")
compRes := ctrl.appStateManager.CompareAppState(app, &testProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &testProj, "abc123", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
@@ -767,11 +695,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
// it doesn't matter for our test whether local manifests are valid
localManifests := []string{"foobar"}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "abc123")
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, localManifests, false)
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, "abc123", app.Spec.Source, false, false, localManifests)
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.Equal(t, argoappv1.SyncStatusCodeUnknown, compRes.syncStatus.Status)
@@ -796,11 +720,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "abc123")
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false)
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, "abc123", app.Spec.Source, false, false, nil)
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
@@ -809,7 +729,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
assert.Len(t, app.Status.Conditions, 0)
}
// Signature required and local manifests supplied and GPG subsystem is disabled - sync
// Signature required and local manifests supplied and GPG subystem is disabled - sync
{
app := newFakeApp()
data := fakeData{
@@ -825,11 +745,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
// it doesn't matter for our test whether local manifests are valid
localManifests := []string{""}
ctrl := newFakeController(&data)
sources := make([]argoappv1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
revisions = append(revisions, "abc123")
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, localManifests, false)
compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, "abc123", app.Spec.Source, false, false, localManifests)
assert.NotNil(t, compRes)
assert.NotNil(t, compRes.syncStatus)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)

View File

@@ -9,8 +9,6 @@ import (
"sync/atomic"
"time"
cdcommon "github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/gitops-engine/pkg/sync"
"github.com/argoproj/gitops-engine/pkg/sync/common"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
@@ -22,6 +20,7 @@ import (
"k8s.io/apimachinery/pkg/util/managedfields"
"k8s.io/kubectl/pkg/util/openapi"
cdcommon "github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/controller/metrics"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
listersv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
@@ -66,8 +65,6 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
var syncOp v1alpha1.SyncOperation
var syncRes *v1alpha1.SyncOperationResult
var source v1alpha1.ApplicationSource
var sources []v1alpha1.ApplicationSource
revisions := make([]string, 0)
if state.Operation.Sync == nil {
state.Phase = common.OperationFailed
@@ -85,53 +82,31 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
return
}
if syncOp.Source == nil || (syncOp.Sources != nil && len(syncOp.Sources) > 0) {
// normal sync case (where source is taken from app.spec.sources)
if app.Spec.HasMultipleSources() {
sources = app.Spec.Sources
} else {
// normal sync case (where source is taken from app.spec.source)
source = app.Spec.GetSource()
sources = make([]v1alpha1.ApplicationSource, 0)
}
if syncOp.Source == nil {
// normal sync case (where source is taken from app.spec.source)
source = app.Spec.Source
} else {
// rollback case
if app.Spec.HasMultipleSources() {
sources = state.Operation.Sync.Sources
} else {
source = *state.Operation.Sync.Source
sources = make([]v1alpha1.ApplicationSource, 0)
}
source = *state.Operation.Sync.Source
}
if state.SyncResult != nil {
syncRes = state.SyncResult
revision = state.SyncResult.Revision
revisions = append(revisions, state.SyncResult.Revisions...)
} else {
syncRes = &v1alpha1.SyncOperationResult{}
// status.operationState.syncResult.source. must be set properly since auto-sync relies
// on this information to decide if it should sync (if source is different than the last
// sync attempt)
if app.Spec.HasMultipleSources() {
syncRes.Sources = sources
} else {
syncRes.Source = source
}
syncRes.Source = source
state.SyncResult = syncRes
}
// if we get here, it means we did not remember a commit SHA which we should be syncing to.
// This typically indicates we are just about to begin a brand new sync/rollback operation.
// Take the value in the requested operation. We will resolve this to a SHA later.
if app.Spec.HasMultipleSources() {
if len(revisions) != len(sources) {
revisions = syncOp.Revisions
}
} else {
if revision == "" {
revision = syncOp.Revision
}
if revision == "" {
// if we get here, it means we did not remember a commit SHA which we should be syncing to.
// This typically indicates we are just about to begin a brand new sync/rollback operation.
// Take the value in the requested operation. We will resolve this to a SHA later.
revision = syncOp.Revision
}
proj, err := argo.GetAppProject(app, listersv1alpha1.NewAppProjectLister(m.projInformer.GetIndexer()), m.namespace, m.settingsMgr, m.db, context.TODO())
@@ -141,23 +116,10 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
return
}
if app.Spec.HasMultipleSources() {
revisions = syncRes.Revisions
} else {
revisions = append(revisions, revision)
}
if !app.Spec.HasMultipleSources() {
sources = []v1alpha1.ApplicationSource{source}
revisions = []string{revision}
}
compareResult := m.CompareAppState(app, proj, revisions, sources, false, true, syncOp.Manifests, app.Spec.HasMultipleSources())
compareResult := m.CompareAppState(app, proj, revision, source, false, true, syncOp.Manifests)
// We now have a concrete commit SHA. Save this in the sync result revision so that we remember
// what we should be syncing to when resuming operations.
syncRes.Revision = compareResult.syncStatus.Revision
syncRes.Revisions = compareResult.syncStatus.Revisions
// If there are any comparison or spec errors error conditions do not perform the operation
if errConditions := app.Status.GetConditions(map[v1alpha1.ApplicationConditionType]bool{
@@ -250,7 +212,14 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
}
trackingMethod := argo.GetTrackingMethod(m.settingsMgr)
opts := []sync.SyncOpt{
syncCtx, cleanup, err := sync.NewSyncContext(
compareResult.syncStatus.Revision,
reconciliationResult,
restConfig,
rawConfig,
m.kubectl,
app.Spec.Destination.Namespace,
openAPISchema,
sync.WithLogr(logutils.NewLogrusLogger(logEntry)),
sync.WithHealthOverride(lua.ResourceHealthOverrides(resourceOverrides)),
sync.WithPermissionValidator(func(un *unstructured.Unstructured, res *v1.APIResource) error {
@@ -280,6 +249,13 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
m.isSelfReferencedObj(live, target, app.GetName(), appLabelKey, trackingMethod)
}),
sync.WithManifestValidation(!syncOp.SyncOptions.HasOption(common.SyncOptionsDisableValidation)),
sync.WithNamespaceCreation(syncOp.SyncOptions.HasOption("CreateNamespace=true"), func(un *unstructured.Unstructured) bool {
if un != nil && kube.GetAppInstanceLabel(un, cdcommon.LabelKeyAppInstance) != "" {
kube.UnsetLabel(un, cdcommon.LabelKeyAppInstance)
return true
}
return false
}),
sync.WithSyncWaveHook(delayBetweenSyncWaves),
sync.WithPruneLast(syncOp.SyncOptions.HasOption(common.SyncOptionPruneLast)),
sync.WithResourceModificationChecker(syncOp.SyncOptions.HasOption("ApplyOutOfSyncOnly=true"), compareResult.diffResultList),
@@ -287,21 +263,6 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
sync.WithReplace(syncOp.SyncOptions.HasOption(common.SyncOptionReplace)),
sync.WithServerSideApply(syncOp.SyncOptions.HasOption(common.SyncOptionServerSideApply)),
sync.WithServerSideApplyManager(cdcommon.ArgoCDSSAManager),
}
if syncOp.SyncOptions.HasOption("CreateNamespace=true") {
opts = append(opts, sync.WithNamespaceModifier(syncNamespace(m.resourceTracking, appLabelKey, trackingMethod, app.Name, app.Spec.SyncPolicy)))
}
syncCtx, cleanup, err := sync.NewSyncContext(
compareResult.syncStatus.Revision,
reconciliationResult,
restConfig,
rawConfig,
m.kubectl,
app.Spec.Destination.Namespace,
openAPISchema,
opts...,
)
if err != nil {
@@ -340,7 +301,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
logEntry.WithField("duration", time.Since(start)).Info("sync/terminate complete")
if !syncOp.DryRun && len(syncOp.Resources) == 0 && state.Phase.Successful() {
err := m.persistRevisionHistory(app, compareResult.syncStatus.Revision, source, compareResult.syncStatus.Revisions, compareResult.syncStatus.ComparedTo.Sources, app.Spec.HasMultipleSources(), state.StartedAt)
err := m.persistRevisionHistory(app, compareResult.syncStatus.Revision, source, state.StartedAt)
if err != nil {
state.Phase = common.OperationError
state.Message = fmt.Sprintf("failed to record sync to history: %v", err)

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