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

Compare commits

..

558 Commits

Author SHA1 Message Date
Hidde Beydals
31d5cb4ad8 Merge pull request #557 from fluxcd/build/tmp-dir-rm
Properly clean-up package build dirs
2020-12-04 21:57:26 +01:00
Hidde Beydals
21576fe459 Properly clean-up package build dirs
Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-12-04 21:49:41 +01:00
Hidde Beydals
65863a2cb8 Merge pull request #556 from fluxcd/fix-goreleaser-aur-publish
Use mock archive for aur publishers
2020-12-04 21:19:47 +01:00
Aurel Canciu
cdd055bfa6 Use mock archive for aur publishers
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-12-04 22:10:52 +02:00
Hidde Beydals
fedf960a5f Merge pull request #555 from fluxcd/fix-goreleaser-aur-publish
Remove `ids` GoReleaser attr in AUR pkg publisher
2020-12-04 20:31:31 +01:00
Aurel Canciu
4546fa3270 Remove ids GoReleaser attr in AUR pkg publisher
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-12-04 21:22:13 +02:00
Hidde Beydals
979f3f557c Merge pull request #554 from fluxcd/fix-goreleaser-aur-publish
Fix GoReleaser AUR publish concurrent exec issue
2020-12-04 20:08:08 +01:00
Aurel Canciu
48a38a8a5d Fix GoReleaser AUR publish concurrent exec issue
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-12-04 20:59:55 +02:00
Stefan Prodan
9880b32b0a Merge pull request #553 from fluxcd/fix-goreleaser-aur-publish
Fix GoReleaser AUR package publishing
2020-12-04 20:17:50 +02:00
Aurel Canciu
e664ef7a8d Fix GoReleaser AUR package publishing
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-12-04 20:08:32 +02:00
Stefan Prodan
7cfef379d0 Merge pull request #552 from fluxcd/fix-workflow-syntax-error
Fix GitHub Actions release workflow syntax error
2020-12-04 19:46:13 +02:00
Aurel Canciu
093a91c7fc Fix syntax error introduced earlier
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-12-04 19:36:01 +02:00
Hidde Beydals
94687a047f Merge pull request #551 from fluxcd/update-components
Update helm-controller to v0.4.2
2020-12-04 18:04:30 +01:00
fluxcdbot
38fdc603ad Update toolkit components 2020-12-04 16:52:10 +00:00
Stefan Prodan
55cecb7f96 Merge pull request #550 from fluxcd/install-with-kubectl
Publish install manifest to GitHub releases
2020-12-04 18:51:01 +02:00
Stefan Prodan
32e949598e Publish install manifest to GitHub releases
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-12-04 18:33:26 +02:00
Stefan Prodan
6d0c8aff4b Merge pull request #549 from fluxcd/add-priv-key-secret-for-goreleaser
Add AUR_BOT_SSH_PRIVATE_KEY env var for goreleaser
2020-12-04 17:58:54 +02:00
Aurel Canciu
5eecf03af6 Add AUR_BOT_SSH_PRIVATE_KEY env var for goreleaser
The AUR_BOT_SSH_PRIVATE_KEY environment variable needs to be set in
goreleaser so publishing the packages to AUR can work.

Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-12-04 17:49:25 +02:00
Stefan Prodan
76e9884032 Merge pull request #547 from fluxcd/create-secret-git
Add create secret git command
2020-12-04 17:39:08 +02:00
Stefan Prodan
9867c4baf0 Add create secret git command
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-12-04 16:54:13 +02:00
Stefan Prodan
2bc05c8cbd Merge pull request #548 from fluxcd/fix-md-aur-docs
Fix list parsing issue in the docs
2020-12-04 16:53:40 +02:00
Aurel Canciu
d15b0107e4 Fix list parsing issue in the docs
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-12-04 16:31:18 +02:00
Aurel Canciu
c64cb1304d Merge pull request #532 from fluxcd/aur-publish
Automated AUR publishing
2020-12-04 16:10:15 +02:00
Aurel Canciu
c1f209c7a5 Add information about the AUR packages to docs
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-12-04 16:01:33 +02:00
Aurel Canciu
116ccd6b3b Rename flux-git to flux-scm to prevent collision
A flux-git package already exists in AUR

Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-12-04 16:01:32 +02:00
Aurel Canciu
b6f30ae3e1 Move aur package templates to .github/aur
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-12-04 16:01:32 +02:00
Aurel Canciu
5c522ed2e1 Add publisher scripts and gorelease config
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-12-04 16:01:32 +02:00
Aurel Canciu
bc29b80912 Add PKGBUILD templates
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-12-04 16:01:32 +02:00
Stefan Prodan
cfbc17fbf8 Merge pull request #546 from fluxcd/label-secrets
Add labels to generated secrets
2020-12-04 13:46:42 +02:00
Stefan Prodan
af0c939302 Add labels to generated secrets
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-12-04 13:15:37 +02:00
Michael Bridgen
e02538d38d Merge pull request #441 from fluxcd/component-readiness-indication
Show the roadmap status more prominently and precisely
2020-12-03 16:32:46 +00:00
Michael Bridgen
001d37567c Provide pointers to the install guides in roadmap
This gives people a way into the software, alongside the idea of how
ready it is.

Signed-off-by: Michael Bridgen <michael@weave.works>
2020-12-03 16:22:56 +00:00
Michael Bridgen
af82ce31a6 Bring image automation roadmap up to date
Specifically,

 - using credentials from a secret is done
 - the CLI integration is underway

I gave the %-complete a decent bump to reflect those, and all the work
on making the image-* controllers have all the GOTK dials and knobs
e.g., suspend.

Signed-off-by: Michael Bridgen <michael@weave.works>
2020-12-03 16:09:27 +00:00
Michael Bridgen
12ad4908fa Separate out "scans at all" from authentication
This makes it a clearer that the component does something worthwhile,
and is lacking mainly in platform-specific support.

Signed-off-by: Michael Bridgen <michael@weave.works>
2020-12-03 16:06:22 +00:00
Hidde Beydals
40ef94ab45 Merge pull request #522 from vfarcic/main
Add link to video review from Viktor Farcic
2020-12-01 14:37:22 +01:00
Viktor Farcic
8834ab0210 Video
Signed-off-by: Viktor Farcic <viktor@farcic.com>
2020-12-01 14:24:45 +01:00
Stefan Prodan
128d23720f Merge pull request #535 from fluxcd/gh-action-auto-updates
Automate Flux upgrades with GitHub Actions
2020-12-01 12:10:36 +02:00
Stefan Prodan
90f4891ca9 Automate Flux upgrades with GitHub Actions
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-12-01 11:16:26 +02:00
Stefan Prodan
61ac81c4d9 Merge pull request #534 from fluxcd/docs-bootstrap
Specify where to place Kubernetes manifests after bootstrap
2020-12-01 10:30:01 +02:00
Stefan Prodan
bd05a8173c Specify where to place Kubernetes manifests after bootstrap
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-12-01 09:46:28 +02:00
Hidde Beydals
e3d6461a80 Merge pull request #528 from fluxcd/update-components
Update helm-controller to v0.4.1
2020-11-30 13:21:29 +01:00
fluxcdbot
2bb582f7ed Update toolkit components 2020-11-30 12:10:44 +00:00
Stefan Prodan
2f9a52852f Merge pull request #527 from fluxcd/tenant-e2e
Add e2e test for create tenant
2020-11-30 12:25:31 +02:00
Stefan Prodan
137f083b4d Add e2e test for create tenant
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-30 12:16:01 +02:00
Stefan Prodan
11f4c54a40 Merge pull request #525 from fluxcd/fixes
Fix tenant and reconcile commands
2020-11-30 11:46:36 +02:00
Stefan Prodan
c813eaf6d1 Do not try to reconcile a suspended object
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-30 11:39:55 +02:00
Stefan Prodan
ffdaa9dfe9 Fix tenant service account binding
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-30 10:28:03 +02:00
Stefan Prodan
182928002b Merge pull request #526 from phillebaba/add-maintainer
Add Philip Laine to maintainer list
2020-11-30 10:27:29 +02:00
Philip Laine
7222af2b7e Add Philip Laine to maintainer list
Signed-off-by: Philip Laine <philip.laine@xenit.se>
2020-11-29 19:17:51 +01:00
Stefan Prodan
034ead5272 Merge pull request #521 from fluxcd/improve-install-script-arch-detection
Improve installer list match for arm arches
2020-11-29 14:19:48 +02:00
Aurel Canciu
eca1f19e95 Improve installer list match for arm arches
`uname -m` will print out architecture codenames based on UTS_MACHINE
and COMPAT_UTS_MACHINE kernel defined constants. These extra values will
ensure the right version of the arm binary is installed on most Linux
systems running on ARM CPUs.

Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-11-27 19:38:06 +02:00
Michael Bridgen
ec70c14649 Merge pull request #520 from fluxcd/fluxv2-maintainers
Note the shared Flux v2 maintainers and team
2020-11-27 16:05:07 +00:00
Michael Bridgen
65d906a735 Note the shared Flux v2 maintainers and team
Many of the GitOps Toolkit controllers will share maintainers with
this repo, acting as the central Flux v2 repo. For convenience of
tracking membership and applying permissions, we can share maintainers
by:

 - referring to the MAINTAINERS file here, from elsewhere;
 - making a GitHub team that tracks those shared maintainers.

This commit makes a note of this in the MAINTAINERS file, to inform
people of the arrangement, and remind them to keep the team up to
date.

Signed-off-by: Michael Bridgen <michael@weave.works>
2020-11-27 12:44:17 +00:00
Stefan Prodan
b981bae1db Merge pull request #519 from fluxcd/service-account
Add service account arg to create commands
2020-11-27 12:28:25 +02:00
Stefan Prodan
d2df9ccf33 Add service account arg to create commands
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-27 12:20:55 +02:00
Stefan Prodan
5e51f51449 Merge pull request #518 from fluxcd/docs-upgrade
Add upgrade docs to install guide
2020-11-27 12:20:07 +02:00
Stefan Prodan
2c044a27e4 Add upgrade docs to install guide
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-27 08:44:34 +02:00
Hidde Beydals
d274a1115e Merge pull request #516 from fluxcd/update-components
Update source-controller to v0.4.1
2020-11-26 19:27:32 +01:00
fluxcdbot
bfae2899f3 Update toolkit components 2020-11-26 18:16:36 +00:00
Stefan Prodan
5352a7e13a Merge pull request #513 from fluxcd/update-components
Update toolkit components to v0.4.0
2020-11-26 18:45:38 +02:00
fluxcdbot
c49f9ef26a Update toolkit components 2020-11-26 16:32:23 +00:00
Stefan Prodan
4a7376c5f5 Merge pull request #512 from fluxcd/suspend-sources
Implement suspend/resume commands for sources
2020-11-26 17:25:47 +02:00
Stefan Prodan
567ce7f987 Add suspend status to get sources commands
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-26 17:17:50 +02:00
Stefan Prodan
26bc0a8100 Add source suspend/resume commands to docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-26 16:45:25 +02:00
Stefan Prodan
e7ff319685 Add resume source commands
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-26 16:40:54 +02:00
Stefan Prodan
072138deff Add suspend source commands
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-26 16:22:47 +02:00
Stefan Prodan
dd8dc90c1e Update source-controller to v0.4.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-26 16:20:00 +02:00
Stefan Prodan
8f1da33375 Merge pull request #511 from fluxcd/kubectl
Set kubecontext and kubeconfig for kubectl exec
2020-11-26 12:04:46 +02:00
Stefan Prodan
c02fbc2794 Set kubecontext and kubeconfig for kubectl exec
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-26 11:53:08 +02:00
Stefan Prodan
371db07108 Merge pull request #506 from chanwit/sops-doc
Add a note not to apply SOPS encrypted secrets directly
2020-11-25 17:49:49 +02:00
Chanwit Kaewkasi
99f5dbf16b add a note not to apply encrypted secrets directly
Signed-off-by: Chanwit Kaewkasi <chanwit@gmail.com>
2020-11-25 22:26:52 +07:00
Stefan Prodan
0db06c8962 Merge pull request #505 from fluxcd/tenant-sa
Add service accounts to tenant command
2020-11-25 17:22:49 +02:00
Stefan Prodan
a8e5876b2e Add create tenant to CLI docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-25 16:42:52 +02:00
Stefan Prodan
8273851b73 Add service accounts to tenant command
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-25 16:39:00 +02:00
Stefan Prodan
c2967240bb Merge pull request #501 from mewzherder/patch-6
Update Upcoming events w/ Nov 30 talk
2020-11-25 16:38:35 +02:00
mewzherder
282a6270c8 Update Upcoming events w/ Nov 30 talk
Signed-off-by: mewzherder <tamao@weave.works>
2020-11-24 09:03:10 -08:00
Stefan Prodan
1b299fad90 Merge pull request #498 from fluxcd/gh-action
Add GitHub Action for Flux CLI
2020-11-23 19:15:34 +02:00
Stefan Prodan
aa8dced7ad Add GitHub Action for Flux CLI
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-23 17:58:06 +02:00
Stefan Prodan
050ba951b0 Merge pull request #496 from gtseres/main
Add reference to the bootstrap migration
2020-11-23 15:49:53 +02:00
George Tseres
5e47c16099 Update docs/guides/flux-v1-migration.md
Co-authored-by: Stefan Prodan <stefan.prodan@gmail.com>
Signed-off-by: gtseres <george.tseres@gmail.com>
2020-11-23 15:39:39 +02:00
George Tseres
902db4c732 Add reference to the bootstrap migration
Signed-off-by: gtseres <george.tseres@gmail.com>
2020-11-23 15:28:42 +02:00
Stefan Prodan
86462fbee6 Merge pull request #491 from fluxcd/hr-values-from
Add values-from arg to create helmrelease cmd
2020-11-23 11:57:34 +02:00
Stefan Prodan
48bed79439 Add values-from arg to create helmrelease cmd
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-23 11:29:35 +02:00
Stefan Prodan
26b61c2b6b Merge pull request #492 from fluxcd/hr-kustomize-generators
Add docs on how to use Kustomize to generate Helm values
2020-11-23 10:18:54 +02:00
Stefan Prodan
3b2253ddc0 Add docs on how to use Kustomize to generate Helm values
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-22 11:30:35 +02:00
Stefan Prodan
5ddcb39129 Merge pull request #487 from fluxcd/sops-aws
Add AWS IAM role example to SOPS docs
2020-11-20 15:34:59 +02:00
Stefan Prodan
59adef5bcc Add AWS IAM role example to SOPS docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-20 15:26:10 +02:00
Stefan Prodan
875aefc8dd Merge pull request #486 from relu/add-relu-to-maintainers
Add @relu to maintainers list
2020-11-20 15:20:35 +02:00
Aurel Canciu
0dbc9d213e Add @relu to maintainers list
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-11-20 15:03:15 +02:00
Hidde Beydals
9f4c53e321 Merge pull request #484 from fluxcd/source-reconcile-at
Utilize LastHandledReconcileAt for source reconcile commands
2020-11-20 13:35:27 +01:00
Hidde Beydals
3c8716f6ac Utilize LastHandledReconcileAt for reconcile cmds
Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-11-20 13:28:28 +01:00
Hidde Beydals
1a7f31ae2e Merge pull request #485 from fluxcd/update-components
Update toolkit component manifests to v0.3.0
2020-11-20 13:28:18 +01:00
fluxcdbot
64ad69acfe Update toolkit components 2020-11-20 12:21:02 +00:00
Stefan Prodan
9f47b55aa9 Merge pull request #474 from relu/adopt-k8s-conditions
Update components to v0.3.0
2020-11-20 13:46:11 +02:00
Aurel Canciu
53a1db0703 Adjustments to support new sa name in kustomize
Supporting changes in fluxcd/kustomize-controller#180

Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-11-20 13:36:36 +02:00
Aurel Canciu
2a789ec705 Refactor to adopt k8s standardized Condition type
Updates to use metav1.Condition type and removes references for
deprecated corev1.Condition* constants and uses the new k8s api/meta
helpers in place of the old pkg/apis/meta types.

Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-11-20 13:19:40 +02:00
Hidde Beydals
3047b25193 Merge pull request #476 from fluxcd/update-components
Update helm-controller to v0.2.2
2020-11-18 12:36:12 +01:00
fluxcdbot
f66399cdc0 Update toolkit components 2020-11-18 11:14:54 +00:00
Stefan Prodan
37fb0f632b Merge pull request #473 from fluxcd/update-components
Update helm-controller to v0.2.1
2020-11-17 13:59:54 +02:00
fluxcdbot
e5dd0c7ff8 Update toolkit components 2020-11-17 11:48:54 +00:00
Stefan Prodan
51392cd54c Merge pull request #468 from RossyWhite/fix-dryrun-option
Fix --dry-run option
2020-11-16 17:31:42 +02:00
RossyWhite
02bcb4ff3c Fix --dry-run option
Signed-off-by: RossyWhite <daikishiroi@gmail.com>
2020-11-16 18:03:08 +09:00
Stefan Prodan
d84297a5b5 Merge pull request #463 from fluxcd/update-components
Update source-controller to v0.2.2
2020-11-12 18:24:28 +02:00
fluxcdbot
c3876e30a9 Update toolkit components 2020-11-12 16:11:58 +00:00
Stefan Prodan
10711ed780 Merge pull request #462 from fluxcd/update-components
Update kustomize-controller to v0.2.2
2020-11-12 17:29:43 +02:00
fluxcdbot
de4e266e33 Update toolkit components 2020-11-12 15:17:44 +00:00
Stefan Prodan
15442969f8 Merge pull request #461 from fluxcd/fix-install-path
Fix cluster path in install docs
2020-11-12 16:30:08 +02:00
Stefan Prodan
bed48ada82 Fix cluster path in install docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-12 16:14:05 +02:00
Stefan Prodan
a66004f567 Merge pull request #458 from fluxcd/kind-update
Update engineerd/setup-kind to v0.5.0
2020-11-12 12:16:07 +02:00
Stefan Prodan
72a4e3b3b8 Update engineerd/setup-kind to v0.5.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-12 12:03:25 +02:00
Stefan Prodan
16761e4fca Merge pull request #455 from fluxcd/fix-gh-https
Fix GitHub bootstrap with token auth
2020-11-12 12:01:58 +02:00
Stefan Prodan
ba34a6d401 Fix GitHub bootstrap with token auth
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-12 09:47:04 +02:00
Stefan Prodan
23912e4091 Merge pull request #452 from fluxcd/terraform-provider
Add the Terraform provider to install docs
2020-11-11 17:26:18 +02:00
Stefan Prodan
17468cb5f5 Add the Terraform provider to install docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-11 17:16:14 +02:00
Stefan Prodan
5ea7aa0a75 Merge pull request #450 from fluxcd/ssh-host-github
Add token authentication option to bootstrap
2020-11-11 16:49:43 +02:00
Stefan Prodan
7792cd6a10 Add token authentication option to bootstrap
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-11 16:41:18 +02:00
Stefan Prodan
237d186207 Merge pull request #444 from arodus/patch-1
Fix create tenant command export
2020-11-11 14:27:59 +02:00
Sebastian Karasek
c41487598e Fix create tenant command export
Signed-off-by: Sebastian Karasek <sebastian@karasek.io>
2020-11-11 13:15:17 +01:00
Stefan Prodan
2c0aa3c3af Merge pull request #446 from fluxcd/helm-values-file
Add values file example to Helm docs
2020-11-11 11:46:45 +02:00
Stefan Prodan
cedb33b2b9 Add values file example to Helm docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-11 10:26:03 +02:00
Stefan Prodan
06a3aa2c60 Merge pull request #442 from fluxcd/helm-upgrade-guide-typo
docs: fix typo
2020-11-11 09:08:36 +02:00
Hidde Beydals
3fadc94711 docs: include releaseName in HelmRelease example
Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-11-10 18:27:06 +01:00
Hidde Beydals
61d02bf5e4 docs: fix typo
Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-11-10 18:20:05 +01:00
Stefan Prodan
a62976461e Merge pull request #439 from fluxcd/update-components
Update notification-controller to v0.2.1
2020-11-09 17:46:07 +02:00
fluxcdbot
d7a893acf9 Update toolkit components 2020-11-09 15:37:09 +00:00
Stefan Prodan
0c67e75fb6 Merge pull request #438 from fluxcd/check-print-images
List component images in check cmd
2020-11-09 17:12:13 +02:00
Stefan Prodan
e6b84c4cfc List components images in check cmd
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-09 16:10:06 +02:00
Stefan Prodan
5d2e793386 Merge pull request #437 from nguyenductoan/docs-fix-typo
docs: fix typo
2020-11-09 14:31:43 +02:00
nguyenductoan
f0517906b7 docs: fix typo
Signed-off-by: nguyenductoan <ductoan593@gmail.com>
2020-11-09 18:43:24 +07:00
Stefan Prodan
16fa167931 Merge pull request #435 from phillebaba/sops-azure-auth
Update authentication hint for Azure
2020-11-08 09:47:16 +02:00
Philip Laine
b036999b8c Update authentication hint for Azure
Signed-off-by: Philip Laine <philip.laine@xenit.se>
2020-11-07 16:05:18 +01:00
Stefan Prodan
1911766b7b Merge pull request #434 from fluxcd/target-namespace-ks
Add target namespace to create ks cmd
2020-11-07 14:14:57 +02:00
Stefan Prodan
9f7835d818 Add target namespace to create ks cmd
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-07 14:01:40 +02:00
Stefan Prodan
1df45e4857 Merge pull request #433 from fluxcd/customize-flux-manifests
Add customize Flux manifests section to install docs
2020-11-07 13:58:40 +02:00
Stefan Prodan
47a1743965 Add customize Flux manifests section to install docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-07 13:44:47 +02:00
Hidde Beydals
d5844bbdaa Merge pull request #430 from fluxcd/migration-title-fix
Rename migration menu items
2020-11-06 13:08:57 +01:00
Hidde Beydals
128c87ab33 Rename migration menu items
As they are used in the metadata, instead of the title from the
document.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-11-06 12:58:51 +01:00
Hidde Beydals
f4adcae79a Merge pull request #425 from plod/main
docs: fixing command for expected output
2020-11-05 13:09:18 +01:00
Daniel Morgan
ba4df070cf fixing command for expected output
The \ before the comment here means the subsequent lines end up getting commented out (and then not exported), see: https://stackoverflow.com/questions/9522631/how-to-put-a-line-comment-for-a-multi-line-command

Signed-off-by: Daniel Morgan <daniel@morgan.cymru>
2020-11-05 11:53:57 +00:00
Hidde Beydals
ce4ecfb388 Merge pull request #421 from fluxcd/update-roadmap
Update Helm v3 feature parity roadmap
2020-11-04 21:35:10 +01:00
Hidde Beydals
e6006e0833 Update Helm v3 feature parity roadmap
Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-11-04 21:21:58 +01:00
Michael Bridgen
d500cc0bd1 Merge pull request #422 from fluxcd/flux2-www-intro
Rework Flux2 website intro
2020-11-04 15:56:01 +00:00
Michael Bridgen
71995b4f83 Refine description of Sources
Signed-off-by: Michael Bridgen <michael@weave.works>
2020-11-04 15:38:23 +00:00
Michael Bridgen
932c91d022 Move gitops toolkit index under components/
Signed-off-by: Michael Bridgen <michael@weave.works>
2020-11-04 15:37:07 +00:00
Michael Bridgen
107e7424d1 Explain more up-front in website homepage
This commit

 - adds a brief explanation of what Flux does
 - makes the target features a little more self-explanatory
 - gives GitOps Toolkit its own index page

Signed-off-by: Michael Bridgen <michael@weave.works>
2020-11-04 15:37:02 +00:00
Michael Bridgen
c93181c0ad Add section on target users
Signed-off-by: Michael Bridgen <michael@weave.works>
2020-11-04 15:29:12 +00:00
Stefan Prodan
050fca6767 Merge pull request #423 from fluxcd/update-components
Update kustomize-controller to v0.2.1
2020-11-04 17:22:53 +02:00
fluxcdbot
71827b4a1a Update toolkit components 2020-11-04 15:11:46 +00:00
Stefan Prodan
1d0315bf5e Merge pull request #420 from fluxcd/tagline
Update tag line and featured talks
2020-11-04 15:35:45 +02:00
Stefan Prodan
b2b64e7283 Update tag line and featured talks
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-04 15:26:13 +02:00
Hidde Beydals
fe0e2edd37 Merge pull request #419 from fluxcd/helm-operator-guide
Add Helm Operator migration guide
2020-11-04 13:25:34 +01:00
Hidde Beydals
e5bb3d5645 Add Helm Operator migration guide
Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-11-04 12:37:09 +01:00
Stefan Prodan
b88a99347b Merge pull request #416 from L3o-pold/main
Fix datasource for cluster Grafana dashboard
2020-11-03 19:30:51 +02:00
Léopold Jacquot
344a909d19 Fix datasource for cluster Grafana dashboard
Signed-off-by: Léopold Jacquot <leopold.jacquot@infomaniak.com>
2020-11-03 17:50:29 +01:00
Stefan Prodan
3cbe3aab25 Merge pull request #405 from relu/k8s-v1.19
Update k8s to 1.19 + kustomize 0.6.4
2020-11-03 13:06:19 +02:00
Aurel Canciu
9e3a4b1810 Update pkg components & k8s 1.19, kustomize 0.6.4
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2020-11-02 23:56:20 +02:00
Stefan Prodan
e855bbaa29 Merge pull request #412 from sylr/kube-context
Add Kubernetes context option to CLI commands
2020-11-02 23:53:34 +02:00
Sylvain Rabot
78d7dca985 Add a --context option
Signed-off-by: Sylvain Rabot <sylvain@abstraction.fr>
2020-11-02 21:32:55 +01:00
Stefan Prodan
9da7ded976 Merge pull request #406 from fluxcd/docs-release-procedure
Add release procedure documentation
2020-11-02 10:53:44 +02:00
Stefan Prodan
427b107d0e Add release procedure documentation
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-11-01 09:33:36 +02:00
Hidde Beydals
1cab68e385 Merge pull request #404 from fluxcd/update-components
Update source-controller component to v0.2.1
2020-10-30 20:53:57 +01:00
fluxcdbot
07e4fa8abd Update toolkit components 2020-10-30 19:45:48 +00:00
Stefan Prodan
77b86c78a4 Merge pull request #403 from fluxcd/install-docs-v0.2.0
Update bootstrap docs to match v0.2
2020-10-30 18:19:52 +02:00
Stefan Prodan
e4c701864a Update bootstrap docs to match v0.2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-30 18:10:59 +02:00
Stefan Prodan
0275f28490 Merge pull request #402 from fluxcd/kubecon-na-talk
Update talks section
2020-10-30 17:11:36 +02:00
Stefan Prodan
300c3dd578 Update talks section
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-30 17:01:06 +02:00
Stefan Prodan
fb81870803 Merge pull request #401 from fluxcd/docs-v1-migration
Add migration guide for Flux v1 users
2020-10-30 16:10:49 +02:00
Stefan Prodan
bb6a61a313 Add migration guide for Flux v1 users
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-30 16:02:21 +02:00
Stefan Prodan
976d917a57 Merge pull request #400 from fluxcd/fix-install
Fix install script
2020-10-29 21:48:19 +02:00
Stefan Prodan
7e13cc2ca8 Fix install script
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-29 21:20:31 +02:00
Stefan Prodan
704296df4e Merge pull request #365 from mewzherder/patch-3
Community section: add link to GH Discussions
2020-10-29 21:19:46 +02:00
mewzherder
65244e3b8d Community section: add link to GH Discussions
Signed-off-by: mewzherder <tamao@weave.works>
2020-10-29 11:49:05 -07:00
Stefan Prodan
3cf54a4cce Merge pull request #397 from fluxcd/dangling-gotk-link
Add GOTK section to index
2020-10-29 20:17:58 +02:00
Michael Bridgen
031c09d8dc Link to specific guide
In the absence of a dev-guides index or other GitOps Toolkit specific
home page, link to the dev guide that exists, for now.

Signed-off-by: Michael Bridgen <michael@weave.works>
2020-10-29 18:08:55 +00:00
Michael Bridgen
5209d9cf75 Add GOTK section to index
Signed-off-by: Michael Bridgen <michael@weave.works>
2020-10-29 17:57:16 +00:00
Michael Bridgen
815dad18f4 Merge pull request #395 from fluxcd/replace-in-docs
Replace GitOps Toolkit in docs
2020-10-29 17:21:38 +00:00
Michael Bridgen
4319382da3 Change title and author of generated website
I changed the author "The Flux project", since it seemed oddly
redundant to effectively say "the author is the Flux authors".

Signed-off-by: Michael Bridgen <michael@weave.works>
2020-10-29 17:11:23 +00:00
Michael Bridgen
5e96cec95b Replace GitOps Toolkit in docs
This replaces most mentions of "GitOps Toolkit" and "toolkit" with
"Flux". I have adopted the style of using "Flux v2" in the first
mention, and thereafter just "Flux".

Signed-off-by: Michael Bridgen <michael@weave.works>
2020-10-29 17:11:23 +00:00
Hidde Beydals
071982097a Merge pull request #396 from fluxcd/make-docs-target
Delete generated docs before regenerating them
2020-10-29 18:10:33 +01:00
Hidde Beydals
56024de6cc Delete generated docs before regenerating them
This ensures no stray files are kept when for example a command name
changes.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-10-29 17:58:48 +01:00
Hidde Beydals
845d4acd8e Merge pull request #393 from fluxcd/rename-cli-ns 2020-10-29 16:47:01 +01:00
Hidde Beydals
b0029e9255 Remove Flux CLI from Toolkit component overview
Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-10-29 16:31:37 +01:00
Hidde Beydals
23bc44a350 Change Homebrew tap instructions
Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-10-29 16:31:37 +01:00
Hidde Beydals
0bf52f4746 Change fluxcd/toolkit to fluxcd/flux2
Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-10-29 16:31:32 +01:00
Hidde Beydals
345707e6cc Incorporate name and metric changes in Grafana cfg
Signed-off-by: Hidde Beydals <hello@hidde.co>

Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-10-29 16:25:16 +01:00
Hidde Beydals
e2752e4508 Rename gotk binary to flux
Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-10-29 16:25:16 +01:00
Hidde Beydals
9916a53761 Rename gotk-system namespace to flux-system
Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-10-29 16:25:16 +01:00
Stefan Prodan
4581c99a81 Merge pull request #389 from fluxcd/docs/helmreleases
Update HelmRelease documentation
2020-10-29 16:53:48 +02:00
Hidde Beydals
c3fdc41a91 Update HelmRelease documentation
* Remove mention of dependency download limitation
* Include bucket sources in HelmRelease guide

Signed-off-by: Hidde Beydals <hello@hidde.co>
2020-10-29 16:46:37 +02:00
Stefan Prodan
edf2f51aa1 Merge pull request #385 from fluxcd/readme-flux2
Minimal rewrite of README to explain Flux v2
2020-10-29 16:45:26 +02:00
Michael Bridgen
de944d0095 Minimal rewrite of README to explain Flux v2
- Adjust the description so it talks about the whole system (Flux) as
   one thing

 - Describe what GitOps Toolkit is, and how it relates to Flux v2.

