Compare commits

...

134 Commits

Author SHA1 Message Date
Alexander Matyushentsev
c2c19f42ad Update manifests to v1.5.2 2020-04-15 09:20:36 -07:00
Alexander Matyushentsev
8a3b36bd28 Update manifests to v1.5.1 2020-04-06 08:53:21 -07:00
Alexander Matyushentsev
35a7350b74 fix: return 401 error code if username does not exist (#3369) 2020-04-06 08:19:49 -07:00
jannfis
241e6d0a6e fix: Do not panic while running hooks with short revision (#3368) 2020-04-06 08:19:45 -07:00
jannfis
dbd6b406ac chore: Keep autogenerated message in upstream.yaml for HA manifests (#3367)
* fix: Keep autogenerated message in upstream.yaml
2020-04-06 08:19:40 -07:00
jannfis
a069639135 fix: Increase HAProxy check interval to prevent intermittent failures (#3356)
* Increase HAProxy check interval to prevent intermittent failures/state flapping

* Restore original namespace
2020-04-06 08:19:33 -07:00
May Zhang
76241f9d3b fix: Helm v3 CRD are not deployed (#3345)
* Fixing could not find plugin issue when app sync and app diff

* Fixing codegen error

* Revert "Fixing codegen error"

This reverts commit b2dcfb81

* Fixing codegen error

* If user is logged in, settings API would return ConfigManagementPlugins

* For helm3, add flag --include-crds when calling helm template to support helm3 crd

* Fixing typo.

* Added further assertion of ResourceSyncStatusIs for CRD resources.
2020-04-06 08:19:22 -07:00
Alexander Matyushentsev
bdda410463 Update manifests to v1.5.0 2020-04-02 09:34:43 -07:00
dthomson25
2faa5c89d1 Add V0.8 changes to Rollouts healthcheck (#3331) 2020-04-02 09:01:19 -07:00
Alexander Matyushentsev
a12b7bdb74 fix: argocd fails to connect clusters with IAM authentication configuration (#3325) 2020-03-31 17:50:09 -07:00
Alexander Matyushentsev
9b21c25783 Update manifests to v1.5.0-rc3 2020-03-30 15:00:06 -07:00
Alexander Matyushentsev
e1deca2a9e fix: avoid nil pointer dereference in badge handler (#3316) 2020-03-30 14:30:38 -07:00
Alexander Matyushentsev
62621428b1 fix: pass APIVersions value to manifest generation request during app validation and during app manifests loading (#3312)
* fix: pass APIVersions value to manifest generation request during app validation and during app manifests loading
2020-03-30 13:38:15 -07:00
Shuwei Hao
ab1f9e4658 fix: update help info about argcd account can-i (#3310)
Signed-off-by: Shuwei Hao <haoshuwei24@gmail.com>
2020-03-30 13:23:30 -07:00
jannfis
36d1b42d5c Fix possible panic when generating Dex config from malformed YAML (#3303) 2020-03-30 13:23:26 -07:00
Alexander Matyushentsev
8b9d25f6e3 fix: SSO user unable to change local account password (#3297) (#3298)
* fix: SSO user unable to change local account password (#3297)

* apply code review notes
2020-03-30 13:23:22 -07:00
Alexander Matyushentsev
323af4d562 fix: use pagination while loading initial cluster state to avoid memory spikes (#3299) 2020-03-30 13:23:19 -07:00
Alexander Matyushentsev
a946b70b5e fix: fix Cannot read property 'length' of undefined error (#3296) 2020-03-30 13:23:15 -07:00
Alexander Matyushentsev
f9f1bdaabe Update manifests to v1.5.0-rc2 2020-03-25 22:12:54 -07:00
Alexander Matyushentsev
e66b6109f7 fix: implement workaround for helm/helm#6870 bug (#3290)
* fix: implement workaround for  helm/helm#6870 bug

* Update app_management_test.go
2020-03-25 22:11:46 -07:00
Jesse Suen
53897e5019 improvement: remove app name and project labels from reconcliation histogram to reduce cardinality (#3271) 2020-03-25 12:42:23 -07:00
Alexander Matyushentsev
7e0d8a490c fix: increase max connections count to support clusters with very large number of CRDs (#3278) 2020-03-25 10:03:40 -07:00
Alexander Matyushentsev
3684a10332 Update manifests to v1.5.0-rc1 2020-03-20 13:48:19 -07:00
Alexander Matyushentsev
ab80a8126b fix: prevent syncing the same cluster cache multiple times due to race condition (#3256) 2020-03-19 12:44:23 -07:00
Jesse Suen
6905196665 feat: rework prometheus metrics to support richer dashboards (#3254)
* the argocd_app_sync_status and argocd_app_health_status are deprecated in place of additional labels to argocd_app_info
* argocd_app_created_time is deprecated
* deprecated labels can be re-enabled using ARGOCD_LEGACY_CONTROLLER_METRICS
* operation label was added to argocd_app_info to support a guauge of in-progress operations.
* dest_server label was added to k8s related counters to support filtering by cluster
2020-03-18 19:59:51 -07:00
Alexander Matyushentsev
4e283c14fb fix: upgrade argoproj/pkg version (#3255) 2020-03-18 18:22:40 -07:00
Alexander Matyushentsev
1b5925a494 fix: stop trigging auto-syncing if app only need to prune resources and automated prune is disabled (#3253) 2020-03-18 14:19:54 -07:00
Alexander Matyushentsev
d500b27f1d feat: store the name operation initator in the app CRD (#3252) 2020-03-18 13:32:39 -07:00
Alexander Matyushentsev
868b4c4c7c fix: UI crashes when trying to enable auto-sync (#3251) 2020-03-18 11:37:32 -07:00
Jesse Suen
4bbce1cb22 perf: reduce unnecessary K8s calls for CRDs during reconciliation (#3246)
* reduce K8s calls for CRDs during reconciliation
* additional metric labels to k8s API requests (server, verb, kind, namespace)
2020-03-18 03:28:31 -07:00
Bruno Clermont
127f50d697 fix: really skip app requeing for some types of resources (#3225)
* Really skip app requeing

* Add new user
2020-03-17 23:03:01 -07:00
Alexander Matyushentsev
e51aab8d1f fix: applications.List API should sort apps by name (#3248) 2020-03-17 17:10:54 -07:00
Miles Armstrong
85a746f861 feat: Add revision to status badge (#2445) (#3128)
* Refactor SVG and colour assignment

* Add option to include revision (short SHA) in the badge

* Remove unnecessary conversion
2020-03-17 15:44:40 -07:00
Alexander Matyushentsev
3c2be61827 feat: implement Service Account / Local Users (#3215)
* feat: implement Service Account / Local Users

* add local users documentation

* implement accounts management UI

* address code review notes
2020-03-17 15:31:37 -07:00
Alexander Matyushentsev
42d572306d feat: use --api-versions during helm chart rendering (#3243) 2020-03-17 14:20:36 -07:00
Alexander Matyushentsev
b3f8e7a02c docs: add v1.5 change log (#3244) 2020-03-17 11:50:00 -07:00
Jesse Suen
476b09cbbf feat: improve api-server and controller performance (#3222)
* group read comparison settings during app reconciliation
* Reduce lock contention in clusterInfo::ensureSynced(). Add getRepoObj stats
* Remove additional source of lock contention
* Exclude the coordination.k8s.io/Lease resource

Co-authored-by: Alexander Matyushentsev <amatyushentsev@gmail.com>
2020-03-16 11:51:59 -07:00
Conlan Cesar
487d6647d5 Add missing parentheses to Webhook docs (#3239) 2020-03-16 09:44:15 -07:00
jannfis
0378819c54 Test for nil to prevent nil pointer dereference (#3237) 2020-03-16 09:43:44 -07:00
jannfis
bbb925cb63 Update testify to v1.5.1 (#3209) 2020-03-13 19:33:22 -07:00
Alexander Matyushentsev
9d1a378ce8 fix: fix broken URL regex expression (#3236) 2020-03-13 14:35:08 -07:00
Alexander Matyushentsev
e2358cabc9 refactor: use http forwarders from argoproj/pkg repository (#3235) 2020-03-13 11:50:19 -07:00
Alexander Matyushentsev
5cd12a3943 fix: 'requires pruning' is not rendered on app details page for resources that should be pruned (#3234) 2020-03-13 11:36:08 -07:00
Alexander Matyushentsev
ebb06b8c89 fix: app reconciliation fails with panic: index out of (#3233) 2020-03-13 10:52:24 -07:00
Alexander Matyushentsev
d5d01eca3e fix: upgrade argoproj/pkg version to fix leaked sensitive information in logs (#3230) 2020-03-12 13:19:14 -07:00
bergur88
e13bb79578 add docs on mapping different scopes for microsoft (#3224) 2020-03-11 09:06:04 -07:00
khhirani
a8b6282b15 improvement: Surface failure reasons for Rollouts/AnalysisRuns (#3219)
* Modify AnalysisRun error messages. Return hard-coded value if AnalysisRun status doesn't contain message

* Create tests
2020-03-10 16:18:51 -07:00
Saradhi Sreegiriraju
fc00d73cf5 docs: Create USERS.md (#3206)
* Create USERS.md

Create a new USERS file to keep track of who is using Argo CD to minimize scrolling on README.

* Update README.md

Removed `Who users Argo CD` section from README. Users are now tracked in USERS file.

* Update README.md

* Update README.md

* Update USERS.md

* Update pull_request_template.md
2020-03-10 09:01:35 +01:00
CBytelabs
303d46e67c docs: Fixed documentation fault in user-guide/projects/ (#3207)
* Update projects.md

~ Fixed adding policy with wildcard in documentation

* Update projects.md

~ acutally fixed the command completly
2020-03-09 20:20:57 +01:00
Matthias Bertschy
a00798bc5e fix: set MaxCallSendMsgSize to MaxGRPCMessageSize for the GRPC caller (#3189) 2020-03-07 19:30:44 -08:00
Abdullah Alqarni
1c4a15129b feat(ui): add docs to sync policy options present in create application panel (Close #3098) (#3203)
* feat(ui): document sealHeal & pruneResources options in create-application panel

* fix(ui): re-order import statements in application-create-panel.tsx

* docs: correct a typo in user guide auto_sync.md

* docs: document Automatic Self-Healing in user guide auto_sync.md

* docs: add v1.4.3 changelog

* fix: capitalize git word

* docs: update CHANGELOG

* docs: remove CHANGELOG update
2020-03-07 18:03:15 +01:00
Alex Khaerov
0ca35ef26c Add Prudential to the customer list (#3199)
Signed-off-by: Alex Khaerov <alex.khaerov@prudential.com.sg>
2020-03-06 16:26:44 -08:00
Alexander Matyushentsev
b38a9aacb2 fix: codegen task is broken locally (#3200) 2020-03-06 12:51:03 -08:00
jannfis
5b239fc1d1 fix: stop caching helm index (#3193)
* fix: stop caching helm index

* Apply reviewer notes
2020-03-05 19:55:47 +01:00
jannfis
fdf7566bb7 fix: error message on login page if login is disabled (#3198) 2020-03-05 19:54:26 +01:00
Alexander Matyushentsev
389858b6df Add note about where the valueFiles param references (#3196)
This file seems to serve as the only real reference as to what parameters are available for the Application CRD. It took me a bit of trial and error to figure out that these are in the git repo referenced and relative to the path of the helm chart set previously. Hopefully this helps a future user save some time.
2020-03-05 10:00:33 -08:00
Alexander Matyushentsev
20adad76ef feat: Disable Admin Login (fixes #3019) (#3179)
feat: Disable Admin Login (fixes #3019) (#3179)
2020-03-04 15:26:07 -08:00
Alexander Matyushentsev
f37ae1c1f6 docs: document resource.inclusions setting (#3190)
* docs: document resource.inclusions setting

* clarify that resource.inclusions and resource.exclusions might be used together
2020-03-04 17:33:08 +01:00
Alexander Matyushentsev
6edd18bb89 feat: support helm3 (#2383) (#3178)
* feat: support helm3 (#2383)

* draft

* Apply reviewer notes
2020-03-04 17:05:44 +01:00
Alex Mironov
4d23fe8108 feat: add "service-account" flag to "cluster add" command (#3183) (#3184)
* Add "skip-rbac-setup" flag to "cluster add" command

"InstallClusterManagerRBAC" method of the clusterauth package
is somewhat opinionated about rolebindings and role definitions
for "argocd-manager" SA. Sometimes it is desirable however to manually
pre-configure such bindings and/or modify them in order to comply
with existing infrastructure requirements.

This commit introduces a new option "--skip-rbac-setup" which allows operator
to skip the aforementioned "InstallClusterManagerRBAC" method call.

* Modified --skip-rbac-setup into --service-account flag

* use reference instead of hardoded SA name
2020-03-04 14:25:36 +01:00
Andy Boyett
7eeefb003c docs: correct typo in diffing section on HPAs (#3172)
Reordering `spec.metrics` will fix an OutOfSync state due to the HPA
controller reordering this array. The previously referenced
`spec.replicas` field doesn't exist within any known version of the
`HorizontalPodAutoscaler` (autoscaling/v1, autoscaling/v2beta1, or
autoscaling/v2beta2)
2020-03-03 17:51:21 -08:00
Masaya Ozawa
3ae5b2bfe4 Fixed description of non-cascade command in App Deletion (#3173) 2020-03-02 18:01:05 +01:00
wecger
cdebd26ab4 examples/dashboard.json: removing filling, add increase to grpc metrics (#3154) 2020-02-28 10:12:02 -08:00
Alexander Matyushentsev
3a088c7c86 fix: dex proxy should forward request to dex preserving the basehref (#3165) 2020-02-28 18:57:14 +01:00
Dai Kurosawa
5a363e9d9f Update Go version from v1.13.8 to v1.14.0 (#3162) 2020-02-28 08:42:56 -08:00
Gustav Paul
57ea24281c fix: set default login redirect to baseHRef (#3164) 2020-02-27 11:35:51 -08:00
Gustav Paul
94d7c10baa fix: don't double-prepend basehref to redirect URLs (fixes #3137) (#3138)
* fix: don't double-prepend basehref to redirect URLs

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

* ui/src/app: add basehref to window.location.href assignment
2020-02-26 15:13:42 -08:00
Shelby Moore
28027897aa fix: upgrade redis-ha chart and enable haproxy (#3147)
* fix: upgrade redis-ha chart and enable haproxy

* fix: regenerate manifests, revert removal of failover cache client

* fix: add kustomize patch to strip namespace from redis-ha manifests
2020-02-26 14:22:34 -08:00
nurinamu
0c610f91e5 fix broken url and resize it (#3145) 2020-02-26 14:18:41 -08:00
jannfis
990d9ef92b Use a more sane regexp pattern without capture groups for URL matching (#3161) 2020-02-26 10:07:52 -08:00
wecger
6592773a35 improvement: example/dashboard.json: added labels to legends (#3140) 2020-02-22 10:32:59 +01:00
Shelby Moore
beee4de10e fix: make dex server deployment init container resilient to restarts (#3136) 2020-02-20 21:52:21 +01:00
David J. M. Karlsen
7fde387dd6 Update auth0.md (#3133)
cosmetics

Signed-off-by: David Karlsen <david@davidkarlsen.com>
2020-02-19 11:30:00 -08:00
Dai Kurosawa
64c8ac70fb Update Go version from v1.13.7 to v1.13.8 (#3129) 2020-02-17 22:42:19 +01:00
Andreas Grimmer
f230df938e Improve docs for Hooks (#3115) 2020-02-14 07:39:47 -08:00
Alex Rowley
c9b0fdf1d7 Add missing CHANGELOG entry for 1.2.5 (#3109) 2020-02-14 07:39:08 -08:00
jannfis
ea57d15a80 fix: Allow multiple hostnames per SSH known hosts entry and also allow IPv6 (#2814) (#3074)
* Allow multiple hostnames per SSH known hosts entry and also allow IPv6

* Satisfy lint monster

* And also satisfy the other lint monster
2020-02-10 14:11:50 -08:00
Alex Collins
ebc048167c feat: Supports the validate-false option at an app level. Closes #1063 (#2542) 2020-02-10 14:09:25 -08:00
Nándor István Krácser
3b8405a89b add Bank-Vaults to Secret Management (#3106) 2020-02-10 14:05:22 -08:00
Jesse Suen
66d496d1ef fix: argocd-util backup produced truncated backups. import app status (#3096) 2020-02-10 11:24:33 -08:00
Alex Stein
9d71ae5ad6 Adding ThousandEyes to user-list in README.md (#3103) 2020-02-10 08:44:14 -08:00
Felix Gläske
85d660f0b9 Update custom_tools.md (#3100)
docs: fix typo in custom_tools.md (#3100)
2020-02-10 09:11:55 +01:00
Alexander Matyushentsev
d5286296eb fix: install exact version of mkdocs and mkdocs_material during docs site building (#3095) 2020-02-07 16:06:06 -08:00
Alexander Matyushentsev
916d4aed57 fix: reduct secret values of manifests stored in git (#3088) 2020-02-07 15:40:58 -08:00
Alexander Matyushentsev
59d7b7d2b4 fix: ui referring to /api/version using absolute path (#3092) 2020-02-07 15:39:07 -08:00
Alexander Matyushentsev
18c8716f0a feat: add dest cluster and namespace in the Events (#3093) 2020-02-07 15:38:58 -08:00
Fred Dubois
a1afe44066 docs: Fix json pointer in docs (#3087)
We just copy/pasted this json pointer because we deployed a
`MutatingWebhookConfiguration` and realized it wasn't fixing the out of sync.
2020-02-06 21:19:21 +01:00
Alexander Matyushentsev
1695457f9c fix: when user tries to rollback an app with auto-sync enabled UI should ask for user confirmation once (#3080) 2020-02-04 14:55:17 -08:00
Alexander Matyushentsev
06bc4064c1 fix: labels not being deleted via UI (#3081) 2020-02-04 13:49:21 -08:00
Abdullah Alqarni
d67b4f6c36 Fix: correct a typo in kustomize.md (#3079)
Only for the sake of perfection, replacing `it's` with `its` :)

More on this here[http://its-not-its.info/](http://its-not-its.info/)
2020-02-03 23:47:04 -08:00
Adam Johnson
d2ff5887ac Rollback disables auto sync issue #2441 (#2591)
* rollback disables auto sync

* add error check

* Add confirmation to disable auto sync in ui and revert backend change
2020-02-03 16:48:22 -08:00
eSamS
205926fa80 feat: allow ssh and http repository references in bitbucketserver webhook #2773 (#3036)
* check ssh and https url in bitbucketserver webhook

* do not break up checking webhook urls if one check fails

* log webhook url if regexp compile fails
2020-02-03 10:03:48 +01:00
jannfis
c4dd9d19c2 Use 'latest' as default tag for Docker image builds (#3072) 2020-02-01 20:47:25 -08:00
Guido Maria Serra+Fenaroli
74fe4af98e fix: HTTP|HTTPS|NO_PROXY env variable reading #3055 (#3063)
* attempting to fix HTTP|HTTPS|NO_PROXY env variable reading #3055 -> @jannfis tnx for the snippet ;)

* adding a couple of sponsors references

* fix! semanthic and form of the statement

* doc: add ref. to companies that sponsored my work on ArgoCD #3055

* avoiding problems

* Trigger notification

Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2020-02-01 20:46:20 -08:00
Miles Armstrong
949808f0b2 docs: Add MOO Print to list of users (#3065)
* Add MOO Print to list of users

* Re-sort 'Who uses' list alphabetically
2020-01-31 14:36:50 -08:00
jannfis
9ef80ef1f7 chore: Update CHANGELOG.md up to 1.4.2 (#3069) 2020-01-31 13:41:23 -08:00
Dai Kurosawa
1801212ac7 chore: Upgrade Go version from v1.13.6 to v1.13.7 (#3056) 2020-01-31 22:00:43 +01:00
jannfis
722d5b02d9 fix: Correct usage text for repo add command regarding insecure repos (#3068)
* Correct usage information for repo add command regarding insecure repositories

* Retrigger stuck CI
2020-01-31 12:50:39 -08:00
jannfis
9f8505205f fix: Ensure SSH private key is written out with a final newline character (#2890) (#3064)
* Ensure SSH private key is written out with a final newline character

* Retrigger stuck CI
2020-01-31 11:02:43 -08:00
jannfis
9e81c38c13 fix: Handle SSH URLs in 'git@server:org/repo' notation correctly (#3062)
* Handle invalid repo URLs better

* Safeguard Git repository root at client creation
2020-01-31 01:14:22 -08:00
rayanebel
ff40297bdc fix sso condition when several sso connectors has been configured (#3057) 2020-01-30 13:40:16 -08:00
Dai Kurosawa
c8d74d1a7f Fix bug where the same pointer is used. (#3059) 2020-01-30 09:47:18 -08:00
Alexander Matyushentsev
a3f8ec33f4 chore: fix codegen-local (#3053) 2020-01-29 20:00:32 +01:00
Alexander Matyushentsev
c7718242f9 chore: publish image on every push to master (#3051) 2020-01-29 19:09:16 +01:00
Sean Dukehart
57eeaa4231 Changes to enable helm --set-file (#2752)
Necessary STDIN changes to support Windows

Added support for SE Linux

Informational message about linting OOM

Updated due to latest helm stable being 3.x
2020-01-29 08:26:05 -08:00
aarongorka
7edcf47a03 docs: Clarify syntax for diff customization should be json-patch (#3044)
One might assume that Argo is expecting
[JSONPath](https://kubernetes.io/docs/reference/kubectl/jsonpath/)
rather than JSON Patch, which this commit clarifies via a link to the
official RFC.
2020-01-29 07:46:58 -08:00
Pablo Fredrikson
f561f22caa Removing extra dot in docs (#3043)
This dot breaks the yaml and it shouldn't be present
2020-01-28 15:07:21 -08:00
jannfis
dcea620ca6 Update argo-ui dependency to latest commit in master (#3038) 2020-01-27 08:57:46 -08:00
jannfis
9790a5da9c fix: Better handling of K8s secrets for repository credentials & templates (#3016 #3028) (#3029)
* Fix for calculation of credential secrets' names and secret deletion

* Fix comments to reflect reality

* Update unit tests

* Don't encode parts of the repo URL into secret names anymore

* Lint fixes

* Satisfy linter: Remove unused variable

* Retrigger stuck CI
2020-01-27 07:56:41 -08:00
jannfis
b1d281e7bb Allow dash character in output of kubectl version (#3035) 2020-01-27 07:16:37 -08:00
Glen Keane
2e7fa935c4 docs: Fix getting started 404, add useful links (#3037) 2020-01-27 13:51:06 +01:00
Dai Kurosawa
8b69efcdb9 fix: Include resource group for events InvolvedObject.APIVersion #3011 (#3031) 2020-01-25 12:09:24 +01:00
jannfis
8b08a337c5 Clarify that non-standard SSH ports have to use ssh:// URLs (#3030) 2020-01-24 14:27:26 -08:00
Daniel Beal
e22f946415 fix: Jsonnet TLA parameters of same type are overwritten (#3022)
* TLA parameters of same time are overwritten

When updating an application deployed with existing TLAs using the following command:

```
argocd app set m2-jsonnet --jsonnet-tla-code "myTLAVar={hello:'world'}"
```

The all the TLAs of type code will be cleared and not preserved as would be expected of a set. The only TLA remaining is `myTLAVar`.
This will set the behavior of TLAs to match that of extVars

Signed-off-by: Daniel Beal <dbeal@wiser.com>

* revert gopkg.lock

* add unit tests

* fix go formatting
2020-01-24 10:34:53 -08:00
Joseph Mulloy
3c6715a6f9 fix: Replace aws-iam-authenticator to support IRSA (#3010)
Replace aws-iam-authenticator with aws cli to support EKS cluster auth
via IAM Roles for Service Accounts (IRSA)

See https://aws.amazon.com/blogs/opensource/introducing-fine-grained-iam-roles-service-accounts/
2020-01-24 10:32:33 -08:00
Dário Nascimento
4cf02fd813 Hide bindPW in dex config (#3025)
Like https://github.com/argoproj/argo-cd/issues/2536 , the DEX password for LDAP is being leaked in a command that prints configuration.
This change not only hides the bindPW but also changes the logging level to trace so that by default, the configuration is not leaked to logs.
2020-01-24 08:37:14 -08:00
Masayuki Ishii
17d217c2d6 feat: Add argocd cmd for Windows #2121 (#3015)
* fix: Explicitly cast Stdin file descriptors to int

Signed-off-by: Masayuki Ishii <masa213f@gmail.com>

* feat: Add the windows CLI

Signed-off-by: Masayuki Ishii <masa213f@gmail.com>

* fix: Fix warning message

Signed-off-by: Masayuki Ishii <masa213f@gmail.com>
2020-01-24 08:18:00 +01:00
Alexander Matyushentsev
32d5a05aef fix: correctly replace cache in namespace isolation mode (#3023) 2020-01-23 16:19:29 -08:00
rumstead
e3f3688227 docs: Update disaster_recovery.md (#3021)
Fixing verbiage.
2020-01-23 19:39:19 +01:00
Dai Kurosawa
ad715565a6 Upgrade Go version from v1.12.6 to v1.13.6 (#2994) 2020-01-23 10:11:01 -08:00
Alexander Matyushentsev
d7cad4ac6d fix: run dep ensure (#3018) 2020-01-22 14:42:06 -08:00
jannfis
cc6c67d343 fix: Provide correct example for repocreds add command (#3016) (#3017)
* Correct SSH example for repocreds add command

* More example & comment fixes for repo and repocreds commands
2020-01-22 10:34:34 -08:00
Alexander Matyushentsev
6ada626dda fix: impossible to config RBAC if group name includes ',' (#3013)
* fix:  impossible to config RBAC if group name includes ','

* apply reviewer notes
2020-01-22 18:19:46 +01:00
Alexander Matyushentsev
5bc59003af chore: add jannfis to approvers list (#3014) 2020-01-22 08:45:39 +01:00
Alexander Matyushentsev
fe583c2f5d docs: update v1.4 contributors list (#2993) 2020-01-21 14:53:07 -08:00
Marco Schmid
539281f89e fix: Fixes username matching for SSH repositories for webhooks (fixes #2988) (#2990)
* fixed username matching for ssh-repos

* fixed string format
2020-01-16 08:02:41 -08:00
Alexander Matyushentsev
e5ea3fe1fb feat: upgrade dex to v2.21.0 (#2985) 2020-01-15 14:06:38 -08:00
Alexander Matyushentsev
f36ea4646d fix: sync apps panel fails with 'No App Selected' message if name contains '.' (#2983) 2020-01-15 11:00:25 -08:00
Alexander Matyushentsev
ddcdbaa990 docs: add notifications.md with recommandation about notifications (#2979)
* docs: add demo argocd/grafana links

* docs: add notifications.md with recommandation about notifications
2020-01-15 10:48:03 -08:00
Paul Brit
857ce87f00 docs: Fix a broken link to Helm Hooks (#2970) 2020-01-14 14:13:45 -08:00
Alexander Matyushentsev
4643a1c26d fix: fix nil pointer dereference in CreateRepositoryCredentials method (#2975) 2020-01-14 14:13:40 -08:00
Alexander Matyushentsev
3bf8dc6fb0 fix: remove 'total' suffix from gauge prom metric (#2976) 2020-01-14 14:13:19 -08:00
Alexander Matyushentsev
f62559128d fix: fix rendering CRD acronym (#2978) 2020-01-14 14:13:00 -08:00
Alexander Matyushentsev
63fe5f32ba docs: v1.3 and v1.4 changelog (#2952) 2020-01-14 14:10:44 -08:00
270 changed files with 11981 additions and 3149 deletions

View File

@@ -25,13 +25,13 @@ commands:
install_golang:
steps:
- run:
name: Install Golang v1.12.6
name: Install Golang v1.14
command: |
go get golang.org/dl/go1.12.6
[ -e /home/circleci/sdk/go1.12.6 ] || go1.12.6 download
go get golang.org/dl/go1.14
[ -e /home/circleci/sdk/go1.14 ] || go1.14 download
go env
echo "export GOPATH=/home/circleci/.go_workspace" | tee -a $BASH_ENV
echo "export PATH=/home/circleci/sdk/go1.12.6/bin:\$PATH" | tee -a $BASH_ENV
echo "export PATH=/home/circleci/sdk/go1.14/bin:\$PATH" | tee -a $BASH_ENV
save_go_cache:
steps:
- save_cache:
@@ -39,7 +39,7 @@ commands:
# https://circleci.com/docs/2.0/language-go/
paths:
- /home/circleci/.cache/go-build
- /home/circleci/sdk/go1.12.6
- /home/circleci/sdk/go1.14
restore_go_cache:
steps:
- restore_cache:
@@ -62,7 +62,7 @@ jobs:
- save_cache:
key: codegen-v1-{{ checksum "Gopkg.lock" }}-{{ checksum "hack/installers/install-codegen-go-tools.sh" }}
paths: [vendor, /tmp/dl, /go/pkg]
- run: helm init --client-only
- run: helm2 init --client-only
- run: make codegen-local
- run:
name: Check nothing has changed
@@ -85,10 +85,10 @@ jobs:
- install_golang
- checkout
- restore_cache:
key: test-dl-v1
- run: sudo ./hack/install.sh kubectl-linux kubectx-linux dep-linux ksonnet-linux helm-linux kustomize-linux
key: test-dl-v2
- run: sudo ./hack/install.sh kubectl-linux kubectx-linux dep-linux ksonnet-linux helm-linux helm2-linux kustomize-linux
- save_cache:
key: test-dl-v1
key: test-dl-v2
paths: [/tmp/dl]
- configure_git
- run: go get github.com/jstemmer/go-junit-report
@@ -128,11 +128,11 @@ jobs:
- install_golang
- checkout
- restore_cache:
keys: [e2e-dl-v1]
- run: sudo ./hack/install.sh kubectx-linux dep-linux ksonnet-linux helm-linux kustomize-linux
keys: [e2e-dl-v2]
- run: sudo ./hack/install.sh kubectx-linux dep-linux ksonnet-linux helm-linux helm2-linux kustomize-linux
- run: go get github.com/jstemmer/go-junit-report
- save_cache:
key: e2e-dl-v10
key: e2e-dl-v2
paths: [/tmp/dl]
- restore_vendor
- run: dep ensure -v

View File

@@ -3,5 +3,5 @@ Checklist:
* [ ] Either (a) I've created an [enhancement proposal](https://github.com/argoproj/argo-cd/issues/new/choose) and discussed it with the community, (b) this is a bug fix, or (c) this does not need to be in the release notes.
* [ ] The title of the PR states what changed and the related issues number (used for the release note).
* [ ] I've updated both the CLI and UI to expose my feature, or I plan to submit a second PR with them.
* [ ] Optional. My organization is added to the README.
* [ ] Optional. My organization is added to USERS.md.
* [ ] I've signed the CLA and my build is green ([troubleshooting builds](https://argoproj.github.io/argo-cd/developer-guide/ci/)).

View File

@@ -16,7 +16,7 @@ jobs:
python-version: 3.x
- name: build
run: |
pip install mkdocs mkdocs_material
pip install mkdocs==1.0.4 mkdocs_material==4.1.1
mkdocs build
mkdir ./site/.circleci && echo '{version: 2, jobs: {build: {branches: {ignore: gh-pages}}}}' > ./site/.circleci/config.yml
- name: deploy

57
.github/workflows/image.yaml vendored Normal file
View File

@@ -0,0 +1,57 @@
name: Image
on:
push:
branches:
- master
jobs:
publish:
runs-on: ubuntu-latest
env:
GOPATH: /home/runner/work/argo-cd/argo-cd
steps:
- uses: actions/setup-go@v1
with:
go-version: '1.14'
- uses: actions/checkout@master
with:
path: src/github.com/argoproj/argo-cd
- uses: actions/cache@v1
with:
path: src/github.com/argoproj/argo-cd/vendor
key: ${{ runner.os }}-go-dep-${{ hashFiles('**/Gopkg.lock') }}
# download dependencies
- run: mkdir -p $GITHUB_WORKSPACE/bin && curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
working-directory: src/github.com/argoproj/argo-cd
- run: $GOPATH/bin/dep ensure -v
working-directory: ./src/github.com/argoproj/argo-cd
# get image tag
- run: echo ::set-output name=tag::$(cat ./VERSION)-${GITHUB_SHA::8}
working-directory: ./src/github.com/argoproj/argo-cd
id: image
# build
- run: make image DEV_IMAGE=true DOCKER_PUSH=false IMAGE_NAMESPACE=docker.pkg.github.com/argoproj/argo-cd IMAGE_TAG=${{ steps.image.outputs.tag }}
working-directory: ./src/github.com/argoproj/argo-cd
# publish
- run: |
docker login docker.pkg.github.com --username $USERNAME --password $PASSWORD
docker push docker.pkg.github.com/argoproj/argo-cd/argocd:${{ steps.image.outputs.tag }}
env:
USERNAME: ${{ secrets.USERNAME }}
PASSWORD: ${{ secrets.TOKEN }}
# deploy
- run: git clone "https://$TOKEN@github.com/argoproj/argoproj-deployments"
env:
TOKEN: ${{ secrets.TOKEN }}
- run: |
docker run -v $(pwd):/src -w /src --rm -t lyft/kustomizer:v3.3.0 kustomize edit set image argoproj/argocd=docker.pkg.github.com/argoproj/argo-cd/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)
working-directory: argoproj-deployments/argocd
# TODO: clean up old images once github supports it: https://github.community/t5/How-to-use-Git-and-GitHub/Deleting-images-from-Github-Package-Registry/m-p/41202/thread-id/9811

View File

@@ -1,14 +1,291 @@
# Changelog
## v1.3.0-rc2 (2019-10-23)
## v1.5.0 (Not released)
- Issue #2339 - Controller should compare with latest git revision if app has changed (#2543)
- Unknown child app should not affect app health (#2544)
- Redact secrets in dex logs (#2538)
- Allows Helm parameters that contains arrays or maps. (#2525)
- Set cookie policy to SameSite=lax and httpOnly (#2498)
#### Helm Integration Enhancements - Helm 3 Support And More
## v1.3.0-rc1 (2019-10-16)
Introduced native support Helm3 charts. For backward compatibility Helm 2 charts are still rendered using Helm 2 CLI. Argo CD inspects the
Charts.yaml file and choose the right binary based on `apiVersion` value.
Following enhancement were implemented in addition to Helm 3:
* The `--api-version` flag is passed to the `helm template` command during manifest generation.
* The `--set-file` flag can be specified in the application specification.
* Fixed bug that prevents automatically update Helm chart when new version is published (#3193)
#### Local accounts
The local accounts had been introduced additional to `admin` user and SSO integration. The feature is useful for creating authentication
tokens with limited permissions to automate Argo CD management. Local accounts also could be used small by teams when SSO integration is overkill.
This enhancement also allows to disable admin user and enforce only SSO logins.
#### Enhancements
* feat: support helm3 (#2383) (#3178)
* feat: Argo CD Service Account / Local Users #3185
* feat: Disable Admin Login (fixes #3019) (#3179)
* feat(ui): add docs to sync policy options present in create application panel (Close #3098) (#3203)
* feat: add "service-account" flag to "cluster add" command (#3183) (#3184)
* feat: Supports the validate-false option at an app level. Closes #1063 (#2542)
* feat: add dest cluster and namespace in the Events (#3093)
* feat: Rollback disables auto sync issue #2441 (#2591)
* feat: allow ssh and http repository references in bitbucketserver webhook #2773 (#3036)
* feat: Add helm --set-file support (#2751)
* feat: Include resource group for Event's InvolvedObject.APIVersion
* feat: Add argocd cmd for Windows #2121 (#3015)
#### Bug Fixes
- fix: app reconciliation fails with panic: index out of (#3233)
- fix: upgrade argoproj/pkg version to fix leaked sensitive information in logs (#3230)
- fix: set MaxCallSendMsgSize to MaxGRPCMessageSize for the GRPC caller (#3117)
- fix: stop caching helm index (#3193)
- fix: dex proxy should forward request to dex preserving the basehref (#3165)
- fix: set default login redirect to baseHRef (#3164)
- fix: don't double-prepend basehref to redirect URLs (fixes #3137)
- fix: ui referring to /api/version using absolute path (#3092)
- fix: Unhang UI on long app info items by using more sane URL match pattern (#3159)
- fix: Allow multiple hostnames per SSH known hosts entry and also allow IPv6 (#2814) (#3074)
- fix: argocd-util backup produced truncated backups. import app status (#3096)
- fix: upgrade redis-ha chart and enable haproxy (#3147)
- fix: make dex server deployment init container resilient to restarts (#3136)
- fix: reduct secret values of manifests stored in git (#3088)
- fix: labels not being deleted via UI (#3081)
- fix: HTTP|HTTPS|NO_PROXY env variable reading #3055 (#3063)
- fix: Correct usage text for repo add command regarding insecure repos (#3068)
- fix: Ensure SSH private key is written out with a final newline character (#2890) (#3064)
- fix: Handle SSH URLs in 'git@server:org/repo' notation correctly (#3062)
- fix sso condition when several sso connectors has been configured (#3057)
- fix: Fix bug where the same pointer is used. (#3059)
- fix: Opening in new tab bad key binding on Linux (#3020)
- fix: K8s secrets for repository credential templates are not deleted when credential template is deleted (#3028)
- fix: SSH credential template not working #3016
- fix: Unable to parse kubectl pre-release version strings (#3034)
- fix: Jsonnet TLA parameters of same type are overwritten (#3022)
- fix: Replace aws-iam-authenticator to support IRSA (#3010)
- fix: Hide bindPW in dex config (#3025)
- fix: SSH repo URL with a user different from `git` is not matched correctly when resolving a webhook (#2988)
- fix: JWT invalid => Password for superuser has changed since token issued (#2108)
#### Contributors
* alexandrfox
* alexec
* alexmt
* bergur88
* CBytelabs
* dbeal-wiser
* dnascimento
* Elgarni
* eSamS
* gpaul
* jannfis
* jdmulloy
* machgo
* masa213f
* matthyx
* rayanebel
* shelby-moore
* tomcruise81
* wecger
* zeph
## v1.4.2 (2020-01-24)
- fix: correctly replace cache in namespace isolation mode (#3023)
## v1.4.1 (2020-01-23)
- fix: impossible to config RBAC if group name includes ',' (#3013)
## v1.4.0 (2020-01-17)
The v1.4.0 is a stability release that brings multiple bug fixes, security, performance enhancements, and multiple usability improvements.
#### New Features
#### Security
A number of security enhancements and features have been implemented (thanks to [@jannfis](https://github.com/jannfis) for driving it! ):
* **Repository Credential Templates Management UI/CLI**. Now you can use Argo CD CLI or UI to configure
[credentials template](https://argoproj.github.io/argo-cd/user-guide/private-repositories/#credential-templates) for multiple repositories!
* **X-Frame-Options header on serving static assets**. The X-Frame-Options prevents third party sites to trick users into interacting with the application.
* **Tighten AppProject RBAC enforcement**. We've improved the enforcement of access rules specified in the
[application project](https://argoproj.github.io/argo-cd/operator-manual/declarative-setup/#projects) configuration.
#### Namespace Isolation
With the namespace isolation feature, you are no longer have to give full read-only cluster access to the Argo CD. Instead, you can give access only to selected namespaces with-in
the cluster:
```bash
argocd cluster add <mycluster> --namespace <mynamespace1> --namespace <mynamespace2>
```
This feature is useful if you don't have full cluster access but still want to use Argo CD to manage some cluster namespaces. The feature also improves performance if Argo CD is
used to manage a few namespaces of a large cluster.
#### Reconciliation Performance
The Argo CD no longer fork/exec `kubectl` to apply resource changes in the target cluster or convert resource manifest to the required manifest version. This reduces
CPU and Memory usage of large Argo CD instances.
#### Resources Health based Hook Status
The existing Argo CD [resource hooks](https://argoproj.github.io/argo-cd/user-guide/resource_hooks/) feature allows running custom logic during the syncing process. You can mark
any Kubernetes resource as a hook and Argo CD assess hook status if resource is a `Pod`, `Job` or `Argo Workflow`. In the v1.4.0 release Argo CD is going to leverage resource
[health assessment](https://argoproj.github.io/argo-cd/operator-manual/health/) to get sync hook status. This allows using any custom CRD as a sync hook and leverage custom health
check logic.
#### Manifest Generation
* **Track Helm Charts By Semantic Version**. You've been able to track charts hosted in Git repositories using branches to tags. This is now possible for Helm charts. You no longer
need to choose the exact version, such as v1.4.0 ,instead you can use a semantic version constraint such as v1.4.* and the latest version that matches will be installed.
* **Build Environment Variables**. Feature allows config management tool to get access to app details during manifest generation via
[environment variables](https://argoproj.github.io/argo-cd/user-guide/build-environment/).
* **Git submodules**. Argo CD is going to automatically fetch sub-modules if your repository has `.gitmodules` directory.
#### UI and CLI
* **Improved Resource Tree View**. The Application details page got even prettier. The resource view was tuned to fit more resources into the screen, include more information about
each resource and don't lose usability at the same time.
* **New Account Management CLI Command**. The CLI allows to check which actions are allowed for your account: `argocd account can-i sync applications '*'`
#### Maintenance Tools
The team put more effort into building tools that help to maintain Argo CD itself:
* **Bulk Project Editing**. The `argocd-util` allows to add and remove permissions defined in multiple project roles using one command.
* **More Prometheus Metrics**. A set of additional metrics that contains useful information managed clusters is exposed by application controller.
More documentation and tools are coming in patch releases.
#### Breaking Changes
The Argo CD deletes all **in-flight** hooks if you terminate running sync operation. The hook state assessment change implemented in this release the Argo CD enables detection of
an in-flight state for all Kubernetes resources including `Deployment`, `PVC`, `StatefulSet`, `ReplicaSet` etc. So if you terminate the sync operation that has, for example,
`StatefulSet` hook that is `Progressing` it will be deleted. The long-running jobs are not supposed to be used as a sync hook and you should consider using
[Sync Waves](https://argoproj.github.io/argo-cd/user-guide/sync-waves/) instead.
#### Enhancements
* feat: Add custom healthchecks for cert-manager v0.11.0 (#2689)
* feat: add git submodule support (#2495)
* feat: Add repository credential management API and CLI (addresses #2136) (#2207)
* feat: add support for --additional-headers cli flag (#2467)
* feat: Add support for ssh-with-port repo url (#2866) (#2948)
* feat: Add Time to ApplicationCondition. (#2417)
* feat: Adds `argocd auth can-i` command. Close #2255
* feat: Adds revision history limit. Closes #2790 (#2818)
* feat: Adds support for ARGO_CD_[TARGET_REVISION|REVISION] and pass to Custom Tool/Helm/Jsonnet
* feat: Adds support for Helm charts to be a semver range. Closes #2552 (#2606)
* feat: Adds tracing to key external invocations. (#2811)
* feat: argocd-util should allow editing project policies in bulk (#2615)
* feat: Displays controllerrevsion's revision in the UI. Closes #2306 (#2702)
* feat: Issue #2559 - Add gauge Prometheus metric which represents the number of pending manifest requests. (#2658)
* feat: Make ConvertToVersion maybe 1090% faster on average (#2820)
* feat: namespace isolation (#2839)
* feat: removes redundant mutex usage in controller cache and adds cluster cache metrics (#2898)
* feat: Set X-Frame-Options on serving static assets (#2706) (#2711)
* feat: Simplify using Argo CD without users/SSO/UI (#2688)
* feat: Template Out Data Source in Grafana Dashboard (#2859)
* feat: Updates UI icons. Closes #2625 and #2757 (#2653)
* feat: use editor arguments in InteractiveEditor (#2833)
* feat: Use kubectl apply library instead of forking binary (#2861)
* feat: use resource health for hook status evaluation (#2938)
#### Bug Fixes
- fix: Adds support for /api/v1/account* via HTTP. Fixes #2664 (#2701)
- fix: Allow '@'-character in SSH usernames when connecting a repository (#2612)
- fix: Allow dot in project policy. Closes #2724 (#2755)
- fix: Allow you to sync local Helm apps. Fixes #2741 (#2747)
- fix: Allows Helm parameters that contains arrays or maps. (#2525)
- fix: application-controller doesn't deal with rm/add same cluster gracefully (x509 unknown) (#2389)
- fix: diff local ignore kustomize build options (#2942)
- fix: Ensures that Helm charts are correctly resolved before sync. Fixes #2758 (#2760)
- fix: Fix 'Open application' link when using basehref (#2729)
- fix: fix a bug with cluster add when token secret is not first in list. (#2744)
- fix: fix bug where manifests are not cached. Fixes #2770 (#2771)
- fix: Fixes bug whereby retry does not work for CLI. Fixes #2767 (#2768)
- fix: git contention leads applications into Unknown state (#2877)
- fix: Issue #1944 - Gracefully handle missing cached app state (#2464)
- fix: Issue #2668 - Delete a specified context (#2669)
- fix: Issue #2683 - Make sure app update don't fail due to concurrent modification (#2852)
- fix: Issue #2721 Optimize helm repo querying (#2816)
- fix: Issue #2853 - Improve application env variables/labels editing (#2856)
- fix: Issue 2848 - Application Deployment history panel shows incorrect info for recent releases (#2849)
- fix: Make BeforeHookCreation the default. Fixes #2754 (#2759)
- fix: No error on `argocd app create` in CLI if `--revision` is omitted #2665
- fix: Only delete resources during app delete cascade if permitted to (fixes #2693) (#2695)
- fix: prevent user from seeing/deleting resources not permitted in project (#2908) (#2910)
- fix: self-heal should retry syncing an application after specified delay
- fix: stop logging dex config secrets #(2904) (#2937)
- fix: stop using jsondiffpatch on clientside to render resource difference (#2869)
- fix: Target Revision truncated #2736
- fix: UI should re-trigger SSO login if SSO JWT token expires (#2891)
- fix: update argocd-util import was not working properly (#2939)
#### Contributors
* Aalok Ahluwalia
* Aananth K
* Abhishek Jaisingh
* Adam Johnson
* Alan Tang
* Alex Collins
* Alexander Matyushentsev
* Andrew Waters
* Byungjin Park
* Christine Banek
* Daniel Helfand
* David Hong
* David J. M. Karlsen
* David Maciel
* Devan Goodwin
* Devin Stein
* dthomson25
* Gene Liverman
* Gregor Krmelj
* Guido Maria Serra
* Ilir Bekteshi
* Imran Ismail
* INOUE BANJI
* Isaac Gaskin
* jannfis
* Jeff Hastings
* Jesse Suen
* John Girvan
* Konstantin
* Lev Aminov
* Manatsawin Hanmongkolchai
* Marco Schmid
* Masayuki Ishii
* Michael Bridgen
* Naoki Oketani
* niqdev
* nitinpatil1992
* Olivier Boukili
* Olivier Lemasle
* Omer Kahani
* Paul Brit
* Qingbo Zhou
* Saradhi Sreegiriraju
* Scott Cabrinha
* shlo
* Simon Behar
* stgarf
* Yujun Zhang
* Zoltán Reegn
## v1.3.4 (2019-12-05)
- #2819 Fixes logging of tracing option in CLI
## v1.3.3 (2019-12-05)
- #2721 High CPU utilisation (5 cores) and spammy logs
## v1.3.2 (2019-12-03)
- #2797 Fix directory traversal edge case and enhance tests
## v1.3.1 (2019-12-02)
- #2664 update account password from API resulted 404
- #2724 Can't use `DNS-1123` compliant app name when creating project role
- #2726 App list does not show chart for Helm app
- #2741 argocd local sync cannot parse kubernetes version
- #2754 BeforeHookCreation should be the default hook
- #2767 Fix bug whereby retry does not work for CLI
- #2770 Always cache miss for manifests
- #1345 argocd-application-controller: can not retrieve list of objects using index : Index with name namespace does not exist
## v1.3.0 (2019-11-13)
#### New Features
@@ -22,7 +299,9 @@ https://youtu.be/GP7xtrnNznw
##### Orphan Resources
Some users would like to make sure that resources in a namespace are managed only by Argo CD. So we've introduced the concept of an "orphan resource" - any resource that is in namespace associated with an app, but not managed by Argo CD. This is enable in the project settings. Once enabled, Argo CD will show in the app view any resources in the app's namepspace that is not mananged by Argo CD.
Some users would like to make sure that resources in a namespace are managed only by Argo CD. So we've introduced the concept of an "orphan resource" - any resource that is in namespace associated with an app, but not managed by Argo CD. This is enabled in the project settings. Once enabled, Argo CD will show in the app view any resources in the app's namepspace that is not mananged by Argo CD.
https://youtu.be/9ZoTevVQf5I
##### Sync Windows
@@ -30,137 +309,110 @@ There may be instances when you want to control the times during which an Argo C
#### Enhancements
* Issue #2396 argocd list command should have filter options like by pr… (#2421)
* Adds support for Helm 1st-class. Closes #1145 (#1865)
* Issue #1167 - Implement orphan resources support (#2103)
* Helm hooks. Closes #355 (#2069)
* Adds support for a literal YAML block of Helm values. Closes #1930 (#2057)
* Adds support for hook-delete-policy: BeforeHookCreation. Closes #2036 (#2048)
* Adds support for setting Helm string parameters via CLI. Closes #2078 (#2109)
* [UI] Add application labels to Applications list and Applications details page (#1099)
* Helm repository as first class Argo CD Application source (#1145)
* Ability to generate a warn/alert when a namespace deviates from the expected state (#1167)
* Improve diff support for resource requests/limits (#1615)
* HTTP API should allow JWT to be passed via Authorization header (#1642)
* Ability to create & upsert projects from spec (#1852)
* Support for in-line block from helm chart values (#1930)
* Request OIDC groups claim if groups scope is not supported (#1956)
* Add a maintenance window for Applications with automated syncing (#1995)
* Support `argocd.argoproj.io/hook-delete-policy: BeforeHookCreation` (#2036)
* Support setting Helm string parameters using CLI/UI (#2078)
* Config management plugin environment variable UI/CLI support (#2203)
* Helm: auto-detect URLs (#2260)
* Helm: UI improvements (#2261)
* Support `helm template --kube-version ` (#2275)
* Use community icons for resources (#2277)
* Make `group` optional for `ignoreDifferences` config (#2298)
* Update Helm docs (#2315)
* Add cluster information into Splunk (#2354)
* argocd list command should have filter options like by project (#2396)
* Add target/current revision to status badge (#2445)
* Update tooling to use Kustomize v3 (#2487)
* Update root `Dockerfile` to use the `hack/install.sh` (#2488)
* Support and document using HPA for repo-server (#2559)
* Upgrade Helm (#2587)
* UI fixes for "Sync Apps" panel. (#2604)
* Upgrade kustomize from v3.1.0 to v3.2.1 (#2609)
* Map helm lifecycle hooks to ArgoCD pre/post/sync hooks (#355)
* [UI] Enhance app creation page with Helm parameters overrides (#1059)
#### Bug Fixes
- Issue #2484 - Impossible to edit chart name using App details page (#2485)
- Issue #2185 - Manual sync don't trigger hooks (#2477)
- Issue #2453 - Application controller sometimes accidentally removes duplicated/excluded resource warning condition (#2454)
- Issue #1944 - Gracefully handle missing cached app state (#2464)
- Issue #2321 - Hook deletion should not fail if error message is not found (#2458)
- Issue #2448 - Custom resource actions cannot be executed from the UI (#2449)
- Issue #2339 - Make sure controller uses latest git version if app reconciliation result expired (#2346)
- Issue #2290 - Fix nil pointer dereference in application controller (#2291)
- Issue #2245 - Intermittent "git ls-remote" request failures should not fail app reconciliation (#2281)
- Issue #2022 - Support limiting number of concurrent kubectl fork/execs (#2264)
- Fix degraded proxy support for http(s) git repository (#2243) (#2249)
- Issue #2198 - Print empty string instead of Unknown in 'argocd app sync' output (#2223)
- Fix for displaying hooks in app diff view. Fixes #2215 (#2218)
- Issue #2212 - Correctly handle trailing slash in configured URL while creating redirect URL (#2214)
- Deals with race condition when deleting resource. Closes #2141 (#2200)
- Issue #2192 - SyncError app condition disappears during app reconciliation (#2193)
- Adds test for updating immutable field, adds UI button to allow force from UI. See #2150 (#2155)
- Issue #2174 - Fix git repo url parsing on application list view (#2175)
- Issue #2146 - Fix nil pointer dereference error during app reconciliation (#2170)
- Issue #2114 - Fix history api fallback implementation to support app names with dots (#2168)
- Issue #2060 - Endpoint incorrectly considered top level managed resource (#2129)
- Fixed truncation of group in UI. Closes #2006 (#2128)
- Allow adding certs for hostnames ending on a dot (fixes #2116) (#2120)
- Escape square brackets in pattern matching hostnames (fixes #2099) (#2113)
- failed parsing on parameters with comma (#1660)
- Statefuleset with OnDelete Update Strategy stuck progressing (#1881)
- Warning during secret diffing (#1923)
- Error message "Unable to load data: key is missing" is confusing (#1944)
- OIDC group bindings are truncated (#2006)
- Multiple parallel app syncs causes OOM (#2022)
- Unknown error when setting params with argocd app set on helm app (#2046)
- Endpoint is no longer shown as a child of services (#2060)
- SSH known hosts entry cannot be deleted if contains shell pattern in name (#2099)
- Application 404s on names with periods (#2114)
- Adding certs for hostnames ending with a dot (.) is not possible (#2116)
- Fix `TestHookDeleteBeforeCreation` (#2141)
- v1.2.0-rc1 nil pointer dereference when syncing (#2146)
- Replacing services failure (#2150)
- 1.2.0-rc1 - Authentication Required error in Repo Server (#2152)
- v1.2.0-rc1 Applications List View doesn't work (#2174)
- Manual sync does not trigger Presync hooks (#2185)
- SyncError app condition disappears during app reconciliation (#2192)
- argocd app wait\sync prints 'Unknown' for resources without health (#2198)
- 1.2.0-rc2 Warning during secret diffing (#2206)
- SSO redirect url is incorrect if configured Argo CD URL has trailing slash (#2212)
- Application summary diff page shows hooks (#2215)
- An app with a single resource and Sync hook remains progressing (#2216)
- CONTRIBUTING documentation outdated (#2231)
- v1.2.0-rc2 does not retrieve http(s) based git repository behind the proxy (#2243)
- Intermittent "git ls-remote" request failures should not fail app reconciliation (#2245)
- Result of ListApps operation for Git repo is cached incorrectly (#2263)
- ListApps does not utilize cache (#2287)
- Controller panics due to nil pointer error (#2290)
- The Helm --kube-version support does not work on GKE: (#2303)
- Fixes bug that prevents you creating repos via UI/CLI. (#2308)
- The 'helm.repositories' settings is dropped without migration path (#2316)
- Badge response does not contain cache control header (#2317)
- Inconsistent sync result from UI and CLI (#2321)
- Failed edit application with plugin type requiring environment (#2330)
- AutoSync doesn't work anymore (#2339)
- End-to-End tests not working with Kubernetes v1.16 (#2371)
- Creating an application from Helm repository should select "Helm" as source type (#2378)
- The parameters of ValidateAccess GRPC method should not be logged (#2386)
- Maintenance window meaning is confusing (#2398)
- UI bug when targetRevision is ommited (#2407)
- Too many vulnerabilities in Docker image (#2425)
- proj windows commands not consistent with other commands (#2443)
- Custom resource actions cannot be executed from the UI (#2448)
- Application controller sometimes accidentally removes duplicated/excluded resource warning condition (#2453)
- Logic that checks sync windows state in the cli is incorrect (#2455)
- UI don't allow to create window with `* * * * *` schedule (#2475)
- Helm Hook is executed twice if annotated with both pre-install and pre-upgrade annotations (#2480)
- Impossible to edit chart name using App details page (#2484)
- ArgoCD does not provide CSRF protection (#2496)
- ArgoCD failing to install CRDs in master from Helm Charts (#2497)
- Timestamp in Helm package file name causes error in Application with Helm source (#2549)
- Attempting to create a repo with password but not username panics (#2567)
- UI incorrectly mark resources as `Required Pruning` (#2577)
- argocd app diff prints only first difference (#2616)
- Bump min client cache version (#2619)
- Cluster list page fails if any cluster is not reachable (#2620)
- Repository type should be mandatory for repo add command in CLI (#2622)
- Repo server executes unnecessary ls-remotes (#2626)
- Application list page incorrectly filter apps by label selector (#2633)
- Custom actions are disabled in Argo CD UI (#2635)
- Failure of `argocd version` in the self-building container image (#2645)
- Application list page is not updated automatically anymore (#2655)
- Login regression issues (#2659)
- Regression: Cannot return Kustomize version for 3.1.0 (#2662)
- API server does not allow creating role with action `action/*` (#2670)
- Application controller `kubectl-parallelism-limit` flag is broken (#2673)
- Annoying toolbar flickering (#2691)
#### Other
## v1.2.5 (2019-10-29)
- Fix possible path traversal attack when supporting Helm `values.yaml` (#2452)
- Fix UI crash on application list page (#2490)
- add support for --additional-headers cli flag (#2467)
- Allow collapse/expand helm values text (#2469)
- Update base image to Debian buster (#2431)
- Error with new `actions run` suggestion (#2434)
- Detach ArgoCD from specific workflow API (#2428)
- Add application labels to Applications list and Applications details page (#2430)
- Fix JS error on application creation page if no plugins configured (#2432)
- Add missing externalURL for networking.k8s.io Ingress type (#2390)
- App status panel shows metadata of current revision in git instead of most recent reconciled revision (#2419)
- Adds support for plugin params. (#2406)
- Granular RBAC Support for actions (#2110)
- Added Kustomize, Helm, and Kubectl to `argocd version` (#2329)
- Stop unnecessary re-loading clusters on every app list page re-render (#2411)
- Add project level maintenance windows for applications (#2380)
- Make argo-cd docker images openshift friendly (#2362)
- Add dest-server and dest-namespace field to reconciliation logs (#2388)
- Add custom action example to argocd-cm.yaml (#2375)
- Try out community icons. (#2349)
- Make `group` optional for `ignoreDifferences` setting (#2335)
- Adds support for Github Enterprise URLs (#2344)
- Add argocd project as variable to grafana dashboard (#2336)
- Fix missing envs when updating application of content management plugin type (#2331)
- util/localconfig: prefer HOME env var over os/user (#2326)
- Auto-detect Helm repos + support Helm basic auth + fix bugs (#2309)
- Add cache-control HTTP header to badge response (#2328)
- Document flags/env variables useful for performance tuning (#2312)
- Re-enable caching when listing apps. (#2295)
- Fixes bug in `argocd repo list` and tidy up UI (#2307)
- Add restart action to Deployment/StatefulSet/DaemonSet (#2300)
- Clean-up the kube-version from Helm so that we can support GKE. (#2304)
- Fixes issue diffing secrets (#2271)
- Add --self-heal flag to argocd cli (#2296)
- Support --kube-version. (#2276)
- Fix building error when following CONTRIBUTING.md (#2278)
- Adding information to make local execution more accessible (#2279)
- API clients may use the HTTP Authorization header for auth. (#2262)
- Fix TestAutoSyncSelfHealEnabled test flakiness (#2282)
- Change Helm repo URLs to argoproj/argo-cd/master (#2266)
- Fix/grafana datasources (#2229)
- If there is only one wave and no pre/post hooks, we should be synced.… (#2217)
- Create projects from manifests (#2202)
- Fix JS crash in EditablePanel component (#2222)
- Use same /24 network for testing immutable field update (#2213)
- Add path to externalURLs (#2208)
- support OIDC claims request (#1957)
- Better detection for authorization_code OIDC response type (#2164)
- Allow list actions to return yaml or json (#1805)
- Adds a floating action button with help and chat links to every page.… (#2125)
- Temporary disable Git LFS test to unblock release (#2172)
- Determine the manifest version from the VERSION file when on release branch (#2166)
- Enhances cookie warning with actual length to help users fix their co… (#2134)
- Fixed routing issue for periods (#2162)
- Added more health filters in UI (#2160)
- Added 'SyncFail' to possible HookTypes in UI (#2153)
- Indicate that `SyncFail` hooks are on v1.2+ (#2149)
- Adds checks around valid paths for apps (#2133)
- Minor CLI bug fixes (#2132)
- Adds support for a literal YAML block of Helm values. Closes #1930 (#2057)
- Fixed truncation of group in UI. Closes #2006 (#2128)
- Redact secrets using "+" rather than "*" as this is base 64 compatiba… (#2119)
#### Contributors
* Aalok Ahluwalia <!-- num=1 -->
* Adam Johnson <!-- num=4 -->
* Alex Collins <!-- num=62 -->
* Alexander Matyushentsev <!-- num=58 -->
* Andrew Waters <!-- num=2 -->
* Ben Doyle <!-- num=1 -->
* Chris Jones <!-- num=1 -->
* Fred Dubois <!-- num=1 -->
* Gregor Krmelj <!-- num=2 -->
* Gustav Paul <!-- num=2 -->
* Isaac Gaskin <!-- num=1 -->
* Jesse Suen <!-- num=1 -->
* John Reese <!-- num=1 -->
* Mitz Amano <!-- num=1 -->
* Olivier Boukili <!-- num=1 -->
* Olivier Lemasle <!-- num=1 -->
* Rayyis <!-- num=1 -->
* Rodolphe Prin <!-- num=1 -->
* Ryota <!-- num=2 -->
* Seiya Muramatsu <!-- num=1 -->
* Simon Behar <!-- num=11 -->
* Sverre Boschman <!-- num=1 -->
* Tom Wieczorek <!-- num=3 -->
* Yujun Zhang <!-- num=4 -->
* Zoltán Reegn <!-- num=1 -->
* agabet <!-- num=1 -->
* dthomson25 <!-- num=2 -->
* jannfis <!-- num=8 -->
* ssbtn <!-- num=2 -->
- Issue #2339 - Don't update `status.reconciledAt` unless compared with latest git version (#2581)
## v1.2.4 (2019-10-23)

View File

@@ -4,7 +4,7 @@ ARG BASE_IMAGE=debian:10-slim
# Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image
# Also used as the image in CI jobs so needs all dependencies
####################################################################################################
FROM golang:1.12.6 as builder
FROM golang:1.14.0 as builder
RUN echo 'deb http://deb.debian.org/debian buster-backports main' >> /etc/apt/sources.list
@@ -30,9 +30,9 @@ RUN ./install.sh dep-linux
RUN ./install.sh packr-linux
RUN ./install.sh kubectl-linux
RUN ./install.sh ksonnet-linux
RUN ./install.sh helm2-linux
RUN ./install.sh helm-linux
RUN ./install.sh kustomize-linux
RUN ./install.sh aws-iam-authenticator-linux
####################################################################################################
# Argo CD Base - used as the base for both the release and dev argocd images
@@ -50,16 +50,17 @@ RUN groupadd -g 999 argocd && \
chmod g=u /home/argocd && \
chmod g=u /etc/passwd && \
apt-get update && \
apt-get install -y git git-lfs && \
apt-get install -y git git-lfs python3-pip && \
apt-get clean && \
pip3 install awscli==1.17.7 && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY hack/git-ask-pass.sh /usr/local/bin/git-ask-pass.sh
COPY --from=builder /usr/local/bin/ks /usr/local/bin/ks
COPY --from=builder /usr/local/bin/helm2 /usr/local/bin/helm2
COPY --from=builder /usr/local/bin/helm /usr/local/bin/helm
COPY --from=builder /usr/local/bin/kubectl /usr/local/bin/kubectl
COPY --from=builder /usr/local/bin/kustomize /usr/local/bin/kustomize
COPY --from=builder /usr/local/bin/aws-iam-authenticator /usr/local/bin/aws-iam-authenticator
# script to add current (possibly arbitrary) user to /etc/passwd at runtime
# (if it's not already there, to be openshift friendly)
COPY uid_entrypoint.sh /usr/local/bin/uid_entrypoint.sh
@@ -96,7 +97,7 @@ RUN NODE_ENV='production' yarn build
####################################################################################################
# Argo CD Build stage which performs the actual build of Argo CD binaries
####################################################################################################
FROM golang:1.12.6 as argocd-build
FROM golang:1.14.0 as argocd-build
COPY --from=builder /usr/local/bin/dep /usr/local/bin/dep
COPY --from=builder /usr/local/bin/packr /usr/local/bin/packr
@@ -115,7 +116,8 @@ RUN cd ${GOPATH}/src/dummy && \
WORKDIR /go/src/github.com/argoproj/argo-cd
COPY . .
RUN make cli server controller repo-server argocd-util && \
make CLI_NAME=argocd-darwin-amd64 GOOS=darwin cli
make CLI_NAME=argocd-darwin-amd64 GOOS=darwin cli && \
make CLI_NAME=argocd-windows-amd64.exe GOOS=windows cli
####################################################################################################
@@ -124,4 +126,3 @@ RUN make cli server controller repo-server argocd-util && \
FROM argocd-base
COPY --from=argocd-build /go/src/github.com/argoproj/argo-cd/dist/argocd* /usr/local/bin/
COPY --from=argocd-ui ./src/dist/app /shared/app

26
Gopkg.lock generated
View File

@@ -66,16 +66,19 @@
[[projects]]
branch = "master"
digest = "1:52905b00a73cda93a2ce8c5fa35185daed673d59e39576e81ad6ab6fb7076b3c"
digest = "1:fbe4779f247babd0b21e2283d419f848a8dab42c0f6bbdeb88d83f190f52c159"
name = "github.com/argoproj/pkg"
packages = [
"errors",
"exec",
"grpc/http",
"kubeclientmetrics",
"rand",
"stats",
"time",
]
pruneopts = ""
revision = "02a6aac40ac4cd23de448afe7a1ec0ba4b6d2b96"
revision = "f46beff7cd548bafc0264b95a4efed645fb1862c"
[[projects]]
digest = "1:d8a2bb36a048d1571bcc1aee208b61f39dc16c6c53823feffd37449dde162507"
@@ -515,6 +518,14 @@
pruneopts = ""
revision = "c34317bd91bf98fab745d77b03933cf8769299fe"
[[projects]]
digest = "1:ad92aa49f34cbc3546063c7eb2cabb55ee2278b72842eda80e2a20a8a06a8d73"
name = "github.com/google/uuid"
packages = ["."]
pruneopts = ""
revision = "0cd6bf5da1e1c83f8b45653022c74f71af0538a4"
version = "v1.1.1"
[[projects]]
digest = "1:2a131706ff80636629ab6373f2944569b8252ecc018cda8040931b05d32e3c16"
name = "github.com/googleapis/gnostic"
@@ -950,15 +961,15 @@
version = "v0.1"
[[projects]]
digest = "1:c587772fb8ad29ad4db67575dad25ba17a51f072ff18a22b4f0257a4d9c24f75"
digest = "1:cc4eb6813da8d08694e557fcafae8fcc24f47f61a0717f952da130ca9a486dfc"
name = "github.com/stretchr/testify"
packages = [
"assert",
"mock",
]
pruneopts = ""
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
version = "v1.2.2"
revision = "3ebf1ddaeb260c4b1ae502a01c7844fa8c1fa0e9"
version = "v1.5.1"
[[projects]]
digest = "1:51cf0fca93f4866709ceaf01b750e51d997c299a7bd2edf7ccd79e3b428754ae"
@@ -1930,10 +1941,12 @@
"github.com/TomOnTime/utfutil",
"github.com/argoproj/pkg/errors",
"github.com/argoproj/pkg/exec",
"github.com/argoproj/pkg/grpc/http",
"github.com/argoproj/pkg/kubeclientmetrics",
"github.com/argoproj/pkg/stats",
"github.com/argoproj/pkg/time",
"github.com/casbin/casbin",
"github.com/casbin/casbin/model",
"github.com/casbin/casbin/persist",
"github.com/coreos/go-oidc",
"github.com/dgrijalva/jwt-go",
"github.com/dustin/go-humanize",
@@ -1957,6 +1970,7 @@
"github.com/golang/protobuf/ptypes/empty",
"github.com/google/go-jsonnet",
"github.com/google/shlex",
"github.com/google/uuid",
"github.com/grpc-ecosystem/go-grpc-middleware",
"github.com/grpc-ecosystem/go-grpc-middleware/auth",
"github.com/grpc-ecosystem/go-grpc-middleware/logging",

View File

@@ -86,7 +86,7 @@ required = [
[[constraint]]
name = "github.com/stretchr/testify"
version = "1.2.2"
version = "1.5.1"
[[constraint]]
name = "github.com/gobuffalo/packr"
@@ -115,3 +115,7 @@ required = [
[[override]]
name = "github.com/evanphx/json-patch"
version = "v4.1.0"
[[constraint]]
name = "github.com/google/uuid"
version = "1.1.1"

View File

@@ -9,7 +9,7 @@ GIT_COMMIT=$(shell git rev-parse HEAD)
GIT_TAG=$(shell if [ -z "`git status --porcelain`" ]; then git describe --exact-match --tags HEAD 2>/dev/null; fi)
GIT_TREE_STATE=$(shell if [ -z "`git status --porcelain`" ]; then echo "clean" ; else echo "dirty"; fi)
PACKR_CMD=$(shell if [ "`which packr`" ]; then echo "packr"; else echo "go run vendor/github.com/gobuffalo/packr/packr/main.go"; fi)
VOLUME_MOUNT=$(shell [[ $(go env GOOS)=="darwin" ]] && echo ":delegated" || echo "")
VOLUME_MOUNT=$(shell if [[ selinuxenabled -eq 0 ]]; then echo ":Z"; elif [[ $(go env GOOS)=="darwin" ]]; then echo ":delegated"; else echo ""; fi)
define run-in-dev-tool
docker run --rm -it -u $(shell id -u) -e HOME=/home/user -v ${CURRENT_DIR}:/go/src/github.com/argoproj/argo-cd${VOLUME_MOUNT} -w /go/src/github.com/argoproj/argo-cd argocd-dev-tools bash -c "GOPATH=/go $(1)"
@@ -38,6 +38,8 @@ endif
ifneq (${GIT_TAG},)
IMAGE_TAG=${GIT_TAG}
LDFLAGS += -X ${PACKAGE}.gitTag=${GIT_TAG}
else
IMAGE_TAG?=latest
endif
ifeq (${DOCKER_PUSH},true)
@@ -81,6 +83,7 @@ release-cli: clean-debug image
docker create --name tmp-argocd-linux $(IMAGE_PREFIX)argocd:$(IMAGE_TAG)
docker cp tmp-argocd-linux:/usr/local/bin/argocd ${DIST_DIR}/argocd-linux-amd64
docker cp tmp-argocd-linux:/usr/local/bin/argocd-darwin-amd64 ${DIST_DIR}/argocd-darwin-amd64
docker cp tmp-argocd-linux:/usr/local/bin/argocd-windows-amd64.exe ${DIST_DIR}/argocd-windows-amd64.exe
docker rm tmp-argocd-linux
.PHONY: argocd-util
@@ -134,6 +137,7 @@ image: packr
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 dist/packr build -v -i -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-util ./cmd/argocd-util
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 dist/packr build -v -i -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd ./cmd/argocd
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 dist/packr build -v -i -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-darwin-amd64 ./cmd/argocd
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 dist/packr build -v -i -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-windows-amd64.exe ./cmd/argocd
cp Dockerfile.dev dist
docker build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) -f dist/Dockerfile.dev dist
else
@@ -162,7 +166,9 @@ install-lint-tools:
.PHONY: lint
lint:
golangci-lint --version
golangci-lint run --fix --verbose
# NOTE: If you get a "Killed" OOM message, try reducing the value of GOGC
# See https://github.com/golangci/golangci-lint#memory-usage-of-golangci-lint
GOGC=100 golangci-lint run --fix --verbose
.PHONY: build
build:
@@ -170,11 +176,12 @@ build:
.PHONY: test
test:
./hack/test.sh -coverprofile=coverage.out `go list ./... | grep -v 'test/e2e'`
./hack/test.sh -coverprofile=coverage.out `go list ./... | grep -v 'test/e2e'`
.PHONY: test-e2e
test-e2e:
./hack/test.sh -timeout 15m ./test/e2e
# NO_PROXY ensures all tests don't go out through a proxy if one is configured on the test system
NO_PROXY=* ./hack/test.sh -timeout 15m -v ./test/e2e
.PHONY: start-e2e
start-e2e: cli
@@ -189,7 +196,7 @@ start-e2e: cli
ARGOCD_TLS_DATA_PATH=/tmp/argo-e2e/app/config/tls \
ARGOCD_E2E_DISABLE_AUTH=false \
ARGOCD_ZJWT_FEATURE_FLAG=always \
goreman start
goreman start ${ARGOCD_START}
# Cleans VSCode debug.test files from sub-dirs to prevent them from being included in packr boxes
.PHONY: clean-debug
@@ -208,7 +215,7 @@ start:
kubectl create ns argocd || true
kubens argocd
ARGOCD_ZJWT_FEATURE_FLAG=always \
goreman start
goreman start ${ARGOCD_START}
.PHONY: pre-commit
pre-commit: dep-ensure codegen build lint test
@@ -237,4 +244,4 @@ lint-docs:
.PHONY: publish-docs
publish-docs: lint-docs
mkdocs gh-deploy
mkdocs gh-deploy

4
OWNERS
View File

@@ -3,10 +3,8 @@ owners:
- alexmt
- jessesuen
reviewers:
- jannfis
approvers:
- alexec
- alexmt
- jannfis
- jessesuen

View File

@@ -1,6 +1,6 @@
controller: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-application-controller/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
api-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-server/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --staticassets ui/dist/app"
dex: sh -c "go run github.com/argoproj/argo-cd/cmd/argocd-util gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml quay.io/dexidp/dex:v2.14.0 serve /dex.yaml"
dex: sh -c "go run github.com/argoproj/argo-cd/cmd/argocd-util gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml quay.io/dexidp/dex:v2.21.0 serve /dex.yaml"
redis: docker run --rm --name argocd-redis -i -p ${ARGOCD_E2E_REDIS_PORT:-6379}:${ARGOCD_E2E_REDIS_PORT:-6379} redis:5.0.3-alpine --save "" --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}
repo-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-repo-server/main.go --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}"
ui: sh -c 'cd ui && ${ARGOCD_E2E_YARN_CMD:-yarn} start'

View File

@@ -12,66 +12,17 @@ Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.
## Why Argo CD?
Application definitions, configurations, and environments should be declarative and version controlled.
Application deployment and lifecycle management should be automated, auditable, and easy to understand.
1. Application definitions, configurations, and environments should be declarative and version controlled.
1. Application deployment and lifecycle management should be automated, auditable, and easy to understand.
## Who uses Argo CD?
Organizations below are **officially** using Argo CD. Please send a PR with your organization name if you are using Argo CD.
1. [127Labs](https://127labs.com/)
1. [Adevinta](https://www.adevinta.com/)
1. [ANSTO - Australian Synchrotron](https://www.synchrotron.org.au/)
1. [ARZ Allgemeines Rechenzentrum GmbH ](https://www.arz.at/)
1. [Baloise](https://www.baloise.com)
1. [BioBox Analytics](https://biobox.io)
1. [CARFAX](https://www.carfax.com)
1. [Celonis](https://www.celonis.com/)
1. [Codility](https://www.codility.com/)
1. [Commonbond](https://commonbond.co/)
1. [CyberAgent](https://www.cyberagent.co.jp/en/)
1. [Cybozu](https://cybozu-global.com)
1. [EDF Renewables](https://www.edf-re.com/)
1. [Elium](https://www.elium.com)
1. [END.](https://www.endclothing.com/)
1. [Fave](https://myfave.com)
1. [Future PLC](https://www.futureplc.com/)
1. [GMETRI](https://gmetri.com/)
1. [hipages](https://hipages.com.au/)
1. [Intuit](https://www.intuit.com/)
1. [KintoHub](https://www.kintohub.com/)
1. [KompiTech GmbH](https://www.kompitech.com/)
1. [Lytt](https://www.lytt.co/)
1. [Major League Baseball](https://mlb.com)
1. [Mambu](https://www.mambu.com/)
1. [Max Kelsen](https://www.maxkelsen.com/)
1. [Mirantis](https://mirantis.com/)
1. [OpenSaaS Studio](https://opensaas.studio)
1. [Optoro](https://www.optoro.com/)
1. [Peloton Interactive](https://www.onepeloton.com/)
1. [Pipefy](https://www.pipefy.com/)
1. [Riskified](https://www.riskified.com/)
1. [Red Hat](https://www.redhat.com/)
1. [Saildrone](https://www.saildrone.com/)
1. [Saloodo! GmbH](https://www.saloodo.com)
1. [Syncier](https://syncier.com/)
1. [Tesla](https://tesla.com/)
1. [Tiger Analytics](https://www.tigeranalytics.com/)
1. [tZERO](https://www.tzero.com/)
1. [Ticketmaster](https://ticketmaster.com)
1. [Twilio SendGrid](https://sendgrid.com)
1. [Yieldlab](https://www.yieldlab.de/)
1. [UBIO](https://ub.io/)
1. [Universidad Mesoamericana](https://www.umes.edu.gt/)
1. [Viaduct](https://www.viaduct.ai/)
1. [Volvo Cars](https://www.volvocars.com/)
1. [Walkbase](https://www.walkbase.com/)
[Official Argo CD user list](USERS.md)
## Documentation
To learn more about Argo CD [go to the complete documentation](https://argoproj.github.io/argo-cd/).
Check live demo at https://cd.apps.argoproj.io/.
## Community Blogs and Presentations

58
USERS.md Normal file
View File

@@ -0,0 +1,58 @@
## Who uses Argo CD?
As the Argo Community grows, we'd like to keep track of our users. Please send a PR with your organization name if you are using Argo CD.
Currently, the following organizations are **officially** using Argo CD:
1. [127Labs](https://127labs.com/)
1. [Adevinta](https://www.adevinta.com/)
1. [ANSTO - Australian Synchrotron](https://www.synchrotron.org.au/)
1. [ARZ Allgemeines Rechenzentrum GmbH ](https://www.arz.at/)
1. [Baloise](https://www.baloise.com)
1. [BioBox Analytics](https://biobox.io)
1. [CARFAX](https://www.carfax.com)
1. [Celonis](https://www.celonis.com/)
1. [Codility](https://www.codility.com/)
1. [Commonbond](https://commonbond.co/)
1. [CyberAgent](https://www.cyberagent.co.jp/en/)
1. [Cybozu](https://cybozu-global.com)
1. [EDF Renewables](https://www.edf-re.com/)
1. [Elium](https://www.elium.com)
1. [END.](https://www.endclothing.com/)
1. [Fave](https://myfave.com)
1. [Future PLC](https://www.futureplc.com/)
1. [GMETRI](https://gmetri.com/)
1. [hipages](https://hipages.com.au/)
1. [Intuit](https://www.intuit.com/)
1. [KintoHub](https://www.kintohub.com/)
1. [KompiTech GmbH](https://www.kompitech.com/)
1. [Lytt](https://www.lytt.co/)
1. [Major League Baseball](https://mlb.com)
1. [Mambu](https://www.mambu.com/)
1. [Max Kelsen](https://www.maxkelsen.com/)
1. [Mirantis](https://mirantis.com/)
1. [MOO Print](https://www.moo.com/)
1. [OpenSaaS Studio](https://opensaas.studio)
1. [Optoro](https://www.optoro.com/)
1. [Peloton Interactive](https://www.onepeloton.com/)
1. [Pipefy](https://www.pipefy.com/)
1. [Prudential](https://prudential.com.sg)
1. [Red Hat](https://www.redhat.com/)
1. [Robotinfra](https://www.robotinfra.com)
1. [Riskified](https://www.riskified.com/)
1. [Saildrone](https://www.saildrone.com/)
1. [Saloodo! GmbH](https://www.saloodo.com)
1. [Syncier](https://syncier.com/)
1. [Tesla](https://tesla.com/)
1. [ThousandEyes](https://www.thousandeyes.com/)
1. [Ticketmaster](https://ticketmaster.com)
1. [Tiger Analytics](https://www.tigeranalytics.com/)
1. [Twilio SendGrid](https://sendgrid.com)
1. [tZERO](https://www.tzero.com/)
1. [UBIO](https://ub.io/)
1. [Universidad Mesoamericana](https://www.umes.edu.gt/)
1. [Viaduct](https://www.viaduct.ai/)
1. [Volvo Cars](https://www.volvocars.com/)
1. [Walkbase](https://www.walkbase.com/)
1. [Whitehat Berlin](https://whitehat.berlin) by Guido Maria Serra +Fenaroli
1. [Yieldlab](https://www.yieldlab.de/)

View File

@@ -1 +1 @@
1.4.0
1.5.2

View File

@@ -1,22 +1,24 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="131" height="20">
<linearGradient id="b" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<clipPath id="a">
<rect width="131" height="20" rx="3" fill="#fff"/>
<svg width="131" height="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
<defs>
<filter id="dropShadow">
<feDropShadow dx="0.2" dy="0.4" stdDeviation="0.2" flood-color="#333" flood-opacity="0.5"/>
</filter>
</defs>
<clipPath id="roundedCorners">
<rect width="100%" height="100%" rx="3" opacity="1" />
</clipPath>
<g clip-path="url(#a)">
<path id="leftPath" fill="#555" d="M0 0h74v20H0z"/>
<path id="rightPath" fill="#4c1" d="M74 0h57v20H74z"/>
<path fill="url(#b)" d="M0 0h131v20H0z"/>
<g clip-path="url(#roundedCorners)">
<rect id="leftRect" fill="#555" x="0" y="0" width="74" height="20" />
<rect id="rightRect" fill="#4c1" x="74" y="0" width="57" height="20" />
<rect id="revisionRect" fill="#4c1" x="131" y="0" width="62" height="20" display="none"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="90">
<g fill="#fff" style="filter: url(#dropShadow);" text-anchor="middle" font-family="DejaVu Sans, sans-serif" font-size="90">
<image x="5" y="3" width="14" height="14" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB8AAAAeCAYAAADU8sWcAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAABPAAAATwFjiv3XAAACC2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiAgICAgICAgIDx0aWZmOkNvbXByZXNzaW9uPjE8L3RpZmY6Q29tcHJlc3Npb24+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgICAgIDx0aWZmOlBob3RvbWV0cmljSW50ZXJwcmV0YXRpb24+MjwvdGlmZjpQaG90b21ldHJpY0ludGVycHJldGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KD0UqkwAACpZJREFUSA11VnmQFcUZ//qY4527by92WWTXwHKqEJDDg0MQUioKSWopK4oaS9RAlMofUSPGbFlBSaViKomgQSNmIdECkUS8ophdozEJArKoKCsgIFlY2Pu9N29mero7X78FxCR2Vb8309PTv+/4fb9vCHz1II2Nm+jmzYul2bJsdlMyO7LyPGlZtYqQck1ZHCgwLZWiROeJgB7bDzpYb/7o0y/emzXv4Pts8+ZGBUC0uf/vQf57wdw3NTVRnOYFfXvj6pJcadkUmbDGRoxVSEItSYAQQrUmRBP81VoRpkFTJUMuZA/3g/28q3dn89b7u885D4348vgf8NPAxY033LJmSlDizlSOU94f6UhoHaZdC/3QCHWON2gDYBhAYyRAWgyD4QSi1815f29++vv/+CoD2Lm2nAFGl8mndzyxMMgk5/iW6xzPi/xVk+oyE8+vLNt14FR/0uYW14ox0IwUJ4ZAaUpAaaBEYByiyLbikWWNnnThvPIxu+L717auVeb81tbWsyk4C34u8I3LnlhcSCameMzykg7TwzOJGIYWQj+M+voLYcSo/hxY1E65FECUq4G4RFP0nSjMCMVAIIKUnOHkw90L6qq/vXvbh02trV8yoBh2E0NMY9GiG+58fIGXTF6epyw7JOnamZQbz/tCnDrVVzgqqdwTT0ZTdWDN0wPpMh3ZPZqHLSw98C7Y4RwtnAodsTwGAg0ppkcxrlkYJFID+Z0bn/zelsFImzQRXfScNJFiOG689dcT/FT6GzlqedVJTHRpPH6yz/PyfTlx2IrLCpvSdWrv5OXkX9fOJB/Mnaz3XzItap+yMDoyZgEE7F1SceIghryeRNwnTBkEqhRIxiLF6bCpDXNybW2v/ruxcTzbt2+zZmfCvWT+zxNhbek3cxaPlyYsXVWSSHT25rxC3o+OWK6aDn7sZ3r79ZNY28w45Esxuhw5RjmVvEQPlIwgR8bOiE7VdrPaA2+TeGEEhFbhtAEmG5pzk5WqqbWTPv7jC8sLpgxNSRWZrUeWTAgor7EY9ytTiURvzg8GskGU5xxKkc33yDcX1yc7x3ijLxF+zZgoEljgCrSiXOWIG/WGrjifHxl1V9iyeKwW1lHNo5SKmDmcYinivwhjVpkor55sQj9+/D4MO9bpLW8RN6zJzMvbPDUkHaecE368N1+IUUJfIm5hPf1w2kTedlm/LgntmqEWEQGT3ScJYUh2NIxiiWupSUFasor1VgzXvPATfv6BC3Roq0E9MLqAXKQcAe1rqi/dv+q3DwQUw6djY6tiAaG1jLEw7nAn64WhcStPqZqpA6chap8aage077GwbQcJDx8Awq3T3DHlbeijUHWwytHFuuizCTergdQ+YocxLRHVPNcESRAJxqo60nbSvExvvvWx23MCVvucDyRt5hitwDRHHG09pZiaT7MlSUdUhtQGZttYRdwA4WnFQjFnDA4LX7UdIlgMYpaouBgGMnuBKVN/ZhgBRCMVynNAHOfRm777q4UcrW3EZxcEnD/kclYlpVaFKFIZrIRtluvdls/G9InnLZ9fpLXoJjwZAzZkDJ5mjkIj8HTCKETH9oD0eoikMSDQ5cTrLrUg4QoaFlxUH5MdYy6yAFAaYBHed6ODkMPOkMcFZggZKa0SkaL/jMeDpq5D1Vez9693V/wNUg1jQRY8yLX8BcSba8AaOgyBOdqtQBz7DNj8lZCeNY9SN6aiD3bTOc89s2iliDVvKa3uGxf6doQAxYE2oBbm0HQPG5IxqKhOg9ZpSSQj+pDU+jv5t7913spV5c70GcqLJwgMGw6ZJUuBLbgHPW0D4rgQdewDvnAllN58B0D918AvzVBn3jWi/p4Hq2/s+et1URgBRlVRMGVvBtITfwyuyYPAoIRmWSIrEqjZW1Ml/qN7dtRWzptfBzXDoaeri6TicWhes8Zsg9iMOaAyU0D3fw4qdSEkrryquP77xx+HZCwG3T09HEZfCBUXTxh125H9VZ9SHp1OfZF4aEWI9MM1AhmiVCmaIwV6a2F5ge2q8s7OBB8ytPiOZduw6pFHYOS4cUUQGsNWXj4MVLYdaGU9UAQ0o2H8eHh49WpAITReKqdmGC0PsvF2JB4Gu+i5RqKg5JSi82mOnu9GYGEhwbFjSOXadJII7Pa6Ed3hwU8igAU8lU7D/ffdZ1pFEUT19YI+sR9oZgLIjo8h6usDu2oIzJpxOc4ZphKQtoqFxw6LzxIV/RMxkabSUPAJRz3A5oc50x9T7Lf3xkR0R0xGSS+IRIFQOUUUkqvGXdR5tGXnLmjbYXI0OLCJykIBvFe2ABVHgCQqgMpjkH9xE9IY7cSgGd0w+8mOVjiy68DOh+sauusiwSM8F11nlhCm39/SvP7ux4qNZVfba/0TJ183Is9opWtxEXe5E/cC+Y5bf+CilmczqaC/JigEOjjYTrwtzwB8tAn4kJFGMIEmy0B98gb4B7tAYimHncd19ObLrP25rW0/rb76pQqsoKTEkKJgoT64biCObVx35xvGGz67qYW3Nl0RWYH/ftxmo7pyfpSoKFFjEiLxhE73jXaueHXlGw+PZ68rS8pQ01QlodUjTqcAfcQo8qGjQB36EwQfbFAuF8wjZbmNtStefZ4nC0uibKIHez92AeZEUln5wocGuLGxyUbg2cVEFp5a9pFz11MH/ZCP6M0V8gmbxWZL35K2paFmUmjDgCXAMQkjqv8wgFMGBFVSCw8g1wWsrB5IBrTDAvB0eaAkhVHCeGzSQDUm3bE9/1hs/d7dBhy5aSqAaNNWN6Mvdn9+e0KGfl8hZCd6vBwqABmISKSkCgkqr/a6QMWrwLpsKaYWhfrwi1ikfWBNvQmUhXItAlznICMlcopFFNXcEA25wBw/EIms2L4O1onZs5u46abFUsILDWhAc/OKo7H+/OtuEFqaUcsmIE8CR47zEMsSuJvRQcceODVmOqR/uAHKftAC6R+9AKcmzgVxci9qexwLTIDZ34+MR6FVErXECXw7kc+3/G7j8gPG0dbWJmQnum1+zDj3U2rJ0rWzvFRynu/YskMTb5vetmwI7xyeg7R0g072ynEGwa0PwZTRDbDn0GGI1j0Ii2pCKPCyqJTl+eei9tOl5Kr1eU2seuG5ZMBv2fjUIMkQymAWC6jouQE3jdlYZa43PLnsLbcn++eYVwi6FCQktTCEmO3QAx2rhOllAl6bOwsahg2FDTMvhRklWVSUMkxcWEyHJFbUqyCW9AtRSV//K18AF4XmbOWeBTegCF78ujTXf3hm+XvTeo49G8/67Sg+A0a0OGc6CDzIlFbDL3+8GPYuuxLWP7AYysprIQx9YNjdzAglyVkD3qGvd3dsWvv0infM2qBj53zr49rZsJsNZwa2WeTTFxtP3L1oe1VCzh3AWqOM2FJJsFBwbMuCUAgQyAqGrVVJ7Zdwyz2RZS/X/GbrguJ5eNYgyhfnncH5v+DmYcft18Y1T5S7fl9jPMN+4aM6IpeQPmgxThNA5AnuJFhIeI2tHafiNqEUW1XQL+8NrfRznENP1drNuTOA5/5/KezmAZ4zaJBSdVaUvQk5PsNTeqfrMsKQOui5LGKibBAjmKgSRk/RIMlc8BiWCLbI95Dx05jybrMkfsh+xfgPf+hH0AC4OlsAAAAASUVORK5CYII="/>
<text id="leftText1" x="435" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="470"></text>
<text id="leftText2" x="435" y="140" transform="scale(.1)" textLength="470"></text>
<text id="rightText1" x="995" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="470"></text>
<text id="rightText1" x="995" y="140" transform="scale(.1)" textLength="470"></text></g>
<text id="leftText" x="435" y="140" transform="scale(.1)" textLength="470"></text>
<text id="rightText" x="995" y="140" transform="scale(.1)" textLength="470"></text>
<text id="revisionText" x="1550" y="140" font-family="monospace" transform="scale(.1)" font-size="110" display="none"></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -11,6 +11,7 @@ p, role:readonly, certificates, get, *, allow
p, role:readonly, clusters, get, *, allow
p, role:readonly, repositories, get, *, allow
p, role:readonly, projects, get, *, allow
p, role:readonly, accounts, get, *, allow
p, role:admin, applications, create, */*, allow
p, role:admin, applications, update, */*, allow
@@ -30,6 +31,7 @@ p, role:admin, repositories, delete, *, allow
p, role:admin, projects, create, *, allow
p, role:admin, projects, update, *, allow
p, role:admin, projects, delete, *, allow
p, role:admin, accounts, update, *, allow
g, role:admin, role:readonly
g, admin, role:admin
1 # Built-in policy which defines two roles: role:readonly and role:admin,
11 p, role:readonly, repositories, get, *, allow
12 p, role:readonly, projects, get, *, allow
13 p, role:admin, applications, create, */*, allow p, role:readonly, accounts, get, *, allow
14 p, role:admin, applications, create, */*, allow
15 p, role:admin, applications, update, */*, allow
16 p, role:admin, applications, delete, */*, allow
17 p, role:admin, applications, sync, */*, allow
31 p, role:admin, projects, delete, *, allow
32 g, role:admin, role:readonly p, role:admin, accounts, update, *, allow
33 g, admin, role:admin g, role:admin, role:readonly
34 g, admin, role:admin
35
36
37

View File

@@ -16,6 +16,22 @@
"version": "version not set"
},
"paths": {
"/api/v1/account": {
"get": {
"tags": [
"AccountService"
],
"operationId": "ListAccounts",
"responses": {
"200": {
"description": "(empty)",
"schema": {
"$ref": "#/definitions/accountAccountsList"
}
}
}
}
},
"/api/v1/account/can-i/{resource}/{action}/{subresource}": {
"get": {
"tags": [
@@ -79,13 +95,99 @@
}
}
},
"/api/v1/account/{name}": {
"get": {
"tags": [
"AccountService"
],
"operationId": "GetAccount",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "(empty)",
"schema": {
"$ref": "#/definitions/accountAccount"
}
}
}
}
},
"/api/v1/account/{name}/token": {
"post": {
"tags": [
"AccountService"
],
"operationId": "CreateTokenMixin9",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/accountCreateTokenRequest"
}
}
],
"responses": {
"200": {
"description": "(empty)",
"schema": {
"$ref": "#/definitions/accountCreateTokenResponse"
}
}
}
}
},
"/api/v1/account/{name}/token/{id}": {
"delete": {
"tags": [
"AccountService"
],
"operationId": "DeleteTokenMixin9",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
},
{
"type": "string",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "(empty)",
"schema": {
"$ref": "#/definitions/accountEmptyResponse"
}
}
}
}
},
"/api/v1/applications": {
"get": {
"tags": [
"ApplicationService"
],
"summary": "List returns list of applications",
"operationId": "ListMixin8",
"operationId": "List",
"parameters": [
{
"type": "string",
@@ -135,7 +237,7 @@
"ApplicationService"
],
"summary": "Create creates an application",
"operationId": "CreateMixin8",
"operationId": "Create",
"parameters": [
{
"name": "body",
@@ -162,7 +264,7 @@
"ApplicationService"
],
"summary": "Update updates an application",
"operationId": "UpdateMixin8",
"operationId": "Update",
"parameters": [
{
"type": "string",
@@ -293,7 +395,7 @@
"ApplicationService"
],
"summary": "Get returns an application by name",
"operationId": "GetMixin8",
"operationId": "Get",
"parameters": [
{
"type": "string",
@@ -343,7 +445,7 @@
"ApplicationService"
],
"summary": "Delete deletes an application",
"operationId": "DeleteMixin8",
"operationId": "Delete",
"parameters": [
{
"type": "string",
@@ -982,7 +1084,7 @@
"ClusterService"
],
"summary": "List returns list of clusters",
"operationId": "List",
"operationId": "ListMixin4",
"parameters": [
{
"type": "string",
@@ -1004,7 +1106,7 @@
"ClusterService"
],
"summary": "Create creates a cluster",
"operationId": "Create",
"operationId": "CreateMixin4",
"parameters": [
{
"name": "body",
@@ -1031,7 +1133,7 @@
"ClusterService"
],
"summary": "Update updates a cluster",
"operationId": "Update",
"operationId": "UpdateMixin4",
"parameters": [
{
"type": "string",
@@ -1064,7 +1166,7 @@
"ClusterService"
],
"summary": "Get returns a cluster by server address",
"operationId": "GetMixin2",
"operationId": "GetMixin4",
"parameters": [
{
"type": "string",
@@ -1087,7 +1189,7 @@
"ClusterService"
],
"summary": "Delete deletes a cluster",
"operationId": "Delete",
"operationId": "DeleteMixin4",
"parameters": [
{
"type": "string",
@@ -1137,7 +1239,7 @@
"ProjectService"
],
"summary": "List returns list of projects",
"operationId": "ListMixin6",
"operationId": "ListMixin5",
"parameters": [
{
"type": "string",
@@ -1159,7 +1261,7 @@
"ProjectService"
],
"summary": "Create a new project.",
"operationId": "CreateMixin6",
"operationId": "CreateMixin5",
"parameters": [
{
"name": "body",
@@ -1186,7 +1288,7 @@
"ProjectService"
],
"summary": "Get returns a project by name",
"operationId": "GetMixin6",
"operationId": "GetMixin5",
"parameters": [
{
"type": "string",
@@ -1209,7 +1311,7 @@
"ProjectService"
],
"summary": "Delete deletes a project",
"operationId": "DeleteMixin6",
"operationId": "DeleteMixin5",
"parameters": [
{
"type": "string",
@@ -1284,7 +1386,7 @@
"ProjectService"
],
"summary": "Update updates a project",
"operationId": "UpdateMixin6",
"operationId": "UpdateMixin5",
"parameters": [
{
"type": "string",
@@ -1803,7 +1905,7 @@
"SettingsService"
],
"summary": "Get returns Argo CD settings",
"operationId": "Get",
"operationId": "GetMixin7",
"responses": {
"200": {
"description": "(empty)",
@@ -1885,6 +1987,41 @@
}
},
"definitions": {
"accountAccount": {
"type": "object",
"properties": {
"capabilities": {
"type": "array",
"items": {
"type": "string"
}
},
"enabled": {
"type": "boolean",
"format": "boolean"
},
"name": {
"type": "string"
},
"tokens": {
"type": "array",
"items": {
"$ref": "#/definitions/accountToken"
}
}
}
},
"accountAccountsList": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/accountAccount"
}
}
}
},
"accountCanIResponse": {
"type": "object",
"properties": {
@@ -1893,12 +2030,55 @@
}
}
},
"accountCreateTokenRequest": {
"type": "object",
"properties": {
"expiresIn": {
"type": "string",
"format": "int64",
"title": "expiresIn represents a duration in seconds"
},
"name": {
"type": "string"
}
}
},
"accountCreateTokenResponse": {
"type": "object",
"properties": {
"token": {
"type": "string"
}
}
},
"accountEmptyResponse": {
"type": "object"
},
"accountToken": {
"type": "object",
"properties": {
"expiresAt": {
"type": "string",
"format": "int64"
},
"id": {
"type": "string"
},
"issuedAt": {
"type": "string",
"format": "int64"
}
}
},
"accountUpdatePasswordRequest": {
"type": "object",
"properties": {
"currentPassword": {
"type": "string"
},
"name": {
"type": "string"
},
"newPassword": {
"type": "string"
}
@@ -2192,6 +2372,10 @@
},
"url": {
"type": "string"
},
"userLoginsDisabled": {
"type": "boolean",
"format": "boolean"
}
}
},
@@ -2301,6 +2485,13 @@
"type": "object",
"title": "HelmAppSpec contains helm app name in source repo",
"properties": {
"fileParameters": {
"type": "array",
"title": "helm file parameters",
"items": {
"$ref": "#/definitions/v1alpha1HelmFileParameter"
}
},
"name": {
"type": "string"
},
@@ -3118,6 +3309,13 @@
"type": "object",
"title": "ApplicationSourceHelm holds helm specific options",
"properties": {
"fileParameters": {
"type": "array",
"title": "FileParameters are file parameters to the helm template",
"items": {
"$ref": "#/definitions/v1alpha1HelmFileParameter"
}
},
"parameters": {
"type": "array",
"title": "Parameters are parameters to the helm template",
@@ -3476,6 +3674,20 @@
}
}
},
"v1alpha1HelmFileParameter": {
"type": "object",
"title": "HelmFileParameter is a file parameter to a helm template",
"properties": {
"name": {
"type": "string",
"title": "Name is the name of the helm parameter"
},
"path": {
"type": "string",
"title": "Path is the path value for the helm parameter"
}
}
},
"v1alpha1HelmParameter": {
"type": "object",
"title": "HelmParameter is a parameter to a helm template",
@@ -3579,11 +3791,29 @@
"description": "Operation contains requested operation parameters.",
"type": "object",
"properties": {
"initiatedBy": {
"$ref": "#/definitions/v1alpha1OperationInitiator"
},
"sync": {
"$ref": "#/definitions/v1alpha1SyncOperation"
}
}
},
"v1alpha1OperationInitiator": {
"type": "object",
"title": "OperationInitiator holds information about the operation initiator",
"properties": {
"automated": {
"description": "Automated is set to true if operation was initiated automatically by the application controller.",
"type": "boolean",
"format": "boolean"
},
"username": {
"description": "Name of a user who started operation.",
"type": "string"
}
}
},
"v1alpha1OperationState": {
"description": "OperationState contains information about state of currently performing operation on application.",
"type": "object",
@@ -4187,6 +4417,13 @@
"source": {
"$ref": "#/definitions/v1alpha1ApplicationSource"
},
"syncOptions": {
"type": "array",
"title": "SyncOptions provide per-sync sync-options, e.g. Validate=false",
"items": {
"type": "string"
}
},
"syncStrategy": {
"$ref": "#/definitions/v1alpha1SyncStrategy"
}
@@ -4233,6 +4470,13 @@
"properties": {
"automated": {
"$ref": "#/definitions/v1alpha1SyncPolicyAutomated"
},
"syncOptions": {
"type": "array",
"title": "Options allow youe to specify whole app sync-options",
"items": {
"type": "string"
}
}
}
},

View File

@@ -6,6 +6,7 @@ import (
"os"
"time"
"github.com/argoproj/pkg/stats"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes"
@@ -19,13 +20,13 @@ import (
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/controller"
"github.com/argoproj/argo-cd/errors"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
"github.com/argoproj/argo-cd/reposerver/apiclient"
appstatecache "github.com/argoproj/argo-cd/util/cache/appstate"
"github.com/argoproj/argo-cd/util/cli"
"github.com/argoproj/argo-cd/util/kube"
"github.com/argoproj/argo-cd/util/settings"
"github.com/argoproj/argo-cd/util/stats"
)
const (
@@ -59,8 +60,7 @@ func newCommand() *cobra.Command {
config, err := clientConfig.ClientConfig()
errors.CheckError(err)
config.QPS = common.K8sClientConfigQPS
config.Burst = common.K8sClientConfigBurst
errors.CheckError(v1alpha1.SetK8SConfigDefaults(config))
kubeClient := kubernetes.NewForConfigOrDie(config)
appClient := appclientset.NewForConfigOrDie(config)
@@ -92,7 +92,8 @@ func newCommand() *cobra.Command {
kubectlParallelismLimit)
errors.CheckError(err)
log.Infof("Application Controller (version: %s) starting (namespace: %s)", common.GetVersion(), namespace)
vers := common.GetVersion()
log.Infof("Application Controller (version: %s, built: %s) starting (namespace: %s)", vers.Version, vers.BuildDate, namespace)
stats.RegisterStackDumper()
stats.StartStatsTicker(10 * time.Minute)
stats.RegisterHeapDumper("memprofile")

View File

@@ -7,6 +7,7 @@ import (
"os"
"time"
"github.com/argoproj/pkg/stats"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -16,7 +17,6 @@ import (
reposervercache "github.com/argoproj/argo-cd/reposerver/cache"
"github.com/argoproj/argo-cd/reposerver/metrics"
"github.com/argoproj/argo-cd/util/cli"
"github.com/argoproj/argo-cd/util/stats"
"github.com/argoproj/argo-cd/util/tls"
)

View File

@@ -4,18 +4,19 @@ import (
"context"
"time"
"github.com/argoproj/pkg/stats"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/errors"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
"github.com/argoproj/argo-cd/reposerver/apiclient"
"github.com/argoproj/argo-cd/server"
servercache "github.com/argoproj/argo-cd/server/cache"
"github.com/argoproj/argo-cd/util/cli"
"github.com/argoproj/argo-cd/util/stats"
"github.com/argoproj/argo-cd/util/tls"
)
@@ -48,8 +49,7 @@ func NewCommand() *cobra.Command {
config, err := clientConfig.ClientConfig()
errors.CheckError(err)
config.QPS = common.K8sClientConfigQPS
config.Burst = common.K8sClientConfigBurst
errors.CheckError(v1alpha1.SetK8SConfigDefaults(config))
namespace, _, err := clientConfig.Namespace()
errors.CheckError(err)

View File

@@ -26,7 +26,6 @@ import (
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/errors"
"github.com/argoproj/argo-cd/util"
"github.com/argoproj/argo-cd/util/cli"
"github.com/argoproj/argo-cd/util/db"
"github.com/argoproj/argo-cd/util/dex"
@@ -109,7 +108,7 @@ func NewRunDexCommand() *cobra.Command {
} else {
err = ioutil.WriteFile("/tmp/dex.yaml", dexCfgBytes, 0644)
errors.CheckError(err)
log.Info(redactor(string(dexCfgBytes)))
log.Debug(redactor(string(dexCfgBytes)))
cmd = exec.Command("dex", "serve", "/tmp/dex.yaml")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
@@ -385,8 +384,14 @@ func NewExportCommand() *cobra.Command {
} else {
f, err := os.Create(out)
errors.CheckError(err)
defer util.Close(f)
writer = bufio.NewWriter(f)
bw := bufio.NewWriter(f)
writer = bw
defer func() {
err = bw.Flush()
errors.CheckError(err)
err = f.Close()
errors.CheckError(err)
}()
}
acdClients := newArgoCDClientsets(config, namespace)
@@ -540,10 +545,21 @@ func specsEqual(left, right unstructured.Unstructured) bool {
leftData, _, _ := unstructured.NestedMap(left.Object, "data")
rightData, _, _ := unstructured.NestedMap(right.Object, "data")
return reflect.DeepEqual(leftData, rightData)
case "AppProject", "Application":
case "AppProject":
leftSpec, _, _ := unstructured.NestedMap(left.Object, "spec")
rightSpec, _, _ := unstructured.NestedMap(right.Object, "spec")
return reflect.DeepEqual(leftSpec, rightSpec)
case "Application":
leftSpec, _, _ := unstructured.NestedMap(left.Object, "spec")
rightSpec, _, _ := unstructured.NestedMap(right.Object, "spec")
leftStatus, _, _ := unstructured.NestedMap(left.Object, "status")
rightStatus, _, _ := unstructured.NestedMap(right.Object, "status")
// reconciledAt and observedAt are constantly changing and we ignore any diff there
delete(leftStatus, "reconciledAt")
delete(rightStatus, "reconciledAt")
delete(leftStatus, "observedAt")
delete(rightStatus, "observedAt")
return reflect.DeepEqual(leftSpec, rightSpec) && reflect.DeepEqual(leftStatus, rightStatus)
}
return false
}
@@ -558,8 +574,13 @@ func updateLive(bak, live *unstructured.Unstructured) *unstructured.Unstructured
switch live.GetKind() {
case "Secret", "ConfigMap":
newLive.Object["data"] = bak.Object["data"]
case "AppProject", "Application":
case "AppProject":
newLive.Object["spec"] = bak.Object["spec"]
case "Application":
newLive.Object["spec"] = bak.Object["spec"]
if _, ok := bak.Object["status"]; ok {
newLive.Object["status"] = bak.Object["status"]
}
}
return newLive
}
@@ -640,7 +661,7 @@ func redactor(dirtyString string) string {
err := yaml.Unmarshal([]byte(dirtyString), &config)
errors.CheckError(err)
iterateStringFields(config, func(name string, val string) string {
if name == "clientSecret" || name == "secret" {
if name == "clientSecret" || name == "secret" || name == "bindPW" {
return "********"
} else {
return val

View File

@@ -18,6 +18,13 @@ connectors:
id: github
name: GitHub
type: github
- config:
bindDN: uid=serviceaccount,cn=users,dc=example,dc=com
bindPW: theSecret
host: ldap.example.com:636
id: ldap
name: LDAP
type: ldap
grpc:
addr: 0.0.0.0:5557
issuer: https://argocd.example.com/api/dex
@@ -49,6 +56,13 @@ var expectedRedaction = `connectors:
id: github
name: GitHub
type: github
- config:
bindDN: uid=serviceaccount,cn=users,dc=example,dc=com
bindPW: '********'
host: ldap.example.com:636
id: ldap
name: LDAP
type: ldap
grpc:
addr: 0.0.0.0:5557
issuer: https://argocd.example.com/api/dex

View File

@@ -5,9 +5,12 @@ import (
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
"syscall"
"text/tabwriter"
"time"
timeutil "github.com/argoproj/pkg/time"
"github.com/ghodss/yaml"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -21,6 +24,7 @@ import (
"github.com/argoproj/argo-cd/util"
"github.com/argoproj/argo-cd/util/cli"
"github.com/argoproj/argo-cd/util/localconfig"
sessionutil "github.com/argoproj/argo-cd/util/session"
)
func NewAccountCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
@@ -35,11 +39,16 @@ func NewAccountCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
command.AddCommand(NewAccountUpdatePasswordCommand(clientOpts))
command.AddCommand(NewAccountGetUserInfoCommand(clientOpts))
command.AddCommand(NewAccountCanICommand(clientOpts))
command.AddCommand(NewAccountListCommand(clientOpts))
command.AddCommand(NewAccountGenerateTokenCommand(clientOpts))
command.AddCommand(NewAccountGetCommand(clientOpts))
command.AddCommand(NewAccountDeleteTokenCommand(clientOpts))
return command
}
func NewAccountUpdatePasswordCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
account string
currentPassword string
newPassword string
)
@@ -51,14 +60,20 @@ func NewAccountUpdatePasswordCommand(clientOpts *argocdclient.ClientOptions) *co
c.HelpFunc()(c, args)
os.Exit(1)
}
acdClient := argocdclient.NewClientOrDie(clientOpts)
conn, usrIf := acdClient.NewAccountClientOrDie()
defer util.Close(conn)
if currentPassword == "" {
userInfo := getCurrentAccount(acdClient)
if userInfo.Iss == sessionutil.SessionManagerClaimsIssuer && currentPassword == "" {
fmt.Print("*** Enter current password: ")
password, err := terminal.ReadPassword(syscall.Stdin)
password, err := terminal.ReadPassword(int(os.Stdin.Fd()))
errors.CheckError(err)
currentPassword = string(password)
fmt.Print("\n")
}
if newPassword == "" {
var err error
newPassword, err = cli.ReadAndConfirmPassword()
@@ -68,37 +83,37 @@ func NewAccountUpdatePasswordCommand(clientOpts *argocdclient.ClientOptions) *co
updatePasswordRequest := accountpkg.UpdatePasswordRequest{
NewPassword: newPassword,
CurrentPassword: currentPassword,
Name: account,
}
acdClient := argocdclient.NewClientOrDie(clientOpts)
conn, usrIf := acdClient.NewAccountClientOrDie()
defer util.Close(conn)
ctx := context.Background()
_, err := usrIf.UpdatePassword(ctx, &updatePasswordRequest)
errors.CheckError(err)
fmt.Printf("Password updated\n")
// Get a new JWT token after updating the password
localCfg, err := localconfig.ReadLocalConfig(clientOpts.ConfigPath)
errors.CheckError(err)
configCtx, err := localCfg.ResolveContext(clientOpts.Context)
errors.CheckError(err)
claims, err := configCtx.User.Claims()
errors.CheckError(err)
tokenString := passwordLogin(acdClient, claims.Subject, newPassword)
localCfg.UpsertUser(localconfig.User{
Name: localCfg.CurrentContext,
AuthToken: tokenString,
})
err = localconfig.WriteLocalConfig(*localCfg, clientOpts.ConfigPath)
errors.CheckError(err)
fmt.Printf("Context '%s' updated\n", localCfg.CurrentContext)
if account == "" || account == userInfo.Username {
// Get a new JWT token after updating the password
localCfg, err := localconfig.ReadLocalConfig(clientOpts.ConfigPath)
errors.CheckError(err)
configCtx, err := localCfg.ResolveContext(clientOpts.Context)
errors.CheckError(err)
claims, err := configCtx.User.Claims()
errors.CheckError(err)
tokenString := passwordLogin(acdClient, claims.Subject, newPassword)
localCfg.UpsertUser(localconfig.User{
Name: localCfg.CurrentContext,
AuthToken: tokenString,
})
err = localconfig.WriteLocalConfig(*localCfg, clientOpts.ConfigPath)
errors.CheckError(err)
fmt.Printf("Context '%s' updated\n", localCfg.CurrentContext)
}
},
}
command.Flags().StringVar(&currentPassword, "current-password", "", "current password you wish to change")
command.Flags().StringVar(&newPassword, "new-password", "", "new password you want to update to")
command.Flags().StringVar(&account, "account", "", "an account name that should be updated. Defaults to current user account")
return command
}
@@ -159,7 +174,7 @@ argocd account can-i sync applications '*'
argocd account can-i update projects 'default'
# Can I create a cluster?
argocd account can-i create cluster '*'
argocd account can-i create clusters '*'
Actions: %v
Resources: %v
@@ -184,3 +199,199 @@ Resources: %v
},
}
}
func printAccountNames(accounts []*accountpkg.Account) {
for _, p := range accounts {
fmt.Println(p.Name)
}
}
func printAccountsTable(items []*accountpkg.Account) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintf(w, "NAME\tENABLED\tCAPABILITIES\n")
for _, a := range items {
fmt.Fprintf(w, "%s\t%v\t%s\n", a.Name, a.Enabled, strings.Join(a.Capabilities, ", "))
}
_ = w.Flush()
}
func NewAccountListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
output string
)
cmd := &cobra.Command{
Use: "list",
Short: "List accounts",
Example: "argocd account list",
Run: func(c *cobra.Command, args []string) {
conn, client := argocdclient.NewClientOrDie(clientOpts).NewAccountClientOrDie()
defer util.Close(conn)
ctx := context.Background()
response, err := client.ListAccounts(ctx, &accountpkg.ListAccountRequest{})
errors.CheckError(err)
switch output {
case "yaml", "json":
err := PrintResourceList(response.Items, output, false)
errors.CheckError(err)
case "name":
printAccountNames(response.Items)
case "wide", "":
printAccountsTable(response.Items)
default:
errors.CheckError(fmt.Errorf("unknown output format: %s", output))
}
},
}
cmd.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide|name")
return cmd
}
func getCurrentAccount(clientset argocdclient.Client) session.GetUserInfoResponse {
conn, client := clientset.NewSessionClientOrDie()
defer util.Close(conn)
userInfo, err := client.GetUserInfo(context.Background(), &session.GetUserInfoRequest{})
errors.CheckError(err)
return *userInfo
}
func NewAccountGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
output string
account string
)
cmd := &cobra.Command{
Use: "get",
Short: "Get account details",
Example: `# Get the currently logged in account details
argocd account get
# Get details for an account by name
argocd account get --account <account-name>`,
Run: func(c *cobra.Command, args []string) {
clientset := argocdclient.NewClientOrDie(clientOpts)
if account == "" {
account = getCurrentAccount(clientset).Username
}
conn, client := clientset.NewAccountClientOrDie()
defer util.Close(conn)
acc, err := client.GetAccount(context.Background(), &accountpkg.GetAccountRequest{Name: account})
errors.CheckError(err)
switch output {
case "yaml", "json":
err := PrintResourceList(acc, output, true)
errors.CheckError(err)
case "name":
fmt.Println(acc.Name)
case "wide", "":
printAccountDetails(acc)
default:
errors.CheckError(fmt.Errorf("unknown output format: %s", output))
}
},
}
cmd.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide|name")
cmd.Flags().StringVarP(&account, "account", "a", "", "Account name. Defaults to the current account.")
return cmd
}
func printAccountDetails(acc *accountpkg.Account) {
fmt.Printf(printOpFmtStr, "Name:", acc.Name)
fmt.Printf(printOpFmtStr, "Enabled:", strconv.FormatBool(acc.Enabled))
fmt.Printf(printOpFmtStr, "Capabilities:", strings.Join(acc.Capabilities, ", "))
fmt.Println("\nTokens:")
if len(acc.Tokens) == 0 {
fmt.Println("NONE")
} else {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintf(w, "ID\tISSUED AT\tEXPIRING AT\n")
for _, t := range acc.Tokens {
expiresAtFormatted := "never"
if t.ExpiresAt > 0 {
expiresAt := time.Unix(t.ExpiresAt, 0)
expiresAtFormatted = expiresAt.Format(time.RFC3339)
if expiresAt.Before(time.Now()) {
expiresAtFormatted = fmt.Sprintf("%s (expired)", expiresAtFormatted)
}
}
fmt.Fprintf(w, "%s\t%s\t%s\n", t.Id, time.Unix(t.IssuedAt, 0).Format(time.RFC3339), expiresAtFormatted)
}
_ = w.Flush()
}
}
func NewAccountGenerateTokenCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
account string
expiresIn string
)
cmd := &cobra.Command{
Use: "generate-token",
Short: "Generate account token",
Example: `# Generate token for the currently logged in account
argocd account generate-token
# Generate token for the account with the specified name
argocd account generate-token --account <account-name>`,
Run: func(c *cobra.Command, args []string) {
clientset := argocdclient.NewClientOrDie(clientOpts)
conn, client := clientset.NewAccountClientOrDie()
defer util.Close(conn)
if account == "" {
account = getCurrentAccount(clientset).Username
}
expiresIn, err := timeutil.ParseDuration(expiresIn)
errors.CheckError(err)
response, err := client.CreateToken(context.Background(), &accountpkg.CreateTokenRequest{
Name: account,
ExpiresIn: int64(expiresIn.Seconds()),
})
errors.CheckError(err)
fmt.Println(response.Token)
},
}
cmd.Flags().StringVarP(&account, "account", "a", "", "Account name. Defaults to the current account.")
cmd.Flags().StringVarP(&expiresIn, "expires-in", "e", "0s", "Duration before the token will expire. (Default: No expiration)")
return cmd
}
func NewAccountDeleteTokenCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
account string
)
cmd := &cobra.Command{
Use: "delete-token",
Short: "Deletes account token",
Example: `# Delete token of the currently logged in account
argocd account delete-token ID
# Delete token of the account with the specified name
argocd account generate-token --account <account-name>`,
Run: func(c *cobra.Command, args []string) {
if len(args) != 1 {
c.HelpFunc()(c, args)
os.Exit(1)
}
id := args[0]
clientset := argocdclient.NewClientOrDie(clientOpts)
conn, client := clientset.NewAccountClientOrDie()
defer util.Close(conn)
if account == "" {
account = getCurrentAccount(clientset).Username
}
_, err := client.DeleteToken(context.Background(), &accountpkg.DeleteTokenRequest{Name: account, Id: id})
errors.CheckError(err)
},
}
cmd.Flags().StringVarP(&account, "account", "a", "", "Account name. Defaults to the current account.")
return cmd
}

View File

@@ -496,6 +496,8 @@ func setAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap
setHelmOpt(&spec.Source, helmOpts{helmSets: appOpts.helmSets})
case "helm-set-string":
setHelmOpt(&spec.Source, helmOpts{helmSetStrings: appOpts.helmSetStrings})
case "helm-set-file":
setHelmOpt(&spec.Source, helmOpts{helmSetFiles: appOpts.helmSetFiles})
case "directory-recurse":
spec.Source.Directory = &argoappv1.ApplicationSourceDirectory{Recurse: appOpts.directoryRecurse}
case "config-management-plugin":
@@ -523,14 +525,36 @@ func setAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap
case "sync-policy":
switch appOpts.syncPolicy {
case "automated":
spec.SyncPolicy = &argoappv1.SyncPolicy{
Automated: &argoappv1.SyncPolicyAutomated{},
if spec.SyncPolicy == nil {
spec.SyncPolicy = &argoappv1.SyncPolicy{}
}
spec.SyncPolicy.Automated = &argoappv1.SyncPolicyAutomated{}
case "none":
spec.SyncPolicy = nil
if spec.SyncPolicy != nil {
spec.SyncPolicy.Automated = nil
}
if spec.SyncPolicy.IsZero() {
spec.SyncPolicy = nil
}
default:
log.Fatalf("Invalid sync-policy: %s", appOpts.syncPolicy)
}
case "sync-option":
if spec.SyncPolicy == nil {
spec.SyncPolicy = &argoappv1.SyncPolicy{}
}
for _, option := range appOpts.syncOptions {
// `!` means remove the option
if strings.HasPrefix(option, "!") {
option = strings.TrimPrefix(option, "!")
spec.SyncPolicy.SyncOptions = spec.SyncPolicy.SyncOptions.RemoveOption(option)
} else {
spec.SyncPolicy.SyncOptions = spec.SyncPolicy.SyncOptions.AddOption(option)
}
}
if spec.SyncPolicy.IsZero() {
spec.SyncPolicy = nil
}
}
})
if flags.Changed("auto-prune") {
@@ -586,6 +610,7 @@ type helmOpts struct {
releaseName string
helmSets []string
helmSetStrings []string
helmSetFiles []string
}
func setHelmOpt(src *argoappv1.ApplicationSource, opts helmOpts) {
@@ -612,6 +637,13 @@ func setHelmOpt(src *argoappv1.ApplicationSource, opts helmOpts) {
}
src.Helm.AddParameter(*p)
}
for _, text := range opts.helmSetFiles {
p, err := argoappv1.NewHelmFileParameter(text)
if err != nil {
log.Fatal(err)
}
src.Helm.AddFileParameter(*p)
}
if src.Helm.IsZero() {
src.Helm = nil
}
@@ -621,31 +653,8 @@ func setJsonnetOpt(src *argoappv1.ApplicationSource, tlaParameters []string, cod
if src.Directory == nil {
src.Directory = &argoappv1.ApplicationSourceDirectory{}
}
if len(tlaParameters) != 0 {
tlas := make([]argoappv1.JsonnetVar, len(tlaParameters))
for index, paramStr := range tlaParameters {
parts := strings.SplitN(paramStr, "=", 2)
if len(parts) != 2 {
log.Fatalf("Expected parameter of the form: param=value. Received: %s", paramStr)
break
}
tlas[index] = argoappv1.JsonnetVar{
Name: parts[0],
Value: parts[1],
Code: code}
}
var existingTLAs []argoappv1.JsonnetVar
for i := range src.Directory.Jsonnet.TLAs {
if src.Directory.Jsonnet.TLAs[i].Code != code {
existingTLAs = append(existingTLAs, src.Directory.Jsonnet.TLAs[i])
}
}
src.Directory.Jsonnet.TLAs = append(existingTLAs, tlas...)
}
if src.Directory.IsZero() {
src.Directory = nil
for _, j := range tlaParameters {
src.Directory.Jsonnet.TLAs = append(src.Directory.Jsonnet.TLAs, argoappv1.NewJsonnetVar(j, code))
}
}
@@ -672,8 +681,10 @@ type appOptions struct {
releaseName string
helmSets []string
helmSetStrings []string
helmSetFiles []string
project string
syncPolicy string
syncOptions []string
autoPrune bool
selfHeal bool
namePrefix string
@@ -701,8 +712,10 @@ func addAppFlags(command *cobra.Command, opts *appOptions) {
command.Flags().StringVar(&opts.releaseName, "release-name", "", "Helm release-name")
command.Flags().StringArrayVar(&opts.helmSets, "helm-set", []string{}, "Helm set values on the command line (can be repeated to set several values: --helm-set key1=val1 --helm-set key2=val2)")
command.Flags().StringArrayVar(&opts.helmSetStrings, "helm-set-string", []string{}, "Helm set STRING values on the command line (can be repeated to set several values: --helm-set-string key1=val1 --helm-set-string key2=val2)")
command.Flags().StringArrayVar(&opts.helmSetFiles, "helm-set-file", []string{}, "Helm set values from respective files specified via the command line (can be repeated to set several values: --helm-set-file key1=path1 --helm-set-file key2=path2)")
command.Flags().StringVar(&opts.project, "project", "", "Application project name")
command.Flags().StringVar(&opts.syncPolicy, "sync-policy", "", "Set the sync policy (one of: automated, none)")
command.Flags().StringArrayVar(&opts.syncOptions, "sync-option", []string{}, "Add or remove a sync options, e.g add `Prune=false`. Remove using `!` prefix, e.g. `!Prune=false`")
command.Flags().BoolVar(&opts.autoPrune, "auto-prune", false, "Set automatic pruning when sync is automated")
command.Flags().BoolVar(&opts.selfHeal, "self-heal", false, "Set self healing when sync is automated")
command.Flags().StringVar(&opts.namePrefix, "nameprefix", "", "Kustomize nameprefix")

View File

@@ -3,6 +3,7 @@ package commands
import (
"testing"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
@@ -34,4 +35,70 @@ func Test_setHelmOpt(t *testing.T) {
setHelmOpt(&src, helmOpts{helmSetStrings: []string{"foo=bar"}})
assert.Equal(t, []v1alpha1.HelmParameter{{Name: "foo", Value: "bar", ForceString: true}}, src.Helm.Parameters)
})
t.Run("HelmSetFiles", func(t *testing.T) {
src := v1alpha1.ApplicationSource{}
setHelmOpt(&src, helmOpts{helmSetFiles: []string{"foo=bar"}})
assert.Equal(t, []v1alpha1.HelmFileParameter{{Name: "foo", Path: "bar"}}, src.Helm.FileParameters)
})
}
func Test_setJsonnetOpt(t *testing.T) {
t.Run("TlaSets", func(t *testing.T) {
src := v1alpha1.ApplicationSource{}
setJsonnetOpt(&src, []string{"foo=bar"}, false)
assert.Equal(t, []v1alpha1.JsonnetVar{{Name: "foo", Value: "bar"}}, src.Directory.Jsonnet.TLAs)
setJsonnetOpt(&src, []string{"bar=baz"}, false)
assert.Equal(t, []v1alpha1.JsonnetVar{{Name: "foo", Value: "bar"}, {Name: "bar", Value: "baz"}}, src.Directory.Jsonnet.TLAs)
})
t.Run("ExtSets", func(t *testing.T) {
src := v1alpha1.ApplicationSource{}
setJsonnetOptExtVar(&src, []string{"foo=bar"}, false)
assert.Equal(t, []v1alpha1.JsonnetVar{{Name: "foo", Value: "bar"}}, src.Directory.Jsonnet.ExtVars)
setJsonnetOptExtVar(&src, []string{"bar=baz"}, false)
assert.Equal(t, []v1alpha1.JsonnetVar{{Name: "foo", Value: "bar"}, {Name: "bar", Value: "baz"}}, src.Directory.Jsonnet.ExtVars)
})
}
type appOptionsFixture struct {
spec *v1alpha1.ApplicationSpec
command *cobra.Command
options *appOptions
}
func (f *appOptionsFixture) SetFlag(key, value string) error {
err := f.command.Flags().Set(key, value)
if err != nil {
return err
}
_ = setAppSpecOptions(f.command.Flags(), f.spec, f.options)
return err
}
func newAppOptionsFixture() *appOptionsFixture {
fixture := &appOptionsFixture{
spec: &v1alpha1.ApplicationSpec{},
command: &cobra.Command{},
options: &appOptions{},
}
addAppFlags(fixture.command, fixture.options)
return fixture
}
func Test_setAppSpecOptions(t *testing.T) {
f := newAppOptionsFixture()
t.Run("SyncPolicy", func(t *testing.T) {
assert.NoError(t, f.SetFlag("sync-policy", "automated"))
assert.NotNil(t, f.spec.SyncPolicy.Automated)
assert.NoError(t, f.SetFlag("sync-policy", "none"))
assert.Nil(t, f.spec.SyncPolicy)
})
t.Run("SyncOptions", func(t *testing.T) {
assert.NoError(t, f.SetFlag("sync-option", "a=1"))
assert.True(t, f.spec.SyncPolicy.SyncOptions.HasOption("a=1"))
// remove the options using !
assert.NoError(t, f.SetFlag("sync-option", "!a=1"))
assert.Nil(t, f.spec.SyncPolicy)
})
}

View File

@@ -174,18 +174,20 @@ func NewCertAddSSHCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
}
for _, knownHostsEntry := range sshKnownHostsLists {
hostname, certSubType, certData, err := certutil.TokenizeSSHKnownHostsEntry(knownHostsEntry)
_, certSubType, certData, err := certutil.TokenizeSSHKnownHostsEntry(knownHostsEntry)
errors.CheckError(err)
_, _, err = certutil.KnownHostsLineToPublicKey(knownHostsEntry)
hostnameList, _, err := certutil.KnownHostsLineToPublicKey(knownHostsEntry)
errors.CheckError(err)
certificate := appsv1.RepositoryCertificate{
ServerName: hostname,
CertType: "ssh",
CertSubType: certSubType,
CertData: certData,
// Each key could be valid for multiple hostnames
for _, hostname := range hostnameList {
certificate := appsv1.RepositoryCertificate{
ServerName: hostname,
CertType: "ssh",
CertSubType: certSubType,
CertData: certData,
}
certificates = append(certificates, certificate)
}
certificates = append(certificates, certificate)
}
certList := &appsv1.RepositoryCertificateList{Items: certificates}

View File

@@ -60,6 +60,7 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
var (
inCluster bool
upsert bool
serviceAccount string
awsRoleArn string
awsClusterName string
systemNamespace string
@@ -101,7 +102,11 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
// Install RBAC resources for managing the cluster
clientset, err := kubernetes.NewForConfig(conf)
errors.CheckError(err)
managerBearerToken, err = clusterauth.InstallClusterManagerRBAC(clientset, systemNamespace, namespaces)
if serviceAccount != "" {
managerBearerToken, err = clusterauth.GetServiceAccountBearerToken(clientset, systemNamespace, serviceAccount)
} else {
managerBearerToken, err = clusterauth.InstallClusterManagerRBAC(clientset, systemNamespace, namespaces)
}
errors.CheckError(err)
}
conn, clusterIf := argocdclient.NewClientOrDie(clientOpts).NewClusterClientOrDie()
@@ -122,7 +127,8 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
command.PersistentFlags().StringVar(&pathOpts.LoadingRules.ExplicitPath, pathOpts.ExplicitFileFlag, pathOpts.LoadingRules.ExplicitPath, "use a particular kubeconfig file")
command.Flags().BoolVar(&inCluster, "in-cluster", false, "Indicates Argo CD resides inside this cluster and should connect using the internal k8s hostname (kubernetes.default.svc)")
command.Flags().BoolVar(&upsert, "upsert", false, "Override an existing cluster with the same name even if the spec differs")
command.Flags().StringVar(&awsClusterName, "aws-cluster-name", "", "AWS Cluster name if set then aws-iam-authenticator will be used to access cluster")
command.Flags().StringVar(&serviceAccount, "service-account", "", fmt.Sprintf("System namespace service account to use for kubernetes resource management. If not set then default \"%s\" SA will be created", clusterauth.ArgoCDManagerServiceAccount))
command.Flags().StringVar(&awsClusterName, "aws-cluster-name", "", "AWS Cluster name if set then aws cli eks token command will be used to access cluster")
command.Flags().StringVar(&awsRoleArn, "aws-role-arn", "", "Optional AWS role arn. If set then AWS IAM Authenticator assume a role to perform cluster operations instead of the default AWS credential provider chain.")
command.Flags().StringVar(&systemNamespace, "system-namespace", common.DefaultSystemNamespace, "Use different system namespace")
command.Flags().StringArrayVar(&namespaces, "namespace", nil, "List of namespaces which are allowed to manage")

View File

@@ -52,7 +52,10 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
// For better readability and easier formatting
var repoAddExamples = ` # Add a Git repository via SSH using a private key for authentication, ignoring the server's host key:
argocd repo add git@git.example.com:repos/repo --insecure-ignore-host-key --ssh-private-key-path ~/id_rsa
argocd repo add git@git.example.com:repos/repo --insecure-ignore-host-key --ssh-private-key-path ~/id_rsa
# Add a Git repository via SSH on a non-default port - need to use ssh:// style URLs here
argocd repo add ssh://git@git.example.com:2222/repos/repo --ssh-private-key-path ~/id_rsa
# Add a private Git repository via HTTPS using username/password and TLS client certificates:
argocd repo add https://git.example.com/repos/repo --username git --password secret --tls-client-cert-path ~/mycert.crt --tls-client-cert-key-path ~/mycert.key
@@ -174,7 +177,7 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
command.Flags().StringVar(&sshPrivateKeyPath, "ssh-private-key-path", "", "path to the private ssh key (e.g. ~/.ssh/id_rsa)")
command.Flags().StringVar(&tlsClientCertPath, "tls-client-cert-path", "", "path to the TLS client cert (must be PEM format)")
command.Flags().StringVar(&tlsClientCertKeyPath, "tls-client-cert-key-path", "", "path to the TLS client cert's key path (must be PEM format)")
command.Flags().BoolVar(&insecureIgnoreHostKey, "insecure-ignore-host-key", false, "disables SSH strict host key checking (deprecated, use --insecure-skip-server-validation instead)")
command.Flags().BoolVar(&insecureIgnoreHostKey, "insecure-ignore-host-key", false, "disables SSH strict host key checking (deprecated, use --insecure-skip-server-verification instead)")
command.Flags().BoolVar(&insecureSkipServerVerification, "insecure-skip-server-verification", false, "disables server certificate and host key checks")
command.Flags().BoolVar(&enableLfs, "enable-lfs", false, "enable git-lfs (Large File Support) on this repository")
command.Flags().BoolVar(&upsert, "upsert", false, "Override an existing repository with the same name even if the spec differs")

View File

@@ -19,7 +19,7 @@ import (
"github.com/argoproj/argo-cd/util/git"
)
// NewRepoCredsCommand returns a new instance of an `argocd repo` command
// NewRepoCredsCommand returns a new instance of an `argocd repocreds` command
func NewRepoCredsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var command = &cobra.Command{
Use: "repocreds",
@@ -36,7 +36,7 @@ func NewRepoCredsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
return command
}
// NewRepoCredsAddCommand returns a new instance of an `argocd repo add` command
// NewRepoCredsAddCommand returns a new instance of an `argocd repocreds add` command
func NewRepoCredsAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
repo appsv1.RepoCreds
@@ -50,8 +50,8 @@ func NewRepoCredsAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comma
var repocredsAddExamples = ` # Add credentials with user/pass authentication to use for all repositories under https://git.example.com/repos
argocd repocreds add https://git.example.com/repos/ --username git --password secret
# Add credentials with SSH private key authentication to use for all repositories under https://git.example.com/repos
argocd repocreds add https://git.example.com/repos/ --ssh-private-key-path ~/.ssh/id_rsa
# Add credentials with SSH private key authentication to use for all repositories under ssh://git@git.example.com/repos
argocd repocreds add ssh://git@git.example.com/repos/ --ssh-private-key-path ~/.ssh/id_rsa
`
var command = &cobra.Command{
@@ -131,7 +131,7 @@ func NewRepoCredsAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comma
return command
}
// NewRepoCredsRemoveCommand returns a new instance of an `argocd repo list` command
// NewRepoCredsRemoveCommand returns a new instance of an `argocd repocreds rm` command
func NewRepoCredsRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var command = &cobra.Command{
Use: "rm CREDSURL",
@@ -172,7 +172,7 @@ func printRepoCredsUrls(repos []appsv1.RepoCreds) {
}
}
// NewRepoCredsListCommand returns a new instance of an `argocd repo rm` command
// NewRepoCredsListCommand returns a new instance of an `argocd repo list` command
func NewRepoCredsListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
output string

View File

@@ -1,5 +1,11 @@
package common
import (
"os"
"strconv"
"time"
)
// Default service addresses and URLS of Argo CD internal services
const (
// DefaultRepoServerAddr is the gRPC address of the Argo CD repo server
@@ -38,8 +44,6 @@ const (
// Default paths on the pod's file system
const (
// The default base path where application config is located
DefaultPathAppConfig = "/app/config"
// The default path where TLS certificates for repositories are located
DefaultPathTLSConfig = "/app/config/tls"
// The default path where SSH known hosts are stored
@@ -62,10 +66,8 @@ const (
AuthCookieName = "argocd.token"
// RevisionHistoryLimit is the max number of successful sync to keep in history
RevisionHistoryLimit = 10
// K8sClientConfigQPS controls the QPS to be used in K8s REST client configs
K8sClientConfigQPS = 25
// K8sClientConfigBurst controls the burst to be used in K8s REST client configs
K8sClientConfigBurst = 50
// ChangePasswordSSOTokenMaxAge is the max token age for password change operation
ChangePasswordSSOTokenMaxAge = time.Minute * 5
)
// Dex related constants
@@ -138,6 +140,12 @@ const (
EnvGitAttemptsCount = "ARGOCD_GIT_ATTEMPTS_COUNT"
// Overrides git submodule support, true by default
EnvGitSubmoduleEnabled = "ARGOCD_GIT_MODULES_ENABLED"
// EnvK8sClientQPS is the QPS value used for the kubernetes client (default: 50)
EnvK8sClientQPS = "ARGOCD_K8S_CLIENT_QPS"
// EnvK8sClientBurst is the burst value used for the kubernetes client (default: twice the client QPS)
EnvK8sClientBurst = "ARGOCD_K8S_CLIENT_BURST"
// EnvK8sClientMaxIdleConnections is the number of max idle connections in K8s REST client HTTP transport (default: 500)
EnvK8sClientMaxIdleConnections = "ARGOCD_K8S_CLIENT_MAX_IDLE_CONNECTIONS"
)
const (
@@ -149,3 +157,33 @@ const (
// Number should be bumped in case of backward incompatible change to make sure cache is invalidated after upgrade.
CacheVersion = "1.0.0"
)
var (
// K8sClientConfigQPS controls the QPS to be used in K8s REST client configs
K8sClientConfigQPS float32 = 50
// K8sClientConfigBurst controls the burst to be used in K8s REST client configs
K8sClientConfigBurst int = 100
// K8sMaxIdleConnections controls the number of max idle connections in K8s REST client HTTP transport
K8sMaxIdleConnections = 500
)
func init() {
if envQPS := os.Getenv(EnvK8sClientQPS); envQPS != "" {
if qps, err := strconv.ParseFloat(envQPS, 32); err != nil {
K8sClientConfigQPS = float32(qps)
}
}
if envBurst := os.Getenv(EnvK8sClientBurst); envBurst != "" {
if burst, err := strconv.Atoi(envBurst); err != nil {
K8sClientConfigBurst = burst
}
} else {
K8sClientConfigBurst = 2 * int(K8sClientConfigQPS)
}
if envMaxConn := os.Getenv(EnvK8sClientMaxIdleConnections); envMaxConn != "" {
if maxConn, err := strconv.Atoi(envMaxConn); err != nil {
K8sMaxIdleConnections = maxConn
}
}
}

View File

@@ -821,22 +821,20 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
return
}
app := origApp.DeepCopy()
logCtx := log.WithFields(log.Fields{"application": app.Name})
startTime := time.Now()
defer func() {
reconcileDuration := time.Since(startTime)
ctrl.metricsServer.IncReconcile(origApp, reconcileDuration)
logCtx := log.WithFields(log.Fields{
"application": origApp.Name,
"time_ms": reconcileDuration.Seconds() * 1e3,
logCtx.WithFields(log.Fields{
"time_ms": reconcileDuration.Milliseconds(),
"level": comparisonLevel,
"dest-server": origApp.Spec.Destination.Server,
"dest-namespace": origApp.Spec.Destination.Namespace,
})
logCtx.Info("Reconciliation completed")
}).Info("Reconciliation completed")
}()
app := origApp.DeepCopy()
logCtx := log.WithFields(log.Fields{"application": app.Name})
if comparisonLevel == ComparisonWithNothing {
managedResources := make([]*appv1.ResourceDiff, 0)
if err := ctrl.cache.GetAppManagedResources(app.Name, &managedResources); err != nil {
@@ -888,6 +886,9 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
observedAt := metav1.Now()
compareResult := ctrl.appStateManager.CompareAppState(app, project, revision, app.Spec.Source, refreshType == appv1.RefreshTypeHard, localManifests)
for k, v := range compareResult.timings {
logCtx = logCtx.WithField(k, v.Milliseconds())
}
ctrl.normalizeApplication(origApp, app)
@@ -912,7 +913,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
)
}
} else {
logCtx.Infof("Sync prevented by sync window")
logCtx.Info("Sync prevented by sync window")
}
if app.Status.ReconciledAt == nil || comparisonLevel == CompareWithLatest {
@@ -1080,14 +1081,30 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
return nil
}
if !app.Spec.SyncPolicy.Automated.Prune {
requirePruneOnly := true
for _, r := range resources {
if r.Status != appv1.SyncStatusCodeSynced && !r.RequiresPruning {
requirePruneOnly = false
break
}
}
if requirePruneOnly {
logCtx.Infof("Skipping auto-sync: need to prune extra resources only but automated prune is disabled")
return nil
}
}
desiredCommitSHA := syncStatus.Revision
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,
Revision: desiredCommitSHA,
Prune: app.Spec.SyncPolicy.Automated.Prune,
SyncOptions: app.Spec.SyncPolicy.SyncOptions,
},
InitiatedBy: appv1.OperationInitiator{Automated: true},
}
// It is possible for manifests to remain OutOfSync even after a sync/kubectl apply (e.g.
// auto-sync with pruning disabled). We need to ensure that we do not keep Syncing an

View File

@@ -111,7 +111,7 @@ func newFakeController(data *fakeData) *ApplicationController {
ctrl.stateCache = &mockStateCache
mockStateCache.On("IsNamespaced", mock.Anything, mock.Anything).Return(true, nil)
mockStateCache.On("GetManagedLiveObjs", mock.Anything, mock.Anything).Return(data.managedLiveObjs, nil)
mockStateCache.On("GetServerVersion", mock.Anything).Return("v1.2.3", nil)
mockStateCache.On("GetVersionsInfo", mock.Anything).Return("v1.2.3", nil, nil)
response := make(map[kube.ResourceKey]argoappv1.ResourceNode)
for k, v := range data.namespacedResources {
response[k] = v.ResourceNode
@@ -228,7 +228,7 @@ func TestAutoSync(t *testing.T) {
Status: argoappv1.SyncStatusCodeOutOfSync,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
}
cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{})
cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: argoappv1.SyncStatusCodeOutOfSync}})
assert.Nil(t, cond)
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get("my-app", metav1.GetOptions{})
assert.NoError(t, err)
@@ -240,7 +240,7 @@ func TestAutoSync(t *testing.T) {
func TestSkipAutoSync(t *testing.T) {
// Verify we skip when we previously synced to it in our most recent history
// Set current to 'aaaaa', desired to 'aaaa' and mark system OutOfSync
{
t.Run("PreviouslySyncedToRevision", func(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}})
syncStatus := argoappv1.SyncStatus{
@@ -252,10 +252,10 @@ func TestSkipAutoSync(t *testing.T) {
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get("my-app", metav1.GetOptions{})
assert.NoError(t, err)
assert.Nil(t, app.Operation)
}
})
// Verify we skip when we are already Synced (even if revision is different)
{
t.Run("AlreadyInSyncedState", func(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}})
syncStatus := argoappv1.SyncStatus{
@@ -267,10 +267,10 @@ func TestSkipAutoSync(t *testing.T) {
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get("my-app", metav1.GetOptions{})
assert.NoError(t, err)
assert.Nil(t, app.Operation)
}
})
// Verify we skip when auto-sync is disabled
{
t.Run("AutoSyncIsDisabled", func(t *testing.T) {
app := newFakeApp()
app.Spec.SyncPolicy = nil
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}})
@@ -283,10 +283,10 @@ func TestSkipAutoSync(t *testing.T) {
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get("my-app", metav1.GetOptions{})
assert.NoError(t, err)
assert.Nil(t, app.Operation)
}
})
// Verify we skip when application is marked for deletion
{
t.Run("ApplicationIsMarkedForDeletion", func(t *testing.T) {
app := newFakeApp()
now := metav1.Now()
app.DeletionTimestamp = &now
@@ -300,11 +300,11 @@ func TestSkipAutoSync(t *testing.T) {
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get("my-app", metav1.GetOptions{})
assert.NoError(t, err)
assert.Nil(t, app.Operation)
}
})
// Verify we skip when previous sync attempt failed and return error condition
// Set current to 'aaaaa', desired to 'bbbbb' and add 'bbbbb' to failure history
{
t.Run("PreviousSyncAttemptFailed", func(t *testing.T) {
app := newFakeApp()
app.Status.OperationState = &argoappv1.OperationState{
Operation: argoappv1.Operation{
@@ -321,12 +321,28 @@ func TestSkipAutoSync(t *testing.T) {
Status: argoappv1.SyncStatusCodeOutOfSync,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
}
cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{})
cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: argoappv1.SyncStatusCodeOutOfSync}})
assert.NotNil(t, cond)
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get("my-app", metav1.GetOptions{})
assert.NoError(t, err)
assert.Nil(t, app.Operation)
}
})
t.Run("NeedsToPruneResourcesOnlyButAutomatedPruneDisabled", func(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}})
syncStatus := argoappv1.SyncStatus{
Status: argoappv1.SyncStatusCodeOutOfSync,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
}
cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{
{Name: "guestbook", Kind: kube.DeploymentKind, Status: argoappv1.SyncStatusCodeOutOfSync, RequiresPruning: true},
})
assert.Nil(t, cond)
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get("my-app", metav1.GetOptions{})
assert.NoError(t, err)
assert.Nil(t, app.Operation)
})
}
// TestAutoSyncIndicateError verifies we skip auto-sync and return error condition if previous sync failed
@@ -357,7 +373,7 @@ func TestAutoSyncIndicateError(t *testing.T) {
Source: *app.Spec.Source.DeepCopy(),
},
}
cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{})
cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: argoappv1.SyncStatusCodeOutOfSync}})
assert.NotNil(t, cond)
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get("my-app", metav1.GetOptions{})
assert.NoError(t, err)
@@ -400,7 +416,7 @@ func TestAutoSyncParameterOverrides(t *testing.T) {
Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
},
}
cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{})
cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: argoappv1.SyncStatusCodeOutOfSync}})
assert.Nil(t, cond)
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get("my-app", metav1.GetOptions{})
assert.NoError(t, err)

View File

@@ -7,6 +7,7 @@ import (
log "github.com/sirupsen/logrus"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/watch"
@@ -28,7 +29,7 @@ type cacheSettings struct {
type LiveStateCache interface {
// Returns k8s server version
GetServerVersion(serverURL string) (string, error)
GetVersionsInfo(serverURL string) (string, []metav1.APIGroup, error)
// Returns true of given group kind is a namespaced resource
IsNamespaced(server string, gk schema.GroupKind) (bool, error)
// Executes give callback against resource specified by the key and all its children
@@ -70,7 +71,7 @@ func NewLiveStateCache(
appInformer: appInformer,
db: db,
clusters: make(map[string]*clusterInfo),
lock: &sync.Mutex{},
lock: &sync.RWMutex{},
onObjectUpdated: onObjectUpdated,
kubectl: kubectl,
settingsMgr: settingsMgr,
@@ -82,7 +83,7 @@ func NewLiveStateCache(
type liveStateCache struct {
db db.ArgoDB
clusters map[string]*clusterInfo
lock *sync.Mutex
lock *sync.RWMutex
appInformer cache.SharedIndexInformer
onObjectUpdated ObjectUpdatedHandler
kubectl kube.Kubectl
@@ -109,32 +110,47 @@ func (c *liveStateCache) loadCacheSettings() (*cacheSettings, error) {
}
func (c *liveStateCache) getCluster(server string) (*clusterInfo, error) {
c.lock.RLock()
info, ok := c.clusters[server]
c.lock.RUnlock()
if ok {
return info, nil
}
c.lock.Lock()
defer c.lock.Unlock()
info, ok := c.clusters[server]
if !ok {
cluster, err := c.db.GetCluster(context.Background(), server)
if err != nil {
return nil, err
}
info = &clusterInfo{
apisMeta: make(map[schema.GroupKind]*apiMeta),
lock: &sync.Mutex{},
nodes: make(map[kube.ResourceKey]*node),
nsIndex: make(map[string]map[kube.ResourceKey]*node),
onObjectUpdated: c.onObjectUpdated,
kubectl: c.kubectl,
cluster: cluster,
syncTime: nil,
log: log.WithField("server", cluster.Server),
cacheSettingsSrc: c.getCacheSettings,
onEventReceived: func(event watch.EventType, un *unstructured.Unstructured) {
c.metricsServer.IncClusterEventsCount(cluster.Server)
},
}
c.clusters[cluster.Server] = info
info, ok = c.clusters[server]
if ok {
return info, nil
}
logCtx := log.WithField("server", server)
logCtx.Info("initializing cluster")
cluster, err := c.db.GetCluster(context.Background(), server)
if err != nil {
return nil, err
}
info = &clusterInfo{
apisMeta: make(map[schema.GroupKind]*apiMeta),
lock: &sync.RWMutex{},
nodes: make(map[kube.ResourceKey]*node),
nsIndex: make(map[string]map[kube.ResourceKey]*node),
onObjectUpdated: c.onObjectUpdated,
kubectl: c.kubectl,
cluster: cluster,
syncTime: nil,
log: logCtx,
cacheSettingsSrc: c.getCacheSettings,
onEventReceived: func(event watch.EventType, un *unstructured.Unstructured) {
gvk := un.GroupVersionKind()
c.metricsServer.IncClusterEventsCount(cluster.Server, gvk.Group, gvk.Kind)
},
metricsServer: c.metricsServer,
}
c.clusters[cluster.Server] = info
return info, nil
}
@@ -152,8 +168,8 @@ func (c *liveStateCache) getSyncedCluster(server string) (*clusterInfo, error) {
func (c *liveStateCache) Invalidate() {
log.Info("invalidating live state cache")
c.lock.Lock()
defer c.lock.Unlock()
c.lock.RLock()
defer c.lock.RLock()
for _, clust := range c.clusters {
clust.invalidate()
}
@@ -190,14 +206,15 @@ func (c *liveStateCache) GetManagedLiveObjs(a *appv1.Application, targetObjs []*
if err != nil {
return nil, err
}
return clusterInfo.getManagedLiveObjs(a, targetObjs, c.metricsServer)
return clusterInfo.getManagedLiveObjs(a, targetObjs)
}
func (c *liveStateCache) GetServerVersion(serverURL string) (string, error) {
func (c *liveStateCache) GetVersionsInfo(serverURL string) (string, []metav1.APIGroup, error) {
clusterInfo, err := c.getSyncedCluster(serverURL)
if err != nil {
return "", err
return "", nil, err
}
return clusterInfo.serverVersion, nil
return clusterInfo.serverVersion, clusterInfo.apiGroups, nil
}
func isClusterHasApps(apps []interface{}, cluster *appv1.Cluster) bool {
@@ -210,8 +227,6 @@ func isClusterHasApps(apps []interface{}, cluster *appv1.Cluster) bool {
}
func (c *liveStateCache) getCacheSettings() *cacheSettings {
c.cacheSettingsLock.Lock()
defer c.cacheSettingsLock.Unlock()
return c.cacheSettings
}
@@ -261,8 +276,9 @@ func (c *liveStateCache) Run(ctx context.Context) error {
util.RetryUntilSucceed(func() error {
clusterEventCallback := func(event *db.ClusterEvent) {
c.lock.Lock()
defer c.lock.Unlock()
if cluster, ok := c.clusters[event.Cluster.Server]; ok {
cluster, ok := c.clusters[event.Cluster.Server]
if ok {
defer c.lock.Unlock()
if event.Type == watch.Deleted {
cluster.invalidate()
delete(c.clusters, event.Cluster.Server)
@@ -270,11 +286,14 @@ func (c *liveStateCache) Run(ctx context.Context) error {
cluster.cluster = event.Cluster
cluster.invalidate()
}
} else if event.Type == watch.Added && isClusterHasApps(c.appInformer.GetStore().List(), event.Cluster) {
go func() {
// warm up cache for cluster with apps
_, _ = c.getSyncedCluster(event.Cluster.Server)
}()
} else {
c.lock.Unlock()
if event.Type == watch.Added && isClusterHasApps(c.appInformer.GetStore().List(), event.Cluster) {
go func() {
// warm up cache for cluster with apps
_, _ = c.getSyncedCluster(event.Cluster.Server)
}()
}
}
}
@@ -287,8 +306,8 @@ func (c *liveStateCache) Run(ctx context.Context) error {
}
func (c *liveStateCache) GetClustersInfo() []metrics.ClusterInfo {
c.lock.Lock()
defer c.lock.Unlock()
c.lock.RLock()
defer c.lock.RUnlock()
res := make([]metrics.ClusterInfo, 0)
for _, info := range c.clusters {
res = append(res, info.getClusterInfo())

View File

@@ -11,16 +11,16 @@ import (
func TestGetServerVersion(t *testing.T) {
now := time.Now()
cache := &liveStateCache{
lock: &sync.Mutex{},
lock: &sync.RWMutex{},
clusters: map[string]*clusterInfo{
"http://localhost": {
syncTime: &now,
lock: &sync.Mutex{},
lock: &sync.RWMutex{},
serverVersion: "123",
},
}}
version, err := cache.GetServerVersion("http://localhost")
version, _, err := cache.GetVersionsInfo("http://localhost")
assert.NoError(t, err)
assert.Equal(t, "123", version)
}

View File

@@ -9,23 +9,22 @@ import (
"sync"
"time"
"k8s.io/client-go/dynamic"
"k8s.io/apimachinery/pkg/types"
"github.com/argoproj/argo-cd/controller/metrics"
log "github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/dynamic"
"github.com/argoproj/argo-cd/controller/metrics"
appv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/util"
"github.com/argoproj/argo-cd/util/health"
"github.com/argoproj/argo-cd/util/kube"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/pager"
)
const (
@@ -45,8 +44,12 @@ type clusterInfo struct {
syncError error
apisMeta map[schema.GroupKind]*apiMeta
serverVersion string
apiGroups []metav1.APIGroup
// namespacedResources is a simple map which indicates a groupKind is namespaced
namespacedResources map[schema.GroupKind]bool
lock *sync.Mutex
// lock is a rw lock which protects the fields of clusterInfo
lock *sync.RWMutex
nodes map[kube.ResourceKey]*node
nsIndex map[string]map[kube.ResourceKey]*node
@@ -56,16 +59,18 @@ type clusterInfo struct {
cluster *appv1.Cluster
log *log.Entry
cacheSettingsSrc func() *cacheSettings
metricsServer *metrics.MetricsServer
}
func (c *clusterInfo) replaceResourceCache(gk schema.GroupKind, resourceVersion string, objs []unstructured.Unstructured) {
func (c *clusterInfo) replaceResourceCache(gk schema.GroupKind, resourceVersion string, objs []unstructured.Unstructured, ns string) {
info, ok := c.apisMeta[gk]
if ok {
objByKind := make(map[kube.ResourceKey]*unstructured.Unstructured)
objByKey := make(map[kube.ResourceKey]*unstructured.Unstructured)
for i := range objs {
objByKind[kube.GetResourceKey(&objs[i])] = &objs[i]
objByKey[kube.GetResourceKey(&objs[i])] = &objs[i]
}
// update existing nodes
for i := range objs {
obj := &objs[i]
key := kube.GetResourceKey(&objs[i])
@@ -73,12 +78,13 @@ func (c *clusterInfo) replaceResourceCache(gk schema.GroupKind, resourceVersion
c.onNodeUpdated(exists, existingNode, obj, key)
}
// remove existing nodes that a no longer exist
for key, existingNode := range c.nodes {
if key.Kind != gk.Kind || key.Group != gk.Group {
if key.Kind != gk.Kind || key.Group != gk.Group || ns != "" && key.Namespace != ns {
continue
}
if _, ok := objByKind[key]; !ok {
if _, ok := objByKey[key]; !ok {
c.onNodeRemoved(key, existingNode)
}
}
@@ -115,8 +121,9 @@ func isServiceAccountTokenSecret(un *unstructured.Unstructured) (bool, metav1.Ow
func (c *clusterInfo) createObjInfo(un *unstructured.Unstructured, appInstanceLabel string) *node {
ownerRefs := un.GetOwnerReferences()
gvk := un.GroupVersionKind()
// Special case for endpoint. Remove after https://github.com/kubernetes/kubernetes/issues/28483 is fixed
if un.GroupVersionKind().Group == "" && un.GetKind() == kube.EndpointsKind && len(un.GetOwnerReferences()) == 0 {
if gvk.Group == "" && gvk.Kind == kube.EndpointsKind && len(un.GetOwnerReferences()) == 0 {
ownerRefs = append(ownerRefs, metav1.OwnerReference{
Name: un.GetName(),
Kind: kube.ServiceKind,
@@ -140,7 +147,15 @@ func (c *clusterInfo) createObjInfo(un *unstructured.Unstructured, appInstanceLa
if len(ownerRefs) == 0 && appName != "" {
nodeInfo.appName = appName
nodeInfo.resource = un
} else {
// edge case. we do not label CRDs, so they miss the tracking label we inject. But we still
// want the full resource to be available in our cache (to diff), so we store all CRDs
switch gvk.Kind {
case kube.CustomResourceDefinitionKind:
nodeInfo.resource = un
}
}
nodeInfo.health, _ = health.GetResourceHealth(un, c.cacheSettingsSrc().ResourceOverrides)
return nodeInfo
}
@@ -174,26 +189,29 @@ func (c *clusterInfo) invalidate() {
c.apisMeta[i].watchCancel()
}
c.apisMeta = nil
c.namespacedResources = nil
c.log.Warnf("invalidated cluster")
}
func (c *clusterInfo) synced() bool {
if c.syncTime == nil {
syncTime := c.syncTime
if syncTime == nil {
return false
}
if c.syncError != nil {
return time.Now().Before(c.syncTime.Add(clusterRetryTimeout))
return time.Now().Before(syncTime.Add(clusterRetryTimeout))
}
return time.Now().Before(c.syncTime.Add(clusterSyncTimeout))
return time.Now().Before(syncTime.Add(clusterSyncTimeout))
}
func (c *clusterInfo) stopWatching(gk schema.GroupKind) {
func (c *clusterInfo) stopWatching(gk schema.GroupKind, ns string) {
c.lock.Lock()
defer c.lock.Unlock()
if info, ok := c.apisMeta[gk]; ok {
info.watchCancel()
delete(c.apisMeta, gk)
c.replaceResourceCache(gk, "", []unstructured.Unstructured{})
log.Warnf("Stop watching %s not found on %s.", gk, c.cluster.Server)
c.replaceResourceCache(gk, "", []unstructured.Unstructured{}, ns)
c.log.Warnf("Stop watching: %s not found", gk)
}
}
@@ -209,16 +227,17 @@ func (c *clusterInfo) startMissingWatches() error {
if err != nil {
return err
}
namespacedResources := make(map[schema.GroupKind]bool)
for i := range apis {
api := apis[i]
namespacedResources[api.GroupKind] = api.Meta.Namespaced
if _, ok := c.apisMeta[api.GroupKind]; !ok {
ctx, cancel := context.WithCancel(context.Background())
info := &apiMeta{namespaced: api.Meta.Namespaced, watchCancel: cancel}
c.apisMeta[api.GroupKind] = info
err = c.processApi(client, api, func(resClient dynamic.ResourceInterface) error {
go c.watchEvents(ctx, api, info, resClient)
err = c.processApi(client, api, func(resClient dynamic.ResourceInterface, ns string) error {
go c.watchEvents(ctx, api, info, resClient, ns)
return nil
})
if err != nil {
@@ -226,16 +245,17 @@ func (c *clusterInfo) startMissingWatches() error {
}
}
}
c.namespacedResources = namespacedResources
return nil
}
func runSynced(lock *sync.Mutex, action func() error) error {
func runSynced(lock sync.Locker, action func() error) error {
lock.Lock()
defer lock.Unlock()
return action()
}
func (c *clusterInfo) watchEvents(ctx context.Context, api kube.APIResourceInfo, info *apiMeta, resClient dynamic.ResourceInterface) {
func (c *clusterInfo) watchEvents(ctx context.Context, api kube.APIResourceInfo, info *apiMeta, resClient dynamic.ResourceInterface, ns string) {
util.RetryUntilSucceed(func() (err error) {
defer func() {
if r := recover(); r != nil {
@@ -245,11 +265,26 @@ func (c *clusterInfo) watchEvents(ctx context.Context, api kube.APIResourceInfo,
err = runSynced(c.lock, func() error {
if info.resourceVersion == "" {
list, err := resClient.List(metav1.ListOptions{})
listPager := pager.New(func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
res, err := resClient.List(opts)
if err == nil {
info.resourceVersion = res.GetResourceVersion()
}
return res, err
})
var items []unstructured.Unstructured
err = listPager.EachListItem(ctx, metav1.ListOptions{}, func(obj runtime.Object) error {
if un, ok := obj.(*unstructured.Unstructured); !ok {
return fmt.Errorf("object %s/%s has an unexpected type", un.GroupVersionKind().String(), un.GetName())
} else {
items = append(items, *un)
}
return nil
})
if err != nil {
return err
return fmt.Errorf("failed to load initial state of resource %s: %v", api.GroupKind.String(), err)
}
c.replaceResourceCache(api.GroupKind, list.GetResourceVersion(), list.Items)
c.replaceResourceCache(api.GroupKind, info.resourceVersion, items, ns)
}
return nil
})
@@ -260,18 +295,13 @@ func (c *clusterInfo) watchEvents(ctx context.Context, api kube.APIResourceInfo,
w, err := resClient.Watch(metav1.ListOptions{ResourceVersion: info.resourceVersion})
if errors.IsNotFound(err) {
c.stopWatching(api.GroupKind)
c.stopWatching(api.GroupKind, ns)
return nil
}
err = runSynced(c.lock, func() error {
if errors.IsGone(err) {
info.resourceVersion = ""
log.Warnf("Resource version of %s on %s is too old.", api.GroupKind, c.cluster.Server)
}
return err
})
if errors.IsGone(err) {
info.resourceVersion = ""
c.log.Warnf("Resource version of %s is too old", api.GroupKind)
}
if err != nil {
return err
}
@@ -292,7 +322,7 @@ func (c *clusterInfo) watchEvents(ctx context.Context, api kube.APIResourceInfo,
if groupOk && groupErr == nil && kindOk && kindErr == nil {
gk := schema.GroupKind{Group: group, Kind: kind}
c.stopWatching(gk)
c.stopWatching(gk, ns)
}
} else {
err = runSynced(c.lock, func() error {
@@ -302,7 +332,7 @@ func (c *clusterInfo) watchEvents(ctx context.Context, api kube.APIResourceInfo,
}
}
if err != nil {
log.Warnf("Failed to start missing watch: %v", err)
c.log.Warnf("Failed to start missing watch: %v", err)
}
} else {
return fmt.Errorf("Watch %s on %s has closed", api.GroupKind, c.cluster.Server)
@@ -313,10 +343,10 @@ func (c *clusterInfo) watchEvents(ctx context.Context, api kube.APIResourceInfo,
}, fmt.Sprintf("watch %s on %s", api.GroupKind, c.cluster.Server), ctx, watchResourcesRetryTimeout)
}
func (c *clusterInfo) processApi(client dynamic.Interface, api kube.APIResourceInfo, callback func(resClient dynamic.ResourceInterface) error) error {
func (c *clusterInfo) processApi(client dynamic.Interface, api kube.APIResourceInfo, callback func(resClient dynamic.ResourceInterface, ns string) error) error {
resClient := client.Resource(api.GroupVersionResource)
if len(c.cluster.Namespaces) == 0 {
return callback(resClient)
return callback(resClient, "")
}
if !api.Meta.Namespaced {
@@ -324,7 +354,7 @@ func (c *clusterInfo) processApi(client dynamic.Interface, api kube.APIResourceI
}
for _, ns := range c.cluster.Namespaces {
err := callback(resClient.Namespace(ns))
err := callback(resClient.Namespace(ns), ns)
if err != nil {
return err
}
@@ -341,12 +371,19 @@ func (c *clusterInfo) sync() (err error) {
}
c.apisMeta = make(map[schema.GroupKind]*apiMeta)
c.nodes = make(map[kube.ResourceKey]*node)
c.namespacedResources = make(map[schema.GroupKind]bool)
config := c.cluster.RESTConfig()
version, err := c.kubectl.GetServerVersion(config)
if err != nil {
return err
}
c.serverVersion = version
groups, err := c.kubectl.GetAPIGroups(config)
if err != nil {
return err
}
c.apiGroups = groups
apis, err := c.kubectl.GetAPIResources(config, c.cacheSettingsSrc().ResourcesFilter)
if err != nil {
return err
@@ -357,25 +394,47 @@ func (c *clusterInfo) sync() (err error) {
}
lock := sync.Mutex{}
err = util.RunAllAsync(len(apis), func(i int) error {
return c.processApi(client, apis[i], func(resClient dynamic.ResourceInterface) error {
list, err := resClient.List(metav1.ListOptions{})
api := apis[i]
lock.Lock()
ctx, cancel := context.WithCancel(context.Background())
info := &apiMeta{namespaced: api.Meta.Namespaced, watchCancel: cancel}
c.apisMeta[api.GroupKind] = info
c.namespacedResources[api.GroupKind] = api.Meta.Namespaced
lock.Unlock()
return c.processApi(client, api, func(resClient dynamic.ResourceInterface, ns string) error {
listPager := pager.New(func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
res, err := resClient.List(opts)
if err == nil {
lock.Lock()
info.resourceVersion = res.GetResourceVersion()
lock.Unlock()
}
return res, err
})
err = listPager.EachListItem(context.Background(), metav1.ListOptions{}, func(obj runtime.Object) error {
if un, ok := obj.(*unstructured.Unstructured); !ok {
return fmt.Errorf("object %s/%s has an unexpected type", un.GroupVersionKind().String(), un.GetName())
} else {
lock.Lock()
c.setNode(c.createObjInfo(un, c.cacheSettingsSrc().AppInstanceLabelKey))
lock.Unlock()
}
return nil
})
if err != nil {
return err
return fmt.Errorf("failed to load initial state of resource %s: %v", api.GroupKind.String(), err)
}
lock.Lock()
for i := range list.Items {
c.setNode(c.createObjInfo(&list.Items[i], c.cacheSettingsSrc().AppInstanceLabelKey))
}
lock.Unlock()
go c.watchEvents(ctx, api, info, resClient, ns)
return nil
})
})
if err == nil {
err = c.startMissingWatches()
}
if err != nil {
log.Errorf("Failed to sync cluster %s: %v", c.cluster.Server, err)
return err
@@ -386,12 +445,17 @@ func (c *clusterInfo) sync() (err error) {
}
func (c *clusterInfo) ensureSynced() error {
c.lock.Lock()
defer c.lock.Unlock()
// first check if cluster is synced *without lock*
if c.synced() {
return c.syncError
}
c.lock.Lock()
defer c.lock.Unlock()
// before doing any work, check once again now that we have the lock, to see if it got
// synced between the first check and now
if c.synced() {
return c.syncError
}
err := c.sync()
syncTime := time.Now()
c.syncTime = &syncTime
@@ -400,8 +464,8 @@ func (c *clusterInfo) ensureSynced() error {
}
func (c *clusterInfo) getNamespaceTopLevelResources(namespace string) map[kube.ResourceKey]appv1.ResourceNode {
c.lock.Lock()
defer c.lock.Unlock()
c.lock.RLock()
defer c.lock.RUnlock()
nodes := make(map[kube.ResourceKey]appv1.ResourceNode)
for _, node := range c.nsIndex[namespace] {
if len(node.ownerRefs) == 0 {
@@ -442,15 +506,17 @@ func (c *clusterInfo) iterateHierarchy(key kube.ResourceKey, action func(child a
}
func (c *clusterInfo) isNamespaced(gk schema.GroupKind) bool {
if api, ok := c.apisMeta[gk]; ok && !api.namespaced {
return false
// this is safe to access without a lock since we always replace the entire map instead of mutating keys
if isNamespaced, ok := c.namespacedResources[gk]; ok {
return isNamespaced
}
log.Warnf("group/kind %s scope is unknown (known objects: %d). assuming namespaced object", gk, len(c.namespacedResources))
return true
}
func (c *clusterInfo) getManagedLiveObjs(a *appv1.Application, targetObjs []*unstructured.Unstructured, metricsServer *metrics.MetricsServer) (map[kube.ResourceKey]*unstructured.Unstructured, error) {
c.lock.Lock()
defer c.lock.Unlock()
func (c *clusterInfo) getManagedLiveObjs(a *appv1.Application, targetObjs []*unstructured.Unstructured) (map[kube.ResourceKey]*unstructured.Unstructured, error) {
c.lock.RLock()
defer c.lock.RUnlock()
managedObjs := make(map[kube.ResourceKey]*unstructured.Unstructured)
// iterate all objects in live state cache to find ones associated with app
@@ -459,8 +525,8 @@ func (c *clusterInfo) getManagedLiveObjs(a *appv1.Application, targetObjs []*uns
managedObjs[key] = o.resource
}
}
config := metrics.AddMetricsTransportWrapper(metricsServer, a, c.cluster.RESTConfig())
// iterate target objects and identify ones that already exist in the cluster,\
config := metrics.AddMetricsTransportWrapper(c.metricsServer, a, c.cluster.RESTConfig())
// iterate target objects and identify ones that already exist in the cluster,
// but are simply missing our label
lock := &sync.Mutex{}
err := util.RunAllAsync(len(targetObjs), func(i int) error {
@@ -528,9 +594,12 @@ func (c *clusterInfo) processEvent(event watch.EventType, un *unstructured.Unstr
if c.onEventReceived != nil {
c.onEventReceived(event, un)
}
key := kube.GetResourceKey(un)
if event == watch.Modified && skipAppRequeing(key) {
return
}
c.lock.Lock()
defer c.lock.Unlock()
key := kube.GetResourceKey(un)
existingNode, exists := c.nodes[key]
if event == watch.Deleted {
if exists {
@@ -554,7 +623,7 @@ func (c *clusterInfo) onNodeUpdated(exists bool, existingNode *node, un *unstruc
n := nodes[i]
if ns, ok := c.nsIndex[n.ref.Namespace]; ok {
app := n.getApp(ns)
if app == "" || skipAppRequeing(key) {
if app == "" {
continue
}
toNotify[app] = n.isRootAppNode() || toNotify[app]
@@ -584,8 +653,8 @@ var (
)
func (c *clusterInfo) getClusterInfo() metrics.ClusterInfo {
c.lock.Lock()
defer c.lock.Unlock()
c.lock.RLock()
defer c.lock.RUnlock()
return metrics.ClusterInfo{
APIsCount: len(c.apisMeta),
K8SVersion: c.serverVersion,

View File

@@ -153,7 +153,7 @@ func newCluster(objs ...*unstructured.Unstructured) *clusterInfo {
func newClusterExt(kubectl kube.Kubectl) *clusterInfo {
return &clusterInfo{
lock: &sync.Mutex{},
lock: &sync.RWMutex{},
nodes: make(map[kube.ResourceKey]*node),
onObjectUpdated: func(managedByApp map[string]bool, reference corev1.ObjectReference) {},
kubectl: kubectl,
@@ -322,7 +322,7 @@ metadata:
Namespace: "default",
},
},
}, []*unstructured.Unstructured{targetDeploy}, nil)
}, []*unstructured.Unstructured{targetDeploy})
assert.Nil(t, err)
assert.Equal(t, managedObjs, map[kube.ResourceKey]*unstructured.Unstructured{
kube.NewResourceKey("apps", "Deployment", "default", "helm-guestbook"): testDeploy,
@@ -504,7 +504,7 @@ func TestWatchCacheUpdated(t *testing.T) {
podGroupKind := testPod.GroupVersionKind().GroupKind()
cluster.replaceResourceCache(podGroupKind, "updated-list-version", []unstructured.Unstructured{*updated, *added})
cluster.replaceResourceCache(podGroupKind, "updated-list-version", []unstructured.Unstructured{*updated, *added}, "")
_, ok := cluster.nodes[kube.GetResourceKey(removed)]
assert.False(t, ok)
@@ -517,6 +517,28 @@ func TestWatchCacheUpdated(t *testing.T) {
assert.True(t, ok)
}
func TestNamespaceModeReplace(t *testing.T) {
ns1Pod := testPod.DeepCopy()
ns1Pod.SetNamespace("ns1")
ns1Pod.SetName("pod1")
ns2Pod := testPod.DeepCopy()
ns2Pod.SetNamespace("ns2")
podGroupKind := testPod.GroupVersionKind().GroupKind()
cluster := newCluster(ns1Pod, ns2Pod)
err := cluster.ensureSynced()
assert.Nil(t, err)
cluster.replaceResourceCache(podGroupKind, "", nil, "ns1")
_, ok := cluster.nodes[kube.GetResourceKey(ns1Pod)]
assert.False(t, ok)
_, ok = cluster.nodes[kube.GetResourceKey(ns2Pod)]
assert.True(t, ok)
}
func TestGetDuplicatedChildren(t *testing.T) {
extensionsRS := testRS.DeepCopy()
extensionsRS.SetGroupVersionKind(schema.GroupVersionKind{Group: "extensions", Kind: kube.ReplicaSetKind, Version: "v1beta1"})

View File

@@ -14,6 +14,8 @@ import (
unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
)
@@ -84,8 +86,8 @@ func (_m *LiveStateCache) GetNamespaceTopLevelResources(server string, namespace
return r0, r1
}
// GetServerVersion provides a mock function with given fields: serverURL
func (_m *LiveStateCache) GetServerVersion(serverURL string) (string, error) {
// GetVersionsInfo provides a mock function with given fields: serverURL
func (_m *LiveStateCache) GetVersionsInfo(serverURL string) (string, []v1.APIGroup, error) {
ret := _m.Called(serverURL)
var r0 string
@@ -95,14 +97,23 @@ func (_m *LiveStateCache) GetServerVersion(serverURL string) (string, error) {
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
var r1 []v1.APIGroup
if rf, ok := ret.Get(1).(func(string) []v1.APIGroup); ok {
r1 = rf(serverURL)
} else {
r1 = ret.Error(1)
if ret.Get(1) != nil {
r1 = ret.Get(1).([]v1.APIGroup)
}
}
return r0, r1
var r2 error
if rf, ok := ret.Get(2).(func(string) error); ok {
r2 = rf(serverURL)
} else {
r2 = ret.Error(2)
}
return r0, r1, r2
}
// Invalidate provides a mock function with given fields:

View File

@@ -3,7 +3,7 @@ package metrics
import (
"context"
"net/http"
"strconv"
"os"
"time"
"github.com/prometheus/client_golang/prometheus"
@@ -31,6 +31,8 @@ type MetricsServer struct {
const (
// MetricsPath is the endpoint to collect application metrics
MetricsPath = "/metrics"
// EnvVarLegacyControllerMetrics is a env var to re-enable deprecated prometheus metrics
EnvVarLegacyControllerMetrics = "ARGOCD_LEGACY_CONTROLLER_METRICS"
)
// Follow Prometheus naming practices
@@ -41,27 +43,71 @@ var (
descAppInfo = prometheus.NewDesc(
"argocd_app_info",
"Information about application.",
append(descAppDefaultLabels, "repo", "dest_server", "dest_namespace"),
append(descAppDefaultLabels, "repo", "dest_server", "dest_namespace", "sync_status", "health_status", "operation"),
nil,
)
// DEPRECATED
descAppCreated = prometheus.NewDesc(
"argocd_app_created_time",
"Creation time in unix timestamp for an application.",
descAppDefaultLabels,
nil,
)
// DEPRECATED: superceded by sync_status label in argocd_app_info
descAppSyncStatusCode = prometheus.NewDesc(
"argocd_app_sync_status",
"The application current sync status.",
append(descAppDefaultLabels, "sync_status"),
nil,
)
// DEPRECATED: superceded by health_status label in argocd_app_info
descAppHealthStatus = prometheus.NewDesc(
"argocd_app_health_status",
"The application current health status.",
append(descAppDefaultLabels, "health_status"),
nil,
)
syncCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "argocd_app_sync_total",
Help: "Number of application syncs.",
},
append(descAppDefaultLabels, "dest_server", "phase"),
)
k8sRequestCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "argocd_app_k8s_request_total",
Help: "Number of kubernetes requests executed during application reconciliation.",
},
append(descAppDefaultLabels, "server", "response_code", "verb", "resource_kind", "resource_namespace"),
)
kubectlExecCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "argocd_kubectl_exec_total",
Help: "Number of kubectl executions",
}, []string{"command"})
kubectlExecPendingGauge = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "argocd_kubectl_exec_pending",
Help: "Number of pending kubectl executions",
}, []string{"command"})
reconcileHistogram = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "argocd_app_reconcile",
Help: "Application reconciliation performance.",
// Buckets chosen after observing a ~2100ms mean reconcile time
Buckets: []float64{0.25, .5, 1, 2, 4, 8, 16},
},
[]string{"namespace", "dest_server"},
)
clusterEventsCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "argocd_cluster_events_total",
Help: "Number of processes k8s resource events.",
}, append(descClusterDefaultLabels, "group", "kind"))
)
// NewMetricsServer returns a new prometheus server which collects application metrics
@@ -76,50 +122,11 @@ func NewMetricsServer(addr string, appLister applister.ApplicationLister, health
}, promhttp.HandlerOpts{}))
healthz.ServeHealthCheck(mux, healthCheck)
syncCounter := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "argocd_app_sync_total",
Help: "Number of application syncs.",
},
append(descAppDefaultLabels, "phase"),
)
registry.MustRegister(syncCounter)
k8sRequestCounter := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "argocd_app_k8s_request_total",
Help: "Number of kubernetes requests executed during application reconciliation.",
},
append(descAppDefaultLabels, "response_code"),
)
registry.MustRegister(k8sRequestCounter)
kubectlExecCounter := prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "argocd_kubectl_exec_total",
Help: "Number of kubectl executions",
}, []string{"command"})
registry.MustRegister(kubectlExecCounter)
kubectlExecPendingGauge := prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "argocd_kubectl_exec_pending_total",
Help: "Number of pending kubectl executions",
}, []string{"command"})
registry.MustRegister(kubectlExecPendingGauge)
reconcileHistogram := prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "argocd_app_reconcile",
Help: "Application reconciliation performance.",
// Buckets chosen after observing a ~2100ms mean reconcile time
Buckets: []float64{0.25, .5, 1, 2, 4, 8, 16},
},
descAppDefaultLabels,
)
registry.MustRegister(reconcileHistogram)
clusterEventsCounter := prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "argocd_cluster_events_total",
Help: "Number of processes k8s resource events.",
}, descClusterDefaultLabels)
registry.MustRegister(clusterEventsCounter)
return &MetricsServer{
@@ -148,7 +155,7 @@ func (m *MetricsServer) IncSync(app *argoappv1.Application, state *argoappv1.Ope
if !state.Phase.Completed() {
return
}
m.syncCounter.WithLabelValues(app.Namespace, app.Name, app.Spec.GetProject(), string(state.Phase)).Inc()
m.syncCounter.WithLabelValues(app.Namespace, app.Name, app.Spec.GetProject(), app.Spec.Destination.Server, string(state.Phase)).Inc()
}
func (m *MetricsServer) IncKubectlExec(command string) {
@@ -164,18 +171,27 @@ func (m *MetricsServer) DecKubectlExecPending(command string) {
}
// IncClusterEventsCount increments the number of cluster events
func (m *MetricsServer) IncClusterEventsCount(server string) {
m.clusterEventsCounter.WithLabelValues(server).Inc()
func (m *MetricsServer) IncClusterEventsCount(server, group, kind string) {
m.clusterEventsCounter.WithLabelValues(server, group, kind).Inc()
}
// IncKubernetesRequest increments the kubernetes requests counter for an application
func (m *MetricsServer) IncKubernetesRequest(app *argoappv1.Application, statusCode int) {
m.k8sRequestCounter.WithLabelValues(app.Namespace, app.Name, app.Spec.GetProject(), strconv.Itoa(statusCode)).Inc()
func (m *MetricsServer) IncKubernetesRequest(app *argoappv1.Application, server, statusCode, verb, resourceKind, resourceNamespace string) {
var namespace, name, project string
if app != nil {
namespace = app.Namespace
name = app.Name
project = app.Spec.GetProject()
}
m.k8sRequestCounter.WithLabelValues(
namespace, name, project, server, statusCode,
verb, resourceKind, resourceNamespace,
).Inc()
}
// IncReconcile increments the reconcile counter for an application
func (m *MetricsServer) IncReconcile(app *argoappv1.Application, duration time.Duration) {
m.reconcileHistogram.WithLabelValues(app.Namespace, app.Name, app.Spec.GetProject()).Observe(duration.Seconds())
m.reconcileHistogram.WithLabelValues(app.Namespace, app.Spec.Destination.Server).Observe(duration.Seconds())
}
type appCollector struct {
@@ -199,7 +215,6 @@ func NewAppRegistry(appLister applister.ApplicationLister) *prometheus.Registry
// Describe implements the prometheus.Collector interface
func (c *appCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- descAppInfo
ch <- descAppCreated
ch <- descAppSyncStatusCode
ch <- descAppHealthStatus
}
@@ -233,20 +248,36 @@ func collectApps(ch chan<- prometheus.Metric, app *argoappv1.Application) {
addConstMetric(desc, prometheus.GaugeValue, v, lv...)
}
addGauge(descAppInfo, 1, git.NormalizeGitURL(app.Spec.Source.RepoURL), app.Spec.Destination.Server, app.Spec.Destination.Namespace)
addGauge(descAppCreated, float64(app.CreationTimestamp.Unix()))
var operation string
if app.DeletionTimestamp != nil {
operation = "delete"
} else if app.Operation != nil && app.Operation.Sync != nil {
operation = "sync"
}
syncStatus := app.Status.Sync.Status
addGauge(descAppSyncStatusCode, boolFloat64(syncStatus == argoappv1.SyncStatusCodeSynced), string(argoappv1.SyncStatusCodeSynced))
addGauge(descAppSyncStatusCode, boolFloat64(syncStatus == argoappv1.SyncStatusCodeOutOfSync), string(argoappv1.SyncStatusCodeOutOfSync))
addGauge(descAppSyncStatusCode, boolFloat64(syncStatus == argoappv1.SyncStatusCodeUnknown || syncStatus == ""), string(argoappv1.SyncStatusCodeUnknown))
if syncStatus == "" {
syncStatus = argoappv1.SyncStatusCodeUnknown
}
healthStatus := app.Status.Health.Status
addGauge(descAppHealthStatus, boolFloat64(healthStatus == argoappv1.HealthStatusUnknown || healthStatus == ""), argoappv1.HealthStatusUnknown)
addGauge(descAppHealthStatus, boolFloat64(healthStatus == argoappv1.HealthStatusProgressing), argoappv1.HealthStatusProgressing)
addGauge(descAppHealthStatus, boolFloat64(healthStatus == argoappv1.HealthStatusSuspended), argoappv1.HealthStatusSuspended)
addGauge(descAppHealthStatus, boolFloat64(healthStatus == argoappv1.HealthStatusHealthy), argoappv1.HealthStatusHealthy)
addGauge(descAppHealthStatus, boolFloat64(healthStatus == argoappv1.HealthStatusDegraded), argoappv1.HealthStatusDegraded)
addGauge(descAppHealthStatus, boolFloat64(healthStatus == argoappv1.HealthStatusMissing), argoappv1.HealthStatusMissing)
if healthStatus == "" {
healthStatus = argoappv1.HealthStatusUnknown
}
addGauge(descAppInfo, 1, git.NormalizeGitURL(app.Spec.Source.RepoURL), app.Spec.Destination.Server, app.Spec.Destination.Namespace, string(syncStatus), healthStatus, operation)
// Deprecated controller metrics
if os.Getenv(EnvVarLegacyControllerMetrics) == "true" {
addGauge(descAppCreated, float64(app.CreationTimestamp.Unix()))
addGauge(descAppSyncStatusCode, boolFloat64(syncStatus == argoappv1.SyncStatusCodeSynced), string(argoappv1.SyncStatusCodeSynced))
addGauge(descAppSyncStatusCode, boolFloat64(syncStatus == argoappv1.SyncStatusCodeOutOfSync), string(argoappv1.SyncStatusCodeOutOfSync))
addGauge(descAppSyncStatusCode, boolFloat64(syncStatus == argoappv1.SyncStatusCodeUnknown || syncStatus == ""), string(argoappv1.SyncStatusCodeUnknown))
addGauge(descAppHealthStatus, boolFloat64(healthStatus == argoappv1.HealthStatusUnknown || healthStatus == ""), argoappv1.HealthStatusUnknown)
addGauge(descAppHealthStatus, boolFloat64(healthStatus == argoappv1.HealthStatusProgressing), argoappv1.HealthStatusProgressing)
addGauge(descAppHealthStatus, boolFloat64(healthStatus == argoappv1.HealthStatusSuspended), argoappv1.HealthStatusSuspended)
addGauge(descAppHealthStatus, boolFloat64(healthStatus == argoappv1.HealthStatusHealthy), argoappv1.HealthStatusHealthy)
addGauge(descAppHealthStatus, boolFloat64(healthStatus == argoappv1.HealthStatusDegraded), argoappv1.HealthStatusDegraded)
addGauge(descAppHealthStatus, boolFloat64(healthStatus == argoappv1.HealthStatusMissing), argoappv1.HealthStatusMissing)
}
}

View File

@@ -5,6 +5,7 @@ import (
"log"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"time"
@@ -42,25 +43,52 @@ status:
status: Healthy
`
const expectedResponse = `# HELP argocd_app_created_time Creation time in unix timestamp for an application.
# TYPE argocd_app_created_time gauge
argocd_app_created_time{name="my-app",namespace="argocd",project="important-project"} -6.21355968e+10
# HELP argocd_app_health_status The application current health status.
# TYPE argocd_app_health_status gauge
argocd_app_health_status{health_status="Degraded",name="my-app",namespace="argocd",project="important-project"} 0
argocd_app_health_status{health_status="Healthy",name="my-app",namespace="argocd",project="important-project"} 1
argocd_app_health_status{health_status="Missing",name="my-app",namespace="argocd",project="important-project"} 0
argocd_app_health_status{health_status="Progressing",name="my-app",namespace="argocd",project="important-project"} 0
argocd_app_health_status{health_status="Suspended",name="my-app",namespace="argocd",project="important-project"} 0
argocd_app_health_status{health_status="Unknown",name="my-app",namespace="argocd",project="important-project"} 0
# HELP argocd_app_info Information about application.
# TYPE argocd_app_info gauge
argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:6443",name="my-app",namespace="argocd",project="important-project",repo="https://github.com/argoproj/argocd-example-apps"} 1
# HELP argocd_app_sync_status The application current sync status.
# TYPE argocd_app_sync_status gauge
argocd_app_sync_status{name="my-app",namespace="argocd",project="important-project",sync_status="OutOfSync"} 0
argocd_app_sync_status{name="my-app",namespace="argocd",project="important-project",sync_status="Synced"} 1
argocd_app_sync_status{name="my-app",namespace="argocd",project="important-project",sync_status="Unknown"} 0
const fakeApp2 = `
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app-2
namespace: argocd
spec:
destination:
namespace: dummy-namespace
server: https://localhost:6443
project: important-project
source:
path: some/path
repoURL: https://github.com/argoproj/argocd-example-apps.git
status:
sync:
status: Synced
health:
status: Healthy
operation:
sync:
revision: 041eab7439ece92c99b043f0e171788185b8fc1d
syncStrategy:
hook: {}
`
const fakeApp3 = `
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app-3
namespace: argocd
deletionTimestamp: "2020-03-16T09:17:45Z"
spec:
destination:
namespace: dummy-namespace
server: https://localhost:6443
project: important-project
source:
path: some/path
repoURL: https://github.com/argoproj/argocd-example-apps.git
status:
sync:
status: OutOfSync
health:
status: Degraded
`
const fakeDefaultApp = `
@@ -83,46 +111,26 @@ status:
status: Healthy
`
const expectedDefaultResponse = `# HELP argocd_app_created_time Creation time in unix timestamp for an application.
# TYPE argocd_app_created_time gauge
argocd_app_created_time{name="my-app",namespace="argocd",project="default"} -6.21355968e+10
# HELP argocd_app_health_status The application current health status.
# TYPE argocd_app_health_status gauge
argocd_app_health_status{health_status="Degraded",name="my-app",namespace="argocd",project="default"} 0
argocd_app_health_status{health_status="Healthy",name="my-app",namespace="argocd",project="default"} 1
argocd_app_health_status{health_status="Missing",name="my-app",namespace="argocd",project="default"} 0
argocd_app_health_status{health_status="Progressing",name="my-app",namespace="argocd",project="default"} 0
argocd_app_health_status{health_status="Suspended",name="my-app",namespace="argocd",project="default"} 0
argocd_app_health_status{health_status="Unknown",name="my-app",namespace="argocd",project="default"} 0
# HELP argocd_app_info Information about application.
# TYPE argocd_app_info gauge
argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:6443",name="my-app",namespace="argocd",project="default",repo="https://github.com/argoproj/argocd-example-apps"} 1
# HELP argocd_app_sync_status The application current sync status.
# TYPE argocd_app_sync_status gauge
argocd_app_sync_status{name="my-app",namespace="argocd",project="default",sync_status="OutOfSync"} 0
argocd_app_sync_status{name="my-app",namespace="argocd",project="default",sync_status="Synced"} 1
argocd_app_sync_status{name="my-app",namespace="argocd",project="default",sync_status="Unknown"} 0
`
var noOpHealthCheck = func() error {
return nil
}
func newFakeApp(fakeApp string) *argoappv1.Application {
func newFakeApp(fakeAppYAML string) *argoappv1.Application {
var app argoappv1.Application
err := yaml.Unmarshal([]byte(fakeApp), &app)
err := yaml.Unmarshal([]byte(fakeAppYAML), &app)
if err != nil {
panic(err)
}
return &app
}
func newFakeLister(fakeApp ...string) (context.CancelFunc, applister.ApplicationLister) {
func newFakeLister(fakeAppYAMLs ...string) (context.CancelFunc, applister.ApplicationLister) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var fakeApps []runtime.Object
for _, name := range fakeApp {
fakeApps = append(fakeApps, newFakeApp(name))
for _, appYAML := range fakeAppYAMLs {
a := newFakeApp(appYAML)
fakeApps = append(fakeApps, a)
}
appClientset := appclientset.NewSimpleClientset(fakeApps...)
factory := appinformer.NewFilteredSharedInformerFactory(appClientset, 0, "argocd", func(options *metav1.ListOptions) {})
@@ -134,8 +142,8 @@ func newFakeLister(fakeApp ...string) (context.CancelFunc, applister.Application
return cancel, factory.Argoproj().V1alpha1().Applications().Lister()
}
func testApp(t *testing.T, fakeApp string, expectedResponse string) {
cancel, appLister := newFakeLister(fakeApp)
func testApp(t *testing.T, fakeAppYAMLs []string, expectedResponse string) {
cancel, appLister := newFakeLister(fakeAppYAMLs...)
defer cancel()
metricsServ := NewMetricsServer("localhost:8082", appLister, noOpHealthCheck)
req, err := http.NewRequest("GET", "/metrics", nil)
@@ -149,39 +157,75 @@ func testApp(t *testing.T, fakeApp string, expectedResponse string) {
}
type testCombination struct {
application string
applications []string
expectedResponse string
}
func TestMetrics(t *testing.T) {
combinations := []testCombination{
{
application: fakeApp,
expectedResponse: expectedResponse,
applications: []string{fakeApp, fakeApp2, fakeApp3},
expectedResponse: `
# HELP argocd_app_info Information about application.
# TYPE argocd_app_info gauge
argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Degraded",name="my-app-3",namespace="argocd",operation="delete",project="important-project",repo="https://github.com/argoproj/argocd-example-apps",sync_status="OutOfSync"} 1
argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Healthy",name="my-app",namespace="argocd",operation="",project="important-project",repo="https://github.com/argoproj/argocd-example-apps",sync_status="Synced"} 1
argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Healthy",name="my-app-2",namespace="argocd",operation="sync",project="important-project",repo="https://github.com/argoproj/argocd-example-apps",sync_status="Synced"} 1
`,
},
{
application: fakeDefaultApp,
expectedResponse: expectedDefaultResponse,
applications: []string{fakeDefaultApp},
expectedResponse: `
# HELP argocd_app_info Information about application.
# TYPE argocd_app_info gauge
argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Healthy",name="my-app",namespace="argocd",operation="",project="default",repo="https://github.com/argoproj/argocd-example-apps",sync_status="Synced"} 1
`,
},
}
for _, combination := range combinations {
testApp(t, combination.application, combination.expectedResponse)
testApp(t, combination.applications, combination.expectedResponse)
}
}
const appSyncTotal = `# HELP argocd_app_sync_total Number of application syncs.
# TYPE argocd_app_sync_total counter
argocd_app_sync_total{name="my-app",namespace="argocd",phase="Error",project="important-project"} 1
argocd_app_sync_total{name="my-app",namespace="argocd",phase="Failed",project="important-project"} 1
argocd_app_sync_total{name="my-app",namespace="argocd",phase="Succeeded",project="important-project"} 2
func TestLegacyMetrics(t *testing.T) {
os.Setenv(EnvVarLegacyControllerMetrics, "true")
defer os.Unsetenv(EnvVarLegacyControllerMetrics)
expectedResponse := `
# HELP argocd_app_created_time Creation time in unix timestamp for an application.
# TYPE argocd_app_created_time gauge
argocd_app_created_time{name="my-app",namespace="argocd",project="important-project"} -6.21355968e+10
# HELP argocd_app_health_status The application current health status.
# TYPE argocd_app_health_status gauge
argocd_app_health_status{health_status="Degraded",name="my-app",namespace="argocd",project="important-project"} 0
argocd_app_health_status{health_status="Healthy",name="my-app",namespace="argocd",project="important-project"} 1
argocd_app_health_status{health_status="Missing",name="my-app",namespace="argocd",project="important-project"} 0
argocd_app_health_status{health_status="Progressing",name="my-app",namespace="argocd",project="important-project"} 0
argocd_app_health_status{health_status="Suspended",name="my-app",namespace="argocd",project="important-project"} 0
argocd_app_health_status{health_status="Unknown",name="my-app",namespace="argocd",project="important-project"} 0
# HELP argocd_app_sync_status The application current sync status.
# TYPE argocd_app_sync_status gauge
argocd_app_sync_status{name="my-app",namespace="argocd",project="important-project",sync_status="OutOfSync"} 0
argocd_app_sync_status{name="my-app",namespace="argocd",project="important-project",sync_status="Synced"} 1
argocd_app_sync_status{name="my-app",namespace="argocd",project="important-project",sync_status="Unknown"} 0
`
testApp(t, []string{fakeApp}, expectedResponse)
}
func TestMetricsSyncCounter(t *testing.T) {
cancel, appLister := newFakeLister()
defer cancel()
metricsServ := NewMetricsServer("localhost:8082", appLister, noOpHealthCheck)
appSyncTotal := `
# HELP argocd_app_sync_total Number of application syncs.
# TYPE argocd_app_sync_total counter
argocd_app_sync_total{dest_server="https://localhost:6443",name="my-app",namespace="argocd",phase="Error",project="important-project"} 1
argocd_app_sync_total{dest_server="https://localhost:6443",name="my-app",namespace="argocd",phase="Failed",project="important-project"} 1
argocd_app_sync_total{dest_server="https://localhost:6443",name="my-app",namespace="argocd",phase="Succeeded",project="important-project"} 2
`
fakeApp := newFakeApp(fakeApp)
metricsServ.IncSync(fakeApp, &argoappv1.OperationState{Phase: argoappv1.OperationRunning})
metricsServ.IncSync(fakeApp, &argoappv1.OperationState{Phase: argoappv1.OperationFailed})
@@ -202,27 +246,31 @@ func TestMetricsSyncCounter(t *testing.T) {
// assertMetricsPrinted asserts every line in the expected lines appears in the body
func assertMetricsPrinted(t *testing.T, expectedLines, body string) {
for _, line := range strings.Split(expectedLines, "\n") {
if line == "" {
continue
}
assert.Contains(t, body, line)
}
}
const appReconcileMetrics = `argocd_app_reconcile_bucket{name="my-app",namespace="argocd",project="important-project",le="0.25"} 0
argocd_app_reconcile_bucket{name="my-app",namespace="argocd",project="important-project",le="0.5"} 0
argocd_app_reconcile_bucket{name="my-app",namespace="argocd",project="important-project",le="1"} 0
argocd_app_reconcile_bucket{name="my-app",namespace="argocd",project="important-project",le="2"} 0
argocd_app_reconcile_bucket{name="my-app",namespace="argocd",project="important-project",le="4"} 0
argocd_app_reconcile_bucket{name="my-app",namespace="argocd",project="important-project",le="8"} 1
argocd_app_reconcile_bucket{name="my-app",namespace="argocd",project="important-project",le="16"} 1
argocd_app_reconcile_bucket{name="my-app",namespace="argocd",project="important-project",le="+Inf"} 1
argocd_app_reconcile_sum{name="my-app",namespace="argocd",project="important-project"} 5
argocd_app_reconcile_count{name="my-app",namespace="argocd",project="important-project"} 1
`
func TestReconcileMetrics(t *testing.T) {
cancel, appLister := newFakeLister()
defer cancel()
metricsServ := NewMetricsServer("localhost:8082", appLister, noOpHealthCheck)
appReconcileMetrics := `
# HELP argocd_app_reconcile Application reconciliation performance.
# TYPE argocd_app_reconcile histogram
argocd_app_reconcile_bucket{dest_server="https://localhost:6443",namespace="argocd",le="0.25"} 0
argocd_app_reconcile_bucket{dest_server="https://localhost:6443",namespace="argocd",le="0.5"} 0
argocd_app_reconcile_bucket{dest_server="https://localhost:6443",namespace="argocd",le="1"} 0
argocd_app_reconcile_bucket{dest_server="https://localhost:6443",namespace="argocd",le="2"} 0
argocd_app_reconcile_bucket{dest_server="https://localhost:6443",namespace="argocd",le="4"} 0
argocd_app_reconcile_bucket{dest_server="https://localhost:6443",namespace="argocd",le="8"} 1
argocd_app_reconcile_bucket{dest_server="https://localhost:6443",namespace="argocd",le="16"} 1
argocd_app_reconcile_bucket{dest_server="https://localhost:6443",namespace="argocd",le="+Inf"} 1
argocd_app_reconcile_sum{dest_server="https://localhost:6443",namespace="argocd"} 5
argocd_app_reconcile_count{dest_server="https://localhost:6443",namespace="argocd"} 1
`
fakeApp := newFakeApp(fakeApp)
metricsServ.IncReconcile(fakeApp, 5*time.Second)

View File

@@ -1,37 +1,24 @@
package metrics
import (
"net/http"
"strconv"
"github.com/argoproj/pkg/kubeclientmetrics"
"k8s.io/client-go/rest"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
)
type metricsRoundTripper struct {
roundTripper http.RoundTripper
app *v1alpha1.Application
metricsServer *MetricsServer
}
func (mrt *metricsRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
resp, err := mrt.roundTripper.RoundTrip(r)
statusCode := 0
if resp != nil {
statusCode = resp.StatusCode
}
mrt.metricsServer.IncKubernetesRequest(mrt.app, statusCode)
return resp, err
}
// AddMetricsTransportWrapper adds a transport wrapper which increments 'argocd_app_k8s_request_total' counter on each kubernetes request
func AddMetricsTransportWrapper(server *MetricsServer, app *v1alpha1.Application, config *rest.Config) *rest.Config {
wrap := config.WrapTransport
config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
if wrap != nil {
rt = wrap(rt)
}
return &metricsRoundTripper{roundTripper: rt, metricsServer: server, app: app}
inc := func(resourceInfo kubeclientmetrics.ResourceInfo) error {
namespace := resourceInfo.Namespace
kind := resourceInfo.Kind
statusCode := strconv.Itoa(resourceInfo.StatusCode)
server.IncKubernetesRequest(app, resourceInfo.Server, statusCode, string(resourceInfo.Verb), kind, namespace)
return nil
}
return config
newConfig := kubeclientmetrics.AddMetricsTransportWrapper(config, inc)
return newConfig
}

View File

@@ -7,6 +7,7 @@ import (
"time"
log "github.com/sirupsen/logrus"
"github.com/yudai/gojsondiff"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -30,6 +31,7 @@ import (
"github.com/argoproj/argo-cd/util/resource"
"github.com/argoproj/argo-cd/util/resource/ignore"
"github.com/argoproj/argo-cd/util/settings"
"github.com/argoproj/argo-cd/util/stats"
)
type managedResource struct {
@@ -70,6 +72,8 @@ type comparisonResult struct {
hooks []*unstructured.Unstructured
diffNormalizer diff.Normalizer
appSourceType v1alpha1.ApplicationSourceType
// timings maps phases of comparison to the duration it took to complete (for statistical purposes)
timings map[string]time.Duration
}
func (cr *comparisonResult) targetObjs() []*unstructured.Unstructured {
@@ -96,14 +100,17 @@ type appStateManager struct {
}
func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1.ApplicationSource, appLabelKey, revision string, noCache bool) ([]*unstructured.Unstructured, []*unstructured.Unstructured, *apiclient.ManifestResponse, error) {
ts := stats.NewTimingStats()
helmRepos, err := m.db.ListHelmRepositories(context.Background())
if err != nil {
return nil, nil, nil, err
}
ts.AddCheckpoint("helm_ms")
repo, err := m.db.GetRepository(context.Background(), source.RepoURL)
if err != nil {
return nil, nil, nil, err
}
ts.AddCheckpoint("repo_ms")
conn, repoClient, err := m.repoClientset.NewRepoServerClient()
if err != nil {
return nil, nil, nil, err
@@ -118,7 +125,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
if err != nil {
return nil, nil, nil, err
}
ts.AddCheckpoint("plugins_ms")
tools := make([]*appv1.ConfigManagementPlugin, len(plugins))
for i := range plugins {
tools[i] = &plugins[i]
@@ -128,10 +135,12 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
if err != nil {
return nil, nil, nil, err
}
serverVersion, err := m.liveStateCache.GetServerVersion(app.Spec.Destination.Server)
ts.AddCheckpoint("build_options_ms")
serverVersion, apiGroups, err := m.liveStateCache.GetVersionsInfo(app.Spec.Destination.Server)
if err != nil {
return nil, nil, nil, err
}
ts.AddCheckpoint("version_ms")
manifestInfo, err := repoClient.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
Repo: repo,
Repos: helmRepos,
@@ -146,14 +155,23 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
BuildOptions: buildOptions,
},
KubeVersion: serverVersion,
ApiVersions: argo.APIGroupsToVersions(apiGroups),
})
if err != nil {
return nil, nil, nil, err
}
ts.AddCheckpoint("manifests_ms")
targetObjs, hooks, err := unmarshalManifests(manifestInfo.Manifests)
if err != nil {
return nil, nil, nil, err
}
ts.AddCheckpoint("unmarshal_ms")
logCtx := log.WithField("application", app.Name)
for k, v := range ts.Timings() {
logCtx = logCtx.WithField(k, v.Milliseconds())
}
logCtx = logCtx.WithField("time_ms", time.Since(ts.StartTime).Milliseconds())
logCtx.Info("getRepoObjs stats")
return targetObjs, hooks, manifestInfo, nil
}
@@ -165,7 +183,7 @@ func unmarshalManifests(manifests []string) ([]*unstructured.Unstructured, []*un
if err != nil {
return nil, nil, err
}
if ignore.Ignore(obj) {
if obj == nil || ignore.Ignore(obj) {
continue
}
if hookutil.IsHook(obj) {
@@ -252,27 +270,33 @@ func dedupLiveResources(targetObjs []*unstructured.Unstructured, liveObjsByKey m
}
}
func (m *appStateManager) getComparisonSettings(app *appv1.Application) (string, map[string]v1alpha1.ResourceOverride, diff.Normalizer, error) {
func (m *appStateManager) getComparisonSettings(app *appv1.Application) (string, map[string]v1alpha1.ResourceOverride, diff.Normalizer, *settings.ResourcesFilter, error) {
resourceOverrides, err := m.settingsMgr.GetResourceOverrides()
if err != nil {
return "", nil, nil, err
return "", nil, nil, nil, err
}
appLabelKey, err := m.settingsMgr.GetAppInstanceLabelKey()
if err != nil {
return "", nil, nil, err
return "", nil, nil, nil, err
}
diffNormalizer, err := argo.NewDiffNormalizer(app.Spec.IgnoreDifferences, resourceOverrides)
if err != nil {
return "", nil, nil, err
return "", nil, nil, nil, err
}
return appLabelKey, resourceOverrides, diffNormalizer, nil
resFilter, err := m.settingsMgr.GetResourcesFilter()
if err != nil {
return "", nil, nil, nil, err
}
return appLabelKey, resourceOverrides, diffNormalizer, resFilter, nil
}
// CompareAppState compares application git state to the live app state, using the specified
// revision and supplied source. If revision or overrides are empty, then compares against
// revision and overrides in the app spec.
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *appv1.AppProject, revision string, source v1alpha1.ApplicationSource, noCache bool, localManifests []string) *comparisonResult {
appLabelKey, resourceOverrides, diffNormalizer, err := m.getComparisonSettings(app)
ts := stats.NewTimingStats()
appLabelKey, resourceOverrides, diffNormalizer, resFilter, err := m.getComparisonSettings(app)
ts.AddCheckpoint("settings_ms")
// return unknown comparison result if basic comparison settings cannot be loaded
if err != nil {
@@ -313,32 +337,27 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
}
manifestInfo = nil
}
ts.AddCheckpoint("git_ms")
targetObjs, dedupConditions, err := DeduplicateTargetObjects(app.Spec.Destination.Server, app.Spec.Destination.Namespace, targetObjs, m.liveStateCache)
if err != nil {
conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now})
}
conditions = append(conditions, dedupConditions...)
resFilter, err := m.settingsMgr.GetResourcesFilter()
if err != nil {
conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now})
} else {
for i := len(targetObjs) - 1; i >= 0; i-- {
targetObj := targetObjs[i]
gvk := targetObj.GroupVersionKind()
if resFilter.IsExcludedResource(gvk.Group, gvk.Kind, app.Spec.Destination.Server) {
targetObjs = append(targetObjs[:i], targetObjs[i+1:]...)
conditions = append(conditions, v1alpha1.ApplicationCondition{
Type: v1alpha1.ApplicationConditionExcludedResourceWarning,
Message: fmt.Sprintf("Resource %s/%s %s is excluded in the settings", gvk.Group, gvk.Kind, targetObj.GetName()),
LastTransitionTime: &now,
})
}
for i := len(targetObjs) - 1; i >= 0; i-- {
targetObj := targetObjs[i]
gvk := targetObj.GroupVersionKind()
if resFilter.IsExcludedResource(gvk.Group, gvk.Kind, app.Spec.Destination.Server) {
targetObjs = append(targetObjs[:i], targetObjs[i+1:]...)
conditions = append(conditions, v1alpha1.ApplicationCondition{
Type: v1alpha1.ApplicationConditionExcludedResourceWarning,
Message: fmt.Sprintf("Resource %s/%s %s is excluded in the settings", gvk.Group, gvk.Kind, targetObj.GetName()),
LastTransitionTime: &now,
})
}
}
ts.AddCheckpoint("dedup_ms")
logCtx.Debugf("Generated config manifests")
liveObjByKey, err := m.liveStateCache.GetManagedLiveObjs(app, targetObjs)
if err != nil {
liveObjByKey = make(map[kubeutil.ResourceKey]*unstructured.Unstructured)
@@ -353,7 +372,6 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
}
}
logCtx.Debugf("Retrieved lived manifests")
for _, liveObj := range liveObjByKey {
if liveObj != nil {
appInstanceName := kubeutil.GetAppInstanceLabel(liveObj, appLabelKey)
@@ -382,7 +400,8 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
managedLiveObj[i] = nil
}
}
logCtx.Debugf("built managed objects list")
ts.AddCheckpoint("live_ms")
// Everything remaining in liveObjByKey are "extra" resources that aren't tracked in git.
// The following adds all the extras to the managedLiveObj list and backfills the targetObj
// list with nils, so that the lists are of equal lengths for comparison purposes.
@@ -398,6 +417,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
failedToLoadObjs = true
conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now})
}
ts.AddCheckpoint("diff_ms")
syncCode := v1alpha1.SyncStatusCodeSynced
managedResources := make([]managedResource, len(targetObjs))
@@ -423,7 +443,17 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
RequiresPruning: targetObj == nil && liveObj != nil,
}
diffResult := diffResults.Diffs[i]
var diffResult diff.DiffResult
if i < len(diffResults.Diffs) {
diffResult = diffResults.Diffs[i]
} else {
diffResult = diff.DiffResult{
Diff: gojsondiff.New().CompareObjects(map[string]interface{}{}, map[string]interface{}{}),
Modified: false,
NormalizedLive: []byte("{}"),
PredictedLive: []byte("{}"),
}
}
if resState.Hook || ignore.Ignore(obj) {
// For resource hooks, don't store sync status, and do not affect overall sync status
} else if diffResult.Modified || targetObj == nil || liveObj == nil {
@@ -477,6 +507,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
if manifestInfo != nil {
syncStatus.Revision = manifestInfo.Revision
}
ts.AddCheckpoint("sync_ms")
healthStatus, err := health.SetApplicationHealth(resourceSummaries, GetLiveObjs(managedResources), resourceOverrides, func(obj *unstructured.Unstructured) bool {
return !isSelfReferencedApp(app, kubeutil.GetObjectRef(obj))
@@ -503,6 +534,8 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
appv1.ApplicationConditionRepeatedResourceWarning: true,
appv1.ApplicationConditionExcludedResourceWarning: true,
})
ts.AddCheckpoint("health_ms")
compRes.timings = ts.Timings()
return &compRes
}

View File

@@ -47,6 +47,7 @@ type syncContext struct {
proj *v1alpha1.AppProject
compareResult *comparisonResult
config *rest.Config
rawConfig *rest.Config
dynamicIf dynamic.Interface
disco discovery.DiscoveryInterface
extensionsclientset *clientset.Clientset
@@ -173,6 +174,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
proj: proj,
compareResult: compareResult,
config: restConfig,
rawConfig: clst.RawRestConfig(),
dynamicIf: dynamicIf,
disco: disco,
extensionsclientset: extensionsclientset,
@@ -422,7 +424,13 @@ func (sc *syncContext) getSyncTasks() (_ syncTasks, successful bool) {
// metadata.generateName, then we will generate a formulated metadata.name before submission.
targetObj := obj.DeepCopy()
if targetObj.GetName() == "" {
postfix := strings.ToLower(fmt.Sprintf("%s-%s-%d", sc.syncRes.Revision[0:7], phase, sc.opState.StartedAt.UTC().Unix()))
var syncRevision string
if len(sc.syncRes.Revision) >= 8 {
syncRevision = sc.syncRes.Revision[0:7]
} else {
syncRevision = sc.syncRes.Revision
}
postfix := strings.ToLower(fmt.Sprintf("%s-%s-%d", syncRevision, phase, sc.opState.StartedAt.UTC().Unix()))
generateName := obj.GetGenerateName()
targetObj.SetName(fmt.Sprintf("%s%s", generateName, postfix))
}
@@ -548,9 +556,8 @@ func (sc *syncContext) ensureCRDReady(name string) {
}
// applyObject performs a `kubectl apply` of a single resource
func (sc *syncContext) applyObject(targetObj *unstructured.Unstructured, dryRun bool, force bool) (v1alpha1.ResultCode, string) {
validate := !resource.HasAnnotationOption(targetObj, common.AnnotationSyncOptions, "Validate=false")
message, err := sc.kubectl.ApplyResource(sc.config, targetObj, targetObj.GetNamespace(), dryRun, force, validate)
func (sc *syncContext) applyObject(targetObj *unstructured.Unstructured, dryRun, force, validate bool) (v1alpha1.ResultCode, string) {
message, err := sc.kubectl.ApplyResource(sc.rawConfig, targetObj, targetObj.GetNamespace(), dryRun, force, validate)
if err != nil {
return v1alpha1.ResultCodeSyncFailed, err.Error()
}
@@ -750,7 +757,8 @@ func (sc *syncContext) runTasks(tasks syncTasks, dryRun bool) runState {
defer createWg.Done()
logCtx := sc.log.WithFields(log.Fields{"dryRun": dryRun, "task": t})
logCtx.Debug("applying")
result, message := sc.applyObject(t.targetObj, dryRun, sc.syncOp.SyncStrategy.Force())
validate := !(sc.syncOp.SyncOptions.HasOption("Validate=false") || resource.HasAnnotationOption(t.targetObj, common.AnnotationSyncOptions, "Validate=false"))
result, message := sc.applyObject(t.targetObj, dryRun, sc.syncOp.SyncStrategy.Force(), validate)
if result == v1alpha1.ResultCodeSyncFailed {
logCtx.WithField("message", message).Info("apply failed")
runState = failed

View File

@@ -44,6 +44,7 @@ func newTestSyncCtx(resources ...*v1.APIResourceList) *syncContext {
})
sc := syncContext{
config: &rest.Config{},
rawConfig: &rest.Config{},
namespace: test.FakeArgoCDNamespace,
server: test.FakeClusterURL,
syncRes: &v1alpha1.SyncOperationResult{
@@ -365,6 +366,20 @@ func TestSyncOptionValidate(t *testing.T) {
}
}
// make sure Validate means we don't validate
func TestSyncValidate(t *testing.T) {
syncCtx := newTestSyncCtx()
pod := test.NewPod()
pod.SetNamespace(test.FakeArgoCDNamespace)
syncCtx.compareResult = &comparisonResult{managedResources: []managedResource{{Target: pod, Live: pod}}}
syncCtx.syncOp.SyncOptions = SyncOptions{"Validate=false"}
syncCtx.sync()
kubectl := syncCtx.kubectl.(*kubetest.MockKubectlCmd)
assert.False(t, kubectl.LastValidate)
}
func TestSelectiveSyncOnly(t *testing.T) {
syncCtx := newTestSyncCtx()
pod1 := test.NewPod()
@@ -384,20 +399,40 @@ func TestSelectiveSyncOnly(t *testing.T) {
}
func TestUnnamedHooksGetUniqueNames(t *testing.T) {
syncCtx := newTestSyncCtx()
syncCtx.syncOp.SyncStrategy.Apply = nil
pod := test.NewPod()
pod.SetName("")
pod.SetAnnotations(map[string]string{common.AnnotationKeyHook: "PreSync,PostSync"})
syncCtx.compareResult = &comparisonResult{hooks: []*unstructured.Unstructured{pod}}
t.Run("Truncated revision", func(t *testing.T) {
syncCtx := newTestSyncCtx()
syncCtx.syncOp.SyncStrategy.Apply = nil
pod := test.NewPod()
pod.SetName("")
pod.SetAnnotations(map[string]string{common.AnnotationKeyHook: "PreSync,PostSync"})
syncCtx.compareResult = &comparisonResult{hooks: []*unstructured.Unstructured{pod}}
tasks, successful := syncCtx.getSyncTasks()
tasks, successful := syncCtx.getSyncTasks()
assert.True(t, successful)
assert.Len(t, tasks, 2)
assert.Contains(t, tasks[0].name(), "foobarb-presync-")
assert.Contains(t, tasks[1].name(), "foobarb-postsync-")
assert.Equal(t, "", pod.GetName())
})
t.Run("Short revision", func(t *testing.T) {
syncCtx := newTestSyncCtx()
syncCtx.syncOp.SyncStrategy.Apply = nil
pod := test.NewPod()
pod.SetName("")
pod.SetAnnotations(map[string]string{common.AnnotationKeyHook: "PreSync,PostSync"})
syncCtx.compareResult = &comparisonResult{hooks: []*unstructured.Unstructured{pod}}
syncCtx.syncRes.Revision = "foobar"
tasks, successful := syncCtx.getSyncTasks()
assert.True(t, successful)
assert.Len(t, tasks, 2)
assert.Contains(t, tasks[0].name(), "foobar-presync-")
assert.Contains(t, tasks[1].name(), "foobar-postsync-")
assert.Equal(t, "", pod.GetName())
})
assert.True(t, successful)
assert.Len(t, tasks, 2)
assert.Contains(t, tasks[0].name(), "foobarb-presync-")
assert.Contains(t, tasks[1].name(), "foobarb-postsync-")
assert.Equal(t, "", pod.GetName())
}
func TestManagedResourceAreNotNamed(t *testing.T) {

View File

@@ -24,7 +24,7 @@ Install:
Brew users can quickly install the lot:
```bash
brew install go git-lfs kubectl kubectx dep ksonnet/tap/ks kubernetes-helm kustomize
brew install go git-lfs kubectl kubectx dep ksonnet/tap/ks helm@2 kustomize
```
Check the versions:

View File

@@ -38,4 +38,12 @@ make builder-image IMAGE_NAMESPACE=argoproj IMAGE_TAG=v1.0.0
## Public CD
[https://cd.apps.argoproj.io/](https://cd.apps.argoproj.io/)
Every commit to master is built and published to `docker.pkg.github.com/argoproj/argo-cd/argocd:<version>-<short-sha>`. The list of images is available at
https://github.com/argoproj/argo-cd/packages.
!!! note
Github docker registry [requires](https://github.community/t5/GitHub-Actions/docker-pull-from-public-GitHub-Package-Registry-fail-with-quot/m-p/32888#M1294) authentication to read
even publicly available packages. Follow the steps from Kubernetes [documentation](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry)
to configure image pull secret if you want to use `docker.pkg.github.com/argoproj/argo-cd/argocd` image.
The image is automatically deployed to the dev Argo CD instance: [https://cd.apps.argoproj.io/](https://cd.apps.argoproj.io/)

View File

@@ -47,6 +47,10 @@ kubectl -n argocd patch secret argocd-secret \
Another option is to delete both the `admin.password` and `admin.passwordMtime` keys and restart argocd-server. This will set the password back to the pod name as per [the getting started guide](getting_started.md).
## How to disable admin user?
Add `admin.enabled: "false"` to the `argocd-cm` ConfigMap (see [user management](operator-manual/user-management/index.md)).
## Argo CD cannot deploy Helm Chart based applications without internet access, how can I solve it?
Argo CD might fail to generate Helm chart manifests if the chart has dependencies located in external repositories. To solve the problem you need to make sure that `requirements.yaml`

View File

@@ -24,8 +24,8 @@ kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
```
Follow our [getting started guide](getting_started.md). Further [documentation](docs/)
is provided for additional features.
Follow our [getting started guide](getting_started.md). Further user oriented [documentation](user_guide/)
is provided for additional features. Developer oriented [documentation](developer-guide/) is available for people interested in building third-party integrations.
## How it works

View File

@@ -27,9 +27,11 @@ spec:
# Release name override (defaults to application name)
releaseName: guestbook
# Helm values files for overriding values in the helm chart
# The path is relative to the spec.source.path directory defined above
valueFiles:
- values-prod.yaml
# Values file as block file
values: |
ingress:
@@ -90,6 +92,7 @@ spec:
automated:
prune: true # Specifies if resources should be pruned during auto-syncing ( false by default ).
selfHeal: true # Specifies if partial app sync should be executed when resources are changed only in target Kubernetes cluster and no git change detected ( false by default ).
validate: true # Validate resources before applying to k8s, defaults to true.
# Ignore differences at the specified json pointers
ignoreDifferences:

View File

@@ -100,7 +100,7 @@ data:
# List of json pointers in the object to ignore differences
ignoreDifferences: |
jsonPointers:
- webhooks/0/clientConfig/caBundle
- /webhooks/0/clientConfig/caBundle
certmanager.k8s.io/Certificate:
# Lua script for customizing the health status assessment
health.lua: |
@@ -183,6 +183,16 @@ data:
clusters:
- "*.local"
# By default all resource group/kinds are included. The resource.inclusions setting allows customizing
# list of included group/kinds.
resource.inclusions: |
- apiGroups:
- repositories.stash.appscode.com
kinds:
- Snapshot
clusters:
- "*.local"
# Configuration to add a config management plugin.
configManagementPlugins: |
- name: kasane
@@ -198,3 +208,12 @@ data:
# Tracking labels are used to determine which resources need to be deleted when pruning.
# If omitted, Argo CD injects the app name into the label: 'app.kubernetes.io/instance'
application.instanceLabelKey: mycompany.com/appname
# disables admin user. Admin is enabled by default
admin.enabled: "false"
# add an additional local user with apiKey and login capabilities
# apiKey - allows generating API keys
# login - allows to login using UI
accounts.alice: apiKey, login
# disables user. User is enabled by default
accounts.alice.enabled: "false"

View File

@@ -34,3 +34,10 @@ data:
webhook.bitbucketserver.secret: shhhh! it's a bitbucket server secret
# gogs server webhook secret
webhook.gogs.secret: shhhh! it's a gogs server secret
# an additional user password and its last modified time (see user definition in argocd-cm.yaml)
accounts.alice.password:
accounts.alice.passwordMtime:
# list of generated account tokens/api keys
accounts.alice.tokens: |
[{"id":"123","iat":1583789194,"exp":1583789194}]

View File

@@ -14,7 +14,7 @@ can be customized to use alternative toolchain required by your environment.
## Adding Tools Via Volume Mounts
The first technique is to use an `init` container and a `volumeMount` to copy a different verison of
The first technique is to use an `init` container and a `volumeMount` to copy a different version of
a tool into the repo-server container. In the following example, an init container is overwriting
the helm binary with a different version than what is bundled in Argo CD:

View File

@@ -506,7 +506,7 @@ data:
key: key
```
## Resource Exclusion
## Resource Exclusion/Inclusion
Resources can be excluded from discovery and sync so that ArgoCD is unaware of them. For example, `events.k8s.io` and `metrics.k8s.io` are always excluded. Use cases:
@@ -543,6 +543,25 @@ The `resource.exclusions` node is a list of objects. Each object can have:
If all three match, then the resource is ignored.
In addition to exclusions, you might configure the list of included resources using the `resource.inclusions` setting.
By default, all resource group/kinds are included. The `resource.inclusions` setting allows customizing the list of included group/kinds:
```yaml
apiVersion: v1
data:
resource.inclusions: |
- apiGroups:
- "*"
kinds:
- Deployment
clusters:
- https://192.168.0.20
kind: ConfigMap
```
The `resource.inclusions` and `resource.exclusions` might be used together. The final list of resources includes group/kinds specified in `resource.inclusions` minus group/kinds
specified in `resource.exclusions` setting.
Notes:
* Quote globs in your YAML to avoid parsing errors.
@@ -551,7 +570,7 @@ Notes:
## SSO & RBAC
* SSO configuration details: [SSO](./sso/index.md)
* SSO configuration details: [SSO](./user-management/index.md)
* RBAC configuration details: [RBAC](./rbac.md)
## Manage Argo CD Using Argo CD

View File

@@ -1,6 +1,6 @@
# Disaster Recovery
You can use `argocd-util` can be used to import and export all Argo CD data.
You can use `argocd-util` to import and export all Argo CD data.
Make sure you have `~/.kube/config` pointing to your Argo CD cluster.

View File

@@ -241,6 +241,8 @@ http {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
# buffering should be disabled for api/v1/stream/applications to support chunked response
proxy_buffering off;
}
}
}

View File

@@ -65,6 +65,7 @@ spec:
## Dashboards
You can find an example Grafana dashboard [here](https://github.com/argoproj/argo-cd/blob/master/examples/dashboard.json)
You can find an example Grafana dashboard [here](https://github.com/argoproj/argo-cd/blob/master/examples/dashboard.json) or check demo instance
[dashboard](https://grafana.apps.argoproj.io).
![dashboard](../assets/dashboard.jpg)

View File

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

View File

@@ -2,7 +2,7 @@
The RBAC feature enables restriction of access to Argo CD resources. Argo CD does not have its own
user management system and has only one built-in user `admin`. The `admin` user is a superuser and
it has unrestricted access to the system. RBAC requires [SSO configuration](sso/index.md). Once SSO is
it has unrestricted access to the system. RBAC requires [SSO configuration](user-management/index.md). Once SSO is
configured, additional RBAC roles can be defined, and SSO groups can man be mapped to roles.
## Basic Built-in Roles

View File

@@ -5,6 +5,7 @@ Argo CD is un-opinionated about how secrets are managed. There's many ways to do
* [Bitnami Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets)
* [Godaddy Kubernetes External Secrets](https://github.com/godaddy/kubernetes-external-secrets)
* [Hashicorp Vault](https://www.vaultproject.io)
* [Banzai Cloud Bank-Vaults](https://github.com/banzaicloud/bank-vaults)
* [Helm Secrets](https://github.com/futuresimple/helm-secrets)
* [Kustomize secret generator plugins](https://github.com/kubernetes-sigs/kustomize/blob/fd7a353df6cece4629b8e8ad56b71e30636f38fc/examples/kvSourceGoPlugin.md#secret-values-from-anywhere)
* [aws-secret-operator](https://github.com/mumoshu/aws-secret-operator)

View File

@@ -1,8 +0,0 @@
# Auth0
!!! note "Are you using this? Please contribute!"
If you're using this IdP please consider [contributing](../../developer-guide/site.md) to this document.
<!-- markdownlint-disable MD033 -->
<div style="text-align:center"><img src="../../../assets/argo.png" /></div>
<!-- markdownlint-enable MD033 -->

View File

@@ -0,0 +1,66 @@
# Auth0
## User-definitions
User-definitions in Auth0 is out of scope for this guide. Add them directly in Auth0 database, use an enterprise registry, or "social login".
*Note*: all users have access to all Auth0 defined apps unless you restrict access via configuration - keep this in mind if argo is exposed on the internet or else anyone can login.
## Registering the app with Auth0
Follow the [register app](https://auth0.com/docs/dashboard/guides/applications/register-app-spa) instructions to create the argocd app in Auth0. In the app definition:
* Take note of the _clientId_ and _clientSecret_ values.
* Register login url as https://your.argoingress.address/login
* Set allowed callback url to https://your.argoingress.address/auth/callback
* Under connections, select the user-registries you want to use with argo
Any other settings are non-essential for the authentication to work.
## Adding authorization rules to Auth0
Follow Auth0 [authorization guide](https://auth0.com/docs/authorization) to setup authorization.
The important part to note here is that group-membership is a non-standard claim, and hence is required to be put under a FQDN claim name, for instance `http://your.domain/groups`.
## Configuring argo
### Configure OIDC for ArgoCD
`kubectl edit configmap argocd-cm`
```
...
data:
application.instanceLabelKey: argocd.argoproj.io/instance
oidc.config: |
name: Auth0
issuer: https://<yourtenant>.<eu|us>.auth0.com/
clientID: <theClientId>
clientSecret: <theClientSecret>
requestedScopes:
- openid
- profile
- email
# not strictly nesscessary - but good practice:
- 'http://your.domain/groups'
...
```
### Configure RBAC for ArgoCD
`kubectl edit configmap argocd-rbac-cm` (or use helm values).
```
...
data:
policy.csv: |
# let members with group someProjectGroup handle apps in someProject
# this can also be defined in the UI in the group-definition to avoid doing it there in the configmap
p, someProjectGroup, applications, *, someProject/*, allow
# let the group membership argocd-admins from OIDC become role:admin - needs to go into the configmap
g, argocd-global-admins, role:admin
policy.default: role:readonly
# essential to get argo to use groups for RBAC:
scopes: '[http://your.domain/groups, email]'
...
```

View File

@@ -1,7 +1,91 @@
# SSO Overview
# Overview
Argo CD does not have any local users other than the built-in `admin` user. All other users are
expected to login via SSO. There are two ways that SSO can be configured:
Once installed Argo CD has one built-in `admin` user that has full access to the system. It is recommended to use `admin` user only
for initial configuration and then switch to local users or configure SSO integration.
## Local users/accounts (v1.5)
The local users/accounts feature serving to main use-cases:
* Auth tokens for Argo CD management automation. It is possible to configure an API account with limited permissions and generate an authentication token.
Such token can be used to automatically create applications, projects etc.
* Additional users for a very small team when SSO integration is overkill. The local users don't provide advanced features such as groups,
login history etc. So if you need such features it is strongly recommended to use SSO.
### Create new user
New users should be defined in `argocd-cm` ConfigMap:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
labels:
app.kubernetes.io/name: argocd-cm
app.kubernetes.io/part-of: argocd
data:
# add an additional local user with apiKey and login capabilities
# apiKey - allows generating API keys
# login - allows to login using UI
accounts.alice: apiKey, login
# disables user. User is enabled by default
accounts.alice.enabled: "false"
```
Each user might have two capabilities:
* apiKey - allows generating authentication tokens for API access
* login - allows to login using UI
### Disable admin user
As soon as additional users are created it is recommended to disable `admin` user:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
labels:
app.kubernetes.io/name: argocd-cm
app.kubernetes.io/part-of: argocd
data:
admin.enabled: "false"
```
### Manage users
The Argo CD CLI provides set of commands to set user password and generate tokens.
* Get full users list
```bash
argocd account list
```
* Get specific user details
```bash
argocd account get <username>
```
* Set user password
```bash
argocd account update-password \
--account <name> \
--current-password <current-admin> \
--new-password <new-user-password>
```
* Generate auth token
```bash
# if flag --account is omitted then Argo CD generates token for current user
argocd account generate-token --account <username>
```
## SSO
There are two ways that SSO can be configured:
* [Bundled Dex OIDC provider](#dex) - use this option if your current provider does not support OIDC (e.g. SAML,
LDAP) or if you wish to leverage any of Dex's connector features (e.g. the ability to map GitHub

View File

@@ -54,6 +54,11 @@
p, role:org-admin, repositories, delete, *, allow
g, "Grp Argo CD", role:org-admin
5. Mapping role from jwt token to argo
If you want to map the roles from the jwt token to match the default roles (readonly and admin) then you must change the scope variable in the rbac-configmap.
scopes: '[roles, email]'
## With Dex

View File

@@ -74,7 +74,7 @@ oidc.config: |
issuer: https://yourorganization.oktapreview.com
clientID: 0oaltaqg3oAIf2NOa0h3
clientSecret: ZXF_CfUc-rtwNfzFecGquzdeJ_MxM4sGc8pDT2Tg6t
requestedScopes: ["openid", "profile", "email", "groups"].
requestedScopes: ["openid", "profile", "email", "groups"]
requestedIDTokenClaims: {"groups": {"essential": true}}
```
<!-- markdownlint-enable MD046 -->

View File

@@ -16,7 +16,7 @@ arbitrary value in the secret. This value will be used when configuring the webh
![Add Webhook](../assets/webhook-config.png "Add Webhook")
### 2. Configure Argo CD With The WebHook Secret Optional)
### 2. Configure Argo CD With The WebHook Secret (Optional)
Configuring a webhook shared secret is optional, since Argo CD will still refresh applications
related to the Git repository, even with unauthenticated webhook events. This is safe to do since

View File

@@ -7,7 +7,7 @@ Apps can be deleted with or without a cascade option. A **cascade delete**, dele
To perform a non-cascade delete:
```bash
argocd app delete APPNAME
argocd app delete APPNAME --cascade=false
```
To perform a cascade delete:
@@ -16,6 +16,12 @@ To perform a cascade delete:
argocd app delete APPNAME --cascade
```
or
```bash
argocd app delete APPNAME
```
# Deletion Using `kubectl`
To perform a non-cascade delete:

View File

@@ -37,6 +37,22 @@ spec:
syncPolicy:
automated:
prune: true
```
## Automatic Self-Healing
By default, changes that are made to the live cluster will not trigger automated sync. To enable automatic sync
when the live cluster's state deviates from the state defined in Git, run:
```bash
argocd app set <APPNAME> --self-heal
```
Or by setting the self heal option to true in the automated sync policy:
```yaml
spec:
syncPolicy:
automated:
selfHeal: true
```
@@ -48,7 +64,7 @@ spec:
application parameters. If the most recent successful sync in the history was already performed
against the same commit-SHA and parameters, a second sync will not be attempted, unless `selfHeal` flag is set to true.
* If `selfHeal` flag is set to true then sync will be attempted again after self heal timeout (5 seconds by default)
which is controller by `--self-heal-timeout-seconds` flag of `argocd-application-controller` deployment.
which is controlled by `--self-heal-timeout-seconds` flag of `argocd-application-controller` deployment.
* Automatic sync will not reattempt a sync if the previous sync attempt against the same commit-SHA
and parameters had failed.

View File

@@ -11,7 +11,7 @@ submitted to Kubernetes in a manner which contradicts Git.
which generates different data every time `helm template` is invoked.
* For Horizontal Pod Autoscaling (HPA) objects, the HPA controller is known to reorder `spec.metrics`
in a specific order. See [kubernetes issue #74099](https://github.com/kubernetes/kubernetes/issues/74099).
To work around this, you can order `spec.replicas` in Git in the same order that the controller
To work around this, you can order `spec.metrics` in Git in the same order that the controller
prefers.
In case it is impossible to fix the upstream issue, Argo CD allows you to optionally ignore differences of problematic resources.
@@ -19,7 +19,7 @@ The diffing customization can be configured for single or multiple application r
## Application Level Configuration
Argo CD allows ignoring differences at a specific JSON path. The following sample application is configured to ignore differences in `spec.replicas` for all deployments:
Argo CD allows ignoring differences at a specific JSON path, using [RFC6902 JSON patches](http://tools.ietf.org/html/rfc6902). The following sample application is configured to ignore differences in `spec.replicas` for all deployments:
```yaml
spec:

View File

@@ -86,7 +86,7 @@ Unsupported hooks are ignored. In Argo CD, hooks are created by using `kubectl a
* Annotate `pre-install` and `post-install` with `hook-weight: "-1"`. This will make sure it runs to success before any upgrade hooks.
* Annotate `pre-upgrade` and `post-upgrade` with `hook-delete-policy: before-hook-creation` to make sure it runs on every sync.
Read more about [Argo hooks](resource_hooks.md) and [Helm hooks](https://github.com/kubernetes/helm/blob/master/docs/charts_hooks.md).
Read more about [Argo hooks](resource_hooks.md) and [Helm hooks](https://github.com/helm/helm/blob/dev-v2/docs/charts_hooks.md).
## Random Data
@@ -118,7 +118,7 @@ argocd app set redis -p password=abc123
> v1.4
Helm apps have access to the [standard build environment](build-environment.md) via substitution as parameters.
Helm apps have access to the [standard build environment](build-environment.md) via substitution as parameters.
E.g. via the CLI:

View File

@@ -15,7 +15,7 @@ To use Kustomize with an overlay, point your path to the overlay.
If you have remote bases that are either (a) HTTPS and need username/password (b) SSH and need SSH private key, then they'll inherit that from the app's repo.
This will work if the remote bases uses the same credentials/private key. It will not work if they use different ones. For security reasons your app only ever knows about it's own repo (not other team's or users repos), and so you won't be able to access other private repo, even if Argo CD knows about them.
This will work if the remote bases uses the same credentials/private key. It will not work if they use different ones. For security reasons your app only ever knows about its own repo (not other team's or users repos), and so you won't be able to access other private repo, even if Argo CD knows about them.
Read more about [private repos](private-repositories.md).
@@ -38,4 +38,4 @@ data:
## Build Environment
Kustomize does not support parameters and therefore cannot support the standard [build environment](build-environment.md).
Kustomize does not support parameters and therefore cannot support the standard [build environment](build-environment.md).

View File

@@ -99,6 +99,9 @@ Using the UI:
!!!note
When pasting SSH private key in the UI, make sure there are no unintended line breaks or additional characters in the text area
!!!note
When your SSH repository is served from a non-standard port, you have to use `ssh://`-style URLs to specify your repository. The scp-style `git@yourgit.com:yourrepo` URLs do **not** support port specification, and will treat any port number as part of the repository's path.
> earlier than v1.2
The Argo CD UI don't support configuring SSH credentials. The SSH credentials can only be configured using the Argo CD CLI:

View File

@@ -170,7 +170,7 @@ argocd app get $PROJ-$ROLE --auth-token $JWT
# Removing the policy we added and adding one with a wildcard.
argocd proj role remove-policy $PROJ $TOKEN -a get -o $PROJ-$TOKEN
argocd proj role remove-policy $PROJ $TOKEN -a get -o '*'
argocd proj role add-policy $PROJ $ROLE -a get --permission allow -o '*'
# The wildcard allows us to access the application due to the wildcard.
argocd app get $PROJ-$TOKEN --auth-token $JWT
argocd proj role get $PROJ

View File

@@ -12,7 +12,7 @@ Kubernetes rolling update strategy.
## Usage
Hooks are simply Kubernetes manifests annotated with `argocd.argoproj.io/hook`, e.g.:
Hooks are simply Kubernetes manifests inside your Argo CD Application annotated with `argocd.argoproj.io/hook`, e.g.:
```yaml
apiVersion: batch/v1

View File

@@ -1072,7 +1072,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 5,
"w": 24,
@@ -1164,7 +1164,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 5,
"w": 24,
@@ -1253,7 +1253,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 8,
"w": 24,
@@ -1288,7 +1288,7 @@
"expr": "sum(increase(argocd_app_reconcile_count{namespace=~\"$namespace\", project=~\"$project\"}[10m])) by (namespace, project)",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{namespace}}",
"legendFormat": "{{namespace}},{{project}}",
"refId": "A"
}
],
@@ -1339,7 +1339,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 8,
"w": 24,
@@ -1374,7 +1374,7 @@
"expr": "sum(increase(argocd_app_k8s_request_total{namespace=~\"$namespace\",project=~\"$project\"}[5m])) by (namespace, project)",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{namespace}}",
"legendFormat": "{{namespace}},{{project}}",
"refId": "A"
}
],
@@ -1489,7 +1489,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 8,
"w": 24,
@@ -1575,7 +1575,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 8,
"w": 24,
@@ -1673,7 +1673,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 8,
"w": 24,
@@ -1759,7 +1759,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 9,
"w": 24,
@@ -1845,7 +1845,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 9,
"w": 24,
@@ -1946,7 +1946,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 9,
"w": 12,
@@ -1978,10 +1978,10 @@
"steppedLine": false,
"targets": [
{
"expr": "grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"application.ApplicationService\",namespace=~\"$namespace\"} > 0",
"expr": "increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"application.ApplicationService\",namespace=~\"$namespace\"}[10m]) > 0 or on() vector (0)",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{grpc_code}},{{grpc_method}}",
"legendFormat": "{{grpc_code}},{{grpc_method}},{{pod}}",
"refId": "A"
}
],
@@ -2040,7 +2040,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 9,
"w": 12,
@@ -2072,10 +2072,10 @@
"steppedLine": false,
"targets": [
{
"expr": "grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"cluster.ClusterService\",namespace=~\"$namespace\"} > 0",
"expr": "increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"cluster.ClusterService\",namespace=~\"$namespace\"}[10m]) > 0 or on() vector (0)",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{grpc_code}},{{grpc_method}}",
"legendFormat": "{{grpc_code}},{{grpc_method}},{{pod}}",
"refId": "A"
}
],
@@ -2134,7 +2134,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 9,
"w": 12,
@@ -2166,10 +2166,10 @@
"steppedLine": false,
"targets": [
{
"expr": "grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"project.ProjectService\",namespace=~\"$namespace\"} > 0",
"expr": "increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"project.ProjectService\",namespace=~\"$namespace\"}[10m]) > 0 or on() vector (0)",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{grpc_code}},{{grpc_method}}",
"legendFormat": "{{grpc_code}},{{grpc_method}},{{pod}}",
"refId": "A"
}
],
@@ -2228,7 +2228,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 9,
"w": 12,
@@ -2260,10 +2260,10 @@
"steppedLine": false,
"targets": [
{
"expr": "grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"repository.RepositoryService\",namespace=~\"$namespace\"} > 0",
"expr": "increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"repository.RepositoryService\",namespace=~\"$namespace\"}[10m]) > 0 or on() vector (0)",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{grpc_code}},{{grpc_method}}",
"legendFormat": "{{grpc_code}},{{grpc_method}},{{pod}}",
"refId": "A"
}
],
@@ -2322,7 +2322,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 9,
"w": 12,
@@ -2354,10 +2354,10 @@
"steppedLine": false,
"targets": [
{
"expr": "grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"session.SessionService\",namespace=~\"$namespace\"} > 0",
"expr": "increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"session.SessionService\",namespace=~\"$namespace\"}[10m]) > 0 or on() vector (0)",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{grpc_code}},{{grpc_method}}",
"legendFormat": "{{grpc_code}},{{grpc_method}},{{pod}}",
"refId": "A"
}
],
@@ -2416,7 +2416,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 9,
"w": 12,
@@ -2448,10 +2448,10 @@
"steppedLine": false,
"targets": [
{
"expr": "grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"version.VersionService\",namespace=~\"$namespace\"} > 0",
"expr": "increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"version.VersionService\",namespace=~\"$namespace\"}[10m]) > 0 or on() vector (0)",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{grpc_code}},{{grpc_method}}",
"legendFormat": "{{grpc_code}},{{grpc_method}},{{pod}}",
"refId": "A"
}
],
@@ -2510,7 +2510,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 9,
"w": 12,
@@ -2542,10 +2542,10 @@
"steppedLine": false,
"targets": [
{
"expr": "grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"account.AccountService\",namespace=~\"$namespace\"} >1",
"expr": "increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"account.AccountService\",namespace=~\"$namespace\"}[10m]) > 1 or on() vector (0)",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{grpc_code}},{{grpc_method}}",
"legendFormat": "{{grpc_code}},{{grpc_method}},{{pod}}",
"refId": "A"
}
],
@@ -2621,7 +2621,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 8,
"w": 24,
@@ -2707,7 +2707,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 9,
"w": 24,
@@ -2793,7 +2793,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 8,
"w": 12,
@@ -2827,6 +2827,7 @@
"expr": "sum(increase(argocd_git_request_total{request_type=\"ls-remote\", namespace=~\"$namespace\"}[10m])) by (namespace)",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{namespace}}",
"refId": "A"
}
],
@@ -2877,7 +2878,7 @@
"dashLength": 10,
"dashes": false,
"datasource": "$Source",
"fill": 1,
"fill": 0,
"gridPos": {
"h": 8,
"w": 12,
@@ -2911,6 +2912,7 @@
"expr": "sum(increase(argocd_git_request_total{request_type=\"fetch\", namespace=~\"$namespace\"}[10m])) by (namespace)",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{namespace}}",
"refId": "A"
}
],
@@ -3060,5 +3062,5 @@
"timezone": "",
"title": "ArgoCD",
"uid": "BjWwX3jik",
"version": 5
}
"version": 7
}

View File

@@ -1,4 +1,4 @@
FROM golang:1.12.6 as builder
FROM golang:1.14.0 as builder
RUN apt-get update && apt-get install -y zip
@@ -9,7 +9,7 @@ RUN ./install.sh codegen-tools
RUN ./install.sh codegen-go-tools
RUN mkdir -p /home/user && chmod 777 /home/user
RUN HELM_HOME=/home/user/.helm helm init --client-only
RUN HELM_HOME=/home/user/.helm helm2 init --client-only
RUN mkdir -p /go/pkg && chmod 777 /go/pkg

View File

@@ -114,7 +114,9 @@ clean_swagger() {
find "${SWAGGER_ROOT}" -name '*.swagger.json' -delete
}
collect_swagger server 31
echo "If additional types are added, the number of expected collisions may need to be increased"
EXPECTED_COLLISION_COUNT=32
collect_swagger server ${EXPECTED_COLLISION_COUNT}
clean_swagger server
clean_swagger reposerver
clean_swagger controller

View File

@@ -1,8 +0,0 @@
#!/bin/bash
set -eux -o pipefail
AWS_IAM_AUTHENTICATOR_VERSION=0.4.0-alpha.1
[ -e $DOWNLOADS/aws-iam-authenticator ] || curl -sLf --retry 3 -o $DOWNLOADS/aws-iam-authenticator https://github.com/kubernetes-sigs/aws-iam-authenticator/releases/download/${AWS_IAM_AUTHENTICATOR_VERSION}/aws-iam-authenticator_${AWS_IAM_AUTHENTICATOR_VERSION}_linux_amd64
cp $DOWNLOADS/aws-iam-authenticator $BIN/
chmod +x $BIN/aws-iam-authenticator
aws-iam-authenticator version

View File

@@ -1,4 +1,4 @@
#!/bin/bash
set -eux -o pipefail
KUSTOMIZE_VERSION=2.0.3 "$(dirname $0)/../install.sh" helm-linux jq-linux kustomize-linux protoc-linux swagger-linux
KUSTOMIZE_VERSION=2.0.3 "$(dirname $0)/../install.sh" helm2-linux jq-linux kustomize-linux protoc-linux swagger-linux

View File

@@ -1,7 +1,7 @@
#!/bin/bash
set -eux -o pipefail
[ -e $DOWNLOADS/helm.tar.gz ] || curl -sLf --retry 3 -o $DOWNLOADS/helm.tar.gz https://storage.googleapis.com/kubernetes-helm/helm-v2.15.2-linux-amd64.tar.gz
tar -C /tmp/ -xf $DOWNLOADS/helm.tar.gz
cp /tmp/linux-amd64/helm $BIN/helm
[ -e $DOWNLOADS/helm.tar.gz ] || curl -sLf --retry 3 -o $DOWNLOADS/helm.tar.gz https://get.helm.sh/helm-v3.1.1-linux-amd64.tar.gz
mkdir -p /tmp/helm && tar -C /tmp/helm -xf $DOWNLOADS/helm.tar.gz
cp /tmp/helm/linux-amd64/helm $BIN/helm
helm version --client

View File

@@ -0,0 +1,7 @@
#!/bin/bash
set -eux -o pipefail
[ -e $DOWNLOADS/helm2.tar.gz ] || curl -sLf --retry 3 -o $DOWNLOADS/helm2.tar.gz https://storage.googleapis.com/kubernetes-helm/helm-v2.15.2-linux-amd64.tar.gz
mkdir -p /tmp/helm2 && tar -C /tmp/helm2 -xf $DOWNLOADS/helm2.tar.gz
cp /tmp/helm2/linux-amd64/helm $BIN/helm2
helm2 version --client

View File

@@ -20,4 +20,4 @@ report() {
trap 'report' EXIT
go test -v $* 2>&1 | tee $TEST_RESULTS/test.out
go test -failfast $* 2>&1 | tee $TEST_RESULTS/test.out

View File

@@ -14,6 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
export GO111MODULE=off
set -o errexit
set -o nounset
set -o pipefail

View File

@@ -20,13 +20,13 @@ spec:
- name: copyutil
image: argoproj/argocd:latest
imagePullPolicy: Always
command: [cp, /usr/local/bin/argocd-util, /shared]
command: [cp, -n, /usr/local/bin/argocd-util, /shared]
volumeMounts:
- mountPath: /shared
name: static-files
containers:
- name: dex
image: quay.io/dexidp/dex:v2.14.0
image: quay.io/dexidp/dex:v2.21.0
imagePullPolicy: Always
command: [/shared/argocd-util, rundex]
ports:

View File

@@ -12,4 +12,4 @@ bases:
images:
- name: argoproj/argocd
newName: argoproj/argocd
newTag: latest
newTag: v1.5.2

View File

@@ -35,6 +35,18 @@ spec:
operation:
description: Operation contains requested operation parameters.
properties:
initiatedBy:
description: OperationInitiator holds information about the operation
initiator
properties:
automated:
description: Automated is set to true if operation was initiated
automatically by the application controller.
type: boolean
username:
description: Name of a user who started operation.
type: string
type: object
sync:
description: SyncOperation contains sync operation details.
properties:
@@ -126,6 +138,21 @@ spec:
helm:
description: Helm holds helm specific options
properties:
fileParameters:
description: FileParameters are file parameters to the helm
template
items:
description: HelmFileParameter is a file parameter to
a helm template
properties:
name:
description: Name is the name of the helm parameter
type: string
path:
description: Path is the path value for the helm parameter
type: string
type: object
type: array
parameters:
description: Parameters are parameters to the helm template
items:
@@ -241,6 +268,11 @@ spec:
required:
- repoURL
type: object
syncOptions:
description: SyncOptions provide per-sync sync-options, e.g. Validate=false
items:
type: string
type: array
syncStrategy:
description: SyncStrategy describes how to perform the sync
properties:
@@ -391,6 +423,21 @@ spec:
helm:
description: Helm holds helm specific options
properties:
fileParameters:
description: FileParameters are file parameters to the helm
template
items:
description: HelmFileParameter is a file parameter to a helm
template
properties:
name:
description: Name is the name of the helm parameter
type: string
path:
description: Path is the path value for the helm parameter
type: string
type: object
type: array
parameters:
description: Parameters are parameters to the helm template
items:
@@ -518,6 +565,11 @@ spec:
description: 'SelfHeal enables auto-syncing if (default: false)'
type: boolean
type: object
syncOptions:
description: Options allow youe to specify whole app sync-options
items:
type: string
type: array
type: object
required:
- destination
@@ -626,6 +678,22 @@ spec:
helm:
description: Helm holds helm specific options
properties:
fileParameters:
description: FileParameters are file parameters to the
helm template
items:
description: HelmFileParameter is a file parameter to
a helm template
properties:
name:
description: Name is the name of the helm parameter
type: string
path:
description: Path is the path value for the helm
parameter
type: string
type: object
type: array
parameters:
description: Parameters are parameters to the helm template
items:
@@ -769,6 +837,18 @@ spec:
operation:
description: Operation is the original requested operation
properties:
initiatedBy:
description: OperationInitiator holds information about the
operation initiator
properties:
automated:
description: Automated is set to true if operation was initiated
automatically by the application controller.
type: boolean
username:
description: Name of a user who started operation.
type: string
type: object
sync:
description: SyncOperation contains sync operation details.
properties:
@@ -865,6 +945,23 @@ spec:
helm:
description: Helm holds helm specific options
properties:
fileParameters:
description: FileParameters are file parameters
to the helm template
items:
description: HelmFileParameter is a file parameter
to a helm template
properties:
name:
description: Name is the name of the helm
parameter
type: string
path:
description: Path is the path value for the
helm parameter
type: string
type: object
type: array
parameters:
description: Parameters are parameters to the helm
template
@@ -988,6 +1085,12 @@ spec:
required:
- repoURL
type: object
syncOptions:
description: SyncOptions provide per-sync sync-options,
e.g. Validate=false
items:
type: string
type: array
syncStrategy:
description: SyncStrategy describes how to perform the sync
properties:
@@ -1132,6 +1235,22 @@ spec:
helm:
description: Helm holds helm specific options
properties:
fileParameters:
description: FileParameters are file parameters to the
helm template
items:
description: HelmFileParameter is a file parameter
to a helm template
properties:
name:
description: Name is the name of the helm parameter
type: string
path:
description: Path is the path value for the helm
parameter
type: string
type: object
type: array
parameters:
description: Parameters are parameters to the helm template
items:
@@ -1389,6 +1508,22 @@ spec:
helm:
description: Helm holds helm specific options
properties:
fileParameters:
description: FileParameters are file parameters to the
helm template
items:
description: HelmFileParameter is a file parameter
to a helm template
properties:
name:
description: Name is the name of the helm parameter
type: string
path:
description: Path is the path value for the helm
parameter
type: string
type: object
type: array
parameters:
description: Parameters are parameters to the helm template
items:

View File

@@ -18,4 +18,4 @@ bases:
images:
- name: argoproj/argocd
newName: argoproj/argocd
newTag: latest
newTag: v1.5.2

View File

@@ -13,11 +13,5 @@ spec:
- "20"
- --operation-processors
- "10"
- --sentinel
- $(ARGOCD_REDIS_HA_ANNOUNCE_0_SERVICE):26379
- --sentinel
- $(ARGOCD_REDIS_HA_ANNOUNCE_1_SERVICE):26379
- --sentinel
- $(ARGOCD_REDIS_HA_ANNOUNCE_2_SERVICE):26379
- --sentinelmaster
- argocd
- --redis
- "argocd-redis-ha-haproxy:6379"

View File

@@ -25,11 +25,5 @@ spec:
command:
- uid_entrypoint.sh
- argocd-repo-server
- --sentinel
- $(ARGOCD_REDIS_HA_ANNOUNCE_0_SERVICE):26379
- --sentinel
- $(ARGOCD_REDIS_HA_ANNOUNCE_1_SERVICE):26379
- --sentinel
- $(ARGOCD_REDIS_HA_ANNOUNCE_2_SERVICE):26379
- --sentinelmaster
- argocd
- --redis
- "argocd-redis-ha-haproxy:6379"

View File

@@ -26,11 +26,5 @@ spec:
- argocd-server
- --staticassets
- /shared/app
- --sentinel
- $(ARGOCD_REDIS_HA_ANNOUNCE_0_SERVICE):26379
- --sentinel
- $(ARGOCD_REDIS_HA_ANNOUNCE_1_SERVICE):26379
- --sentinel
- $(ARGOCD_REDIS_HA_ANNOUNCE_2_SERVICE):26379
- --sentinelmaster
- argocd
- --redis
- "argocd-redis-ha-haproxy:6379"

View File

@@ -1,6 +1,6 @@
dependencies:
- name: redis-ha
repository: https://kubernetes-charts.storage.googleapis.com
version: 3.3.1
digest: sha256:3e273208c389589d3d8935ddc39bf245f72c3ea0b6d3e61c4dc0862b7c3839eb
generated: 2019-03-19T21:34:14.183861-07:00
version: 4.3.4
digest: sha256:d130faa98f99a99e503bce560bcec26e1dc0a988775a6609e39a8d855ec687d5
generated: "2020-02-20T10:42:01.98332-08:00"

View File

@@ -1,4 +1,4 @@
dependencies:
- name: redis-ha
version: 3.3.1
version: 4.3.4
repository: https://kubernetes-charts.storage.googleapis.com

View File

@@ -5,18 +5,20 @@ apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-redis-ha-configmap
namespace: default
labels:
heritage: Tiller
release: argocd
chart: redis-ha-3.3.1
chart: redis-ha-4.3.4
app: argocd-redis-ha
data:
redis.conf: |
dir "/data"
port 6379
maxmemory 0
maxmemory-policy volatile-lru
min-slaves-max-lag 5
min-slaves-to-write 1
min-replicas-max-lag 5
min-replicas-to-write 1
rdbchecksum yes
rdbcompression yes
repl-diskless-sync yes
@@ -24,9 +26,10 @@ data:
sentinel.conf: |
dir "/data"
sentinel down-after-milliseconds argocd 10000
sentinel failover-timeout argocd 180000
sentinel parallel-syncs argocd 5
sentinel down-after-milliseconds argocd 10000
sentinel failover-timeout argocd 180000
maxclients 10000
sentinel parallel-syncs argocd 5
init.sh: |
HOSTNAME="$(hostname)"
@@ -42,7 +45,7 @@ data:
set -eu
sentinel_update() {
echo "Updating sentinel config"
echo "Updating sentinel config with master $MASTER"
eval MY_SENTINEL_ID="\${SENTINEL_ID_$INDEX}"
sed -i "1s/^/sentinel myid $MY_SENTINEL_ID\\n/" "$SENTINEL_CONF"
sed -i "2s/^/sentinel monitor $MASTER_GROUP $1 $REDIS_PORT $QUORUM \\n/" "$SENTINEL_CONF"
@@ -85,7 +88,7 @@ data:
echo "Attempting to find master"
if [ "$(redis-cli -h "$MASTER" ping)" != "PONG" ]; then
echo "Can't ping master, attempting to force failover"
if redis-cli -h "$SERVICE" -p "$SENTINEL_PORT" sentinel failover "$MASTER_GROUP" | grep -q 'NOGOODSLAVE' ; then
if redis-cli -h "$SERVICE" -p "$SENTINEL_PORT" sentinel failover "$MASTER_GROUP" | grep -q 'NOGOODSLAVE' ; then
setup_defaults
return 0
fi
@@ -122,53 +125,140 @@ data:
if [ "${AUTH:-}" ]; then
echo "Setting auth values"
sed -i "s/replace-default-auth/$AUTH/" "$REDIS_CONF" "$SENTINEL_CONF"
ESCAPED_AUTH=$(echo "$AUTH" | sed -e 's/[\/&]/\\&/g');
sed -i "s/replace-default-auth/${ESCAPED_AUTH}/" "$REDIS_CONF" "$SENTINEL_CONF"
fi
echo "Ready..."
---
# Source: redis-ha/charts/redis-ha/templates/redis-ha-healthchecks.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-redis-ha-probes
labels:
heritage: Tiller
release: argocd
chart: redis-ha-3.3.1
app: argocd-redis-ha
data:
check-quorum.sh: |
#!/bin/sh
set -eu
MASTER_GROUP="argocd"
SENTINEL_PORT=26379
REDIS_PORT=6379
NUM_SLAVES=$(redis-cli -p "$SENTINEL_PORT" sentinel master argocd | awk '/num-slaves/{getline; print}')
MIN_SLAVES=1
haproxy.cfg: |-
defaults REDIS
mode tcp
timeout connect 4s
timeout server 30s
timeout client 30s
timeout check 2s
if [ "$1" = "$SENTINEL_PORT" ]; then
if redis-cli -p "$SENTINEL_PORT" sentinel ckquorum "$MASTER_GROUP" | grep -q NOQUORUM ; then
echo "ERROR: NOQUORUM. Sentinel quorum check failed, not enough sentinels found"
exit 1
fi
elif [ "$1" = "$REDIS_PORT" ]; then
if [ "$MIN_SLAVES" -gt "$NUM_SLAVES" ]; then
echo "Could not find enough replicating slaves. Needed $MIN_SLAVES but found $NUM_SLAVES"
exit 1
fi
listen health_check_http_url
bind :8888
mode http
monitor-uri /healthz
option dontlognull
# Check Sentinel and whether they are nominated master
backend check_if_redis_is_master_0
mode tcp
option tcp-check
tcp-check connect
tcp-check send PING\r\n
tcp-check expect string +PONG
tcp-check send SENTINEL\ get-master-addr-by-name\ argocd\r\n
tcp-check expect string REPLACE_ANNOUNCE0
tcp-check send QUIT\r\n
tcp-check expect string +OK
server R0 argocd-redis-ha-announce-0:26379 check inter 3s
server R1 argocd-redis-ha-announce-1:26379 check inter 3s
server R2 argocd-redis-ha-announce-2:26379 check inter 3s
# Check Sentinel and whether they are nominated master
backend check_if_redis_is_master_1
mode tcp
option tcp-check
tcp-check connect
tcp-check send PING\r\n
tcp-check expect string +PONG
tcp-check send SENTINEL\ get-master-addr-by-name\ argocd\r\n
tcp-check expect string REPLACE_ANNOUNCE1
tcp-check send QUIT\r\n
tcp-check expect string +OK
server R0 argocd-redis-ha-announce-0:26379 check inter 3s
server R1 argocd-redis-ha-announce-1:26379 check inter 3s
server R2 argocd-redis-ha-announce-2:26379 check inter 3s
# Check Sentinel and whether they are nominated master
backend check_if_redis_is_master_2
mode tcp
option tcp-check
tcp-check connect
tcp-check send PING\r\n
tcp-check expect string +PONG
tcp-check send SENTINEL\ get-master-addr-by-name\ argocd\r\n
tcp-check expect string REPLACE_ANNOUNCE2
tcp-check send QUIT\r\n
tcp-check expect string +OK
server R0 argocd-redis-ha-announce-0:26379 check inter 3s
server R1 argocd-redis-ha-announce-1:26379 check inter 3s
server R2 argocd-redis-ha-announce-2:26379 check inter 3s
# decide redis backend to use
#master
frontend ft_redis_master
bind *:6379
use_backend bk_redis_master
# Check all redis servers to see if they think they are master
backend bk_redis_master
mode tcp
option tcp-check
tcp-check connect
tcp-check send PING\r\n
tcp-check expect string +PONG
tcp-check send info\ replication\r\n
tcp-check expect string role:master
tcp-check send QUIT\r\n
tcp-check expect string +OK
use-server R0 if { srv_is_up(R0) } { nbsrv(check_if_redis_is_master_0) ge 2 }
server R0 argocd-redis-ha-announce-0:6379 check inter 3s fall 1 rise 1
use-server R1 if { srv_is_up(R1) } { nbsrv(check_if_redis_is_master_1) ge 2 }
server R1 argocd-redis-ha-announce-1:6379 check inter 3s fall 1 rise 1
use-server R2 if { srv_is_up(R2) } { nbsrv(check_if_redis_is_master_2) ge 2 }
server R2 argocd-redis-ha-announce-2:6379 check inter 3s fall 1 rise 1
haproxy_init.sh: |
HAPROXY_CONF=/data/haproxy.cfg
cp /readonly/haproxy.cfg "$HAPROXY_CONF"
for loop in $(seq 1 10); do
getent hosts argocd-redis-ha-announce-0 && break
echo "Waiting for service argocd-redis-ha-announce-0 to be ready ($loop) ..." && sleep 1
done
ANNOUNCE_IP0=$(getent hosts "argocd-redis-ha-announce-0" | awk '{ print $1 }')
if [ -z "$ANNOUNCE_IP0" ]; then
echo "Could not resolve the announce ip for argocd-redis-ha-announce-0"
exit 1
fi
sh /probes/readiness.sh "$1"
sed -i "s/REPLACE_ANNOUNCE0/$ANNOUNCE_IP0/" "$HAPROXY_CONF"
readiness.sh: |
#!/bin/sh
set -eu
CHECK_SERVER="$(redis-cli -p "$1" ping)"
if [ "${AUTH:-}" ]; then
echo "Setting auth values"
ESCAPED_AUTH=$(echo "$AUTH" | sed -e 's/[\/&]/\\&/g');
sed -i "s/REPLACE_AUTH_SECRET/${ESCAPED_AUTH}/" "$HAPROXY_CONF"
fi
for loop in $(seq 1 10); do
getent hosts argocd-redis-ha-announce-1 && break
echo "Waiting for service argocd-redis-ha-announce-1 to be ready ($loop) ..." && sleep 1
done
ANNOUNCE_IP1=$(getent hosts "argocd-redis-ha-announce-1" | awk '{ print $1 }')
if [ -z "$ANNOUNCE_IP1" ]; then
echo "Could not resolve the announce ip for argocd-redis-ha-announce-1"
exit 1
fi
sed -i "s/REPLACE_ANNOUNCE1/$ANNOUNCE_IP1/" "$HAPROXY_CONF"
if [ "$CHECK_SERVER" != "PONG" ]; then
echo "Server check failed with: $CHECK_SERVER"
exit 1
if [ "${AUTH:-}" ]; then
echo "Setting auth values"
ESCAPED_AUTH=$(echo "$AUTH" | sed -e 's/[\/&]/\\&/g');
sed -i "s/REPLACE_AUTH_SECRET/${ESCAPED_AUTH}/" "$HAPROXY_CONF"
fi
for loop in $(seq 1 10); do
getent hosts argocd-redis-ha-announce-2 && break
echo "Waiting for service argocd-redis-ha-announce-2 to be ready ($loop) ..." && sleep 1
done
ANNOUNCE_IP2=$(getent hosts "argocd-redis-ha-announce-2" | awk '{ print $1 }')
if [ -z "$ANNOUNCE_IP2" ]; then
echo "Could not resolve the announce ip for argocd-redis-ha-announce-2"
exit 1
fi
sed -i "s/REPLACE_ANNOUNCE2/$ANNOUNCE_IP2/" "$HAPROXY_CONF"
if [ "${AUTH:-}" ]; then
echo "Setting auth values"
ESCAPED_AUTH=$(echo "$AUTH" | sed -e 's/[\/&]/\\&/g');
sed -i "s/REPLACE_AUTH_SECRET/${ESCAPED_AUTH}/" "$HAPROXY_CONF"
fi
---
@@ -178,10 +268,25 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: argocd-redis-ha
namespace: default
labels:
heritage: Tiller
release: argocd
chart: redis-ha-3.3.1
chart: redis-ha-4.3.4
app: argocd-redis-ha
---
# Source: redis-ha/charts/redis-ha/templates/redis-haproxy-serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: argocd-redis-ha-haproxy
namespace: default
labels:
heritage: Tiller
release: argocd
chart: redis-ha-4.3.4
app: argocd-redis-ha
---
@@ -191,10 +296,11 @@ apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: argocd-redis-ha
namespace: default
labels:
heritage: Tiller
release: argocd
chart: redis-ha-3.3.1
chart: redis-ha-4.3.4
app: argocd-redis-ha
rules:
- apiGroups:
@@ -211,10 +317,11 @@ kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: argocd-redis-ha
namespace: default
labels:
heritage: Tiller
release: argocd
chart: redis-ha-3.3.1
chart: redis-ha-4.3.4
app: argocd-redis-ha
subjects:
- kind: ServiceAccount
@@ -232,11 +339,12 @@ apiVersion: v1
kind: Service
metadata:
name: argocd-redis-ha-announce-0
namespace: default
labels:
app: redis-ha
heritage: "Tiller"
release: "argocd"
chart: redis-ha-3.3.1
chart: redis-ha-4.3.4
annotations:
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
spec:
@@ -260,11 +368,12 @@ apiVersion: v1
kind: Service
metadata:
name: argocd-redis-ha-announce-1
namespace: default
labels:
app: redis-ha
heritage: "Tiller"
release: "argocd"
chart: redis-ha-3.3.1
chart: redis-ha-4.3.4
annotations:
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
spec:
@@ -288,11 +397,12 @@ apiVersion: v1
kind: Service
metadata:
name: argocd-redis-ha-announce-2
namespace: default
labels:
app: redis-ha
heritage: "Tiller"
release: "argocd"
chart: redis-ha-3.3.1
chart: redis-ha-4.3.4
annotations:
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
spec:
@@ -318,11 +428,12 @@ apiVersion: v1
kind: Service
metadata:
name: argocd-redis-ha
namespace: default
labels:
app: redis-ha
heritage: "Tiller"
release: "argocd"
chart: redis-ha-3.3.1
chart: redis-ha-4.3.4
annotations:
spec:
type: ClusterIP
@@ -339,6 +450,140 @@ spec:
selector:
release: argocd
app: redis-ha
---
# Source: redis-ha/charts/redis-ha/templates/redis-haproxy-service.yaml
apiVersion: v1
kind: Service
metadata:
name: argocd-redis-ha-haproxy
namespace: default
labels:
app: redis-ha
heritage: "Tiller"
release: "argocd"
chart: redis-ha-4.3.4
component: argocd-redis-ha-haproxy
annotations:
spec:
type: ClusterIP
ports:
- name: haproxy
port: 6379
protocol: TCP
targetPort: redis
selector:
release: argocd
app: redis-ha-haproxy
---
# Source: redis-ha/charts/redis-ha/templates/redis-haproxy-deployment.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
name: argocd-redis-ha-haproxy
namespace: default
labels:
app: redis-ha
heritage: "Tiller"
release: "argocd"
chart: redis-ha-4.3.4
spec:
strategy:
type: RollingUpdate
revisionHistoryLimit: 1
replicas: 3
selector:
matchLabels:
app: redis-ha-haproxy
release: argocd
template:
metadata:
name: argocd-redis-ha-haproxy
labels:
app: redis-ha-haproxy
release: argocd
annotations:
checksum/config: 790be9eae7c7e468c497c0256949ab96cb3f14b935c6702424647c3c60fba91c
spec:
# Needed when using unmodified rbac-setup.yml
serviceAccountName: argocd-redis-ha-haproxy
nodeSelector:
{}
tolerations:
null
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: redis-ha-haproxy
release: argocd
topologyKey: kubernetes.io/hostname
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: redis-ha-haproxy
release: argocd
topologyKey: failure-domain.beta.kubernetes.io/zone
initContainers:
- name: config-init
image: haproxy:2.0.4
imagePullPolicy: IfNotPresent
resources:
{}
command:
- sh
args:
- /readonly/haproxy_init.sh
volumeMounts:
- name: config-volume
mountPath: /readonly
readOnly: true
- name: data
mountPath: /data
securityContext:
fsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
containers:
- name: haproxy
image: haproxy:2.0.4
imagePullPolicy: IfNotPresent
livenessProbe:
httpGet:
path: /healthz
port: 8888
initialDelaySeconds: 5
periodSeconds: 3
ports:
- name: redis
containerPort: 6379
resources:
{}
volumeMounts:
- name: data
mountPath: /usr/local/etc/haproxy
- name: shared-socket
mountPath: /run/haproxy
volumes:
- name: config-volume
configMap:
name: argocd-redis-ha-configmap
- name: shared-socket
emptyDir: {}
- name: data
emptyDir: {}
---
# Source: redis-ha/charts/redis-ha/templates/redis-ha-statefulset.yaml
@@ -346,11 +591,13 @@ apiVersion: apps/v1
kind: StatefulSet
metadata:
name: argocd-redis-ha-server
namespace: default
labels:
argocd-redis-ha: replica
app: redis-ha
heritage: "Tiller"
release: "argocd"
chart: redis-ha-3.3.1
chart: redis-ha-4.3.4
spec:
selector:
matchLabels:
@@ -364,11 +611,11 @@ spec:
template:
metadata:
annotations:
checksum/init-config: 06440ee4a409be2aa01dfa08c14dd964fe3bad2ada57da1a538ad5cd771a045f
checksum/probe-config: 4b9888f173366e436f167856ee3469e8c1fd5221e29caa2129373db23578ec10
checksum/init-config: 552ee3bec8fe5d9d865e371f7b615c6d472253649eb65d53ed4ae874f782647c
labels:
release: argocd
app: redis-ha
argocd-redis-ha: replica
spec:
affinity:
podAntiAffinity:
@@ -377,6 +624,7 @@ spec:
matchLabels:
app: redis-ha
release: argocd
argocd-redis-ha: replica
topologyKey: kubernetes.io/hostname
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
@@ -385,8 +633,8 @@ spec:
matchLabels:
app: redis-ha
release: argocd
argocd-redis-ha: replica
topologyKey: failure-domain.beta.kubernetes.io/zone
securityContext:
fsGroup: 1000
runAsNonRoot: true
@@ -395,7 +643,7 @@ spec:
serviceAccountName: argocd-redis-ha
initContainers:
- name: config-init
image: redis:5.0.3-alpine
image: redis:5.0.6-alpine
imagePullPolicy: IfNotPresent
resources:
{}
@@ -406,13 +654,13 @@ spec:
- /readonly-config/init.sh
env:
- name: SENTINEL_ID_0
value: e791a161cb06f0d3eb0cc392117d34cf0eae9d71
value: 25b71bd9d0e4a51945d8422cab53f27027397c12
- name: SENTINEL_ID_1
value: d9b3204a90597a7500530efd881942d8145996ac
value: 896627000a81c7bdad8dbdcffd39728c9c17b309
- name: SENTINEL_ID_2
value: d9deb539c0402841c2492e9959c8086602fa4284
value: 3acbca861108bc47379b71b1d87d1c137dce591f
volumeMounts:
- name: config
@@ -422,22 +670,17 @@ spec:
mountPath: /data
containers:
- name: redis
image: redis:5.0.3-alpine
image: redis:5.0.6-alpine
imagePullPolicy: IfNotPresent
command:
- redis-server
args:
- /data/conf/redis.conf
env:
livenessProbe:
exec:
command: [ "sh", "/probes/readiness.sh", "6379"]
tcpSocket:
port: 6379
initialDelaySeconds: 15
periodSeconds: 5
readinessProbe:
exec:
command: ["sh", "/probes/readiness.sh", "6379"]
initialDelaySeconds: 15
periodSeconds: 5
resources:
{}
@@ -447,25 +690,17 @@ spec:
volumeMounts:
- mountPath: /data
name: data
- mountPath: /probes
name: probes
- name: sentinel
image: redis:5.0.3-alpine
image: redis:5.0.6-alpine
imagePullPolicy: IfNotPresent
command:
- redis-sentinel
args:
- /data/conf/sentinel.conf
livenessProbe:
exec:
command: [ "sh", "/probes/readiness.sh", "26379"]
tcpSocket:
port: 26379
initialDelaySeconds: 15
periodSeconds: 5
readinessProbe:
exec:
command: ["sh", "/probes/readiness.sh", "26379"]
initialDelaySeconds: 15
periodSeconds: 5
resources:
{}
@@ -475,21 +710,27 @@ spec:
volumeMounts:
- mountPath: /data
name: data
- mountPath: /probes
name: probes
volumes:
- name: config
configMap:
name: argocd-redis-ha-configmap
- name: probes
configMap:
name: argocd-redis-ha-probes
- name: data
emptyDir: {}
---
# Source: redis-ha/charts/redis-ha/templates/redis-auth-secret.yaml
---
# Source: redis-ha/charts/redis-ha/templates/redis-ha-exporter-script-configmap.yaml
---
# Source: redis-ha/charts/redis-ha/templates/redis-ha-pdb.yaml
---
# Source: redis-ha/charts/redis-ha/templates/redis-ha-servicemonitor.yaml
---
# Source: redis-ha/charts/redis-ha/templates/redis-haproxy-servicemonitor.yaml

View File

@@ -5,3 +5,5 @@ redis-ha:
masterGroupName: argocd
config:
save: "\"\""
haproxy:
enabled: true

View File

@@ -1,6 +1,6 @@
#!/bin/sh -xe
helm dependency update ./chart --skip-refresh
helm2 dependency update ./chart --skip-refresh
# This step is necessary because we do not want the helm tests to be included
templates=$(tar -tf ./chart/charts/redis-ha-*.tgz | grep 'redis-ha/templates/redis-.*.yaml')
@@ -12,8 +12,10 @@ done
AUTOGENMSG="# This is an auto-generated file. DO NOT EDIT"
echo "${AUTOGENMSG}" > ./chart/upstream.yaml
helm template ./chart \
helm2 template ./chart \
--name argocd \
--values ./chart/values.yaml \
${helm_execute} \
>> ./chart/upstream.yaml
>> ./chart/upstream_orig.yaml
sed -e 's/check inter 1s/check inter 3s/' ./chart/upstream_orig.yaml >> ./chart/upstream.yaml && rm ./chart/upstream_orig.yaml

View File

@@ -11,11 +11,6 @@ patchesJson6902:
kind: ConfigMap
name: argocd-redis-ha-configmap
path: overlays/modify-labels.yaml
- target:
version: v1
kind: ConfigMap
name: argocd-redis-ha-probes
path: overlays/modify-labels.yaml
- target:
version: v1
kind: Service
@@ -59,6 +54,22 @@ patchesJson6902:
kind: RoleBinding
name: argocd-redis-ha
path: overlays/modify-labels.yaml
- target:
version: v1
kind: ServiceAccount
name: argocd-redis-ha-haproxy
path: overlays/haproxy-modify-labels.yaml
- target:
version: v1
kind: Service
name: argocd-redis-ha-haproxy
path: overlays/haproxy-modify-labels.yaml
- target:
group: apps
version: v1
kind: Deployment
name: argocd-redis-ha-haproxy
path: overlays/haproxy-modify-labels.yaml
# add pod template labels
- target:
@@ -67,6 +78,12 @@ patchesJson6902:
kind: StatefulSet
name: argocd-redis-ha-server
path: overlays/statefulset-labels.yaml
- target:
group: apps
version: v1
kind: Deployment
name: argocd-redis-ha-haproxy
path: overlays/deployment-labels.yaml
# update service selectors to match
- target:
@@ -89,27 +106,73 @@ patchesJson6902:
kind: Service
name: argocd-redis-ha
path: overlays/service-selector.yaml
- target:
version: v1
kind: Service
name: argocd-redis-ha-haproxy
path: overlays/haproxy-service-selector.yaml
vars:
- name: ARGOCD_REDIS_HA_ANNOUNCE_0_SERVICE
objref:
- target:
version: v1
kind: ConfigMap
name: argocd-redis-ha-configmap
path: overlays/remove-namespace.yaml
- target:
version: v1
kind: ServiceAccount
name: argocd-redis-ha
path: overlays/remove-namespace.yaml
- target:
version: v1
kind: ServiceAccount
name: argocd-redis-ha-haproxy
path: overlays/remove-namespace.yaml
- target:
group: rbac.authorization.k8s.io
version: v1
kind: Role
name: argocd-redis-ha
path: overlays/remove-namespace.yaml
- target:
group: rbac.authorization.k8s.io
version: v1
kind: RoleBinding
name: argocd-redis-ha
path: overlays/remove-namespace.yaml
- target:
version: v1
kind: Service
name: argocd-redis-ha-announce-0
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: ARGOCD_REDIS_HA_ANNOUNCE_1_SERVICE
objref:
path: overlays/remove-namespace.yaml
- target:
version: v1
kind: Service
name: argocd-redis-ha-announce-1
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: ARGOCD_REDIS_HA_ANNOUNCE_2_SERVICE
objref:
path: overlays/remove-namespace.yaml
- target:
version: v1
kind: Service
name: argocd-redis-ha-announce-2
apiVersion: v1
fieldref:
fieldpath: metadata.name
path: overlays/remove-namespace.yaml
- target:
version: v1
kind: Service
name: argocd-redis-ha
path: overlays/remove-namespace.yaml
- target:
version: v1
kind: Service
name: argocd-redis-ha-haproxy
path: overlays/remove-namespace.yaml
- target:
group: apps
version: v1
kind: Deployment
name: argocd-redis-ha-haproxy
path: overlays/remove-namespace.yaml
- target:
group: apps
version: v1
kind: StatefulSet
name: argocd-redis-ha-server
path: overlays/remove-namespace.yaml

View File

@@ -0,0 +1,16 @@
- op: replace
path: /spec/selector/matchLabels
value:
app.kubernetes.io/name: argocd-redis-ha-haproxy
- op: replace
path: /spec/template/metadata/labels
value:
app.kubernetes.io/name: argocd-redis-ha-haproxy
- op: replace
path: /spec/template/spec/affinity/podAntiAffinity/preferredDuringSchedulingIgnoredDuringExecution/0/podAffinityTerm/labelSelector/matchLabels
value:
app.kubernetes.io/name: argocd-redis-ha-haproxy
- op: replace
path: /spec/template/spec/affinity/podAntiAffinity/requiredDuringSchedulingIgnoredDuringExecution/0/labelSelector/matchLabels
value:
app.kubernetes.io/name: argocd-redis-ha-haproxy

View File

@@ -0,0 +1,6 @@
- op: replace
path: /metadata/labels
value:
app.kubernetes.io/name: argocd-redis-ha-haproxy
app.kubernetes.io/component: redis
app.kubernetes.io/part-of: argocd

View File

@@ -0,0 +1,3 @@
- {op: remove, path: /spec/selector/app}
- {op: remove, path: /spec/selector/release}
- {op: add, path: /spec/selector/app.kubernetes.io~1name, value: argocd-redis-ha-haproxy}

View File

@@ -0,0 +1 @@
- {op: remove, path: /metadata/namespace}

File diff suppressed because it is too large Load Diff

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