1
0
mirror of synced 2026-03-01 11:16:56 +00:00

Compare commits

..

133 Commits

Author SHA1 Message Date
Hidde Beydals
bc5fbb9fa5 Merge pull request #774 from fluxcd/doc-helm-storage-ns 2021-01-26 14:15:00 +01:00
Hidde Beydals
3e9749c6b1 Document StorageNamespace in Helm migration guide
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-26 14:05:54 +01:00
Hidde Beydals
eaf08fbe90 Merge pull request #781 from fluxcd/docs-image-update 2021-01-26 14:05:47 +01:00
Hidde Beydals
df411cdb88 Update alpha warning
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-26 13:54:28 +01:00
Hidde Beydals
a83c26a864 Provide link to CalVer, build ID, etc. policies
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-26 13:54:28 +01:00
Hidde Beydals
6aa853491c Add image automation to menu
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-26 13:54:28 +01:00
Hidde Beydals
3af1d7a5b8 Merge pull request #771 from fluxcd/update-components 2021-01-26 13:53:47 +01:00
fluxcdbot
c7c57f6717 Update toolkit components 2021-01-26 12:32:15 +00:00
Stefan Prodan
cbb97768d1 Merge pull request #777 from fluxcd/dedicated-service-accounts
Add a dedicated service account per controller
2021-01-26 14:31:38 +02:00
Stefan Prodan
2bb40d335b Replace the default service account in docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-26 12:57:00 +02:00
Stefan Prodan
1b581d6f51 Add dedicated service accounts per controller
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-26 12:27:58 +02:00
Stefan Prodan
c219eb2883 Merge pull request #776 from SomtochiAma/refactor-get-commands
Refactor get command for kustomization and helmrelease
2021-01-26 11:55:27 +02:00
Somtochi Onyekwere
65a2c87b5a Refactor get cmd for kustomization and helmrelease
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-26 10:15:35 +01:00
Stefan Prodan
13aa523c37 Merge pull request #761 from SomtochiAma/cli-refactoring
Refactor get source commands
2021-01-26 10:42:49 +02:00
Somtochi Onyekwere
584f0eea58 Refactor get source commands
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-26 09:26:55 +01:00
Stefan Prodan
b5ebdb16b2 Merge pull request #773 from nairb774/sharp_payne
Add permissions for controller leader election
2021-01-25 23:35:19 +02:00
Brian Atkinson
a18f84c27b Add permissions for controller leader election.
The v0.8.0 version of the controller-runtime uses both config maps and
leases to perform leader election. These permissions seem to be in the
individual controller repos, but not here. For example
2d38de8779/config/rbac/leader_election_role.yaml (L33-L44)

Signed-off-by: Brian Atkinson <brian@atkinson.mn>
2021-01-25 10:15:57 -08:00
Stefan Prodan
eb86505375 Merge pull request #769 from fluxcd/update-release-doc
Add the image automation controllers to release doc
2021-01-25 15:31:31 +02:00
Stefan Prodan
984f1c8669 Add the image automation controllers to release doc
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-25 15:21:43 +02:00
Hidde Beydals
c7378edabc Merge pull request #765 from fluxcd/update-controllers 2021-01-22 16:35:30 +00:00
Hidde Beydals
ac6c6e3a30 Incorporate required API changes
* Use `LocalObjectReference` and `NamespacedObjectKindReference`
  from `meta` package, as required by controller API changes.
* Remove `Update` field from created `ImageUpdateAutomation`,
  as the API changed and the default is now defined in the Custom
  Resource Definition.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-22 17:21:36 +01:00
fluxcdbot
1bca31f32c Update toolkit components 2021-01-22 16:07:19 +00:00
Hidde Beydals
28d099a6b2 Merge pull request #741 from fluxcd/include-image-spec-docs 2021-01-22 16:06:33 +00:00
Michael Bridgen
6a2b53fbf5 Put image specs and refs in place
This adds the image controller specs and refs to the workflow that
prepares the docs, and links to them in the index.

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-01-22 16:49:18 +01:00
Michael Bridgen
7568f301b8 Make home for image-* component docs
This has a description of the controllers, and is where the API specs
and refs will get copied to.

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-01-22 16:49:18 +01:00
Stefan Prodan
6add511447 Merge pull request #755 from SomtochiAma/cli-refactoring
Refactor cmd global variables into structs
2021-01-22 12:27:39 +02:00
Somtochi Onyekwere
a7586e69fd Refactor cmd global variables into structs
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-22 10:42:31 +01:00
Stefan Prodan
77db369213 Merge pull request #757 from fluxcd/gitlab-fix
Update fluxcd/pkg/git to v0.2.3
2021-01-21 18:12:11 +02:00
Stefan Prodan
2eb6a0513e Update fluxcd/pkg/git to v0.2.3
Fixes Gitlab bootstrap when used with a project token

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-21 17:51:07 +02:00
Stefan Prodan
38468c72db Merge pull request #750 from SomtochiAma/kms-docs
Update guide for mozilla sops
2021-01-20 17:04:56 +02:00
Somtochi Onyekwere
5f759200c6 update guide for mozilla sops
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-20 15:54:26 +01:00
Daniel Holbach
81f68157fa Merge pull request #753 from dholbach/f-community-24
move talk info, part of fluxcd/community#24
2021-01-20 15:21:15 +01:00
Daniel Holbach
0f3e8abf06 move talk info, part of fluxcd/community#24
Signed-off-by: Daniel Holbach <daniel@weave.works>
2021-01-20 15:07:08 +01:00
Stefan Prodan
fcadd5312d Merge pull request #747 from mewzherder/patch-8
Clarify options on our GH Discussions page
2021-01-20 10:59:22 +02:00
mewzherder
6e32820910 Clarify options on our GH Discussions page
Signed-off-by: mewzherder <tamao@weave.works>
2021-01-19 22:27:50 -08:00
Hidde Beydals
8499269bab Merge pull request #744 from fluxcd/update-components
Update kustomize-controller to v0.6.3
2021-01-19 16:47:52 +01:00
fluxcdbot
72122120cb Update toolkit components 2021-01-19 15:37:38 +00:00
Hidde Beydals
2bbcb95f4f Merge pull request #728 from fluxcd/update-components
Update toolkit components
2021-01-19 14:29:22 +01:00
fluxcdbot
19982fa4a6 Update toolkit components 2021-01-19 13:04:46 +00:00
Hidde Beydals
41cf38c6a7 Merge pull request #740 from fluxcd/fluxcd/pkg/git-v0.2.2
Update fluxcd/pkg/git to v0.2.2
2021-01-19 14:03:43 +01:00
Stefan Prodan
16e74647eb Update fluxcd/pkg/git to v0.2.2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-19 14:36:11 +02:00
Hidde Beydals
53cdcbc4ee Merge pull request #722 from fluxcd/workflow-tweaks
Fire 'Update Components' workflow on push to main
2021-01-15 17:34:56 +01:00
Hidde Beydals
eb2535e066 Fire 'Update Components' workflow on push to main
This results in the automatic rebase of an outstanding PR on merges to
this branch, removing the need of manually firing it.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-15 17:20:16 +01:00
Hidde Beydals
f5c29a7a72 Merge pull request #720 from fluxcd/update-components
Update kustomize-controller to v0.6.2
2021-01-15 17:16:50 +01:00
fluxcdbot
e243df93f1 Update toolkit components 2021-01-15 16:02:02 +00:00
Hidde Beydals
388642d9dd Merge pull request #721 from fluxcd/git-impl-fixes 2021-01-15 17:01:08 +01:00
Hidde Beydals
9e1db06936 Move Git implementation validation to custom flag
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-15 16:50:23 +01:00
Hidde Beydals
a260403334 Remove GitImplementation default
As the field in the CRD is optional.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-15 16:49:26 +01:00
Stefan Prodan
6396b25886 Merge pull request #641 from jonaskello/patch-1
Link docs how to get zsh/fish/ps completion to work in getting-started
2021-01-15 15:12:11 +02:00
Jonas Kello
ca480164b7 Merge branch 'main' into patch-1 2021-01-15 13:55:42 +01:00
Jonas Kello
714f9df3cf Link docs how to get zsh completion to work in getting-started
I tried to make completions work in zsh by just adding the same code as for the bash example but of course switching bash for zsh but it did not work. When I googled and dug deeper I finally found the answer in the deeper docs here:

https://github.com/fluxcd/flux2/blob/main/docs/cmd/flux_completion_zsh.md

The command in there works if I add it to my .zshrc file. I think linking to these specific docs may prevent others from just assuming it will work the same in zsh.

Signed-off-by: Jonas Kello <jonas.kello@gmail.com>
2021-01-15 13:17:29 +01:00
Hidde Beydals
6a7f1e7d48 Merge pull request #714 from fluxcd/tag-filter 2021-01-15 12:32:07 +01:00
Stefan Prodan
bcdce02b78 Add image tags regex filter arg to policy command
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-15 13:24:59 +02:00
Stefan Prodan
2f0835b655 Make branch arg required for image updates
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-15 13:22:43 +02:00
Hidde Beydals
36bafa23df Merge pull request #709 from SomtochiAma/gcp-kms-docs
Add GCP docs for Mozilla SOPS
2021-01-15 12:21:59 +01:00
Somtochi Onyekwere
db611549f2 Add GCP docs for Mozilla SOPS
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-15 12:13:00 +01:00
Hidde Beydals
5d4cdcc207 Merge pull request #713 from fluxcd/doc-fixes
docs: styling of hint blocks
2021-01-15 12:12:32 +01:00
Hidde Beydals
a3b9c094b6 docs: styling of hint blocks
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-15 12:03:55 +01:00
Hidde Beydals
f82174adae Merge pull request #680 from fluxcd/goreleaser-project-name
Configure `project_name` for GoReleaser
2021-01-15 12:01:55 +01:00
Hidde Beydals
c7080d2834 Configure project_name for GoReleaser
This causes the format of the checksum file generated during the release
to change from `flux2_*_checksums.txt` to `flux_*_checksums.txt`.

The configuration change is made through `project_name` and not via the
`checksum.name_template` setting, because a single checksum file is
generated during the release process.

The download and/or installation script in `install/flux.sh` has been
adapted to assume the new filename starting with MINOR version `0.6.0`.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-15 11:54:18 +01:00
Stefan Prodan
381127d413 Merge pull request #712 from fluxcd/reconcile-request-annotation
Use reconcile request annotation
2021-01-15 12:49:56 +02:00
Stefan Prodan
f6fa468acb Use reconcile request annotation
Replace deprecated `ReconcileAtAnnotation` annotation with `ReconcileRequestAnnotation`

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-15 12:41:13 +02:00
Hidde Beydals
9228130f92 Merge pull request #684 from fluxcd/multi-arch-image
Deprecate arch flags in favor of multi-arch images
2021-01-15 11:40:24 +01:00
Hidde Beydals
207c50ceac Deprecate arch flags in favor of multi-arch images
This commit deprecates the architecture flag (`--arch`) for the install
and bootstrap commands, in favor of the bundled multi-arch images that
will be available for the next MINOR range of GOTK controller releases.

Summary of changes:

* `*Arch` variables have been marked as deprecated for both commands.
* `-arm64` suffix is no longer selectively added to the image definition
  of a component's `Deployment`.
* `kubernetes.io/arch` node selector with the defined value has been
  removed from the components' `Deployment`s.
* `Arch` has been removed from the available `Options` in
  `manifestgen/install`.
* Documentation references have been changed to highlight existence
  of multi-arch images and supported architectures.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-15 11:25:20 +01:00