Signed-off-by: Michael Bridgen <michael@weave.works>
2020-10-29 16:38:05 +02:00
Stefan Prodan
49ffc972f8 Merge pull request #392 from fluxcd/update-components
Update toolkit components
2020-10-29 15:22:42 +02:00
fluxcdbot
2d8e5b2420 Update toolkit components 2020-10-29 13:14:48 +00:00
Stefan Prodan
7c48975198 Merge pull request #387 from fluxcd/bootstrap-refac
Refactor manifests generation
2020-10-29 12:40:32 +02:00
Stefan Prodan
9bc250d027 Refactor manifests generation
- introduce manifestgen pkg, to be consumed by the CLI and Terraform provider
- consolidate defaults in manifestgen/install pkg
- introduce Manifest as the returning type of manifest generation
- add helper function to Manifest for writing multi-doc YAMLs on disk

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-29 10:15:53 +02:00
Stefan Prodan
41d4e7e15b Merge pull request #376 from phillebaba/refactor-manifest-generation
Refactor manifest generation into a separate package
2020-10-28 18:15:38 +02:00
Philip Laine
b0d2a38ff6 Refactor manifest generation
Signed-off-by: Philip Laine <philip.laine@xenit.se>
2020-10-28 16:01:43 +01:00
Stefan Prodan
bd4d4d927e Merge pull request #384 from fluxcd/update-stable-repo
Update the stable Helm repository in docs
2020-10-28 15:51:40 +02:00
Stefan Prodan
db17cacbf4 Update the stable Helm repository in docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-28 15:40:26 +02:00
Stefan Prodan
0c5961df98 Merge pull request #381 from fluxcd/copyright
Change copyright to Flux authors
2020-10-27 19:09:46 +02:00
Stefan Prodan
0e67b76b57 Change copyright to Flux authors
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-27 18:59:01 +02:00
Stefan Prodan
f72b323ab5 Merge pull request #378 from chanwit/windows-zip
change the windows binary release format to .zip
2020-10-27 18:54:22 +02:00
Chanwit Kaewkasi
927c21a60f change the windows binary release format to .zip
Signed-off-by: Chanwit Kaewkasi <chanwit@gmail.com>
2020-10-27 23:24:28 +07:00
Hidde Beydals
624a9ba8eb Merge pull request #364 from staceypotter/patch-4
Update featured talks and add upcoming meeting
2020-10-22 17:09:08 +02:00
Stacey Potter
8509283ac2 Update featured talks and add upcoming meeting 2020-10-22 16:44:15 +02:00
Stefan Prodan
aa9ba27f40 Merge pull request #369 from fluxcd/mon-guide
Add monitoring guide
2020-10-21 10:48:40 +03:00
Stefan Prodan
06434464bb Add monitoring guide
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-21 10:09:28 +03:00
Stefan Prodan
3e7bfc72a2 Merge pull request #361 from fluxcd/uninstall-ignore-missing-crds
Ignore missing kinds when uninstalling
2020-10-20 21:57:10 +03:00
Stefan Prodan
8dfbc35e60 Ignore missing kinds when uninstalling
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-20 00:38:58 +03:00
Stefan Prodan
503e5ec950 Merge pull request #358 from fluxcd/update-components
Update toolkit components
2020-10-19 17:56:48 +03:00
fluxcdbot
414aeb0ac3 Update toolkit components 2020-10-19 14:23:20 +00:00
Stefan Prodan
55b8544d32 Merge pull request #350 from allymparker/source-git-secret-ref
Add secret-ref flag to create source git
2020-10-19 17:21:14 +03:00
Ally Parker
2d67ea5f7f Add secret-ref flag to git source
Add secret-ref flag to Helm source

Add secret-ref to bucket source
2020-10-19 14:49:14 +01:00
Stefan Prodan
4eaf72fa3e Merge pull request #356 from StupidScience/custom-flags
Implement custom flags for options with validation rules
2020-10-19 13:41:47 +03:00
“Anton
95ef3c1782 Update docs 2020-10-19 13:09:53 +03:00
“Anton
b3ef410fb7 Add source bucket provider flag 2020-10-19 13:05:56 +03:00
“Anton
0c55bca218 Add helm chart source flag 2020-10-19 12:55:34 +03:00
“Anton
5fd28439dc Add kustomization source and decryption provider flags 2020-10-19 12:46:10 +03:00
“Anton
a58c18e992 Refresh bootstrap and install docs 2020-10-17 23:47:20 +03:00
“Anton
058dfdfcd6 Move flags and utils to internal packages 2020-10-17 23:35:09 +03:00
Stefan Prodan
637fdac28a Merge pull request #354 from fluxcd/windows-exe
Add Windows OS to CLI install docs
2020-10-17 15:43:54 +03:00
Stefan Prodan
a8b667780a Add Windows OS to CLI install docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-17 14:05:17 +03:00
Stefan Prodan
b4f13e10d3 Merge pull request #351 from fluxcd/gitlab-https-auth
Add GitLab HTTPS auth to bootstrap options
2020-10-17 13:15:26 +03:00
Stefan Prodan
d0eb55fb86 Merge branch 'gitlab-https-auth' of https://github.com/fluxcd/toolkit into gitlab-https-auth 2020-10-17 13:08:38 +03:00
Stefan Prodan
b041dbd14f Add GitLab HTTPS auth to bootstrap options
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-17 09:27:47 +00:00
Stefan Prodan
0ab814fbc4 Merge pull request #348 from fluxcd/update-components
Update toolkit components
2020-10-17 12:26:46 +03:00
fluxcdbot
a2144b1759 Update toolkit components 2020-10-17 07:21:01 +00:00
Stefan Prodan
82eb3b5ccf Merge pull request #353 from fluxcd/build/remove-docs-hotfix
Remove documentation version hotfix
2020-10-17 10:05:00 +03:00
Hidde Beydals
7515080c63 Remove documentation version hotfix
And re-use the same logic to properly compare current and next release
versions in update workflow.
2020-10-16 22:19:58 +02:00
Hidde Beydals
07015c5172 Merge pull request #352 from fluxcd/refactor-create-reconcile-resume
Refactor create, reconcile and resume commands
2020-10-16 20:47:39 +02:00
Hidde Beydals
19918cd342 Refactor create, reconcile and resume cmds
* Take ObservedGeneration into account in readiness checks where
  applicable
* Reduce amount of code (and duplicate GETs) by working with pointers
  where possible
* Improve logged messages to properly take resource names into account
  and better describe processes
2020-10-16 20:17:39 +02:00
Stefan Prodan
16f0ed548e Add GitLab HTTPS auth to bootstrap options
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-16 20:57:21 +03:00
Stefan Prodan
0d1600275d Merge pull request #349 from fluxcd/windows-os-cli
Publish CLI binary for Windows
2020-10-16 17:30:59 +03:00
Stefan Prodan
768f32bd2d Publish CLI binary for Windows
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-16 16:32:11 +03:00
Stefan Prodan
d86798a7c6 Merge pull request #345 from staceypotter/patch-2
updated featured talks + upcoming meetups
2020-10-16 10:50:49 +03:00
Stefan Prodan
7718c6a2a5 Merge pull request #340 from fluxcd/bootstrap-validate-manifests
Enable client side validation on bootstrap
2020-10-16 10:41:47 +03:00
Stefan Prodan
a0616ac2cb Merge pull request #334 from StupidScience/windows-support
Get rid of shell-out and invoke command directly via exec
2020-10-16 10:41:31 +03:00
Stefan Prodan
23bbe0d52b Merge pull request #346 from staceypotter/patch-3
updated with featured talks + upcoming meetups
2020-10-16 10:41:07 +03:00
Stefan Prodan
6d9e7758a2 Merge pull request #347 from fluxcd/rebase-action
Add rebase action
2020-10-16 10:39:48 +03:00
Stefan Prodan
f81a80c2da Add rebase action
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-16 10:31:50 +03:00
Stefan Prodan
ab64619a41 Merge pull request #344 from smorimoto/fossa-action
Use fossa-contrib/fossa-action instead
2020-10-16 10:23:33 +03:00
Stacey Potter
18bdd26be8 updated with featured talks + upcoming meetups 2020-10-15 19:57:21 -07:00
Stacey Potter
c5f3a674d6 updated featured talks + upcoming meetups 2020-10-15 19:52:07 -07:00
Sora Morimoto
f95e17b144 Use fossa-contrib/fossa-action instead
Signed-off-by: Sora Morimoto <sora@morimoto.io>
2020-10-16 08:16:19 +09:00
“Anton
4989826124 Get rid of shell-out and invoke kubetcl directly via exec 2020-10-15 20:38:44 +03:00
Stefan Prodan
f23a551ae3 Enable client side validation on bootstrap
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-15 18:04:35 +03:00
Stefan Prodan
bd2df01b12 Merge pull request #343 from fluxcd/alert-provider-fix
Set alert provider secretRef only if specified
2020-10-15 18:03:23 +03:00
Stefan Prodan
880ef303e8 Set alert provider secretRef only if specified
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-15 17:51:43 +03:00
Michael Bridgen
b4ed1a0bdc Merge pull request #341 from fluxcd/update-image-auto-progress
Mark the design tasks for image automation as done
2020-10-15 12:23:33 +01:00
Michael Bridgen
7a2eae0699 Mark the design tasks for image automation as done
This leaves the implementation tasks as not done -- a bit of a
simplification, since there's some implementation done, and some
design left to do, but it's close enough at this level.

I estimated that having the design basics figured out is worth 30%
overall.
2020-10-15 12:12:04 +01:00
Stefan Prodan
4464252cae Merge pull request #337 from fluxcd/monitoring
Add cluster stats dashboard to monitoring stack
2020-10-14 17:12:30 +03:00
Stefan Prodan
ca8cf44200 Add cluster stats dashboard to docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-14 16:34:46 +03:00
Stefan Prodan
4565165579 Add cluster stats dashboard
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-14 16:16:56 +03:00
Stefan Prodan
a37be432a9 Merge pull request #333 from fluxcd/docs-update-v0.1.6
Update docs website
2020-10-14 12:11:30 +03:00
Stefan Prodan
90591e852d Update docs website
- add notification-controller/api commands to index
- move diagrams to docs website
- update CRDs docs

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-14 10:35:29 +03:00
Stefan Prodan
13f7d44a06 Merge pull request #327 from nanikjava/f-fix-306
Add ARM instruction to get started guide
2020-10-13 23:55:58 +03:00
Nanik
7dc8aa66a6 Add ARM instruction under staging and production bootstrap 2020-10-14 07:44:16 +11:00
Stefan Prodan
6cf28ab718 Merge pull request #331 from fluxcd/update-components
Update toolkit components
2020-10-13 23:41:39 +03:00
fluxcdbot
f461c5e8b7 Update toolkit components 2020-10-13 17:47:46 +00:00
Stefan Prodan
9433bdf4ad Merge pull request #332 from fluxcd/uninstall-fix
Uninstall improvements
2020-10-13 20:43:48 +03:00
Stefan Prodan
d2d494e079 Uninstall improvements
- ignore not found errors when deleting objects
- remove the CR/CRDs before deleting the cluster role binding
- capture kubectl exist code

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-13 20:30:17 +03:00
Stefan Prodan
e64b35cde8 Merge pull request #302 from phillebaba/feature/notification-controller
Add notification controller CLI commands
2020-10-13 18:31:16 +03:00
Philip Laine
d32e8c6e98 Remove aliases 2020-10-13 12:21:45 +02:00
Philip Laine
55cee488bc Update docs 2020-10-13 11:11:55 +02:00
Philip Laine
65b8942416 Fix minor issues 2020-10-13 11:11:55 +02:00
Philip Laine
94cf7c329c Update docs 2020-10-13 11:11:55 +02:00
Philip Laine
8eac7d6b4d Implement table output 2020-10-13 11:11:55 +02:00
Philip Laine
7ebb34de80 Add receiver command 2020-10-13 11:11:55 +02:00
Philip Laine
6ea84906ac Add alert commands 2020-10-13 11:11:54 +02:00
Philip Laine
f7971a871a Add alert provider commands 2020-10-13 11:11:54 +02:00
Stefan Prodan
54b35b7c2b Merge pull request #323 from fluxcd/monitoring
docs: Install the monitoring stack with gotk
2020-10-12 13:04:43 +03:00
Stefan Prodan
ca970b4ffb docs: Install the monitoring stack with gotk
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-12 09:50:43 +03:00
Stefan Prodan
8a96e32679 Update Prometheus and Grafana
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-11 15:13:16 +03:00
Stefan Prodan
fc4d01b3e5 Allow scraping and webhooks
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-11 13:48:06 +03:00
Stefan Prodan
b6afc8f6ce Merge pull request #317 from staceypotter/patch-1
Add featured talks and meetups section
2020-10-09 09:03:14 +03:00
Stefan Prodan
c481a431be Merge branch 'main' into patch-1 2020-10-09 08:54:45 +03:00
Stacey Potter
0a7b82793e removed header link
Removed "(Check out our [Upcoming Meetups](#upcoming-meetups)!)" from the top of the page.
2020-10-08 22:54:04 -07:00
Stacey Potter
3653236bcb added "featured talks" section
+ upcoming meetups & header link
2020-10-08 15:31:10 -07:00
Stefan Prodan
a2eee72015 Merge pull request #318 from fluxcd/install-pkg
Introduce install package
2020-10-08 14:01:25 +03:00
Stefan Prodan
5672646278 Use install pkg in CLI
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-08 12:47:25 +03:00
Stefan Prodan
c4d3fa7a48 init install pkg
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2020-10-08 02:31:33 +03:00
Stacey Potter
32b0267b9f Added GOTK guide walk-through
Added invite for Leigh's GOTK guide walk-through on Oct 19 (10am PT/18:00 BST) to the Community Section. LMK if this should be somewhere else - or condensed (wasn't sure how much info to include). Thanks! :)
2020-10-07 11:43:14 -07:00
Stefan Prodan
a7b41a4b8c Merge pull request #315 from rieger-jared/bug/update-notification-api-in-docs
Update api versions in guides
2020-10-07 18:10:38 +03:00
Jared Rieger
bfd6d14bf3 Update api versions in guides 2020-10-07 17:00:43 +02:00
Daniel Holbach
469de31218 Merge pull request #313 from dholbach/update-frontpage
close parentheses, make link to guide more obvious
2020-10-06 14:51:18 +02:00
Daniel Holbach
2ce9823b3a close parentheses, make link to guide more obvious 2020-10-06 14:34:21 +02:00
Stefan Prodan
e8b3d09ddf Merge pull request #310 from fluxcd/mod-cleanup
Use GitHub actions from fluxcd/pkg@main
2020-10-06 11:09:46 +03:00
stefanprodan
f613c01803 Update blang/semver to v4
Signed-off-by: stefanprodan <stefan.prodan@gmail.com>
2020-10-06 10:50:32 +03:00
stefanprodan
a5a5908fb5 Use GitHub actions from fluxcd/pkg@main 2020-10-06 10:50:02 +03:00
Hidde Beydals
5313a0ed47 Merge pull request #305 from fluxcd/docs/get-cmds-columns
Update guide to include column output commands
2020-10-05 18:26:51 +02:00
Hidde Beydals
1c15eebd7c Merge pull request #307 from fluxcd/bugfix-get-source
Display proper revision for sources
2020-10-05 18:26:28 +02:00
Hidde Beydals
f3cab6e177 Display proper revision for sources
Includes a change to an empty revision string if the reconciler has not
produced an artifact yet, as this will otherwise result in a nil
pointer dereference.
2020-10-05 18:16:22 +02:00
Hidde Beydals
c0623334ee Update guide to include column output commands 2020-10-05 18:11:01 +02:00
Hidde Beydals
d41bd6b6b1 Merge pull request #299 from circa10a/main
Switch get commands to use tables for output
2020-10-05 12:34:49 +02:00
Hidde Beydals
c9b4a8eef5 Merge pull request #301 from fluxcd/multi-context-kubeconfig
Support multi-path KUBECONFIG
2020-10-05 08:45:20 +02:00
circa10a
3619cb8bd1 Switch get commands to use tables for output
Signed-off-by: circa10a <caleblemoine@gmail.com>
2020-10-04 16:34:04 -05:00
Hidde Beydals
8e2316ba62 Support multi-path KUBECONFIG
Ref:
https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#the-kubeconfig-environment-variable
2020-10-04 18:22:03 +02:00
Stefan Prodan
495abf42ef Merge pull request #298 from yiannistri/sealed-secrets-docs
Update api versions in docs
2020-10-03 21:54:30 +03:00
Yiannis
5372dd633e Update api versions in docs 2020-10-03 19:08:16 +01:00
Stefan Prodan
5efa1ebe88 Merge pull request #297 from fluxcd/opt-out-network-policy
Add option to disable the network policy at install time
2020-10-03 19:15:00 +03:00
stefanprodan
07677ed4a7 Add option to disable the network policy at install time 2020-10-03 17:35:55 +03:00
Hidde Beydals
73e5640109 Merge pull request #295 from fluxcd/update-components
Update toolkit components
2020-10-02 20:39:49 +02:00
fluxcdbot
bdbded8588 Update toolkit components 2020-10-02 18:20:24 +00:00
Hidde Beydals
e0fbf8920d Merge pull request #290 from fluxcd/bug-get-break
Remove faulty `break` from get commands
2020-10-02 14:01:19 +02:00
Hidde Beydals
7b2227bfac Remove faulty break from get commands 2020-10-02 13:34:48 +02:00
Hidde Beydals
12866ca7ba Merge pull request #289 from fluxcd/fix-kustomization-depends-on
Fix Kusomization depends-on mapping
2020-10-02 13:01:47 +02:00
stefanprodan
1427b1537e Fix Kusomization depends-on mapping 2020-10-02 13:43:05 +03:00
Stefan Prodan
6ceb133bb5 Merge pull request #287 from fluxcd/go-1.15
Update Go to v1.15
2020-10-01 23:45:55 +03:00
stefanprodan
4ab67aaf90 Update Go to v1.15 2020-10-01 23:38:25 +03:00
Stefan Prodan
6cce0a3901 Merge pull request #286 from fluxcd/main-branch
Change default branch to main
2020-10-01 22:55:48 +03:00
stefanprodan
fa67789350 Change default branch to main 2020-10-01 22:45:45 +03:00
Stefan Prodan
16adeb1373 Merge pull request #285 from fluxcd/bootstrap-default-branch
Change the bootstrap default branch to main
2020-10-01 22:31:20 +03:00
stefanprodan
29c1cf1237 Retry setting annotation on conflict 2020-10-01 22:23:59 +03:00
stefanprodan
0e52065893 Change the bootstrap default branch to main 2020-10-01 21:47:33 +03:00
Hidde Beydals
3972c08efc Merge pull request #284 from fluxcd/hotfix-resource-to-string
Remove creationTimestamp leading spaces
2020-10-01 20:25:03 +02:00
Hidde Beydals
1a679ee05d Remove creationTimestamp leading spaces 2020-10-01 20:17:59 +02:00
Stefan Prodan
b2286055b0 Merge pull request #283 from fluxcd/roadmap-v0.1-update
Roadmap v0.1 update
2020-10-01 18:16:28 +03:00
Hidde Beydals
249d0d43de docs: hotfix component versions 2020-10-01 16:39:48 +02:00
stefanprodan
536630cbcd Update roadmap after v0.1 release 2020-10-01 16:59:04 +03:00
Hidde Beydals
70d0bfce15 Merge pull request #281 from fluxcd/meta-reconciler-improv 2020-10-01 14:31:00 +02:00
Hidde Beydals
84e36ed847 Use LastHandledReconcileAt in reconcile commands 2020-10-01 14:20:23 +02:00
Stefan Prodan
3d4ff687b5 Merge pull request #250 from phillebaba/git-status-docs
Update docs for git notifiers
2020-10-01 14:05:53 +03:00
Philip Laine
edddf65d0e Update docs for git notifiers 2020-10-01 12:55:01 +02:00
Hidde Beydals
f216273008 Make use of GetCondition from pkg/apis/meta 2020-09-30 23:23:28 +02:00
Hidde Beydals
3295ef4fcf Merge pull request #282 from mewzherder/patch-2
Fix broken link to Get Started Guide
2020-09-30 23:23:01 +02:00
mewzherder
4ea0e04852 Fix broken link to Get Started Guide 2020-09-30 14:12:57 -07:00
Hidde Beydals
414c0b3a8d Merge pull request #237 from fluxcd/rename-ns
Rename 'gitops-system' namespace to 'gotk-system'
2020-09-30 22:39:27 +02:00
Hidde Beydals
ff6a1c14be Rename 'gitops-system' namespace to 'gotk-system'
To align with the project name, and the group introduced in #236.
2020-09-30 22:32:26 +02:00
Stefan Prodan
0e1a862e34 Merge pull request #280 from fluxcd/api-v0.1
Update components to v0.1
2020-09-30 23:20:56 +03:00
stefanprodan
d902c71a6f Update components to v0.1 2020-09-30 23:09:21 +03:00
Daniel Holbach
b3f6d5206a Merge pull request #279 from mewzherder/patch-1
Add mailing list link to Community section
2020-09-30 21:33:46 +02:00
mewzherder
ff0d80e84f Add mailing list link to Community section 2020-09-30 12:07:52 -07:00
Stefan Prodan
cf080330ba Merge pull request #276 from fluxcd/kustomize-bootstrap-dir
Generate a kustomize package for the bootstrap manifests
2020-09-29 08:45:52 +03:00
stefanprodan
2373bacb0c Generate a kustomize package for the bootstrap manifests 2020-09-29 08:36:28 +03:00
Stefan Prodan
938edefea1 Merge pull request #273 from fluxcd/tenant-customization
Add support for multi-namespace tenant ownership
2020-09-28 13:11:04 +03:00
stefanprodan
393be92632 Add support for multi-namespace tenant ownership 2020-09-26 16:42:36 +03:00
Stefan Prodan
267440142e Merge pull request #270 from fluxcd/hr-ks-bucket-source
Add support for Bucket sources to Kustomizations/HRs
2020-09-24 10:03:55 +03:00
stefanprodan
d11fa476e1 Refactor object kind/name parsing 2020-09-23 18:19:33 +03:00
stefanprodan
bd2994f9ab Add support for Bucket sources to Kustomizations/HRs 2020-09-23 16:44:31 +03:00
Stefan Prodan
2806feb468 Merge pull request #269 from fluxcd/update-components
Update toolkit components
2020-09-23 16:07:21 +03:00
fluxcdbot
8e40069e67 Update toolkit components 2020-09-23 12:57:46 +00:00
Stefan Prodan
24d7d8dcc4 Merge pull request #267 from fluxcd/bucket-cmds
Implement bucket CRUD commands
2020-09-23 12:42:35 +03:00
stefanprodan
34147d7694 Add validation for bucket providers 2020-09-23 12:30:14 +03:00
stefanprodan
83bd245bfd Add Bucket API spec to docs 2020-09-23 12:17:10 +03:00
stefanprodan
a02452ccb9 Implement bucket CRUD commands 2020-09-23 12:04:28 +03:00
Hidde Beydals
a8f72564f4 Merge pull request #265 from fluxcd/docs/readme-community-sec
Add community section to `README.md`
2020-09-23 10:20:46 +02:00
Hidde Beydals
6e7b311696 Add community section to README.md 2020-09-23 10:07:47 +02:00
Stefan Prodan
2bda0eb761 Merge pull request #262 from dholbach/fix-261
Add community section
2020-09-23 09:57:16 +03:00
Daniel Holbach
c2661fb79e Add community section
fixes: #261
2020-09-22 17:37:47 +02:00
Daniel Holbach
4e70fd704b remove superfluous spaces 2020-09-22 17:25:22 +02:00
Stefan Prodan
85d03a9946 Merge pull request #260 from fluxcd/dependson-ns
Add support for namespace/name format in depends-on
2020-09-22 18:20:21 +03:00
stefanprodan
1c7994a353 Add support for namespace/name format in depends-on 2020-09-22 18:11:00 +03:00
fluxcdbot
347c2b6bcc Update toolkit components 2020-09-22 13:17:27 +00:00
Stefan Prodan
19d9953a48 Merge pull request #259 from fluxcd/fix-bootstrap-sync
Always apply sync manifests on bootstrap
2020-09-22 15:13:08 +03:00
stefanprodan
7b4e815a8d Always apply sync manifests on bootstrap 2020-09-22 14:58:51 +03:00
Hidde Beydals
59011c9517 Merge pull request #258 from fluxcd/ci-release-replace
ci: take "v" of RELEASE_VERSION into account
2020-09-22 11:54:17 +02:00
Hidde Beydals
39d5c9e525 ci: take "v" of RELEASE_VERSION into account 2020-09-22 11:36:42 +02:00
Stefan Prodan
e6d553c8ff Merge pull request #256 from fluxcd/install-from-archives
Use release archive as kustomize base
2020-09-22 11:56:00 +03:00
Hidde Beydals
fecd777d30 ci: update replace pattern to match release zip 2020-09-22 10:41:46 +02:00
stefanprodan
ce64b1fc09 Use release archive as kustomize base 2020-09-22 09:58:07 +03:00
stefanprodan
857e442376 Update kustomize/api to v0.6.2 2020-09-22 09:57:22 +03:00
Stefan Prodan
b0e407bf30 Merge pull request #254 from fluxcd/uninstall-fix
Suspend bootstrap kustomization on uninstall
2020-09-22 09:29:23 +03:00
Stefan Prodan
cad64ba044 Merge pull request #253 from fluxcd/bootstrap-required-components
Validate bootstrap required components
2020-09-22 09:20:42 +03:00
stefanprodan
85801f18ae Add uninstall section to install guide 2020-09-22 08:55:40 +03:00
stefanprodan
f93a40a18b Suspend bootstrap kustomization on uninstall 2020-09-22 08:54:49 +03:00
stefanprodan
9b0c44162a Validate bootstrap required components 2020-09-22 08:23:01 +03:00
Stefan Prodan
a66ac1594b Merge pull request #247 from fluxcd/arm-v7
Add support for ARMv7
2020-09-21 10:47:46 +03:00
stefanprodan
101e7bbce0 Add support for ARMv7 2020-09-21 10:37:55 +03:00
Stefan Prodan
0e969bbaad Merge pull request #240 from idvoretskyi/idvoretskyi-fossa
FOSSA scan enabled
2020-09-16 19:16:03 +03:00
Ihor Dvoretskyi
621b4c8213 FOSSA scan enabled
Signed-off-by: Ihor Dvoretskyi <ihor@linux.com>
2020-09-16 16:02:23 +00:00
Stefan Prodan
8ca6e44de7 Merge pull request #236 from fluxcd/tenant-cmd
Add create tenant command
2020-09-16 18:50:32 +03:00
stefanprodan
8ee2c972d3 Publish docs on releases instead of master push 2020-09-16 18:40:39 +03:00
stefanprodan
fafcf09570 Add -n shorthand for namespace flag 2020-09-16 15:10:34 +03:00
stefanprodan
0b14328024 Use the group version for HR APIVersion 2020-09-16 13:59:46 +03:00
Hidde Beydals
2d2b24f589 Merge pull request #239 from fluxcd/readme-update
docs: add more content to the README.md
2020-09-15 18:16:04 +02:00
Hidde Beydals
346d8f7583 docs: add more content to the README.md 2020-09-15 18:01:10 +02:00
stefanprodan
2096532f5d Add create tenant command 2020-09-15 16:49:48 +03:00
stefanprodan
4136eb1444 Add export resource helper function 2020-09-15 16:36:13 +03:00
Stefan Prodan
67e0acd044 Merge pull request #235 from stealthybox/shell-completions
Support bash, fish, zsh, and powershell shell completions as separate sub-commands
2020-09-15 12:15:47 +03:00
leigh capili
cbcdfc5f6c Support bash, fish, zsh, and powershell shell completions as separate sub-commands 2020-09-14 16:35:55 -06:00
Stefan Prodan
288d952686 Merge pull request #231 from fluxcd/kc-v0.0.12
Update kustomize-controller to v0.0.12
2020-09-14 18:34:56 +03:00
stefanprodan
c36e02bba9 Update kustomize-controller to v0.0.12 2020-09-14 18:20:05 +03:00
Stefan Prodan
c121a4c0f5 Merge pull request #229 from fluxcd/log-level
Add log level flag
2020-09-14 12:56:06 +03:00
stefanprodan
2bac5aabee Add log level flag 2020-09-14 12:35:24 +03:00
Stefan Prodan
97ff225bc0 Merge pull request #227 from fluxcd/watch-all-namespaces
Add watch all namespaces flag
2020-09-14 12:23:14 +03:00
stefanprodan
d5e78b9f80 Add watch all namespaces flag 2020-09-13 10:38:15 +03:00
Stefan Prodan
3f98affd5a Merge pull request #223 from fluxcd/update-components
Update toolkit components
2020-09-12 12:11:32 +03:00
stefanprodan
531c2bcf00 Import fluxcd/pkg/runtime 2020-09-12 12:04:37 +03:00
fluxcdbot
dd5505918a Update toolkit components 2020-09-12 08:54:22 +00:00
Stefan Prodan
4a30a69eb4 Merge pull request #226 from fluxcd/bot-pr
Use fluxcdbot token in CI
2020-09-12 11:51:31 +03:00
stefanprodan
38b302e5a5 Use fluxcdbot token in CI 2020-09-12 11:44:41 +03:00
Hidde Beydals
ea010895a0 docs: update Helm roadmap 2020-09-11 15:31:15 +02:00
Stefan Prodan
7b88512698 Merge pull request #222 from fluxcd/rbac-patch-events
Add PATCH rule to crd-controller role for events
2020-09-11 09:21:50 +03:00
Hidde Beydals
1ff24d9285 Add PATCH rule to crd-controller role for events
During high custom resource count / low interval tests, I was greated
with a `cannot patch resource "events"` message. This happened due to
event compaction, where it will perform a patch instead of a create.
By giving the role the permission to do so this should no longer pose
a problem.
2020-09-10 20:57:59 +02:00
Stefan Prodan
ebf742d272 Merge pull request #219 from fluxcd/bootstrap-branch
Add branch flag to bootstrap cmd
2020-09-09 17:59:30 +03:00
stefanprodan
a7b1b04920 Add bootstrap reinstall e2e test 2020-09-09 17:27:56 +03:00
stefanprodan
1218d6abe8 Add branch flag to bootstrap cmd 2020-09-09 16:41:48 +03:00
Stefan Prodan
f9d546676b Merge pull request #218 from fluxcd/refac
Add GitHub bootstrap e2e test
2020-09-09 14:15:33 +03:00
stefanprodan
afef6960b9 Cleanup GitHub e2e repo 2020-09-09 14:03:26 +03:00
stefanprodan
f6626b8975 Add GitHub bootstrap e2e test 2020-09-09 08:56:55 +03:00
stefanprodan
b1e66f81ab Add label validation 2020-09-08 20:08:28 +03:00
Stefan Prodan
9cc018e618 Merge pull request #216 from fluxcd/labels
Add label arg to create commands
2020-09-08 18:14:31 +03:00
stefanprodan
797cd9bea2 Add label arg to create commands 2020-09-08 18:03:04 +03:00
Hidde Beydals
9dbfca3d7a Merge pull request #212 from fluxcd/refactor-hr-source-kind-validation
Refactor HelmRelease chart source kind validation
2020-09-07 12:02:34 +02:00
Hidde Beydals
f18d1efdcb Refactor HelmRelease chart source kind validation 2020-09-07 11:13:15 +02:00
stefanprodan
29a9b89224 Set Homebrew formula name 2020-09-07 12:04:27 +03:00
Stefan Prodan
11b5b9808b Merge pull request #211 from fluxcd/homebrew
Publish Homebrew formula
2020-09-07 11:55:10 +03:00
stefanprodan
ca1f84d22b Publish Homebrew formula 2020-09-07 11:41:06 +03:00
Stefan Prodan
d6c6c88e6e Merge pull request #209 from fluxcd/sops
Mozilla SOPS
2020-09-06 15:02:36 +03:00
stefanprodan
ee33702463 Add Mozilla SOPS guide to docs 2020-09-06 14:24:33 +03:00
stefanprodan
8b6995e9ec Add decryption flags to create kustomization cmd 2020-09-06 13:56:56 +03:00
Stefan Prodan
36ba8f0fcb Merge pull request #207 from fluxcd/kustomize-controller-v0.0.10
Update kustomize-controller to v0.0.10
2020-09-05 11:19:33 +03:00
stefanprodan
bfb560ec50 Update kustomize-controller to v0.0.10 2020-09-05 11:04:41 +03:00
Stefan Prodan
78bb11dcbf Merge pull request #204 from fluxcd/ghcr
Use GitHub Container Registry for AMD64/ARM64 images
2020-09-04 17:35:25 +03:00
stefanprodan
5c8d00665f Use GitHub Container Registry for AMD64/ARM64 images 2020-09-04 17:18:33 +03:00
Stefan Prodan
f4d78cc08e Merge pull request #202 from fluxcd/arch
Add ARM64 support to install/bootstrap
2020-09-04 16:37:03 +03:00
stefanprodan
2aa395ba12 Update source and helm controllers
helm-controller/api v0.0.7
source-controller/api v0.0.14
2020-09-04 16:23:21 +03:00
Hidde Beydals
ac862e6822 Merge pull request #201 from fluxcd/update-hr-create-docs
Update `gotk create helmrelease` examples
2020-09-04 14:24:37 +02:00
stefanprodan
1b55ead16e Add ARM64 to install docs and script 2020-09-04 15:10:42 +03:00
stefanprodan
b24727ec22 Update kustomize-controller to v0.0.9 2020-09-04 14:28:37 +03:00
stefanprodan
2768926683 Publish gotk linux/arm64 binary 2020-09-04 12:54:26 +03:00
stefanprodan
3f07bd6471 Add arch flag to install/bootstrap 2020-09-04 12:46:08 +03:00
Hidde Beydals
2f861f19c0 Update gotk create helmrelease examples
To better reflect optional fields and highlight specific configuration
options.
2020-09-03 19:31:19 +02:00
Hidde Beydals
6b397cff73 Merge pull request #200 from scottrigby/docs-gotk-create-hr-fix
Docs: fix gotk create helmrelease examples
2020-09-03 17:45:37 +02:00
Scott Rigby
44a3cf86d3 Docs: fix gotk create helmrelease examples
Signed-off-by: Scott Rigby <scott@r6by.com>
2020-09-03 17:39:12 +02:00
Hidde Beydals
dfb0a40293 Merge pull request #199 from fluxcd/docs/helmrelease-git-guide
Document GitRepository source in HelmRelease guide
2020-09-03 16:48:22 +02:00
Hidde Beydals
7719dd378b docs: GitRepository source in HelmRelease guide 2020-09-03 15:09:12 +02:00
Hidde Beydals
c9f8e43681 Merge pull request #191 from phillebaba/feature/git
Add documentation for github commit status
2020-09-03 12:27:48 +02:00
Hidde Beydals
4a7538041d Merge pull request #198 from fluxcd/notification-component-upgrade
Upgrade notification-controller to v0.0.8
2020-09-03 12:23:45 +02:00
Hidde Beydals
dd3b2288e2 Upgrade notification-controller to v0.0.8 2020-09-03 12:16:29 +02:00
Philip Laine
496abc3a98 Add documentation for github commit status 2020-09-03 12:13:53 +02:00
Hidde Beydals
8b9abfb26e Merge pull request #196 from fluxcd/docs/helmrelease-guide-changes 2020-09-03 12:12:25 +02:00
Hidde Beydals
330e21e2ba Merge pull request #197 from fluxcd/update-tk-components 2020-09-03 12:11:00 +02:00
Hidde Beydals
e53d0dadbf Support GitRepository source in HelmRelease cmds 2020-09-03 11:16:57 +02:00
Hidde Beydals
fa56685767 Upgrade Toolkit components and K8S deps
* github.com/fluxcd/helm-controller/api to v0.0.6
* github.com/fluxcd/source-controller/api to v0.0.13

* k8s.io/api to v0.18.8
* k8s.io/apiextensions-apiserver to v0.18.8
* k8s.io/apimachinery to v0.18.8
* k8s.io/client-go to v0.18.8
* sigs.k8s.io/controller-runtime to v0.6.2
2020-09-03 11:16:50 +02:00
Hidde Beydals
2727f4b92d docs: update helm-controller doc 2020-09-03 10:44:04 +02:00
Hidde Beydals
0f74f65af8 docs: update FAQ differences Helm integration 2020-09-03 10:40:33 +02:00
Hidde Beydals
8e03968370 docs: incorporate HelmRelease API changes in guide 2020-09-03 10:40:30 +02:00
Daniel Holbach
969f181f3e Merge pull request #195 from dholbach/update-roadmap
update roadmap
2020-09-02 17:12:43 +02:00
Daniel Holbach
cc18077192 update roadmap 2020-09-02 16:31:35 +02:00
Daniel Holbach
47d07b2326 Merge pull request #193 from dholbach/roadmap-is-settled
Roadmap for Flux v2 is settled for now, remove note.
2020-09-02 16:20:57 +02:00
Daniel Holbach
a96bb72fb8 Roadmap for Flux v2 is settled for now, remove note 2020-09-02 14:20:14 +02:00
Hidde Beydals
75364dd5b4 Merge pull request #180 from fluxcd/rename-tk-to-gotk
Rename `tk` binary to `gotk`
2020-09-01 12:33:09 +02:00
Hidde Beydals
22624ae4d5 Rename tk binary to gotk
To avoid conflicts with the `tk` binary from the Tanka project.
2020-09-01 11:33:49 +02:00
Hidde Beydals
cb23d3ff3c Merge pull request #185 from fluxcd/helmrelease-json-pointer 2020-09-01 11:32:00 +02:00
Hidde Beydals
e751bdc8a9 Change readiness check for HelmRelease
As the HelmRelease injects its own HelmChart, the first reconciliation
will always trigger a `Ready==False` condition while it waits for the
chart to become ready. Given this, we should only take this condition
into account when the `status.LastAttemptedRevision` has been recorded,
as this marks the fact that the chart is available and an action was
attempted.
2020-09-01 11:15:53 +02:00
Hidde Beydals
2078d048a1 Fix: change v1.JSON for HelmRelease to pointer 2020-08-28 15:20:34 +02:00
Hidde Beydals
22ff25269d Merge pull request #184 from fluxcd/update-components
Update toolkit components
2020-08-28 11:18:19 +02:00
hiddeco
1ee9a6a39d Update toolkit components 2020-08-28 07:54:06 +00:00
Hidde Beydals
50efd865d9 Merge pull request #182 from fluxcd/docs-detect-component-versions 2020-08-28 09:48:32 +02:00
Hidde Beydals
d688d3837f build: use mini curl progress bar and error on 404 2020-08-26 12:27:03 +02:00
Hidde Beydals
6cb438440d build: detect current version from kustomize
This allows controller components to be updated when they are not
included as a Go Mod dependency, which is currently the case for the
notification-controller.
2020-08-26 12:22:04 +02:00
Hidde Beydals
2c5771d9e8 build: detect component versions for docs 2020-08-26 12:21:40 +02:00
Hidde Beydals
0ce06116e6 Merge pull request #177 from mberwanger/git-workflow-component-updates 2020-08-26 10:16:14 +02:00
Martin H Berwanger
706bc0fdfe Update PR commit message 2020-08-25 14:52:11 -04:00
Martin H Berwanger
0b5b1ba11a Automate components updates #36
Add component update GitHub action
- check for new controller release
- bump versions in go mod, kustomize, and docs
- create PR for review
2020-08-25 10:34:07 -04:00
Stefan Prodan
0ed8ca961e Merge pull request #173 from fluxcd/include-author-changelog
Include PR author in changelog
2020-08-21 18:15:01 +03:00
stefanprodan
31d4b62bf3 Include author in changelog
Replace kustomize action with fluxcd/pkg/actions
2020-08-21 17:55:11 +03:00
Stefan Prodan
35d6172d06 Merge pull request #172 from fluxcd/ssh-host
Add SSH hostname arg to GitLab bootstrap
2020-08-21 17:50:29 +03:00
stefanprodan
b5ed8f0183 Add SSH hostname arg to GitLab bootstrap 2020-08-21 17:37:44 +03:00
stefanprodan
7cb3bb0d4e Fix Harbor typo 2020-08-21 17:31:56 +03:00
Hidde Beydals
d27d42d9ca Merge pull request #163 from mberwanger/master 2020-08-20 18:07:51 +02:00
Hidde Beydals
e2fd6e8f86 Merge pull request #168 from fluxcd/update-helm-roadmap
Update helm-controller roadmap
2020-08-20 15:59:30 +02:00
Hidde Beydals
a8e534a8a4 Update helm-controller roadmap 2020-08-20 15:52:42 +02:00
Hidde Beydals
479d7575fa Merge pull request #167 from fluxcd/guide-helm-targetpath
Document targetPath in Helm Releases guide
2020-08-20 15:27:58 +02:00
Hidde Beydals
4707a3075e Document targetPath in Helm Releases guide 2020-08-20 15:14:50 +02:00
Hidde Beydals
21a189e0b7 Merge pull request #166 from fluxcd/helm-v0.0.4
Update helm-controller to v0.0.4
2020-08-20 14:38:31 +02:00
Martin H Berwanger
ab7ff6551f Install script improvements #24
- add checksum verification with sha256sum fallback to shasum
- add downloader fallback to wget
- add os and architecture checks
2020-08-20 08:32:04 -04:00
Hidde Beydals
248961d58c Update helm-controller to v0.0.4 2020-08-20 14:27:36 +02:00
Hidde Beydals
473e226883 Merge pull request #162 from fluxcd/components-upgrade 2020-08-18 15:10:42 +02:00
Hidde Beydals
2ebb06d330 Update notification controller docs to v0.0.7 2020-08-18 14:25:19 +02:00
Hidde Beydals
cc88e68c4e Update components
- source-controller to v0.0.10
- kustomize-controller to v0.0.8
- helm-controller to v0.0.3
2020-08-18 14:23:29 +02:00
Hidde Beydals
f8704747d9 Merge pull request #161 from fluxcd/dedicated-pkgs
Switch to dedicated fluxcd/pkg and api modules
2020-08-18 14:01:19 +02:00
Hidde Beydals
0c33df883c Switch to dedicated fluxcd/pkg and api modules 2020-08-18 13:45:48 +02:00
Stefan Prodan
3fbc396bc8 Merge pull request #160 from fluxcd/export-fix
Make export work offline
2020-08-18 14:36:58 +03:00
stefanprodan
17df7a46e2 Make export work offline 2020-08-17 19:58:17 +03:00
Michael Bridgen
925c1d3d8e Merge pull request #158 from fluxcd/add-secrets-to-roadmap
Add roadmap line item for SOPS support
2020-08-13 16:47:16 +01:00
Michael Bridgen
1976d4cc1b Add line item for SOPS support 2020-08-13 16:30:39 +01:00
Stefan Prodan
d98578f260 Merge pull request #157 from fluxcd/helm-v3.3.0
Update controllers for Helm v3.3.0
2020-08-13 15:17:15 +03:00
stefanprodan
8d1dddf205 Update controllers for Helm v3.3.0 2020-08-13 14:28:51 +03:00
Daniel Holbach
2584b6ca5b Merge pull request #149 from dholbach/fix-142
Add initial set of FAQ
2020-08-11 18:11:28 +02:00
Daniel Holbach
70897cebfe Add initial set of FAQ
closes: #142
2020-08-11 18:04:32 +02:00
Stefan Prodan
0e80cd5c44 Merge pull request #148 from fluxcd/monitoring-stack
Add monitoring stack and dashboards
2020-08-05 17:26:03 +03:00
Stefan Prodan
b979e313b2 Merge pull request #150 from fluxcd/notification-0.0.7
Update notification-controller to v0.0.7
2020-08-05 17:24:38 +03:00
stefanprodan
533cb42d29 Update notification-controller to v0.0.7 2020-08-05 17:07:45 +03:00
stefanprodan
35a209903e Add monitoring section to install docs 2020-08-05 16:17:18 +03:00
stefanprodan
824de61579 Filter controllers in control plane dashboard 2020-08-04 18:56:32 +03:00
stefanprodan
17ca3f8ac2 Add control plane dashboard screens 2020-08-04 15:43:17 +03:00
stefanprodan
87a299736e Add control plane Grafana dashboard 2020-08-04 15:41:13 +03:00
stefanprodan
e86286722a Add Prom+Grafana monitoring stack 2020-08-04 15:40:38 +03:00
Daniel Holbach
c4a0724c8d Merge pull request #145 from dholbach/update-contributor-guide
Update contributors guide
2020-08-03 17:27:59 +02:00
Daniel Holbach
17139f34dd Update contributors guide
- point out GH discussions
	- move "understanding GOTK" earlier
	- point out dev-guide
	- update reality on calendar invitations
2020-08-03 15:24:48 +02:00
Stefan Prodan
1779714b0d Merge pull request #144 from fluxcd/docs-installation
Add installation guide
2020-08-03 11:27:47 +03:00
stefanprodan
1ff4495737 Link to installation docs from other guides 2020-08-03 10:43:42 +03:00
stefanprodan
02c0dc1217 Add bootstrap path example to installation 2020-08-03 10:24:25 +03:00
stefanprodan
fb43c194b9 Add installation guide 2020-08-01 13:22:22 +03:00
Hidde Beydals
ae94bb56d9 Merge pull request #141 from fluxcd/enhancement/create-source-helm-certs
Support providing TLS certs for helm source
2020-07-31 16:41:52 +02:00
Hidde Beydals
123433c4ea Support providing TLS certs for helm source 2020-07-31 16:29:52 +02:00
Stefan Prodan
58619076ea Merge pull request #140 from fluxcd/docs-roadmap-update
Mark metrics as completed in roadmap
2020-07-31 14:14:55 +03:00
stefanprodan
a50d1c5784 Update roadmap 2020-07-31 14:07:06 +03:00
Hidde Beydals
91c8cb197f Merge pull request #139 from fluxcd/docs/helm-valuesfrom
docs/helm: guide on values from resources
2020-07-31 13:03:43 +02:00
Hidde Beydals
427c60618f docs/helm: guide on values from resources 2020-07-31 12:56:09 +02:00
Hidde Beydals
2d417f200d Merge pull request #138 from fluxcd/update-components
Update components
2020-07-31 12:17:37 +02:00
Hidde Beydals
54b11e7b25 Update components
- source-controller to v0.0.7
- kustomize-controller to v0.0.7
- helm-controller to v0.0.1
- notification-controller to v0.0.6
2020-07-31 10:24:29 +02:00
Hidde Beydals
50d2eb7d57 Merge pull request #134 from bia/132-beautify-roadmap 2020-07-30 22:50:28 +02:00
bia
dfb20dd1ca docs: progressbar as subtitle 2020-07-30 22:00:01 +02:00
bia
4f22016f13 docs: improve goals styling 2020-07-30 12:12:22 +02:00
bia
430a2d0454 docs: add progressbar and checkmarks to roadmap 2020-07-29 23:54:40 +02:00
Hidde Beydals
db23c8ce9f Merge pull request #131 from mmorejon/update-tk-help-description 2020-07-26 23:38:37 +02:00
Manuel Morejon
ffd4784916 Replace tab by space 2020-07-26 00:35:40 +02:00
Manuel Morejon
750830c302 Replace tk sync example by tk reconcile 2020-07-26 00:24:58 +02:00
Manuel Morejon
d245ef9b39 Remove tk sync example from help command
Signed-off-by: Manuel Morejon <manuel@mmorejon.io>
2020-07-25 14:32:33 +02:00
Stefan Prodan
c8586d1ef4 Merge pull request #130 from fluxcd/kustomize-0.0.6
Update kustomize-controller to v0.0.6
2020-07-25 11:26:44 +03:00
stefanprodan
316cba1cb8 Update kustomize-controller to v0.0.6 2020-07-25 11:13:18 +03:00
Stefan Prodan
13dba62b8d Merge pull request #128 from fluxcd/container-registry
Add container registry and image pull secret as install options
2020-07-23 15:34:27 +03:00
stefanprodan
c2ff169c08 Add image pull secret arg to install/bootstrap 2020-07-23 13:38:32 +03:00
stefanprodan
57a1dbfc6d Add container registry option to install/bootstrap 2020-07-23 13:07:34 +03:00
Stefan Prodan
efb39d6fc6 Merge pull request #127 from fluxcd/node-selector
Add linux/amd64 node selector to controllers
2020-07-23 12:44:34 +03:00
Stefan Prodan
b784234430 Merge pull request #126 from fluxcd/uninstall-crs
Delete custom resources during uninstall
2020-07-23 12:44:18 +03:00
stefanprodan
aebad92426 Add linux/amd64 node selector to controllers
Set nodeSelector to linux/amd64 for clusters with mixed nodes (linux, windows, amd64, arm).
2020-07-23 09:59:45 +03:00
stefanprodan
8e67cfd5c9 Delete custom resources during uninstall
Remove Kustomizations, GitRepositories and HelmRepositories before deleting the toolkit controllers and CRDs.
2020-07-23 09:26:10 +03:00
Stefan Prodan
10cc6d7e08 Merge pull request #124 from fluxcd/helm-beta.4
Update helm-controller to v0.0.1-beta.4
2020-07-22 16:49:11 +03:00
stefanprodan
83c236c829 Update helm-controller to v0.0.1-beta.4 2020-07-22 16:36:59 +03:00
Stefan Prodan
b6ab37691f Merge pull request #120 from fluxcd/sealed-secrets
Add sealed secrets guide
2020-07-22 15:45:00 +03:00
stefanprodan
c85af78025 Add sealed secrets guide 2020-07-22 14:43:55 +03:00
Stefan Prodan
2c2fc6dd97 Merge pull request #123 from fluxcd/optional-notifications
Make notification component optional
2020-07-22 14:41:40 +03:00
stefanprodan
3620b76139 Make notification component optional 2020-07-22 14:30:39 +03:00
Stefan Prodan
ca5732e586 Merge pull request #121 from fluxcd/helm-beta.3
Update helm-controller to v0.0.1-beta.3
2020-07-21 20:31:31 +03:00
stefanprodan
2463d72f3b Update helm-controller to v0.0.1-beta.3 2020-07-21 20:18:23 +03:00
stefanprodan
d6f7474200 Add get/export HelmRelease e2e tests 2020-07-21 14:25:31 +03:00
stefanprodan
0b2bc7ab3f Implement get/export HelmRelease for Helm releases 2020-07-21 14:22:20 +03:00
Stefan Prodan
0a4fac61d4 Merge pull request #118 from fluxcd/hr-cmd
Implement create/delete for Helm releases
2020-07-21 14:10:45 +03:00
stefanprodan
797aec5528 Add create/delete HelmRelease e2e tests 2020-07-21 14:02:29 +03:00
stefanprodan
5f0b95dc59 Implement create/delete for Helm releases 2020-07-21 12:20:41 +03:00
Stefan Prodan
b384c5f14c Merge pull request #116 from fluxcd/helm-repo-cmd
Implement Helm repository commands
2020-07-21 11:09:31 +03:00
stefanprodan
5254dca9d9 Add Helm repository cmd docs 2020-07-21 10:42:05 +03:00
stefanprodan
8534ccbf37 Implement Helm repository commands 2020-07-21 10:39:17 +03:00
stefanprodan
9af874d810 Add examples to all tk commands 2020-07-21 10:38:44 +03:00
Stefan Prodan
4e3dee15ce Merge pull request #114 from fluxcd/fix-kustomize-cmd
Rename kustomization arg from validate to validation
2020-07-20 15:30:00 +03:00
stefanprodan
aaad618e20 Rename kustomization arg from validate to validation
Fix `tk create kustomization` command args inconsistency with the Kustomize API
2020-07-20 15:10:33 +03:00
Stefan Prodan
10bb50bd82 Merge pull request #113 from fluxcd/crd-v1
Drop support for Kubernetes <1.16
2020-07-20 14:56:45 +03:00
stefanprodan
6d2ff6e019 Update controllers and APIs 2020-07-20 14:41:23 +03:00
stefanprodan
670070a879 Drop support for Kubernetes <1.16 2020-07-20 14:37:50 +03:00
Stefan Prodan
dcec8007d4 Merge pull request #88 from luxas/go_git_provider
Add go-git-providers proposal
2020-07-20 11:53:36 +03:00
Michael Bridgen
3abf4a49cd Merge pull request #108 from fluxcd/link-to-image-update-discussion
Link to image update discussion
2020-07-17 13:03:03 +01:00
Michael Bridgen
38825bf96a Cosmetic: indent sublist 2020-07-17 12:55:24 +01:00
Michael Bridgen
faa69da28d Link to image update discussion
.. and rearrange the line items a little. I removed the mention of source-controller because it doesn't feature in the design as drafted.
2020-07-17 12:08:42 +01:00
Hidde Beydals
5cf524e2fd Merge pull request #106 from fluxcd/docs/update-helm-roadmap
Make nested list work correctly in roadmap
2020-07-17 12:45:44 +02:00
Hidde Beydals
88802a44e7 Make nested list work correctly in roadmap 2020-07-17 12:34:16 +02:00
Stefan Prodan
94498d862d Merge pull request #105 from fluxcd/static-manifests
Use semver manifests as kustomize base
2020-07-17 13:27:51 +03:00
Hidde Beydals
9418b24e8f Merge pull request #104 from fluxcd/docs/update-helm-roadmap
Update "Helm Operator v2" roadmap
2020-07-17 12:11:57 +02:00
stefanprodan
b92cbcd7e7 Use semver manifests as kustomize base
Instead of cloning the components repositories to download the base manifests, we build them in CI at release time and download them in tk install/bootstrap based on the provided semver. This speeds up the manifests generation from minutes to milliseconds.
2020-07-17 13:10:19 +03:00
Hidde Beydals
9ef2ff92df Update "Helm Operator v2" roadmap 2020-07-17 12:04:09 +02:00
Lucas Käldström
b1993d2fb7 Add Reconcile methods and TeamAccess struct. Mention ErrNotFound and ErrAlreadyExists. Add List() to TeamAccess. Rename GetTitle() to GetName() 2020-07-14 16:39:31 +03:00
Lucas Käldström
e8096dec88 Rename the Repository Teams and Credential clients 2020-07-14 16:39:25 +03:00
Lucas Käldström
39eee51ec8 Add extra goals of best practices 2020-07-14 16:39:14 +03:00
Lucas Käldström
7bb3a10795 Remove the URLParser, and Provider from the *Ref types 2020-07-14 16:39:02 +03:00
Lucas Käldström
4c684df653 Add go-git-providers proposal 2020-07-14 12:49:29 +03:00
324 changed files with 21044 additions and 3999 deletions

View File

@@ -1,9 +0,0 @@
name: 'kustomize'
description: 'A GitHub Action to run kustomize commands'
author: 'Stefan Prodan'
branding:
icon: 'command'
color: 'blue'
runs:
using: 'docker'
image: 'Dockerfile'

View File

@@ -1,12 +0,0 @@
#!/bin/sh -l
VERSION=3.5.4
curl -sL https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv${VERSION}/kustomize_v${VERSION}_linux_amd64.tar.gz | tar xz
mkdir -p $GITHUB_WORKSPACE/bin
cp ./kustomize $GITHUB_WORKSPACE/bin
chmod +x $GITHUB_WORKSPACE/bin/kustomize
ls -lh $GITHUB_WORKSPACE/bin
echo "::add-path::$GITHUB_WORKSPACE/bin"
echo "::add-path::$RUNNER_WORKSPACE/$(basename $GITHUB_REPOSITORY)/bin"

17
.github/aur/flux-bin/.SRCINFO.template vendored Normal file
View File

@@ -0,0 +1,17 @@
pkgbase = flux-bin
pkgdesc = Open and extensible continuous delivery solution for Kubernetes
pkgver = ${PKGVER}
pkgrel = ${PKGREL}
url = https://fluxcd.io/
arch = x86_64
arch = armv6h
arch = armv7h
arch = aarch64
license = APACHE
optdepends = kubectl
source_x86_64 = flux-bin-${PKGVER}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v1/flux_${PKGVER}_linux_amd64.tar.gz
source_armv6h = flux-bin-${PKGVER}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v1/flux_${PKGVER}_linux_arm.tar.gz
source_armv7h = flux-bin-${PKGVER}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v1/flux_${PKGVER}_linux_arm.tar.gz
source_aarch64 = flux-bin-${PKGVER}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v1/flux_${PKGVER}_linux_arm64.tar.gz
pkgname = flux-bin

1
.github/aur/flux-bin/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.pkg

39
.github/aur/flux-bin/PKGBUILD.template vendored Normal file
View File

@@ -0,0 +1,39 @@
# Maintainer: Aurel Canciu <aurelcanciu@gmail.com>
# Maintainer: Hidde Beydals <hello@hidde.co>
pkgname=flux-bin
pkgver=${PKGVER}
pkgrel=${PKGREL}
pkgdesc="Open and extensible continuous delivery solution for Kubernetes"
url="https://fluxcd.io/"
arch=("x86_64" "armv6h" "armv7h" "aarch64")
license=("APACHE")
optdepends=("kubectl")
source_x86_64=(
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_amd64.tar.gz"
)
source_armv6h=(
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_arm.tar.gz"
)
source_armv7h=(
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_arm.tar.gz"
)
source_aarch64=(
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_arm64.tar.gz"
)
sha256sums_x86_64=(
${SHA256SUM_AMD64}
)
sha256sums_armv6h=(
${SHA256SUM_ARM}
)
sha256sums_armv7h=(
${SHA256SUM_ARM}
)
sha256sums_aarch64=(
${SHA256SUM_ARM64}
)
package() {
install -Dm755 flux "$pkgdir/usr/bin/flux"
}

50
.github/aur/flux-bin/publish.sh vendored Executable file
View File

@@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -e
WD=$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)
PKGNAME=$(basename $WD)
ROOT=${WD%/.github/aur/$PKGNAME}
export VERSION=$1
echo "Publishing to AUR as version ${VERSION}"
cd $WD
export GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
eval $(ssh-agent -s)
ssh-add <(echo "$AUR_BOT_SSH_PRIVATE_KEY")
GITDIR=$(mktemp -d /tmp/aur-$PKGNAME-XXX)
trap "rm -rf $GITDIR" EXIT
git clone aur@aur.archlinux.org:$PKGNAME $GITDIR 2>&1
CURRENT_PKGVER=$(cat $GITDIR/.SRCINFO | grep pkgver | awk '{ print $3 }')
CURRENT_PKGREL=$(cat $GITDIR/.SRCINFO | grep pkgrel | awk '{ print $3 }')
export PKGVER=${VERSION/-/}
if [[ "${CURRENT_PKGVER}" == "${PKGVER}" ]]; then
export PKGREL=$((CURRENT_PKGREL+1))
else
export PKGREL=1
fi
export SHA256SUM_ARM=$(sha256sum ${ROOT}/dist/flux_${PKGVER}_linux_arm.tar.gz | awk '{ print $1 }')
export SHA256SUM_ARM64=$(sha256sum ${ROOT}/dist/flux_${PKGVER}_linux_arm64.tar.gz | awk '{ print $1 }')
export SHA256SUM_AMD64=$(sha256sum ${ROOT}/dist/flux_${PKGVER}_linux_amd64.tar.gz | awk '{ print $1 }')
envsubst '$PKGVER $PKGREL $SHA256SUM_AMD64 $SHA256SUM_ARM $SHA256SUM_ARM64' < .SRCINFO.template > $GITDIR/.SRCINFO
envsubst '$PKGVER $PKGREL $SHA256SUM_AMD64 $SHA256SUM_ARM $SHA256SUM_ARM64' < PKGBUILD.template > $GITDIR/PKGBUILD
cd $GITDIR
git config user.name "fluxcdbot"
git config user.email "fluxcdbot@users.noreply.github.com"
git add -A
if [ -z "$(git status --porcelain)" ]; then
echo "No changes."
else
git commit -m "Updated to version v${PKGVER} release ${PKGREL}"
git push origin master
fi

19
.github/aur/flux-go/.SRCINFO.template vendored Normal file
View File

@@ -0,0 +1,19 @@
pkgbase = flux-go
pkgdesc = Open and extensible continuous delivery solution for Kubernetes
pkgver = ${PKGVER}
pkgrel = ${PKGREL}
url = https://fluxcd.io/
arch = x86_64
arch = armv6h
arch = armv7h
arch = aarch64
license = APACHE
makedepends = go
depends = glibc
optdepends = kubectl
provides = flux-bin
conflicts = flux-bin
replaces = flux-cli
source = flux-go-${PKGVER}.tar.gz::https://github.com/fluxcd/flux2/archive/v${PKGVER}.tar.gz
pkgname = flux-go

1
.github/aur/flux-go/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.pkg

43
.github/aur/flux-go/PKGBUILD.template vendored Normal file
View File

@@ -0,0 +1,43 @@
# Maintainer: Aurel Canciu <aurelcanciu@gmail.com>
# Maintainer: Hidde Beydals <hello@hidde.co>
pkgname=flux-go
pkgver=${PKGVER}
pkgrel=${PKGREL}
pkgdesc="Open and extensible continuous delivery solution for Kubernetes"
url="https://fluxcd.io/"
arch=("x86_64" "armv6h" "armv7h" "aarch64")
license=("APACHE")
provides=("flux-bin")
conflicts=("flux-bin")
replaces=("flux-cli")
depends=("glibc")
makedepends=("go")
optdepends=("kubectl")
source=(
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/archive/v$pkgver.tar.gz"
)
sha256sums=(
${SHA256SUM}
)
build() {
cd "flux2-$pkgver"
export CGO_LDFLAGS="$LDFLAGS"
export CGO_CFLAGS="$CFLAGS"
export CGO_CXXFLAGS="$CXXFLAGS"
export CGO_CPPFLAGS="$CPPFLAGS"
export GOFLAGS="-buildmode=pie -trimpath -ldflags=-linkmode=external -mod=readonly -modcacherw"
go build -ldflags "-X main.VERSION=$pkgver" -o flux-bin ./cmd/flux
}
check() {
cd "flux2-$pkgver"
make test
}
package() {
cd "flux2-$pkgver"
install -Dm755 flux-bin "$pkgdir/usr/bin/flux"
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
}

48
.github/aur/flux-go/publish.sh vendored Executable file
View File