Hidde Beydals
c3255a6e1e Merge pull request #711 from fluxcd/image-policy-e2e 2021-01-15 11:24:51 +01:00
Stefan Prodan
5e1c93a167 Add e2e tests for image repository and policy
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-15 12:03:47 +02:00
Hidde Beydals
43c33a0cc3 Merge pull request #686 from fluxcd/update-components
Update toolkit components
2021-01-15 11:02:14 +01:00
fluxcdbot
f5117329e4 Update toolkit components 2021-01-15 09:49:23 +00:00
Hidde Beydals
f7c62d12a5 Merge pull request #651 from Sijoma/main
Typo fix in image-update documentation
2021-01-15 10:43:12 +01:00
Simon Zengerling
fe5f181706 fix(image-update.md): typo maker => marker
Signed-off-by: Simon Zengerling <simon.zengerling@lht.dlh.de>
2021-01-15 10:26:28 +01:00
Stefan Prodan
cc09b29a2e Merge pull request #705 from SomtochiAma/custom-domain-gitlab
Update pkg/git to v0.2.1
2021-01-15 09:49:05 +02:00
Somtochi Onyekwere
406601eead Update pkg/git to v0.2.2
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-14 20:15:17 +01:00
Stefan Prodan
341d860c51 Merge pull request #708 from fluxcd/allow-egress-between-flux-pods
Allow egress traffic for controller pods
2021-01-14 14:17:15 +02:00
Stefan Prodan
8214bb8e33 Allow egress traffic for controller pods
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-14 13:38:38 +02:00
Stefan Prodan
884e3c678c Merge pull request #702 from fluxcd/feature/git-implementation
Add git implementation to generate sync options
2021-01-14 10:49:37 +02:00
Philip Laine
3b249dfe69 Change default to use const
Signed-off-by: Philip Laine <philip.laine@gmail.com>
2021-01-14 00:21:59 +01:00
Philip Laine
d236a9af57 Add git implementation to generate sync options
Signed-off-by: Philip Laine <philip.laine@gmail.com>
2021-01-13 23:44:29 +01:00
Hidde Beydals
ad9b0ae067 Merge pull request #698 from staceypotter/patch-6
Moved 11 Jan talk from Upcoming to Featured
2021-01-13 19:47:33 +01:00
Stacey Potter
31f166cd02 Moved 11 Jan talk from Upcoming to Featured
Updated and moved this from Upcoming Events: 
- 11 Jan 2021 - [Helm + GitOps = ️ with Scott Rigby](https://www.meetup.com/GitOps-Community/events/275348736/)

To this in Featured Talks:
- 11 Jan 2021 - [Helm + GitOps = ️ with Scott Rigby](https://youtu.be/YG8jMFrYQvM)

Signed-off-by: Stacey Potter <50154848+staceypotter@users.noreply.github.com>
2021-01-13 16:33:42 +01:00
Hidde Beydals
5685ebc3a5 Merge pull request #678 from staceypotter/patch-5
Added Jan 25 Meetup to Upcoming Events section
2021-01-13 16:32:39 +01:00
Stacey Potter
46bcf5da33 Added Jan 25 Meetup to Upcoming Events section
Signed-off-by: Stacey Potter <50154848+staceypotter@users.noreply.github.com>
2021-01-13 15:49:35 +01:00
Michael Bridgen
1784d15f36 Merge pull request #696 from fluxcd/controller-runtime-070
Update to controller-runtime 0.7.0
2021-01-13 11:50:58 +00:00
Michael Bridgen
cafce536bb Rename asRuntime* -> asClient*
For the avoidance of misdirection.

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-01-13 11:38:02 +00:00
Michael Bridgen
d03280a12f Update to controller-runtime 0.7.0
controller-runtime methods now accept `client.Object` and
`client.ObjectList` rather than `runtime.Object`. This means the
adapter interfaces need to change signature, but happily, little else.

Since the list adapter is now distinct to the object adapter, `len()`
can go there instead of the command-specific interfaces.

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-01-13 11:25:40 +00:00
Stefan Prodan
b30ef523f8 Merge pull request #688 from SomtochiAma/gcp-docs
Add GCR auth to image update guide
2021-01-13 12:25:32 +02:00
Somtochi Onyekwere
a6a303629a Add doc for authenticating gcr
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-13 11:15:13 +01:00
Stefan Prodan
61e79ef793 Merge pull request #694 from fluxcd/fix-hr-docs
Remove deprecated source behaviour
2021-01-13 11:45:39 +02:00
Stefan Prodan
f632abd8fa Remove deprecated source behaviour
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-13 11:26:00 +02:00
Philip Laine
c3911fe490 Merge pull request #668 from fluxcd/update/commit-status-guide
Update commit status notification guide
2021-01-12 22:52:59 +01:00
Philip Laine
505701e1c6 Fix cluster path in examples
Signed-off-by: Philip Laine <philip.laine@gmail.com>
2021-01-12 22:15:51 +01:00
Philip Laine
67643e7487 Minimize deployment yaml
Signed-off-by: Philip Laine <philip.laine@gmail.com>
2021-01-12 15:21:28 +01:00
Philip Laine
a962c17adb Add gitlab screenshots
Signed-off-by: Philip Laine <philip.laine@gmail.com>
2021-01-12 15:21:28 +01:00
Philip Laine
479b4b5859 Update commit status notification guide
Signed-off-by: Philip Laine <philip.laine@gmail.com>
2021-01-12 15:21:28 +01:00
Hidde Beydals
57f8cf85ca Merge pull request #687 from Kissy/main
docs: update sealed-secrets chart URL
2021-01-12 15:16:05 +01:00
Guillaume Le Biller
dd2c20b225 Update sealed-secrets chart URL
Signed-off-by: Guillaume Le Biller <glebiller@Traveldoo.com>
2021-01-12 15:03:03 +01:00
Stefan Prodan
9da427a515 Merge pull request #682 from SomtochiAma/multiple-config-files
Check for multiple files in KUBECONFIG variable
2021-01-12 11:39:53 +02:00
Somtochi Onyekwere
604773e866 check for multiple files in KUBECONFIG variable
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-12 10:26:29 +01:00
Hidde Beydals
1331f5260a Merge pull request #683 from fluxcd/fix-azure-url
Fix Azure DevOps URL in docs
2021-01-11 20:13:24 +01:00
Stefan Prodan
65d0f3569c Fix Azure DevOps URL in docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-11 19:51:00 +02:00
Stefan Prodan
ba522877ec Merge pull request #681 from SomtochiAma/gitlab-path
Fix GitLab bootstrap when used with sub-groups
2021-01-11 17:36:18 +02:00
Somtochi Onyekwere
4b63ccf140 Update fluxcd/pkg/git
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-11 16:17:07 +01:00
Somtochi Onyekwere
4fcf93306a Gets actual path for owner
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-11 15:02:02 +01:00
Hidde Beydals
96d8ec2016 Merge pull request #679 from staceypotter/patch-4
Added Jan 25 Meetup to Upcoming Events section
2021-01-11 09:55:59 +01:00
Stacey Potter
3697a5e348 Added Jan 25 Meetup to Upcoming Events section
Signed-off-by: Stacey Potter <50154848+staceypotter@users.noreply.github.com>
2021-01-10 14:07:09 -05:00
Stefan Prodan
084c587c0e Merge pull request #675 from fluxcd/docs-fixes
Add generated manifests to get started guide
2021-01-08 17:57:09 +02:00
Stefan Prodan
dcb505045e Add generated manifests to get started guide
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-08 17:46:00 +02:00
Stefan Prodan
0aeb3128ed Fix semver range prerelease examples
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-08 17:45:31 +02:00
Stefan Prodan
c61cfcbd18 Merge pull request #608 from SomtochiAma/getting-started-guide
Simplify the getting started guide
2021-01-08 16:16:07 +02:00
Somtochi Onyekwere
eba2dd36e0 Update getting started guide
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-08 14:46:49 +01:00
Stefan Prodan
2a75754561 Merge pull request #673 from fluxcd/doc-signoff
Add DCO signoff ref to contributing doc
2021-01-08 13:52:09 +02:00
Stefan Prodan
d03944893d Add DCO signoff ref to contributing doc
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-08 13:12:07 +02:00
Stefan Prodan
884c6ebd37 Merge pull request #672 from fluxcd/create-secret-helm
Add create secret helm command
2021-01-08 12:51:34 +02:00
Stefan Prodan
331ac3f031 Add create secret helm command
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-08 12:36:11 +02:00
Stefan Prodan
ccc84a8367 Merge pull request #671 from SomtochiAma/incorrect-tf-path
Fix manifests path on Windows
2021-01-08 12:23:31 +02:00
Somtochi Onyekwere
daeb41c31b Uses path instead of filepath
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-08 11:13:27 +01:00
Stefan Prodan
17bda9c110 Merge pull request #670 from fluxcd/fix-secret-git
Map ecdsa/ed25519 args to create secret
2021-01-08 11:34:20 +02:00
Stefan Prodan
febedaad8f Map ecdsa/ed25519 args to create secret
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-08 11:20:36 +02:00
Stefan Prodan
d1357dff1f Merge pull request #664 from fluxcd/source-watcher
Update dev guide to point to fluxcd/source-watcher
2021-01-07 14:35:45 +02:00
Stefan Prodan
102552427f Update dev guide to point to fluxcd/source-watcher
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-07 14:19:19 +02:00
Michael Bridgen
f33898265d Merge pull request #663 from fluxcd/update-img-roadmap
Cross off tasks in the image automation roadmap
2021-01-07 12:06:04 +00:00
Michael Bridgen
57bdaf939a Cross off tasks in the image automation roadmap
Specifically:
 - integration into `flux` CLI
 - guide to how to use the controllers

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-01-07 11:45:46 +00:00
Stefan Prodan
981fed111b Merge pull request #660 from SomtochiAma/check-bootstrap-path
Checks if bootstrap path differs
2021-01-07 12:08:54 +02:00
Somtochi Onyekwere
3a4a2002d4 Corrects typo
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-07 10:44:40 +01:00
Somtochi Onyekwere
b8d4af5538 Inform user of path being used
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-07 10:30:17 +01:00
Somtochi Onyekwere
0646538cef Checks if bootstrap path differs
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-07 10:22:13 +01:00
Stefan Prodan
70a87247e2 Merge pull request #658 from SomtochiAma/incorrect-windows-file-path
Coverts backward slash to forward slash in path flag
2021-01-07 11:17:51 +02:00
Somtochi Onyekwere
61129c6b6a Coverts backward slash to forward slash in path flag
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-07 09:29:37 +01:00
Aurel Canciu
c158f95130 Merge pull request #657 from fluxcd/image-repo-auth-docs
Add documentation for ECR authentication
2021-01-06 18:38:41 +02:00
Aurel Canciu
ad90d37f14 Add documentation for ECR authentication
Document a workaround solution for users to rely on until native image
repository authentication is implemented for supported cloud providers.

Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2021-01-06 18:19:51 +02:00
Stefan Prodan
73ba754481 Merge pull request #656 from pepesenaris/patch-1
Minor fixes to core concepts doc
2021-01-06 17:53:18 +02:00
Jose Javier Señaris
7dcfbdbb29 Minor fixes
Fix small typo.
Added verb to make the intent clear
Added spaces before "(" to match the same pattern used in other parts of the docs

Signed-off-by: Jose Javier Senaris Carballo <pepe.senaris@alayacare.com>
2021-01-06 10:44:32 -05:00
Philip Laine
f453507fcc Merge pull request #654 from fluxcd/update/helm-cloud-storage
Update helm release guide
2021-01-06 14:25:56 +01:00
Philip Laine
c5465de000 Update helm release guide with how to use cloud storage backends
Signed-off-by: Philip Laine <philip.laine@gmail.com>
2021-01-06 12:35:45 +01:00
161 changed files with 3041 additions and 1961 deletions

View File

@@ -54,6 +54,18 @@ jobs:
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/notification-controller/$NOTIFICATION_VER/docs/spec/v1beta1/receiver.md" > docs/components/notification/receiver.md
}
{
# image-*-controller CRDs; these use the same API group
IMG_REFL_VER=$(controller_version image-reflector-controller)
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/image-reflector-controller/$IMG_REFL_VER/docs/api/image-reflector.md" > docs/components/image/reflector-api.md
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/image-reflector-controller/$IMG_REFL_VER/docs/spec/v1alpha1/imagerepositories.md" > docs/components/image/imagerepositories.md
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/image-reflector-controller/$IMG_REFL_VER/docs/spec/v1alpha1/imagepolicies.md" > docs/components/image/imagepolicies.md
IMG_AUTO_VER=$(controller_version image-automation-controller)
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/image-automation-controller/$IMG_AUTO_VER/docs/api/image-automation.md" > docs/components/image/automation-api.md
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/image-automation-controller/$IMG_AUTO_VER/docs/spec/v1alpha1/imageupdateautomations.md" > docs/components/image/imageupdateautomations.md
}
{
# install script
cp install/flux.sh docs/install.sh

View File

@@ -146,6 +146,20 @@ jobs:
--chart=podinfo \
--chart-version="5.0.x" \
--service-account=dev-team
- name: flux create image repository
run: |
./bin/flux create image repository podinfo \
--image=ghcr.io/stefanprodan/podinfo \
--interval=1m
- name: flux create image policy
run: |
./bin/flux create image policy podinfo \
--image-ref=podinfo \
--interval=1m \
--semver=5.0.x
- name: flux get image policy
run: |
./bin/flux get image policy podinfo | grep '5.0.3'
- name: flux2-kustomize-helm-example
run: |
./bin/flux create source git flux-system \

View File

@@ -4,6 +4,8 @@ on:
workflow_dispatch:
schedule:
- cron: "0 * * * *"
push:
branches: [main]
jobs:
update-components:

View File

@@ -1,3 +1,4 @@
project_name: flux
builds:
- <<: &build_defaults
binary: flux

View File

@@ -1,7 +1,6 @@
# Contributing
Flux is [Apache 2.0
licensed](https://github.com/fluxcd/flux2/blob/main/LICENSE) and
Flux is [Apache 2.0 licensed](https://github.com/fluxcd/flux2/blob/main/LICENSE) and
accepts contributions via GitHub pull requests. This document outlines
some of the conventions on to make it easier to get your contribution
accepted.
@@ -14,9 +13,18 @@ code.
By contributing to this project you agree to the Developer Certificate of
Origin (DCO). This document was created by the Linux Kernel community and is a
simple statement that you, as a contributor, have the legal right to make the
contribution. No action from you is required, but it's a good idea to see the
[DCO](DCO) file for details before you start contributing code to FluxCD
organization.
contribution.
We require all commits to be signed. By signing off with your signature, you
certify that you wrote the patch or otherwise have the right to contribute the
material by the rules of the [DCO](DCO):
`Signed-off-by: Jane Doe <jane.doe@example.com>`
The signature must contain your real name
(sorry, no pseudonyms or anonymous contributions)
If your `user.name` and `user.email` are configured in your Git config,
you can sign your commit automatically with `git commit -s`.
## Communications

View File

@@ -102,23 +102,13 @@ Depending on what you want to do, some of the following bits might be your first
- Join our upcoming dev meetings ([meeting access and agenda](https://docs.google.com/document/d/1l_M0om0qUEN_NNiGgpqJ2tvsF2iioHkaARDeh6b70B0/view))
- Talk to us in the #flux channel on [CNCF Slack](https://slack.cncf.io/)
- Join the [planning discussions](https://github.com/fluxcd/flux2/discussions)
- Ask questions and propose features on our [GH Discussions page](https://github.com/fluxcd/flux2/discussions)
- And if you are completely new to Flux and the GitOps Toolkit, take a look at our [Get Started guide](https://toolkit.fluxcd.io/get-started/) and give us feedback
- To be part of the conversation about Flux's development, [join the flux-dev mailing list](https://lists.cncf.io/g/cncf-flux-dev).
- Check out [how to contribute](CONTRIBUTING.md) to the project
### Upcoming Events
- 11 Jan 2021 - [Helm + GitOps = ⚡️⚡️⚡️ with Scott Rigby](https://www.meetup.com/GitOps-Community/events/275348736/)
### Events
### Featured Talks
- 14 Dec 2020 - [The Power of GitOps with Flux and Flagger (GitOps Hands-On) with Leigh Capili](https://youtu.be/cB7iXeNLteE)
- 30 Nov 2020 - [The Power of GitOps with Flux 2 - Part 3 with Leigh Capili](https://youtu.be/N_K5g7o9JKg)
- 24 Nov 2020 - [Flux CD v2 with GitOps Toolkit - Kubernetes Deployment and Sync Mechanism](https://youtu.be/R6OeIgb7lUI)
- 02 Nov 2020 - [The Power of GitOps with Flux & GitOps Toolkit - Part 2 with Leigh Capili](https://youtu.be/fC2YCxQRUwU)
- 28 Oct 2020 - [The Kubelist Podcast: Flux with Michael Bridgen](https://www.heavybit.com/library/podcasts/the-kubelist-podcast/ep-5-flux-with-michael-bridgen-of-weaveworks/)
- 19 Oct 2020 - [The Power of GitOps with Flux & GitOps Toolkit - Part 1 with Leigh Capili](https://youtu.be/0v5bjysXTL8)
- 12 Oct 2020 - [Rawkode Live: Introduction to GitOps Toolkit with Stefan Prodan](https://youtu.be/HqTzuOBP0eY)
- 04 Sep 2020 - [KubeCon Europe: The road to Flux v2 and Progressive Delivery with Stefan Prodan & Hidde Beydals](https://youtu.be/8v94nUkXsxU)
- 25 Jun 2020 - [Cloud Native Nordics: Introduction to GitOps & GitOps Toolkit with Alexis Richardson & Stefan Prodan](https://youtu.be/qQBtSkgl7tI)
Check out our **[events calendar](https://fluxcd.io/community/#talks)**, both with upcoming talks you can attend or past events videos you can watch.
We look forward to seeing you with us!

View File

@@ -45,61 +45,71 @@ var bootstrapCmd = &cobra.Command{
Long: "The bootstrap sub-commands bootstrap the toolkit components on the targeted Git provider.",
}
var (
bootstrapVersion string
bootstrapDefaultComponents []string
bootstrapExtraComponents []string
bootstrapRegistry string
bootstrapImagePullSecret string
bootstrapBranch string
bootstrapWatchAllNamespaces bool
bootstrapNetworkPolicy bool
bootstrapManifestsPath string
bootstrapArch = flags.Arch(defaults.Arch)
bootstrapLogLevel = flags.LogLevel(defaults.LogLevel)
bootstrapRequiredComponents = []string{"source-controller", "kustomize-controller"}
bootstrapTokenAuth bool
bootstrapClusterDomain string
)
type bootstrapFlags struct {
version string
defaultComponents []string
extraComponents []string
registry string
imagePullSecret string
branch string
watchAllNamespaces bool
networkPolicy bool
manifestsPath string
arch flags.Arch
logLevel flags.LogLevel
requiredComponents []string
tokenAuth bool
clusterDomain string
}
const (
bootstrapDefaultBranch = "main"
)
var bootstrapArgs = NewBootstrapFlags()
func init() {
bootstrapCmd.PersistentFlags().StringVarP(&bootstrapVersion, "version", "v", defaults.Version,
bootstrapCmd.PersistentFlags().StringVarP(&bootstrapArgs.version, "version", "v", rootArgs.defaults.Version,
"toolkit version")
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapDefaultComponents, "components", defaults.Components,
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.defaultComponents, "components", rootArgs.defaults.Components,
"list of components, accepts comma-separated values")
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapExtraComponents, "components-extra", nil,
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.extraComponents, "components-extra", nil,
"list of components in addition to those supplied or defaulted, accepts comma-separated values")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapRegistry, "registry", "ghcr.io/fluxcd",
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.registry, "registry", "ghcr.io/fluxcd",
"container registry where the toolkit images are published")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapImagePullSecret, "image-pull-secret", "",
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.imagePullSecret, "image-pull-secret", "",
"Kubernetes secret name used for pulling the toolkit images from a private registry")
bootstrapCmd.PersistentFlags().Var(&bootstrapArch, "arch", bootstrapArch.Description())
bootstrapCmd.PersistentFlags().StringVar(&bootstrapBranch, "branch", bootstrapDefaultBranch,
bootstrapCmd.PersistentFlags().Var(&bootstrapArgs.arch, "arch", bootstrapArgs.arch.Description())
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.branch, "branch", bootstrapDefaultBranch,
"default branch (for GitHub this must match the default branch setting for the organization)")
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapWatchAllNamespaces, "watch-all-namespaces", true,
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapArgs.watchAllNamespaces, "watch-all-namespaces", true,
"watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed")
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapNetworkPolicy, "network-policy", true,
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapArgs.networkPolicy, "network-policy", true,
"deny ingress access to the toolkit controllers from other namespaces using network policies")
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapTokenAuth, "token-auth", false,
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapArgs.tokenAuth, "token-auth", false,
"when enabled, the personal access token will be used instead of SSH deploy key")
bootstrapCmd.PersistentFlags().Var(&bootstrapLogLevel, "log-level", bootstrapLogLevel.Description())
bootstrapCmd.PersistentFlags().StringVar(&bootstrapManifestsPath, "manifests", "", "path to the manifest directory")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapClusterDomain, "cluster-domain", defaults.ClusterDomain, "internal cluster domain")
bootstrapCmd.PersistentFlags().Var(&bootstrapArgs.logLevel, "log-level", bootstrapArgs.logLevel.Description())
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.manifestsPath, "manifests", "", "path to the manifest directory")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.clusterDomain, "cluster-domain", rootArgs.defaults.ClusterDomain, "internal cluster domain")
bootstrapCmd.PersistentFlags().MarkHidden("manifests")
bootstrapCmd.PersistentFlags().MarkDeprecated("arch", "multi-arch container image is now available for AMD64, ARMv7 and ARM64")
rootCmd.AddCommand(bootstrapCmd)
}
func NewBootstrapFlags() bootstrapFlags {
return bootstrapFlags{
logLevel: flags.LogLevel(rootArgs.defaults.LogLevel),
requiredComponents: []string{"source-controller", "kustomize-controller"},
}
}
func bootstrapComponents() []string {
return append(bootstrapDefaultComponents, bootstrapExtraComponents...)
return append(bootstrapArgs.defaultComponents, bootstrapArgs.extraComponents...)
}
func bootstrapValidate() error {
components := bootstrapComponents()
for _, component := range bootstrapRequiredComponents {
for _, component := range bootstrapArgs.requiredComponents {
if !utils.ContainsItemString(components, component) {
return fmt.Errorf("component %s is required", component)
}
@@ -115,24 +125,23 @@ func bootstrapValidate() error {
func generateInstallManifests(targetPath, namespace, tmpDir string, localManifests string) (string, error) {
opts := install.Options{
BaseURL: localManifests,
Version: bootstrapVersion,
Namespace: namespace,
Version: bootstrapArgs.version,
Namespace: rootArgs.namespace,
Components: bootstrapComponents(),
Registry: bootstrapRegistry,
ImagePullSecret: bootstrapImagePullSecret,
Arch: bootstrapArch.String(),
WatchAllNamespaces: bootstrapWatchAllNamespaces,
NetworkPolicy: bootstrapNetworkPolicy,
LogLevel: bootstrapLogLevel.String(),
NotificationController: defaults.NotificationController,
ManifestFile: defaults.ManifestFile,
Timeout: timeout,
Registry: bootstrapArgs.registry,
ImagePullSecret: bootstrapArgs.imagePullSecret,
WatchAllNamespaces: bootstrapArgs.watchAllNamespaces,
NetworkPolicy: bootstrapArgs.networkPolicy,
LogLevel: bootstrapArgs.logLevel.String(),
NotificationController: rootArgs.defaults.NotificationController,
ManifestFile: rootArgs.defaults.ManifestFile,
Timeout: rootArgs.timeout,
TargetPath: targetPath,
ClusterDomain: bootstrapClusterDomain,
ClusterDomain: bootstrapArgs.clusterDomain,
}
if localManifests == "" {
opts.BaseURL = defaults.BaseURL
opts.BaseURL = rootArgs.defaults.BaseURL
}
output, err := install.Generate(opts)
@@ -149,13 +158,13 @@ func generateInstallManifests(targetPath, namespace, tmpDir string, localManifes
func applyInstallManifests(ctx context.Context, manifestPath string, components []string) error {
kubectlArgs := []string{"apply", "-f", manifestPath}
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
return fmt.Errorf("install failed")
}
for _, deployment := range components {
kubectlArgs = []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
kubectlArgs = []string{"-n", rootArgs.namespace, "rollout", "status", "deployment", deployment, "--timeout", rootArgs.timeout.String()}
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
return fmt.Errorf("install failed")
}
}
@@ -191,20 +200,20 @@ func generateSyncManifests(url, branch, name, namespace, targetPath, tmpDir stri
func applySyncManifests(ctx context.Context, kubeClient client.Client, name, namespace, manifestsPath string) error {
kubectlArgs := []string{"apply", "-k", manifestsPath}
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
return err
}
logger.Waitingf("waiting for cluster sync")
var gitRepository sourcev1.GitRepository
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isGitRepositoryReady(ctx, kubeClient, types.NamespacedName{Name: name, Namespace: namespace}, &gitRepository)); err != nil {
return err
}
var kustomization kustomizev1.Kustomization
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isKustomizationReady(ctx, kubeClient, types.NamespacedName{Name: name, Namespace: namespace}, &kustomization)); err != nil {
return err
}
@@ -239,7 +248,7 @@ func shouldCreateDeployKey(ctx context.Context, kubeClient client.Client, namesp
}
func generateDeployKey(ctx context.Context, kubeClient client.Client, url *url.URL, namespace string) (string, error) {
pair, err := generateKeyPair(ctx)
pair, err := generateKeyPair(ctx, sourceArgs.GitKeyAlgorithm, sourceArgs.GitRSABits, sourceArgs.GitECDSACurve)
if err != nil {
return "", err
}
@@ -266,3 +275,20 @@ func generateDeployKey(ctx context.Context, kubeClient client.Client, url *url.U
return string(pair.PublicKey), nil
}
func checkIfBootstrapPathDiffers(ctx context.Context, kubeClient client.Client, namespace string, path string) (string, bool) {
namespacedName := types.NamespacedName{
Name: namespace,
Namespace: namespace,
}
var fluxSystemKustomization kustomizev1.Kustomization
err := kubeClient.Get(ctx, namespacedName, &fluxSystemKustomization)
if err != nil {
return "", false
}
if fluxSystemKustomization.Spec.Path == path {
return "", false
}
return fluxSystemKustomization.Spec.Path, true
}

View File

@@ -23,6 +23,7 @@ import (
"net/url"
"os"
"path"
"path/filepath"
"time"
"github.com/spf13/cobra"
@@ -56,7 +57,7 @@ the bootstrap command will perform an upgrade if needed.`,
flux bootstrap github --owner=<organization> --repository=<repo name> --path=dev-cluster
# Run bootstrap for a public repository on a personal account
flux bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
flux bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
# Run bootstrap for a private repo hosted on GitHub Enterprise using SSH auth
flux bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain> --ssh-hostname=<domain>
@@ -70,35 +71,37 @@ the bootstrap command will perform an upgrade if needed.`,
RunE: bootstrapGitHubCmdRun,
}
var (
ghOwner string
ghRepository string
ghInterval time.Duration
ghPersonal bool
ghPrivate bool
ghHostname string
ghPath flags.SafeRelativePath
ghTeams []string
ghDelete bool
ghSSHHostname string
)
type githubFlags struct {
owner string
repository string
interval time.Duration
personal bool
private bool
hostname string
path flags.SafeRelativePath
teams []string
delete bool
sshHostname string
}
const (
ghDefaultPermission = "maintain"
)
func init() {
bootstrapGitHubCmd.Flags().StringVar(&ghOwner, "owner", "", "GitHub user or organization name")
bootstrapGitHubCmd.Flags().StringVar(&ghRepository, "repository", "", "GitHub repository name")
bootstrapGitHubCmd.Flags().StringArrayVar(&ghTeams, "team", []string{}, "GitHub team to be given maintainer access")
bootstrapGitHubCmd.Flags().BoolVar(&ghPersonal, "personal", false, "is personal repository")
bootstrapGitHubCmd.Flags().BoolVar(&ghPrivate, "private", true, "is private repository")
bootstrapGitHubCmd.Flags().DurationVar(&ghInterval, "interval", time.Minute, "sync interval")
bootstrapGitHubCmd.Flags().StringVar(&ghHostname, "hostname", git.GitHubDefaultHostname, "GitHub hostname")
bootstrapGitHubCmd.Flags().StringVar(&ghSSHHostname, "ssh-hostname", "", "GitHub SSH hostname, to be used when the SSH host differs from the HTTPS one")
bootstrapGitHubCmd.Flags().Var(&ghPath, "path", "path relative to the repository root, when specified the cluster sync will be scoped to this path")
var githubArgs githubFlags
bootstrapGitHubCmd.Flags().BoolVar(&ghDelete, "delete", false, "delete repository (used for testing only)")
func init() {
bootstrapGitHubCmd.Flags().StringVar(&githubArgs.owner, "owner", "", "GitHub user or organization name")
bootstrapGitHubCmd.Flags().StringVar(&githubArgs.repository, "repository", "", "GitHub repository name")
bootstrapGitHubCmd.Flags().StringArrayVar(&githubArgs.teams, "team", []string{}, "GitHub team to be given maintainer access")
bootstrapGitHubCmd.Flags().BoolVar(&githubArgs.personal, "personal", false, "is personal repository")
bootstrapGitHubCmd.Flags().BoolVar(&githubArgs.private, "private", true, "is private repository")
bootstrapGitHubCmd.Flags().DurationVar(&githubArgs.interval, "interval", time.Minute, "sync interval")
bootstrapGitHubCmd.Flags().StringVar(&githubArgs.hostname, "hostname", git.GitHubDefaultHostname, "GitHub hostname")
bootstrapGitHubCmd.Flags().StringVar(&githubArgs.sshHostname, "ssh-hostname", "", "GitHub SSH hostname, to be used when the SSH host differs from the HTTPS one")
bootstrapGitHubCmd.Flags().Var(&githubArgs.path, "path", "path relative to the repository root, when specified the cluster sync will be scoped to this path")
bootstrapGitHubCmd.Flags().BoolVar(&githubArgs.delete, "delete", false, "delete repository (used for testing only)")
bootstrapGitHubCmd.Flags().MarkHidden("delete")
bootstrapCmd.AddCommand(bootstrapGitHubCmd)
@@ -114,30 +117,41 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
return err
}
repository, err := git.NewRepository(ghRepository, ghOwner, ghHostname, ghToken, "flux", ghOwner+"@users.noreply.github.com")
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if ghSSHHostname != "" {
repository.SSHHost = ghSSHHostname
usedPath, bootstrapPathDiffers := checkIfBootstrapPathDiffers(ctx, kubeClient, rootArgs.namespace, filepath.ToSlash(githubArgs.path.String()))
if bootstrapPathDiffers {
return fmt.Errorf("cluster already bootstrapped to %v path", usedPath)
}
repository, err := git.NewRepository(githubArgs.repository, githubArgs.owner, githubArgs.hostname, ghToken, "flux", githubArgs.owner+"@users.noreply.github.com")
if err != nil {
return err
}
if githubArgs.sshHostname != "" {
repository.SSHHost = githubArgs.sshHostname
}
provider := &git.GithubProvider{
IsPrivate: ghPrivate,
IsPersonal: ghPersonal,
IsPrivate: githubArgs.private,
IsPersonal: githubArgs.personal,
}
tmpDir, err := ioutil.TempDir("", namespace)
tmpDir, err := ioutil.TempDir("", rootArgs.namespace)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
if ghDelete {
if githubArgs.delete {
if err := provider.DeleteRepository(ctx, repository); err != nil {
return err
}
@@ -146,7 +160,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
}
// create GitHub repository if doesn't exists
logger.Actionf("connecting to %s", ghHostname)
logger.Actionf("connecting to %s", githubArgs.hostname)
changed, err := provider.CreateRepository(ctx, repository)
if err != nil {
return err
@@ -157,8 +171,8 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
withErrors := false
// add teams to org repository
if !ghPersonal {
for _, team := range ghTeams {
if !githubArgs.personal {
for _, team := range githubArgs.teams {
if changed, err := provider.AddTeam(ctx, repository, team, ghDefaultPermission); err != nil {
logger.Failuref(err.Error())
withErrors = true
@@ -169,20 +183,20 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
}
// clone repository and checkout the main branch
if err := repository.Checkout(ctx, bootstrapBranch, tmpDir); err != nil {
if err := repository.Checkout(ctx, bootstrapArgs.branch, tmpDir); err != nil {
return err
}
logger.Successf("repository cloned")
// generate install manifests
logger.Generatef("generating manifests")
installManifest, err := generateInstallManifests(ghPath.String(), namespace, tmpDir, bootstrapManifestsPath)
installManifest, err := generateInstallManifests(githubArgs.path.String(), rootArgs.namespace, tmpDir, bootstrapArgs.manifestsPath)
if err != nil {
return err
}
// stage install manifests
changed, err = repository.Commit(ctx, path.Join(ghPath.String(), namespace), "Add manifests")
changed, err = repository.Commit(ctx, path.Join(githubArgs.path.String(), rootArgs.namespace), "Add manifests")
if err != nil {
return err
}
@@ -197,17 +211,12 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("components are up to date")
}
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
// determine if repo synchronization is working
isInstall := shouldInstallManifests(ctx, kubeClient, namespace)
isInstall := shouldInstallManifests(ctx, kubeClient, rootArgs.namespace)
if isInstall {
// apply install manifests
logger.Actionf("installing components in %s namespace", namespace)
logger.Actionf("installing components in %s namespace", rootArgs.namespace)
if err := applyInstallManifests(ctx, installManifest, bootstrapComponents()); err != nil {
return err
}
@@ -216,12 +225,12 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
repoURL := repository.GetURL()
if bootstrapTokenAuth {
if bootstrapArgs.tokenAuth {
// setup HTTPS token auth
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
Namespace: namespace,
Name: rootArgs.namespace,
Namespace: rootArgs.namespace,
},
StringData: map[string]string{
"username": "git",
@@ -234,21 +243,21 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
} else {
// setup SSH deploy key
repoURL = repository.GetSSH()
if shouldCreateDeployKey(ctx, kubeClient, namespace) {
if shouldCreateDeployKey(ctx, kubeClient, rootArgs.namespace) {
logger.Actionf("configuring deploy key")
u, err := url.Parse(repository.GetSSH())
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
key, err := generateDeployKey(ctx, kubeClient, u, namespace)
key, err := generateDeployKey(ctx, kubeClient, u, rootArgs.namespace)
if err != nil {
return fmt.Errorf("generating deploy key failed: %w", err)
}
keyName := "flux"
if ghPath != "" {
keyName = fmt.Sprintf("flux-%s", ghPath)
if githubArgs.path != "" {
keyName = fmt.Sprintf("flux-%s", githubArgs.path)
}
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
@@ -261,13 +270,13 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
// configure repo synchronization
logger.Actionf("generating sync manifests")
syncManifests, err := generateSyncManifests(repoURL, bootstrapBranch, namespace, namespace, ghPath.String(), tmpDir, ghInterval)
syncManifests, err := generateSyncManifests(repoURL, bootstrapArgs.branch, rootArgs.namespace, rootArgs.namespace, filepath.ToSlash(githubArgs.path.String()), tmpDir, githubArgs.interval)
if err != nil {
return err
}
// commit and push manifests
if changed, err = repository.Commit(ctx, path.Join(ghPath.String(), namespace), "Add manifests"); err != nil {
if changed, err = repository.Commit(ctx, path.Join(githubArgs.path.String(), rootArgs.namespace), "Add manifests"); err != nil {
return err
} else if changed {
if err := repository.Push(ctx); err != nil {
@@ -278,7 +287,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
// apply manifests and waiting for sync
logger.Actionf("applying sync manifests")
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, syncManifests); err != nil {
if err := applySyncManifests(ctx, kubeClient, rootArgs.namespace, rootArgs.namespace, syncManifests); err != nil {
return err
}

View File

@@ -23,6 +23,7 @@ import (
"net/url"
"os"
"path"
"path/filepath"
"regexp"
"time"
@@ -47,7 +48,7 @@ the bootstrap command will perform an upgrade if needed.`,
Example: ` # Create a GitLab API token and export it as an env var
export GITLAB_TOKEN=<my-token>
# Run bootstrap for a private repo using HTTPS token authentication
# Run bootstrap for a private repo using HTTPS token authentication
flux bootstrap gitlab --owner=<group> --repository=<repo name> --token-auth
# Run bootstrap for a private repo using SSH authentication
@@ -59,7 +60,7 @@ the bootstrap command will perform an upgrade if needed.`,
# Run bootstrap for a public repository on a personal account
flux bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal --token-auth
# Run bootstrap for a private repo hosted on a GitLab server
# Run bootstrap for a private repo hosted on a GitLab server
flux bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain> --token-auth
# Run bootstrap for a an existing repository with a branch named main
@@ -72,26 +73,28 @@ const (
gitlabProjectRegex = `\A[[:alnum:]\x{00A9}-\x{1f9ff}_][[:alnum:]\p{Pd}\x{00A9}-\x{1f9ff}_\.]*\z`
)
var (
glOwner string
glRepository string
glInterval time.Duration
glPersonal bool
glPrivate bool
glHostname string
glSSHHostname string
glPath flags.SafeRelativePath
)
type gitlabFlags struct {
owner string
repository string
interval time.Duration
personal bool
private bool
hostname string
sshHostname string
path flags.SafeRelativePath
}
var gitlabArgs gitlabFlags
func init() {
bootstrapGitLabCmd.Flags().StringVar(&glOwner, "owner", "", "GitLab user or group name")
bootstrapGitLabCmd.Flags().StringVar(&glRepository, "repository", "", "GitLab repository name")
bootstrapGitLabCmd.Flags().BoolVar(&glPersonal, "personal", false, "is personal repository")
bootstrapGitLabCmd.Flags().BoolVar(&glPrivate, "private", true, "is private repository")
bootstrapGitLabCmd.Flags().DurationVar(&glInterval, "interval", time.Minute, "sync interval")
bootstrapGitLabCmd.Flags().StringVar(&glHostname, "hostname", git.GitLabDefaultHostname, "GitLab hostname")
bootstrapGitLabCmd.Flags().StringVar(&glSSHHostname, "ssh-hostname", "", "GitLab SSH hostname, to be used when the SSH host differs from the HTTPS one")
bootstrapGitLabCmd.Flags().Var(&glPath, "path", "path relative to the repository root, when specified the cluster sync will be scoped to this path")
bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.owner, "owner", "", "GitLab user or group name")
bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.repository, "repository", "", "GitLab repository name")
bootstrapGitLabCmd.Flags().BoolVar(&gitlabArgs.personal, "personal", false, "is personal repository")
bootstrapGitLabCmd.Flags().BoolVar(&gitlabArgs.private, "private", true, "is private repository")
bootstrapGitLabCmd.Flags().DurationVar(&gitlabArgs.interval, "interval", time.Minute, "sync interval")
bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.hostname, "hostname", git.GitLabDefaultHostname, "GitLab hostname")
bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.sshHostname, "ssh-hostname", "", "GitLab SSH hostname, to be used when the SSH host differs from the HTTPS one")
bootstrapGitLabCmd.Flags().Var(&gitlabArgs.path, "path", "path relative to the repository root, when specified the cluster sync will be scoped to this path")
bootstrapCmd.AddCommand(bootstrapGitLabCmd)
}
@@ -102,48 +105,54 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("%s environment variable not found", git.GitLabTokenName)
}
projectNameIsValid, err := regexp.MatchString(gitlabProjectRegex, glRepository)
projectNameIsValid, err := regexp.MatchString(gitlabProjectRegex, gitlabArgs.repository)
if err != nil {
return err
}
if !projectNameIsValid {
return fmt.Errorf("%s is an invalid project name for gitlab.\nIt can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter, digit, emoji or '_'.", glRepository)
return fmt.Errorf("%s is an invalid project name for gitlab.\nIt can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter, digit, emoji or '_'.", gitlabArgs.repository)
}
if err := bootstrapValidate(); err != nil {
return err
}
repository, err := git.NewRepository(glRepository, glOwner, glHostname, glToken, "flux", glOwner+"@users.noreply.gitlab.com")
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if glSSHHostname != "" {
repository.SSHHost = glSSHHostname
usedPath, bootstrapPathDiffers := checkIfBootstrapPathDiffers(ctx, kubeClient, rootArgs.namespace, filepath.ToSlash(gitlabArgs.path.String()))
if bootstrapPathDiffers {
return fmt.Errorf("cluster already bootstrapped to %v path", usedPath)
}
provider := &git.GitLabProvider{
IsPrivate: glPrivate,
IsPersonal: glPersonal,
}
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
repository, err := git.NewRepository(gitlabArgs.repository, gitlabArgs.owner, gitlabArgs.hostname, glToken, "flux", gitlabArgs.owner+"@users.noreply.gitlab.com")
if err != nil {
return err
}
tmpDir, err := ioutil.TempDir("", namespace)
if gitlabArgs.sshHostname != "" {
repository.SSHHost = gitlabArgs.sshHostname
}
tmpDir, err := ioutil.TempDir("", rootArgs.namespace)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
provider := &git.GitLabProvider{
IsPrivate: gitlabArgs.private,
IsPersonal: gitlabArgs.personal,
}
// create GitLab project if doesn't exists
logger.Actionf("connecting to %s", glHostname)
logger.Actionf("connecting to %s", gitlabArgs.hostname)
changed, err := provider.CreateRepository(ctx, repository)
if err != nil {
return err
@@ -153,20 +162,20 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
}
// clone repository and checkout the master branch
if err := repository.Checkout(ctx, bootstrapBranch, tmpDir); err != nil {
if err := repository.Checkout(ctx, bootstrapArgs.branch, tmpDir); err != nil {
return err
}
logger.Successf("repository cloned")
// generate install manifests
logger.Generatef("generating manifests")
installManifest, err := generateInstallManifests(glPath.String(), namespace, tmpDir, bootstrapManifestsPath)
installManifest, err := generateInstallManifests(gitlabArgs.path.String(), rootArgs.namespace, tmpDir, bootstrapArgs.manifestsPath)
if err != nil {
return err
}
// stage install manifests
changed, err = repository.Commit(ctx, path.Join(glPath.String(), namespace), "Add manifests")
changed, err = repository.Commit(ctx, path.Join(gitlabArgs.path.String(), rootArgs.namespace), "Add manifests")
if err != nil {
return err
}
@@ -182,11 +191,11 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
}
// determine if repo synchronization is working
isInstall := shouldInstallManifests(ctx, kubeClient, namespace)
isInstall := shouldInstallManifests(ctx, kubeClient, rootArgs.namespace)
if isInstall {
// apply install manifests
logger.Actionf("installing components in %s namespace", namespace)
logger.Actionf("installing components in %s namespace", rootArgs.namespace)
if err := applyInstallManifests(ctx, installManifest, bootstrapComponents()); err != nil {
return err
}
@@ -195,12 +204,12 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
repoURL := repository.GetURL()
if bootstrapTokenAuth {
if bootstrapArgs.tokenAuth {
// setup HTTPS token auth
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
Namespace: namespace,
Name: rootArgs.namespace,
Namespace: rootArgs.namespace,
},
StringData: map[string]string{
"username": "git",
@@ -213,21 +222,21 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
} else {
// setup SSH deploy key
repoURL = repository.GetSSH()
if shouldCreateDeployKey(ctx, kubeClient, namespace) {
if shouldCreateDeployKey(ctx, kubeClient, rootArgs.namespace) {
logger.Actionf("configuring deploy key")
u, err := url.Parse(repoURL)
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
key, err := generateDeployKey(ctx, kubeClient, u, namespace)
key, err := generateDeployKey(ctx, kubeClient, u, rootArgs.namespace)
if err != nil {
return fmt.Errorf("generating deploy key failed: %w", err)
}
keyName := "flux"
if glPath != "" {
keyName = fmt.Sprintf("flux-%s", glPath)
if gitlabArgs.path != "" {
keyName = fmt.Sprintf("flux-%s", gitlabArgs.path)
}
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
@@ -240,13 +249,13 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
// configure repo synchronization
logger.Actionf("generating sync manifests")
syncManifests, err := generateSyncManifests(repoURL, bootstrapBranch, namespace, namespace, glPath.String(), tmpDir, glInterval)
syncManifests, err := generateSyncManifests(repoURL, bootstrapArgs.branch, rootArgs.namespace, rootArgs.namespace, filepath.ToSlash(gitlabArgs.path.String()), tmpDir, gitlabArgs.interval)
if err != nil {
return err
}
// commit and push manifests
if changed, err = repository.Commit(ctx, path.Join(glPath.String(), namespace), "Add manifests"); err != nil {
if changed, err = repository.Commit(ctx, path.Join(gitlabArgs.path.String(), rootArgs.namespace), "Add manifests"); err != nil {
return err
} else if changed {
if err := repository.Push(ctx); err != nil {
@@ -257,7 +266,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
// apply manifests and waiting for sync
logger.Actionf("applying sync manifests")
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, syncManifests); err != nil {
if err := applySyncManifests(ctx, kubeClient, rootArgs.namespace, rootArgs.namespace, syncManifests); err != nil {
return err
}

View File

@@ -44,25 +44,27 @@ the local environment is configured correctly and if the installed components ar
RunE: runCheckCmd,
}
var (
checkPre bool
checkComponents []string
)
type checkFlags struct {
pre bool
components []string
}
type kubectlVersion struct {
ClientVersion *apimachineryversion.Info `json:"clientVersion"`
}
var checkArgs checkFlags
func init() {
checkCmd.Flags().BoolVarP(&checkPre, "pre", "", false,
checkCmd.Flags().BoolVarP(&checkArgs.pre, "pre", "", false,
"only run pre-installation checks")
checkCmd.Flags().StringSliceVar(&checkComponents, "components", defaults.Components,
checkCmd.Flags().StringSliceVar(&checkArgs.components, "components", rootArgs.defaults.Components,
"list of components, accepts comma-separated values")
rootCmd.AddCommand(checkCmd)
}
func runCheckCmd(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
logger.Actionf("checking prerequisites")
@@ -76,7 +78,7 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
checkFailed = true
}
if checkPre {
if checkArgs.pre {
if checkFailed {
os.Exit(1)
}
@@ -103,7 +105,7 @@ func kubectlCheck(ctx context.Context, version string) bool {
}
kubectlArgs := []string{"version", "--client", "--output", "json"}
output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubeconfig, kubecontext, kubectlArgs...)
output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...)
if err != nil {
logger.Failuref("kubectl version can't be determined")
return false
@@ -132,7 +134,7 @@ func kubectlCheck(ctx context.Context, version string) bool {
}
func kubernetesCheck(version string) bool {
cfg, err := utils.KubeConfig(kubeconfig, kubecontext)
cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
return false
@@ -167,20 +169,20 @@ func kubernetesCheck(version string) bool {
}
func componentsCheck() bool {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
ok := true
for _, deployment := range checkComponents {
kubectlArgs := []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubeconfig, kubecontext, kubectlArgs...); err != nil {
for _, deployment := range checkArgs.components {
kubectlArgs := []string{"-n", rootArgs.namespace, "rollout", "status", "deployment", deployment, "--timeout", rootArgs.timeout.String()}
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
logger.Failuref("%s: %s", deployment, strings.TrimSuffix(output, "\n"))
ok = false
} else {
logger.Successf("%s is healthy", deployment)
}
kubectlArgs = []string{"-n", namespace, "get", "deployment", deployment, "-o", "jsonpath=\"{..image}\""}
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubeconfig, kubecontext, kubectlArgs...); err == nil {
kubectlArgs = []string{"-n", rootArgs.namespace, "get", "deployment", deployment, "-o", "jsonpath=\"{..image}\""}
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err == nil {
logger.Actionf(strings.TrimPrefix(strings.TrimSuffix(output, "\""), "\""))
}
}

View File

@@ -38,16 +38,18 @@ var createCmd = &cobra.Command{
Long: "The create sub-commands generate sources and resources.",
}
var (
type createFlags struct {
interval time.Duration
export bool
labels []string
)
}
var createArgs createFlags
func init() {
createCmd.PersistentFlags().DurationVarP(&interval, "interval", "", time.Minute, "source sync interval")
createCmd.PersistentFlags().BoolVar(&export, "export", false, "export in YAML format to stdout")
createCmd.PersistentFlags().StringSliceVar(&labels, "label", nil,
createCmd.PersistentFlags().DurationVarP(&createArgs.interval, "interval", "", time.Minute, "source sync interval")
createCmd.PersistentFlags().BoolVar(&createArgs.export, "export", false, "export in YAML format to stdout")
createCmd.PersistentFlags().StringSliceVar(&createArgs.labels, "label", nil,
"set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2)")
rootCmd.AddCommand(createCmd)
}
@@ -76,7 +78,7 @@ func (names apiType) upsert(ctx context.Context, kubeClient client.Client, objec
Name: object.GetName(),
}
op, err := controllerutil.CreateOrUpdate(ctx, kubeClient, object.asRuntimeObject(), mutate)
op, err := controllerutil.CreateOrUpdate(ctx, kubeClient, object.asClientObject(), mutate)
if err != nil {
return nsname, err
}
@@ -99,10 +101,10 @@ type upsertWaitable interface {
// resource, then waiting for it to reconcile. See the note on
// `upsert` for how to work with the `mutate` argument.
func (names apiType) upsertAndWait(object upsertWaitable, mutate func() error) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext) // NB globals
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) // NB globals
if err != nil {
return err
}
@@ -116,7 +118,7 @@ func (names apiType) upsertAndWait(object upsertWaitable, mutate func() error) e
}
logger.Waitingf("waiting for %s reconciliation", names.kind)
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isReady(ctx, kubeClient, namespacedName, object)); err != nil {
return err
}
@@ -126,7 +128,7 @@ func (names apiType) upsertAndWait(object upsertWaitable, mutate func() error) e
func parseLabels() (map[string]string, error) {
result := make(map[string]string)
for _, label := range labels {
for _, label := range createArgs.labels {
// validate key value pair
parts := strings.Split(label, "=")
if len(parts) != 2 {

View File

@@ -20,11 +20,7 @@ import (
"context"
"fmt"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -33,6 +29,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/flux2/internal/utils"
)
var createAlertCmd = &cobra.Command{
@@ -49,16 +48,18 @@ var createAlertCmd = &cobra.Command{
RunE: createAlertCmdRun,
}
var (
aProviderRef string
aEventSeverity string
aEventSources []string
)
type alertFlags struct {
providerRef string
eventSeverity string
eventSources []string
}
var alertArgs alertFlags
func init() {
createAlertCmd.Flags().StringVar(&aProviderRef, "provider-ref", "", "reference to provider")
createAlertCmd.Flags().StringVar(&aEventSeverity, "event-severity", "", "severity of events to send alerts for")
createAlertCmd.Flags().StringArrayVar(&aEventSources, "event-source", []string{}, "sources that should generate alerts (<kind>/<name>)")
createAlertCmd.Flags().StringVar(&alertArgs.providerRef, "provider-ref", "", "reference to provider")
createAlertCmd.Flags().StringVar(&alertArgs.eventSeverity, "event-severity", "", "severity of events to send alerts for")
createAlertCmd.Flags().StringArrayVar(&alertArgs.eventSources, "event-source", []string{}, "sources that should generate alerts (<kind>/<name>)")
createCmd.AddCommand(createAlertCmd)
}
@@ -68,12 +69,12 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
if aProviderRef == "" {
if alertArgs.providerRef == "" {
return fmt.Errorf("provider ref is required")
}
eventSources := []notificationv1.CrossNamespaceObjectReference{}
for _, eventSource := range aEventSources {
for _, eventSource := range alertArgs.eventSources {
kind, name := utils.ParseObjectKindName(eventSource)
if kind == "" {
return fmt.Errorf("invalid event source '%s', must be in format <kind>/<name>", eventSource)
@@ -94,34 +95,34 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !export {
if !createArgs.export {
logger.Generatef("generating Alert")
}
alert := notificationv1.Alert{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
Spec: notificationv1.AlertSpec{
ProviderRef: corev1.LocalObjectReference{
Name: aProviderRef,
ProviderRef: meta.LocalObjectReference{
Name: alertArgs.providerRef,
},
EventSeverity: aEventSeverity,
EventSeverity: alertArgs.eventSeverity,
EventSources: eventSources,
Suspend: false,
},
}
if export {
if createArgs.export {
return exportAlert(alert)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
@@ -133,7 +134,7 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
}
logger.Waitingf("waiting for Alert reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isAlertReady(ctx, kubeClient, namespacedName, &alert)); err != nil {
return err
}

View File

@@ -21,7 +21,6 @@ import (
"fmt"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -29,9 +28,10 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/flux2/internal/utils"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/flux2/internal/utils"
)
var createAlertProviderCmd = &cobra.Command{
@@ -54,20 +54,22 @@ var createAlertProviderCmd = &cobra.Command{
RunE: createAlertProviderCmdRun,
}
var (
apType string
apChannel string
apUsername string
apAddress string
apSecretRef string
)
type alertProviderFlags struct {
alertType string
channel string
username string
address string
secretRef string
}
var alertProviderArgs alertProviderFlags
func init() {
createAlertProviderCmd.Flags().StringVar(&apType, "type", "", "type of provider")
createAlertProviderCmd.Flags().StringVar(&apChannel, "channel", "", "channel to send messages to in the case of a chat provider")
createAlertProviderCmd.Flags().StringVar(&apUsername, "username", "", "bot username used by the provider")
createAlertProviderCmd.Flags().StringVar(&apAddress, "address", "", "path to either the git repository, chat provider or webhook")
createAlertProviderCmd.Flags().StringVar(&apSecretRef, "secret-ref", "", "name of secret containing authentication token")
createAlertProviderCmd.Flags().StringVar(&alertProviderArgs.alertType, "type", "", "type of provider")
createAlertProviderCmd.Flags().StringVar(&alertProviderArgs.channel, "channel", "", "channel to send messages to in the case of a chat provider")
createAlertProviderCmd.Flags().StringVar(&alertProviderArgs.username, "username", "", "bot username used by the provider")
createAlertProviderCmd.Flags().StringVar(&alertProviderArgs.address, "address", "", "path to either the git repository, chat provider or webhook")
createAlertProviderCmd.Flags().StringVar(&alertProviderArgs.secretRef, "secret-ref", "", "name of secret containing authentication token")
createCmd.AddCommand(createAlertProviderCmd)
}
@@ -77,7 +79,7 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
if apType == "" {
if alertProviderArgs.alertType == "" {
return fmt.Errorf("Provider type is required")
}
@@ -86,38 +88,38 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !export {
if !createArgs.export {
logger.Generatef("generating Provider")
}
provider := notificationv1.Provider{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
Spec: notificationv1.ProviderSpec{
Type: apType,
Channel: apChannel,
Username: apUsername,
Address: apAddress,
Type: alertProviderArgs.alertType,
Channel: alertProviderArgs.channel,
Username: alertProviderArgs.username,
Address: alertProviderArgs.address,
},
}
if apSecretRef != "" {
provider.Spec.SecretRef = &corev1.LocalObjectReference{
Name: apSecretRef,
if alertProviderArgs.secretRef != "" {
provider.Spec.SecretRef = &meta.LocalObjectReference{
Name: alertProviderArgs.secretRef,
}
}
if export {
if createArgs.export {
return exportAlertProvider(provider)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
@@ -129,7 +131,7 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
}
logger.Waitingf("waiting for Provider reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isAlertProviderReady(ctx, kubeClient, namespacedName, &provider)); err != nil {
return err
}

View File

@@ -98,28 +98,30 @@ var createHelmReleaseCmd = &cobra.Command{
RunE: createHelmReleaseCmdRun,
}
var (
hrName string
hrSource flags.HelmChartSource
hrDependsOn []string
hrChart string
hrChartVersion string
hrTargetNamespace string
hrValuesFile string
hrValuesFrom flags.HelmReleaseValuesFrom
hrSAName string
)
type helmReleaseFlags struct {
name string
source flags.HelmChartSource
dependsOn []string
chart string
chartVersion string
targetNamespace string
valuesFile string
valuesFrom flags.HelmReleaseValuesFrom
saName string
}
var helmReleaseArgs helmReleaseFlags
func init() {
createHelmReleaseCmd.Flags().StringVar(&hrName, "release-name", "", "name used for the Helm release, defaults to a composition of '[<target-namespace>-]<HelmRelease-name>'")
createHelmReleaseCmd.Flags().Var(&hrSource, "source", hrSource.Description())
createHelmReleaseCmd.Flags().StringVar(&hrChart, "chart", "", "Helm chart name or path")
createHelmReleaseCmd.Flags().StringVar(&hrChartVersion, "chart-version", "", "Helm chart version, accepts a semver range (ignored for charts from GitRepository sources)")
createHelmReleaseCmd.Flags().StringArrayVar(&hrDependsOn, "depends-on", nil, "HelmReleases that must be ready before this release can be installed, supported formats '<name>' and '<namespace>/<name>'")
createHelmReleaseCmd.Flags().StringVar(&hrTargetNamespace, "target-namespace", "", "namespace to install this release, defaults to the HelmRelease namespace")
createHelmReleaseCmd.Flags().StringVar(&hrSAName, "service-account", "", "the name of the service account to impersonate when reconciling this HelmRelease")
createHelmReleaseCmd.Flags().StringVar(&hrValuesFile, "values", "", "local path to the values.yaml file")
createHelmReleaseCmd.Flags().Var(&hrValuesFrom, "values-from", hrValuesFrom.Description())
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.name, "release-name", "", "name used for the Helm release, defaults to a composition of '[<target-namespace>-]<HelmRelease-name>'")
createHelmReleaseCmd.Flags().Var(&helmReleaseArgs.source, "source", helmReleaseArgs.source.Description())
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.chart, "chart", "", "Helm chart name or path")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.chartVersion, "chart-version", "", "Helm chart version, accepts a semver range (ignored for charts from GitRepository sources)")
createHelmReleaseCmd.Flags().StringArrayVar(&helmReleaseArgs.dependsOn, "depends-on", nil, "HelmReleases that must be ready before this release can be installed, supported formats '<name>' and '<namespace>/<name>'")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.targetNamespace, "target-namespace", "", "namespace to install this release, defaults to the HelmRelease namespace")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.saName, "service-account", "", "the name of the service account to impersonate when reconciling this HelmRelease")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.valuesFile, "values", "", "local path to the values.yaml file")
createHelmReleaseCmd.Flags().Var(&helmReleaseArgs.valuesFrom, "values-from", helmReleaseArgs.valuesFrom.Description())
createCmd.AddCommand(createHelmReleaseCmd)
}
@@ -129,7 +131,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
if hrChart == "" {
if helmReleaseArgs.chart == "" {
return fmt.Errorf("chart name or path is required")
}
@@ -138,30 +140,30 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !export {
if !createArgs.export {
logger.Generatef("generating HelmRelease")
}
helmRelease := helmv2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
Spec: helmv2.HelmReleaseSpec{
ReleaseName: hrName,
DependsOn: utils.MakeDependsOn(hrDependsOn),
ReleaseName: helmReleaseArgs.name,
DependsOn: utils.MakeDependsOn(helmReleaseArgs.dependsOn),
Interval: metav1.Duration{
Duration: interval,
Duration: createArgs.interval,
},
TargetNamespace: hrTargetNamespace,
TargetNamespace: helmReleaseArgs.targetNamespace,
Chart: helmv2.HelmChartTemplate{
Spec: helmv2.HelmChartTemplateSpec{
Chart: hrChart,
Version: hrChartVersion,
Chart: helmReleaseArgs.chart,
Version: helmReleaseArgs.chartVersion,
SourceRef: helmv2.CrossNamespaceObjectReference{
Kind: hrSource.Kind,
Name: hrSource.Name,
Kind: helmReleaseArgs.source.Kind,
Name: helmReleaseArgs.source.Name,
},
},
},
@@ -169,39 +171,39 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
},
}
if hrSAName != "" {
helmRelease.Spec.ServiceAccountName = hrSAName
if helmReleaseArgs.saName != "" {
helmRelease.Spec.ServiceAccountName = helmReleaseArgs.saName
}
if hrValuesFile != "" {
data, err := ioutil.ReadFile(hrValuesFile)
if helmReleaseArgs.valuesFile != "" {
data, err := ioutil.ReadFile(helmReleaseArgs.valuesFile)
if err != nil {
return fmt.Errorf("reading values from %s failed: %w", hrValuesFile, err)
return fmt.Errorf("reading values from %s failed: %w", helmReleaseArgs.valuesFile, err)
}
json, err := yaml.YAMLToJSON(data)
if err != nil {
return fmt.Errorf("converting values to JSON from %s failed: %w", hrValuesFile, err)
return fmt.Errorf("converting values to JSON from %s failed: %w", helmReleaseArgs.valuesFile, err)
}
helmRelease.Spec.Values = &apiextensionsv1.JSON{Raw: json}
}
if hrValuesFrom.String() != "" {
if helmReleaseArgs.valuesFrom.String() != "" {
helmRelease.Spec.ValuesFrom = []helmv2.ValuesReference{{
Kind: hrValuesFrom.Kind,
Name: hrValuesFrom.Name,
Kind: helmReleaseArgs.valuesFrom.Kind,
Name: helmReleaseArgs.valuesFrom.Name,
}}
}
if export {
if createArgs.export {
return exportHelmRelease(helmRelease)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
@@ -213,7 +215,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
}
logger.Waitingf("waiting for HelmRelease reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isHelmReleaseReady(ctx, kubeClient, namespacedName, &helmRelease)); err != nil {
return err
}

View File

@@ -20,9 +20,10 @@ import (
"fmt"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/pkg/apis/meta"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
)
@@ -38,8 +39,9 @@ the status of the object.`,
RunE: createImagePolicyRun}
type imagePolicyFlags struct {
imageRef string
semver string
imageRef string
semver string
filterRegex string
}
var imagePolicyArgs = imagePolicyFlags{}
@@ -48,6 +50,7 @@ func init() {
flags := createImagePolicyCmd.Flags()
flags.StringVar(&imagePolicyArgs.imageRef, "image-ref", "", "the name of an image repository object")
flags.StringVar(&imagePolicyArgs.semver, "semver", "", "a semver range to apply to tags; e.g., '1.x'")
flags.StringVar(&imagePolicyArgs.filterRegex, "filter-regex", "", " regular expression pattern used to filter the image tags")
createImageCmd.AddCommand(createImagePolicyCmd)
}
@@ -76,11 +79,11 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
var policy = imagev1.ImagePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: objectName,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: labels,
},
Spec: imagev1.ImagePolicySpec{
ImageRepositoryRef: corev1.LocalObjectReference{
ImageRepositoryRef: meta.LocalObjectReference{
Name: imagePolicyArgs.imageRef,
},
},
@@ -95,7 +98,13 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("a policy must be provided with --semver")
}
if export {
if imagePolicyArgs.filterRegex != "" {
policy.Spec.FilterTags = &imagev1.TagFilter{
Pattern: imagePolicyArgs.filterRegex,
}
}
if createArgs.export {
return printExport(exportImagePolicy(&policy))
}

View File

@@ -22,9 +22,10 @@ import (
"github.com/google/go-containerregistry/pkg/name"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/pkg/apis/meta"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
)
@@ -77,24 +78,24 @@ func createImageRepositoryRun(cmd *cobra.Command, args []string) error {
var repo = imagev1.ImageRepository{
ObjectMeta: metav1.ObjectMeta{
Name: objectName,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: labels,
},
Spec: imagev1.ImageRepositorySpec{
Image: imageRepoArgs.image,
Interval: metav1.Duration{Duration: interval},
Interval: metav1.Duration{Duration: createArgs.interval},
},
}
if imageRepoArgs.timeout != 0 {
repo.Spec.Timeout = &metav1.Duration{Duration: imageRepoArgs.timeout}
}
if imageRepoArgs.secretRef != "" {
repo.Spec.SecretRef = &corev1.LocalObjectReference{
repo.Spec.SecretRef = &meta.LocalObjectReference{
Name: imageRepoArgs.secretRef,
}
}
if export {
if createArgs.export {
return printExport(exportImageRepository(&repo))
}

View File

@@ -20,9 +20,10 @@ import (
"fmt"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/pkg/apis/meta"
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha1"
)
@@ -50,7 +51,7 @@ var imageUpdateArgs = imageUpdateFlags{}
func init() {
flags := createImageUpdateCmd.Flags()
flags.StringVar(&imageUpdateArgs.gitRepoRef, "git-repo-ref", "", "the name of a GitRepository resource with details of the upstream git repository")
flags.StringVar(&imageUpdateArgs.branch, "branch", "", "the branch to push commits to")
flags.StringVar(&imageUpdateArgs.branch, "branch", "", "the branch to checkout and push commits to")
flags.StringVar(&imageUpdateArgs.commitTemplate, "commit-template", "", "a template for commit messages")
flags.StringVar(&imageUpdateArgs.authorName, "author-name", "", "the name to use for commit author")
flags.StringVar(&imageUpdateArgs.authorEmail, "author-email", "", "the email to use for commit author")
@@ -68,6 +69,10 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("a reference to a GitRepository is required (--git-repo-ref)")
}
if imageUpdateArgs.branch == "" {
return fmt.Errorf("the Git repoistory branch is required (--branch)")
}
labels, err := parseLabels()
if err != nil {
return err
@@ -76,20 +81,17 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
var update = autov1.ImageUpdateAutomation{
ObjectMeta: metav1.ObjectMeta{
Name: objectName,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: labels,
},
Spec: autov1.ImageUpdateAutomationSpec{
Checkout: autov1.GitCheckoutSpec{
GitRepositoryRef: corev1.LocalObjectReference{
GitRepositoryRef: meta.LocalObjectReference{
Name: imageUpdateArgs.gitRepoRef,
},
Branch: imageUpdateArgs.branch,
},
Interval: metav1.Duration{Duration: interval},
Update: autov1.UpdateStrategy{
Setters: &autov1.SettersStrategy{},
},
Interval: metav1.Duration{Duration: createArgs.interval},
Commit: autov1.CommitSpec{
AuthorName: imageUpdateArgs.authorName,
AuthorEmail: imageUpdateArgs.authorEmail,
@@ -98,7 +100,7 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
},
}
if export {
if createArgs.export {
return printExport(exportImageUpdate(&update))
}

View File

@@ -23,7 +23,6 @@ import (
"time"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -31,11 +30,12 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
)
var createKsCmd = &cobra.Command{
@@ -72,53 +72,61 @@ var createKsCmd = &cobra.Command{
RunE: createKsCmdRun,
}
var (
ksSource flags.KustomizationSource
ksPath flags.SafeRelativePath = "./"
ksPrune bool
ksDependsOn []string
ksValidation string
ksHealthCheck []string
ksHealthTimeout time.Duration
ksSAName string
ksDecryptionProvider flags.DecryptionProvider
ksDecryptionSecret string
ksTargetNamespace string
)
type kustomizationFlags struct {
source flags.KustomizationSource
path flags.SafeRelativePath
prune bool
dependsOn []string
validation string
healthCheck []string
healthTimeout time.Duration
saName string
decryptionProvider flags.DecryptionProvider
decryptionSecret string
targetNamespace string
}
var kustomizationArgs = NewKustomizationFlags()
func init() {
createKsCmd.Flags().Var(&ksSource, "source", ksSource.Description())
createKsCmd.Flags().Var(&ksPath, "path", "path to the directory containing a kustomization.yaml file")
createKsCmd.Flags().BoolVar(&ksPrune, "prune", false, "enable garbage collection")
createKsCmd.Flags().StringArrayVar(&ksHealthCheck, "health-check", nil, "workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'")
createKsCmd.Flags().DurationVar(&ksHealthTimeout, "health-check-timeout", 2*time.Minute, "timeout of health checking operations")
createKsCmd.Flags().StringVar(&ksValidation, "validation", "", "validate the manifests before applying them on the cluster, can be 'client' or 'server'")
createKsCmd.Flags().StringArrayVar(&ksDependsOn, "depends-on", nil, "Kustomization that must be ready before this Kustomization can be applied, supported formats '<name>' and '<namespace>/<name>'")
createKsCmd.Flags().StringVar(&ksSAName, "service-account", "", "the name of the service account to impersonate when reconciling this Kustomization")
createKsCmd.Flags().Var(&ksDecryptionProvider, "decryption-provider", ksDecryptionProvider.Description())
createKsCmd.Flags().StringVar(&ksDecryptionSecret, "decryption-secret", "", "set the Kubernetes secret name that contains the OpenPGP private keys used for sops decryption")
createKsCmd.Flags().StringVar(&ksTargetNamespace, "target-namespace", "", "overrides the namespace of all Kustomization objects reconciled by this Kustomization")
createKsCmd.Flags().Var(&kustomizationArgs.source, "source", kustomizationArgs.source.Description())
createKsCmd.Flags().Var(&kustomizationArgs.path, "path", "path to the directory containing a kustomization.yaml file")
createKsCmd.Flags().BoolVar(&kustomizationArgs.prune, "prune", false, "enable garbage collection")
createKsCmd.Flags().StringArrayVar(&kustomizationArgs.healthCheck, "health-check", nil, "workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'")
createKsCmd.Flags().DurationVar(&kustomizationArgs.healthTimeout, "health-check-timeout", 2*time.Minute, "timeout of health checking operations")
createKsCmd.Flags().StringVar(&kustomizationArgs.validation, "validation", "", "validate the manifests before applying them on the cluster, can be 'client' or 'server'")
createKsCmd.Flags().StringArrayVar(&kustomizationArgs.dependsOn, "depends-on", nil, "Kustomization that must be ready before this Kustomization can be applied, supported formats '<name>' and '<namespace>/<name>'")
createKsCmd.Flags().StringVar(&kustomizationArgs.saName, "service-account", "", "the name of the service account to impersonate when reconciling this Kustomization")
createKsCmd.Flags().Var(&kustomizationArgs.decryptionProvider, "decryption-provider", kustomizationArgs.decryptionProvider.Description())
createKsCmd.Flags().StringVar(&kustomizationArgs.decryptionSecret, "decryption-secret", "", "set the Kubernetes secret name that contains the OpenPGP private keys used for sops decryption")
createKsCmd.Flags().StringVar(&kustomizationArgs.targetNamespace, "target-namespace", "", "overrides the namespace of all Kustomization objects reconciled by this Kustomization")
createCmd.AddCommand(createKsCmd)
}
func NewKustomizationFlags() kustomizationFlags {
return kustomizationFlags{
path: "./",
}
}
func createKsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Kustomization name is required")
}
name := args[0]
if ksPath == "" {
if kustomizationArgs.path == "" {
return fmt.Errorf("path is required")
}
if !strings.HasPrefix(ksPath.String(), "./") {
if !strings.HasPrefix(kustomizationArgs.path.String(), "./") {
return fmt.Errorf("path must begin with ./")
}
if !export {
if !createArgs.export {
logger.Generatef("generating Kustomization")
}
ksLabels, err := parseLabels()
kslabels, err := parseLabels()
if err != nil {
return err
}
@@ -126,29 +134,29 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
kustomization := kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: ksLabels,
Namespace: rootArgs.namespace,
Labels: kslabels,
},
Spec: kustomizev1.KustomizationSpec{
DependsOn: utils.MakeDependsOn(ksDependsOn),
DependsOn: utils.MakeDependsOn(kustomizationArgs.dependsOn),
Interval: metav1.Duration{
Duration: interval,
Duration: createArgs.interval,
},
Path: ksPath.String(),
Prune: ksPrune,
Path: kustomizationArgs.path.String(),
Prune: kustomizationArgs.prune,
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Kind: ksSource.Kind,
Name: ksSource.Name,
Kind: kustomizationArgs.source.Kind,
Name: kustomizationArgs.source.Name,
},
Suspend: false,
Validation: ksValidation,
TargetNamespace: ksTargetNamespace,
Validation: kustomizationArgs.validation,
TargetNamespace: kustomizationArgs.targetNamespace,
},
}
if len(ksHealthCheck) > 0 {
healthChecks := make([]kustomizev1.CrossNamespaceObjectReference, 0)
for _, w := range ksHealthCheck {
if len(kustomizationArgs.healthCheck) > 0 {
healthChecks := make([]meta.NamespacedObjectKindReference, 0)
for _, w := range kustomizationArgs.healthCheck {
kindObj := strings.Split(w, "/")
if len(kindObj) != 2 {
return fmt.Errorf("invalid health check '%s' must be in the format 'kind/name.namespace' %v", w, kindObj)
@@ -170,7 +178,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("invalid health check '%s' must be in the format 'kind/name.namespace'", w)
}
check := kustomizev1.CrossNamespaceObjectReference{
check := meta.NamespacedObjectKindReference{
Kind: kind,
Name: nameNs[0],
Namespace: nameNs[1],
@@ -183,32 +191,32 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
}
kustomization.Spec.HealthChecks = healthChecks
kustomization.Spec.Timeout = &metav1.Duration{
Duration: ksHealthTimeout,
Duration: kustomizationArgs.healthTimeout,
}
}
if ksSAName != "" {
kustomization.Spec.ServiceAccountName = ksSAName
if kustomizationArgs.saName != "" {
kustomization.Spec.ServiceAccountName = kustomizationArgs.saName
}
if ksDecryptionProvider != "" {
if kustomizationArgs.decryptionProvider != "" {
kustomization.Spec.Decryption = &kustomizev1.Decryption{
Provider: ksDecryptionProvider.String(),
Provider: kustomizationArgs.decryptionProvider.String(),
}
if ksDecryptionSecret != "" {
kustomization.Spec.Decryption.SecretRef = &corev1.LocalObjectReference{Name: ksDecryptionSecret}
if kustomizationArgs.decryptionSecret != "" {
kustomization.Spec.Decryption.SecretRef = &meta.LocalObjectReference{Name: kustomizationArgs.decryptionSecret}
}
}
if export {
if createArgs.export {
return exportKs(kustomization)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
@@ -220,7 +228,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
}
logger.Waitingf("waiting for Kustomization reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isKustomizationReady(ctx, kubeClient, namespacedName, &kustomization)); err != nil {
return err
}

View File

@@ -21,7 +21,6 @@ import (
"fmt"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -29,9 +28,10 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/flux2/internal/utils"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/flux2/internal/utils"
)
var createReceiverCmd = &cobra.Command{
@@ -50,18 +50,20 @@ var createReceiverCmd = &cobra.Command{
RunE: createReceiverCmdRun,
}
var (
rcvType string
rcvSecretRef string
rcvEvents []string
rcvResources []string
)
type receiverFlags struct {
receiverType string
secretRef string
events []string
resources []string
}
var receiverArgs receiverFlags
func init() {
createReceiverCmd.Flags().StringVar(&rcvType, "type", "", "")
createReceiverCmd.Flags().StringVar(&rcvSecretRef, "secret-ref", "", "")
createReceiverCmd.Flags().StringArrayVar(&rcvEvents, "event", []string{}, "")
createReceiverCmd.Flags().StringArrayVar(&rcvResources, "resource", []string{}, "")
createReceiverCmd.Flags().StringVar(&receiverArgs.receiverType, "type", "", "")
createReceiverCmd.Flags().StringVar(&receiverArgs.secretRef, "secret-ref", "", "")
createReceiverCmd.Flags().StringArrayVar(&receiverArgs.events, "event", []string{}, "")
createReceiverCmd.Flags().StringArrayVar(&receiverArgs.resources, "resource", []string{}, "")
createCmd.AddCommand(createReceiverCmd)
}
@@ -71,16 +73,16 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
if rcvType == "" {
if receiverArgs.receiverType == "" {
return fmt.Errorf("Receiver type is required")
}
if rcvSecretRef == "" {
if receiverArgs.secretRef == "" {
return fmt.Errorf("secret ref is required")
}
resources := []notificationv1.CrossNamespaceObjectReference{}
for _, resource := range rcvResources {
for _, resource := range receiverArgs.resources {
kind, name := utils.ParseObjectKindName(resource)
if kind == "" {
return fmt.Errorf("invalid event source '%s', must be in format <kind>/<name>", resource)
@@ -101,35 +103,35 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !export {
if !createArgs.export {
logger.Generatef("generating Receiver")
}
receiver := notificationv1.Receiver{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
Spec: notificationv1.ReceiverSpec{
Type: rcvType,
Events: rcvEvents,
Type: receiverArgs.receiverType,
Events: receiverArgs.events,
Resources: resources,
SecretRef: corev1.LocalObjectReference{
Name: rcvSecretRef,
SecretRef: meta.LocalObjectReference{
Name: receiverArgs.secretRef,
},
Suspend: false,
},
}
if export {
if createArgs.export {
return exportReceiver(receiver)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
@@ -141,7 +143,7 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
}
logger.Waitingf("waiting for Receiver reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isReceiverReady(ctx, kubeClient, namespacedName, &receiver)); err != nil {
return err
}

View File

@@ -17,11 +17,15 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
)
@@ -35,6 +39,32 @@ func init() {
createCmd.AddCommand(createSecretCmd)
}
func upsertSecret(ctx context.Context, kubeClient client.Client, secret corev1.Secret) error {
namespacedName := types.NamespacedName{
Namespace: secret.GetNamespace(),
Name: secret.GetName(),
}
var existing corev1.Secret
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, &secret); err != nil {
return err
} else {
return nil
}
}
return err
}
existing.StringData = secret.StringData
if err := kubeClient.Update(ctx, &existing); err != nil {
return err
}
return nil
}
func exportSecret(secret corev1.Secret) error {
secret.TypeMeta = metav1.TypeMeta{
APIVersion: "v1",

View File

@@ -21,6 +21,7 @@ import (
"crypto/elliptic"
"fmt"
"net/url"
"time"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
@@ -28,6 +29,7 @@ import (
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/ssh"
)
var createSecretGitCmd = &cobra.Command{
@@ -53,7 +55,7 @@ For Git over HTTP/S, the provided basic authentication credentials are stored in
# Create a Git SSH secret on disk and print the deploy key
flux create secret git podinfo-auth \
--url=ssh://git@github.com/stefanprodan/podinfo \
--export > podinfo-auth.yaml
--export > podinfo-auth.yaml
yq read podinfo-auth.yaml 'data."identity.pub"' | base64 --decode
@@ -61,7 +63,7 @@ For Git over HTTP/S, the provided basic authentication credentials are stored in
flux create secret git podinfo-auth \
--namespace=apps \
--url=ssh://git@github.com/stefanprodan/podinfo \
--export > podinfo-auth.yaml
--export > podinfo-auth.yaml
sops --encrypt --encrypted-regex '^(data|stringData)$' \
--in-place podinfo-auth.yaml
@@ -69,37 +71,47 @@ For Git over HTTP/S, the provided basic authentication credentials are stored in
RunE: createSecretGitCmdRun,
}
var (
secretGitURL string
secretGitUsername string
secretGitPassword string
secretGitKeyAlgorithm flags.PublicKeyAlgorithm = "rsa"
secretGitRSABits flags.RSAKeyBits = 2048
secretGitECDSACurve = flags.ECDSACurve{Curve: elliptic.P384()}
)
type secretGitFlags struct {
url string
username string
password string
keyAlgorithm flags.PublicKeyAlgorithm
rsaBits flags.RSAKeyBits
ecdsaCurve flags.ECDSACurve
}
var secretGitArgs = NewSecretGitFlags()
func init() {
createSecretGitCmd.Flags().StringVar(&secretGitURL, "url", "", "git address, e.g. ssh://git@host/org/repository")
createSecretGitCmd.Flags().StringVarP(&secretGitUsername, "username", "u", "", "basic authentication username")
createSecretGitCmd.Flags().StringVarP(&secretGitPassword, "password", "p", "", "basic authentication password")
createSecretGitCmd.Flags().Var(&secretGitKeyAlgorithm, "ssh-key-algorithm", sourceGitKeyAlgorithm.Description())
createSecretGitCmd.Flags().Var(&secretGitRSABits, "ssh-rsa-bits", sourceGitRSABits.Description())
createSecretGitCmd.Flags().Var(&secretGitECDSACurve, "ssh-ecdsa-curve", sourceGitECDSACurve.Description())
createSecretGitCmd.Flags().StringVar(&secretGitArgs.url, "url", "", "git address, e.g. ssh://git@host/org/repository")
createSecretGitCmd.Flags().StringVarP(&secretGitArgs.username, "username", "u", "", "basic authentication username")
createSecretGitCmd.Flags().StringVarP(&secretGitArgs.password, "password", "p", "", "basic authentication password")
createSecretGitCmd.Flags().Var(&secretGitArgs.keyAlgorithm, "ssh-key-algorithm", secretGitArgs.keyAlgorithm.Description())
createSecretGitCmd.Flags().Var(&secretGitArgs.rsaBits, "ssh-rsa-bits", secretGitArgs.rsaBits.Description())
createSecretGitCmd.Flags().Var(&secretGitArgs.ecdsaCurve, "ssh-ecdsa-curve", secretGitArgs.ecdsaCurve.Description())
createSecretCmd.AddCommand(createSecretGitCmd)
}
func NewSecretGitFlags() secretGitFlags {
return secretGitFlags{
keyAlgorithm: "rsa",
rsaBits: 2048,
ecdsaCurve: flags.ECDSACurve{Curve: elliptic.P384()},
}
}
func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("secret name is required")
}
name := args[0]
if secretGitURL == "" {
if secretGitArgs.url == "" {
return fmt.Errorf("url is required")
}
u, err := url.Parse(secretGitURL)
u, err := url.Parse(secretGitArgs.url)
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
@@ -109,20 +121,20 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: secretLabels,
},
}
switch u.Scheme {
case "ssh":
pair, err := generateKeyPair(ctx)
pair, err := generateKeyPair(ctx, secretGitArgs.keyAlgorithm, secretGitArgs.rsaBits, secretGitArgs.ecdsaCurve)
if err != nil {
return err
}
@@ -138,28 +150,28 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
"known_hosts": hostKey,
}
if !export {
if !createArgs.export {
logger.Generatef("deploy key: %s", string(pair.PublicKey))
}
case "http", "https":
if secretGitUsername == "" || secretGitPassword == "" {
if secretGitArgs.username == "" || secretGitArgs.password == "" {
return fmt.Errorf("for Git over HTTP/S the username and password are required")
}
// TODO: add cert data when it's implemented in source-controller
secret.Data = map[string][]byte{
"username": []byte(secretGitUsername),
"password": []byte(secretGitPassword),
"username": []byte(secretGitArgs.username),
"password": []byte(secretGitArgs.password),
}
default:
return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme)
}
if export {
if createArgs.export {
return exportSecret(secret)
}
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
@@ -167,7 +179,38 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err
}
logger.Actionf("secret '%s' created in '%s' namespace", name, namespace)
logger.Actionf("secret '%s' created in '%s' namespace", name, rootArgs.namespace)
return nil
}
func generateKeyPair(ctx context.Context, alg flags.PublicKeyAlgorithm, rsa flags.RSAKeyBits, ecdsa flags.ECDSACurve) (*ssh.KeyPair, error) {
var keyGen ssh.KeyPairGenerator
switch algorithm := alg.String(); algorithm {
case "rsa":
keyGen = ssh.NewRSAGenerator(int(rsa))
case "ecdsa":
keyGen = ssh.NewECDSAGenerator(ecdsa.Curve)
case "ed25519":
keyGen = ssh.NewEd25519Generator()
default:
return nil, fmt.Errorf("unsupported public key algorithm: %s", algorithm)
}
pair, err := keyGen.Generate()
if err != nil {
return nil, fmt.Errorf("key pair generation failed, error: %w", err)
}
return pair, nil
}
func scanHostKey(ctx context.Context, url *url.URL) ([]byte, error) {
host := url.Host
if url.Port() == "" {
host = host + ":22"
}
hostKey, err := ssh.ScanHostKey(host, 30*time.Second)
if err != nil {
return nil, fmt.Errorf("SSH key scan for host %s failed, error: %w", host, err)
}
return hostKey, nil
}

View File

@@ -0,0 +1,143 @@
/*
Copyright 2021 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"fmt"
"io/ioutil"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/flux2/internal/utils"
)
var createSecretHelmCmd = &cobra.Command{
Use: "helm [name]",
Short: "Create or update a Kubernetes secret for Helm repository authentication",
Long: `
The create secret helm command generates a Kubernetes secret with basic authentication credentials.`,
Example: ` # Create a Helm authentication secret on disk and encrypt it with Mozilla SOPS
flux create secret helm repo-auth \
--namespace=my-namespace \
--username=my-username \
--password=my-password \
--export > repo-auth.yaml
sops --encrypt --encrypted-regex '^(data|stringData)$' \
--in-place repo-auth.yaml
# Create an authentication secret using a custom TLS cert
flux create secret helm repo-auth \
--username=username \
--password=password \
--cert-file=./cert.crt \
--key-file=./key.crt \
--ca-file=./ca.crt
`,
RunE: createSecretHelmCmdRun,
}
type secretHelmFlags struct {
username string
password string
certFile string
keyFile string
caFile string
}
var secretHelmArgs secretHelmFlags
func init() {
createSecretHelmCmd.Flags().StringVarP(&secretHelmArgs.username, "username", "u", "", "basic authentication username")
createSecretHelmCmd.Flags().StringVarP(&secretHelmArgs.password, "password", "p", "", "basic authentication password")
createSecretHelmCmd.Flags().StringVar(&secretHelmArgs.certFile, "cert-file", "", "TLS authentication cert file path")
createSecretHelmCmd.Flags().StringVar(&secretHelmArgs.keyFile, "key-file", "", "TLS authentication key file path")
createSecretHelmCmd.Flags().StringVar(&secretHelmArgs.caFile, "ca-file", "", "TLS authentication CA file path")
createSecretCmd.AddCommand(createSecretHelmCmd)
}
func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("secret name is required")
}
name := args[0]
secretLabels, err := parseLabels()
if err != nil {
return err
}
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: rootArgs.namespace,
Labels: secretLabels,
},
StringData: map[string]string{},
}
if secretHelmArgs.username != "" && secretHelmArgs.password != "" {
secret.StringData["username"] = secretHelmArgs.username
secret.StringData["password"] = secretHelmArgs.password
}
if secretHelmArgs.certFile != "" && secretHelmArgs.keyFile != "" {
cert, err := ioutil.ReadFile(secretHelmArgs.certFile)
if err != nil {
return fmt.Errorf("failed to read repository cert file '%s': %w", secretHelmArgs.certFile, err)
}
secret.StringData["certFile"] = string(cert)
key, err := ioutil.ReadFile(secretHelmArgs.keyFile)
if err != nil {
return fmt.Errorf("failed to read repository key file '%s': %w", secretHelmArgs.keyFile, err)
}
secret.StringData["keyFile"] = string(key)
}
if secretHelmArgs.caFile != "" {
ca, err := ioutil.ReadFile(secretHelmArgs.caFile)
if err != nil {
return fmt.Errorf("failed to read repository CA file '%s': %w", secretHelmArgs.caFile, err)
}
secret.StringData["caFile"] = string(ca)
}
if createArgs.export {
return exportSecret(secret)
}
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err
}
logger.Actionf("secret '%s' created in '%s' namespace", name, rootArgs.namespace)
return nil
}

View File

@@ -30,9 +30,11 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
)
var createSourceBucketCmd = &cobra.Command{
@@ -61,41 +63,49 @@ For Buckets with static authentication, the credentials are stored in a Kubernet
RunE: createSourceBucketCmdRun,
}
var (
sourceBucketName string
sourceBucketProvider = flags.SourceBucketProvider(sourcev1.GenericBucketProvider)
sourceBucketEndpoint string
sourceBucketAccessKey string
sourceBucketSecretKey string
sourceBucketRegion string
sourceBucketInsecure bool
sourceBucketSecretRef string
)
type sourceBucketFlags struct {
name string
provider flags.SourceBucketProvider
endpoint string
accessKey string
secretKey string
region string
insecure bool
secretRef string
}
var sourceBucketArgs = NewSourceBucketFlags()
func init() {
createSourceBucketCmd.Flags().Var(&sourceBucketProvider, "provider", sourceBucketProvider.Description())
createSourceBucketCmd.Flags().StringVar(&sourceBucketName, "bucket-name", "", "the bucket name")
createSourceBucketCmd.Flags().StringVar(&sourceBucketEndpoint, "endpoint", "", "the bucket endpoint address")
createSourceBucketCmd.Flags().StringVar(&sourceBucketAccessKey, "access-key", "", "the bucket access key")
createSourceBucketCmd.Flags().StringVar(&sourceBucketSecretKey, "secret-key", "", "the bucket secret key")
createSourceBucketCmd.Flags().StringVar(&sourceBucketRegion, "region", "", "the bucket region")
createSourceBucketCmd.Flags().BoolVar(&sourceBucketInsecure, "insecure", false, "for when connecting to a non-TLS S3 HTTP endpoint")
createSourceBucketCmd.Flags().StringVar(&sourceBucketSecretRef, "secret-ref", "", "the name of an existing secret containing credentials")
createSourceBucketCmd.Flags().Var(&sourceBucketArgs.provider, "provider", sourceBucketArgs.provider.Description())
createSourceBucketCmd.Flags().StringVar(&sourceBucketArgs.name, "bucket-name", "", "the bucket name")
createSourceBucketCmd.Flags().StringVar(&sourceBucketArgs.endpoint, "endpoint", "", "the bucket endpoint address")
createSourceBucketCmd.Flags().StringVar(&sourceBucketArgs.accessKey, "access-key", "", "the bucket access key")
createSourceBucketCmd.Flags().StringVar(&sourceBucketArgs.secretKey, "secret-key", "", "the bucket secret key")
createSourceBucketCmd.Flags().StringVar(&sourceBucketArgs.region, "region", "", "the bucket region")
createSourceBucketCmd.Flags().BoolVar(&sourceBucketArgs.insecure, "insecure", false, "for when connecting to a non-TLS S3 HTTP endpoint")
createSourceBucketCmd.Flags().StringVar(&sourceBucketArgs.secretRef, "secret-ref", "", "the name of an existing secret containing credentials")
createSourceCmd.AddCommand(createSourceBucketCmd)
}
func NewSourceBucketFlags() sourceBucketFlags {
return sourceBucketFlags{
provider: flags.SourceBucketProvider(sourcev1.GenericBucketProvider),
}
}
func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Bucket source name is required")
}
name := args[0]
if sourceBucketName == "" {
if sourceBucketArgs.name == "" {
return fmt.Errorf("bucket-name is required")
}
if sourceBucketEndpoint == "" {
if sourceBucketArgs.endpoint == "" {
return fmt.Errorf("endpoint is required")
}
@@ -113,55 +123,55 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
bucket := &sourcev1.Bucket{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
Spec: sourcev1.BucketSpec{
BucketName: sourceBucketName,
Provider: sourceBucketProvider.String(),
Insecure: sourceBucketInsecure,
Endpoint: sourceBucketEndpoint,
Region: sourceBucketRegion,
BucketName: sourceBucketArgs.name,
Provider: sourceBucketArgs.provider.String(),
Insecure: sourceBucketArgs.insecure,
Endpoint: sourceBucketArgs.endpoint,
Region: sourceBucketArgs.region,
Interval: metav1.Duration{
Duration: interval,
Duration: createArgs.interval,
},
},
}
if sourceHelmSecretRef != "" {
bucket.Spec.SecretRef = &corev1.LocalObjectReference{
Name: sourceBucketSecretRef,
if sourceHelmArgs.secretRef != "" {
bucket.Spec.SecretRef = &meta.LocalObjectReference{
Name: sourceBucketArgs.secretRef,
}
}
if export {
if createArgs.export {
return exportBucket(*bucket)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
logger.Generatef("generating Bucket source")
if sourceBucketSecretRef == "" {
if sourceBucketArgs.secretRef == "" {
secretName := fmt.Sprintf("bucket-%s", name)
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
StringData: map[string]string{},
}
if sourceBucketAccessKey != "" && sourceBucketSecretKey != "" {
secret.StringData["accesskey"] = sourceBucketAccessKey
secret.StringData["secretkey"] = sourceBucketSecretKey
if sourceBucketArgs.accessKey != "" && sourceBucketArgs.secretKey != "" {
secret.StringData["accesskey"] = sourceBucketArgs.accessKey
secret.StringData["secretkey"] = sourceBucketArgs.secretKey
}
if len(secret.StringData) > 0 {
@@ -169,7 +179,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err
}
bucket.Spec.SecretRef = &corev1.LocalObjectReference{
bucket.Spec.SecretRef = &meta.LocalObjectReference{
Name: secretName,
}
logger.Successf("authentication configured")
@@ -183,7 +193,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
}
logger.Waitingf("waiting for Bucket source reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isBucketReady(ctx, kubeClient, namespacedName, bucket)); err != nil {
return err
}

View File

@@ -23,13 +23,7 @@ import (
"io/ioutil"
"net/url"
"os"
"time"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
@@ -40,9 +34,28 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/pkg/ssh"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
)
type SourceGitFlags struct {
GitURL string
GitBranch string
GitTag string
GitSemver string
GitUsername string
GitPassword string
GitKeyAlgorithm flags.PublicKeyAlgorithm
GitRSABits flags.RSAKeyBits
GitECDSACurve flags.ECDSACurve
GitSecretRef string
GitImplementation flags.GitImplementation
}
var createSourceGitCmd = &cobra.Command{
Use: "git [name]",
Short: "Create or update a GitRepository source",
@@ -87,44 +100,39 @@ For private Git repositories, the basic authentication credentials are stored in
RunE: createSourceGitCmdRun,
}
var (
sourceGitURL string
sourceGitBranch string
sourceGitTag string
sourceGitSemver string
sourceGitUsername string
sourceGitPassword string
sourceGitKeyAlgorithm flags.PublicKeyAlgorithm = "rsa"
sourceGitRSABits flags.RSAKeyBits = 2048
sourceGitECDSACurve = flags.ECDSACurve{Curve: elliptic.P384()}
sourceGitSecretRef string
sourceGitImplementation string
)
var sourceArgs = NewSourceGitFlags()
func init() {
createSourceGitCmd.Flags().StringVar(&sourceGitURL, "url", "", "git address, e.g. ssh://git@host/org/repository")
createSourceGitCmd.Flags().StringVar(&sourceGitBranch, "branch", "master", "git branch")
createSourceGitCmd.Flags().StringVar(&sourceGitTag, "tag", "", "git tag")
createSourceGitCmd.Flags().StringVar(&sourceGitSemver, "tag-semver", "", "git tag semver range")
createSourceGitCmd.Flags().StringVarP(&sourceGitUsername, "username", "u", "", "basic authentication username")
createSourceGitCmd.Flags().StringVarP(&sourceGitPassword, "password", "p", "", "basic authentication password")
createSourceGitCmd.Flags().Var(&sourceGitKeyAlgorithm, "ssh-key-algorithm", sourceGitKeyAlgorithm.Description())
createSourceGitCmd.Flags().Var(&sourceGitRSABits, "ssh-rsa-bits", sourceGitRSABits.Description())
createSourceGitCmd.Flags().Var(&sourceGitECDSACurve, "ssh-ecdsa-curve", sourceGitECDSACurve.Description())
createSourceGitCmd.Flags().StringVarP(&sourceGitSecretRef, "secret-ref", "", "", "the name of an existing secret containing SSH or basic credentials")
createSourceGitCmd.Flags().StringVar(&sourceGitImplementation, "git-implementation", "", "the git implementation to use, can be 'go-git' or 'libgit2'")
createSourceGitCmd.Flags().StringVar(&sourceArgs.GitURL, "url", "", "git address, e.g. ssh://git@host/org/repository")
createSourceGitCmd.Flags().StringVar(&sourceArgs.GitBranch, "branch", "master", "git branch")
createSourceGitCmd.Flags().StringVar(&sourceArgs.GitTag, "tag", "", "git tag")
createSourceGitCmd.Flags().StringVar(&sourceArgs.GitSemver, "tag-semver", "", "git tag semver range")
createSourceGitCmd.Flags().StringVarP(&sourceArgs.GitUsername, "username", "u", "", "basic authentication username")
createSourceGitCmd.Flags().StringVarP(&sourceArgs.GitPassword, "password", "p", "", "basic authentication password")
createSourceGitCmd.Flags().Var(&sourceArgs.GitKeyAlgorithm, "ssh-key-algorithm", sourceArgs.GitKeyAlgorithm.Description())
createSourceGitCmd.Flags().Var(&sourceArgs.GitRSABits, "ssh-rsa-bits", sourceArgs.GitRSABits.Description())
createSourceGitCmd.Flags().Var(&sourceArgs.GitECDSACurve, "ssh-ecdsa-curve", sourceArgs.GitECDSACurve.Description())
createSourceGitCmd.Flags().StringVarP(&sourceArgs.GitSecretRef, "secret-ref", "", "", "the name of an existing secret containing SSH or basic credentials")
createSourceGitCmd.Flags().Var(&sourceArgs.GitImplementation, "git-implementation", sourceArgs.GitImplementation.Description())
createSourceCmd.AddCommand(createSourceGitCmd)
}
func NewSourceGitFlags() SourceGitFlags {
return SourceGitFlags{
GitKeyAlgorithm: "rsa",
GitRSABits: 2048,
GitECDSACurve: flags.ECDSACurve{Curve: elliptic.P384()},
}
}
func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("GitRepository source name is required")
}
name := args[0]
if sourceGitURL == "" {
if sourceArgs.GitURL == "" {
return fmt.Errorf("url is required")
}
@@ -134,7 +142,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
}
defer os.RemoveAll(tmpDir)
u, err := url.Parse(sourceGitURL)
u, err := url.Parse(sourceArgs.GitURL)
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
@@ -144,58 +152,57 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !utils.ContainsItemString([]string{sourcev1.GoGitImplementation, sourcev1.LibGit2Implementation, ""}, sourceGitImplementation) {
return fmt.Errorf("Invalid git implementation %q", sourceGitImplementation)
}
gitRepository := sourcev1.GitRepository{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
Spec: sourcev1.GitRepositorySpec{
URL: sourceGitURL,
URL: sourceArgs.GitURL,
Interval: metav1.Duration{
Duration: interval,
Duration: createArgs.interval,
},
Reference: &sourcev1.GitRepositoryRef{},
GitImplementation: sourceGitImplementation,
Reference: &sourcev1.GitRepositoryRef{},
},
}
if sourceGitSemver != "" {
gitRepository.Spec.Reference.SemVer = sourceGitSemver
} else if sourceGitTag != "" {
gitRepository.Spec.Reference.Tag = sourceGitTag
} else {
gitRepository.Spec.Reference.Branch = sourceGitBranch
if sourceArgs.GitImplementation != "" {
gitRepository.Spec.GitImplementation = sourceArgs.GitImplementation.String()
}
if export {
if sourceGitSecretRef != "" {
gitRepository.Spec.SecretRef = &corev1.LocalObjectReference{
Name: sourceGitSecretRef,
if sourceArgs.GitSemver != "" {
gitRepository.Spec.Reference.SemVer = sourceArgs.GitSemver
} else if sourceArgs.GitTag != "" {
gitRepository.Spec.Reference.Tag = sourceArgs.GitTag
} else {
gitRepository.Spec.Reference.Branch = sourceArgs.GitBranch
}
if createArgs.export {
if sourceArgs.GitSecretRef != "" {
gitRepository.Spec.SecretRef = &meta.LocalObjectReference{
Name: sourceArgs.GitSecretRef,
}
}
return exportGit(gitRepository)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
withAuth := false
// TODO(hidde): move all auth prep to separate func?
if sourceGitSecretRef != "" {
if sourceArgs.GitSecretRef != "" {
withAuth = true
} else if u.Scheme == "ssh" {
logger.Generatef("generating deploy key pair")
pair, err := generateKeyPair(ctx)
pair, err := generateKeyPair(ctx, sourceArgs.GitKeyAlgorithm, sourceArgs.GitRSABits, sourceArgs.GitECDSACurve)
if err != nil {
return err
}
@@ -220,7 +227,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
StringData: map[string]string{
@@ -233,17 +240,17 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return err
}
withAuth = true
} else if sourceGitUsername != "" && sourceGitPassword != "" {
} else if sourceArgs.GitUsername != "" && sourceArgs.GitPassword != "" {
logger.Actionf("applying secret with basic auth credentials")
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
StringData: map[string]string{
"username": sourceGitUsername,
"password": sourceGitPassword,
"username": sourceArgs.GitUsername,
"password": sourceArgs.GitPassword,
},
}
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
@@ -260,10 +267,10 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if withAuth {
secretName := name
if sourceGitSecretRef != "" {
secretName = sourceGitSecretRef
if sourceArgs.GitSecretRef != "" {
secretName = sourceArgs.GitSecretRef
}
gitRepository.Spec.SecretRef = &corev1.LocalObjectReference{
gitRepository.Spec.SecretRef = &meta.LocalObjectReference{
Name: secretName,
}
}
@@ -275,7 +282,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
}
logger.Waitingf("waiting for GitRepository source reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isGitRepositoryReady(ctx, kubeClient, namespacedName, &gitRepository)); err != nil {
return err
}
@@ -288,63 +295,6 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return nil
}
func generateKeyPair(ctx context.Context) (*ssh.KeyPair, error) {
var keyGen ssh.KeyPairGenerator
switch algorithm := sourceGitKeyAlgorithm.String(); algorithm {
case "rsa":
keyGen = ssh.NewRSAGenerator(int(sourceGitRSABits))
case "ecdsa":
keyGen = ssh.NewECDSAGenerator(sourceGitECDSACurve.Curve)
case "ed25519":
keyGen = ssh.NewEd25519Generator()
default:
return nil, fmt.Errorf("unsupported public key algorithm: %s", algorithm)
}
pair, err := keyGen.Generate()
if err != nil {
return nil, fmt.Errorf("key pair generation failed, error: %w", err)
}
return pair, nil
}
func scanHostKey(ctx context.Context, url *url.URL) ([]byte, error) {
host := url.Host
if url.Port() == "" {
host = host + ":22"
}
hostKey, err := ssh.ScanHostKey(host, 30*time.Second)
if err != nil {
return nil, fmt.Errorf("SSH key scan for host %s failed, error: %w", host, err)
}
return hostKey, nil
}
func upsertSecret(ctx context.Context, kubeClient client.Client, secret corev1.Secret) error {
namespacedName := types.NamespacedName{
Namespace: secret.GetNamespace(),
Name: secret.GetName(),
}
var existing corev1.Secret
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, &secret); err != nil {
return err
} else {
return nil
}
}
return err
}
existing.StringData = secret.StringData
if err := kubeClient.Update(ctx, &existing); err != nil {
return err
}
return nil
}
func upsertGitRepository(ctx context.Context, kubeClient client.Client,
gitRepository *sourcev1.GitRepository) (types.NamespacedName, error) {
namespacedName := types.NamespacedName{

View File

@@ -33,8 +33,9 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/flux2/internal/utils"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/utils"
)
var createSourceHelmCmd = &cobra.Command{
@@ -64,24 +65,26 @@ For private Helm repositories, the basic authentication credentials are stored i
RunE: createSourceHelmCmdRun,
}
var (
sourceHelmURL string
sourceHelmUsername string
sourceHelmPassword string
sourceHelmCertFile string
sourceHelmKeyFile string
sourceHelmCAFile string
sourceHelmSecretRef string
)
type sourceHelmFlags struct {
url string
username string
password string
certFile string
keyFile string
caFile string
secretRef string
}
var sourceHelmArgs sourceHelmFlags
func init() {
createSourceHelmCmd.Flags().StringVar(&sourceHelmURL, "url", "", "Helm repository address")
createSourceHelmCmd.Flags().StringVarP(&sourceHelmUsername, "username", "u", "", "basic authentication username")
createSourceHelmCmd.Flags().StringVarP(&sourceHelmPassword, "password", "p", "", "basic authentication password")
createSourceHelmCmd.Flags().StringVar(&sourceHelmCertFile, "cert-file", "", "TLS authentication cert file path")
createSourceHelmCmd.Flags().StringVar(&sourceHelmKeyFile, "key-file", "", "TLS authentication key file path")
createSourceHelmCmd.Flags().StringVar(&sourceHelmCAFile, "ca-file", "", "TLS authentication CA file path")
createSourceHelmCmd.Flags().StringVarP(&sourceHelmSecretRef, "secret-ref", "", "", "the name of an existing secret containing TLS or basic auth credentials")
createSourceHelmCmd.Flags().StringVar(&sourceHelmArgs.url, "url", "", "Helm repository address")
createSourceHelmCmd.Flags().StringVarP(&sourceHelmArgs.username, "username", "u", "", "basic authentication username")
createSourceHelmCmd.Flags().StringVarP(&sourceHelmArgs.password, "password", "p", "", "basic authentication password")
createSourceHelmCmd.Flags().StringVar(&sourceHelmArgs.certFile, "cert-file", "", "TLS authentication cert file path")
createSourceHelmCmd.Flags().StringVar(&sourceHelmArgs.keyFile, "key-file", "", "TLS authentication key file path")
createSourceHelmCmd.Flags().StringVar(&sourceHelmArgs.caFile, "ca-file", "", "TLS authentication CA file path")
createSourceHelmCmd.Flags().StringVarP(&sourceHelmArgs.secretRef, "secret-ref", "", "", "the name of an existing secret containing TLS or basic auth credentials")
createSourceCmd.AddCommand(createSourceHelmCmd)
}
@@ -92,7 +95,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
if sourceHelmURL == "" {
if sourceHelmArgs.url == "" {
return fmt.Errorf("url is required")
}
@@ -107,78 +110,78 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
}
defer os.RemoveAll(tmpDir)
if _, err := url.Parse(sourceHelmURL); err != nil {
if _, err := url.Parse(sourceHelmArgs.url); err != nil {
return fmt.Errorf("url parse failed: %w", err)
}
helmRepository := &sourcev1.HelmRepository{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
Spec: sourcev1.HelmRepositorySpec{
URL: sourceHelmURL,
URL: sourceHelmArgs.url,
Interval: metav1.Duration{
Duration: interval,
Duration: createArgs.interval,
},
},
}
if sourceHelmSecretRef != "" {
helmRepository.Spec.SecretRef = &corev1.LocalObjectReference{
Name: sourceHelmSecretRef,
if sourceHelmArgs.secretRef != "" {
helmRepository.Spec.SecretRef = &meta.LocalObjectReference{
Name: sourceHelmArgs.secretRef,
}
}
if export {
if createArgs.export {
return exportHelmRepository(*helmRepository)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
logger.Generatef("generating HelmRepository source")
if sourceHelmSecretRef == "" {
if sourceHelmArgs.secretRef == "" {
secretName := fmt.Sprintf("helm-%s", name)
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
StringData: map[string]string{},
}
if sourceHelmUsername != "" && sourceHelmPassword != "" {
secret.StringData["username"] = sourceHelmUsername
secret.StringData["password"] = sourceHelmPassword
if sourceHelmArgs.username != "" && sourceHelmArgs.password != "" {
secret.StringData["username"] = sourceHelmArgs.username
secret.StringData["password"] = sourceHelmArgs.password
}
if sourceHelmCertFile != "" && sourceHelmKeyFile != "" {
cert, err := ioutil.ReadFile(sourceHelmCertFile)
if sourceHelmArgs.certFile != "" && sourceHelmArgs.keyFile != "" {
cert, err := ioutil.ReadFile(sourceHelmArgs.certFile)
if err != nil {
return fmt.Errorf("failed to read repository cert file '%s': %w", sourceHelmCertFile, err)
return fmt.Errorf("failed to read repository cert file '%s': %w", sourceHelmArgs.certFile, err)
}
secret.StringData["certFile"] = string(cert)
key, err := ioutil.ReadFile(sourceHelmKeyFile)
key, err := ioutil.ReadFile(sourceHelmArgs.keyFile)
if err != nil {
return fmt.Errorf("failed to read repository key file '%s': %w", sourceHelmKeyFile, err)
return fmt.Errorf("failed to read repository key file '%s': %w", sourceHelmArgs.keyFile, err)
}
secret.StringData["keyFile"] = string(key)
}
if sourceHelmCAFile != "" {
ca, err := ioutil.ReadFile(sourceHelmCAFile)
if sourceHelmArgs.caFile != "" {
ca, err := ioutil.ReadFile(sourceHelmArgs.caFile)
if err != nil {
return fmt.Errorf("failed to read repository CA file '%s': %w", sourceHelmCAFile, err)
return fmt.Errorf("failed to read repository CA file '%s': %w", sourceHelmArgs.caFile, err)
}
secret.StringData["caFile"] = string(ca)
}
@@ -188,7 +191,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err
}
helmRepository.Spec.SecretRef = &corev1.LocalObjectReference{
helmRepository.Spec.SecretRef = &meta.LocalObjectReference{
Name: secretName,
}
logger.Successf("authentication configured")
@@ -202,7 +205,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
}
logger.Waitingf("waiting for HelmRepository source reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isHelmRepositoryReady(ctx, kubeClient, namespacedName, helmRepository)); err != nil {
return err
}

View File

@@ -58,14 +58,16 @@ const (
tenantLabel = "toolkit.fluxcd.io/tenant"
)
var (
tenantNamespaces []string
tenantClusterRole string
)
type tenantFlags struct {
namespaces []string
clusterRole string
}
var tenantArgs tenantFlags
func init() {
createTenantCmd.Flags().StringSliceVar(&tenantNamespaces, "with-namespace", nil, "namespace belonging to this tenant")
createTenantCmd.Flags().StringVar(&tenantClusterRole, "cluster-role", "cluster-admin", "cluster role of the tenant role binding")
createTenantCmd.Flags().StringSliceVar(&tenantArgs.namespaces, "with-namespace", nil, "namespace belonging to this tenant")
createTenantCmd.Flags().StringVar(&tenantArgs.clusterRole, "cluster-role", "cluster-admin", "cluster role of the tenant role binding")
createCmd.AddCommand(createTenantCmd)
}
@@ -78,11 +80,11 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("invalid tenant name '%s': %v", tenant, err)
}
if tenantClusterRole == "" {
if tenantArgs.clusterRole == "" {
return fmt.Errorf("cluster-role is required")
}
if tenantNamespaces == nil {
if tenantArgs.namespaces == nil {
return fmt.Errorf("with-namespace is required")
}
@@ -90,7 +92,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
var accounts []corev1.ServiceAccount
var roleBindings []rbacv1.RoleBinding
for _, ns := range tenantNamespaces {
for _, ns := range tenantArgs.namespaces {
if err := validation.IsQualifiedName(ns); len(err) > 0 {
return fmt.Errorf("invalid namespace '%s': %v", ns, err)
}
@@ -141,14 +143,14 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: tenantClusterRole,
Name: tenantArgs.clusterRole,
},
}
roleBindings = append(roleBindings, roleBinding)
}
if export {
for i, _ := range tenantNamespaces {
if createArgs.export {
for i, _ := range tenantArgs.namespaces {
if err := exportTenant(namespaces[i], accounts[i], roleBindings[i]); err != nil {
return err
}
@@ -156,15 +158,15 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
return nil
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
for i, _ := range tenantNamespaces {
for i, _ := range tenantArgs.namespaces {
logger.Actionf("applying namespace %s", namespaces[i].Name)
if err := upsertNamespace(ctx, kubeClient, namespaces[i]); err != nil {
return err

View File

@@ -33,12 +33,14 @@ var deleteCmd = &cobra.Command{
Long: "The delete sub-commands delete sources and resources.",
}
var (
deleteSilent bool
)
type deleteFlags struct {
silent bool
}
var deleteArgs deleteFlags
func init() {
deleteCmd.PersistentFlags().BoolVarP(&deleteSilent, "silent", "s", false,
deleteCmd.PersistentFlags().BoolVarP(&deleteArgs.silent, "silent", "s", false,
"delete resource without asking for confirmation")
rootCmd.AddCommand(deleteCmd)
@@ -55,25 +57,25 @@ func (del deleteCommand) run(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
err = kubeClient.Get(ctx, namespacedName, del.object.asRuntimeObject())
err = kubeClient.Get(ctx, namespacedName, del.object.asClientObject())
if err != nil {
return err
}
if !deleteSilent {
if !deleteArgs.silent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this " + del.humanKind,
IsConfirm: true,
@@ -83,8 +85,8 @@ func (del deleteCommand) run(cmd *cobra.Command, args []string) error {
}
}
logger.Actionf("deleting %s %s in %s namespace", del.humanKind, name, namespace)
err = kubeClient.Delete(ctx, del.object.asRuntimeObject())
logger.Actionf("deleting %s %s in %s namespace", del.humanKind, name, rootArgs.namespace)
err = kubeClient.Delete(ctx, del.object.asClientObject())
if err != nil {
return err
}

View File

@@ -48,16 +48,16 @@ func deleteAlertCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
@@ -67,7 +67,7 @@ func deleteAlertCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !deleteSilent {
if !deleteArgs.silent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this Alert",
IsConfirm: true,
@@ -77,7 +77,7 @@ func deleteAlertCmdRun(cmd *cobra.Command, args []string) error {
}
}
logger.Actionf("deleting alert %s in %s namespace", name, namespace)
logger.Actionf("deleting alert %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &alert)
if err != nil {
return err

View File

@@ -48,16 +48,16 @@ func deleteAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
@@ -67,7 +67,7 @@ func deleteAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !deleteSilent {
if !deleteArgs.silent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this Provider",
IsConfirm: true,
@@ -77,7 +77,7 @@ func deleteAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
}
}
logger.Actionf("deleting provider %s in %s namespace", name, namespace)
logger.Actionf("deleting provider %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &alertProvider)
if err != nil {
return err

View File

@@ -49,16 +49,16 @@ func deleteHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
@@ -68,7 +68,7 @@ func deleteHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !deleteSilent {
if !deleteArgs.silent {
if !helmRelease.Spec.Suspend {
logger.Waitingf("This action will remove the Kubernetes objects previously applied by the %s Helm release!", name)
}
@@ -81,7 +81,7 @@ func deleteHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
}
}
logger.Actionf("deleting release %s in %s namespace", name, namespace)
logger.Actionf("deleting release %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &helmRelease)
if err != nil {
return err

View File

@@ -48,16 +48,16 @@ func deleteKsCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
@@ -67,7 +67,7 @@ func deleteKsCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !deleteSilent {
if !deleteArgs.silent {
if !kustomization.Spec.Suspend {
logger.Waitingf("This action will remove the Kubernetes objects previously applied by the %s kustomization!", name)
}
@@ -80,7 +80,7 @@ func deleteKsCmdRun(cmd *cobra.Command, args []string) error {
}
}
logger.Actionf("deleting kustomization %s in %s namespace", name, namespace)
logger.Actionf("deleting kustomization %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &kustomization)
if err != nil {
return err

View File

@@ -48,16 +48,16 @@ func deleteReceiverCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
@@ -67,7 +67,7 @@ func deleteReceiverCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !deleteSilent {
if !deleteArgs.silent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this Receiver",
IsConfirm: true,
@@ -77,7 +77,7 @@ func deleteReceiverCmdRun(cmd *cobra.Command, args []string) error {
}
}
logger.Actionf("deleting receiver %s in %s namespace", name, namespace)
logger.Actionf("deleting receiver %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &receiver)
if err != nil {
return err

View File

@@ -47,16 +47,16 @@ func deleteSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
@@ -66,7 +66,7 @@ func deleteSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !deleteSilent {
if !deleteArgs.silent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this source",
IsConfirm: true,
@@ -76,7 +76,7 @@ func deleteSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
}
}
logger.Actionf("deleting source %s in %s namespace", name, namespace)
logger.Actionf("deleting source %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &bucket)
if err != nil {
return err

View File

@@ -47,16 +47,16 @@ func deleteSourceGitCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
@@ -66,7 +66,7 @@ func deleteSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !deleteSilent {
if !deleteArgs.silent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this source",
IsConfirm: true,
@@ -76,7 +76,7 @@ func deleteSourceGitCmdRun(cmd *cobra.Command, args []string) error {
}
}
logger.Actionf("deleting source %s in %s namespace", name, namespace)
logger.Actionf("deleting source %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &git)
if err != nil {
return err

View File

@@ -47,16 +47,16 @@ func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
@@ -66,7 +66,7 @@ func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !deleteSilent {
if !deleteArgs.silent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this source",
IsConfirm: true,
@@ -76,7 +76,7 @@ func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
}
}
logger.Actionf("deleting source %s in %s namespace", name, namespace)
logger.Actionf("deleting source %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &helmRepository)
if err != nil {
return err

View File

@@ -35,12 +35,14 @@ var exportCmd = &cobra.Command{
Long: "The export sub-commands export resources in YAML format.",
}
var (
exportAll bool
)
type exportFlags struct {
all bool
}
var exportArgs exportFlags
func init() {
exportCmd.PersistentFlags().BoolVar(&exportAll, "all", false, "select all resources")
exportCmd.PersistentFlags().BoolVar(&exportArgs.all, "all", false, "select all resources")
rootCmd.AddCommand(exportCmd)
}
@@ -55,8 +57,7 @@ type exportable interface {
// exportableList represents a type that has a list of values, each of
// which is exportable.
type exportableList interface {
adapter
len() int
listAdapter
exportItem(i int) interface{}
}
@@ -66,26 +67,26 @@ type exportCommand struct {
}
func (export exportCommand) run(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
if !exportArgs.all && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if exportAll {
err = kubeClient.List(ctx, export.list.asRuntimeObject(), client.InNamespace(namespace))
if exportArgs.all {
err = kubeClient.List(ctx, export.list.asClientList(), client.InNamespace(rootArgs.namespace))
if err != nil {
return err
}
if export.list.len() == 0 {
logger.Failuref("no objects found in %s namespace", namespace)
logger.Failuref("no objects found in %s namespace", rootArgs.namespace)
return nil
}
@@ -97,10 +98,10 @@ func (export exportCommand) run(cmd *cobra.Command, args []string) error {
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
err = kubeClient.Get(ctx, namespacedName, export.object.asRuntimeObject())
err = kubeClient.Get(ctx, namespacedName, export.object.asClientObject())
if err != nil {
return err
}

View File

@@ -48,27 +48,27 @@ func init() {
}
func exportAlertCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
if !exportArgs.all && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if exportAll {
if exportArgs.all {
var list notificationv1.AlertList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no alerts found in %s namespace", namespace)
logger.Failuref("no alerts found in %s namespace", rootArgs.namespace)
return nil
}
@@ -80,7 +80,7 @@ func exportAlertCmdRun(cmd *cobra.Command, args []string) error {
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var alert notificationv1.Alert

View File

@@ -48,27 +48,27 @@ func init() {
}
func exportAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
if !exportArgs.all && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if exportAll {
if exportArgs.all {
var list notificationv1.ProviderList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no alertproviders found in %s namespace", namespace)
logger.Failuref("no alertproviders found in %s namespace", rootArgs.namespace)
return nil
}
@@ -80,7 +80,7 @@ func exportAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var alertProvider notificationv1.Provider

View File

@@ -49,27 +49,27 @@ func init() {
}
func exportHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
if !exportArgs.all && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if exportAll {
if exportArgs.all {
var list helmv2.HelmReleaseList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no helmrelease found in %s namespace", namespace)
logger.Failuref("no helmrelease found in %s namespace", rootArgs.namespace)
return nil
}
@@ -81,7 +81,7 @@ func exportHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease

View File

@@ -49,27 +49,27 @@ func init() {
}
func exportKsCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
if !exportArgs.all && len(args) < 1 {
return fmt.Errorf("kustomization name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if exportAll {
if exportArgs.all {
var list kustomizev1.KustomizationList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no kustomizations found in %s namespace", namespace)
logger.Failuref("no kustomizations found in %s namespace", rootArgs.namespace)
return nil
}
@@ -81,7 +81,7 @@ func exportKsCmdRun(cmd *cobra.Command, args []string) error {
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var kustomization kustomizev1.Kustomization

View File

@@ -48,27 +48,27 @@ func init() {
}
func exportReceiverCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
if !exportArgs.all && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if exportAll {
if exportArgs.all {
var list notificationv1.ReceiverList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no receivers found in %s namespace", namespace)
logger.Failuref("no receivers found in %s namespace", rootArgs.namespace)
return nil
}
@@ -80,7 +80,7 @@ func exportReceiverCmdRun(cmd *cobra.Command, args []string) error {
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var receiver notificationv1.Receiver

View File

@@ -49,27 +49,27 @@ func init() {
}
func exportSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
if !exportArgs.all && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if exportAll {
if exportArgs.all {
var list sourcev1.BucketList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no source found in %s namespace", namespace)
logger.Failuref("no source found in %s namespace", rootArgs.namespace)
return nil
}
@@ -86,7 +86,7 @@ func exportSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var bucket sourcev1.Bucket

View File

@@ -49,27 +49,27 @@ func init() {
}
func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
if !exportArgs.all && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if exportAll {
if exportArgs.all {
var list sourcev1.GitRepositoryList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no source found in %s namespace", namespace)
logger.Failuref("no source found in %s namespace", rootArgs.namespace)
return nil
}
@@ -86,7 +86,7 @@ func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.GitRepository

View File

@@ -49,27 +49,27 @@ func init() {
}
func exportSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
if !exportArgs.all && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if exportAll {
if exportArgs.all {
var list sourcev1.HelmRepositoryList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no source found in %s namespace", namespace)
logger.Failuref("no source found in %s namespace", rootArgs.namespace)
return nil
}
@@ -86,7 +86,7 @@ func exportSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.HelmRepository

View File

@@ -36,17 +36,20 @@ var getCmd = &cobra.Command{
Long: "The get sub-commands print the statuses of sources and resources.",
}
var allNamespaces bool
type GetFlags struct {
allNamespaces bool
}
var getArgs GetFlags
func init() {
getCmd.PersistentFlags().BoolVarP(&allNamespaces, "all-namespaces", "A", false,
getCmd.PersistentFlags().BoolVarP(&getArgs.allNamespaces, "all-namespaces", "A", false,
"list the requested object(s) across all namespaces")
rootCmd.AddCommand(getCmd)
}
type summarisable interface {
adapter
len() int
listAdapter
summariseItem(i int, includeNamespace bool) []string
headers(includeNamespace bool) []string
}
@@ -75,32 +78,32 @@ type getCommand struct {
}
func (get getCommand) run(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
var listOpts []client.ListOption
if !allNamespaces {
listOpts = append(listOpts, client.InNamespace(namespace))
if !getArgs.allNamespaces {
listOpts = append(listOpts, client.InNamespace(rootArgs.namespace))
}
err = kubeClient.List(ctx, get.list.asRuntimeObject(), listOpts...)
err = kubeClient.List(ctx, get.list.asClientList(), listOpts...)
if err != nil {
return err
}
if get.list.len() == 0 {
logger.Failuref("no %s objects found in %s namespace", get.kind, namespace)
logger.Failuref("no %s objects found in %s namespace", get.kind, rootArgs.namespace)
return nil
}
header := get.list.headers(allNamespaces)
header := get.list.headers(getArgs.allNamespaces)
var rows [][]string
for i := 0; i < get.list.len(); i++ {
row := get.list.summariseItem(i, allNamespaces)
row := get.list.summariseItem(i, getArgs.allNamespaces)
rows = append(rows, row)
}
utils.PrintTable(os.Stdout, header, rows)

View File

@@ -47,17 +47,17 @@ func init() {
}
func getAlertCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
var listOpts []client.ListOption
if !allNamespaces {
listOpts = append(listOpts, client.InNamespace(namespace))
if !getArgs.allNamespaces {
listOpts = append(listOpts, client.InNamespace(rootArgs.namespace))
}
var list notificationv1.AlertList
err = kubeClient.List(ctx, &list, listOpts...)
@@ -66,12 +66,12 @@ func getAlertCmdRun(cmd *cobra.Command, args []string) error {
}
if len(list.Items) == 0 {
logger.Failuref("no alerts found in %s namespace", namespace)
logger.Failuref("no alerts found in %s namespace", rootArgs.namespace)
return nil
}
header := []string{"Name", "Ready", "Message", "Suspended"}
if allNamespaces {
if getArgs.allNamespaces {
header = append([]string{"Namespace"}, header...)
}
var rows [][]string
@@ -92,7 +92,7 @@ func getAlertCmdRun(cmd *cobra.Command, args []string) error {
strings.Title(strconv.FormatBool(alert.Spec.Suspend)),
}
}
if allNamespaces {
if getArgs.allNamespaces {
row = append([]string{alert.Namespace}, row...)
}
rows = append(rows, row)

View File

@@ -45,17 +45,17 @@ func init() {
}
func getAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
var listOpts []client.ListOption
if !allNamespaces {
listOpts = append(listOpts, client.InNamespace(namespace))
if !getArgs.allNamespaces {
listOpts = append(listOpts, client.InNamespace(rootArgs.namespace))
}
var list notificationv1.ProviderList
err = kubeClient.List(ctx, &list, listOpts...)
@@ -64,12 +64,12 @@ func getAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
}
if len(list.Items) == 0 {
logger.Failuref("no providers found in %s namespace", namespace)
logger.Failuref("no providers found in %s namespace", rootArgs.namespace)
return nil
}
header := []string{"Name", "Ready", "Message"}
if allNamespaces {
if getArgs.allNamespaces {
header = append([]string{"Namespace"}, header...)
}
var rows [][]string
@@ -88,7 +88,7 @@ func getAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
"waiting to be reconciled",
}
}
if allNamespaces {
if getArgs.allNamespaces {
row = append([]string{provider.Namespace}, row...)
}
rows = append(rows, row)

View File

@@ -17,20 +17,11 @@ limitations under the License.
package main
import (
"context"
"os"
"strconv"
"strings"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
"github.com/spf13/cobra"
)
var getHelmReleaseCmd = &cobra.Command{
@@ -41,66 +32,28 @@ var getHelmReleaseCmd = &cobra.Command{
Example: ` # List all Helm releases and their status
flux get helmreleases
`,
RunE: getHelmReleaseCmdRun,
RunE: getCommand{
apiType: helmReleaseType,
list: &helmReleaseListAdapter{&helmv2.HelmReleaseList{}},
}.run,
}
func init() {
getCmd.AddCommand(getHelmReleaseCmd)
}
func getHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
var listOpts []client.ListOption
if !allNamespaces {
listOpts = append(listOpts, client.InNamespace(namespace))
}
var list helmv2.HelmReleaseList
err = kubeClient.List(ctx, &list, listOpts...)
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no releases found in %s namespace", namespace)
return nil
}
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if allNamespaces {
header = append([]string{"Namespace"}, header...)
}
var rows [][]string
for _, helmRelease := range list.Items {
row := []string{}
if c := apimeta.FindStatusCondition(helmRelease.Status.Conditions, meta.ReadyCondition); c != nil {
row = []string{
helmRelease.GetName(),
string(c.Status),
c.Message,
helmRelease.Status.LastAppliedRevision,
strings.Title(strconv.FormatBool(helmRelease.Spec.Suspend)),
}
} else {
row = []string{
helmRelease.GetName(),
string(metav1.ConditionFalse),
"waiting to be reconciled",
helmRelease.Status.LastAppliedRevision,
strings.Title(strconv.FormatBool(helmRelease.Spec.Suspend)),
}
}
if allNamespaces {
row = append([]string{helmRelease.Namespace}, row...)
}
rows = append(rows, row)
}
utils.PrintTable(os.Stdout, header, rows)
return nil
func (a helmReleaseListAdapter) summariseItem(i int, includeNamespace bool) []string {
item := a.Items[i]
revision := item.Status.LastAppliedRevision
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}
func (a helmReleaseListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if includeNamespace {
headers = append([]string{"Namespace"}, headers...)
}
return headers
}

View File

@@ -17,19 +17,11 @@ limitations under the License.
package main
import (
"context"
"os"
"strconv"
"strings"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var getKsCmd = &cobra.Command{
@@ -40,66 +32,28 @@ var getKsCmd = &cobra.Command{
Example: ` # List all kustomizations and their status
flux get kustomizations
`,
RunE: getKsCmdRun,
RunE: getCommand{
apiType: kustomizationType,
list: &kustomizationListAdapter{&kustomizev1.KustomizationList{}},
}.run,
}
func init() {
getCmd.AddCommand(getKsCmd)
}
func getKsCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
var listOpts []client.ListOption
if !allNamespaces {
listOpts = append(listOpts, client.InNamespace(namespace))
}
var list kustomizev1.KustomizationList
err = kubeClient.List(ctx, &list, listOpts...)
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no kustomizations found in %s namespace", namespace)
return nil
}
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if allNamespaces {
header = append([]string{"Namespace"}, header...)
}
var rows [][]string
for _, kustomization := range list.Items {
row := []string{}
if c := apimeta.FindStatusCondition(kustomization.Status.Conditions, meta.ReadyCondition); c != nil {
row = []string{
kustomization.GetName(),
string(c.Status),
c.Message,
kustomization.Status.LastAppliedRevision,
strings.Title(strconv.FormatBool(kustomization.Spec.Suspend)),
}
} else {
row = []string{
kustomization.GetName(),
string(metav1.ConditionFalse),
"waiting to be reconciled",
kustomization.Status.LastAppliedRevision,
strings.Title(strconv.FormatBool(kustomization.Spec.Suspend)),
}
}
if allNamespaces {
row = append([]string{kustomization.Namespace}, row...)
}
rows = append(rows, row)
}
utils.PrintTable(os.Stdout, header, rows)
return nil
func (a kustomizationListAdapter) summariseItem(i int, includeNamespace bool) []string {
item := a.Items[i]
revision := item.Status.LastAppliedRevision
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}
func (a kustomizationListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if includeNamespace {
headers = append([]string{"Namespace"}, headers...)
}
return headers
}

View File

@@ -47,17 +47,17 @@ func init() {
}
func getReceiverCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
var listOpts []client.ListOption
if !allNamespaces {
listOpts = append(listOpts, client.InNamespace(namespace))
if !getArgs.allNamespaces {
listOpts = append(listOpts, client.InNamespace(rootArgs.namespace))
}
var list notificationv1.ReceiverList
err = kubeClient.List(ctx, &list, listOpts...)
@@ -66,12 +66,12 @@ func getReceiverCmdRun(cmd *cobra.Command, args []string) error {
}
if len(list.Items) == 0 {
logger.Failuref("no receivers found in %s namespace", namespace)
logger.Failuref("no receivers found in %s namespace", rootArgs.namespace)
return nil
}
header := []string{"Name", "Ready", "Message", "Suspended"}
if allNamespaces {
if getArgs.allNamespaces {
header = append([]string{"Namespace"}, header...)
}
var rows [][]string

View File

@@ -17,19 +17,11 @@ limitations under the License.
package main
import (
"context"
"os"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"strconv"
"strings"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var getSourceBucketCmd = &cobra.Command{
@@ -42,70 +34,31 @@ var getSourceBucketCmd = &cobra.Command{
# List buckets from all namespaces
flux get sources helm --all-namespaces
`,
RunE: getSourceBucketCmdRun,
RunE: getCommand{
apiType: bucketType,
list: &bucketListAdapter{&sourcev1.BucketList{}},
}.run,
}
func init() {
getSourceCmd.AddCommand(getSourceBucketCmd)
}
func getSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
func (a *bucketListAdapter) summariseItem(i int, includeNamespace bool) []string {
item := a.Items[i]
var revision string
if item.GetArtifact() != nil {
revision = item.GetArtifact().Revision
}
var listOpts []client.ListOption
if !allNamespaces {
listOpts = append(listOpts, client.InNamespace(namespace))
}
var list sourcev1.BucketList
err = kubeClient.List(ctx, &list, listOpts...)
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no bucket sources found in %s namespace", namespace)
return nil
}
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if allNamespaces {
header = append([]string{"Namespace"}, header...)
}
var rows [][]string
for _, source := range list.Items {
var row []string
var revision string
if source.GetArtifact() != nil {
revision = source.GetArtifact().Revision
}
if c := apimeta.FindStatusCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
row = []string{
source.GetName(),
string(c.Status),
c.Message,
revision,
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
}
} else {
row = []string{
source.GetName(),
string(metav1.ConditionFalse),
"waiting to be reconciled",
revision,
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
}
}
if allNamespaces {
row = append([]string{source.Namespace}, row...)
}
rows = append(rows, row)
}
utils.PrintTable(os.Stdout, header, rows)
return nil
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}
func (a bucketListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if includeNamespace {
headers = append([]string{"Namespace"}, headers...)
}
return headers
}

View File

@@ -17,19 +17,11 @@ limitations under the License.
package main
import (
"context"
"os"
"strconv"
"strings"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var getSourceHelmChartCmd = &cobra.Command{
@@ -42,70 +34,31 @@ var getSourceHelmChartCmd = &cobra.Command{
# List Helm charts from all namespaces
flux get sources chart --all-namespaces
`,
RunE: getSourceHelmChartCmdRun,
RunE: getCommand{
apiType: bucketType,
list: &helmChartListAdapter{&sourcev1.HelmChartList{}},
}.run,
}
func init() {
getSourceCmd.AddCommand(getSourceHelmChartCmd)
}
func getSourceHelmChartCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
func (a *helmChartListAdapter) summariseItem(i int, includeNamespace bool) []string {
item := a.Items[i]
var revision string
if item.GetArtifact() != nil {
revision = item.GetArtifact().Revision
}
var listOpts []client.ListOption
if !allNamespaces {
listOpts = append(listOpts, client.InNamespace(namespace))
}
var list sourcev1.HelmChartList
err = kubeClient.List(ctx, &list, listOpts...)
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no chart sources found in %s namespace", namespace)
return nil
}
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if allNamespaces {
header = append([]string{"Namespace"}, header...)
}
var rows [][]string
for _, source := range list.Items {
var row []string
var revision string
if source.GetArtifact() != nil {
revision = source.GetArtifact().Revision
}
if c := apimeta.FindStatusCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
row = []string{
source.GetName(),
string(c.Status),
c.Message,
revision,
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
}
} else {
row = []string{
source.GetName(),
string(metav1.ConditionFalse),
"waiting to be reconciled",
revision,
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
}
}
if allNamespaces {
row = append([]string{source.Namespace}, row...)
}
rows = append(rows, row)
}
utils.PrintTable(os.Stdout, header, rows)
return nil
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}
func (a helmChartListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if includeNamespace {
headers = append([]string{"Namespace"}, headers...)
}
return headers
}

View File

@@ -17,19 +17,11 @@ limitations under the License.
package main
import (
"context"
"os"
"strconv"
"strings"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var getSourceGitCmd = &cobra.Command{
@@ -42,70 +34,31 @@ var getSourceGitCmd = &cobra.Command{
# List Git repositories from all namespaces
flux get sources git --all-namespaces
`,
RunE: getSourceGitCmdRun,
RunE: getCommand{
apiType: bucketType,
list: &gitRepositoryListAdapter{&sourcev1.GitRepositoryList{}},
}.run,
}
func init() {
getSourceCmd.AddCommand(getSourceGitCmd)
}
func getSourceGitCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
func (a *gitRepositoryListAdapter) summariseItem(i int, includeNamespace bool) []string {
item := a.Items[i]
var revision string
if item.GetArtifact() != nil {
revision = item.GetArtifact().Revision
}
var listOpts []client.ListOption
if !allNamespaces {
listOpts = append(listOpts, client.InNamespace(namespace))
}
var list sourcev1.GitRepositoryList
err = kubeClient.List(ctx, &list, listOpts...)
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no git sources found in %s namespace", namespace)
return nil
}
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if allNamespaces {
header = append([]string{"Namespace"}, header...)
}
var rows [][]string
for _, source := range list.Items {
var row []string
var revision string
if source.GetArtifact() != nil {
revision = source.GetArtifact().Revision
}
if c := apimeta.FindStatusCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
row = []string{
source.GetName(),
string(c.Status),
c.Message,
revision,
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
}
} else {
row = []string{
source.GetName(),
string(metav1.ConditionFalse),
"waiting to be reconciled",
revision,
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
}
}
if allNamespaces {
row = append([]string{source.Namespace}, row...)
}
rows = append(rows, row)
}
utils.PrintTable(os.Stdout, header, rows)
return nil
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}
func (a gitRepositoryListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if includeNamespace {
headers = append([]string{"Namespace"}, headers...)
}
return headers
}

View File

@@ -17,19 +17,11 @@ limitations under the License.
package main
import (
"context"
"os"
"strconv"
"strings"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var getSourceHelmCmd = &cobra.Command{
@@ -42,70 +34,31 @@ var getSourceHelmCmd = &cobra.Command{
# List Helm repositories from all namespaces
flux get sources helm --all-namespaces
`,
RunE: getSourceHelmCmdRun,
RunE: getCommand{
apiType: bucketType,
list: &helmRepositoryListAdapter{&sourcev1.HelmRepositoryList{}},
}.run,
}
func init() {
getSourceCmd.AddCommand(getSourceHelmCmd)
}
func getSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
func (a *helmRepositoryListAdapter) summariseItem(i int, includeNamespace bool) []string {
item := a.Items[i]
var revision string
if item.GetArtifact() != nil {
revision = item.GetArtifact().Revision
}
var listOpts []client.ListOption
if !allNamespaces {
listOpts = append(listOpts, client.InNamespace(namespace))
}
var list sourcev1.HelmRepositoryList
err = kubeClient.List(ctx, &list, listOpts...)
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no helm sources found in %s namespace", namespace)
return nil
}
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if allNamespaces {
header = append([]string{"Namespace"}, header...)
}
var rows [][]string
for _, source := range list.Items {
var row []string
var revision string
if source.GetArtifact() != nil {
revision = source.GetArtifact().Revision
}
if c := apimeta.FindStatusCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
row = []string{
source.GetName(),
string(c.Status),
c.Message,
revision,
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
}
} else {
row = []string{
source.GetName(),
string(metav1.ConditionFalse),
"waiting to be reconciled",
revision,
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
}
}
if allNamespaces {
row = append([]string{source.Namespace}, row...)
}
rows = append(rows, row)
}
utils.PrintTable(os.Stdout, header, rows)
return nil
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}
func (a helmRepositoryListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if includeNamespace {
headers = append([]string{"Namespace"}, headers...)
}
return headers
}

51
cmd/flux/helmrelease.go Normal file
View File

@@ -0,0 +1,51 @@
/*
Copyright 2021 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// helmv2.HelmRelease
var helmReleaseType = apiType{
kind: helmv2.HelmReleaseKind,
humanKind: "helmreleases",
}
type helmReleaseAdapter struct {
*helmv2.HelmRelease
}
func (h helmReleaseAdapter) asClientObject() client.Object {
return h.HelmRelease
}
// helmv2.HelmReleaseList
type helmReleaseListAdapter struct {
*helmv2.HelmReleaseList
}
func (h helmReleaseListAdapter) asClientList() client.ObjectList {
return h.HelmReleaseList
}
func (h helmReleaseListAdapter) len() int {
return len(h.HelmReleaseList.Items)
}

View File

@@ -17,7 +17,7 @@ limitations under the License.
package main
import (
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha1"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
@@ -38,7 +38,7 @@ type imageRepositoryAdapter struct {
*imagev1.ImageRepository
}
func (a imageRepositoryAdapter) asRuntimeObject() runtime.Object {
func (a imageRepositoryAdapter) asClientObject() client.Object {
return a.ImageRepository
}
@@ -48,7 +48,7 @@ type imageRepositoryListAdapter struct {
*imagev1.ImageRepositoryList
}
func (a imageRepositoryListAdapter) asRuntimeObject() runtime.Object {
func (a imageRepositoryListAdapter) asClientList() client.ObjectList {
return a.ImageRepositoryList
}
@@ -67,7 +67,7 @@ type imagePolicyAdapter struct {
*imagev1.ImagePolicy
}
func (a imagePolicyAdapter) asRuntimeObject() runtime.Object {
func (a imagePolicyAdapter) asClientObject() client.Object {
return a.ImagePolicy
}
@@ -77,7 +77,7 @@ type imagePolicyListAdapter struct {
*imagev1.ImagePolicyList
}
func (a imagePolicyListAdapter) asRuntimeObject() runtime.Object {
func (a imagePolicyListAdapter) asClientList() client.ObjectList {
return a.ImagePolicyList
}
@@ -96,7 +96,7 @@ type imageUpdateAutomationAdapter struct {
*autov1.ImageUpdateAutomation
}
func (a imageUpdateAutomationAdapter) asRuntimeObject() runtime.Object {
func (a imageUpdateAutomationAdapter) asClientObject() client.Object {
return a.ImageUpdateAutomation
}
@@ -106,7 +106,7 @@ type imageUpdateAutomationListAdapter struct {
*autov1.ImageUpdateAutomationList
}
func (a imageUpdateAutomationListAdapter) asRuntimeObject() runtime.Object {
func (a imageUpdateAutomationListAdapter) asClientList() client.ObjectList {
return a.ImageUpdateAutomationList
}

View File

@@ -62,8 +62,8 @@ var (
installImagePullSecret string
installWatchAllNamespaces bool
installNetworkPolicy bool
installArch = flags.Arch(defaults.Arch)
installLogLevel = flags.LogLevel(defaults.LogLevel)
installArch flags.Arch
installLogLevel = flags.LogLevel(rootArgs.defaults.LogLevel)
installClusterDomain string
)
@@ -72,33 +72,34 @@ func init() {
"write the install manifests to stdout and exit")
installCmd.Flags().BoolVarP(&installDryRun, "dry-run", "", false,
"only print the object that would be applied")
installCmd.Flags().StringVarP(&installVersion, "version", "v", defaults.Version,
installCmd.Flags().StringVarP(&installVersion, "version", "v", rootArgs.defaults.Version,
"toolkit version")
installCmd.Flags().StringSliceVar(&installDefaultComponents, "components", defaults.Components,
installCmd.Flags().StringSliceVar(&installDefaultComponents, "components", rootArgs.defaults.Components,
"list of components, accepts comma-separated values")
installCmd.Flags().StringSliceVar(&installExtraComponents, "components-extra", nil,
"list of components in addition to those supplied or defaulted, accepts comma-separated values")
installCmd.Flags().StringVar(&installManifestsPath, "manifests", "", "path to the manifest directory")
installCmd.Flags().MarkHidden("manifests")
installCmd.Flags().StringVar(&installRegistry, "registry", defaults.Registry,
installCmd.Flags().StringVar(&installRegistry, "registry", rootArgs.defaults.Registry,
"container registry where the toolkit images are published")
installCmd.Flags().StringVar(&installImagePullSecret, "image-pull-secret", "",
"Kubernetes secret name used for pulling the toolkit images from a private registry")
installCmd.Flags().Var(&installArch, "arch", installArch.Description())
installCmd.Flags().BoolVar(&installWatchAllNamespaces, "watch-all-namespaces", defaults.WatchAllNamespaces,
installCmd.Flags().BoolVar(&installWatchAllNamespaces, "watch-all-namespaces", rootArgs.defaults.WatchAllNamespaces,
"watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed")
installCmd.Flags().Var(&installLogLevel, "log-level", installLogLevel.Description())
installCmd.Flags().BoolVar(&installNetworkPolicy, "network-policy", defaults.NetworkPolicy,
installCmd.Flags().BoolVar(&installNetworkPolicy, "network-policy", rootArgs.defaults.NetworkPolicy,
"deny ingress access to the toolkit controllers from other namespaces using network policies")
installCmd.Flags().StringVar(&installClusterDomain, "cluster-domain", defaults.ClusterDomain, "internal cluster domain")
installCmd.Flags().StringVar(&installClusterDomain, "cluster-domain", rootArgs.defaults.ClusterDomain, "internal cluster domain")
installCmd.Flags().MarkHidden("manifests")
installCmd.Flags().MarkDeprecated("arch", "multi-arch container image is now available for AMD64, ARMv7 and ARM64")
rootCmd.AddCommand(installCmd)
}
func installCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
tmpDir, err := ioutil.TempDir("", namespace)
tmpDir, err := ioutil.TempDir("", rootArgs.namespace)
if err != nil {
return err
}
@@ -117,17 +118,16 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
opts := install.Options{
BaseURL: installManifestsPath,
Version: installVersion,
Namespace: namespace,
Namespace: rootArgs.namespace,
Components: components,
Registry: installRegistry,
ImagePullSecret: installImagePullSecret,
Arch: installArch.String(),
WatchAllNamespaces: installWatchAllNamespaces,
NetworkPolicy: installNetworkPolicy,
LogLevel: installLogLevel.String(),
NotificationController: defaults.NotificationController,
ManifestFile: fmt.Sprintf("%s.yaml", namespace),
Timeout: timeout,
NotificationController: rootArgs.defaults.NotificationController,
ManifestFile: fmt.Sprintf("%s.yaml", rootArgs.namespace),
Timeout: rootArgs.timeout,
ClusterDomain: installClusterDomain,
}
@@ -144,7 +144,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("install failed: %w", err)
}
if verbose {
if rootArgs.verbose {
fmt.Print(manifest.Content)
} else if installExport {
fmt.Println("---")
@@ -156,9 +156,9 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
}
logger.Successf("manifests build completed")
logger.Actionf("installing components in %s namespace", namespace)
logger.Actionf("installing components in %s namespace", rootArgs.namespace)
applyOutput := utils.ModeStderrOS
if verbose {
if rootArgs.verbose {
applyOutput = utils.ModeOS
}
@@ -167,7 +167,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
kubectlArgs = append(kubectlArgs, "--dry-run=client")
applyOutput = utils.ModeOS
}
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, kubeconfig, kubecontext, kubectlArgs...); err != nil {
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
return fmt.Errorf("install failed")
}
@@ -180,8 +180,8 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
logger.Waitingf("verifying installation")
for _, deployment := range components {
kubectlArgs = []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, kubeconfig, kubecontext, kubectlArgs...); err != nil {
kubectlArgs = []string{"-n", rootArgs.namespace, "rollout", "status", "deployment", deployment, "--timeout", rootArgs.timeout.String()}
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
return fmt.Errorf("install failed")
} else {
logger.Successf("%s ready", deployment)

51
cmd/flux/kustomization.go Normal file
View File

@@ -0,0 +1,51 @@
/*
Copyright 2020 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// kustomizev1.Kustomization
var kustomizationType = apiType{
kind: kustomizev1.KustomizationKind,
humanKind: "kustomizations",
}
type kustomizationAdapter struct {
*kustomizev1.Kustomization
}
func (a kustomizationAdapter) asClientObject() client.Object {
return a.Kustomization
}
// kustomizev1.KustomizationList
type kustomizationListAdapter struct {
*kustomizev1.KustomizationList
}
func (a kustomizationListAdapter) asClientList() client.ObjectList {
return a.KustomizationList
}
func (a kustomizationListAdapter) len() int {
return len(a.KustomizationList.Items)
}

View File

@@ -26,7 +26,6 @@ import (
"github.com/spf13/cobra/doc"
_ "k8s.io/client-go/plugin/pkg/client/auth"
fluxlog "github.com/fluxcd/flux2/pkg/log"
"github.com/fluxcd/flux2/pkg/manifestgen/install"
)
@@ -94,22 +93,32 @@ var rootCmd = &cobra.Command{
`,
}
var (
var logger = stderrLogger{stderr: os.Stderr}
type rootFlags struct {
kubeconfig string
kubecontext string
namespace string
timeout time.Duration
verbose bool
pollInterval = 2 * time.Second
logger fluxlog.Logger = stderrLogger{stderr: os.Stderr}
defaults = install.MakeDefaultOptions()
)
pollInterval time.Duration
defaults install.Options
}
var rootArgs = NewRootFlags()
func init() {
rootCmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", defaults.Namespace, "the namespace scope for this operation")
rootCmd.PersistentFlags().DurationVar(&timeout, "timeout", 5*time.Minute, "timeout for this operation")
rootCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "print generated objects")
rootCmd.PersistentFlags().StringVarP(&kubecontext, "context", "", "", "kubernetes context to use")
rootCmd.PersistentFlags().StringVarP(&rootArgs.namespace, "namespace", "n", rootArgs.defaults.Namespace, "the namespace scope for this operation")
rootCmd.PersistentFlags().DurationVar(&rootArgs.timeout, "timeout", 5*time.Minute, "timeout for this operation")
rootCmd.PersistentFlags().BoolVar(&rootArgs.verbose, "verbose", false, "print generated objects")
rootCmd.PersistentFlags().StringVarP(&rootArgs.kubecontext, "context", "", "", "kubernetes context to use")
}
func NewRootFlags() rootFlags {
return rootFlags{
pollInterval: 2 * time.Second,
defaults: install.MakeDefaultOptions(),
}
}
func main() {
@@ -124,22 +133,22 @@ func main() {
func kubeconfigFlag() {
if home := homeDir(); home != "" {
rootCmd.PersistentFlags().StringVarP(&kubeconfig, "kubeconfig", "", filepath.Join(home, ".kube", "config"),
rootCmd.PersistentFlags().StringVarP(&rootArgs.kubeconfig, "kubeconfig", "", filepath.Join(home, ".kube", "config"),
"path to the kubeconfig file")
} else {
rootCmd.PersistentFlags().StringVarP(&kubeconfig, "kubeconfig", "", "",
rootCmd.PersistentFlags().StringVarP(&rootArgs.kubeconfig, "kubeconfig", "", "",
"absolute path to the kubeconfig file")
}
if len(os.Getenv("KUBECONFIG")) > 0 {
kubeconfig = os.Getenv("KUBECONFIG")
rootArgs.kubeconfig = os.Getenv("KUBECONFIG")
}
}
func generateDocs() {
args := os.Args[1:]
if len(args) > 0 && args[0] == "docgen" {
rootCmd.PersistentFlags().StringVarP(&kubeconfig, "kubeconfig", "", "~/.kube/config",
rootCmd.PersistentFlags().StringVarP(&rootArgs.kubeconfig, "kubeconfig", "", "~/.kube/config",
"path to the kubeconfig file")
rootCmd.DisableAutoGenTag = true
err := doc.GenMarkdownTree(rootCmd, "./docs/cmd")

View File

@@ -17,7 +17,7 @@ limitations under the License.
package main
import (
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// Most commands need one or both of the kind (e.g.,
@@ -35,16 +35,24 @@ type apiType struct {
// use values of the wrapper with `client.Client`, which only deals
// with types that have been added to the schema.
type adapter interface {
asRuntimeObject() runtime.Object
asClientObject() client.Object
}
// universalAdapter is an adapter for any runtime.Object. Use this if
// listAdapater is the analogue to adapter, but for lists; the
// controller runtime distinguishes between methods dealing with
// objects and lists.
type listAdapter interface {
asClientList() client.ObjectList
len() int
}
// universalAdapter is an adapter for any client.Object. Use this if
// there are no other methods needed.
type universalAdapter struct {
obj runtime.Object
obj client.Object
}
func (c universalAdapter) asRuntimeObject() runtime.Object {
func (c universalAdapter) asClientObject() client.Object {
return c.obj
}

View File

@@ -69,20 +69,20 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
err = kubeClient.Get(ctx, namespacedName, reconcile.object.asRuntimeObject())
err = kubeClient.Get(ctx, namespacedName, reconcile.object.asClientObject())
if err != nil {
return err
}
@@ -91,7 +91,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
return fmt.Errorf("resource is suspended")
}
logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, namespace)
logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, rootArgs.namespace)
if err := requestReconciliation(ctx, kubeClient, namespacedName, reconcile.object); err != nil {
return err
}
@@ -99,7 +99,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
lastHandledReconcileAt := reconcile.object.lastHandledReconcileRequest()
logger.Waitingf("waiting for %s reconciliation", reconcile.kind)
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
reconciliationHandled(ctx, kubeClient, namespacedName, reconcile.object, lastHandledReconcileAt)); err != nil {
return err
}
@@ -115,7 +115,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
func reconciliationHandled(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, obj reconcilable, lastHandledReconcileAt string) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, obj.asRuntimeObject())
err := kubeClient.Get(ctx, namespacedName, obj.asClientObject())
if err != nil {
return false, err
}
@@ -126,17 +126,17 @@ func reconciliationHandled(ctx context.Context, kubeClient client.Client,
func requestReconciliation(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, obj reconcilable) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
if err := kubeClient.Get(ctx, namespacedName, obj.asRuntimeObject()); err != nil {
if err := kubeClient.Get(ctx, namespacedName, obj.asClientObject()); err != nil {
return err
}
if ann := obj.GetAnnotations(); ann == nil {
obj.SetAnnotations(map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
})
} else {
ann[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
ann[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
obj.SetAnnotations(ann)
}
return kubeClient.Update(ctx, obj.asRuntimeObject())
return kubeClient.Update(ctx, obj.asClientObject())
})
}

View File

@@ -51,16 +51,16 @@ func reconcileAlertCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
@@ -74,13 +74,13 @@ func reconcileAlertCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("resource is suspended")
}
logger.Actionf("annotating Alert %s in %s namespace", name, namespace)
logger.Actionf("annotating Alert %s in %s namespace", name, rootArgs.namespace)
if alert.Annotations == nil {
alert.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
alert.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
alert.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
if err := kubeClient.Update(ctx, &alert); err != nil {
@@ -89,7 +89,7 @@ func reconcileAlertCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("Alert annotated")
logger.Waitingf("waiting for reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isAlertReady(ctx, kubeClient, namespacedName, &alert)); err != nil {
return err
}

View File

@@ -51,20 +51,20 @@ func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
logger.Actionf("annotating Provider %s in %s namespace", name, namespace)
logger.Actionf("annotating Provider %s in %s namespace", name, rootArgs.namespace)
var alertProvider notificationv1.Provider
err = kubeClient.Get(ctx, namespacedName, &alertProvider)
if err != nil {
@@ -73,10 +73,10 @@ func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
if alertProvider.Annotations == nil {
alertProvider.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
alertProvider.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
alertProvider.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
if err := kubeClient.Update(ctx, &alertProvider); err != nil {
return err
@@ -84,7 +84,7 @@ func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("Provider annotated")
logger.Waitingf("waiting for reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isAlertProviderReady(ctx, kubeClient, namespacedName, &alertProvider)); err != nil {
return err
}

View File

@@ -51,12 +51,14 @@ The reconcile kustomization command triggers a reconciliation of a HelmRelease r
RunE: reconcileHrCmdRun,
}
var (
type reconcileHelmReleaseFlags struct {
syncHrWithSource bool
)
}
var rhrArgs reconcileHelmReleaseFlags
func init() {
reconcileHrCmd.Flags().BoolVar(&syncHrWithSource, "with-source", false, "reconcile HelmRelease source")
reconcileHrCmd.Flags().BoolVar(&rhrArgs.syncHrWithSource, "with-source", false, "reconcile HelmRelease source")
reconcileCmd.AddCommand(reconcileHrCmd)
}
@@ -67,16 +69,16 @@ func reconcileHrCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
@@ -90,7 +92,7 @@ func reconcileHrCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("resource is suspended")
}
if syncHrWithSource {
if rhrArgs.syncHrWithSource {
switch helmRelease.Spec.Chart.Spec.SourceRef.Kind {
case sourcev1.HelmRepositoryKind:
err = reconcileSourceHelmCmdRun(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
@@ -105,14 +107,14 @@ func reconcileHrCmdRun(cmd *cobra.Command, args []string) error {
}
lastHandledReconcileAt := helmRelease.Status.LastHandledReconcileAt
logger.Actionf("annotating HelmRelease %s in %s namespace", name, namespace)
logger.Actionf("annotating HelmRelease %s in %s namespace", name, rootArgs.namespace)
if err := requestHelmReleaseReconciliation(ctx, kubeClient, namespacedName, &helmRelease); err != nil {
return err
}
logger.Successf("HelmRelease annotated")
logger.Waitingf("waiting for HelmRelease reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
helmReleaseReconciliationHandled(ctx, kubeClient, namespacedName, &helmRelease, lastHandledReconcileAt),
); err != nil {
return err
@@ -153,10 +155,10 @@ func requestHelmReleaseReconciliation(ctx context.Context, kubeClient client.Cli
}
if helmRelease.Annotations == nil {
helmRelease.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
helmRelease.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
helmRelease.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, helmRelease)
})

View File

@@ -50,12 +50,14 @@ The reconcile kustomization command triggers a reconciliation of a Kustomization
RunE: reconcileKsCmdRun,
}
var (
type reconcileKsFlags struct {
syncKsWithSource bool
)
}
var rksArgs reconcileKsFlags
func init() {
reconcileKsCmd.Flags().BoolVar(&syncKsWithSource, "with-source", false, "reconcile Kustomization source")
reconcileKsCmd.Flags().BoolVar(&rksArgs.syncKsWithSource, "with-source", false, "reconcile Kustomization source")
reconcileCmd.AddCommand(reconcileKsCmd)
}
@@ -66,16 +68,16 @@ func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var kustomization kustomizev1.Kustomization
@@ -88,7 +90,7 @@ func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("resource is suspended")
}
if syncKsWithSource {
if rksArgs.syncKsWithSource {
switch kustomization.Spec.SourceRef.Kind {
case sourcev1.GitRepositoryKind:
err = reconcileSourceGitCmdRun(nil, []string{kustomization.Spec.SourceRef.Name})
@@ -101,7 +103,7 @@ func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
}
lastHandledReconcileAt := kustomization.Status.LastHandledReconcileAt
logger.Actionf("annotating Kustomization %s in %s namespace", name, namespace)
logger.Actionf("annotating Kustomization %s in %s namespace", name, rootArgs.namespace)
if err := requestKustomizeReconciliation(ctx, kubeClient, namespacedName, &kustomization); err != nil {
return err
}
@@ -109,7 +111,7 @@ func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
logger.Waitingf("waiting for Kustomization reconciliation")
if err := wait.PollImmediate(
pollInterval, timeout,
rootArgs.pollInterval, rootArgs.timeout,
kustomizeReconciliationHandled(ctx, kubeClient, namespacedName, &kustomization, lastHandledReconcileAt),
); err != nil {
return err
@@ -142,10 +144,10 @@ func requestKustomizeReconciliation(ctx context.Context, kubeClient client.Clien
}
if kustomization.Annotations == nil {
kustomization.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
kustomization.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
kustomization.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, kustomization)
})

View File

@@ -51,16 +51,16 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
@@ -74,13 +74,13 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("resource is suspended")
}
logger.Actionf("annotating Receiver %s in %s namespace", name, namespace)
logger.Actionf("annotating Receiver %s in %s namespace", name, rootArgs.namespace)
if receiver.Annotations == nil {
receiver.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
receiver.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
receiver.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
if err := kubeClient.Update(ctx, &receiver); err != nil {
return err
@@ -88,7 +88,7 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("Receiver annotated")
logger.Waitingf("waiting for Receiver reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isReceiverReady(ctx, kubeClient, namespacedName, &receiver)); err != nil {
return err
}

View File

@@ -56,16 +56,16 @@ func reconcileSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var bucket sourcev1.Bucket
@@ -79,7 +79,7 @@ func reconcileSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
}
lastHandledReconcileAt := bucket.Status.LastHandledReconcileAt
logger.Actionf("annotating Bucket source %s in %s namespace", name, namespace)
logger.Actionf("annotating Bucket source %s in %s namespace", name, rootArgs.namespace)
if err := requestBucketReconciliation(ctx, kubeClient, namespacedName, &bucket); err != nil {
return err
}
@@ -87,7 +87,7 @@ func reconcileSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
logger.Waitingf("waiting for Bucket source reconciliation")
if err := wait.PollImmediate(
pollInterval, timeout,
rootArgs.pollInterval, rootArgs.timeout,
bucketReconciliationHandled(ctx, kubeClient, namespacedName, &bucket, lastHandledReconcileAt),
); err != nil {
return err
@@ -145,10 +145,10 @@ func requestBucketReconciliation(ctx context.Context, kubeClient client.Client,
}
if bucket.Annotations == nil {
bucket.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
bucket.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
bucket.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, bucket)
})

View File

@@ -54,16 +54,16 @@ func reconcileSourceGitCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.GitRepository
@@ -76,7 +76,7 @@ func reconcileSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("resource is suspended")
}
logger.Actionf("annotating GitRepository source %s in %s namespace", name, namespace)
logger.Actionf("annotating GitRepository source %s in %s namespace", name, rootArgs.namespace)
if err := requestGitRepositoryReconciliation(ctx, kubeClient, namespacedName, &repository); err != nil {
return err
}
@@ -84,7 +84,7 @@ func reconcileSourceGitCmdRun(cmd *cobra.Command, args []string) error {
lastHandledReconcileAt := repository.Status.LastHandledReconcileAt
logger.Waitingf("waiting for GitRepository source reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
gitRepositoryReconciliationHandled(ctx, kubeClient, namespacedName, &repository, lastHandledReconcileAt)); err != nil {
return err
}
@@ -116,10 +116,10 @@ func requestGitRepositoryReconciliation(ctx context.Context, kubeClient client.C
}
if repository.Annotations == nil {
repository.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
repository.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
repository.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, repository)
})

View File

@@ -55,16 +55,16 @@ func reconcileSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.HelmRepository
@@ -77,7 +77,7 @@ func reconcileSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("resource is suspended")
}
logger.Actionf("annotating HelmRepository source %s in %s namespace", name, namespace)
logger.Actionf("annotating HelmRepository source %s in %s namespace", name, rootArgs.namespace)
if err := requestHelmRepositoryReconciliation(ctx, kubeClient, namespacedName, &repository); err != nil {
return err
}
@@ -85,7 +85,7 @@ func reconcileSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
lastHandledReconcileAt := repository.Status.LastHandledReconcileAt
logger.Waitingf("waiting for HelmRepository source reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
helmRepositoryReconciliationHandled(ctx, kubeClient, namespacedName, &repository, lastHandledReconcileAt)); err != nil {
return err
}
@@ -117,10 +117,10 @@ func requestHelmRepositoryReconciliation(ctx context.Context, kubeClient client.
}
if repository.Annotations == nil {
repository.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
repository.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
repository.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, repository)
})

View File

@@ -55,33 +55,33 @@ func (resume resumeCommand) run(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
err = kubeClient.Get(ctx, namespacedName, resume.object.asRuntimeObject())
err = kubeClient.Get(ctx, namespacedName, resume.object.asClientObject())
if err != nil {
return err
}
logger.Actionf("resuming %s %s in %s namespace", resume.humanKind, name, namespace)
logger.Actionf("resuming %s %s in %s namespace", resume.humanKind, name, rootArgs.namespace)
resume.object.setUnsuspended()
if err := kubeClient.Update(ctx, resume.object.asRuntimeObject()); err != nil {
if err := kubeClient.Update(ctx, resume.object.asClientObject()); err != nil {
return err
}
logger.Successf("%s resumed", resume.humanKind)
logger.Waitingf("waiting for %s reconciliation", resume.kind)
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isReady(ctx, kubeClient, namespacedName, resume.object)); err != nil {
return err
}

View File

@@ -54,16 +54,16 @@ func resumeAlertCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var alert notificationv1.Alert
@@ -72,7 +72,7 @@ func resumeAlertCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("resuming Alert %s in %s namespace", name, namespace)
logger.Actionf("resuming Alert %s in %s namespace", name, rootArgs.namespace)
alert.Spec.Suspend = false
if err := kubeClient.Update(ctx, &alert); err != nil {
return err
@@ -80,7 +80,7 @@ func resumeAlertCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("Alert resumed")
logger.Waitingf("waiting for Alert reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isAlertResumed(ctx, kubeClient, namespacedName, &alert)); err != nil {
return err
}

View File

@@ -55,16 +55,16 @@ func resumeHrCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease
@@ -73,7 +73,7 @@ func resumeHrCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("resuming HelmRelease %s in %s namespace", name, namespace)
logger.Actionf("resuming HelmRelease %s in %s namespace", name, rootArgs.namespace)
helmRelease.Spec.Suspend = false
if err := kubeClient.Update(ctx, &helmRelease); err != nil {
return err
@@ -81,7 +81,7 @@ func resumeHrCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("HelmRelease resumed")
logger.Waitingf("waiting for HelmRelease reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isHelmReleaseResumed(ctx, kubeClient, namespacedName, &helmRelease)); err != nil {
return err
}

View File

@@ -54,16 +54,16 @@ func resumeKsCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var kustomization kustomizev1.Kustomization
@@ -72,7 +72,7 @@ func resumeKsCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("resuming Kustomization %s in %s namespace", name, namespace)
logger.Actionf("resuming Kustomization %s in %s namespace", name, rootArgs.namespace)
kustomization.Spec.Suspend = false
if err := kubeClient.Update(ctx, &kustomization); err != nil {
return err
@@ -80,7 +80,7 @@ func resumeKsCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("Kustomization resumed")
logger.Waitingf("waiting for Kustomization reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isKustomizationResumed(ctx, kubeClient, namespacedName, &kustomization)); err != nil {
return err
}

View File

@@ -54,16 +54,16 @@ func resumeReceiverCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var receiver notificationv1.Receiver
@@ -72,7 +72,7 @@ func resumeReceiverCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("resuming Receiver %s in %s namespace", name, namespace)
logger.Actionf("resuming Receiver %s in %s namespace", name, rootArgs.namespace)
receiver.Spec.Suspend = false
if err := kubeClient.Update(ctx, &receiver); err != nil {
return err
@@ -80,7 +80,7 @@ func resumeReceiverCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("Receiver resumed")
logger.Waitingf("waiting for Receiver reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isReceiverResumed(ctx, kubeClient, namespacedName, &receiver)); err != nil {
return err
}

View File

@@ -53,16 +53,16 @@ func resumeSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var bucket sourcev1.Bucket
@@ -71,7 +71,7 @@ func resumeSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("resuming source %s in %s namespace", name, namespace)
logger.Actionf("resuming source %s in %s namespace", name, rootArgs.namespace)
bucket.Spec.Suspend = false
if err := kubeClient.Update(ctx, &bucket); err != nil {
return err
@@ -79,7 +79,7 @@ func resumeSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("source resumed")
logger.Waitingf("waiting for Bucket reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isBucketResumed(ctx, kubeClient, namespacedName, &bucket)); err != nil {
return err
}

View File

@@ -53,16 +53,16 @@ func resumeSourceHelmChartCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.HelmChart
@@ -71,7 +71,7 @@ func resumeSourceHelmChartCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("resuming source %s in %s namespace", name, namespace)
logger.Actionf("resuming source %s in %s namespace", name, rootArgs.namespace)
repository.Spec.Suspend = false
if err := kubeClient.Update(ctx, &repository); err != nil {
return err
@@ -79,7 +79,7 @@ func resumeSourceHelmChartCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("source resumed")
logger.Waitingf("waiting for HelmChart reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isHelmChartResumed(ctx, kubeClient, namespacedName, &repository)); err != nil {
return err
}

View File

@@ -53,16 +53,16 @@ func resumeSourceGitCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.GitRepository
@@ -71,7 +71,7 @@ func resumeSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("resuming source %s in %s namespace", name, namespace)
logger.Actionf("resuming source %s in %s namespace", name, rootArgs.namespace)
repository.Spec.Suspend = false
if err := kubeClient.Update(ctx, &repository); err != nil {
return err
@@ -79,7 +79,7 @@ func resumeSourceGitCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("source resumed")
logger.Waitingf("waiting for GitRepository reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isGitRepositoryResumed(ctx, kubeClient, namespacedName, &repository)); err != nil {
return err
}

View File

@@ -53,16 +53,16 @@ func resumeSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.HelmRepository
@@ -71,7 +71,7 @@ func resumeSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("resuming source %s in %s namespace", name, namespace)
logger.Actionf("resuming source %s in %s namespace", name, rootArgs.namespace)
repository.Spec.Suspend = false
if err := kubeClient.Update(ctx, &repository); err != nil {
return err
@@ -79,7 +79,7 @@ func resumeSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("source resumed")
logger.Waitingf("waiting for HelmRepository reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isHelmRepositoryResumed(ctx, kubeClient, namespacedName, &repository)); err != nil {
return err
}

143
cmd/flux/source.go Normal file
View File

@@ -0,0 +1,143 @@
/*
Copyright 2021 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"sigs.k8s.io/controller-runtime/pkg/client"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
)
// These are general-purpose adapters for attaching methods to, for
// the various commands. The *List adapters implement len(), since
// it's used in at least a couple of commands.
// sourcev1.Bucket
var bucketType = apiType{
kind: sourcev1.BucketKind,
humanKind: "source bucket",
}
type bucketAdapter struct {
*sourcev1.Bucket
}
func (a bucketAdapter) asClientObject() client.Object {
return a.Bucket
}
// sourcev1.BucketList
type bucketListAdapter struct {
*sourcev1.BucketList
}
func (a bucketListAdapter) asClientList() client.ObjectList {
return a.BucketList
}
func (a bucketListAdapter) len() int {
return len(a.BucketList.Items)
}
// sourcev1.HelmChart
var helmChartType = apiType{
kind: sourcev1.HelmChartKind,
humanKind: "source chart",
}
type helmChartAdapter struct {
*sourcev1.HelmChart
}
func (a helmChartAdapter) asClientObject() client.Object {
return a.HelmChart
}
// sourcev1.ImagePolicyList
type helmChartListAdapter struct {
*sourcev1.HelmChartList
}
func (a helmChartListAdapter) asClientList() client.ObjectList {
return a.HelmChartList
}
func (a helmChartListAdapter) len() int {
return len(a.HelmChartList.Items)
}
// sourcev1.GitRepository
var gitRepositoryType = apiType{
kind: sourcev1.GitRepositoryKind,
humanKind: "source git",
}
type gitRepositoryAdapter struct {
*sourcev1.GitRepository
}
func (a gitRepositoryAdapter) asClientObject() client.Object {
return a.GitRepository
}
// sourcev1.GitRepositoryList
type gitRepositoryListAdapter struct {
*sourcev1.GitRepositoryList
}
func (a gitRepositoryListAdapter) asClientList() client.ObjectList {
return a.GitRepositoryList
}
func (a gitRepositoryListAdapter) len() int {
return len(a.GitRepositoryList.Items)
}
// sourcev1.HelmRepository
var helmRepositoryType = apiType{
kind: sourcev1.HelmRepositoryKind,
humanKind: "source helm",
}
type helmRepositoryAdapter struct {
*sourcev1.HelmRepository
}
func (a helmRepositoryAdapter) asClientObject() client.Object {
return a.HelmRepository
}
// sourcev1.HelmRepositoryList
type helmRepositoryListAdapter struct {
*sourcev1.HelmRepositoryList
}
func (a helmRepositoryListAdapter) asClientList() client.ObjectList {
return a.HelmRepositoryList
}
func (a helmRepositoryListAdapter) len() int {
return len(a.HelmRepositoryList.Items)
}

View File

@@ -42,7 +42,7 @@ type statusable interface {
func isReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, object statusable) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, object.asRuntimeObject())
err := kubeClient.Get(ctx, namespacedName, object.asClientObject())
if err != nil {
return false, err
}

View File

@@ -53,26 +53,26 @@ func (suspend suspendCommand) run(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
err = kubeClient.Get(ctx, namespacedName, suspend.object.asRuntimeObject())
err = kubeClient.Get(ctx, namespacedName, suspend.object.asClientObject())
if err != nil {
return err
}
logger.Actionf("suspending %s %s in %s namespace", suspend.humanKind, name, namespace)
logger.Actionf("suspending %s %s in %s namespace", suspend.humanKind, name, rootArgs.namespace)
suspend.object.setSuspended()
if err := kubeClient.Update(ctx, suspend.object.asRuntimeObject()); err != nil {
if err := kubeClient.Update(ctx, suspend.object.asClientObject()); err != nil {
return err
}
logger.Successf("%s suspended", suspend.humanKind)

View File

@@ -47,16 +47,16 @@ func suspendAlertCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var alert notificationv1.Alert
@@ -65,7 +65,7 @@ func suspendAlertCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("suspending Alert %s in %s namespace", name, namespace)
logger.Actionf("suspending Alert %s in %s namespace", name, rootArgs.namespace)
alert.Spec.Suspend = true
if err := kubeClient.Update(ctx, &alert); err != nil {
return err

View File

@@ -48,16 +48,16 @@ func suspendHrCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease
@@ -66,7 +66,7 @@ func suspendHrCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("suspending HelmRelease %s in %s namespace", name, namespace)
logger.Actionf("suspending HelmRelease %s in %s namespace", name, rootArgs.namespace)
helmRelease.Spec.Suspend = true
if err := kubeClient.Update(ctx, &helmRelease); err != nil {
return err

View File

@@ -47,16 +47,16 @@ func suspendKsCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var kustomization kustomizev1.Kustomization
@@ -65,7 +65,7 @@ func suspendKsCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("suspending kustomization %s in %s namespace", name, namespace)
logger.Actionf("suspending kustomization %s in %s namespace", name, rootArgs.namespace)
kustomization.Spec.Suspend = true
if err := kubeClient.Update(ctx, &kustomization); err != nil {
return err

View File

@@ -47,16 +47,16 @@ func suspendReceiverCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var receiver notificationv1.Receiver
@@ -65,7 +65,7 @@ func suspendReceiverCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("suspending Receiver %s in %s namespace", name, namespace)
logger.Actionf("suspending Receiver %s in %s namespace", name, rootArgs.namespace)
receiver.Spec.Suspend = true
if err := kubeClient.Update(ctx, &receiver); err != nil {
return err

View File

@@ -46,16 +46,16 @@ func suspendSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var bucket sourcev1.Bucket
@@ -64,7 +64,7 @@ func suspendSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("suspending source %s in %s namespace", name, namespace)
logger.Actionf("suspending source %s in %s namespace", name, rootArgs.namespace)
bucket.Spec.Suspend = true
if err := kubeClient.Update(ctx, &bucket); err != nil {
return err

View File

@@ -46,16 +46,16 @@ func suspendSourceHelmChartCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var chart sourcev1.HelmChart
@@ -64,7 +64,7 @@ func suspendSourceHelmChartCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("suspending source %s in %s namespace", name, namespace)
logger.Actionf("suspending source %s in %s namespace", name, rootArgs.namespace)
chart.Spec.Suspend = true
if err := kubeClient.Update(ctx, &chart); err != nil {
return err

View File

@@ -46,16 +46,16 @@ func suspendSourceGitCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.GitRepository
@@ -64,7 +64,7 @@ func suspendSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("suspending source %s in %s namespace", name, namespace)
logger.Actionf("suspending source %s in %s namespace", name, rootArgs.namespace)
repository.Spec.Suspend = true
if err := kubeClient.Update(ctx, &repository); err != nil {
return err

View File

@@ -46,16 +46,16 @@ func suspendSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.HelmRepository
@@ -64,7 +64,7 @@ func suspendSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
return err
}
logger.Actionf("suspending source %s in %s namespace", name, namespace)
logger.Actionf("suspending source %s in %s namespace", name, rootArgs.namespace)
repository.Spec.Suspend = true
if err := kubeClient.Update(ctx, &repository); err != nil {
return err

View File

@@ -45,38 +45,40 @@ var uninstallCmd = &cobra.Command{
RunE: uninstallCmdRun,
}
var (
uninstallCRDs bool
uninstallResources bool
uninstallDryRun bool
uninstallSilent bool
)
type uninstallFlags struct {
crds bool
resources bool
dryRun bool
silent bool
}
var uninstallArgs uninstallFlags
func init() {
uninstallCmd.Flags().BoolVar(&uninstallResources, "resources", true,
uninstallCmd.Flags().BoolVar(&uninstallArgs.resources, "resources", true,
"removes custom resources such as Kustomizations, GitRepositories and HelmRepositories")
uninstallCmd.Flags().BoolVar(&uninstallCRDs, "crds", false,
uninstallCmd.Flags().BoolVar(&uninstallArgs.crds, "crds", false,
"removes all CRDs previously installed")
uninstallCmd.Flags().BoolVar(&uninstallDryRun, "dry-run", false,
uninstallCmd.Flags().BoolVar(&uninstallArgs.dryRun, "dry-run", false,
"only print the object that would be deleted")
uninstallCmd.Flags().BoolVarP(&uninstallSilent, "silent", "s", false,
uninstallCmd.Flags().BoolVarP(&uninstallArgs.silent, "silent", "s", false,
"delete components without asking for confirmation")
rootCmd.AddCommand(uninstallCmd)
}
func uninstallCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if !uninstallDryRun && !uninstallSilent {
if !uninstallArgs.dryRun && !uninstallArgs.silent {
prompt := promptui.Prompt{
Label: fmt.Sprintf("Are you sure you want to delete the %s namespace", namespace),
Label: fmt.Sprintf("Are you sure you want to delete the %s namespace", rootArgs.namespace),
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
@@ -85,7 +87,7 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
}
dryRun := "--dry-run=server"
deleteResources := uninstallResources || uninstallCRDs
deleteResources := uninstallArgs.resources || uninstallArgs.crds
// known kinds with finalizers
namespacedKinds := []string{
@@ -96,8 +98,8 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
// suspend bootstrap kustomization to avoid finalizers deadlock
kustomizationName := types.NamespacedName{
Namespace: namespace,
Name: namespace,
Namespace: rootArgs.namespace,
Name: rootArgs.namespace,
}
var kustomization kustomizev1.Kustomization
err = kubeClient.Get(ctx, kustomizationName, &kustomization)
@@ -113,21 +115,21 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
// add HelmRelease kind to deletion list if exists
var list helmv2.HelmReleaseList
if err := kubeClient.List(ctx, &list, client.InNamespace(namespace)); err == nil {
if err := kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace)); err == nil {
namespacedKinds = append(namespacedKinds, helmv2.HelmReleaseKind)
}
if deleteResources {
logger.Actionf("uninstalling custom resources")
for _, kind := range namespacedKinds {
if err := deleteAll(ctx, kind, uninstallDryRun); err != nil {
if err := deleteAll(ctx, kind, uninstallArgs.dryRun); err != nil {
logger.Failuref("kubectl: %s", err.Error())
}
}
}
var kinds []string
if uninstallCRDs {
if uninstallArgs.crds {
kinds = append(kinds, "crds")
}
@@ -138,13 +140,13 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
for _, kind := range kinds {
kubectlArgs := []string{
"delete", kind,
"-l", fmt.Sprintf("app.kubernetes.io/instance=%s", namespace),
"--ignore-not-found", "--timeout", timeout.String(),
"-l", fmt.Sprintf("app.kubernetes.io/instance=%s", rootArgs.namespace),
"--ignore-not-found", "--timeout", rootArgs.timeout.String(),
}
if uninstallDryRun {
if uninstallArgs.dryRun {
kubectlArgs = append(kubectlArgs, dryRun)
}
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
return fmt.Errorf("uninstall failed: %w", err)
}
}
@@ -157,13 +159,13 @@ func deleteAll(ctx context.Context, kind string, dryRun bool) error {
kubectlArgs := []string{
"delete", kind, "--ignore-not-found",
"--all", "--all-namespaces",
"--timeout", timeout.String(),
"--timeout", rootArgs.timeout.String(),
}
if dryRun {
kubectlArgs = append(kubectlArgs, "--dry-run=server")
}
_, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubeconfig, kubecontext, kubectlArgs...)
_, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...)
return err
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -9,7 +9,6 @@ The bootstrap sub-commands bootstrap the toolkit components on the targeted Git
### Options
```
--arch arch cluster architecture, available options are: (amd64, arm, arm64) (default amd64)
--branch string default branch (for GitHub this must match the default branch setting for the organization) (default "main")
--cluster-domain string internal cluster domain (default "cluster.local")
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])

View File

@@ -30,7 +30,7 @@ flux bootstrap github [flags]
flux bootstrap github --owner=<organization> --repository=<repo name> --path=dev-cluster
# Run bootstrap for a public repository on a personal account
flux bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
flux bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
# Run bootstrap for a private repo hosted on GitHub Enterprise using SSH auth
flux bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain> --ssh-hostname=<domain>
@@ -61,7 +61,6 @@ flux bootstrap github [flags]
### Options inherited from parent commands
```
--arch arch cluster architecture, available options are: (amd64, arm, arm64) (default amd64)
--branch string default branch (for GitHub this must match the default branch setting for the organization) (default "main")
--cluster-domain string internal cluster domain (default "cluster.local")
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])

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