@@ -0,0 +1,48 @@
#!/usr/bin/env bash
set -e
WD=$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)
PKGNAME=$(basename $WD)
ROOT=${WD%/.github/aur/$PKGNAME}
export VERSION=$1
echo "Publishing to AUR as version ${VERSION}"
cd $WD
export GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
eval $(ssh-agent -s)
ssh-add <(echo "$AUR_BOT_SSH_PRIVATE_KEY")
GITDIR=$(mktemp -d /tmp/aur-$PKGNAME-XXX)
trap "rm -rf $GITDIR" EXIT
git clone aur@aur.archlinux.org:$PKGNAME $GITDIR 2>&1
CURRENT_PKGVER=$(cat $GITDIR/.SRCINFO | grep pkgver | awk '{ print $3 }')
CURRENT_PKGREL=$(cat $GITDIR/.SRCINFO | grep pkgrel | awk '{ print $3 }')
export PKGVER=${VERSION/-/}
if [[ "${CURRENT_PKGVER}" == "${PKGVER}" ]]; then
export PKGREL=$((CURRENT_PKGREL+1))
else
export PKGREL=1
fi
export SHA256SUM=$(curl -sL https://github.com/fluxcd/flux2/archive/v$PKGVER.tar.gz | sha256sum | awk '{ print $1 }')
envsubst '$PKGVER $PKGREL $SHA256SUM' < .SRCINFO.template > $GITDIR/.SRCINFO
envsubst '$PKGVER $PKGREL $SHA256SUM' < PKGBUILD.template > $GITDIR/PKGBUILD
cd $GITDIR
git config user.name "fluxcdbot"
git config user.email "fluxcdbot@users.noreply.github.com"
git add -A
if [ -z "$(git status --porcelain)" ]; then
echo "No changes."
else
git commit -m "Updated to version v${PKGVER} release ${PKGREL}"
git push origin master
fi

19
.github/aur/flux-scm/.SRCINFO.template vendored Normal file
View File

@@ -0,0 +1,19 @@
pkgbase = flux-scm
pkgdesc = Open and extensible continuous delivery solution for Kubernetes
pkgver = ${PKGVER}
pkgrel = ${PKGREL}
url = https://fluxcd.io/
arch = x86_64
arch = armv6h
arch = armv7h
arch = aarch64
license = APACHE
makedepends = go
depends = glibc
optdepends = kubectl
provides = flux-bin
conflicts = flux-bin
source = git+https://github.com/fluxcd/flux2.git
md5sums = SKIP
pkgname = flux-scm

1
.github/aur/flux-scm/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.pkg

45
.github/aur/flux-scm/PKGBUILD.template vendored Normal file
View File

@@ -0,0 +1,45 @@
# Maintainer: Aurel Canciu <aurelcanciu@gmail.com>
# Maintainer: Hidde Beydals <hello@hidde.co>
pkgname=flux-scm
pkgver=${PKGVER}
pkgrel=${PKGREL}
pkgdesc="Open and extensible continuous delivery solution for Kubernetes"
url="https://fluxcd.io/"
arch=("x86_64" "armv6h" "armv7h" "aarch64")
license=("APACHE")
provides=("flux-bin")
conflicts=("flux-bin")
depends=("glibc")
makedepends=("go")
optdepends=("kubectl")
source=(
"git+https://github.com/fluxcd/flux2.git"
)
md5sums=('SKIP')
pkgver() {
cd "flux2"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
build() {
cd "flux2"
export CGO_LDFLAGS="$LDFLAGS"
export CGO_CFLAGS="$CFLAGS"
export CGO_CXXFLAGS="$CXXFLAGS"
export CGO_CPPFLAGS="$CPPFLAGS"
export GOFLAGS="-buildmode=pie -trimpath -ldflags=-linkmode=external -mod=readonly -modcacherw"
go build -ldflags "-X main.VERSION=$pkgver" -o flux-bin ./cmd/flux
}
check() {
cd "flux2"
make test
}
package() {
cd "flux2"
install -Dm755 flux-bin "$pkgdir/usr/bin/flux"
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
}

46
.github/aur/flux-scm/publish.sh vendored Executable file
View File

@@ -0,0 +1,46 @@
#!/usr/bin/env bash
set -e
WD=$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)
PKGNAME=$(basename $WD)
ROOT=${WD%/.github/aur/$PKGNAME}
export VERSION=$1
echo "Publishing to AUR as version ${VERSION}"
cd $WD
export GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
eval $(ssh-agent -s)
ssh-add <(echo "$AUR_BOT_SSH_PRIVATE_KEY")
GITDIR=$(mktemp -d /tmp/aur-$PKGNAME-XXX)
trap "rm -rf $GITDIR" EXIT
git clone aur@aur.archlinux.org:$PKGNAME $GITDIR 2>&1
CURRENT_PKGVER=$(cat $GITDIR/.SRCINFO | grep pkgver | awk '{ print $3 }')
CURRENT_PKGREL=$(cat $GITDIR/.SRCINFO | grep pkgrel | awk '{ print $3 }')
export PKGVER=${VERSION/-/}
if [[ "${CURRENT_PKGVER}" == "${PKGVER}" ]]; then
export PKGREL=$((CURRENT_PKGREL+1))
else
export PKGREL=1
fi
envsubst '$PKGVER $PKGREL' < .SRCINFO.template > $GITDIR/.SRCINFO
envsubst '$PKGVER $PKGREL' < PKGBUILD.template > $GITDIR/PKGBUILD
cd $GITDIR
git config user.name "fluxcdbot"
git config user.email "fluxcdbot@users.noreply.github.com"
git add -A
if [ -z "$(git status --porcelain)" ]; then
echo "No changes."
else
git commit -m "Updated to version v${PKGVER} release ${PKGREL}"
git push origin master
fi

78
.github/workflows/bootstrap.yaml vendored Normal file
View File

@@ -0,0 +1,78 @@
name: bootstrap
on:
push:
branches:
- '*'
jobs:
github:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Restore Go cache
uses: actions/cache@v1
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.15.x
- name: Setup Kubernetes
uses: engineerd/setup-kind@v0.5.0
- name: Set outputs
id: vars
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
- name: Build
run: sudo go build -o ./bin/flux ./cmd/flux
- name: bootstrap init
run: |
./bin/flux bootstrap github --manifests ./manifests/install/ \
--owner=fluxcd-testing \
--repository=flux-test-${{ steps.vars.outputs.sha_short }} \
--branch=main \
--path=test-cluster
env:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
- name: bootstrap no-op
run: |
./bin/flux bootstrap github --manifests ./manifests/install/ \
--owner=fluxcd-testing \
--repository=flux-test-${{ steps.vars.outputs.sha_short }} \
--branch=main \
--path=test-cluster
env:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
- name: uninstall
run: |
./bin/flux suspend kustomization flux-system
./bin/flux uninstall --resources --crds -s
- name: bootstrap reinstall
run: |
./bin/flux bootstrap github --manifests ./manifests/install/ \
--owner=fluxcd-testing \
--repository=flux-test-${{ steps.vars.outputs.sha_short }} \
--branch=main \
--path=test-cluster
env:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
- name: delete repository
run: |
./bin/flux bootstrap github --manifests ./manifests/install/ \
--owner=fluxcd-testing \
--repository=flux-test-${{ steps.vars.outputs.sha_short }} \
--branch=main \
--path=test-cluster \
--delete
env:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
- name: Debug failure
if: failure()
run: |
kubectl -n flux-system get all
kubectl -n flux-system logs deploy/source-controller
kubectl -n flux-system logs deploy/kustomize-controller

View File

@@ -3,7 +3,7 @@ on:
push:
branches:
- docs*
- master
- main
jobs:
build:
@@ -13,30 +13,51 @@ jobs:
- name: Checkout master
uses: actions/checkout@v1
- name: Copy assets
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# source-controller CRDs
curl https://raw.githubusercontent.com/fluxcd/source-controller/master/docs/api/source.md > docs/components/source/api.md
curl https://raw.githubusercontent.com/fluxcd/source-controller/master/docs/spec/v1alpha1/gitrepositories.md > docs/components/source/gitrepositories.md
curl https://raw.githubusercontent.com/fluxcd/source-controller/master/docs/spec/v1alpha1/helmrepositories.md > docs/components/source/helmrepositories.md
curl https://raw.githubusercontent.com/fluxcd/source-controller/master/docs/spec/v1alpha1/helmcharts.md > docs/components/source/helmcharts.md
controller_version() {
sed -n "s/.*$1\/archive\/\(.*\).zip.*/\1/p;n" manifests/bases/$1/kustomization.yaml
}
# kustomize-controller CRDs
curl https://raw.githubusercontent.com/fluxcd/kustomize-controller/master/docs/api/kustomize.md > docs/components/kustomize/api.md
curl https://raw.githubusercontent.com/fluxcd/kustomize-controller/master/docs/spec/v1alpha1/kustomization.md > docs/components/kustomize/kustomization.md
{
# source-controller CRDs
SOURCE_VER=$(controller_version source-controller)
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/source-controller/$SOURCE_VER/docs/api/source.md" > docs/components/source/api.md
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/source-controller/$SOURCE_VER/docs/spec/v1beta1/gitrepositories.md" > docs/components/source/gitrepositories.md
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/source-controller/$SOURCE_VER/docs/spec/v1beta1/helmrepositories.md" > docs/components/source/helmrepositories.md
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/source-controller/$SOURCE_VER/docs/spec/v1beta1/helmcharts.md" > docs/components/source/helmcharts.md
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/source-controller/$SOURCE_VER/docs/spec/v1beta1/buckets.md" > docs/components/source/buckets.md
}
# helm-controller CRDs
curl https://raw.githubusercontent.com/fluxcd/helm-controller/master/docs/api/helmrelease.md > docs/components/helm/api.md
curl https://raw.githubusercontent.com/fluxcd/helm-controller/master/docs/spec/v2alpha1/helmreleases.md > docs/components/helm/helmreleases.md
{
# kustomize-controller CRDs
KUSTOMIZE_VER=$(controller_version kustomize-controller)
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/kustomize-controller/$KUSTOMIZE_VER/docs/api/kustomize.md" > docs/components/kustomize/api.md
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/kustomize-controller/$KUSTOMIZE_VER/docs/spec/v1beta1/kustomization.md" > docs/components/kustomize/kustomization.md
}
# notification-controller CRDs
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/api/notification.md > docs/components/notification/api.md
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/spec/v1alpha1/event.md > docs/components/notification/event.md
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/spec/v1alpha1/alert.md > docs/components/notification/alert.md
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/spec/v1alpha1/provider.md > docs/components/notification/provider.md
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/spec/v1alpha1/receiver.md > docs/components/notification/receiver.md
{
# helm-controller CRDs
HELM_VER=$(controller_version helm-controller)
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/helm-controller/$HELM_VER/docs/api/helmrelease.md" > docs/components/helm/api.md
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/helm-controller/$HELM_VER/docs/spec/v2beta1/helmreleases.md" > docs/components/helm/helmreleases.md
}
# install script
cp install/tk.sh docs/install.sh
{
# notification-controller CRDs
NOTIFICATION_VER=$(controller_version notification-controller)
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/notification-controller/$NOTIFICATION_VER/docs/api/notification.md" > docs/components/notification/api.md
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/notification-controller/$NOTIFICATION_VER/docs/spec/v1beta1/event.md" > docs/components/notification/event.md
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/notification-controller/$NOTIFICATION_VER/docs/spec/v1beta1/alert.md" > docs/components/notification/alert.md
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/notification-controller/$NOTIFICATION_VER/docs/spec/v1beta1/provider.md" > docs/components/notification/provider.md
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/notification-controller/$NOTIFICATION_VER/docs/spec/v1beta1/receiver.md" > docs/components/notification/receiver.md
}
{
# install script
cp install/flux.sh docs/install.sh
}
- name: Deploy docs
uses: mhausenblas/mkdocs-deploy-gh-pages@master
env:

View File

@@ -4,7 +4,7 @@ on:
pull_request:
push:
branches:
- master
- main
jobs:
kind:
@@ -20,11 +20,13 @@ jobs:
restore-keys: |
${{ runner.os }}-go-
- name: Setup Go
uses: actions/setup-go@v2-beta
uses: actions/setup-go@v2
with:
go-version: 1.14.x
go-version: 1.15.x
- name: Setup Kubernetes
uses: engineerd/setup-kind@v0.3.0
uses: engineerd/setup-kind@v0.5.0
with:
image: kindest/node:v1.16.9
- name: Run test
run: make test
- name: Check if working tree is dirty
@@ -35,68 +37,126 @@ jobs:
exit 1
fi
- name: Build
run: sudo go build -o ./bin/tk ./cmd/tk
- name: tk check --pre
run: sudo go build -o ./bin/flux ./cmd/flux
- name: flux check --pre
run: |
./bin/tk check --pre
- name: tk install --version
./bin/flux check --pre
- name: flux install --manifests
run: |
./bin/tk install --version=master --namespace=test --verbose --components="source-controller,kustomize-controller"
- name: tk uninstall
./bin/flux install --manifests ./manifests/install/
- name: flux create source git
run: |
./bin/tk uninstall --namespace=test --crds --silent
- name: tk install --manifests
run: |
./bin/tk install --manifests ./manifests/install/ --version=""
- name: tk create source git
run: |
./bin/tk create source git podinfo \
./bin/flux create source git podinfo \
--url https://github.com/stefanprodan/podinfo \
--tag-semver=">=3.2.3"
- name: tk get sources git
- name: flux create source git export apply
run: |
./bin/tk get sources git
- name: tk create kustomization
./bin/flux create source git podinfo-export \
--url https://github.com/stefanprodan/podinfo \
--tag-semver=">=3.2.3" \
--export | kubectl apply -f -
./bin/flux delete source git podinfo-export --silent
- name: flux get sources git
run: |
./bin/tk create kustomization podinfo \
./bin/flux get sources git
- name: flux get sources git --all-namespaces
run: |
./bin/flux get sources git --all-namespaces
- name: flux create kustomization
run: |
./bin/flux create kustomization podinfo \
--source=podinfo \
--path="./deploy/overlays/dev" \
--prune=true \
--interval=5m \
--validate=client \
--validation=client \
--health-check="Deployment/frontend.dev" \
--health-check="Deployment/backend.dev" \
--health-check-timeout=3m
- name: tk sync kustomization --with-source
- name: flux reconcile kustomization --with-source
run: |
./bin/tk reconcile kustomization podinfo --with-source
- name: tk get kustomizations
./bin/flux reconcile kustomization podinfo --with-source
- name: flux get kustomizations
run: |
./bin/tk get kustomizations
- name: tk suspend kustomization
./bin/flux get kustomizations
- name: flux get kustomizations --all-namespaces
run: |
./bin/tk suspend kustomization podinfo
- name: tk resume kustomization
./bin/flux get kustomizations --all-namespaces
- name: flux suspend kustomization
run: |
./bin/tk resume kustomization podinfo
- name: tk export
./bin/flux suspend kustomization podinfo
- name: flux resume kustomization
run: |
./bin/tk export source git --all
./bin/tk export kustomization --all
- name: tk delete kustomization
./bin/flux resume kustomization podinfo
- name: flux export
run: |
./bin/tk delete kustomization podinfo --silent
- name: tk delete source git
./bin/flux export source git --all
./bin/flux export kustomization --all
- name: flux delete kustomization
run: |
./bin/tk delete source git podinfo --silent
- name: tk check
./bin/flux delete kustomization podinfo --silent
- name: flux create source helm
run: |
./bin/tk check
./bin/flux create source helm podinfo \
--url https://stefanprodan.github.io/podinfo
- name: flux create helmrelease --source=HelmRepository/podinfo
run: |
./bin/flux create hr podinfo-helm \
--target-namespace=default \
--source=HelmRepository/podinfo \
--chart=podinfo \
--chart-version=">4.0.0 <5.0.0"
- name: flux create helmrelease --source=GitRepository/podinfo
run: |
./bin/flux create hr podinfo-git \
--target-namespace=default \
--source=GitRepository/podinfo \
--chart=./charts/podinfo
- name: flux reconcile helmrelease --with-source
run: |
./bin/flux reconcile helmrelease podinfo-git --with-source
- name: flux get helmreleases
run: |
./bin/flux get helmreleases
- name: flux get helmreleases --all-namespaces
run: |
./bin/flux get helmreleases --all-namespaces
- name: flux export helmrelease
run: |
./bin/flux export hr --all
- name: flux delete helmrelease podinfo-helm
run: |
./bin/flux delete hr podinfo-helm --silent
- name: flux delete helmrelease podinfo-git
run: |
./bin/flux delete hr podinfo-git --silent
- name: flux delete source helm
run: |
./bin/flux delete source helm podinfo --silent
- name: flux delete source git
run: |
./bin/flux delete source git podinfo --silent
- name: flux create tenant
run: |
./bin/flux create tenant dev-team --with-namespace=apps
./bin/flux -n apps create source helm podinfo \
--url https://stefanprodan.github.io/podinfo
./bin/flux -n apps create hr podinfo-helm \
--source=HelmRepository/podinfo \
--chart=podinfo \
--chart-version="5.0.x" \
--service-account=dev-team
- name: flux check
run: |
./bin/flux check
- name: flux uninstall
run: |
./bin/flux uninstall --crds --silent
- name: Debug failure
if: failure()
run: |
kubectl version --client --short
kubectl -n gitops-system get all
kubectl -n gitops-system get kustomizations -oyaml
kubectl -n gitops-system logs deploy/source-controller
kubectl -n gitops-system logs deploy/kustomize-controller
kubectl -n flux-system get all
kubectl -n flux-system get kustomizations -oyaml
kubectl -n flux-system logs deploy/source-controller
kubectl -n flux-system logs deploy/kustomize-controller

25
.github/workflows/fossa.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: FOSSA
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: "^1.14.x"
- name: Add GOPATH to GITHUB_ENV
run: echo "GOPATH=$(go env GOPATH)" >>"$GITHUB_ENV"
- name: Add GOPATH to GITHUB_PATH
run: echo "$GOPATH/bin" >>"$GITHUB_PATH"
- name: Run FOSSA scan and upload build data
uses: fossa-contrib/fossa-action@v1
with:
# FOSSA Push-Only API Token
fossa-api-key: 5ee8bf422db1471e0bcf2bcb289185de
github-token: ${{ github.token }}

21
.github/workflows/rebase.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: rebase
on:
pull_request:
types: [opened]
issue_comment:
types: [created]
jobs:
rebase:
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') && (github.event.comment.author_association == 'CONTRIBUTOR' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER')
runs-on: ubuntu-latest
steps:
- name: Checkout the latest code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.3.1
env:
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}

View File

@@ -16,7 +16,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.14.x
go-version: 1.15.x
- name: Download release notes utility
env:
GH_REL_URL: https://github.com/buchanae/github-release-notes/releases/download/0.2.0/github-release-notes-linux-amd64-0.2.0.tar.gz
@@ -24,9 +24,11 @@ jobs:
- name: Generate release notes
run: |
echo 'CHANGELOG' > /tmp/release.txt
github-release-notes -org fluxcd -repo toolkit -since-latest-release >> /tmp/release.txt
github-release-notes -org fluxcd -repo toolkit -since-latest-release -include-author >> /tmp/release.txt
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Kustomize
uses: ./.github/actions/kustomize
uses: fluxcd/pkg//actions/kustomize@main
- name: Generate manifests tarball
run: |
mkdir -p ./output
@@ -57,24 +59,9 @@ jobs:
# create tarball
cd ./output && tar -cvzf manifests.tar.gz $files
- name: Create release
id: create_release
uses: actions/create-release@latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
- name: Upload artifacts
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./output/manifests.tar.gz
asset_name: manifests.tar.gz
asset_content_type: application/gzip
- name: Generate install manifest
run: |
kustomize build ./manifests/install > ./output/install.yaml
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v1
with:
@@ -82,3 +69,5 @@ jobs:
args: release --release-notes=/tmp/release.txt --skip-validate
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
AUR_BOT_SSH_PRIVATE_KEY: ${{ secrets.AUR_BOT_SSH_PRIVATE_KEY }}

74
.github/workflows/update.yml vendored Normal file
View File

@@ -0,0 +1,74 @@
name: Update Components
on:
workflow_dispatch:
schedule:
- cron: "0 * * * *"
jobs:
update-components:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Update component versions
id: update
run: |
PR_BODY=""
bump_version() {
local RELEASE_VERSION=$(curl -s https://api.github.com/repos/fluxcd/$1/releases | jq -r 'sort_by(.published_at) | .[-1] | .tag_name')
local CURRENT_VERSION=$(sed -n "s/.*$1\/archive\/\(.*\).zip.*/\1/p;n" manifests/bases/$1/kustomization.yaml)
if [[ "${RELEASE_VERSION}" != "${CURRENT_VERSION}" ]]; then
# bump kustomize
sed -i "s/\($1\/archive\/\)v.*\(.zip\/\/$1-\).*\(\/config.*\)/\1${RELEASE_VERSION}\2${RELEASE_VERSION/v}\3/g" "manifests/bases/$1/kustomization.yaml"
if [[ ! -z $(go list -m all | grep "github.com/fluxcd/$1/api" | awk '{print $2}') ]]; then
# bump go mod
go mod edit -require="github.com/fluxcd/$1/api@${RELEASE_VERSION}"
fi
PR_BODY="$PR_BODY- $1 to ${RELEASE_VERSION}%0A"
fi
}
{
# bump controller versions
bump_version helm-controller
bump_version kustomize-controller
bump_version source-controller
bump_version notification-controller
# add missing and remove unused modules
go mod tidy
# diff change
git diff
# export PR_BODY for PR
echo "::set-output name=pr_body::$PR_BODY"
}
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.BOT_GITHUB_TOKEN }}
commit-message: Update toolkit components
committer: GitHub <noreply@github.com>
author: fluxcdbot <fluxcdbot@users.noreply.github.com>
title: Update toolkit components
body: |
${{ steps.update.outputs.pr_body }}
Auto-generated by [create-pull-request][1]
[1]: https://github.com/peter-evans/create-pull-request
branch: update-components
reviewers: ${{ secrets.ASSIGNEES }}
- name: Check output
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"

View File

@@ -1,16 +1,93 @@
builds:
- main: ./cmd/tk
ldflags:
- -s -w -X main.VERSION={{ .Version }}
binary: tk
- <<: &build_defaults
binary: flux
main: ./cmd/flux
ldflags:
- -s -w -X main.VERSION={{ .Version }}
env:
- CGO_ENABLED=0
id: linux
goos:
- darwin
- linux
goarch:
- amd64
- arm64
- arm
goarm:
- 7
- <<: *build_defaults
id: darwin
goos:
- darwin
- <<: *build_defaults
id: windows
goos:
- windows
- id: aurmock
binary: aurmock
main: ./cmd/flux
env:
- CGO_ENABLED=0
goos:
- linux
goarch:
- amd64
archives:
- name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
id: nix
builds: [linux, darwin]
format: tar.gz
files:
- none*
- name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
id: windows
builds: [windows]
format: zip
files:
- none*
- name_template: "aur_{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
id: aur
builds: [aurmock]
brews:
- name: flux
tap:
owner: fluxcd
name: homebrew-tap
token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
folder: Formula
homepage: "https://toolkit.fluxcd.io/"
description: "Flux CLI"
dependencies:
- name: kubectl
type: optional
test: |
system "#{bin}/flux --version"
publishers:
- name: aur-pkg-bin
ids:
- aur
env:
- AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }}
cmd: |
.github/aur/flux-bin/publish.sh {{ .Version }}
- name: aur-pkg-scm
ids:
- aur
env:
- AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }}
cmd: |
.github/aur/flux-scm/publish.sh {{ .Version }}
- name: aur-pkg-go
ids:
- aur
env:
- AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }}
cmd: |
.github/aur/flux-go/publish.sh {{ .Version }}
release:
ids:
- nix
- windows
extra_files:
- glob: ./output/manifests.tar.gz
- glob: ./output/install.yaml

View File

@@ -1,8 +1,10 @@
# Contributing
The GitOps Toolkit is [Apache 2.0 licensed](https://github.com/fluxcd/toolkit/blob/master/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.
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.
We gratefully welcome improvements to issues and documentation as well as to
code.
@@ -18,15 +20,38 @@ organization.
## Communications
The project uses Slack: To join the conversation, simply join the
[CNCF](https://slack.cncf.io/) Slack workspace and use the
For realtime communications we use Slack: To join the conversation, simply
join the [CNCF](https://slack.cncf.io/) Slack workspace and use the
[#flux-dev](https://cloud-native.slack.com/messages/flux-dev/) channel.
The developers use a mailing list to discuss development as well.
Simply subscribe to [flux-dev on cncf.io](https://lists.cncf.io/g/cncf-flux-dev)
to join the conversation (this will also add an invitation to your
Google calendar for our [Flux
meeting](https://docs.google.com/document/d/1l_M0om0qUEN_NNiGgpqJ2tvsF2iioHkaARDeh6b70B0/edit#)).
To discuss ideas and specifications we use [Github
Discussions](https://github.com/fluxcd/flux2/discussions).
For announcements we use a mailing list as well. Simply subscribe to
[flux-dev on cncf.io](https://lists.cncf.io/g/cncf-flux-dev)
to join the conversation (there you can also add calendar invites
to your Google calendar for our [Flux
meeting](https://docs.google.com/document/d/1l_M0om0qUEN_NNiGgpqJ2tvsF2iioHkaARDeh6b70B0/view)).
## Understanding Flux and the GitOps Toolkit
If you are entirely new to Flux and the GitOps Toolkit,
you might want to take a look at the [introductory talk and demo](https://www.youtube.com/watch?v=qQBtSkgl7tI).
This project is composed of:
- [/f/flux2](https://github.com/fluxcd/flux2): The Flux CLI
- [/f/source-manager](https://github.com/fluxcd/source-controller): Kubernetes operator for managing sources
- [/f/kustomize-controller](https://github.com/fluxcd/kustomize-controller): Kubernetes operator for building GitOps pipelines with Kustomize
- [/f/helm-controller](https://github.com/fluxcd/helm-controller): Kubernetes operator for building GitOps pipelines with Helm
- [/f/notification-controller](https://github.com/fluxcd/notification-controller): Kubernetes operator for handling inbound and outbound events
### Understanding the code
To get started with developing controllers, you might want to review
[our guide](https://toolkit.fluxcd.io/dev-guides/source-watcher/) which
walks you through writing a short and concise controller that watches out
for source changes.
### How to run the test suite
@@ -66,16 +91,3 @@ For the GitOps Toolkit controllers we prefer the following rules for good commit
The [following article](https://chris.beams.io/posts/git-commit/#seven-rules)
has some more helpful advice on documenting your work.
## Understanding the GitOps Toolkit
If you are entirely new to the GitOps Toolkit,
you might want to take a look at the [introductory talk and demo](https://www.youtube.com/watch?v=qQBtSkgl7tI).
This project is composed of:
- [/f/toolkit](https://github.com/fluxcd/toolkit): The GitOps Toolkit CLI
- [/f/source-manager](https://github.com/fluxcd/source-controller): Kubernetes operator for managing sources
- [/f/kustomize-controller](https://github.com/fluxcd/kustomize-controller): Kubernetes operator for building GitOps pipelines with Kustomize
- [/f/helm-controller](https://github.com/fluxcd/helm-controller): Kubernetes operator for building GitOps pipelines with Helm
- [/f/notification-controller](https://github.com/fluxcd/notification-controller): Kubernetes operator for handling inbound and outbound events

View File

@@ -2,7 +2,17 @@ The maintainers are generally available in Slack at
https://cloud-native.slack.com in #flux (https://cloud-native.slack.com/messages/CLAJ40HV3)
(obtain an invitation at https://slack.cncf.io/).
These maintainers are shared with other Flux v2-related git
repositories under https://github.com/fluxcd, as noted in their
respective MAINTAINERS files.
For convenience, they are reflected in the GitHub team
@fluxcd/flux2-maintainers -- if the list here changes, that team also
should.
In alphabetical order:
Aurel Canciu, Sortlist <aurel@sortlist.com> (github: @relu, slack: relu)
Hidde Beydals, Weaveworks <hidde@weave.works> (github: @hiddeco, slack: hidde)
Philip Laine, Xenit <philip.laine@xenit.se> (github: @phillebaba, slack: phillebaba)
Stefan Prodan, Weaveworks <stefan@weave.works> (github: @stefanprodan, slack: stefanprodan)

View File

@@ -1,4 +1,4 @@
VERSION?=$(shell grep 'VERSION' cmd/tk/main.go | awk '{ print $$4 }' | tr -d '"')
VERSION?=$(shell grep 'VERSION' cmd/flux/main.go | awk '{ print $$4 }' | tr -d '"')
all: test build
@@ -15,14 +15,15 @@ test: tidy fmt vet docs
go test ./... -coverprofile cover.out
build:
CGO_ENABLED=0 go build -o ./bin/tk ./cmd/tk
CGO_ENABLED=0 go build -o ./bin/flux ./cmd/flux
install:
go install cmd/tk
go install cmd/flux
.PHONY: docs
docs:
mkdir -p ./docs/cmd && go run ./cmd/tk/ docgen
rm docs/cmd/*
mkdir -p ./docs/cmd && go run ./cmd/flux/ docgen
install-dev:
CGO_ENABLED=0 go build -o /usr/local/bin ./cmd/tk
CGO_ENABLED=0 go build -o /usr/local/bin ./cmd/flux

128
README.md
View File

@@ -1,12 +1,124 @@
# GitOps Toolkit
# Flux version 2
[![e2e](https://github.com/fluxcd/toolkit/workflows/e2e/badge.svg)](https://github.com/fluxcd/toolkit/actions)
[![report](https://goreportcard.com/badge/github.com/fluxcd/toolkit)](https://goreportcard.com/report/github.com/fluxcd/toolkit)
[![license](https://img.shields.io/github/license/fluxcd/toolkit.svg)](https://github.com/fluxcd/toolkit/blob/master/LICENSE)
[![release](https://img.shields.io/github/release/fluxcd/toolkit/all.svg)](https://github.com/fluxcd/toolkit/releases)
[![e2e](https://github.com/fluxcd/flux2/workflows/e2e/badge.svg)](https://github.com/fluxcd/flux2/actions)
[![report](https://goreportcard.com/badge/github.com/fluxcd/flux2)](https://goreportcard.com/report/github.com/fluxcd/flux2)
[![license](https://img.shields.io/github/license/fluxcd/flux2.svg)](https://github.com/fluxcd/flux2/blob/main/LICENSE)
[![release](https://img.shields.io/github/release/fluxcd/flux2/all.svg)](https://github.com/fluxcd/flux2/releases)
Experimental toolkit for assembling CD pipelines the GitOps way.
Flux is a tool for keeping Kubernetes clusters in sync with sources of
configuration (like Git repositories), and automating updates to
configuration when there is new code to deploy.
![overview](docs/diagrams/tk-feature.png)
Flux version 2 ("v2") is built from the ground up to use Kubernetes'
API extension system, and to integrate with Prometheus and other core
components of the Kubernetes ecosystem. In version 2, Flux supports
multi-tenancy and support for syncing an arbitrary number of Git
repositories, among other long-requested features.
To get started with the toolkit please read the [docs](https://toolkit.fluxcd.io/).
Flux v2 is constructed with the [GitOps Toolkit](#gitops-toolkit), a
set of composable APIs and specialized tools for building Continuous
Delivery on top of Kubernetes.
## Flux installation
With Homebrew:
```sh
brew install fluxcd/tap/flux
```
With Bash:
```sh
curl -s https://toolkit.fluxcd.io/install.sh | sudo bash
# enable completions in ~/.bash_profile
. <(flux completion bash)
```
Arch Linux (AUR) packages:
- [flux-bin](https://aur.archlinux.org/packages/flux-bin): install the latest
stable version using a pre-build binary (recommended)
- [flux-go](https://aur.archlinux.org/packages/flux-go): build the latest
stable version from source code
- [flux-scm](https://aur.archlinux.org/packages/flux-scm): build the latest
(unstable) version from source code from our git `main` branch
Binaries for macOS, Windows and Linux AMD64/ARM are available to download on the
[release page](https://github.com/fluxcd/flux2/releases).
Verify that your cluster satisfies the prerequisites with:
```sh
flux check --pre
```
## Get started
To get started with Flux, start [browsing the
documentation](https://toolkit.fluxcd.io) or get started with one of
the following guides:
- [Get started with Flux (deep dive)](https://toolkit.fluxcd.io/get-started/)
- [Installation](https://toolkit.fluxcd.io/guides/installation/)
- [Manage Helm Releases](https://toolkit.fluxcd.io/guides/helmreleases/)
- [Setup Notifications](https://toolkit.fluxcd.io/guides/notifications/)
- [Setup Webhook Receivers](https://toolkit.fluxcd.io/guides/webhook-receivers/)
## GitOps Toolkit
The GitOps Toolkit is the set of APIs and controllers that make up the
runtime for Flux v2. The APIs comprise Kubernetes custom resources,
which can be created and updated by a cluster user, or by other
automation tooling.
![overview](docs/diagrams/gitops-toolkit.png)
You can use the toolkit to extend Flux, or to build your own systems
for continuous delivery -- see [the developer
guides](https://toolkit.fluxcd.io/dev-guides/source-watcher/).
### Components
- [Source Controller](https://toolkit.fluxcd.io/components/source/controller/)
- [GitRepository CRD](https://toolkit.fluxcd.io/components/source/gitrepositories/)
- [HelmRepository CRD](https://toolkit.fluxcd.io/components/source/helmrepositories/)
- [HelmChart CRD](https://toolkit.fluxcd.io/components/source/helmcharts/)
- [Bucket CRD](https://toolkit.fluxcd.io/components/source/buckets/)
- [Kustomize Controller](https://toolkit.fluxcd.io/components/kustomize/controller/)
- [Kustomization CRD](https://toolkit.fluxcd.io/components/kustomize/kustomization/)
- [Helm Controller](https://toolkit.fluxcd.io/components/helm/controller/)
- [HelmRelease CRD](https://toolkit.fluxcd.io/components/helm/helmreleases/)
- [Notification Controller](https://toolkit.fluxcd.io/components/notification/controller/)
- [Provider CRD](https://toolkit.fluxcd.io/components/notification/provider/)
- [Alert CRD](https://toolkit.fluxcd.io/components/notification/alert/)
- [Receiver CRD](https://toolkit.fluxcd.io/components/notification/receiver/)
## Community
The Flux project is always looking for new contributors and there are a multitude of ways to get involved.
Depending on what you want to do, some of the following bits might be your first steps:
- 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)
- 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
### Featured Talks
- 24 Nov 2020 - [Flux CD v2 with GitOps Toolkit - Kubernetes Deployment and Sync Mechanism](https://youtu.be/R6OeIgb7lUI)
- 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)
- 4 Sep 2020 - [KubeCon Europe: The road to Flux v2 and Progressive Delivery with Stefan Prodan & Hidde Beydals](https://youtu.be/8v94nUkXsxU)
- 25 June 2020 - [Cloud Native Nordics: Introduction to GitOps & GitOps Toolkit with Alexis Richardson & Stefan Prodan](https://youtu.be/qQBtSkgl7tI)
- 7 May 2020 - [GitOps Days - Community Special: GitOps Toolkit Experimentation with Stefan Prodan](https://youtu.be/WHzxunv4DKk?t=6521)
### Upcoming Events
- 30 Nov 2020 - [The Power of GitOps with Flux & GitOps Toolkit - Part 3 with Leigh Capili](https://www.meetup.com/Weave-User-Group/events/274657228/)
We are looking forward to seeing you with us!

View File

@@ -1,4 +1,4 @@
FROM giantswarm/tiny-tools
FROM stefanprodan/alpine-base:latest
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

79
action/README.md Normal file
View File

@@ -0,0 +1,79 @@
# Flux GitHub Action
Usage:
```yaml
steps:
- name: Setup Flux CLI
uses: fluxcd/flux2/action@main
- name: Run Flux commands
run: flux -v
```
### Automate Flux updates
Example workflow for updating Flux's components generated with `flux bootstrap --arch=amd64 --path=clusters/production`:
```yaml
name: update-flux
on:
workflow_dispatch:
schedule:
- cron: "0 * * * *"
jobs:
components:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Setup Flux CLI
uses: fluxcd/flux2/action@main
- name: Check for updates
id: update
run: |
flux install --arch=amd64 \
--export > ./clusters/production/flux-system/gotk-components.yaml
VERSION="$(flux -v)"
echo "::set-output name=flux_version::$VERSION"
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: update-flux
commit-message: Update to ${{ steps.update.outputs.flux_version }}
title: Update to ${{ steps.update.outputs.flux_version }}
body: |
${{ steps.update.outputs.flux_version }}
```
### End-to-end testing
Example workflow for running Flux in Kubernetes Kind:
```yaml
name: e2e
on:
push:
branches:
- '*'
jobs:
kubernetes:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Flux CLI
uses: fluxcd/flux2/action@main
- name: Setup Kubernetes Kind
uses: engineerd/setup-kind@v0.5.0
- name: Install Flux in Kubernetes Kind
run: flux install
```
A complete e2e testing workflow is available here
[flux2-kustomize-helm-example](https://github.com/fluxcd/flux2-kustomize-helm-example/blob/main/.github/workflows/e2e.yaml)

15
action/action.yml Normal file
View File

@@ -0,0 +1,15 @@
name: 'kustomize'
description: 'A GitHub Action for running Flux commands'
author: 'Flux project'
branding:
icon: 'command'
color: 'blue'
inputs:
version:
description: 'strict semver'
required: false
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.version }}

40
action/entrypoint.sh Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/bash
# 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.
set -e
VERSION=$1
if [ -z $VERSION ]; then
# Find latest release if no version is specified
VERSION=$(curl https://api.github.com/repos/fluxcd/flux2/releases/latest -sL | grep tag_name | sed -E 's/.*"([^"]+)".*/\1/' | cut -c 2-)
fi
# Download linux binary
BIN_URL="https://github.com/fluxcd/flux2/releases/download/v${VERSION}/flux_${VERSION}_linux_amd64.tar.gz"
curl -sL $BIN_URL | tar xz
# Copy binary to GitHub runner
mkdir -p $GITHUB_WORKSPACE/bin
cp ./flux $GITHUB_WORKSPACE/bin
chmod +x $GITHUB_WORKSPACE/bin/flux
# Print version
$GITHUB_WORKSPACE/bin/flux -v
# Add binary to GitHub runner path
echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH
echo "$RUNNER_WORKSPACE/$(basename $GITHUB_REPOSITORY)/bin" >> $GITHUB_PATH

254
cmd/flux/bootstrap.go Normal file
View File

@@ -0,0 +1,254 @@
/*
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 (
"context"
"fmt"
"net/url"
"path/filepath"
"time"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/install"
"github.com/fluxcd/flux2/pkg/manifestgen/sync"
)
var bootstrapCmd = &cobra.Command{
Use: "bootstrap",
Short: "Bootstrap toolkit components",
Long: "The bootstrap sub-commands bootstrap the toolkit components on the targeted Git provider.",
}
var (
bootstrapVersion string
bootstrapComponents []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
)
const (
bootstrapDefaultBranch = "main"
)
func init() {
bootstrapCmd.PersistentFlags().StringVarP(&bootstrapVersion, "version", "v", defaults.Version,
"toolkit version")
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapComponents, "components", defaults.Components,
"list of components, accepts comma-separated values")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapRegistry, "registry", "ghcr.io/fluxcd",
"container registry where the toolkit images are published")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapImagePullSecret, "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,
"default branch (for GitHub this must match the default branch setting for the organization)")
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapWatchAllNamespaces, "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,
"deny ingress access to the toolkit controllers from other namespaces using network policies")
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapTokenAuth, "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().MarkHidden("manifests")
rootCmd.AddCommand(bootstrapCmd)
}
func bootstrapValidate() error {
for _, component := range bootstrapRequiredComponents {
if !utils.ContainsItemString(bootstrapComponents, component) {
return fmt.Errorf("component %s is required", component)
}
}
return nil
}
func generateInstallManifests(targetPath, namespace, tmpDir string, localManifests string) (string, error) {
opts := install.Options{
BaseURL: localManifests,
Version: bootstrapVersion,
Namespace: 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,
TargetPath: targetPath,
}
if localManifests == "" {
opts.BaseURL = defaults.BaseURL
}
output, err := install.Generate(opts)
if err != nil {
return "", fmt.Errorf("generating install manifests failed: %w", err)
}
if filePath, err := output.WriteFile(tmpDir); err != nil {
return "", fmt.Errorf("generating install manifests failed: %w", err)
} else {
return filePath, nil
}
}
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 {
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 {
return fmt.Errorf("install failed")
}
}
return nil
}
func generateSyncManifests(url, branch, name, namespace, targetPath, tmpDir string, interval time.Duration) error {
opts := sync.Options{
Name: name,
Namespace: namespace,
URL: url,
Branch: branch,
Interval: interval,
TargetPath: targetPath,
ManifestFile: sync.MakeDefaultOptions().ManifestFile,
}
manifest, err := sync.Generate(opts)
if err != nil {
return fmt.Errorf("generating install manifests failed: %w", err)
}
if _, err := manifest.WriteFile(tmpDir); err != nil {
return err
}
if err := utils.GenerateKustomizationYaml(filepath.Join(tmpDir, targetPath, namespace)); err != nil {
return err
}
return nil
}
func applySyncManifests(ctx context.Context, kubeClient client.Client, name, namespace, targetPath, tmpDir string) error {
kubectlArgs := []string{"apply", "-k", filepath.Join(tmpDir, targetPath, namespace)}
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
return err
}
logger.Waitingf("waiting for cluster sync")
var gitRepository sourcev1.GitRepository
if err := wait.PollImmediate(pollInterval, 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,
isKustomizationReady(ctx, kubeClient, types.NamespacedName{Name: name, Namespace: namespace}, &kustomization)); err != nil {
return err
}
return nil
}
func shouldInstallManifests(ctx context.Context, kubeClient client.Client, namespace string) bool {
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: namespace,
}
var kustomization kustomizev1.Kustomization
if err := kubeClient.Get(ctx, namespacedName, &kustomization); err != nil {
return true
}
return kustomization.Status.LastAppliedRevision == ""
}
func shouldCreateDeployKey(ctx context.Context, kubeClient client.Client, namespace string) bool {
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: namespace,
}
var existing corev1.Secret
if err := kubeClient.Get(ctx, namespacedName, &existing); err != nil {
return true
}
return false
}
func generateDeployKey(ctx context.Context, kubeClient client.Client, url *url.URL, namespace string) (string, error) {
pair, err := generateKeyPair(ctx)
if err != nil {
return "", err
}
hostKey, err := scanHostKey(ctx, url)
if err != nil {
return "", err
}
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
Namespace: namespace,
},
StringData: map[string]string{
"identity": string(pair.PrivateKey),
"identity.pub": string(pair.PublicKey),
"known_hosts": string(hostKey),
},
}
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return "", err
}
return string(pair.PublicKey), nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -26,7 +26,10 @@ import (
"time"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/git"
)
@@ -34,7 +37,7 @@ var bootstrapGitHubCmd = &cobra.Command{
Use: "github",
Short: "Bootstrap toolkit components in a GitHub repository",
Long: `The bootstrap github command creates the GitHub repository if it doesn't exists and
commits the toolkit components manifests to the master branch.
commits the toolkit components manifests to the main branch.
Then it configures the target cluster to synchronize with the repository.
If the toolkit components are present on the cluster,
the bootstrap command will perform an upgrade if needed.`,
@@ -42,32 +45,40 @@ the bootstrap command will perform an upgrade if needed.`,
export GITHUB_TOKEN=<my-token>
# Run bootstrap for a private repo owned by a GitHub organization
bootstrap github --owner=<organization> --repository=<repo name>
flux bootstrap github --owner=<organization> --repository=<repo name>
# Run bootstrap for a private repo and assign organization teams to it
bootstrap github --owner=<organization> --repository=<repo name> --team=<team1 slug> --team=<team2 slug>
flux bootstrap github --owner=<organization> --repository=<repo name> --team=<team1 slug> --team=<team2 slug>
# Run bootstrap for a repository path
bootstrap github --owner=<organization> --repository=<repo name> --path=dev-cluster
flux bootstrap github --owner=<organization> --repository=<repo name> --path=dev-cluster
# Run bootstrap for a public repository on a personal account
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
bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain>
# 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>
# Run bootstrap for a private repo hosted on GitHub Enterprise using HTTPS auth
flux bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain> --token-auth
# Run bootstrap for a an existing repository with a branch named main
flux bootstrap github --owner=<organization> --repository=<repo name> --branch=main
`,
RunE: bootstrapGitHubCmdRun,
}
var (
ghOwner string
ghRepository string
ghInterval time.Duration
ghPersonal bool
ghPrivate bool
ghHostname string
ghPath string
ghTeams []string
ghOwner string
ghRepository string
ghInterval time.Duration
ghPersonal bool
ghPrivate bool
ghHostname string
ghPath string
ghTeams []string
ghDelete bool
ghSSHHostname string
)
const (
@@ -82,8 +93,12 @@ func init() {
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().StringVar(&ghPath, "path", "", "repository path, when specified the cluster sync will be scoped to this path")
bootstrapGitHubCmd.Flags().BoolVar(&ghDelete, "delete", false, "delete repository (used for testing only)")
bootstrapGitHubCmd.Flags().MarkHidden("delete")
bootstrapCmd.AddCommand(bootstrapGitHubCmd)
}
@@ -93,21 +108,24 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("%s environment variable not found", git.GitHubTokenName)
}
repository, err := git.NewRepository(ghRepository, ghOwner, ghHostname, ghToken, "tk", ghOwner+"@users.noreply.github.com")
if err := bootstrapValidate(); err != nil {
return err
}
repository, err := git.NewRepository(ghRepository, ghOwner, ghHostname, ghToken, "flux", ghOwner+"@users.noreply.github.com")
if err != nil {
return err
}
if ghSSHHostname != "" {
repository.SSHHost = ghSSHHostname
}
provider := &git.GithubProvider{
IsPrivate: ghPrivate,
IsPersonal: ghPersonal,
}
kubeClient, err := utils.kubeClient(kubeconfig)
if err != nil {
return err
}
tmpDir, err := ioutil.TempDir("", namespace)
if err != nil {
return err
@@ -117,6 +135,14 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
if ghDelete {
if err := provider.DeleteRepository(ctx, repository); err != nil {
return err
}
logger.Successf("repository deleted")
return nil
}
// create GitHub repository if doesn't exists
logger.Actionf("connecting to %s", ghHostname)
changed, err := provider.CreateRepository(ctx, repository)
@@ -140,7 +166,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
}
}
// clone repository and checkout the master branch
// clone repository and checkout the main branch
if err := repository.Checkout(ctx, bootstrapBranch, tmpDir); err != nil {
return err
}
@@ -148,7 +174,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
// generate install manifests
logger.Generatef("generating manifests")
manifest, err := generateInstallManifests(ghPath, namespace, tmpDir)
manifest, err := generateInstallManifests(ghPath, namespace, tmpDir, bootstrapManifestsPath)
if err != nil {
return err
}
@@ -169,6 +195,11 @@ 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)
@@ -181,54 +212,71 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("install completed")
}
// setup SSH deploy key
if shouldCreateDeployKey(ctx, kubeClient, namespace) {
logger.Actionf("configuring deploy key")
u, err := url.Parse(repository.GetSSH())
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
repoURL := repository.GetURL()
key, err := generateDeployKey(ctx, kubeClient, u, namespace)
if err != nil {
return fmt.Errorf("generating deploy key failed: %w", err)
if bootstrapTokenAuth {
// setup HTTPS token auth
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
Namespace: namespace,
},
StringData: map[string]string{
"username": "git",
"password": ghToken,
},
}
keyName := "tk"
if ghPath != "" {
keyName = fmt.Sprintf("tk-%s", ghPath)
}
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err
} else if changed {
logger.Successf("deploy key configured")
}
} else {
// setup SSH deploy key
repoURL = repository.GetSSH()
if shouldCreateDeployKey(ctx, kubeClient, 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)
if err != nil {
return fmt.Errorf("generating deploy key failed: %w", err)
}
keyName := "flux"
if ghPath != "" {
keyName = fmt.Sprintf("flux-%s", ghPath)
}
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
return err
} else if changed {
logger.Successf("deploy key configured")
}
}
}
// configure repo synchronization
if isInstall {
// generate source and kustomization manifests
logger.Actionf("generating sync manifests")
if err := generateSyncManifests(repository.GetSSH(), namespace, namespace, ghPath, tmpDir, ghInterval); err != nil {
return err
}
logger.Actionf("generating sync manifests")
if err := generateSyncManifests(repoURL, bootstrapBranch, namespace, namespace, ghPath, tmpDir, ghInterval); err != nil {
return err
}
// commit and push manifests
if changed, err = repository.Commit(ctx, path.Join(ghPath, namespace), "Add manifests"); err != nil {
// commit and push manifests
if changed, err = repository.Commit(ctx, path.Join(ghPath, namespace), "Add manifests"); err != nil {
return err
} else if changed {
if err := repository.Push(ctx); err != nil {
return err
} else if changed {
if err := repository.Push(ctx); err != nil {
return err
}
logger.Successf("sync manifests pushed")
}
logger.Successf("sync manifests pushed")
}
// apply manifests and waiting for sync
logger.Actionf("applying sync manifests")
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, ghPath, tmpDir); err != nil {
return err
}
// apply manifests and waiting for sync
logger.Actionf("applying sync manifests")
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, ghPath, tmpDir); err != nil {
return err
}
if withErrors {

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -26,7 +26,10 @@ import (
"time"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/git"
)
@@ -41,29 +44,36 @@ 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 owned by a GitLab group
bootstrap gitlab --owner=<group> --repository=<repo name>
# 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
flux bootstrap gitlab --owner=<group> --repository=<repo name>
# Run bootstrap for a repository path
bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
flux bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
# Run bootstrap for a public repository on a personal account
bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal=true
flux bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal --token-auth
# Run bootstrap for a private repo hosted on a GitLab server
bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain>
flux bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain> --token-auth
# Run bootstrap for a an existing repository with a branch named main
flux bootstrap gitlab --owner=<organization> --repository=<repo name> --branch=main --token-auth
`,
RunE: bootstrapGitLabCmdRun,
}
var (
glOwner string
glRepository string
glInterval time.Duration
glPersonal bool
glPrivate bool
glHostname string
glPath string
glOwner string
glRepository string
glInterval time.Duration
glPersonal bool
glPrivate bool
glHostname string
glSSHHostname string
glPath string
)
func init() {
@@ -73,6 +83,7 @@ func init() {
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().StringVar(&glPath, "path", "", "repository path, when specified the cluster sync will be scoped to this path")
bootstrapCmd.AddCommand(bootstrapGitLabCmd)
@@ -84,17 +95,25 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("%s environment variable not found", git.GitLabTokenName)
}
repository, err := git.NewRepository(glRepository, glOwner, glHostname, glToken, "tk", glOwner+"@users.noreply.gitlab.com")
if err := bootstrapValidate(); err != nil {
return err
}
repository, err := git.NewRepository(glRepository, glOwner, glHostname, glToken, "flux", glOwner+"@users.noreply.gitlab.com")
if err != nil {
return err
}
if glSSHHostname != "" {
repository.SSHHost = glSSHHostname
}
provider := &git.GitLabProvider{
IsPrivate: glPrivate,
IsPersonal: glPersonal,
}
kubeClient, err := utils.kubeClient(kubeconfig)
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
@@ -126,7 +145,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
// generate install manifests
logger.Generatef("generating manifests")
manifest, err := generateInstallManifests(glPath, namespace, tmpDir)
manifest, err := generateInstallManifests(glPath, namespace, tmpDir, bootstrapManifestsPath)
if err != nil {
return err
}
@@ -159,54 +178,71 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("install completed")
}
// setup SSH deploy key
if shouldCreateDeployKey(ctx, kubeClient, namespace) {
logger.Actionf("configuring deploy key")
u, err := url.Parse(repository.GetSSH())
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
repoURL := repository.GetURL()
key, err := generateDeployKey(ctx, kubeClient, u, namespace)
if err != nil {
return fmt.Errorf("generating deploy key failed: %w", err)
if bootstrapTokenAuth {
// setup HTTPS token auth
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
Namespace: namespace,
},
StringData: map[string]string{
"username": "git",
"password": glToken,
},
}
keyName := "tk"
if glPath != "" {
keyName = fmt.Sprintf("tk-%s", glPath)
}
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err
} else if changed {
logger.Successf("deploy key configured")
}
} else {
// setup SSH deploy key
repoURL = repository.GetSSH()
if shouldCreateDeployKey(ctx, kubeClient, 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)
if err != nil {
return fmt.Errorf("generating deploy key failed: %w", err)
}
keyName := "flux"
if glPath != "" {
keyName = fmt.Sprintf("flux-%s", glPath)
}
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
return err
} else if changed {
logger.Successf("deploy key configured")
}
}
}
// configure repo synchronization
if isInstall {
// generate source and kustomization manifests
logger.Actionf("generating sync manifests")
if err := generateSyncManifests(repository.GetSSH(), namespace, namespace, glPath, tmpDir, glInterval); err != nil {
return err
}
logger.Actionf("generating sync manifests")
if err := generateSyncManifests(repoURL, bootstrapBranch, namespace, namespace, glPath, tmpDir, glInterval); err != nil {
return err
}
// commit and push manifests
if changed, err = repository.Commit(ctx, path.Join(glPath, namespace), "Add manifests"); err != nil {
// commit and push manifests
if changed, err = repository.Commit(ctx, path.Join(glPath, namespace), "Add manifests"); err != nil {
return err
} else if changed {
if err := repository.Push(ctx); err != nil {
return err
} else if changed {
if err := repository.Push(ctx); err != nil {
return err
}
logger.Successf("sync manifests pushed")
}
logger.Successf("sync manifests pushed")
}
// apply manifests and waiting for sync
logger.Actionf("applying sync manifests")
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, glPath, tmpDir); err != nil {
return err
}
// apply manifests and waiting for sync
logger.Actionf("applying sync manifests")
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, glPath, tmpDir); err != nil {
return err
}
logger.Successf("bootstrap finished")

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -18,13 +18,15 @@ package main
import (
"context"
"fmt"
"encoding/json"
"os"
"os/exec"
"strings"
"github.com/blang/semver"
"github.com/blang/semver/v4"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
apimachineryversion "k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
@@ -35,10 +37,10 @@ var checkCmd = &cobra.Command{
Long: `The check command will perform a series of checks to validate that
the local environment is configured correctly and if the installed components are healthy.`,
Example: ` # Run pre-installation checks
tk check --pre
flux check --pre
# Run installation checks
tk check
flux check
`,
RunE: runCheckCmd,
}
@@ -48,10 +50,14 @@ var (
checkComponents []string
)
type kubectlVersion struct {
ClientVersion *apimachineryversion.Info `json:"clientVersion"`
}
func init() {
checkCmd.Flags().BoolVarP(&checkPre, "pre", "", false,
"only run pre-installation checks")
checkCmd.Flags().StringSliceVar(&checkComponents, "components", defaultComponents,
checkCmd.Flags().StringSliceVar(&checkComponents, "components", defaults.Components,
"list of components, accepts comma-separated values")
rootCmd.AddCommand(checkCmd)
}
@@ -67,7 +73,7 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
checkFailed = true
}
if !kubernetesCheck(">=1.14.0") {
if !kubernetesCheck(">=1.16.0") {
checkFailed = true
}
@@ -97,14 +103,20 @@ func kubectlCheck(ctx context.Context, version string) bool {
return false
}
command := "kubectl version --client --short | awk '{ print $3 }'"
output, err := utils.execCommand(ctx, ModeCapture, command)
kubectlArgs := []string{"version", "--client", "--output", "json"}
output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubeconfig, kubecontext, kubectlArgs...)
if err != nil {
logger.Failuref("kubectl version can't be determined")
return false
}
v, err := semver.ParseTolerant(output)
kv := &kubectlVersion{}
if err = json.Unmarshal([]byte(output), kv); err != nil {
logger.Failuref("kubectl version output can't be unmarshaled")
return false
}
v, err := semver.ParseTolerant(kv.ClientVersion.GitVersion)
if err != nil {
logger.Failuref("kubectl version can't be parsed")
return false
@@ -161,14 +173,17 @@ func componentsCheck() bool {
ok := true
for _, deployment := range checkComponents {
command := fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s",
namespace, deployment, timeout.String())
if output, err := utils.execCommand(ctx, ModeCapture, command); err != nil {
kubectlArgs := []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubeconfig, 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 {
logger.Actionf(strings.TrimPrefix(strings.TrimSuffix(output, "\""), "\""))
}
}
return ok
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -17,24 +17,15 @@ limitations under the License.
package main
import (
"time"
"github.com/spf13/cobra"
)
var createCmd = &cobra.Command{
Use: "create",
Short: "Create or update sources and resources",
Long: "The create sub-commands generate sources and resources.",
var completionCmd = &cobra.Command{
Use: "completion",
Short: "Generates completion scripts for various shells",
Long: "The completion sub-command generates completion scripts for various shells",
}
var (
interval time.Duration
export bool
)
func init() {
createCmd.PersistentFlags().DurationVarP(&interval, "interval", "", time.Minute, "source sync interval")
createCmd.PersistentFlags().BoolVar(&export, "export", false, "export in YAML format to stdout")
rootCmd.AddCommand(createCmd)
rootCmd.AddCommand(completionCmd)
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -22,17 +22,17 @@ import (
"github.com/spf13/cobra"
)
var completionCmd = &cobra.Command{
Use: "completion",
var completionBashCmd = &cobra.Command{
Use: "bash",
Short: "Generates bash completion scripts",
Example: `To load completion run
. <(tk completion)
. <(flux completion bash)
To configure your bash shell to load completions for each session add to your bashrc
# ~/.bashrc or ~/.profile
. <(tk completion)
command -v flux >/dev/null && . <(flux completion bash)
`,
Run: func(cmd *cobra.Command, args []string) {
rootCmd.GenBashCompletion(os.Stdout)
@@ -40,5 +40,5 @@ To configure your bash shell to load completions for each session add to your ba
}
func init() {
rootCmd.AddCommand(completionCmd)
completionCmd.AddCommand(completionBashCmd)
}

View File

@@ -0,0 +1,45 @@
/*
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 (
"os"
"github.com/spf13/cobra"
)
var completionFishCmd = &cobra.Command{
Use: "fish",
Short: "Generates fish completion scripts",
Example: `To load completion run
. <(flux completion fish)
To configure your fish shell to load completions for each session write this script to your completions dir:
flux completion fish > ~/.config/fish/completions/flux
See http://fishshell.com/docs/current/index.html#completion-own for more details
`,
Run: func(cmd *cobra.Command, args []string) {
rootCmd.GenFishCompletion(os.Stdout, true)
},
}
func init() {
completionCmd.AddCommand(completionFishCmd)
}

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 (
"os"
"github.com/spf13/cobra"
)
var completionPowerShellCmd = &cobra.Command{
Use: "powershell",
Short: "Generates powershell completion scripts",
Example: `To load completion run
. <(flux completion powershell)
To configure your powershell shell to load completions for each session add to your powershell profile
Windows:
cd "$env:USERPROFILE\Documents\WindowsPowerShell\Modules"
flux completion >> flux-completion.ps1
Linux:
cd "${XDG_CONFIG_HOME:-"$HOME/.config/"}/powershell/modules"
flux completion >> flux-completions.ps1
`,
Run: func(cmd *cobra.Command, args []string) {
rootCmd.GenPowerShellCompletion(os.Stdout)
},
}
func init() {
completionCmd.AddCommand(completionPowerShellCmd)
}

View File

@@ -0,0 +1,52 @@
/*
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 (
"os"
"github.com/spf13/cobra"
)
var completionZshCmd = &cobra.Command{
Use: "zsh",
Short: "Generates zsh completion scripts",
Example: `To load completion run
. <(flux completion zsh) && compdef _flux flux
To configure your zsh shell to load completions for each session add to your zshrc
# ~/.zshrc or ~/.profile
command -v flux >/dev/null && . <(flux completion zsh) && compdef _flux flux
or write a cached file in one of the completion directories in your ${fpath}:
echo "${fpath// /\n}" | grep -i completion
flux completions zsh > _flux
mv _flux ~/.oh-my-zsh/completions # oh-my-zsh
mv _flux ~/.zprezto/modules/completion/external/src/ # zprezto
`,
Run: func(cmd *cobra.Command, args []string) {
rootCmd.GenZshCompletion(os.Stdout)
},
}
func init() {
completionCmd.AddCommand(completionZshCmd)
}

72
cmd/flux/create.go Normal file
View File

@@ -0,0 +1,72 @@
/*
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 (
"fmt"
"strings"
"time"
"k8s.io/apimachinery/pkg/util/validation"
"github.com/spf13/cobra"
)
var createCmd = &cobra.Command{
Use: "create",
Short: "Create or update sources and resources",
Long: "The create sub-commands generate sources and resources.",
}
var (
interval time.Duration
export bool
labels []string
)
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,
"set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2)")
rootCmd.AddCommand(createCmd)
}
func parseLabels() (map[string]string, error) {
result := make(map[string]string)
for _, label := range labels {
// validate key value pair
parts := strings.Split(label, "=")
if len(parts) != 2 {
return nil, fmt.Errorf("invalid label format '%s', must be key=value", label)
}
// validate label name
if errors := validation.IsQualifiedName(parts[0]); len(errors) > 0 {
return nil, fmt.Errorf("invalid label '%s': %v", parts[0], errors)
}
// validate label value
if errors := validation.IsValidLabelValue(parts[1]); len(errors) > 0 {
return nil, fmt.Errorf("invalid label value '%s': %v", parts[1], errors)
}
result[parts[0]] = parts[1]
}
return result, nil
}

193
cmd/flux/create_alert.go Normal file
View File

@@ -0,0 +1,193 @@
/*
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 (
"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"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
)
var createAlertCmd = &cobra.Command{
Use: "alert [name]",
Short: "Create or update a Alert resource",
Long: "The create alert command generates a Alert resource.",
Example: ` # Create an Alert for kustomization events
flux create alert \
--event-severity info \
--event-source Kustomization/flux-system \
--provider-ref slack \
flux-system
`,
RunE: createAlertCmdRun,
}
var (
aProviderRef string
aEventSeverity string
aEventSources []string
)
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>)")
createCmd.AddCommand(createAlertCmd)
}
func createAlertCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Alert name is required")
}
name := args[0]
if aProviderRef == "" {
return fmt.Errorf("provider ref is required")
}
eventSources := []notificationv1.CrossNamespaceObjectReference{}
for _, eventSource := range aEventSources {
kind, name := utils.ParseObjectKindName(eventSource)
if kind == "" {
return fmt.Errorf("invalid event source '%s', must be in format <kind>/<name>", eventSource)
}
eventSources = append(eventSources, notificationv1.CrossNamespaceObjectReference{
Kind: kind,
Name: name,
})
}
if len(eventSources) == 0 {
return fmt.Errorf("at least one event source is required")
}
sourceLabels, err := parseLabels()
if err != nil {
return err
}
if !export {
logger.Generatef("generating Alert")
}
alert := notificationv1.Alert{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: sourceLabels,
},
Spec: notificationv1.AlertSpec{
ProviderRef: corev1.LocalObjectReference{
Name: aProviderRef,
},
EventSeverity: aEventSeverity,
EventSources: eventSources,
Suspend: false,
},
}
if export {
return exportAlert(alert)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
logger.Actionf("applying Alert")
namespacedName, err := upsertAlert(ctx, kubeClient, &alert)
if err != nil {
return err
}
logger.Waitingf("waiting for Alert reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isAlertReady(ctx, kubeClient, namespacedName, &alert)); err != nil {
return err
}
logger.Successf("Alert %s is ready", name)
return nil
}
func upsertAlert(ctx context.Context, kubeClient client.Client,
alert *notificationv1.Alert) (types.NamespacedName, error) {
namespacedName := types.NamespacedName{
Namespace: alert.GetNamespace(),
Name: alert.GetName(),
}
var existing notificationv1.Alert
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, alert); err != nil {
return namespacedName, err
} else {
logger.Successf("Alert created")
return namespacedName, nil
}
}
return namespacedName, err
}
existing.Labels = alert.Labels
existing.Spec = alert.Spec
if err := kubeClient.Update(ctx, &existing); err != nil {
return namespacedName, err
}
alert = &existing
logger.Successf("Alert updated")
return namespacedName, nil
}
func isAlertReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, alert *notificationv1.Alert) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, alert)
if err != nil {
return false, err
}
if c := apimeta.FindStatusCondition(alert.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
return false, fmt.Errorf(c.Message)
}
}
return false, nil
}
}

View File

@@ -0,0 +1,191 @@
/*
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 (
"context"
"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"
"k8s.io/apimachinery/pkg/types"
"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"
)
var createAlertProviderCmd = &cobra.Command{
Use: "alert-provider [name]",
Short: "Create or update a Provider resource",
Long: "The create alert-provider command generates a Provider resource.",
Example: ` # Create a Provider for a Slack channel
flux create alert-provider slack \
--type slack \
--channel general \
--address https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK \
--secret-ref webhook-url
# Create a Provider for a Github repository
flux create alert-provider github-podinfo \
--type github \
--address https://github.com/stefanprodan/podinfo \
--secret-ref github-token
`,
RunE: createAlertProviderCmdRun,
}
var (
apType string
apChannel string
apUsername string
apAddress string
apSecretRef string
)
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")
createCmd.AddCommand(createAlertProviderCmd)
}
func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Provider name is required")
}
name := args[0]
if apType == "" {
return fmt.Errorf("Provider type is required")
}
sourceLabels, err := parseLabels()
if err != nil {
return err
}
if !export {
logger.Generatef("generating Provider")
}
provider := notificationv1.Provider{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: sourceLabels,
},
Spec: notificationv1.ProviderSpec{
Type: apType,
Channel: apChannel,
Username: apUsername,
Address: apAddress,
},
}
if apSecretRef != "" {
provider.Spec.SecretRef = &corev1.LocalObjectReference{
Name: apSecretRef,
}
}
if export {
return exportAlertProvider(provider)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
logger.Actionf("applying Provider")
namespacedName, err := upsertAlertProvider(ctx, kubeClient, &provider)
if err != nil {
return err
}
logger.Waitingf("waiting for Provider reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isAlertProviderReady(ctx, kubeClient, namespacedName, &provider)); err != nil {
return err
}
logger.Successf("Provider %s is ready", name)
return nil
}
func upsertAlertProvider(ctx context.Context, kubeClient client.Client,
provider *notificationv1.Provider) (types.NamespacedName, error) {
namespacedName := types.NamespacedName{
Namespace: provider.GetNamespace(),
Name: provider.GetName(),
}
var existing notificationv1.Provider
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, provider); err != nil {
return namespacedName, err
} else {
logger.Successf("Provider created")
return namespacedName, nil
}
}
return namespacedName, err
}
existing.Labels = provider.Labels
existing.Spec = provider.Spec
if err := kubeClient.Update(ctx, &existing); err != nil {
return namespacedName, err
}
provider = &existing
logger.Successf("Provider updated")
return namespacedName, nil
}
func isAlertProviderReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, provider *notificationv1.Provider) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, provider)
if err != nil {
return false, err
}
if c := apimeta.FindStatusCondition(provider.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
return false, fmt.Errorf(c.Message)
}
}
return false, nil
}
}

View File

@@ -0,0 +1,272 @@
/*
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 (
"context"
"fmt"
"io/ioutil"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
"github.com/spf13/cobra"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
)
var createHelmReleaseCmd = &cobra.Command{
Use: "helmrelease [name]",
Aliases: []string{"hr"},
Short: "Create or update a HelmRelease resource",
Long: "The helmrelease create command generates a HelmRelease resource for a given HelmRepository source.",
Example: ` # Create a HelmRelease with a chart from a HelmRepository source
flux create hr podinfo \
--interval=10m \
--source=HelmRepository/podinfo \
--chart=podinfo \
--chart-version=">4.0.0"
# Create a HelmRelease with a chart from a GitRepository source
flux create hr podinfo \
--interval=10m \
--source=GitRepository/podinfo \
--chart=./charts/podinfo
# Create a HelmRelease with a chart from a Bucket source
flux create hr podinfo \
--interval=10m \
--source=Bucket/podinfo \
--chart=./charts/podinfo
# Create a HelmRelease with values from a local YAML file
flux create hr podinfo \
--source=HelmRepository/podinfo \
--chart=podinfo \
--values=./my-values.yaml
# Create a HelmRelease with values from a Kubernetes secret
kubectl -n app create secret generic my-secret-values \
--from-file=values.yaml=/path/to/my-secret-values.yaml
flux -n app create hr podinfo \
--source=HelmRepository/podinfo \
--chart=podinfo \
--values-from=Secret/my-secret-values
# Create a HelmRelease with a custom release name
flux create hr podinfo \
--release-name=podinfo-dev
--source=HelmRepository/podinfo \
--chart=podinfo \
# Create a HelmRelease targeting another namespace than the resource
flux create hr podinfo \
--target-namespace=default \
--source=HelmRepository/podinfo \
--chart=podinfo
# Create a HelmRelease definition on disk without applying it on the cluster
flux create hr podinfo \
--source=HelmRepository/podinfo \
--chart=podinfo \
--values=./values.yaml \
--export > podinfo-release.yaml
`,
RunE: createHelmReleaseCmdRun,
}
var (
hrName string
hrSource flags.HelmChartSource
hrDependsOn []string
hrChart string
hrChartVersion string
hrTargetNamespace string
hrValuesFile string
hrValuesFrom flags.HelmReleaseValuesFrom
hrSAName string
)
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())
createCmd.AddCommand(createHelmReleaseCmd)
}
func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("HelmRelease name is required")
}
name := args[0]
if hrChart == "" {
return fmt.Errorf("chart name or path is required")
}
sourceLabels, err := parseLabels()
if err != nil {
return err
}
if !export {
logger.Generatef("generating HelmRelease")
}
helmRelease := helmv2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: sourceLabels,
},
Spec: helmv2.HelmReleaseSpec{
ReleaseName: hrName,
DependsOn: utils.MakeDependsOn(hrDependsOn),
Interval: metav1.Duration{
Duration: interval,
},
TargetNamespace: hrTargetNamespace,
Chart: helmv2.HelmChartTemplate{
Spec: helmv2.HelmChartTemplateSpec{
Chart: hrChart,
Version: hrChartVersion,
SourceRef: helmv2.CrossNamespaceObjectReference{
Kind: hrSource.Kind,
Name: hrSource.Name,
},
},
},
Suspend: false,
},
}
if hrSAName != "" {
helmRelease.Spec.ServiceAccountName = hrSAName
}
if hrValuesFile != "" {
data, err := ioutil.ReadFile(hrValuesFile)
if err != nil {
return fmt.Errorf("reading values from %s failed: %w", hrValuesFile, err)
}
json, err := yaml.YAMLToJSON(data)
if err != nil {
return fmt.Errorf("converting values to JSON from %s failed: %w", hrValuesFile, err)
}
helmRelease.Spec.Values = &apiextensionsv1.JSON{Raw: json}
}
if hrValuesFrom.String() != "" {
helmRelease.Spec.ValuesFrom = []helmv2.ValuesReference{{
Kind: hrValuesFrom.Kind,
Name: hrValuesFrom.Name,
}}
}
if export {
return exportHelmRelease(helmRelease)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
logger.Actionf("applying HelmRelease")
namespacedName, err := upsertHelmRelease(ctx, kubeClient, &helmRelease)
if err != nil {
return err
}
logger.Waitingf("waiting for HelmRelease reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isHelmReleaseReady(ctx, kubeClient, namespacedName, &helmRelease)); err != nil {
return err
}
logger.Successf("HelmRelease %s is ready", name)
logger.Successf("applied revision %s", helmRelease.Status.LastAppliedRevision)
return nil
}
func upsertHelmRelease(ctx context.Context, kubeClient client.Client,
helmRelease *helmv2.HelmRelease) (types.NamespacedName, error) {
namespacedName := types.NamespacedName{
Namespace: helmRelease.GetNamespace(),
Name: helmRelease.GetName(),
}
var existing helmv2.HelmRelease
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, helmRelease); err != nil {
return namespacedName, err
} else {
logger.Successf("HelmRelease created")
return namespacedName, nil
}
}
return namespacedName, err
}
existing.Labels = helmRelease.Labels
existing.Spec = helmRelease.Spec
if err := kubeClient.Update(ctx, &existing); err != nil {
return namespacedName, err
}
helmRelease = &existing
logger.Successf("HelmRelease updated")
return namespacedName, nil
}
func isHelmReleaseReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, helmRelease *helmv2.HelmRelease) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, helmRelease)
if err != nil {
return false, err
}
// Confirm the state we are observing is for the current generation
if helmRelease.Generation != helmRelease.Status.ObservedGeneration {
return false, nil
}
return apimeta.IsStatusConditionTrue(helmRelease.Status.Conditions, meta.ReadyCondition), nil
}
}

View File

@@ -0,0 +1,287 @@
/*
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 (
"context"
"fmt"
"strings"
"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"
"k8s.io/apimachinery/pkg/types"
"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"
)
var createKsCmd = &cobra.Command{
Use: "kustomization [name]",
Aliases: []string{"ks"},
Short: "Create or update a Kustomization resource",
Long: "The kustomization source create command generates a Kustomize resource for a given source.",
Example: ` # Create a Kustomization resource from a source at a given path
flux create kustomization contour \
--source=contour \
--path="./examples/contour/" \
--prune=true \
--interval=10m \
--validation=client \
--health-check="Deployment/contour.projectcontour" \
--health-check="DaemonSet/envoy.projectcontour" \
--health-check-timeout=3m
# Create a Kustomization resource that depends on the previous one
flux create kustomization webapp \
--depends-on=contour \
--source=webapp \
--path="./deploy/overlays/dev" \
--prune=true \
--interval=5m \
--validation=client
# Create a Kustomization resource that references a Bucket
flux create kustomization secrets \
--source=Bucket/secrets \
--prune=true \
--interval=5m
`,
RunE: createKsCmdRun,
}
var (
ksSource flags.KustomizationSource
ksPath string
ksPrune bool
ksDependsOn []string
ksValidation string
ksHealthCheck []string
ksHealthTimeout time.Duration
ksSAName string
ksDecryptionProvider flags.DecryptionProvider
ksDecryptionSecret string
ksTargetNamespace string
)
func init() {
createKsCmd.Flags().Var(&ksSource, "source", ksSource.Description())
createKsCmd.Flags().StringVar(&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")
createCmd.AddCommand(createKsCmd)
}
func createKsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Kustomization name is required")
}
name := args[0]
if ksPath == "" {
return fmt.Errorf("path is required")
}
if !strings.HasPrefix(ksPath, "./") {
return fmt.Errorf("path must begin with ./")
}
if !export {
logger.Generatef("generating Kustomization")
}
ksLabels, err := parseLabels()
if err != nil {
return err
}
kustomization := kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: ksLabels,
},
Spec: kustomizev1.KustomizationSpec{
DependsOn: utils.MakeDependsOn(ksDependsOn),
Interval: metav1.Duration{
Duration: interval,
},
Path: ksPath,
Prune: ksPrune,
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Kind: ksSource.Kind,
Name: ksSource.Name,
},
Suspend: false,
Validation: ksValidation,
TargetNamespace: ksTargetNamespace,
},
}
if len(ksHealthCheck) > 0 {
healthChecks := make([]kustomizev1.CrossNamespaceObjectReference, 0)
for _, w := range ksHealthCheck {
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)
}
kind := kindObj[0]
//TODO: (stefan) extend this list with all the kstatus builtin kinds
kinds := map[string]bool{
"Deployment": true,
"DaemonSet": true,
"StatefulSet": true,
helmv2.HelmReleaseKind: true,
}
if !kinds[kind] {
return fmt.Errorf("invalid health check kind '%s' can be HelmRelease, Deployment, DaemonSet or StatefulSet", kind)
}
nameNs := strings.Split(kindObj[1], ".")
if len(nameNs) != 2 {
return fmt.Errorf("invalid health check '%s' must be in the format 'kind/name.namespace'", w)
}
check := kustomizev1.CrossNamespaceObjectReference{
Kind: kind,
Name: nameNs[0],
Namespace: nameNs[1],
}
if kind == helmv2.HelmReleaseKind {
check.APIVersion = helmv2.GroupVersion.String()
}
healthChecks = append(healthChecks, check)
}
kustomization.Spec.HealthChecks = healthChecks
kustomization.Spec.Timeout = &metav1.Duration{
Duration: ksHealthTimeout,
}
}
if ksSAName != "" {
kustomization.Spec.ServiceAccountName = ksSAName
}
if ksDecryptionProvider != "" {
kustomization.Spec.Decryption = &kustomizev1.Decryption{
Provider: ksDecryptionProvider.String(),
}
if ksDecryptionSecret != "" {
kustomization.Spec.Decryption.SecretRef = &corev1.LocalObjectReference{Name: ksDecryptionSecret}
}
}
if export {
return exportKs(kustomization)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
logger.Actionf("applying Kustomization")
namespacedName, err := upsertKustomization(ctx, kubeClient, &kustomization)
if err != nil {
return err
}
logger.Waitingf("waiting for Kustomization reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isKustomizationReady(ctx, kubeClient, namespacedName, &kustomization)); err != nil {
return err
}
logger.Successf("Kustomization %s is ready", name)
logger.Successf("applied revision %s", kustomization.Status.LastAppliedRevision)
return nil
}
func upsertKustomization(ctx context.Context, kubeClient client.Client,
kustomization *kustomizev1.Kustomization) (types.NamespacedName, error) {
namespacedName := types.NamespacedName{
Namespace: kustomization.GetNamespace(),
Name: kustomization.GetName(),
}
var existing kustomizev1.Kustomization
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, kustomization); err != nil {
return namespacedName, err
} else {
logger.Successf("Kustomization created")
return namespacedName, nil
}
}
return namespacedName, err
}
existing.Labels = kustomization.Labels
existing.Spec = kustomization.Spec
if err := kubeClient.Update(ctx, &existing); err != nil {
return namespacedName, err
}
kustomization = &existing
logger.Successf("Kustomization updated")
return namespacedName, nil
}
func isKustomizationReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, kustomization *kustomizev1.Kustomization) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, kustomization)
if err != nil {
return false, err
}
// Confirm the state we are observing is for the current generation
if kustomization.Generation != kustomization.Status.ObservedGeneration {
return false, nil
}
if c := apimeta.FindStatusCondition(kustomization.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
return false, fmt.Errorf(c.Message)
}
}
return false, nil
}
}

203
cmd/flux/create_receiver.go Normal file
View File

@@ -0,0 +1,203 @@
/*
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 (
"context"
"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"
"k8s.io/apimachinery/pkg/types"
"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"
)
var createReceiverCmd = &cobra.Command{
Use: "receiver [name]",
Short: "Create or update a Receiver resource",
Long: "The create receiver command generates a Receiver resource.",
Example: ` # Create a Receiver
flux create receiver github-receiver \
--type github \
--event ping \
--event push \
--secret-ref webhook-token \
--resource GitRepository/webapp \
--resource HelmRepository/webapp
`,
RunE: createReceiverCmdRun,
}
var (
rcvType string
rcvSecretRef string
rcvEvents []string
rcvResources []string
)
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{}, "")
createCmd.AddCommand(createReceiverCmd)
}
func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Receiver name is required")
}
name := args[0]
if rcvType == "" {
return fmt.Errorf("Receiver type is required")
}
if rcvSecretRef == "" {
return fmt.Errorf("secret ref is required")
}
resources := []notificationv1.CrossNamespaceObjectReference{}
for _, resource := range rcvResources {
kind, name := utils.ParseObjectKindName(resource)
if kind == "" {
return fmt.Errorf("invalid event source '%s', must be in format <kind>/<name>", resource)
}
resources = append(resources, notificationv1.CrossNamespaceObjectReference{
Kind: kind,
Name: name,
})
}
if len(resources) == 0 {
return fmt.Errorf("atleast one resource is required")
}
sourceLabels, err := parseLabels()
if err != nil {
return err
}
if !export {
logger.Generatef("generating Receiver")
}
receiver := notificationv1.Receiver{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: sourceLabels,
},
Spec: notificationv1.ReceiverSpec{
Type: rcvType,
Events: rcvEvents,
Resources: resources,
SecretRef: corev1.LocalObjectReference{
Name: rcvSecretRef,
},
Suspend: false,
},
}
if export {
return exportReceiver(receiver)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
logger.Actionf("applying Receiver")
namespacedName, err := upsertReceiver(ctx, kubeClient, &receiver)
if err != nil {
return err
}
logger.Waitingf("waiting for Receiver reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isReceiverReady(ctx, kubeClient, namespacedName, &receiver)); err != nil {
return err
}
logger.Successf("Receiver %s is ready", name)
logger.Successf("generated webhook URL %s", receiver.Status.URL)
return nil
}
func upsertReceiver(ctx context.Context, kubeClient client.Client,
receiver *notificationv1.Receiver) (types.NamespacedName, error) {
namespacedName := types.NamespacedName{
Namespace: receiver.GetNamespace(),
Name: receiver.GetName(),
}
var existing notificationv1.Receiver
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, receiver); err != nil {
return namespacedName, err
} else {
logger.Successf("Receiver created")
return namespacedName, nil
}
}
return namespacedName, err
}
existing.Labels = receiver.Labels
existing.Spec = receiver.Spec
if err := kubeClient.Update(ctx, &existing); err != nil {
return namespacedName, err
}
receiver = &existing
logger.Successf("Receiver updated")
return namespacedName, nil
}
func isReceiverReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, receiver *notificationv1.Receiver) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, receiver)
if err != nil {
return false, err
}
if c := apimeta.FindStatusCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
return false, fmt.Errorf(c.Message)
}
}
return false, nil
}
}

52
cmd/flux/create_secret.go Normal file
View File

@@ -0,0 +1,52 @@
/*
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 (
"fmt"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)
var createSecretCmd = &cobra.Command{
Use: "secret",
Short: "Create or update Kubernetes secrets",
Long: "The create source sub-commands generate Kubernetes secrets specific to Flux.",
}
func init() {
createCmd.AddCommand(createSecretCmd)
}
func exportSecret(secret corev1.Secret) error {
secret.TypeMeta = metav1.TypeMeta{
APIVersion: "v1",
Kind: "Secret",
}
data, err := yaml.Marshal(secret)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
return nil
}

View File

@@ -0,0 +1,173 @@
/*
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 (
"context"
"crypto/elliptic"
"fmt"
"net/url"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
)
var createSecretGitCmd = &cobra.Command{
Use: "git [name]",
Short: "Create or update a Kubernetes secret for Git authentication",
Long: `
The create secret git command generates a Kubernetes secret with Git credentials.
For Git over SSH, the host and SSH keys are automatically generated and stored in the secret.
For Git over HTTP/S, the provided basic authentication credentials are stored in the secret.`,
Example: ` # Create a Git SSH authentication secret using an ECDSA P-521 curve public key
flux create secret git podinfo-auth \
--url=ssh://git@github.com/stefanprodan/podinfo \
--ssh-key-algorithm=ecdsa \
--ssh-ecdsa-curve=p521
# Create a secret for a Git repository using basic authentication
flux create secret git podinfo-auth \
--url=https://github.com/stefanprodan/podinfo \
--username=username \
--password=password
# 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
yq read podinfo-auth.yaml 'data."identity.pub"' | base64 --decode
# Create a Git SSH secret on disk and encrypt it with Mozilla SOPS
flux create secret git podinfo-auth \
--namespace=apps \
--url=ssh://git@github.com/stefanprodan/podinfo \
--export > podinfo-auth.yaml
sops --encrypt --encrypted-regex '^(data|stringData)$' \
--in-place podinfo-auth.yaml
`,
RunE: createSecretGitCmdRun,
}
var (
secretGitURL string
secretGitUsername string
secretGitPassword string
secretGitKeyAlgorithm flags.PublicKeyAlgorithm = "rsa"
secretGitRSABits flags.RSAKeyBits = 2048
secretGitECDSACurve = flags.ECDSACurve{Curve: elliptic.P384()}
)
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())
createSecretCmd.AddCommand(createSecretGitCmd)
}
func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("secret name is required")
}
name := args[0]
if secretGitURL == "" {
return fmt.Errorf("url is required")
}
u, err := url.Parse(secretGitURL)
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
secretLabels, err := parseLabels()
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: secretLabels,
},
}
switch u.Scheme {
case "ssh":
pair, err := generateKeyPair(ctx)
if err != nil {
return err
}
hostKey, err := scanHostKey(ctx, u)
if err != nil {
return err
}
secret.Data = map[string][]byte{
"identity": pair.PrivateKey,
"identity.pub": pair.PublicKey,
"known_hosts": hostKey,
}
if !export {
logger.Generatef("deploy key: %s", string(pair.PublicKey))
}
case "http", "https":
if sourceGitUsername == "" || sourceGitPassword == "" {
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),
}
default:
return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme)
}
if export {
return exportSecret(secret)
}
kubeClient, err := utils.KubeClient(kubeconfig, 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, namespace)
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.

View File

@@ -0,0 +1,228 @@
/*
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 (
"context"
"fmt"
"io/ioutil"
"os"
"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"
"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"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
)
var createSourceBucketCmd = &cobra.Command{
Use: "bucket [name]",
Short: "Create or update a Bucket source",
Long: `
The create source bucket command generates a Bucket resource and waits for it to be downloaded.
For Buckets with static authentication, the credentials are stored in a Kubernetes secret.`,
Example: ` # Create a source from a Buckets using static authentication
flux create source bucket podinfo \
--bucket-name=podinfo \
--endpoint=minio.minio.svc.cluster.local:9000 \
--insecure=true \
--access-key=myaccesskey \
--secret-key=mysecretkey \
--interval=10m
# Create a source from an Amazon S3 Bucket using IAM authentication
flux create source bucket podinfo \
--bucket-name=podinfo \
--provider=aws \
--endpoint=s3.amazonaws.com \
--region=us-east-1 \
--interval=10m
`,
RunE: createSourceBucketCmdRun,
}
var (
sourceBucketName string
sourceBucketProvider = flags.SourceBucketProvider(sourcev1.GenericBucketProvider)
sourceBucketEndpoint string
sourceBucketAccessKey string
sourceBucketSecretKey string
sourceBucketRegion string
sourceBucketInsecure bool
sourceBucketSecretRef string
)
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")
createSourceCmd.AddCommand(createSourceBucketCmd)
}
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 == "" {
return fmt.Errorf("bucket-name is required")
}
if sourceBucketEndpoint == "" {
return fmt.Errorf("endpoint is required")
}
sourceLabels, err := parseLabels()
if err != nil {
return err
}
tmpDir, err := ioutil.TempDir("", name)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
bucket := &sourcev1.Bucket{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: sourceLabels,
},
Spec: sourcev1.BucketSpec{
BucketName: sourceBucketName,
Provider: sourceBucketProvider.String(),
Insecure: sourceBucketInsecure,
Endpoint: sourceBucketEndpoint,
Region: sourceBucketRegion,
Interval: metav1.Duration{
Duration: interval,
},
},
}
if sourceHelmSecretRef != "" {
bucket.Spec.SecretRef = &corev1.LocalObjectReference{
Name: sourceBucketSecretRef,
}
}
if export {
return exportBucket(*bucket)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
logger.Generatef("generating Bucket source")
if sourceBucketSecretRef == "" {
secretName := fmt.Sprintf("bucket-%s", name)
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
Labels: sourceLabels,
},
StringData: map[string]string{},
}
if sourceBucketAccessKey != "" && sourceBucketSecretKey != "" {
secret.StringData["accesskey"] = sourceBucketAccessKey
secret.StringData["secretkey"] = sourceBucketSecretKey
}
if len(secret.StringData) > 0 {
logger.Actionf("applying secret with the bucket credentials")
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err
}
bucket.Spec.SecretRef = &corev1.LocalObjectReference{
Name: secretName,
}
logger.Successf("authentication configured")
}
}
logger.Actionf("applying Bucket source")
namespacedName, err := upsertBucket(ctx, kubeClient, bucket)
if err != nil {
return err
}
logger.Waitingf("waiting for Bucket source reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isBucketReady(ctx, kubeClient, namespacedName, bucket)); err != nil {
return err
}
logger.Successf("Bucket source reconciliation completed")
if bucket.Status.Artifact == nil {
return fmt.Errorf("Bucket source reconciliation but no artifact was found")
}
logger.Successf("fetched revision: %s", bucket.Status.Artifact.Revision)
return nil
}
func upsertBucket(ctx context.Context, kubeClient client.Client,
bucket *sourcev1.Bucket) (types.NamespacedName, error) {
namespacedName := types.NamespacedName{
Namespace: bucket.GetNamespace(),
Name: bucket.GetName(),
}
var existing sourcev1.Bucket
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, bucket); err != nil {
return namespacedName, err
} else {
logger.Successf("Bucket source created")
return namespacedName, nil
}
}
return namespacedName, err
}
existing.Labels = bucket.Labels
existing.Spec = bucket.Spec
if err := kubeClient.Update(ctx, &existing); err != nil {
return namespacedName, err
}
bucket = &existing
logger.Successf("Bucket source updated")
return namespacedName, nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -25,11 +25,16 @@ import (
"os"
"time"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"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"
"k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
@@ -46,35 +51,35 @@ The create source git command generates a GitRepository resource and waits for i
For Git over SSH, host and SSH keys are automatically generated and stored in a Kubernetes secret.
For private Git repositories, the basic authentication credentials are stored in a Kubernetes secret.`,
Example: ` # Create a source from a public Git repository master branch
create source git podinfo \
flux create source git podinfo \
--url=https://github.com/stefanprodan/podinfo \
--branch=master
# Create a source from a Git repository pinned to specific git tag
create source git podinfo \
flux create source git podinfo \
--url=https://github.com/stefanprodan/podinfo \
--tag="3.2.3"
# Create a source from a public Git repository tag that matches a semver range
create source git podinfo \
flux create source git podinfo \
--url=https://github.com/stefanprodan/podinfo \
--tag-semver=">=3.2.0 <3.3.0"
# Create a source from a Git repository using SSH authentication
create source git podinfo \
flux create source git podinfo \
--url=ssh://git@github.com/stefanprodan/podinfo \
--branch=master
# Create a source from a Git repository using SSH authentication and an
# ECDSA P-521 curve public key
create source git podinfo \
flux create source git podinfo \
--url=ssh://git@github.com/stefanprodan/podinfo \
--branch=master \
--ssh-key-algorithm=ecdsa \
--ssh-ecdsa-curve=p521
# Create a source from a Git repository using basic authentication
create source git podinfo \
flux create source git podinfo \
--url=https://github.com/stefanprodan/podinfo \
--username=username \
--password=password
@@ -83,15 +88,17 @@ For private Git repositories, the basic authentication credentials are stored in
}
var (
sourceGitURL string
sourceGitBranch string
sourceGitTag string
sourceGitSemver string
sourceGitUsername string
sourceGitPassword string
sourceGitKeyAlgorithm PublicKeyAlgorithm = "rsa"
sourceGitRSABits RSAKeyBits = 2048
sourceGitECDSACurve = ECDSACurve{elliptic.P384()}
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
)
func init() {
@@ -104,18 +111,19 @@ func init() {
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")
createSourceCmd.AddCommand(createSourceGitCmd)
}
func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("source name is required")
return fmt.Errorf("GitRepository source name is required")
}
name := args[0]
if sourceGitURL == "" {
return fmt.Errorf("git-url is required")
return fmt.Errorf("url is required")
}
tmpDir, err := ioutil.TempDir("", name)
@@ -129,10 +137,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("git URL parse failed: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.kubeClient(kubeconfig)
sourceLabels, err := parseLabels()
if err != nil {
return err
}
@@ -141,6 +146,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: sourceLabels,
},
Spec: sourcev1.GitRepositorySpec{
URL: sourceGitURL,
@@ -160,12 +166,27 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
}
if export {
if sourceGitSecretRef != "" {
gitRepository.Spec.SecretRef = &corev1.LocalObjectReference{
Name: sourceGitSecretRef,
}
}
return exportGit(gitRepository)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
withAuth := false
// TODO(hidde): move all auth prep to separate func?
if u.Scheme == "ssh" {
if sourceGitSecretRef != "" {
withAuth = true
} else if u.Scheme == "ssh" {
logger.Actionf("generating deploy key pair")
pair, err := generateKeyPair(ctx)
if err != nil {
@@ -194,6 +215,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: sourceLabels,
},
StringData: map[string]string{
"identity": string(pair.PrivateKey),
@@ -211,6 +233,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: sourceLabels,
},
StringData: map[string]string{
"username": sourceGitUsername,
@@ -227,42 +250,35 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("authentication configured")
}
logger.Generatef("generating source")
logger.Generatef("generating GitRepository source")
if withAuth {
secretName := name
if sourceGitSecretRef != "" {
secretName = sourceGitSecretRef
}
gitRepository.Spec.SecretRef = &corev1.LocalObjectReference{
Name: name,
Name: secretName,
}
}
logger.Actionf("applying source")
if err := upsertGitRepository(ctx, kubeClient, gitRepository); err != nil {
return err
}
logger.Waitingf("waiting for git sync")
if err := wait.PollImmediate(pollInterval, timeout,
isGitRepositoryReady(ctx, kubeClient, name, namespace)); err != nil {
return err
}
logger.Successf("git sync completed")
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err = kubeClient.Get(ctx, namespacedName, &gitRepository)
logger.Actionf("applying GitRepository source")
namespacedName, err := upsertGitRepository(ctx, kubeClient, &gitRepository)
if err != nil {
return fmt.Errorf("git sync failed: %w", err)
return err
}
if gitRepository.Status.Artifact != nil {
logger.Successf("fetched revision: %s", gitRepository.Status.Artifact.Revision)
} else {
return fmt.Errorf("git sync failed, artifact not found")
logger.Waitingf("waiting for GitRepository source reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isGitRepositoryReady(ctx, kubeClient, namespacedName, &gitRepository)); err != nil {
return err
}
logger.Successf("GitRepository source reconciliation completed")
if gitRepository.Status.Artifact == nil {
return fmt.Errorf("GitRepository source reconciliation completed but no artifact was found")
}
logger.Successf("fetched revision: %s", gitRepository.Status.Artifact.Revision)
return nil
}
@@ -323,7 +339,8 @@ func upsertSecret(ctx context.Context, kubeClient client.Client, secret corev1.S
return nil
}
func upsertGitRepository(ctx context.Context, kubeClient client.Client, gitRepository sourcev1.GitRepository) error {
func upsertGitRepository(ctx context.Context, kubeClient client.Client,
gitRepository *sourcev1.GitRepository) (types.NamespacedName, error) {
namespacedName := types.NamespacedName{
Namespace: gitRepository.GetNamespace(),
Name: gitRepository.GetName(),
@@ -333,45 +350,40 @@ func upsertGitRepository(ctx context.Context, kubeClient client.Client, gitRepos
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, &gitRepository); err != nil {
return err
if err := kubeClient.Create(ctx, gitRepository); err != nil {
return namespacedName, err
} else {
logger.Successf("source created")
return nil
logger.Successf("GitRepository source created")
return namespacedName, nil
}
}
return err
return namespacedName, err
}
existing.Labels = gitRepository.Labels
existing.Spec = gitRepository.Spec
if err := kubeClient.Update(ctx, &existing); err != nil {
return err
return namespacedName, err
}
logger.Successf("source updated")
return nil
gitRepository = &existing
logger.Successf("GitRepository source updated")
return namespacedName, nil
}
func isGitRepositoryReady(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc {
func isGitRepositoryReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, gitRepository *sourcev1.GitRepository) wait.ConditionFunc {
return func() (bool, error) {
var gitRepository sourcev1.GitRepository
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err := kubeClient.Get(ctx, namespacedName, &gitRepository)
err := kubeClient.Get(ctx, namespacedName, gitRepository)
if err != nil {
return false, err
}
for _, condition := range gitRepository.Status.Conditions {
if condition.Type == sourcev1.ReadyCondition {
if condition.Status == corev1.ConditionTrue {
return true, nil
} else if condition.Status == corev1.ConditionFalse {
return false, fmt.Errorf(condition.Message)
}
if c := apimeta.FindStatusCondition(gitRepository.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
return false, fmt.Errorf(c.Message)
}
}
return false, nil

View File

@@ -0,0 +1,272 @@
/*
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 (
"context"
"fmt"
"io/ioutil"
"net/url"
"os"
"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"
"k8s.io/apimachinery/pkg/types"
"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"
)
var createSourceHelmCmd = &cobra.Command{
Use: "helm [name]",
Short: "Create or update a HelmRepository source",
Long: `
The create source helm command generates a HelmRepository resource and waits for it to fetch the index.
For private Helm repositories, the basic authentication credentials are stored in a Kubernetes secret.`,
Example: ` # Create a source from a public Helm repository
flux create source helm podinfo \
--url=https://stefanprodan.github.io/podinfo \
--interval=10m
# Create a source from a Helm repository using basic authentication
flux create source helm podinfo \
--url=https://stefanprodan.github.io/podinfo \
--username=username \
--password=password
# Create a source from a Helm repository using TLS authentication
flux create source helm podinfo \
--url=https://stefanprodan.github.io/podinfo \
--cert-file=./cert.crt \
--key-file=./key.crt \
--ca-file=./ca.crt
`,
RunE: createSourceHelmCmdRun,
}
var (
sourceHelmURL string
sourceHelmUsername string
sourceHelmPassword string
sourceHelmCertFile string
sourceHelmKeyFile string
sourceHelmCAFile string
sourceHelmSecretRef string
)
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")
createSourceCmd.AddCommand(createSourceHelmCmd)
}
func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("HelmRepository source name is required")
}
name := args[0]
if sourceHelmURL == "" {
return fmt.Errorf("url is required")
}
sourceLabels, err := parseLabels()
if err != nil {
return err
}
tmpDir, err := ioutil.TempDir("", name)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
if _, err := url.Parse(sourceHelmURL); err != nil {
return fmt.Errorf("url parse failed: %w", err)
}
helmRepository := &sourcev1.HelmRepository{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: sourceLabels,
},
Spec: sourcev1.HelmRepositorySpec{
URL: sourceHelmURL,
Interval: metav1.Duration{
Duration: interval,
},
},
}
if sourceHelmSecretRef != "" {
helmRepository.Spec.SecretRef = &corev1.LocalObjectReference{
Name: sourceHelmSecretRef,
}
}
if export {
return exportHelmRepository(*helmRepository)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
logger.Generatef("generating HelmRepository source")
if sourceHelmSecretRef == "" {
secretName := fmt.Sprintf("helm-%s", name)
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
Labels: sourceLabels,
},
StringData: map[string]string{},
}
if sourceHelmUsername != "" && sourceHelmPassword != "" {
secret.StringData["username"] = sourceHelmUsername
secret.StringData["password"] = sourceHelmPassword
}
if sourceHelmCertFile != "" && sourceHelmKeyFile != "" {
cert, err := ioutil.ReadFile(sourceHelmCertFile)
if err != nil {
return fmt.Errorf("failed to read repository cert file '%s': %w", sourceHelmCertFile, err)
}
secret.StringData["certFile"] = string(cert)
key, err := ioutil.ReadFile(sourceHelmKeyFile)
if err != nil {
return fmt.Errorf("failed to read repository key file '%s': %w", sourceHelmKeyFile, err)
}
secret.StringData["keyFile"] = string(key)
}
if sourceHelmCAFile != "" {
ca, err := ioutil.ReadFile(sourceHelmCAFile)
if err != nil {
return fmt.Errorf("failed to read repository CA file '%s': %w", sourceHelmCAFile, err)
}
secret.StringData["caFile"] = string(ca)
}
if len(secret.StringData) > 0 {
logger.Actionf("applying secret with repository credentials")
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err
}
helmRepository.Spec.SecretRef = &corev1.LocalObjectReference{
Name: secretName,
}
logger.Successf("authentication configured")
}
}
logger.Actionf("applying HelmRepository source")
namespacedName, err := upsertHelmRepository(ctx, kubeClient, helmRepository)
if err != nil {
return err
}
logger.Waitingf("waiting for HelmRepository source reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isHelmRepositoryReady(ctx, kubeClient, namespacedName, helmRepository)); err != nil {
return err
}
logger.Successf("HelmRepository source reconciliation completed")
if helmRepository.Status.Artifact == nil {
return fmt.Errorf("HelmRepository source reconciliation completed but no artifact was found")
}
logger.Successf("fetched revision: %s", helmRepository.Status.Artifact.Revision)
return nil
}
func upsertHelmRepository(ctx context.Context, kubeClient client.Client,
helmRepository *sourcev1.HelmRepository) (types.NamespacedName, error) {
namespacedName := types.NamespacedName{
Namespace: helmRepository.GetNamespace(),
Name: helmRepository.GetName(),
}
var existing sourcev1.HelmRepository
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, helmRepository); err != nil {
return namespacedName, err
} else {
logger.Successf("source created")
return namespacedName, nil
}
}
return namespacedName, err
}
existing.Labels = helmRepository.Labels
existing.Spec = helmRepository.Spec
if err := kubeClient.Update(ctx, &existing); err != nil {
return namespacedName, err
}
helmRepository = &existing
logger.Successf("source updated")
return namespacedName, nil
}
func isHelmRepositoryReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, helmRepository *sourcev1.HelmRepository) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, helmRepository)
if err != nil {
return false, err
}
// Confirm the state we are observing is for the current generation
if helmRepository.Generation != helmRepository.Status.ObservedGeneration {
return false, nil
}
if c := apimeta.FindStatusCondition(helmRepository.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
return false, fmt.Errorf(c.Message)
}
}
return false, nil
}
}

319
cmd/flux/create_tenant.go Normal file
View File

@@ -0,0 +1,319 @@
/*
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 (
"bytes"
"context"
"fmt"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
)
var createTenantCmd = &cobra.Command{
Use: "tenant",
Short: "Create or update a tenant",
Long: `
The create tenant command generates namespaces, service accounts and role bindings to limit the
reconcilers scope to the tenant namespaces.`,
Example: ` # Create a tenant with access to a namespace
flux create tenant dev-team \
--with-namespace=frontend \
--label=environment=dev
# Generate tenant namespaces and role bindings in YAML format
flux create tenant dev-team \
--with-namespace=frontend \
--with-namespace=backend \
--export > dev-team.yaml
`,
RunE: createTenantCmdRun,
}
const (
tenantLabel = "toolkit.fluxcd.io/tenant"
)
var (
tenantNamespaces []string
tenantClusterRole string
)
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")
createCmd.AddCommand(createTenantCmd)
}
func createTenantCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("tenant name is required")
}
tenant := args[0]
if err := validation.IsQualifiedName(tenant); len(err) > 0 {
return fmt.Errorf("invalid tenant name '%s': %v", tenant, err)
}
if tenantClusterRole == "" {
return fmt.Errorf("cluster-role is required")
}
if tenantNamespaces == nil {
return fmt.Errorf("with-namespace is required")
}
var namespaces []corev1.Namespace
var accounts []corev1.ServiceAccount
var roleBindings []rbacv1.RoleBinding
for _, ns := range tenantNamespaces {
if err := validation.IsQualifiedName(ns); len(err) > 0 {
return fmt.Errorf("invalid namespace '%s': %v", ns, err)
}
objLabels, err := parseLabels()
if err != nil {
return err
}
objLabels[tenantLabel] = tenant
namespace := corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: ns,
Labels: objLabels,
},
}
namespaces = append(namespaces, namespace)
account := corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: tenant,
Namespace: ns,
Labels: objLabels,
},
}
accounts = append(accounts, account)
roleBinding := rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-reconciler", tenant),
Namespace: ns,
Labels: objLabels,
},
Subjects: []rbacv1.Subject{
{
APIGroup: "rbac.authorization.k8s.io",
Kind: "User",
Name: fmt.Sprintf("gotk:%s:reconciler", ns),
},
{
Kind: "ServiceAccount",
Name: tenant,
Namespace: ns,
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: tenantClusterRole,
},
}
roleBindings = append(roleBindings, roleBinding)
}
if export {
for i, _ := range tenantNamespaces {
if err := exportTenant(namespaces[i], accounts[i], roleBindings[i]); err != nil {
return err
}
}
return nil
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
for i, _ := range tenantNamespaces {
logger.Actionf("applying namespace %s", namespaces[i].Name)
if err := upsertNamespace(ctx, kubeClient, namespaces[i]); err != nil {
return err
}
logger.Actionf("applying service account %s", accounts[i].Name)
if err := upsertServiceAccount(ctx, kubeClient, accounts[i]); err != nil {
return err
}
logger.Actionf("applying role binding %s", roleBindings[i].Name)
if err := upsertRoleBinding(ctx, kubeClient, roleBindings[i]); err != nil {
return err
}
}
logger.Successf("tenant setup completed")
return nil
}
func upsertNamespace(ctx context.Context, kubeClient client.Client, namespace corev1.Namespace) error {
namespacedName := types.NamespacedName{
Namespace: namespace.GetNamespace(),
Name: namespace.GetName(),
}
var existing corev1.Namespace
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, &namespace); err != nil {
return err
} else {
return nil
}
}
return err
}
if !equality.Semantic.DeepDerivative(namespace.Labels, existing.Labels) {
existing.Labels = namespace.Labels
if err := kubeClient.Update(ctx, &existing); err != nil {
return err
}
}
return nil
}
func upsertServiceAccount(ctx context.Context, kubeClient client.Client, account corev1.ServiceAccount) error {
namespacedName := types.NamespacedName{
Namespace: account.GetNamespace(),
Name: account.GetName(),
}
var existing corev1.ServiceAccount
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, &account); err != nil {
return err
} else {
return nil
}
}
return err
}
if !equality.Semantic.DeepDerivative(account.Labels, existing.Labels) {
existing.Labels = account.Labels
if err := kubeClient.Update(ctx, &existing); err != nil {
return err
}
}
return nil
}
func upsertRoleBinding(ctx context.Context, kubeClient client.Client, roleBinding rbacv1.RoleBinding) error {
namespacedName := types.NamespacedName{
Namespace: roleBinding.GetNamespace(),
Name: roleBinding.GetName(),
}
var existing rbacv1.RoleBinding
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, &roleBinding); err != nil {
return err
} else {
return nil
}
}
return err
}
if !equality.Semantic.DeepDerivative(roleBinding.Subjects, existing.Subjects) ||
!equality.Semantic.DeepDerivative(roleBinding.RoleRef, existing.RoleRef) ||
!equality.Semantic.DeepDerivative(roleBinding.Labels, existing.Labels) {
if err := kubeClient.Delete(ctx, &existing); err != nil {
return err
}
if err := kubeClient.Create(ctx, &roleBinding); err != nil {
return err
}
}
return nil
}
func exportTenant(namespace corev1.Namespace, account corev1.ServiceAccount, roleBinding rbacv1.RoleBinding) error {
namespace.TypeMeta = metav1.TypeMeta{
APIVersion: "v1",
Kind: "Namespace",
}
data, err := yaml.Marshal(namespace)
if err != nil {
return err
}
fmt.Println("---")
data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1)
fmt.Println(resourceToString(data))
account.TypeMeta = metav1.TypeMeta{
APIVersion: "v1",
Kind: "ServiceAccount",
}
data, err = yaml.Marshal(account)
if err != nil {
return err
}
fmt.Println("---")
data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1)
fmt.Println(resourceToString(data))
roleBinding.TypeMeta = metav1.TypeMeta{
APIVersion: "rbac.authorization.k8s.io/v1",
Kind: "RoleBinding",
}
data, err = yaml.Marshal(roleBinding)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.

88
cmd/flux/delete_alert.go Normal file
View File

@@ -0,0 +1,88 @@
/*
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 (
"context"
"fmt"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/flux2/internal/utils"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
)
var deleteAlertCmd = &cobra.Command{
Use: "alert [name]",
Short: "Delete a Alert resource",
Long: "The delete alert command removes the given Alert from the cluster.",
Example: ` # Delete an Alert and the Kubernetes resources created by it
flux delete alert main
`,
RunE: deleteAlertCmdRun,
}
func init() {
deleteCmd.AddCommand(deleteAlertCmd)
}
func deleteAlertCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("alert name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var alert notificationv1.Alert
err = kubeClient.Get(ctx, namespacedName, &alert)
if err != nil {
return err
}
if !deleteSilent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this Alert",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting alert %s in %s namespace", name, namespace)
err = kubeClient.Delete(ctx, &alert)
if err != nil {
return err
}
logger.Successf("alert deleted")
return nil
}

View File

@@ -0,0 +1,88 @@
/*
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 (
"context"
"fmt"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/flux2/internal/utils"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
)
var deleteAlertProviderCmd = &cobra.Command{
Use: "alert-provider [name]",
Short: "Delete a Provider resource",
Long: "The delete alert-provider command removes the given Provider from the cluster.",
Example: ` # Delete a Provider and the Kubernetes resources created by it
flux delete alert-provider slack
`,
RunE: deleteAlertProviderCmdRun,
}
func init() {
deleteCmd.AddCommand(deleteAlertProviderCmd)
}
func deleteAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("provider name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var alertProvider notificationv1.Provider
err = kubeClient.Get(ctx, namespacedName, &alertProvider)
if err != nil {
return err
}
if !deleteSilent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this Provider",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting provider %s in %s namespace", name, namespace)
err = kubeClient.Delete(ctx, &alertProvider)
if err != nil {
return err
}
logger.Successf("provider deleted")
return nil
}

View File

@@ -0,0 +1,92 @@
/*
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 (
"context"
"fmt"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/flux2/internal/utils"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
)
var deleteHelmReleaseCmd = &cobra.Command{
Use: "helmrelease [name]",
Aliases: []string{"hr"},
Short: "Delete a HelmRelease resource",
Long: "The delete helmrelease command removes the given HelmRelease from the cluster.",
Example: ` # Delete a Helm release and the Kubernetes resources created by it
flux delete hr podinfo
`,
RunE: deleteHelmReleaseCmdRun,
}
func init() {
deleteCmd.AddCommand(deleteHelmReleaseCmd)
}
func deleteHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("release name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
if !deleteSilent {
if !helmRelease.Spec.Suspend {
logger.Waitingf("This action will remove the Kubernetes objects previously applied by the %s Helm release!", name)
}
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this Helm release",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting release %s in %s namespace", name, namespace)
err = kubeClient.Delete(ctx, &helmRelease)
if err != nil {
return err
}
logger.Successf("release deleted")
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -20,7 +20,8 @@ import (
"context"
"fmt"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
"github.com/fluxcd/flux2/internal/utils"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
@@ -31,7 +32,10 @@ var deleteKsCmd = &cobra.Command{
Aliases: []string{"ks"},
Short: "Delete a Kustomization resource",
Long: "The delete kustomization command deletes the given Kustomization from the cluster.",
RunE: deleteKsCmdRun,
Example: ` # Delete a kustomization and the Kubernetes resources created by it
flux delete kustomization podinfo
`,
RunE: deleteKsCmdRun,
}
func init() {
@@ -47,7 +51,7 @@ func deleteKsCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.kubeClient(kubeconfig)
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}

View File

@@ -0,0 +1,88 @@
/*
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 (
"context"
"fmt"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/flux2/internal/utils"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
)
var deleteReceiverCmd = &cobra.Command{
Use: "receiver [name]",
Short: "Delete a Receiver resource",
Long: "The delete receiver command removes the given Receiver from the cluster.",
Example: ` # Delete an Receiver and the Kubernetes resources created by it
flux delete receiver main
`,
RunE: deleteReceiverCmdRun,
}
func init() {
deleteCmd.AddCommand(deleteReceiverCmd)
}
func deleteReceiverCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("receiver name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var receiver notificationv1.Receiver
err = kubeClient.Get(ctx, namespacedName, &receiver)
if err != nil {
return err
}
if !deleteSilent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this Receiver",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting receiver %s in %s namespace", name, namespace)
err = kubeClient.Delete(ctx, &receiver)
if err != nil {
return err
}
logger.Successf("receiver deleted")
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.

View File

@@ -0,0 +1,87 @@
/*
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 (
"context"
"fmt"
"github.com/fluxcd/flux2/internal/utils"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var deleteSourceBucketCmd = &cobra.Command{
Use: "bucket [name]",
Short: "Delete a Bucket source",
Long: "The delete source bucket command deletes the given Bucket from the cluster.",
Example: ` # Delete a Bucket source
flux delete source bucket podinfo
`,
RunE: deleteSourceBucketCmdRun,
}
func init() {
deleteSourceCmd.AddCommand(deleteSourceBucketCmd)
}
func deleteSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var bucket sourcev1.Bucket
err = kubeClient.Get(ctx, namespacedName, &bucket)
if err != nil {
return err
}
if !deleteSilent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this source",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting source %s in %s namespace", name, namespace)
err = kubeClient.Delete(ctx, &bucket)
if err != nil {
return err
}
logger.Successf("source deleted")
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -20,7 +20,8 @@ import (
"context"
"fmt"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"github.com/fluxcd/flux2/internal/utils"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
@@ -30,7 +31,10 @@ var deleteSourceGitCmd = &cobra.Command{
Use: "git [name]",
Short: "Delete a GitRepository source",
Long: "The delete source git command deletes the given GitRepository from the cluster.",
RunE: deleteSourceGitCmdRun,
Example: ` # Delete a Git repository
flux delete source git podinfo
`,
RunE: deleteSourceGitCmdRun,
}
func init() {
@@ -46,7 +50,7 @@ func deleteSourceGitCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.kubeClient(kubeconfig)
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}

View File

@@ -0,0 +1,87 @@
/*
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 (
"context"
"fmt"
"github.com/fluxcd/flux2/internal/utils"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var deleteSourceHelmCmd = &cobra.Command{
Use: "helm [name]",
Short: "Delete a HelmRepository source",
Long: "The delete source helm command deletes the given HelmRepository from the cluster.",
Example: ` # Delete a Helm repository
flux delete source helm podinfo
`,
RunE: deleteSourceHelmCmdRun,
}
func init() {
deleteSourceCmd.AddCommand(deleteSourceHelmCmd)
}
func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var helmRepository sourcev1.HelmRepository
err = kubeClient.Get(ctx, namespacedName, &helmRepository)
if err != nil {
return err
}
if !deleteSilent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this source",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting source %s in %s namespace", name, namespace)
err = kubeClient.Delete(ctx, &helmRepository)
if err != nil {
return err
}
logger.Successf("source deleted")
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -17,6 +17,8 @@ limitations under the License.
package main
import (
"bytes"
"github.com/spf13/cobra"
)
@@ -35,3 +37,9 @@ func init() {
rootCmd.AddCommand(exportCmd)
}
func resourceToString(data []byte) string {
data = bytes.Replace(data, []byte(" creationTimestamp: null\n"), []byte(""), 1)
data = bytes.Replace(data, []byte("status: {}\n"), []byte(""), 1)
return string(data)
}

120
cmd/flux/export_alert.go Normal file
View File

@@ -0,0 +1,120 @@
/*
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 (
"context"
"fmt"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/utils"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
)
var exportAlertCmd = &cobra.Command{
Use: "alert [name]",
Short: "Export Alert resources in YAML format",
Long: "The export alert command exports one or all Alert resources in YAML format.",
Example: ` # Export all Alert resources
flux export alert --all > alerts.yaml
# Export a Alert
flux export alert main > main.yaml
`,
RunE: exportAlertCmdRun,
}
func init() {
exportCmd.AddCommand(exportAlertCmd)
}
func exportAlertCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
if exportAll {
var list notificationv1.AlertList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no alerts found in %s namespace", namespace)
return nil
}
for _, alert := range list.Items {
if err := exportAlert(alert); err != nil {
return err
}
}
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var alert notificationv1.Alert
err = kubeClient.Get(ctx, namespacedName, &alert)
if err != nil {
return err
}
return exportAlert(alert)
}
return nil
}
func exportAlert(alert notificationv1.Alert) error {
gvk := notificationv1.GroupVersion.WithKind("Alert")
export := notificationv1.Alert{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: alert.Name,
Namespace: alert.Namespace,
Labels: alert.Labels,
Annotations: alert.Annotations,
},
Spec: alert.Spec,
}
data, err := yaml.Marshal(export)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
return nil
}

View File

@@ -0,0 +1,120 @@
/*
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 (
"context"
"fmt"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/utils"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
)
var exportAlertProviderCmd = &cobra.Command{
Use: "alert-provider [name]",
Short: "Export Provider resources in YAML format",
Long: "The export alert-provider command exports one or all Provider resources in YAML format.",
Example: ` # Export all Provider resources
flux export alert-provider --all > alert-providers.yaml
# Export a Provider
flux export alert-provider slack > slack.yaml
`,
RunE: exportAlertProviderCmdRun,
}
func init() {
exportCmd.AddCommand(exportAlertProviderCmd)
}
func exportAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
if exportAll {
var list notificationv1.ProviderList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no alertproviders found in %s namespace", namespace)
return nil
}
for _, alertProvider := range list.Items {
if err := exportAlertProvider(alertProvider); err != nil {
return err
}
}
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var alertProvider notificationv1.Provider
err = kubeClient.Get(ctx, namespacedName, &alertProvider)
if err != nil {
return err
}
return exportAlertProvider(alertProvider)
}
return nil
}
func exportAlertProvider(alertProvider notificationv1.Provider) error {
gvk := notificationv1.GroupVersion.WithKind("Provider")
export := notificationv1.Provider{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: alertProvider.Name,
Namespace: alertProvider.Namespace,
Labels: alertProvider.Labels,
Annotations: alertProvider.Annotations,
},
Spec: alertProvider.Spec,
}
data, err := yaml.Marshal(export)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
return nil
}

View File

@@ -0,0 +1,121 @@
/*
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 (
"context"
"fmt"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/utils"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
)
var exportHelmReleaseCmd = &cobra.Command{
Use: "helmrelease [name]",
Aliases: []string{"hr"},
Short: "Export HelmRelease resources in YAML format",
Long: "The export helmrelease command exports one or all HelmRelease resources in YAML format.",
Example: ` # Export all HelmRelease resources
flux export helmrelease --all > kustomizations.yaml
# Export a HelmRelease
flux export hr my-app > app-release.yaml
`,
RunE: exportHelmReleaseCmdRun,
}
func init() {
exportCmd.AddCommand(exportHelmReleaseCmd)
}
func exportHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
if exportAll {
var list helmv2.HelmReleaseList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no helmrelease found in %s namespace", namespace)
return nil
}
for _, helmRelease := range list.Items {
if err := exportHelmRelease(helmRelease); err != nil {
return err
}
}
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
return exportHelmRelease(helmRelease)
}
return nil
}
func exportHelmRelease(helmRelease helmv2.HelmRelease) error {
gvk := helmv2.GroupVersion.WithKind(helmv2.HelmReleaseKind)
export := helmv2.HelmRelease{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: helmRelease.Name,
Namespace: helmRelease.Namespace,
Labels: helmRelease.Labels,
Annotations: helmRelease.Annotations,
},
Spec: helmRelease.Spec,
}
data, err := yaml.Marshal(export)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -20,12 +20,14 @@ import (
"context"
"fmt"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/utils"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
)
var exportKsCmd = &cobra.Command{
@@ -34,10 +36,10 @@ var exportKsCmd = &cobra.Command{
Short: "Export Kustomization resources in YAML format",
Long: "The export kustomization command exports one or all Kustomization resources in YAML format.",
Example: ` # Export all Kustomization resources
export kustomization --all > kustomizations.yaml
flux export kustomization --all > kustomizations.yaml
# Export a Kustomization
export kustomization my-app > kustomization.yaml
flux export kustomization my-app > kustomization.yaml
`,
RunE: exportKsCmdRun,
}
@@ -54,7 +56,7 @@ func exportKsCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.kubeClient(kubeconfig)
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
@@ -100,8 +102,10 @@ func exportKs(kustomization kustomizev1.Kustomization) error {
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: kustomization.Name,
Namespace: kustomization.Namespace,
Name: kustomization.Name,
Namespace: kustomization.Namespace,
Labels: kustomization.Labels,
Annotations: kustomization.Annotations,
},
Spec: kustomization.Spec,
}
@@ -112,6 +116,6 @@ func exportKs(kustomization kustomizev1.Kustomization) error {
}
fmt.Println("---")
fmt.Println(string(data))
fmt.Println(resourceToString(data))
return nil
}

120
cmd/flux/export_receiver.go Normal file
View File

@@ -0,0 +1,120 @@
/*
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 (
"context"
"fmt"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/utils"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
)
var exportReceiverCmd = &cobra.Command{
Use: "receiver [name]",
Short: "Export Receiver resources in YAML format",
Long: "The export receiver command exports one or all Receiver resources in YAML format.",
Example: ` # Export all Receiver resources
flux export receiver --all > receivers.yaml
# Export a Receiver
flux export receiver main > main.yaml
`,
RunE: exportReceiverCmdRun,
}
func init() {
exportCmd.AddCommand(exportReceiverCmd)
}
func exportReceiverCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
if exportAll {
var list notificationv1.ReceiverList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no receivers found in %s namespace", namespace)
return nil
}
for _, receiver := range list.Items {
if err := exportReceiver(receiver); err != nil {
return err
}
}
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var receiver notificationv1.Receiver
err = kubeClient.Get(ctx, namespacedName, &receiver)
if err != nil {
return err
}
return exportReceiver(receiver)
}
return nil
}
func exportReceiver(receiver notificationv1.Receiver) error {
gvk := notificationv1.GroupVersion.WithKind("Receiver")
export := notificationv1.Receiver{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: receiver.Name,
Namespace: receiver.Namespace,
Labels: receiver.Labels,
Annotations: receiver.Annotations,
},
Spec: receiver.Spec,
}
data, err := yaml.Marshal(export)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.

View File

@@ -0,0 +1,167 @@
/*
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 (
"context"
"fmt"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/utils"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
)
var exportSourceBucketCmd = &cobra.Command{
Use: "bucket [name]",
Short: "Export Bucket sources in YAML format",
Long: "The export source git command exports on or all Bucket sources in YAML format.",
Example: ` # Export all Bucket sources
flux export source bucket --all > sources.yaml
# Export a Bucket source including the static credentials
flux export source bucket my-bucket --with-credentials > source.yaml
`,
RunE: exportSourceBucketCmdRun,
}
func init() {
exportSourceCmd.AddCommand(exportSourceBucketCmd)
}
func exportSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
if exportAll {
var list sourcev1.BucketList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no source found in %s namespace", namespace)
return nil
}
for _, bucket := range list.Items {
if err := exportBucket(bucket); err != nil {
return err
}
if exportSourceWithCred {
if err := exportBucketCredentials(ctx, kubeClient, bucket); err != nil {
return err
}
}
}
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var bucket sourcev1.Bucket
err = kubeClient.Get(ctx, namespacedName, &bucket)
if err != nil {
return err
}
if err := exportBucket(bucket); err != nil {
return err
}
if exportSourceWithCred {
return exportBucketCredentials(ctx, kubeClient, bucket)
}
}
return nil
}
func exportBucket(source sourcev1.Bucket) error {
gvk := sourcev1.GroupVersion.WithKind(sourcev1.BucketKind)
export := sourcev1.Bucket{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: source.Name,
Namespace: source.Namespace,
Labels: source.Labels,
Annotations: source.Annotations,
},
Spec: source.Spec,
}
data, err := yaml.Marshal(export)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
return nil
}
func exportBucketCredentials(ctx context.Context, kubeClient client.Client, source sourcev1.Bucket) error {
if source.Spec.SecretRef != nil {
namespacedName := types.NamespacedName{
Namespace: source.Namespace,
Name: source.Spec.SecretRef.Name,
}
var cred corev1.Secret
err := kubeClient.Get(ctx, namespacedName, &cred)
if err != nil {
return fmt.Errorf("failed to retrieve secret %s, error: %w", namespacedName.Name, err)
}
exported := corev1.Secret{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Secret",
},
ObjectMeta: metav1.ObjectMeta{
Name: namespacedName.Name,
Namespace: namespacedName.Namespace,
},
Data: cred.Data,
Type: cred.Type,
}
data, err := yaml.Marshal(exported)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
}
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -20,13 +20,15 @@ import (
"context"
"fmt"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/utils"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
)
var exportSourceGitCmd = &cobra.Command{
@@ -34,10 +36,10 @@ var exportSourceGitCmd = &cobra.Command{
Short: "Export GitRepository sources in YAML format",
Long: "The export source git command exports on or all GitRepository sources in YAML format.",
Example: ` # Export all GitRepository sources
export source git --all > sources.yaml
flux export source git --all > sources.yaml
# Export a GitRepository source including the SSH key pair or basic auth credentials
export source git my-private-repo --with-credentials > source.yaml
flux export source git my-private-repo --with-credentials > source.yaml
`,
RunE: exportSourceGitCmdRun,
}
@@ -48,13 +50,13 @@ func init() {
func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("kustomization name is required")
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.kubeClient(kubeconfig)
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
@@ -103,15 +105,17 @@ func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
}
func exportGit(source sourcev1.GitRepository) error {
gvk := sourcev1.GroupVersion.WithKind("GitRepository")
gvk := sourcev1.GroupVersion.WithKind(sourcev1.GitRepositoryKind)
export := sourcev1.GitRepository{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: source.Name,
Namespace: source.Namespace,
Name: source.Name,
Namespace: source.Namespace,
Labels: source.Labels,
Annotations: source.Annotations,
},
Spec: source.Spec,
}
@@ -122,7 +126,7 @@ func exportGit(source sourcev1.GitRepository) error {
}
fmt.Println("---")
fmt.Println(string(data))
fmt.Println(resourceToString(data))
return nil
}
@@ -157,7 +161,7 @@ func exportGitCredentials(ctx context.Context, kubeClient client.Client, source
}
fmt.Println("---")
fmt.Println(string(data))
fmt.Println(resourceToString(data))
}
return nil
}

View File

@@ -0,0 +1,167 @@
/*
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 (
"context"
"fmt"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/utils"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
)
var exportSourceHelmCmd = &cobra.Command{
Use: "helm [name]",
Short: "Export HelmRepository sources in YAML format",
Long: "The export source git command exports on or all HelmRepository sources in YAML format.",
Example: ` # Export all HelmRepository sources
flux export source helm --all > sources.yaml
# Export a HelmRepository source including the basic auth credentials
flux export source helm my-private-repo --with-credentials > source.yaml
`,
RunE: exportSourceHelmCmdRun,
}
func init() {
exportSourceCmd.AddCommand(exportSourceHelmCmd)
}
func exportSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
if exportAll {
var list sourcev1.HelmRepositoryList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no source found in %s namespace", namespace)
return nil
}
for _, repository := range list.Items {
if err := exportHelmRepository(repository); err != nil {
return err
}
if exportSourceWithCred {
if err := exportHelmCredentials(ctx, kubeClient, repository); err != nil {
return err
}
}
}
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var repository sourcev1.HelmRepository
err = kubeClient.Get(ctx, namespacedName, &repository)
if err != nil {
return err
}
if err := exportHelmRepository(repository); err != nil {
return err
}
if exportSourceWithCred {
return exportHelmCredentials(ctx, kubeClient, repository)
}
}
return nil
}
func exportHelmRepository(source sourcev1.HelmRepository) error {
gvk := sourcev1.GroupVersion.WithKind(sourcev1.HelmRepositoryKind)
export := sourcev1.HelmRepository{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: source.Name,
Namespace: source.Namespace,
Labels: source.Labels,
Annotations: source.Annotations,
},
Spec: source.Spec,
}
data, err := yaml.Marshal(export)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
return nil
}
func exportHelmCredentials(ctx context.Context, kubeClient client.Client, source sourcev1.HelmRepository) error {
if source.Spec.SecretRef != nil {
namespacedName := types.NamespacedName{
Namespace: source.Namespace,
Name: source.Spec.SecretRef.Name,
}
var cred corev1.Secret
err := kubeClient.Get(ctx, namespacedName, &cred)
if err != nil {
return fmt.Errorf("failed to retrieve secret %s, error: %w", namespacedName.Name, err)
}
exported := corev1.Secret{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Secret",
},
ObjectMeta: metav1.ObjectMeta{
Name: namespacedName.Name,
Namespace: namespacedName.Namespace,
},
Data: cred.Data,
Type: cred.Type,
}
data, err := yaml.Marshal(exported)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
}
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -26,6 +26,10 @@ var getCmd = &cobra.Command{
Long: "The get sub-commands print the statuses of sources and resources.",
}
var allNamespaces bool
func init() {
getCmd.PersistentFlags().BoolVarP(&allNamespaces, "all-namespaces", "A", false,
"list the requested object(s) across all namespaces")
rootCmd.AddCommand(getCmd)
}

102
cmd/flux/get_alert.go Normal file
View File

@@ -0,0 +1,102 @@
/*
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 (
"context"
"os"
"strconv"
"strings"
"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"
"github.com/fluxcd/flux2/internal/utils"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
"github.com/fluxcd/pkg/apis/meta"
)
var getAlertCmd = &cobra.Command{
Use: "alerts",
Short: "Get Alert statuses",
Long: "The get alert command prints the statuses of the resources.",
Example: ` # List all Alerts and their status
flux get alerts
`,
RunE: getAlertCmdRun,
}
func init() {
getCmd.AddCommand(getAlertCmd)
}
func getAlertCmdRun(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 notificationv1.AlertList
err = kubeClient.List(ctx, &list, listOpts...)
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no alerts found in %s namespace", namespace)
return nil
}
header := []string{"Name", "Ready", "Message", "Suspended"}
if allNamespaces {
header = append([]string{"Namespace"}, header...)
}
var rows [][]string
for _, alert := range list.Items {
row := []string{}
if c := apimeta.FindStatusCondition(alert.Status.Conditions, meta.ReadyCondition); c != nil {
row = []string{
alert.GetName(),
string(c.Status),
c.Message,
strings.Title(strconv.FormatBool(alert.Spec.Suspend)),
}
} else {
row = []string{
alert.GetName(),
string(metav1.ConditionFalse),
"waiting to be reconciled",
strings.Title(strconv.FormatBool(alert.Spec.Suspend)),
}
}
if allNamespaces {
row = append([]string{alert.Namespace}, row...)
}
rows = append(rows, row)
}
utils.PrintTable(os.Stdout, header, rows)
return nil
}

View File

@@ -0,0 +1,98 @@
/*
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 (
"context"
"os"
"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"
"github.com/fluxcd/flux2/internal/utils"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
"github.com/fluxcd/pkg/apis/meta"
)
var getAlertProviderCmd = &cobra.Command{
Use: "alert-providers",
Short: "Get Provider statuses",
Long: "The get alert-provider command prints the statuses of the resources.",
Example: ` # List all Providers and their status
flux get alert-providers
`,
RunE: getAlertProviderCmdRun,
}
func init() {
getCmd.AddCommand(getAlertProviderCmd)
}
func getAlertProviderCmdRun(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 notificationv1.ProviderList
err = kubeClient.List(ctx, &list, listOpts...)
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no providers found in %s namespace", namespace)
return nil
}
header := []string{"Name", "Ready", "Message"}
if allNamespaces {
header = append([]string{"Namespace"}, header...)
}
var rows [][]string
for _, provider := range list.Items {
row := []string{}
if c := apimeta.FindStatusCondition(provider.Status.Conditions, meta.ReadyCondition); c != nil {
row = []string{
provider.GetName(),
string(c.Status),
c.Message,
}
} else {
row = []string{
provider.GetName(),
string(metav1.ConditionFalse),
"waiting to be reconciled",
}
}
if allNamespaces {
row = append([]string{provider.Namespace}, row...)
}
rows = append(rows, row)
}
utils.PrintTable(os.Stdout, header, rows)
return nil
}

106
cmd/flux/get_helmrelease.go Normal file
View File

@@ -0,0 +1,106 @@
/*
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 (
"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"
)
var getHelmReleaseCmd = &cobra.Command{
Use: "helmreleases",
Aliases: []string{"hr"},
Short: "Get HelmRelease statuses",
Long: "The get helmreleases command prints the statuses of the resources.",
Example: ` # List all Helm releases and their status
flux get helmreleases
`,
RunE: getHelmReleaseCmdRun,
}
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
}

View File

@@ -0,0 +1,105 @@
/*
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 (
"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{
Use: "kustomizations",
Aliases: []string{"ks"},
Short: "Get Kustomization statuses",
Long: "The get kustomizations command prints the statuses of the resources.",
Example: ` # List all kustomizations and their status
flux get kustomizations
`,
RunE: getKsCmdRun,
}
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
}

99
cmd/flux/get_receiver.go Normal file
View File

@@ -0,0 +1,99 @@
/*
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 (
"context"
"os"
"strconv"
"strings"
"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"
"github.com/fluxcd/flux2/internal/utils"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
"github.com/fluxcd/pkg/apis/meta"
)
var getReceiverCmd = &cobra.Command{
Use: "receivers",
Short: "Get Receiver statuses",
Long: "The get receiver command prints the statuses of the resources.",
Example: ` # List all Receiver and their status
flux get receivers
`,
RunE: getReceiverCmdRun,
}
func init() {
getCmd.AddCommand(getReceiverCmd)
}
func getReceiverCmdRun(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 notificationv1.ReceiverList
err = kubeClient.List(ctx, &list, listOpts...)
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no receivers found in %s namespace", namespace)
return nil
}
header := []string{"Name", "Ready", "Message", "Suspended"}
if allNamespaces {
header = append([]string{"Namespace"}, header...)
}
var rows [][]string
for _, receiver := range list.Items {
row := []string{}
if c := apimeta.FindStatusCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil {
row = []string{
receiver.GetName(),
string(c.Status),
c.Message,
strings.Title(strconv.FormatBool(receiver.Spec.Suspend)),
}
} else {
row = []string{
receiver.GetName(),
string(metav1.ConditionFalse),
"waiting to be reconciled",
strings.Title(strconv.FormatBool(receiver.Spec.Suspend)),
}
}
rows = append(rows, row)
}
utils.PrintTable(os.Stdout, header, rows)
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.

View File

@@ -0,0 +1,111 @@
/*
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 (
"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 getSourceBucketCmd = &cobra.Command{
Use: "bucket",
Short: "Get Bucket source statuses",
Long: "The get sources bucket command prints the status of the Bucket sources.",
Example: ` # List all Buckets and their status
flux get sources bucket
# List buckets from all namespaces
flux get sources helm --all-namespaces
`,
RunE: getSourceBucketCmdRun,
}
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
}
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
}

View File

@@ -0,0 +1,111 @@
/*
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 (
"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{
Use: "chart",
Short: "Get HelmChart statuses",
Long: "The get sources chart command prints the status of the HelmCharts.",
Example: ` # List all Helm charts and their status
flux get sources chart
# List Helm charts from all namespaces
flux get sources chart --all-namespaces
`,
RunE: getSourceHelmChartCmdRun,
}
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
}
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
}

111
cmd/flux/get_source_git.go Normal file
View File

@@ -0,0 +1,111 @@
/*
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 (
"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{
Use: "git",
Short: "Get GitRepository source statuses",
Long: "The get sources git command prints the status of the GitRepository sources.",
Example: ` # List all Git repositories and their status
flux get sources git
# List Git repositories from all namespaces
flux get sources git --all-namespaces
`,
RunE: getSourceGitCmdRun,
}
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
}
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
}

111
cmd/flux/get_source_helm.go Normal file
View File

@@ -0,0 +1,111 @@
/*
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 (
"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{
Use: "helm",
Short: "Get HelmRepository source statuses",
Long: "The get sources helm command prints the status of the HelmRepository sources.",
Example: ` # List all Helm repositories and their status
flux get sources helm
# List Helm repositories from all namespaces
flux get sources helm --all-namespaces
`,
RunE: getSourceHelmCmdRun,
}
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
}
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
}

181
cmd/flux/install.go Normal file
View File

@@ -0,0 +1,181 @@
/*
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 (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/spf13/cobra"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/install"
)
var installCmd = &cobra.Command{
Use: "install",
Short: "Install the toolkit components",
Long: `The install command deploys the toolkit components in the specified namespace.
If a previous version is installed, then an in-place upgrade will be performed.`,
Example: ` # Install the latest version in the flux-system namespace
flux install --version=latest --namespace=flux-system
# Dry-run install for a specific version and a series of components
flux install --dry-run --version=v0.0.7 --components="source-controller,kustomize-controller"
# Dry-run install with manifests preview
flux install --dry-run --verbose
# Write install manifests to file
flux install --export > flux-system.yaml
`,
RunE: installCmdRun,
}
var (
installExport bool
installDryRun bool
installManifestsPath string
installVersion string
installComponents []string
installRegistry string
installImagePullSecret string
installWatchAllNamespaces bool
installNetworkPolicy bool
installArch = flags.Arch(defaults.Arch)
installLogLevel = flags.LogLevel(defaults.LogLevel)
)
func init() {
installCmd.Flags().BoolVar(&installExport, "export", false,
"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,
"toolkit version")
installCmd.Flags().StringSliceVar(&installComponents, "components", defaults.Components,
"list of components, 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,
"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,
"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,
"deny ingress access to the toolkit controllers from other namespaces using network policies")
rootCmd.AddCommand(installCmd)
}
func installCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
tmpDir, err := ioutil.TempDir("", namespace)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
if !installExport {
logger.Generatef("generating manifests")
}
opts := install.Options{
BaseURL: installManifestsPath,
Version: installVersion,
Namespace: namespace,
Components: installComponents,
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,
}
if installManifestsPath == "" {
opts.BaseURL = install.MakeDefaultOptions().BaseURL
}
manifest, err := install.Generate(opts)
if err != nil {
return fmt.Errorf("install failed: %w", err)
}
if _, err := manifest.WriteFile(tmpDir); err != nil {
return fmt.Errorf("install failed: %w", err)
}
if verbose {
fmt.Print(manifest.Content)
} else if installExport {
fmt.Println("---")
fmt.Println("# GitOps Toolkit revision", installVersion)
fmt.Println("# Components:", strings.Join(installComponents, ","))
fmt.Print(manifest.Content)
fmt.Println("---")
return nil
}
logger.Successf("manifests build completed")
logger.Actionf("installing components in %s namespace", namespace)
applyOutput := utils.ModeStderrOS
if verbose {
applyOutput = utils.ModeOS
}
kubectlArgs := []string{"apply", "-f", filepath.Join(tmpDir, manifest.Path)}
if installDryRun {
kubectlArgs = append(kubectlArgs, "--dry-run=client")
applyOutput = utils.ModeOS
}
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, kubeconfig, kubecontext, kubectlArgs...); err != nil {
return fmt.Errorf("install failed")
}
if installDryRun {
logger.Successf("install dry-run finished")
return nil
} else {
logger.Successf("install completed")
}
logger.Waitingf("verifying installation")
for _, deployment := range installComponents {
kubectlArgs = []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, kubeconfig, kubecontext, kubectlArgs...); err != nil {
return fmt.Errorf("install failed")
} else {
logger.Successf("%s ready", deployment)
}
}
logger.Successf("install finished")
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -26,96 +26,90 @@ import (
"github.com/spf13/cobra/doc"
_ "k8s.io/client-go/plugin/pkg/client/auth"
tklog "github.com/fluxcd/toolkit/pkg/log"
fluxlog "github.com/fluxcd/flux2/pkg/log"
"github.com/fluxcd/flux2/pkg/manifestgen/install"
)
var VERSION = "0.0.0-dev.0"
var rootCmd = &cobra.Command{
Use: "tk",
Use: "flux",
Version: VERSION,
SilenceUsage: true,
SilenceErrors: true,
Short: "Command line utility for assembling Kubernetes CD pipelines",
Long: `Command line utility for assembling Kubernetes CD pipelines the GitOps way.`,
Example: ` # Check prerequisites
tk check --pre
Example: ` # Check prerequisites
flux check --pre
# Install the latest version of the toolkit
tk install --version=master
flux install --version=master
# Create a source from a public Git repository
tk create source git webapp-latest \
flux create source git webapp-latest \
--url=https://github.com/stefanprodan/podinfo \
--branch=master \
--interval=3m
# List GitRepository sources and their status
tk get sources git
flux get sources git
# Trigger a GitRepository source sync
tk sync source git webapp-latest
# Trigger a GitRepository source reconciliation
flux reconcile source git flux-system
# Export GitRepository sources in YAML format
tk export source git --all > sources.yaml
flux export source git --all > sources.yaml
# Create a Kustomization for deploying a series of microservices
tk create kustomization webapp-dev \
flux create kustomization webapp-dev \
--source=webapp-latest \
--path="./deploy/webapp/" \
--prune=true \
--interval=5m \
--validate=client \
--validation=client \
--health-check="Deployment/backend.webapp" \
--health-check="Deployment/frontend.webapp" \
--health-check-timeout=2m
# Trigger a git sync of the Kustomization's source and apply changes
tk reconcile kustomization webapp-dev --with-source
flux reconcile kustomization webapp-dev --with-source
# Suspend a Kustomization reconciliation
tk suspend kustomization webapp-dev
flux suspend kustomization webapp-dev
# Export Kustomizations in YAML format
tk export kustomization --all > kustomizations.yaml
flux export kustomization --all > kustomizations.yaml
# Resume a Kustomization reconciliation
tk resume kustomization webapp-dev
flux resume kustomization webapp-dev
# Delete a Kustomization
tk delete kustomization webapp-dev
flux delete kustomization webapp-dev
# Delete a GitRepository source
tk delete source git webapp-latest
flux delete source git webapp-latest
# Uninstall the toolkit and delete CRDs
tk uninstall --crds
flux uninstall --crds
`,
}
var (
kubeconfig string
kubecontext string
namespace string
timeout time.Duration
verbose bool
utils Utils
pollInterval = 2 * time.Second
logger tklog.Logger = printLogger{}
)
var (
defaultComponents = []string{"source-controller", "kustomize-controller", "helm-controller", "notification-controller"}
defaultVersion = "master"
defaultNamespace = "gitops-system"
pollInterval = 2 * time.Second
logger fluxlog.Logger = printLogger{}
defaults = install.MakeDefaultOptions()
)
func init() {
rootCmd.PersistentFlags().StringVar(&namespace, "namespace", defaultNamespace,
"the namespace scope for this operation")
rootCmd.PersistentFlags().DurationVarP(&timeout, "timeout", "", 5*time.Minute,
"timeout for this operation")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "", false,
"print generated objects")
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")
}
func main() {

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.

View File

@@ -0,0 +1,98 @@
/*
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 (
"context"
"fmt"
"time"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
)
var reconcileAlertCmd = &cobra.Command{
Use: "alert [name]",
Short: "Reconcile an Alert",
Long: `The reconcile alert command triggers a reconciliation of an Alert resource and waits for it to finish.`,
Example: ` # Trigger a reconciliation for an existing alert
flux reconcile alert main
`,
RunE: reconcileAlertCmdRun,
}
func init() {
reconcileCmd.AddCommand(reconcileAlertCmd)
}
func reconcileAlertCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Alert name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var alert notificationv1.Alert
err = kubeClient.Get(ctx, namespacedName, &alert)
if err != nil {
return err
}
if alert.Spec.Suspend {
return fmt.Errorf("resource is suspended")
}
logger.Actionf("annotating Alert %s in %s namespace", name, namespace)
if alert.Annotations == nil {
alert.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
alert.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
}
if err := kubeClient.Update(ctx, &alert); err != nil {
return err
}
logger.Successf("Alert annotated")
logger.Waitingf("waiting for reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isAlertReady(ctx, kubeClient, namespacedName, &alert)); err != nil {
return err
}
logger.Successf("Alert reconciliation completed")
return nil
}

View File

@@ -0,0 +1,93 @@
/*
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 (
"context"
"fmt"
"time"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
)
var reconcileAlertProviderCmd = &cobra.Command{
Use: "alert-provider [name]",
Short: "Reconcile a Provider",
Long: `The reconcile alert-provider command triggers a reconciliation of a Provider resource and waits for it to finish.`,
Example: ` # Trigger a reconciliation for an existing provider
flux reconcile alert-provider slack
`,
RunE: reconcileAlertProviderCmdRun,
}
func init() {
reconcileCmd.AddCommand(reconcileAlertProviderCmd)
}
func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Provider name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
logger.Actionf("annotating Provider %s in %s namespace", name, namespace)
var alertProvider notificationv1.Provider
err = kubeClient.Get(ctx, namespacedName, &alertProvider)
if err != nil {
return err
}
if alertProvider.Annotations == nil {
alertProvider.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
alertProvider.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
}
if err := kubeClient.Update(ctx, &alertProvider); err != nil {
return err
}
logger.Successf("Provider annotated")
logger.Waitingf("waiting for reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isAlertProviderReady(ctx, kubeClient, namespacedName, &alertProvider)); err != nil {
return err
}
logger.Successf("Provider reconciliation completed")
return nil
}

View File

@@ -0,0 +1,163 @@
/*
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 (
"context"
"fmt"
"time"
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
)
var reconcileHrCmd = &cobra.Command{
Use: "helmrelease [name]",
Aliases: []string{"hr"},
Short: "Reconcile a HelmRelease resource",
Long: `
The reconcile kustomization command triggers a reconciliation of a HelmRelease resource and waits for it to finish.`,
Example: ` # Trigger a HelmRelease apply outside of the reconciliation interval
flux reconcile hr podinfo
# Trigger a reconciliation of the HelmRelease's source and apply changes
flux reconcile hr podinfo --with-source
`,
RunE: reconcileHrCmdRun,
}
var (
syncHrWithSource bool
)
func init() {
reconcileHrCmd.Flags().BoolVar(&syncHrWithSource, "with-source", false, "reconcile HelmRelease source")
reconcileCmd.AddCommand(reconcileHrCmd)
}
func reconcileHrCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("HelmRelease name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
if helmRelease.Spec.Suspend {
return fmt.Errorf("resource is suspended")
}
if syncHrWithSource {
switch helmRelease.Spec.Chart.Spec.SourceRef.Kind {
case sourcev1.HelmRepositoryKind:
err = reconcileSourceHelmCmdRun(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
case sourcev1.GitRepositoryKind:
err = reconcileSourceGitCmdRun(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
case sourcev1.BucketKind:
err = reconcileSourceBucketCmdRun(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
}
if err != nil {
return err
}
}
lastHandledReconcileAt := helmRelease.Status.LastHandledReconcileAt
logger.Actionf("annotating HelmRelease %s in %s namespace", name, 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,
helmReleaseReconciliationHandled(ctx, kubeClient, namespacedName, &helmRelease, lastHandledReconcileAt),
); err != nil {
return err
}
logger.Successf("HelmRelease reconciliation completed")
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
if c := apimeta.FindStatusCondition(helmRelease.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status {
case metav1.ConditionFalse:
return fmt.Errorf("HelmRelease reconciliation failed: %s", c.Message)
default:
logger.Successf("reconciled revision %s", helmRelease.Status.LastAppliedRevision)
}
}
return nil
}
func helmReleaseReconciliationHandled(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, helmRelease *helmv2.HelmRelease, lastHandledReconcileAt string) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, helmRelease)
if err != nil {
return false, err
}
return helmRelease.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
}
}
func requestHelmReleaseReconciliation(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, helmRelease *helmv2.HelmRelease) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
if err := kubeClient.Get(ctx, namespacedName, helmRelease); err != nil {
return err
}
if helmRelease.Annotations == nil {
helmRelease.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
helmRelease.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, helmRelease)
})
}

View File

@@ -0,0 +1,152 @@
/*
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 (
"context"
"fmt"
"time"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
)
var reconcileKsCmd = &cobra.Command{
Use: "kustomization [name]",
Aliases: []string{"ks"},
Short: "Reconcile a Kustomization resource",
Long: `
The reconcile kustomization command triggers a reconciliation of a Kustomization resource and waits for it to finish.`,
Example: ` # Trigger a Kustomization apply outside of the reconciliation interval
flux reconcile kustomization podinfo
# Trigger a sync of the Kustomization's source and apply changes
flux reconcile kustomization podinfo --with-source
`,
RunE: reconcileKsCmdRun,
}
var (
syncKsWithSource bool
)
func init() {
reconcileKsCmd.Flags().BoolVar(&syncKsWithSource, "with-source", false, "reconcile Kustomization source")
reconcileCmd.AddCommand(reconcileKsCmd)
}
func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Kustomization name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var kustomization kustomizev1.Kustomization
err = kubeClient.Get(ctx, namespacedName, &kustomization)
if err != nil {
return err
}
if kustomization.Spec.Suspend {
return fmt.Errorf("resource is suspended")
}
if syncKsWithSource {
switch kustomization.Spec.SourceRef.Kind {
case sourcev1.GitRepositoryKind:
err = reconcileSourceGitCmdRun(nil, []string{kustomization.Spec.SourceRef.Name})
case sourcev1.BucketKind:
err = reconcileSourceBucketCmdRun(nil, []string{kustomization.Spec.SourceRef.Name})
}
if err != nil {
return err
}
}
lastHandledReconcileAt := kustomization.Status.LastHandledReconcileAt
logger.Actionf("annotating Kustomization %s in %s namespace", name, namespace)
if err := requestKustomizeReconciliation(ctx, kubeClient, namespacedName, &kustomization); err != nil {
return err
}
logger.Successf("Kustomization annotated")
logger.Waitingf("waiting for Kustomization reconciliation")
if err := wait.PollImmediate(
pollInterval, timeout,
kustomizeReconciliationHandled(ctx, kubeClient, namespacedName, &kustomization, lastHandledReconcileAt),
); err != nil {
return err
}
logger.Successf("Kustomization reconciliation completed")
if apimeta.IsStatusConditionFalse(kustomization.Status.Conditions, meta.ReadyCondition) {
return fmt.Errorf("Kustomization reconciliation failed")
}
logger.Successf("reconciled revision %s", kustomization.Status.LastAppliedRevision)
return nil
}
func kustomizeReconciliationHandled(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, kustomization *kustomizev1.Kustomization, lastHandledReconcileAt string) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, kustomization)
if err != nil {
return false, err
}
return kustomization.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
}
}
func requestKustomizeReconciliation(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, kustomization *kustomizev1.Kustomization) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
if err := kubeClient.Get(ctx, namespacedName, kustomization); err != nil {
return err
}
if kustomization.Annotations == nil {
kustomization.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
kustomization.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, kustomization)
})
}

View File

@@ -0,0 +1,99 @@
/*
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 (
"context"
"fmt"
"time"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
)
var reconcileReceiverCmd = &cobra.Command{
Use: "receiver [name]",
Short: "Reconcile a Receiver",
Long: `The reconcile receiver command triggers a reconciliation of a Receiver resource and waits for it to finish.`,
Example: ` # Trigger a reconciliation for an existing receiver
flux reconcile receiver main
`,
RunE: reconcileReceiverCmdRun,
}
func init() {
reconcileCmd.AddCommand(reconcileReceiverCmd)
}
func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("receiver name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var receiver notificationv1.Receiver
err = kubeClient.Get(ctx, namespacedName, &receiver)
if err != nil {
return err
}
if receiver.Spec.Suspend {
return fmt.Errorf("resource is suspended")
}
logger.Actionf("annotating Receiver %s in %s namespace", name, namespace)
if receiver.Annotations == nil {
receiver.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
receiver.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
}
if err := kubeClient.Update(ctx, &receiver); err != nil {
return err
}
logger.Successf("Receiver annotated")
logger.Waitingf("waiting for Receiver reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isReceiverReady(ctx, kubeClient, namespacedName, &receiver)); err != nil {
return err
}
logger.Successf("Receiver reconciliation completed")
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.

View File

@@ -0,0 +1,155 @@
/*
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 (
"context"
"fmt"
"time"
"github.com/fluxcd/pkg/apis/meta"
"k8s.io/client-go/util/retry"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
)
var reconcileSourceBucketCmd = &cobra.Command{
Use: "bucket [name]",
Short: "Reconcile a Bucket source",
Long: `The reconcile source command triggers a reconciliation of a Bucket resource and waits for it to finish.`,
Example: ` # Trigger a reconciliation for an existing source
flux reconcile source bucket podinfo
`,
RunE: reconcileSourceBucketCmdRun,
}
func init() {
reconcileSourceCmd.AddCommand(reconcileSourceBucketCmd)
}
func reconcileSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("source name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var bucket sourcev1.Bucket
err = kubeClient.Get(ctx, namespacedName, &bucket)
if err != nil {
return err
}
if bucket.Spec.Suspend {
return fmt.Errorf("resource is suspended")
}
lastHandledReconcileAt := bucket.Status.LastHandledReconcileAt
logger.Actionf("annotating Bucket source %s in %s namespace", name, namespace)
if err := requestBucketReconciliation(ctx, kubeClient, namespacedName, &bucket); err != nil {
return err
}
logger.Successf("Bucket source annotated")
logger.Waitingf("waiting for Bucket source reconciliation")
if err := wait.PollImmediate(
pollInterval, timeout,
bucketReconciliationHandled(ctx, kubeClient, namespacedName, &bucket, lastHandledReconcileAt),
); err != nil {
return err
}
logger.Successf("Bucket source reconciliation completed")
if apimeta.IsStatusConditionFalse(bucket.Status.Conditions, meta.ReadyCondition) {
return fmt.Errorf("Bucket source reconciliation failed")
}
logger.Successf("fetched revision %s", bucket.Status.Artifact.Revision)
return nil
}
func isBucketReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, bucket *sourcev1.Bucket) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, bucket)
if err != nil {
return false, err
}
// Confirm the state we are observing is for the current generation
if bucket.Generation != bucket.Status.ObservedGeneration {
return false, nil
}
if c := apimeta.FindStatusCondition(bucket.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
return false, fmt.Errorf(c.Message)
}
}
return false, nil
}
}
func bucketReconciliationHandled(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, bucket *sourcev1.Bucket, lastHandledReconcileAt string) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, bucket)
if err != nil {
return false, err
}
return bucket.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
}
}
func requestBucketReconciliation(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, bucket *sourcev1.Bucket) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
if err := kubeClient.Get(ctx, namespacedName, bucket); err != nil {
return err
}
if bucket.Annotations == nil {
bucket.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
bucket.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, bucket)
})
}

View File

@@ -0,0 +1,126 @@
/*
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 (
"context"
"fmt"
"time"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
)
var reconcileSourceGitCmd = &cobra.Command{
Use: "git [name]",
Short: "Reconcile a GitRepository source",
Long: `The reconcile source command triggers a reconciliation of a GitRepository resource and waits for it to finish.`,
Example: ` # Trigger a git pull for an existing source
flux reconcile source git podinfo
`,
RunE: reconcileSourceGitCmdRun,
}
func init() {
reconcileSourceCmd.AddCommand(reconcileSourceGitCmd)
}
func reconcileSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("source name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var repository sourcev1.GitRepository
err = kubeClient.Get(ctx, namespacedName, &repository)
if err != nil {
return err
}
if repository.Spec.Suspend {
return fmt.Errorf("resource is suspended")
}
logger.Actionf("annotating GitRepository source %s in %s namespace", name, namespace)
if err := requestGitRepositoryReconciliation(ctx, kubeClient, namespacedName, &repository); err != nil {
return err
}
logger.Successf("GitRepository source annotated")
lastHandledReconcileAt := repository.Status.LastHandledReconcileAt
logger.Waitingf("waiting for GitRepository source reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
gitRepositoryReconciliationHandled(ctx, kubeClient, namespacedName, &repository, lastHandledReconcileAt)); err != nil {
return err
}
logger.Successf("GitRepository source reconciliation completed")
if apimeta.IsStatusConditionFalse(repository.Status.Conditions, meta.ReadyCondition) {
return fmt.Errorf("GitRepository source reconciliation failed")
}
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
return nil
}
func gitRepositoryReconciliationHandled(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, repository *sourcev1.GitRepository, lastHandledReconcileAt string) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, repository)
if err != nil {
return false, err
}
return repository.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
}
}
func requestGitRepositoryReconciliation(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, repository *sourcev1.GitRepository) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
if err := kubeClient.Get(ctx, namespacedName, repository); err != nil {
return err
}
if repository.Annotations == nil {
repository.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
repository.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, repository)
})
}

View File

@@ -0,0 +1,127 @@
/*
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 (
"context"
"fmt"
"time"
"github.com/fluxcd/pkg/apis/meta"
"k8s.io/client-go/util/retry"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
)
var reconcileSourceHelmCmd = &cobra.Command{
Use: "helm [name]",
Short: "Reconcile a HelmRepository source",
Long: `The reconcile source command triggers a reconciliation of a HelmRepository resource and waits for it to finish.`,
Example: ` # Trigger a reconciliation for an existing source
flux reconcile source helm podinfo
`,
RunE: reconcileSourceHelmCmdRun,
}
func init() {
reconcileSourceCmd.AddCommand(reconcileSourceHelmCmd)
}
func reconcileSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("HelmRepository source name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var repository sourcev1.HelmRepository
err = kubeClient.Get(ctx, namespacedName, &repository)
if err != nil {
return err
}
if repository.Spec.Suspend {
return fmt.Errorf("resource is suspended")
}
logger.Actionf("annotating HelmRepository source %s in %s namespace", name, namespace)
if err := requestHelmRepositoryReconciliation(ctx, kubeClient, namespacedName, &repository); err != nil {
return err
}
logger.Successf("HelmRepository source annotated")
lastHandledReconcileAt := repository.Status.LastHandledReconcileAt
logger.Waitingf("waiting for HelmRepository source reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
helmRepositoryReconciliationHandled(ctx, kubeClient, namespacedName, &repository, lastHandledReconcileAt)); err != nil {
return err
}
logger.Successf("HelmRepository source reconciliation completed")
if apimeta.IsStatusConditionFalse(repository.Status.Conditions, meta.ReadyCondition) {
return fmt.Errorf("HelmRepository source reconciliation failed")
}
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
return nil
}
func helmRepositoryReconciliationHandled(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, repository *sourcev1.HelmRepository, lastHandledReconcileAt string) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, repository)
if err != nil {
return false, err
}
return repository.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
}
}
func requestHelmRepositoryReconciliation(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, repository *sourcev1.HelmRepository) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
if err := kubeClient.Get(ctx, namespacedName, repository); err != nil {
return err
}
if repository.Annotations == nil {
repository.Annotations = map[string]string{
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
repository.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, repository)
})
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.

112
cmd/flux/resume_alert.go Normal file
View File

@@ -0,0 +1,112 @@
/*
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 (
"context"
"fmt"
"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"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
)
var resumeAlertCmd = &cobra.Command{
Use: "alert [name]",
Short: "Resume a suspended Alert",
Long: `The resume command marks a previously suspended Alert resource for reconciliation and waits for it to
finish the apply.`,
Example: ` # Resume reconciliation for an existing Alert
flux resume alert main
`,
RunE: resumeAlertCmdRun,
}
func init() {
resumeCmd.AddCommand(resumeAlertCmd)
}
func resumeAlertCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Alert name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var alert notificationv1.Alert
err = kubeClient.Get(ctx, namespacedName, &alert)
if err != nil {
return err
}
logger.Actionf("resuming Alert %s in %s namespace", name, namespace)
alert.Spec.Suspend = false
if err := kubeClient.Update(ctx, &alert); err != nil {
return err
}
logger.Successf("Alert resumed")
logger.Waitingf("waiting for Alert reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isAlertResumed(ctx, kubeClient, namespacedName, &alert)); err != nil {
return err
}
logger.Successf("Alert reconciliation completed")
return nil
}
func isAlertResumed(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, alert *notificationv1.Alert) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, alert)
if err != nil {
return false, err
}
if c := apimeta.FindStatusCondition(alert.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
if c.Reason == meta.SuspendedReason {
return false, nil
}
return false, fmt.Errorf(c.Message)
}
}
return false, nil
}
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -20,13 +20,17 @@ 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"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
)
var resumeHrCmd = &cobra.Command{
@@ -35,6 +39,9 @@ var resumeHrCmd = &cobra.Command{
Short: "Resume a suspended HelmRelease",
Long: `The resume command marks a previously suspended HelmRelease resource for reconciliation and waits for it to
finish the apply.`,
Example: ` # Resume reconciliation for an existing Helm release
flux resume hr podinfo
`,
RunE: resumeHrCmdRun,
}
@@ -51,7 +58,7 @@ func resumeHrCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.kubeClient(kubeconfig)
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
@@ -75,50 +82,34 @@ func resumeHrCmdRun(cmd *cobra.Command, args []string) error {
logger.Waitingf("waiting for HelmRelease reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isHelmReleaseResumed(ctx, kubeClient, name, namespace)); err != nil {
isHelmReleaseResumed(ctx, kubeClient, namespacedName, &helmRelease)); err != nil {
return err
}
logger.Successf("HelmRelease reconciliation completed")
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
if helmRelease.Status.LastAppliedRevision != "" {
logger.Successf("applied revision %s", helmRelease.Status.LastAppliedRevision)
} else {
return fmt.Errorf("HelmRelease reconciliation failed")
}
logger.Successf("applied revision %s", helmRelease.Status.LastAppliedRevision)
return nil
}
func isHelmReleaseResumed(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc {
func isHelmReleaseResumed(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, helmRelease *helmv2.HelmRelease) wait.ConditionFunc {
return func() (bool, error) {
var helmRelease helmv2.HelmRelease
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err := kubeClient.Get(ctx, namespacedName, &helmRelease)
err := kubeClient.Get(ctx, namespacedName, helmRelease)
if err != nil {
return false, err
}
for _, condition := range helmRelease.Status.Conditions {
if condition.Type == helmv2.ReadyCondition {
if condition.Status == corev1.ConditionTrue {
return true, nil
} else if condition.Status == corev1.ConditionFalse {
if condition.Reason == helmv2.SuspendedReason {
return false, nil
}
// Confirm the state we are observing is for the current generation
if helmRelease.Generation != helmRelease.Status.ObservedGeneration {
return false, err
}
return false, fmt.Errorf(condition.Message)
}
if c := apimeta.FindStatusCondition(helmRelease.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
return false, fmt.Errorf(c.Message)
}
}
return false, nil

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 The Flux CD contributors.
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.
@@ -20,10 +20,13 @@ import (
"context"
"fmt"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -35,6 +38,9 @@ var resumeKsCmd = &cobra.Command{
Short: "Resume a suspended Kustomization",
Long: `The resume command marks a previously suspended Kustomization resource for reconciliation and waits for it to
finish the apply.`,
Example: ` # Resume reconciliation for an existing Kustomization
flux resume ks podinfo
`,
RunE: resumeKsCmdRun,
}
@@ -44,14 +50,14 @@ func init() {
func resumeKsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("kustomization name is required")
return fmt.Errorf("Kustomization name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.kubeClient(kubeconfig)
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
@@ -66,59 +72,43 @@ 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, namespace)
kustomization.Spec.Suspend = false
if err := kubeClient.Update(ctx, &kustomization); err != nil {
return err
}
logger.Successf("kustomization resumed")
logger.Successf("Kustomization resumed")
logger.Waitingf("waiting for kustomization sync")
logger.Waitingf("waiting for Kustomization reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isKustomizationResumed(ctx, kubeClient, name, namespace)); err != nil {
isKustomizationResumed(ctx, kubeClient, namespacedName, &kustomization)); err != nil {
return err
}
logger.Successf("Kustomization reconciliation completed")
logger.Successf("kustomization sync completed")
err = kubeClient.Get(ctx, namespacedName, &kustomization)
if err != nil {
return err
}
if kustomization.Status.LastAppliedRevision != "" {
logger.Successf("applied revision %s", kustomization.Status.LastAppliedRevision)
} else {
return fmt.Errorf("kustomization sync failed")
}
logger.Successf("applied revision %s", kustomization.Status.LastAppliedRevision)
return nil
}
func isKustomizationResumed(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc {
func isKustomizationResumed(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, kustomization *kustomizev1.Kustomization) wait.ConditionFunc {
return func() (bool, error) {
var kustomization kustomizev1.Kustomization
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err := kubeClient.Get(ctx, namespacedName, &kustomization)
err := kubeClient.Get(ctx, namespacedName, kustomization)
if err != nil {
return false, err
}
for _, condition := range kustomization.Status.Conditions {
if condition.Type == sourcev1.ReadyCondition {
if condition.Status == corev1.ConditionTrue {
return true, nil
} else if condition.Status == corev1.ConditionFalse {
if condition.Reason == kustomizev1.SuspendedReason {
return false, nil
}
// Confirm the state we are observing is for the current generation
if kustomization.Generation != kustomization.Status.ObservedGeneration {
return false, nil
}
return false, fmt.Errorf(condition.Message)
}
if c := apimeta.FindStatusCondition(kustomization.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
return false, fmt.Errorf(c.Message)
}
}
return false, nil

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