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

Compare commits

...

206 Commits

Author SHA1 Message Date
Stefan Prodan
ff2833c4d1 Merge pull request #993 from fluxcd/air-gapped-install
Document air-gapped install procedure
2021-02-25 19:45:37 +02:00
Stefan Prodan
45ba845f23 Document air-gapped install procedure
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-25 19:23:57 +02:00
Hidde Beydals
771a14fcf6 Merge pull request #998 from fluxcd/update-components
Update image-automation-controller to v0.6.1
2021-02-25 17:55:36 +01:00
fluxcdbot
c8ff861d00 Update toolkit components
- image-automation-controller to v0.6.1
  https://github.com/fluxcd/image-automation-controller/blob/v0.6.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2021-02-25 16:43:31 +00:00
Hidde Beydals
0f05ce3605 Merge pull request #994 from fluxcd/update-components
Update toolkit components
2021-02-25 15:16:01 +01:00
fluxcdbot
38a3f3ba11 Update toolkit components
- kustomize-controller to v0.9.1
  https://github.com/fluxcd/kustomize-controller/blob/v0.9.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2021-02-25 14:01:37 +00:00
Hidde Beydals
659a19cd80 Merge pull request #992 from fluxcd/status-poller-fix
Update sigs.k8s.io/cli-utils to v0.22.2
2021-02-25 13:20:47 +01:00
Hidde Beydals
baaa466c0f Update sigs.k8s.io/cli-utils to v0.22.2
This is the first release that includes a patch of the
`CachingClusterReader` so that it continues on all list errors.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-25 12:56:16 +01:00
Stefan Prodan
168c65bb6e Merge pull request #987 from fluxcd/embed-install-manifests
Embed the Kubernetes manifests in flux binary
2021-02-25 13:27:12 +02:00
Stefan Prodan
6003d11156 Embed the install manifests in flux binary
- add make target for generating the install manifests using kustomize
- embed the generated manifests in flux binary
- the install and bootstrap commands default to using the embedded manifests
- download the install manifests from GitHub only if the install/bootstrap version arg is set

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-25 12:53:04 +02:00
Stefan Prodan
1f16b6d639 Merge pull request #988 from fluxcd/setup-go-update-ci
Properly setup Go version in update workflow
2021-02-25 12:16:15 +02:00
Hidde Beydals
54bb4b2efd Properly setup Go version in update workflow
To prevent false `go.mod` modifications.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-25 10:48:09 +01:00
Stefan Prodan
f54770c21a Merge pull request #984 from fluxcd/darwin-arm64-build
Publish flux binary for Apple Silicon
2021-02-25 09:21:27 +02:00
Stefan Prodan
1244a62deb Publish flux binary for Apple Silicon
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-24 23:05:46 +02:00
Stefan Prodan
2fe55bcdde Update Go to v1.16
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-24 23:05:42 +02:00
Hidde Beydals
9943690855 Merge pull request #983 from fluxcd/doc-controller-ver-fix 2021-02-24 19:14:39 +01:00
Hidde Beydals
89c46a6379 Fix controller_version helper func
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-24 18:34:52 +01:00
Hidde Beydals
a0d4530cc0 Merge pull request #982 from fluxcd/update-components-plus-ci 2021-02-24 18:31:50 +01:00
Hidde Beydals
6db84269af Update Toolkit component update script
To recognize and correctly replace the versions in the components'
Kustomization files.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-24 18:17:04 +01:00
Hidde Beydals
2cd3c32ca7 Update toolkit components
This includes a change to the components' Kustomization files to make
use of the YAML multi-doc manifests that are now attached to the GitHub
releases.

- helm-controller to v0.8.0
  https://github.com/fluxcd/helm-controller/blob/v0.8.0/CHANGELOG.md
- kustomize-controller to v0.9.0
  https://github.com/fluxcd/kustomize-controller/blob/v0.9.0/CHANGELOG.md
- source-controller to v0.9.0
  https://github.com/fluxcd/source-controller/blob/v0.9.0/CHANGELOG.md
- notification-controller to v0.9.0
  https://github.com/fluxcd/notification-controller/blob/v0.9.0/CHANGELOG.md
- image-reflector-controller to v0.7.0
  https://github.com/fluxcd/image-reflector-controller/blob/v0.7.0/CHANGELOG.md
- image-automation-controller to v0.6.0
  https://github.com/fluxcd/image-automation-controller/blob/v0.6.0/CHANGELOG.md

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-24 18:16:44 +01:00
Stefan Prodan
9740fecc35 Merge pull request #974 from tarioch/patch-1
Add example podMonitor for prometheus
2021-02-24 18:34:36 +02:00
Patrick Ruckstuhl
433492791b Add example podMonitor for prometheus
Signed-off-by: Patrick Ruckstuhl <patrick@ch.tario.org>
2021-02-24 16:01:00 +00:00
Hidde Beydals
7d3c63ad74 Merge pull request #981 from fluxcd/docs/v1-migration-notes
Add notes about flux bootstrap and feature parity
2021-02-24 13:42:51 +01:00
Hidde Beydals
a6538b117e Add notes about flux bootstrap and feature parity
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-24 13:29:04 +01:00
Stefan Prodan
d54e7559a5 Merge pull request #966 from stealthybox/fixup-az-imgup-kustomize-build
Use git remote-base instead of zip-archive for cloud image-update example
2021-02-23 11:39:59 +02:00
Hidde Beydals
bb9eca7232 Merge pull request #967 from fluxcd/ci/tweak-if-cond
Fix detection of PRs from forks
2021-02-23 10:24:25 +01:00
leigh capili
b5027d8f3f Use git remote-base instead of zip-archive for cloud image-update example
Signed-off-by: leigh capili <leigh@null.net>
2021-02-23 10:24:24 +01:00
Hidde Beydals
00a134e23f Fix detection of PRs from forks
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-23 10:10:03 +01:00
Hidde Beydals
aab3452773 Merge pull request #949 from fluxcd/k8s-ver-check
Include prerelease data in k8s version constraints
2021-02-19 12:01:14 +01:00
Hidde Beydals
5903dfc627 Include prerelease data in k8s version constraints
This ensures the advertised version from e.g. GKE or EKS (for example
`v1.17.15-gke.800`) do not trigger a false warning.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-19 11:39:16 +01:00
Stefan Prodan
a5272b2b39 Merge pull request #945 from fluxcd/docs-ga-roadmap
Add production ready and GA sections to roadmap
2021-02-18 19:57:13 +02:00
Stefan Prodan
771fc20bb2 Add production ready and GA sections to roadmap
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-18 19:03:49 +02:00
Hidde Beydals
b5f48bee78 Merge pull request #944 from fluxcd/build/codeql-on-push 2021-02-18 15:55:49 +01:00
Hidde Beydals
ff78af5808 Run bootstrap for trusted PRs
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-18 15:41:37 +01:00
Hidde Beydals
7eab649abc Bundle CodeQL, FOSSA, Snyk as jobs in workflow
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-18 15:41:37 +01:00
Hidde Beydals
1b5db157b1 Align formatting and extensions workflows
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-18 15:41:32 +01:00
Hidde Beydals
0fa9aebf7a Split analysis workflows into CodeQL, FOSSA, Snyk
This reverts #934, but takes into account the mistakes that were fixed
there.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-18 14:36:02 +01:00
Hidde Beydals
9fb9965ffe Merge pull request #943 from fluxcd/disable-darwin-arm64
Exclude ARM archs from Darwin release builds
2021-02-18 12:17:50 +01:00
Hidde Beydals
02c9f29499 Exclude ARM archs from Darwin release builds
As we are not on Go 1.16 yet.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-18 12:04:32 +01:00
Hidde Beydals
c6243ad002 Merge pull request #942 from fluxcd/update-components
Update toolkit components
2021-02-18 11:36:09 +01:00
fluxcdbot
f4650c7a84 Update toolkit components
- kustomize-controller to v0.8.1
  https://github.com/fluxcd/kustomize-controller/blob/v0.8.1/CHANGELOG.md
- source-controller to v0.8.1
  https://github.com/fluxcd/source-controller/blob/v0.8.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2021-02-18 10:22:26 +00:00
Stefan Prodan
6df691598e Merge pull request #934 from fluxcd/merge-scan-actions
Merge scanning actions
2021-02-17 14:43:35 +02:00
Stefan Prodan
26964b7f88 Merge scanning actions
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-17 11:12:55 +02:00
Stefan Prodan
71712ae1c3 Merge pull request #935 from Niksko/patch-1
Fix typo in gotk_reconcile_condition status
2021-02-17 09:03:53 +02:00
Nik Skoufis
0b6c979e47 Fix typo in gotk_reconcile_condition status
Signed-off-by: Nikolas Skoufis <nskoufis@seek.com.au>
2021-02-17 15:30:24 +11:00
Stefan Prodan
cc2cbc2519 Merge pull request #929 from fluxcd/flux-action
Refactor Flux GitHub Action
2021-02-17 00:33:56 +02:00
Stefan Prodan
8043ae961a Refactor Flux GitHub Action
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-17 00:07:39 +02:00
Hidde Beydals
b1d1d30cdb Merge pull request #932 from idvoretskyi/idvoretskyi-snyk
Snyk GitHub Action added
2021-02-16 22:50:46 +01:00
Ihor Dvoretskyi
28d606cb0e Snyk GitHub Action added
Signed-off-by: Ihor Dvoretskyi <ihor@linux.com>
2021-02-16 23:38:04 +02:00
Hidde Beydals
e9c5b6e917 Merge pull request #933 from adrian/updates-to-sealed-secrets-docs
A few minor updates to sealed secrets docs
2021-02-16 22:20:11 +01:00
Adrian Smith
68f96235fc A few minor updates to sealed secrets docs
* Update to sealed secrets 1.13 helm chart. 1.10 is no longer available.
* Use `--dry-run=client` with kubectl. `--dry-run` on its own is
deprecated.

Signed-off-by: Adrian Smith <adrian@17od.com>
2021-02-16 21:06:50 +00:00
Hidde Beydals
12f22ddeba Merge pull request #931 from fluxcd/add-codeql
Add CodeQL Security Scanning
2021-02-16 19:06:19 +01:00
Chris Aniszczyk
9db5c644a6 Create codeql-analysis.yml
Add CodeSQL Security Scanning to start.

Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
2021-02-16 11:46:25 -06:00
Hidde Beydals
ef6a1fb09b Merge pull request #923 from arbourd/update-runtime
Use `MergeMaps` from pkg/runtime v0.8.2
2021-02-16 00:43:23 +01:00
Dylan Arbour
99002f92f4 Update pkg/runtime to v0.8.2
pkg/runtime v0.8.2 introduces runtime/transform which includes
`MergeMaps`:
https://github.com/fluxcd/pkg/pull/85

Signed-off-by: Dylan Arbour <arbourd@users.noreply.github.com>
2021-02-15 18:06:54 -05:00
Hidde Beydals
298d6a1a15 Merge pull request #922 from fluxcd/check-improvements 2021-02-15 22:14:00 +01:00
Hidde Beydals
5a21f50230 Remove unused util functions
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-15 21:57:11 +01:00
Hidde Beydals
5263dabd22 Check if targeted version is supported by binary
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-15 21:57:11 +01:00
Hidde Beydals
9b649f6c72 Check if targeted bootstrap/install version exists
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-15 21:57:06 +01:00
Hidde Beydals
b903cd5b68 Check for new Flux binary version
This prints a warning if the user has internet access and is running
an older version of the binary.

It also replaces the `blang/semver` package with `pkg/version` and
`Masterminds/semver` to align with controller dependencies.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-15 21:48:27 +01:00
Hidde Beydals
890b5c5202 Use label selector to check components
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-15 16:39:29 +01:00
Hidde Beydals
a14e88d04d Merge pull request #915 from fluxcd/docs-helm-features 2021-02-13 19:08:11 +01:00
Hidde Beydals
58e09b4c68 docs: list Helm post renderer feature
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-13 15:56:43 +01:00
Stefan Prodan
631201d541 Merge pull request #914 from fluxcd/img-update-roadmap
Update image update feature parity roadmap
2021-02-12 18:35:48 +02:00
Stefan Prodan
0fbeb6d2cd Update semver flag in image update guide
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-12 18:23:25 +02:00
Stefan Prodan
11f8e2ffde Update image update feature parity roadmap
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-12 18:21:29 +02:00
Hidde Beydals
055eb4a61a Merge pull request #806 from fluxcd/image-auto-migration-howto 2021-02-12 17:20:35 +01:00
Hidde Beydals
30c1c5c3d3 Link to image automation guides in menu
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-12 17:01:43 +01:00
Hidde Beydals
e034ec3207 Add missing link to image update automation ref
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-12 17:01:08 +01:00
Hidde Beydals
8edc4bd24b Add missing link to SemVer spec
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-12 16:49:33 +01:00
Hidde Beydals
6e1672f73c Change policy example to numerical in asc order
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-12 16:47:16 +01:00
Michael Bridgen
5e1f6f7317 Fix up internal links
Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-12 16:46:30 +01:00
Michael Bridgen
386780ba12 Make hrefs absolute and spelt correctly
Stray characters here and there threw off the markdown engine.

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-12 16:46:30 +01:00
Michael Bridgen
e785971ba8 Rewrite to account for numerical sorting
Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-12 16:46:30 +01:00
Michael Bridgen
daaae07649 Persuade markdown relative paths are links
Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-12 16:46:30 +01:00
Michael Bridgen
6cd567dc66 Remove draft TODO comments
I have moved TODO comments (that still apply) to the PR description.

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-12 16:46:30 +01:00
Michael Bridgen
a541a7ee85 Remove suggestions of using commit number
Using a commit number is trickier than it sounds. It would need to be
padded to sort correctly, for one thing. It is better to leave it out
than to give an incomplete account.

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-12 16:46:30 +01:00
Michael Bridgen
43572bba04 Rearrange so that observing an auto commit is last
Previously, creating an automation object was the last instruction. It
is easier to describe what to expect at each step when the last step
is to add an update marker in the file to be updated, since the next
thing that should happen is that the automation makes an update as a
consequence.

This commit shifts the sections around so that setting up the
GitRepository and ImageUpdateAutomation are done earlier, and
migrating each file are done after that, and completes the steps
described including checking the expected status at each stage.

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-12 16:46:30 +01:00
Michael Bridgen
2a3a4456c1 Separate image tags howto from migration howto
The Flux v1 migration how-to flows better if the section on how to set
builds up to tag images in the right way is its own document. It's a
lot to skim past when you don't need it, and (since it's a different
layer of yak hair) something you might want to figure out first if you
do need it.

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-12 16:46:30 +01:00
Michael Bridgen
15f8e6369b Add image automation migration how-to
This doc describes how to move from using Flux v1 to update image refs
in git, to using Flux v2. There is some overlap with the tutorial on
how to use Flux v2 automation. This how-to spends more time on how to
convert existing configuration to be used with Flux v2.

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-12 16:46:30 +01:00
Hidde Beydals
cfad9a19eb Merge pull request #911 from fluxcd/select-numeric-validation
Validate if only one image policy selector is given
2021-02-12 16:14:21 +01:00
Hidde Beydals
e4c3136433 Merge pull request #910 from fluxcd/git-ca-file
Add caFile to create source/secret git commands
2021-02-12 16:01:27 +01:00
Hidde Beydals
73b8a26850 Validate if only 1 image policy selector is given
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-12 16:01:25 +01:00
Stefan Prodan
aa533b28fb Add caFile to create source/secret git commands
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-12 16:47:00 +02:00
Hidde Beydals
9d70e09a57 Add numeric selector to create image policy cmd
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-12 15:38:01 +01:00
Stefan Prodan
17e18985e6 Merge pull request #908 from fluxcd/update-kustomize-api
Update sigs.k8s.io/kustomize/api to v0.7.4
2021-02-12 15:49:39 +02:00
Hidde Beydals
7c39aaf463 Update sigs.k8s.io/kustomize/api to v0.7.4
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-12 14:32:44 +01:00
Hidde Beydals
bae5c125e8 Merge pull request #907 from fluxcd/update-components
Update toolkit components
2021-02-12 14:29:23 +01:00
fluxcdbot
1c84fa0d97 Update toolkit components
- helm-controller to v0.7.0
  https://github.com/fluxcd/helm-controller/blob/v0.7.0/CHANGELOG.md
- kustomize-controller to v0.8.0
  https://github.com/fluxcd/kustomize-controller/blob/v0.8.0/CHANGELOG.md
- source-controller to v0.8.0
  https://github.com/fluxcd/source-controller/blob/v0.8.0/CHANGELOG.md
- notification-controller to v0.8.0
  https://github.com/fluxcd/notification-controller/blob/v0.8.0/CHANGELOG.md
- image-reflector-controller to v0.6.0
  https://github.com/fluxcd/image-reflector-controller/blob/v0.6.0/CHANGELOG.md
- image-automation-controller to v0.5.0
  https://github.com/fluxcd/image-automation-controller/blob/v0.5.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2021-02-12 13:16:13 +00:00
Hidde Beydals
6f583f9f0e Merge pull request #878 from fluxcd/pprof-guide 2021-02-12 14:02:36 +01:00
Hidde Beydals
217574b75c Add debugging to dev guides menu
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-12 13:44:35 +01:00
Hidde Beydals
1378530aeb Add section about resource usage
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-12 13:44:35 +01:00
Hidde Beydals
0b10ed4d88 Add guide for pprof endpoints
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-12 13:44:35 +01:00
Stefan Prodan
a2887f5776 Merge pull request #891 from fluxcd/refac-uninstall
Refactor flux uninstall command
2021-02-12 14:44:23 +02:00
Stefan Prodan
0f1d27f1e6 Remove network policies on uninstall
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-12 14:30:57 +02:00
Stefan Prodan
850ab0942b Implement uninstall dry run
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-12 14:30:50 +02:00
Stefan Prodan
f5ae8f44b4 Refactor flux uninstall command
- deletes Flux components (deployments and services)
- deletes Flux RBAC (service accounts, cluster roles and cluster role bindings)
- removes the Kubernetes finalizers from Flux custom resources
- deletes Flux custom resource definitions and custom resources
- deletes the namespace where Flux was installed
- preserves the Kubernetes objects and Helm releases that were reconciled on the cluster by Flux

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-12 14:30:50 +02:00
Michael Bridgen
7f98cfd506 Merge pull request #906 from fluxcd/personal-flag
Give more explanation for --personal flag
2021-02-12 12:02:22 +00:00
Michael Bridgen
bc45a79b92 Give more explanation for --personal flag
Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-12 11:41:27 +00:00
Stefan Prodan
5003cf674d Merge pull request #904 from fluxcd/add-version-to-commits
Add flux version to bootstrap commit messages
2021-02-12 11:38:35 +02:00
Stefan Prodan
bc9cbc387c Add flux version to bootstrap commit messages
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-12 10:47:00 +02:00
Stefan Prodan
60a1e78869 Merge pull request #899 from fluxcd/toleration-keys
Allow Flux to be deployed on tainted Kubernetes nodes
2021-02-11 15:46:45 +02:00
Stefan Prodan
37f5587085 Allow Flux to be deployed on tainted Kubernetes nodes
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-11 15:20:19 +02:00
Hidde Beydals
fa6e3d3706 Merge pull request #898 from fluxcd/docs-fix-list 2021-02-11 13:20:19 +01:00
Hidde Beydals
bb8bc875b4 docs: improve Kustomize behavior FAQ
- Fix the formatting of the list.
- Add a hint block for validating changes locally and/or in CI.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-11 12:54:03 +01:00
Stefan Prodan
b3dca737be Merge pull request #897 from fluxcd/fix-timeout
Map timeout arg to bootstrap status check
2021-02-11 13:30:05 +02:00
Stefan Prodan
9094f85487 Add image automation to readme
Sync community section readme/docs index

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-11 13:11:03 +02:00
Stefan Prodan
1256bbfbaf Fix bootstrap status check timeout
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-11 13:09:16 +02:00
Daniel Holbach
24fe74f2f6 Merge pull request #893 from dholbach/link-to-community-page
Link to community page from docs home page
2021-02-10 08:40:15 +01:00
Daniel Holbach
908f501e03 link to community page from toolkit.f.i
Signed-off-by: Daniel Holbach <daniel@weave.works>
2021-02-09 14:52:17 +01:00
Stefan Prodan
35507c7854 Merge pull request #860 from jonathan-innis/joinnis/image-policy
Adding --select-alpha and --extract to create image policy
2021-02-09 15:05:57 +02:00
Jonathan Innis
eb7102ecac Adding extract pattern validation
Signed-off-by: Jonathan Innis <jonathan.innis.ji@gmail.com>
2021-02-08 16:51:45 -08:00
Jonathan Innis
ade6bfcbca Update e2e testing with new cli args
Signed-off-by: Jonathan Innis <jonathan.innis.ji@gmail.com>
2021-02-08 16:49:07 -08:00
Jonathan Innis
fa98403aa8 Add newly generated create image doc
Signed-off-by: Jonathan Innis <jonathan.innis.ji@gmail.com>
2021-02-08 16:49:07 -08:00
jonathan-innis
3f0cb1637c Add select-alpha and extract to create policy
Signed-off-by: jonathan-innis <jonathan.innis.ji@gmail.com>
2021-02-08 16:49:07 -08:00
Stefan Prodan
42011d028e Merge pull request #879 from fluxcd/azure-devops-pat
Add Azure DevOps PAT auth to install docs
2021-02-08 19:01:49 +02:00
Stefan Prodan
307bb0dea1 Add Azure DevOps PAT auth to install docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-08 18:44:22 +02:00
Stefan Prodan
ec2a8347d4 Merge pull request #877 from stealthybox/integrations-registry-credentials-sync
Add ACR auth to Image Updates examples
2021-02-08 18:43:22 +02:00
leigh capili
e99b1c3ed8 Document ACR / AKS Image Update Considerations
Signed-off-by: leigh capili <leigh@null.net>
2021-02-08 09:15:42 -07:00
leigh capili
99825f2663 Add registry cred Deployments/CronJobs for aws/gcp/azure via kustomize
Signed-off-by: leigh capili <leigh@null.net>
2021-02-08 09:15:42 -07:00
Stefan Prodan
afffdfbc5c Merge pull request #880 from chanwit/add_kustomize_fag
Add FAQ to explain the current Kustomize behavior
2021-02-08 17:54:28 +02:00
Chanwit Kaewkasi
cd874acfd5 add FAQ to explain the current Kustomize behavior
Signed-off-by: Chanwit Kaewkasi <chanwit@gmail.com>
2021-02-08 21:24:31 +07:00
Stefan Prodan
34edbf469e Merge pull request #871 from fluxcd/incident-mgmt
Add incident management section to image automation docs
2021-02-06 12:47:10 +02:00
Stefan Prodan
d9ed30e436 Add incident management section to image automation docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-06 10:51:37 +02:00
Stefan Prodan
30008de400 Merge pull request #867 from fluxcd/get-resource-by-name
Add support for getting resources by name
2021-02-05 17:24:50 +02:00
Stefan Prodan
a5fa731545 Add support for getting resources by name
- add singular alias to get commands
- allow filtering the get commands result by resource name
- add the image commands to mkdocs index

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-05 16:35:23 +02:00
Stefan Prodan
493ee3c956 Merge pull request #866 from fluxcd/hr-values
Add support for multiple values files to create hr
2021-02-05 16:09:29 +02:00
Stefan Prodan
3dd574ee51 Add support for multiple values files to create hr
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-05 15:43:03 +02:00
Hidde Beydals
5416c19b2e Merge pull request #863 from fluxcd/update-git-pkg 2021-02-05 14:42:32 +01:00
Hidde Beydals
2f31d80c7a Update git from fluxcd/pkg
This incorporates the changes made to the GitLab provider.

This means that we no longer rely on UI names, but rather use the unique
path identifier (the elements you see in your address bar when looking
at e.g. a group in your GitLab environment).

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-05 13:38:49 +01:00
Stefan Prodan
27d1833854 Merge pull request #848 from ViBiOh/patch-1
Exclude deleted resources on prometheus alerting query
2021-02-05 09:28:49 +02:00
Vincent Boutour
84ed716908 Exclude deleted resources on prometheus alerting query
Signed-off-by: Vincent Boutour <bob@vibioh.fr>
2021-02-04 18:10:42 +01:00
Michael Bridgen
6c9c9c7578 Merge pull request #790 from fluxcd/certs-for-imagerepo
Give image repository a cert-secret-ref flag
2021-02-04 13:13:43 +00:00
Michael Bridgen
cc7b7b0689 Give examples of create image repository
Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-04 12:55:42 +00:00
Michael Bridgen
5df8e05d1a Give image repository a cert-secret-ref flag
ImageRepository objects can now refer to a secret containing
certificates to use for TLS. This adds the flag

    flux create image repository --cert-secret-ref

for naming a secret to use. You can create such a secret with

    flux create secret tls

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-04 12:55:42 +00:00
Michael Bridgen
b3b224b0ca Merge pull request #862 from fluxcd/correct-image-delete
Rename flux delete auto to flux delete image
2021-02-04 12:54:05 +00:00
Michael Bridgen
75ab28ee5d Rename flux delete auto to flux delete image
This slipped through the auto->image change made in the course of
preparing #538.

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-04 11:57:40 +00:00
Michael Bridgen
aa9ea2b4ab Merge pull request #843 from fluxcd/create-image-update-typo
Correct spelling of repository in error
2021-02-04 10:46:27 +00:00
Michael Bridgen
1e6be99c36 Correct spelling of repository in error
Signed-off-by: Michael Bridgen <michael@weave.works>
2021-02-04 10:16:09 +00:00
Stefan Prodan
49fb396bf8 Merge pull request #861 from fluxcd/refactor-checks
Refactor components status check
2021-02-04 11:56:22 +02:00
Stefan Prodan
e055c9ddc1 Refactor components status check
- run install/bootstrap checks in parallel (1m timeout)
- list not found components

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-02-04 11:16:27 +02:00
Stefan Prodan
c708e390a7 Merge pull request #845 from jonathan-innis/jonathan-innis/kstatus
Replace kubectl rollout with kstatus checks
2021-02-04 09:11:41 +02:00
jonathan-innis
d5ad26c934 Change failed message for bootstrap
Signed-off-by: jonathan-innis <jonathan.innis.ji@gmail.com>
2021-02-03 12:08:10 -08:00
jonathan-innis
144b7cd922 Update errors returned to user
Signed-off-by: jonathan-innis <jonathan.innis.ji@gmail.com>
2021-02-03 12:07:29 -08:00
jonathan-innis
9e86fbb311 Tidy up the mod imports
Signed-off-by: jonathan-innis <jonathan.innis.ji@gmail.com>
2021-02-03 12:07:29 -08:00
jonathan-innis
b528428d02 Add kstatus to install and check commands
Signed-off-by: jonathan-innis <jonathan.innis.ji@gmail.com>
2021-02-03 12:07:29 -08:00
jonathan-innis
b3d7730e79 Use status polling in bootstrap command
Signed-off-by: jonathan-innis <jonathan.innis.ji@gmail.com>
2021-02-03 12:07:19 -08:00
Hidde Beydals
f2ba567ca4 Merge pull request #857 from fluxcd/update-components
Update toolkit components
2021-02-03 19:34:43 +01:00
fluxcdbot
8342f77087 Update toolkit components
- source-controller to v0.7.4
  https://github.com/fluxcd/source-controller/blob/v0.7.4/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2021-02-03 14:51:22 +00:00
Hidde Beydals
7cade1b98f Merge pull request #858 from fluxcd/component-update-cfg
Put CHANGELOG URL on new line in commit / PR body
2021-02-03 15:50:47 +01:00
Hidde Beydals
ee4c1fb36c Put CHANGELOG URL on new line in commit / PR body
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-03 15:22:57 +01:00
Hidde Beydals
dbc4e537fe Merge pull request #854 from fluxcd/move-migration-menu 2021-02-03 13:10:59 +01:00
Hidde Beydals
e28990b96c Move migration sub-menu to top-menu
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-03 11:49:51 +01:00
Hidde Beydals
408cf92c04 Merge pull request #853 from fluxcd/component-update-cfg
Tune component update configuration
2021-02-03 10:22:58 +01:00
Hidde Beydals
425af2e0dc Tune component update configuration
- Include link to changelog of component in commit and PR message
- Label pull request automatically with `area/build`
- Enable sign-off of commits to free us from manual labour

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-02 18:48:49 +01:00
Stefan Prodan
22df860eca Merge pull request #849 from fluxcd/update-components
Update toolkit components
2021-02-02 18:07:29 +02:00
fluxcdbot
f395044d65 Update toolkit components 2021-02-02 15:40:37 +00:00
Hidde Beydals
afe0ddcd84 Merge pull request #824 from fluxcd/upgrade-semver-tip
Highlight PATCH versions can be used to upgrade
2021-02-01 18:41:34 +01:00
Hidde Beydals
2c0323684c Highlight PATCH versions can be used to upgrade
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-01 18:21:54 +01:00
Hidde Beydals
6d5ffdea57 Merge pull request #841 from fluxcd/update-components
Update toolkit components
2021-02-01 18:07:15 +01:00
fluxcdbot
648af6e645 Update toolkit components 2021-02-01 16:50:07 +00:00
Hidde Beydals
e1895a4e21 Merge pull request #840 from relu/fix-image-update-docs-ecr-cronjob
Improve image update CronJob examples
2021-02-01 17:49:31 +01:00
Aurel Canciu
d5f45800ae Clarify how to use the generated cronjob secret
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2021-02-01 17:11:14 +01:00
Aurel Canciu
51f9d249ff Fix image update guide ECR cronjob manifest
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2021-02-01 17:11:14 +01:00
Hidde Beydals
6f525356cb Merge pull request #837 from aholbreich/patch-1 2021-02-01 17:10:54 +01:00
Alexander Holbreich
5008f9064e Update image-update.md
Increase attention to missing flux components.

Signed-off-by: Alexander Holbreich <alexander@holbreich.org>
2021-02-01 16:53:19 +01:00
Stefan Prodan
cff96ed7ca Merge pull request #834 from fluxcd/fix-secret-cmd
Fix create secret commands
2021-01-30 16:36:44 +02:00
Stefan Prodan
4e8a600f34 Add e2e tests for create secret commands
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-30 15:19:45 +02:00
Stefan Prodan
4fd5684277 Fix create secret commands
Regression bug introduced in https://github.com/fluxcd/flux2/pull/788

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-30 15:07:48 +02:00
Hidde Beydals
06bf469ba7 Merge pull request #825 from SomtochiAma/refactor-reconcile-command
Refactor resume command
2021-01-29 19:52:07 +01:00
Somtochi Onyekwere
b8a215230c refactor resume command
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-29 19:05:38 +01:00
Stefan Prodan
2460cfcf1c Merge pull request #821 from fluxcd/docs-helm-faq
Add HelmChart not ready to FAQ
2021-01-29 17:05:39 +02:00
Stefan Prodan
364242c857 Add HelmChart not ready to FAQ
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-29 16:20:35 +02:00
Stefan Prodan
29e2900f59 Merge pull request #818 from fluxcd/docs-image-webhook
Add webhook section to image update docs
2021-01-29 13:33:17 +02:00
Stefan Prodan
61e1fb770e Add webhook section to image update docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-29 13:09:01 +02:00
Stefan Prodan
2d3fcbdea3 Merge pull request #815 from fluxcd/e2e-kube-1.20.2
Update e2e tests to Kubernetes v1.20.2
2021-01-29 09:49:42 +02:00
Stefan Prodan
47e15cee3d Update e2e tests to Kubernetes v1.20.2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-28 19:50:19 +02:00
Stefan Prodan
adeb3e3f42 Merge pull request #814 from mewzherder/patch-9
Community section clarity of purpose + support page link
2021-01-28 19:42:42 +02:00
mewzherder
fb1278285b Community section clarity of purpose + support page link
Signed-off-by: mewzherder <tamao@weave.works>
2021-01-28 09:24:08 -08:00
Stefan Prodan
e371610849 Merge pull request #812 from chanwit/network_policy_e2e
Enable network policy in e2e
2021-01-28 16:46:45 +02:00
Chanwit Kaewkasi
424de63bd1 update KIND to v0.10.0 and node to 1.16.15
Signed-off-by: Chanwit Kaewkasi <chanwit@gmail.com>
2021-01-28 21:21:02 +07:00
Chanwit Kaewkasi
832c925d39 setup Calico to enable network policy for e2e testing
Signed-off-by: Chanwit Kaewkasi <chanwit@gmail.com>
2021-01-28 21:21:02 +07:00
Chanwit Kaewkasi
378f118d51 add kind config to disable kind-net
Signed-off-by: Chanwit Kaewkasi <chanwit@gmail.com>
2021-01-28 21:21:02 +07:00
Hidde Beydals
d651777122 Merge pull request #813 from fluxcd/iua-docs-example-update
Update docs ImageUpdateAutomation example
2021-01-28 15:13:40 +01:00
Aurel Canciu
65d8ebabb8 Update docs ImageUpdateAutomation example
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2021-01-28 15:57:25 +02:00
Hidde Beydals
9195ed9a1b Merge pull request #809 from SomtochiAma/refactor-reconcile-command
Refactor reconcile commands
2021-01-28 14:16:15 +01:00
Somtochi Onyekwere
5df8f7313c Refactor reconcile commands
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-28 13:21:29 +01:00
Hidde Beydals
25ed6ca0a4 Merge pull request #780 from dholbach/link-to-support-page 2021-01-28 11:59:08 +01:00
Daniel Holbach
9f972995bd add very basic issue template
Also link to support page.

	Fixes: fluxcd/website#77

Signed-off-by: Daniel Holbach <daniel@weave.works>
2021-01-27 17:34:26 +01:00
Hidde Beydals
29c46a9892 Merge pull request #791 from SomtochiAma/refactor-reconcile-commands
Refactor suspend commands
2021-01-27 10:05:32 +01:00
Somtochi Onyekwere
ef579fe596 Refactor suspend commands
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-27 09:57:37 +01:00
Hidde Beydals
5b268f62a3 Merge pull request #789 from SomtochiAma/refactor-delete-command 2021-01-27 09:57:17 +01:00
Somtochi Onyekwere
1f1c8286a5 Refactor delete command for kustomizations, sources and helmreleases
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-27 09:43:39 +01:00
Hidde Beydals
5401e1ace4 Merge pull request #794 from fluxcd/get-type-fixes
Use correct type in various get source commands
2021-01-27 09:37:25 +01:00
Hidde Beydals
69294ef56d Use correct type in various get source commands
This fixes a bug where the wrong type was displayed for various
`get source` commands.

```console
$ flux get sources helm --namespace default
✗ no Bucket objects found in default namespace
```

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-27 09:28:48 +01:00
Hidde Beydals
a685ed8029 Merge pull request #793 from fluxcd/reconcile-w-source-other-ns
Set source namespace when reconciling with source
2021-01-27 09:21:12 +01:00
Hidde Beydals
68d0be3818 Set source namespace when reconciling with source
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-26 22:21:40 +01:00
Michael Bridgen
84e2cb4c1f Merge pull request #788 from fluxcd/create-secret-tls
Create secret for TLS command
2021-01-26 17:33:50 +00:00
Michael Bridgen
263c664acd Factor out more common secrets command code
Making the secret without data is always the same, so factor that out.

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-01-26 17:25:33 +00:00
Michael Bridgen
b12c4c22fb Add command for creating TLS secrets
The image-reflector controller now accepts a secret containing a
client certificate and key, and/or a CA certificate; so it's useful to
have a command for creating them.

`flux create secret helm` is close, but accepts username/password
(which would be ignored), and has the wrong name of course. Happily
though, much can be shared between the implementations.

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-01-26 17:25:33 +00:00
Stefan Prodan
9f39fadb9e Merge pull request #787 from fluxcd/fix-rbac-namespace
RBAC Fix: Replace SA namespace in ClusterRoleBindings
2021-01-26 19:21:19 +02:00
Stefan Prodan
4c29a1ca27 Replace SA namespace in RBAC
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-26 18:57:36 +02:00
Stefan Prodan
f4db124d50 Merge pull request #783 from fluxcd/rbac-fix
RBAC Fix: Add SA namespace to cluster role bindings
2021-01-26 16:24:16 +02:00
Stefan Prodan
8f8c7cccc6 Add SA namespace to RBAC
Fix flux install when not all controllers have been selected

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-26 16:16:34 +02:00
Hidde Beydals
e2097c28bd Merge pull request #782 from fluxcd/docs-img-auto-links
docs: fix image automation menu links
2021-01-26 14:34:29 +01:00
Hidde Beydals
871eb444fc docs: fix image automation menu links
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-26 14:26:18 +01:00
163 changed files with 4881 additions and 2243 deletions

46
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,46 @@
---
name: Bug report
about: Create a report to help us improve Flux v2
title: ''
assignees: ''
---
<!--
Find out more about your support options and getting help at
https://fluxcd.io/support/
-->
### Describe the bug
A clear and concise description of what the bug is.
### To Reproduce
Steps to reproduce the behaviour:
1. Provide Flux install instructions
2. Provide a GitHub repository with Kubernetes manifests
### Expected behavior
A clear and concise description of what you expected to happen.
### Additional context
- Kubernetes version:
- Git provider:
- Container registry provider:
Below please provide the output of the following commands:
```cli
flux --version
flux check
kubectl -n <namespace> get all
kubectl -n <namespace> logs deploy/source-controller
kubectl -n <namespace> logs deploy/kustomize-controller
```

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: Ask a question
url: https://github.com/fluxcd/flux2/discussions
about: Please ask and answer questions here.

5
.github/kind/config.yaml vendored Normal file
View File

@@ -0,0 +1,5 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
disableDefaultCNI: true # disable kindnet
podSubnet: 192.168.0.0/16 # set to Calico's default subnet

View File

@@ -2,12 +2,14 @@ name: bootstrap
on:
push:
branches:
- '*'
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
github:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
steps:
- name: Checkout
uses: actions/checkout@v2
@@ -15,23 +17,27 @@ jobs:
uses: actions/cache@v1
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
key: ${{ runner.os }}-go1.16-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
${{ runner.os }}-go1.16-
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.15.x
go-version: 1.16.x
- name: Setup Kubernetes
uses: engineerd/setup-kind@v0.5.0
- name: Setup Kustomize
uses: fluxcd/pkg//actions/kustomize@main
- name: Build
run: |
make build-manifests
go build -o /tmp/flux ./cmd/flux
- 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/ \
/tmp/flux bootstrap github --manifests ./manifests/install/ \
--owner=fluxcd-testing \
--repository=flux-test-${{ steps.vars.outputs.sha_short }} \
--branch=main \
@@ -40,7 +46,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
- name: bootstrap no-op
run: |
./bin/flux bootstrap github --manifests ./manifests/install/ \
/tmp/flux bootstrap github --manifests ./manifests/install/ \
--owner=fluxcd-testing \
--repository=flux-test-${{ steps.vars.outputs.sha_short }} \
--branch=main \
@@ -49,10 +55,11 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
- name: uninstall
run: |
./bin/flux uninstall --resources --crds -s --timeout=10m
/tmp/flux uninstall -s --keep-namespace
kubectl delete ns flux-system --timeout=10m --wait=true
- name: bootstrap reinstall
run: |
./bin/flux bootstrap github --manifests ./manifests/install/ \
/tmp/flux bootstrap github --manifests ./manifests/install/ \
--owner=fluxcd-testing \
--repository=flux-test-${{ steps.vars.outputs.sha_short }} \
--branch=main \
@@ -61,7 +68,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
- name: delete repository
run: |
./bin/flux bootstrap github --manifests ./manifests/install/ \
/tmp/flux bootstrap github --manifests ./manifests/install/ \
--owner=fluxcd-testing \
--repository=flux-test-${{ steps.vars.outputs.sha_short }} \
--branch=main \

View File

@@ -1,9 +1,8 @@
name: Publish docs via GitHub Pages
on:
push:
branches:
- docs*
- main
branches: [ 'docs*', main ]
jobs:
build:
@@ -17,7 +16,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
controller_version() {
sed -n "s/.*$1\/archive\/\(.*\).zip.*/\1/p;n" manifests/bases/$1/kustomization.yaml
sed -n "s/.*$1\/releases\/download\/\(.*\)\/.*/\1/p;n" manifests/bases/$1/kustomization.yaml
}
{

View File

@@ -1,10 +1,10 @@
name: e2e
on:
pull_request:
push:
branches:
- main
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
kind:
@@ -16,17 +16,25 @@ jobs:
uses: actions/cache@v1
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
key: ${{ runner.os }}-go1.16-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
${{ runner.os }}-go1.16-
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.15.x
go-version: 1.16.x
- name: Setup Kubernetes
uses: engineerd/setup-kind@v0.5.0
with:
image: kindest/node:v1.16.9
version: "v0.10.0"
image: kindest/node:v1.20.2@sha256:8f7ea6e7642c0da54f04a7ee10431549c0257315b3a634f6ef2fecaaedb19bab
config: .github/kind/config.yaml # disable KIND-net
- name: Setup Calico for network policy
run: |
kubectl apply -f https://docs.projectcalico.org/v3.16/manifests/calico.yaml
kubectl -n kube-system set env daemonset/calico-node FELIX_IGNORELOOSERPF=true
- name: Setup Kustomize
uses: fluxcd/pkg//actions/kustomize@main
- name: Run test
run: make test
- name: Check if working tree is dirty
@@ -37,34 +45,44 @@ jobs:
exit 1
fi
- name: Build
run: sudo go build -o ./bin/flux ./cmd/flux
run: |
go build -o /tmp/flux ./cmd/flux
- name: flux check --pre
run: |
./bin/flux check --pre
/tmp/flux check --pre
- name: flux install --manifests
run: |
./bin/flux install --manifests ./manifests/install/
/tmp/flux install --manifests ./manifests/install/
- name: flux create secret
run: |
/tmp/flux create secret git git-ssh-test \
--url ssh://git@github.com/stefanprodan/podinfo
/tmp/flux create secret git git-https-test \
--url https://github.com/stefanprodan/podinfo \
--username=test --password=test
/tmp/flux create secret helm helm-test \
--username=test --password=test
- name: flux create source git
run: |
./bin/flux create source git podinfo \
/tmp/flux create source git podinfo \
--url https://github.com/stefanprodan/podinfo \
--tag-semver=">=3.2.3"
- name: flux create source git export apply
run: |
./bin/flux create source git podinfo-export \
/tmp/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
/tmp/flux delete source git podinfo-export --silent
- name: flux get sources git
run: |
./bin/flux get sources git
/tmp/flux get sources git
- name: flux get sources git --all-namespaces
run: |
./bin/flux get sources git --all-namespaces
/tmp/flux get sources git --all-namespaces
- name: flux create kustomization
run: |
./bin/flux create kustomization podinfo \
/tmp/flux create kustomization podinfo \
--source=podinfo \
--path="./deploy/overlays/dev" \
--prune=true \
@@ -75,106 +93,112 @@ jobs:
--health-check-timeout=3m
- name: flux reconcile kustomization --with-source
run: |
./bin/flux reconcile kustomization podinfo --with-source
/tmp/flux reconcile kustomization podinfo --with-source
- name: flux get kustomizations
run: |
./bin/flux get kustomizations
/tmp/flux get kustomizations
- name: flux get kustomizations --all-namespaces
run: |
./bin/flux get kustomizations --all-namespaces
/tmp/flux get kustomizations --all-namespaces
- name: flux suspend kustomization
run: |
./bin/flux suspend kustomization podinfo
/tmp/flux suspend kustomization podinfo
- name: flux resume kustomization
run: |
./bin/flux resume kustomization podinfo
/tmp/flux resume kustomization podinfo
- name: flux export
run: |
./bin/flux export source git --all
./bin/flux export kustomization --all
/tmp/flux export source git --all
/tmp/flux export kustomization --all
- name: flux delete kustomization
run: |
./bin/flux delete kustomization podinfo --silent
/tmp/flux delete kustomization podinfo --silent
- name: flux create source helm
run: |
./bin/flux create source helm podinfo \
/tmp/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 \
/tmp/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 \
/tmp/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
/tmp/flux reconcile helmrelease podinfo-git --with-source
- name: flux get helmreleases
run: |
./bin/flux get helmreleases
/tmp/flux get helmreleases
- name: flux get helmreleases --all-namespaces
run: |
./bin/flux get helmreleases --all-namespaces
/tmp/flux get helmreleases --all-namespaces
- name: flux export helmrelease
run: |
./bin/flux export hr --all
/tmp/flux export hr --all
- name: flux delete helmrelease podinfo-helm
run: |
./bin/flux delete hr podinfo-helm --silent
/tmp/flux delete hr podinfo-helm --silent
- name: flux delete helmrelease podinfo-git
run: |
./bin/flux delete hr podinfo-git --silent
/tmp/flux delete hr podinfo-git --silent
- name: flux delete source helm
run: |
./bin/flux delete source helm podinfo --silent
/tmp/flux delete source helm podinfo --silent
- name: flux delete source git
run: |
./bin/flux delete source git podinfo --silent
/tmp/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 \
/tmp/flux create tenant dev-team --with-namespace=apps
/tmp/flux -n apps create source helm podinfo \
--url https://stefanprodan.github.io/podinfo
./bin/flux -n apps create hr podinfo-helm \
/tmp/flux -n apps create hr podinfo-helm \
--source=HelmRepository/podinfo \
--chart=podinfo \
--chart-version="5.0.x" \
--service-account=dev-team
- name: flux create image repository
run: |
./bin/flux create image repository podinfo \
/tmp/flux create image repository podinfo \
--image=ghcr.io/stefanprodan/podinfo \
--interval=1m
- name: flux create image policy
run: |
./bin/flux create image policy podinfo \
/tmp/flux create image policy podinfo \
--image-ref=podinfo \
--interval=1m \
--semver=5.0.x
--select-semver=5.0.x
- name: flux create image policy podinfo-select-alpha
run: |
/tmp/flux create image policy podinfo-alpha \
--image-ref=podinfo \
--interval=1m \
--select-alpha=desc
- name: flux get image policy
run: |
./bin/flux get image policy podinfo | grep '5.0.3'
/tmp/flux get image policy podinfo | grep '5.0.3'
- name: flux2-kustomize-helm-example
run: |
./bin/flux create source git flux-system \
/tmp/flux create source git flux-system \
--url=https://github.com/fluxcd/flux2-kustomize-helm-example \
--branch=main
./bin/flux create kustomization flux-system \
/tmp/flux create kustomization flux-system \
--source=flux-system \
--path=./clusters/staging
kubectl -n flux-system wait kustomization/apps --for=condition=ready --timeout=2m
- name: flux check
run: |
./bin/flux check
/tmp/flux check
- name: flux uninstall
run: |
./bin/flux uninstall --crds --silent --timeout=10m
/tmp/flux uninstall --silent
- name: Debug failure
if: failure()
run: |

View File

@@ -1,25 +0,0 @@
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 }}

View File

@@ -2,9 +2,9 @@ name: rebase
on:
pull_request:
types: [opened]
types: [ opened ]
issue_comment:
types: [created]
types: [ created ]
jobs:
rebase:

View File

@@ -2,8 +2,7 @@ name: release
on:
push:
tags:
- '*'
tags: [ 'v*' ]
jobs:
goreleaser:
@@ -16,7 +15,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.15.x
go-version: 1.16.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
@@ -29,38 +28,10 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Kustomize
uses: fluxcd/pkg//actions/kustomize@main
- name: Generate manifests tarball
run: |
mkdir -p ./output
files=""
# build controllers
for controller in ./manifests/bases/*/; do
output_path="./output/$(basename $controller).yaml"
echo "building $controller to $output_path"
kustomize build $controller > $output_path
files+=" $(basename $output_path)"
done
# build rbac
rbac_path="./manifests/rbac"
rbac_output_path="./output/rbac.yaml"
echo "building $rbac_path to $rbac_output_path"
kustomize build $rbac_path > $rbac_output_path
files+=" $(basename $rbac_output_path)"
# build policies
policies_path="./manifests/policies"
policies_output_path="./output/policies.yaml"
echo "building $policies_path to $policies_output_path"
kustomize build $policies_path > $policies_output_path
files+=" $(basename $policies_output_path)"
# create tarball
cd ./output && tar -cvzf manifests.tar.gz $files
- name: Generate install manifest
- name: Generate manifests
run: |
make build-manifests
./manifests/scripts/bundle.sh ./output manifests.tar.gz
kustomize build ./manifests/install > ./output/install.yaml
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v1

60
.github/workflows/scan.yaml vendored Normal file
View File

@@ -0,0 +1,60 @@
name: Scan
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: '18 10 * * 3'
jobs:
fossa:
name: FOSSA
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- 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 }}
snyk:
name: Snyk
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v2
- name: Setup Kustomize
uses: fluxcd/pkg//actions/kustomize@main
- name: Build manifests
run: |
make build-manifests
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/golang@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --sarif-file-output=snyk.sarif
- name: Upload result to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v1
with:
sarif_file: snyk.sarif
codeql:
name: CodeQL
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: go
- name: Autobuild
uses: github/codeql-action/autobuild@v1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@@ -13,7 +13,10 @@ jobs:
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.16.x
- name: Update component versions
id: update
run: |
@@ -21,18 +24,19 @@ jobs:
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)
local CURRENT_VERSION=$(sed -n "s/.*$1\/releases\/download\/\(.*\)\/.*/\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"
sed -i "s/\($1\/releases\/download\/\)v.*\(\/.*\)/\1${RELEASE_VERSION}\2/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"
# NB: special URL encoded formatting required for newlines
PR_BODY="$PR_BODY- $1 to ${RELEASE_VERSION}%0A https://github.com/fluxcd/$1/blob/${RELEASE_VERSION}/CHANGELOG.md%0A"
fi
}
@@ -51,7 +55,7 @@ jobs:
# diff change
git diff
# export PR_BODY for PR
# export PR_BODY for PR and commit
echo "::set-output name=pr_body::$PR_BODY"
}
@@ -60,19 +64,22 @@ jobs:
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.BOT_GITHUB_TOKEN }}
commit-message: Update toolkit components
commit-message: |
Update toolkit components
${{ steps.update.outputs.pr_body }}
committer: GitHub <noreply@github.com>
author: fluxcdbot <fluxcdbot@users.noreply.github.com>
signoff: true
branch: update-components
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
labels: |
area/build
reviewers: ${{ secrets.ASSIGNEES }}
- name: Check output
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"

3
.gitignore vendored
View File

@@ -14,4 +14,5 @@
# Dependency directories (remove the comment below to include it)
# vendor/
bin/
output/
output/
cmd/flux/manifests/

View File

@@ -20,6 +20,9 @@ builds:
id: darwin
goos:
- darwin
goarch:
- amd64
- arm64
- <<: *build_defaults
id: windows
goos:

View File

@@ -11,9 +11,12 @@ fmt:
vet:
go vet ./...
test: tidy fmt vet docs
test: build-manifests tidy fmt vet docs
go test ./... -coverprofile cover.out
build-manifests:
./manifests/scripts/bundle.sh
build:
CGO_ENABLED=0 go build -o ./bin/flux ./cmd/flux

View File

@@ -60,11 +60,12 @@ 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/)
- [Get started with Flux](https://toolkit.fluxcd.io/get-started/)
- [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/)
- [Automate image updates to Git](https://toolkit.fluxcd.io/guides/image-update/)
- [Manage Kubernetes secrets with Mozilla SOPS](https://toolkit.fluxcd.io/guides/mozilla-sops/)
If you need help, please refer to our **[Support page](https://fluxcd.io/support/)**.
## GitOps Toolkit
@@ -94,21 +95,33 @@ guides](https://toolkit.fluxcd.io/dev-guides/source-watcher/).
- [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/)
- [Image Automation Controllers](https://toolkit.fluxcd.io/components/image/controller/)
- [ImageRepository CRD](https://toolkit.fluxcd.io/components/image/imagerepositories/)
- [ImagePolicy CRD](https://toolkit.fluxcd.io/components/image/imagepolicies/)
- [ImageUpdateAutomation CRD](https://toolkit.fluxcd.io/components/image/imageupdateautomations/)
## 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:
Need help or want to contribute? Please see the links below. The Flux project is always looking for
new contributors and there are a multitude of ways to get involved.
- 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/)
- Ask questions and propose features on our [GH Discussions page](https://github.com/fluxcd/flux2/discussions)
- And if you are completely new to Flux and the GitOps Toolkit, take a look at our [Get Started guide](https://toolkit.fluxcd.io/get-started/) and give us feedback
- To be part of the conversation about Flux's development, [join the flux-dev mailing list](https://lists.cncf.io/g/cncf-flux-dev).
- Check out [how to contribute](CONTRIBUTING.md) to the project
- Getting Started?
- Look at our [Get Started guide](https://toolkit.fluxcd.io/get-started/) and give us feedback
- Need help?
- First: Ask questions on our [GH Discussions page](https://github.com/fluxcd/flux2/discussions)
- Second: Talk to us in the #flux channel on [CNCF Slack](https://slack.cncf.io/)
- Please follow our [Support Guidelines](https://fluxcd.io/support/)
(in short: be nice, be respectful of volunteers' time, understand that maintainers and
contributors cannot respond to all DMs, and keep discussions in the public #flux channel as much as possible).
- Have feature proposals or want to contribute?
- Propose features on our [GH Discussions page](https://github.com/fluxcd/flux2/discussions)
- Join our upcoming dev meetings ([meeting access and agenda](https://docs.google.com/document/d/1l_M0om0qUEN_NNiGgpqJ2tvsF2iioHkaARDeh6b70B0/view))
- [Join the flux-dev mailing list](https://lists.cncf.io/g/cncf-flux-dev).
- Check out [how to contribute](CONTRIBUTING.md) to the project
### Events
Check out our **[events calendar](https://fluxcd.io/community/#talks)**, both with upcoming talks you can attend or past events videos you can watch.
Check out our **[events calendar](https://fluxcd.io/community/#talks)**,
both with upcoming talks you can attend or past events videos you can watch.
We look forward to seeing you with us!

View File

@@ -1,6 +0,0 @@
FROM stefanprodan/alpine-base:latest
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -10,19 +10,24 @@ Usage:
run: flux -v
```
This action places the `flux` binary inside your repository root under `bin/flux`.
You should add `bin/flux` to your `.gitignore` file, as in the following example:
```gitignore
# ignore flux binary
bin/flux
```
Note that this action can only be used on GitHub **Linux AMD64** runners.
The latest stable version of the `flux` binary is downloaded from
GitHub [releases](https://github.com/fluxcd/flux2/releases)
and placed at `/usr/local/bin/flux`.
You can download a specific version with:
```yaml
steps:
- name: Setup Flux CLI
uses: fluxcd/flux2/action@main
with:
version: 0.8.0
```
### Automate Flux updates
Example workflow for updating Flux's components generated with `flux bootstrap --arch=amd64 --path=clusters/production`:
Example workflow for updating Flux's components generated with `flux bootstrap --path=clusters/production`:
```yaml
name: update-flux
@@ -43,7 +48,7 @@ jobs:
- name: Check for updates
id: update
run: |
flux install --arch=amd64 \
flux install \
--export > ./clusters/production/flux-system/gotk-components.yaml
VERSION="$(flux -v)"

View File

@@ -1,15 +1,38 @@
name: 'kustomize'
description: 'A GitHub Action for running Flux commands'
author: 'Flux project'
name: Setup Flux CLI
description: A GitHub Action for running Flux commands
author: Stefan Prodan
branding:
icon: 'command'
color: 'blue'
color: blue
icon: command
inputs:
version:
description: 'strict semver'
description: "Flux version e.g. 0.8.0 (defaults to latest stable release)"
required: false
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.version }}
using: composite
steps:
- name: "Download flux binary to tmp"
shell: bash
run: |
VERSION=${{ inputs.version }}
if [ -z $VERSION ]; then
VERSION=$(curl https://api.github.com/repos/fluxcd/flux2/releases/latest -sL | grep tag_name | sed -E 's/.*"([^"]+)".*/\1/' | cut -c 2-)
fi
BIN_URL="https://github.com/fluxcd/flux2/releases/download/v${VERSION}/flux_${VERSION}_linux_amd64.tar.gz"
curl -sL ${BIN_URL} -o /tmp/flux.tar.gz
mkdir -p /tmp/flux
tar -C /tmp/flux/ -zxvf /tmp/flux.tar.gz
- name: "Add flux binary to /usr/local/bin"
shell: bash
run: |
sudo cp /tmp/flux/flux /usr/local/bin
- name: "Cleanup tmp"
shell: bash
run: |
rm -rf /tmp/flux/ /tmp/flux.tar.gz
- name: "Verify correct installation of binary"
shell: bash
run: |
flux -v

View File

@@ -1,40 +0,0 @@
#!/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
mv ./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

View File

@@ -60,6 +60,7 @@ type bootstrapFlags struct {
requiredComponents []string
tokenAuth bool
clusterDomain string
tolerationKeys []string
}
const (
@@ -69,8 +70,8 @@ const (
var bootstrapArgs = NewBootstrapFlags()
func init() {
bootstrapCmd.PersistentFlags().StringVarP(&bootstrapArgs.version, "version", "v", rootArgs.defaults.Version,
"toolkit version")
bootstrapCmd.PersistentFlags().StringVarP(&bootstrapArgs.version, "version", "v", "",
"toolkit version, when specified the manifests are downloaded from https://github.com/fluxcd/flux2/releases")
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.defaultComponents, "components", rootArgs.defaults.Components,
"list of components, accepts comma-separated values")
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.extraComponents, "components-extra", nil,
@@ -91,6 +92,8 @@ func init() {
bootstrapCmd.PersistentFlags().Var(&bootstrapArgs.logLevel, "log-level", bootstrapArgs.logLevel.Description())
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.manifestsPath, "manifests", "", "path to the manifest directory")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.clusterDomain, "cluster-domain", rootArgs.defaults.ClusterDomain, "internal cluster domain")
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.tolerationKeys, "toleration-keys", nil,
"list of toleration keys used to schedule the components pods onto nodes with matching taints")
bootstrapCmd.PersistentFlags().MarkHidden("manifests")
bootstrapCmd.PersistentFlags().MarkDeprecated("arch", "multi-arch container image is now available for AMD64, ARMv7 and ARM64")
rootCmd.AddCommand(bootstrapCmd)
@@ -123,10 +126,24 @@ func bootstrapValidate() error {
}
func generateInstallManifests(targetPath, namespace, tmpDir string, localManifests string) (string, error) {
if ver, err := getVersion(bootstrapArgs.version); err != nil {
return "", err
} else {
bootstrapArgs.version = ver
}
manifestsBase := ""
if isEmbeddedVersion(bootstrapArgs.version) {
if err := writeEmbeddedManifests(tmpDir); err != nil {
return "", err
}
manifestsBase = tmpDir
}
opts := install.Options{
BaseURL: localManifests,
Version: bootstrapArgs.version,
Namespace: rootArgs.namespace,
Namespace: namespace,
Components: bootstrapComponents(),
Registry: bootstrapArgs.registry,
ImagePullSecret: bootstrapArgs.imagePullSecret,
@@ -138,13 +155,14 @@ func generateInstallManifests(targetPath, namespace, tmpDir string, localManifes
Timeout: rootArgs.timeout,
TargetPath: targetPath,
ClusterDomain: bootstrapArgs.clusterDomain,
TolerationKeys: bootstrapArgs.tolerationKeys,
}
if localManifests == "" {
opts.BaseURL = rootArgs.defaults.BaseURL
}
output, err := install.Generate(opts)
output, err := install.Generate(opts, manifestsBase)
if err != nil {
return "", fmt.Errorf("generating install manifests failed: %w", err)
}
@@ -162,12 +180,16 @@ func applyInstallManifests(ctx context.Context, manifestPath string, components
return fmt.Errorf("install failed")
}
for _, deployment := range components {
kubectlArgs = []string{"-n", rootArgs.namespace, "rollout", "status", "deployment", deployment, "--timeout", rootArgs.timeout.String()}
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
return fmt.Errorf("install failed")
}
statusChecker, err := NewStatusChecker(time.Second, rootArgs.timeout)
if err != nil {
return fmt.Errorf("install failed: %w", err)
}
logger.Waitingf("verifying installation")
if err := statusChecker.Assess(components...); err != nil {
return fmt.Errorf("install failed")
}
return nil
}
@@ -248,7 +270,7 @@ func shouldCreateDeployKey(ctx context.Context, kubeClient client.Client, namesp
}
func generateDeployKey(ctx context.Context, kubeClient client.Client, url *url.URL, namespace string) (string, error) {
pair, err := generateKeyPair(ctx, sourceArgs.GitKeyAlgorithm, sourceArgs.GitRSABits, sourceArgs.GitECDSACurve)
pair, err := generateKeyPair(ctx, sourceGitArgs.keyAlgorithm, sourceGitArgs.keyRSABits, sourceGitArgs.keyECDSACurve)
if err != nil {
return "", err
}

View File

@@ -94,8 +94,8 @@ func init() {
bootstrapGitHubCmd.Flags().StringVar(&githubArgs.owner, "owner", "", "GitHub user or organization name")
bootstrapGitHubCmd.Flags().StringVar(&githubArgs.repository, "repository", "", "GitHub repository name")
bootstrapGitHubCmd.Flags().StringArrayVar(&githubArgs.teams, "team", []string{}, "GitHub team to be given maintainer access")
bootstrapGitHubCmd.Flags().BoolVar(&githubArgs.personal, "personal", false, "is personal repository")
bootstrapGitHubCmd.Flags().BoolVar(&githubArgs.private, "private", true, "is private repository")
bootstrapGitHubCmd.Flags().BoolVar(&githubArgs.personal, "personal", false, "if true, the owner is assumed to be a GitHub user; otherwise an org")
bootstrapGitHubCmd.Flags().BoolVar(&githubArgs.private, "private", true, "if true, the repository is assumed to be private")
bootstrapGitHubCmd.Flags().DurationVar(&githubArgs.interval, "interval", time.Minute, "sync interval")
bootstrapGitHubCmd.Flags().StringVar(&githubArgs.hostname, "hostname", git.GitHubDefaultHostname, "GitHub hostname")
bootstrapGitHubCmd.Flags().StringVar(&githubArgs.sshHostname, "ssh-hostname", "", "GitHub SSH hostname, to be used when the SSH host differs from the HTTPS one")
@@ -125,13 +125,25 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
return err
}
usedPath, bootstrapPathDiffers := checkIfBootstrapPathDiffers(ctx, kubeClient, rootArgs.namespace, filepath.ToSlash(githubArgs.path.String()))
usedPath, bootstrapPathDiffers := checkIfBootstrapPathDiffers(
ctx,
kubeClient,
rootArgs.namespace,
filepath.ToSlash(githubArgs.path.String()),
)
if bootstrapPathDiffers {
return fmt.Errorf("cluster already bootstrapped to %v path", usedPath)
}
repository, err := git.NewRepository(githubArgs.repository, githubArgs.owner, githubArgs.hostname, ghToken, "flux", githubArgs.owner+"@users.noreply.github.com")
repository, err := git.NewRepository(
githubArgs.repository,
githubArgs.owner,
githubArgs.hostname,
ghToken,
"flux",
githubArgs.owner+"@users.noreply.github.com",
)
if err != nil {
return err
}
@@ -190,13 +202,22 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
// generate install manifests
logger.Generatef("generating manifests")
installManifest, err := generateInstallManifests(githubArgs.path.String(), rootArgs.namespace, tmpDir, bootstrapArgs.manifestsPath)
installManifest, err := generateInstallManifests(
githubArgs.path.String(),
rootArgs.namespace,
tmpDir,
bootstrapArgs.manifestsPath,
)
if err != nil {
return err
}
// stage install manifests
changed, err = repository.Commit(ctx, path.Join(githubArgs.path.String(), rootArgs.namespace), "Add manifests")
changed, err = repository.Commit(
ctx,
path.Join(githubArgs.path.String(), rootArgs.namespace),
fmt.Sprintf("Add flux %s components manifests", bootstrapArgs.version),
)
if err != nil {
return err
}
@@ -270,13 +291,25 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
// configure repo synchronization
logger.Actionf("generating sync manifests")
syncManifests, err := generateSyncManifests(repoURL, bootstrapArgs.branch, rootArgs.namespace, rootArgs.namespace, filepath.ToSlash(githubArgs.path.String()), tmpDir, githubArgs.interval)
syncManifests, err := generateSyncManifests(
repoURL,
bootstrapArgs.branch,
rootArgs.namespace,
rootArgs.namespace,
filepath.ToSlash(githubArgs.path.String()),
tmpDir,
githubArgs.interval,
)
if err != nil {
return err
}
// commit and push manifests
if changed, err = repository.Commit(ctx, path.Join(githubArgs.path.String(), rootArgs.namespace), "Add manifests"); err != nil {
if changed, err = repository.Commit(
ctx,
path.Join(githubArgs.path.String(), rootArgs.namespace),
fmt.Sprintf("Add flux %s sync manifests", bootstrapArgs.version),
); err != nil {
return err
} else if changed {
if err := repository.Push(ctx); err != nil {

View File

@@ -89,8 +89,8 @@ var gitlabArgs gitlabFlags
func init() {
bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.owner, "owner", "", "GitLab user or group name")
bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.repository, "repository", "", "GitLab repository name")
bootstrapGitLabCmd.Flags().BoolVar(&gitlabArgs.personal, "personal", false, "is personal repository")
bootstrapGitLabCmd.Flags().BoolVar(&gitlabArgs.private, "private", true, "is private repository")
bootstrapGitLabCmd.Flags().BoolVar(&gitlabArgs.personal, "personal", false, "if true, the owner is assumed to be a GitLab user; otherwise a group")
bootstrapGitLabCmd.Flags().BoolVar(&gitlabArgs.private, "private", true, "if true, the repository is assumed to be private")
bootstrapGitLabCmd.Flags().DurationVar(&gitlabArgs.interval, "interval", time.Minute, "sync interval")
bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.hostname, "hostname", git.GitLabDefaultHostname, "GitLab hostname")
bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.sshHostname, "ssh-hostname", "", "GitLab SSH hostname, to be used when the SSH host differs from the HTTPS one")
@@ -131,7 +131,14 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("cluster already bootstrapped to %v path", usedPath)
}
repository, err := git.NewRepository(gitlabArgs.repository, gitlabArgs.owner, gitlabArgs.hostname, glToken, "flux", gitlabArgs.owner+"@users.noreply.gitlab.com")
repository, err := git.NewRepository(
gitlabArgs.repository,
gitlabArgs.owner,
gitlabArgs.hostname,
glToken,
"flux",
gitlabArgs.owner+"@users.noreply.gitlab.com",
)
if err != nil {
return err
}
@@ -169,13 +176,22 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
// generate install manifests
logger.Generatef("generating manifests")
installManifest, err := generateInstallManifests(gitlabArgs.path.String(), rootArgs.namespace, tmpDir, bootstrapArgs.manifestsPath)
installManifest, err := generateInstallManifests(
gitlabArgs.path.String(),
rootArgs.namespace,
tmpDir,
bootstrapArgs.manifestsPath,
)
if err != nil {
return err
}
// stage install manifests
changed, err = repository.Commit(ctx, path.Join(gitlabArgs.path.String(), rootArgs.namespace), "Add manifests")
changed, err = repository.Commit(
ctx,
path.Join(gitlabArgs.path.String(), rootArgs.namespace),
fmt.Sprintf("Add flux %s components manifests", bootstrapArgs.version),
)
if err != nil {
return err
}
@@ -249,13 +265,25 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
// configure repo synchronization
logger.Actionf("generating sync manifests")
syncManifests, err := generateSyncManifests(repoURL, bootstrapArgs.branch, rootArgs.namespace, rootArgs.namespace, filepath.ToSlash(gitlabArgs.path.String()), tmpDir, gitlabArgs.interval)
syncManifests, err := generateSyncManifests(
repoURL,
bootstrapArgs.branch,
rootArgs.namespace,
rootArgs.namespace,
filepath.ToSlash(gitlabArgs.path.String()),
tmpDir,
gitlabArgs.interval,
)
if err != nil {
return err
}
// commit and push manifests
if changed, err = repository.Commit(ctx, path.Join(gitlabArgs.path.String(), rootArgs.namespace), "Add manifests"); err != nil {
if changed, err = repository.Commit(
ctx,
path.Join(gitlabArgs.path.String(), rootArgs.namespace),
fmt.Sprintf("Add flux %s sync manifests", bootstrapArgs.version),
); err != nil {
return err
} else if changed {
if err := repository.Push(ctx); err != nil {

View File

@@ -21,13 +21,19 @@ import (
"encoding/json"
"os"
"os/exec"
"strings"
"time"
"github.com/blang/semver/v4"
"github.com/fluxcd/flux2/internal/utils"
"github.com/Masterminds/semver/v3"
"github.com/spf13/cobra"
v1 "k8s.io/api/apps/v1"
apimachineryversion "k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/kubernetes"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/pkg/version"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/install"
)
var checkCmd = &cobra.Command{
@@ -45,8 +51,9 @@ the local environment is configured correctly and if the installed components ar
}
type checkFlags struct {
pre bool
components []string
pre bool
components []string
extraComponents []string
}
type kubectlVersion struct {
@@ -60,6 +67,8 @@ func init() {
"only run pre-installation checks")
checkCmd.Flags().StringSliceVar(&checkArgs.components, "components", rootArgs.defaults.Components,
"list of components, accepts comma-separated values")
checkCmd.Flags().StringSliceVar(&checkArgs.extraComponents, "components-extra", nil,
"list of components in addition to those supplied or defaulted, accepts comma-separated values")
rootCmd.AddCommand(checkCmd)
}
@@ -70,11 +79,13 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
logger.Actionf("checking prerequisites")
checkFailed := false
if !kubectlCheck(ctx, ">=1.18.0") {
fluxCheck()
if !kubectlCheck(ctx, ">=1.18.0-0") {
checkFailed = true
}
if !kubernetesCheck(">=1.16.0") {
if !kubernetesCheck(">=1.16.0-0") {
checkFailed = true
}
@@ -97,7 +108,29 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
return nil
}
func kubectlCheck(ctx context.Context, version string) bool {
func fluxCheck() {
curSv, err := version.ParseVersion(VERSION)
if err != nil {
return
}
// Exclude development builds.
if curSv.Prerelease() != "" {
return
}
latest, err := install.GetLatestVersion()
if err != nil {
return
}
latestSv, err := version.ParseVersion(latest)
if err != nil {
return
}
if latestSv.GreaterThan(curSv) {
logger.Failuref("flux %s <%s (new version is available, please upgrade)", curSv, latestSv)
}
}
func kubectlCheck(ctx context.Context, constraint string) bool {
_, err := exec.LookPath("kubectl")
if err != nil {
logger.Failuref("kubectl not found")
@@ -113,58 +146,58 @@ func kubectlCheck(ctx context.Context, version string) bool {
kv := &kubectlVersion{}
if err = json.Unmarshal([]byte(output), kv); err != nil {
logger.Failuref("kubectl version output can't be unmarshaled")
logger.Failuref("kubectl version output can't be unmarshalled")
return false
}
v, err := semver.ParseTolerant(kv.ClientVersion.GitVersion)
v, err := version.ParseVersion(kv.ClientVersion.GitVersion)
if err != nil {
logger.Failuref("kubectl version can't be parsed")
return false
}
rng, _ := semver.ParseRange(version)
if !rng(v) {
logger.Failuref("kubectl version must be %s", version)
c, _ := semver.NewConstraint(constraint)
if !c.Check(v) {
logger.Failuref("kubectl version %s < %s", v.Original(), constraint)
return false
}
logger.Successf("kubectl %s %s", v.String(), version)
logger.Successf("kubectl %s %s", v.String(), constraint)
return true
}
func kubernetesCheck(version string) bool {
func kubernetesCheck(constraint string) bool {
cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
return false
}
client, err := kubernetes.NewForConfig(cfg)
clientSet, err := kubernetes.NewForConfig(cfg)
if err != nil {
logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
return false
}
ver, err := client.Discovery().ServerVersion()
kv, err := clientSet.Discovery().ServerVersion()
if err != nil {
logger.Failuref("Kubernetes API call failed: %s", err.Error())
return false
}
v, err := semver.ParseTolerant(ver.String())
v, err := version.ParseVersion(kv.String())
if err != nil {
logger.Failuref("Kubernetes version can't be determined")
return false
}
rng, _ := semver.ParseRange(version)
if !rng(v) {
logger.Failuref("Kubernetes version must be %s", version)
c, _ := semver.NewConstraint(constraint)
if !c.Check(v) {
logger.Failuref("Kubernetes version %s < %s", v.Original(), constraint)
return false
}
logger.Successf("Kubernetes %s %s", v.String(), version)
logger.Successf("Kubernetes %s %s", v.String(), constraint)
return true
}
@@ -172,18 +205,29 @@ func componentsCheck() bool {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return false
}
statusChecker, err := NewStatusChecker(time.Second, rootArgs.timeout)
if err != nil {
return false
}
ok := true
for _, deployment := range checkArgs.components {
kubectlArgs := []string{"-n", rootArgs.namespace, "rollout", "status", "deployment", deployment, "--timeout", rootArgs.timeout.String()}
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
logger.Failuref("%s: %s", deployment, strings.TrimSuffix(output, "\n"))
ok = false
} else {
logger.Successf("%s is healthy", deployment)
}
kubectlArgs = []string{"-n", rootArgs.namespace, "get", "deployment", deployment, "-o", "jsonpath=\"{..image}\""}
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err == nil {
logger.Actionf(strings.TrimPrefix(strings.TrimSuffix(output, "\""), "\""))
selector := client.MatchingLabels{"app.kubernetes.io/instance": rootArgs.namespace}
var list v1.DeploymentList
if err := kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace), selector); err == nil {
for _, d := range list.Items {
if err := statusChecker.Assess(d.Name); err != nil {
ok = false
} else {
logger.Successf("%s: healthy", d.Name)
}
for _, c := range d.Spec.Template.Spec.Containers {
logger.Actionf(c.Image)
}
}
}
return ok

View File

@@ -18,12 +18,14 @@ package main
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/transform"
"github.com/spf13/cobra"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@@ -62,11 +64,12 @@ var createHelmReleaseCmd = &cobra.Command{
--source=Bucket/podinfo \
--chart=./charts/podinfo
# Create a HelmRelease with values from a local YAML file
# Create a HelmRelease with values from local YAML files
flux create hr podinfo \
--source=HelmRepository/podinfo \
--chart=podinfo \
--values=./my-values.yaml
--values=./my-values1.yaml \
--values=./my-values2.yaml
# Create a HelmRelease with values from a Kubernetes secret
kubectl -n app create secret generic my-secret-values \
@@ -105,7 +108,7 @@ type helmReleaseFlags struct {
chart string
chartVersion string
targetNamespace string
valuesFile string
valuesFile []string
valuesFrom flags.HelmReleaseValuesFrom
saName string
}
@@ -120,7 +123,7 @@ func init() {
createHelmReleaseCmd.Flags().StringArrayVar(&helmReleaseArgs.dependsOn, "depends-on", nil, "HelmReleases that must be ready before this release can be installed, supported formats '<name>' and '<namespace>/<name>'")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.targetNamespace, "target-namespace", "", "namespace to install this release, defaults to the HelmRelease namespace")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.saName, "service-account", "", "the name of the service account to impersonate when reconciling this HelmRelease")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.valuesFile, "values", "", "local path to the values.yaml file")
createHelmReleaseCmd.Flags().StringArrayVar(&helmReleaseArgs.valuesFile, "values", nil, "local path to values.yaml files")
createHelmReleaseCmd.Flags().Var(&helmReleaseArgs.valuesFrom, "values-from", helmReleaseArgs.valuesFrom.Description())
createCmd.AddCommand(createHelmReleaseCmd)
}
@@ -175,18 +178,37 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
helmRelease.Spec.ServiceAccountName = helmReleaseArgs.saName
}
if helmReleaseArgs.valuesFile != "" {
data, err := ioutil.ReadFile(helmReleaseArgs.valuesFile)
if err != nil {
return fmt.Errorf("reading values from %s failed: %w", helmReleaseArgs.valuesFile, err)
if len(helmReleaseArgs.valuesFile) > 0 {
var valuesMap map[string]interface{}
for _, v := range helmReleaseArgs.valuesFile {
data, err := ioutil.ReadFile(v)
if err != nil {
return fmt.Errorf("reading values from %s failed: %w", v, err)
}
jsonBytes, err := yaml.YAMLToJSON(data)
if err != nil {
return fmt.Errorf("converting values to JSON from %s failed: %w", v, err)
}
jsonMap := make(map[string]interface{})
if err := json.Unmarshal(jsonBytes, &jsonMap); err != nil {
return fmt.Errorf("unmarshaling values from %s failed: %w", v, err)
}
if valuesMap == nil {
valuesMap = jsonMap
} else {
valuesMap = transform.MergeMaps(valuesMap, jsonMap)
}
}
json, err := yaml.YAMLToJSON(data)
jsonRaw, err := json.Marshal(valuesMap)
if err != nil {
return fmt.Errorf("converting values to JSON from %s failed: %w", helmReleaseArgs.valuesFile, err)
return fmt.Errorf("marshaling values failed: %w", err)
}
helmRelease.Spec.Values = &apiextensionsv1.JSON{Raw: json}
helmRelease.Spec.Values = &apiextensionsv1.JSON{Raw: jsonRaw}
}
if helmReleaseArgs.valuesFrom.String() != "" {

View File

@@ -18,6 +18,10 @@ package main
import (
"fmt"
"regexp/syntax"
"strings"
"unicode"
"unicode/utf8"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -39,9 +43,13 @@ the status of the object.`,
RunE: createImagePolicyRun}
type imagePolicyFlags struct {
imageRef string
semver string
filterRegex string
imageRef string
semver string
alpha string
numeric string
filterRegex string
filterExtract string
filterNumerical string
}
var imagePolicyArgs = imagePolicyFlags{}
@@ -49,8 +57,11 @@ var imagePolicyArgs = imagePolicyFlags{}
func init() {
flags := createImagePolicyCmd.Flags()
flags.StringVar(&imagePolicyArgs.imageRef, "image-ref", "", "the name of an image repository object")
flags.StringVar(&imagePolicyArgs.semver, "semver", "", "a semver range to apply to tags; e.g., '1.x'")
flags.StringVar(&imagePolicyArgs.filterRegex, "filter-regex", "", " regular expression pattern used to filter the image tags")
flags.StringVar(&imagePolicyArgs.semver, "select-semver", "", "a semver range to apply to tags; e.g., '1.x'")
flags.StringVar(&imagePolicyArgs.alpha, "select-alpha", "", "use alphabetical sorting to select image; either \"asc\" meaning select the last, or \"desc\" meaning select the first")
flags.StringVar(&imagePolicyArgs.numeric, "select-numeric", "", "use numeric sorting to select image; either \"asc\" meaning select the last, or \"desc\" meaning select the first")
flags.StringVar(&imagePolicyArgs.filterRegex, "filter-regex", "", "regular expression pattern used to filter the image tags")
flags.StringVar(&imagePolicyArgs.filterExtract, "filter-extract", "", "replacement pattern (using capture groups from --filter-regex) to use for sorting")
createImageCmd.AddCommand(createImagePolicyCmd)
}
@@ -90,18 +101,49 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
}
switch {
case imagePolicyArgs.semver != "" && imagePolicyArgs.alpha != "":
case imagePolicyArgs.semver != "" && imagePolicyArgs.numeric != "":
case imagePolicyArgs.alpha != "" && imagePolicyArgs.numeric != "":
return fmt.Errorf("only one of --select-semver, --select-alpha or --select-numeric can be specified")
case imagePolicyArgs.semver != "":
policy.Spec.Policy.SemVer = &imagev1.SemVerPolicy{
Range: imagePolicyArgs.semver,
}
case imagePolicyArgs.alpha != "":
if imagePolicyArgs.alpha != "desc" && imagePolicyArgs.alpha != "asc" {
return fmt.Errorf("--select-alpha must be one of [\"asc\", \"desc\"]")
}
policy.Spec.Policy.Alphabetical = &imagev1.AlphabeticalPolicy{
Order: imagePolicyArgs.alpha,
}
case imagePolicyArgs.numeric != "":
if imagePolicyArgs.numeric != "desc" && imagePolicyArgs.numeric != "asc" {
return fmt.Errorf("--select-numeric must be one of [\"asc\", \"desc\"]")
}
policy.Spec.Policy.Numerical = &imagev1.NumericalPolicy{
Order: imagePolicyArgs.numeric,
}
default:
return fmt.Errorf("a policy must be provided with --semver")
return fmt.Errorf("a policy must be provided with either --select-semver or --select-alpha")
}
if imagePolicyArgs.filterRegex != "" {
exp, err := syntax.Parse(imagePolicyArgs.filterRegex, syntax.Perl)
if err != nil {
return fmt.Errorf("--filter-regex is an invalid regex pattern")
}
policy.Spec.FilterTags = &imagev1.TagFilter{
Pattern: imagePolicyArgs.filterRegex,
}
if imagePolicyArgs.filterExtract != "" {
if err := validateExtractStr(imagePolicyArgs.filterExtract, exp.CapNames()); err != nil {
return err
}
policy.Spec.FilterTags.Extract = imagePolicyArgs.filterExtract
}
} else if imagePolicyArgs.filterExtract != "" {
return fmt.Errorf("cannot specify --filter-extract without specifying --filter-regex")
}
if createArgs.export {
@@ -117,3 +159,94 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
})
return err
}
// Performs a dry-run of the extract function in Regexp to validate the template
func validateExtractStr(template string, capNames []string) error {
for len(template) > 0 {
i := strings.Index(template, "$")
if i < 0 {
return nil
}
template = template[i:]
if len(template) > 1 && template[1] == '$' {
template = template[2:]
continue
}
name, num, rest, ok := extract(template)
if !ok {
// Malformed extract string, assume user didn't want this
template = template[1:]
return fmt.Errorf("--filter-extract is malformed")
}
template = rest
if num >= 0 {
// we won't worry about numbers as we can't validate these
continue
} else {
found := false
for _, capName := range capNames {
if name == capName {
found = true
}
}
if !found {
return fmt.Errorf("capture group $%s used in --filter-extract not found in --filter-regex", name)
}
}
}
return nil
}
// extract method from the regexp package
// returns the name or number of the value prepended by $
func extract(str string) (name string, num int, rest string, ok bool) {
if len(str) < 2 || str[0] != '$' {
return
}
brace := false
if str[1] == '{' {
brace = true
str = str[2:]
} else {
str = str[1:]
}
i := 0
for i < len(str) {
rune, size := utf8.DecodeRuneInString(str[i:])
if !unicode.IsLetter(rune) && !unicode.IsDigit(rune) && rune != '_' {
break
}
i += size
}
if i == 0 {
// empty name is not okay
return
}
name = str[:i]
if brace {
if i >= len(str) || str[i] != '}' {
// missing closing brace
return
}
i++
}
// Parse number.
num = 0
for i := 0; i < len(name); i++ {
if name[i] < '0' || '9' < name[i] || num >= 1e8 {
num = -1
break
}
num = num*10 + int(name[i]) - '0'
}
// Disallow leading zeros.
if name[0] == '0' && len(name) > 1 {
num = -1
}
rest = str[i:]
ok = true
return
}

View File

@@ -34,13 +34,39 @@ var createImageRepositoryCmd = &cobra.Command{
Short: "Create or update an ImageRepository object",
Long: `The create image repository command generates an ImageRepository resource.
An ImageRepository object specifies an image repository to scan.`,
Example: ` # Create an ImageRepository object to scan the alpine image repository:
flux create image repository alpine-repo --image alpine --interval 20m
# Create an image repository that uses an image pull secret (assumed to
# have been created already):
flux create image repository myapp-repo \
--secret-ref image-pull \
--image ghcr.io/example.com/myapp --interval 5m
# Create a TLS secret for a local image registry using a self-signed
# host certificate, and use it to scan an image. ca.pem is a file
# containing the CA certificate used to sign the host certificate.
flux create secret tls local-registry-cert --ca-file ./ca.pem
flux create image repository app-repo \
--cert-secret-ref local-registry-cert \
--image local-registry:5000/app --interval 5m
# Create a TLS secret with a client certificate and key, and use it
# to scan a private image registry.
flux create secret tls client-cert \
--cert-file client.crt --key-file client.key
flux create image repository app-repo \
--cert-secret-ref client-cert \
--image registry.example.com/private/app --interval 5m
`,
RunE: createImageRepositoryRun,
}
type imageRepoFlags struct {
image string
secretRef string
timeout time.Duration
image string
secretRef string
certSecretRef string
timeout time.Duration
}
var imageRepoArgs = imageRepoFlags{}
@@ -49,6 +75,7 @@ func init() {
flags := createImageRepositoryCmd.Flags()
flags.StringVar(&imageRepoArgs.image, "image", "", "the image repository to scan; e.g., library/alpine")
flags.StringVar(&imageRepoArgs.secretRef, "secret-ref", "", "the name of a docker-registry secret to use for credentials")
flags.StringVar(&imageRepoArgs.certSecretRef, "cert-ref", "", "the name of a secret to use for TLS certificates")
// NB there is already a --timeout in the global flags, for
// controlling timeout on operations while e.g., creating objects.
flags.DurationVar(&imageRepoArgs.timeout, "scan-timeout", 0, "a timeout for scanning; this defaults to the interval if not set")
@@ -94,6 +121,11 @@ func createImageRepositoryRun(cmd *cobra.Command, args []string) error {
Name: imageRepoArgs.secretRef,
}
}
if imageRepoArgs.certSecretRef != "" {
repo.Spec.CertSecretRef = &meta.LocalObjectReference{
Name: imageRepoArgs.certSecretRef,
}
}
if createArgs.export {
return printExport(exportImageRepository(&repo))

View File

@@ -70,7 +70,7 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
}
if imageUpdateArgs.branch == "" {
return fmt.Errorf("the Git repoistory branch is required (--branch)")
return fmt.Errorf("the Git repository branch is required (--branch)")
}
labels, err := parseLabels()

View File

@@ -39,6 +39,23 @@ func init() {
createCmd.AddCommand(createSecretCmd)
}
func makeSecret(name string) (corev1.Secret, error) {
secretLabels, err := parseLabels()
if err != nil {
return corev1.Secret{}, err
}
return corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: rootArgs.namespace,
Labels: secretLabels,
},
StringData: map[string]string{},
Data: nil,
}, nil
}
func upsertSecret(ctx context.Context, kubeClient client.Client, secret corev1.Secret) error {
namespacedName := types.NamespacedName{
Namespace: secret.GetNamespace(),

View File

@@ -20,12 +20,11 @@ import (
"context"
"crypto/elliptic"
"fmt"
"io/ioutil"
"net/url"
"time"
"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"
@@ -78,6 +77,7 @@ type secretGitFlags struct {
keyAlgorithm flags.PublicKeyAlgorithm
rsaBits flags.RSAKeyBits
ecdsaCurve flags.ECDSACurve
caFile string
}
var secretGitArgs = NewSecretGitFlags()
@@ -89,6 +89,7 @@ func init() {
createSecretGitCmd.Flags().Var(&secretGitArgs.keyAlgorithm, "ssh-key-algorithm", secretGitArgs.keyAlgorithm.Description())
createSecretGitCmd.Flags().Var(&secretGitArgs.rsaBits, "ssh-rsa-bits", secretGitArgs.rsaBits.Description())
createSecretGitCmd.Flags().Var(&secretGitArgs.ecdsaCurve, "ssh-ecdsa-curve", secretGitArgs.ecdsaCurve.Description())
createSecretGitCmd.Flags().StringVar(&secretGitArgs.caFile, "ca-file", "", "path to TLS CA file used for validating self-signed certificates")
createSecretCmd.AddCommand(createSecretGitCmd)
}
@@ -106,6 +107,10 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("secret name is required")
}
name := args[0]
secret, err := makeSecret(name)
if err != nil {
return err
}
if secretGitArgs.url == "" {
return fmt.Errorf("url is required")
@@ -116,22 +121,9 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("git URL parse failed: %w", err)
}
secretLabels, err := parseLabels()
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: rootArgs.namespace,
Labels: secretLabels,
},
}
switch u.Scheme {
case "ssh":
pair, err := generateKeyPair(ctx, secretGitArgs.keyAlgorithm, secretGitArgs.rsaBits, secretGitArgs.ecdsaCurve)
@@ -144,10 +136,10 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
return err
}
secret.Data = map[string][]byte{
"identity": pair.PrivateKey,
"identity.pub": pair.PublicKey,
"known_hosts": hostKey,
secret.StringData = map[string]string{
"identity": string(pair.PrivateKey),
"identity.pub": string(pair.PublicKey),
"known_hosts": string(hostKey),
}
if !createArgs.export {
@@ -158,11 +150,19 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
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(secretGitArgs.username),
"password": []byte(secretGitArgs.password),
secret.StringData = map[string]string{
"username": secretGitArgs.username,
"password": secretGitArgs.password,
}
if secretGitArgs.caFile != "" {
ca, err := ioutil.ReadFile(secretGitArgs.caFile)
if err != nil {
return fmt.Errorf("failed to read CA file '%s': %w", secretGitArgs.caFile, err)
}
secret.StringData["caFile"] = string(ca)
}
default:
return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme)
}

View File

@@ -19,11 +19,8 @@ package main
import (
"context"
"fmt"
"io/ioutil"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/flux2/internal/utils"
)
@@ -58,9 +55,7 @@ The create secret helm command generates a Kubernetes secret with basic authenti
type secretHelmFlags struct {
username string
password string
certFile string
keyFile string
caFile string
secretTLSFlags
}
var secretHelmArgs secretHelmFlags
@@ -68,10 +63,7 @@ var secretHelmArgs secretHelmFlags
func init() {
createSecretHelmCmd.Flags().StringVarP(&secretHelmArgs.username, "username", "u", "", "basic authentication username")
createSecretHelmCmd.Flags().StringVarP(&secretHelmArgs.password, "password", "p", "", "basic authentication password")
createSecretHelmCmd.Flags().StringVar(&secretHelmArgs.certFile, "cert-file", "", "TLS authentication cert file path")
createSecretHelmCmd.Flags().StringVar(&secretHelmArgs.keyFile, "key-file", "", "TLS authentication key file path")
createSecretHelmCmd.Flags().StringVar(&secretHelmArgs.caFile, "ca-file", "", "TLS authentication CA file path")
initSecretTLSFlags(createSecretHelmCmd.Flags(), &secretHelmArgs.secretTLSFlags)
createSecretCmd.AddCommand(createSecretHelmCmd)
}
@@ -80,46 +72,18 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("secret name is required")
}
name := args[0]
secretLabels, err := parseLabels()
secret, err := makeSecret(name)
if err != nil {
return err
}
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: rootArgs.namespace,
Labels: secretLabels,
},
StringData: map[string]string{},
}
if secretHelmArgs.username != "" && secretHelmArgs.password != "" {
secret.StringData["username"] = secretHelmArgs.username
secret.StringData["password"] = secretHelmArgs.password
}
if secretHelmArgs.certFile != "" && secretHelmArgs.keyFile != "" {
cert, err := ioutil.ReadFile(secretHelmArgs.certFile)
if err != nil {
return fmt.Errorf("failed to read repository cert file '%s': %w", secretHelmArgs.certFile, err)
}
secret.StringData["certFile"] = string(cert)
key, err := ioutil.ReadFile(secretHelmArgs.keyFile)
if err != nil {
return fmt.Errorf("failed to read repository key file '%s': %w", secretHelmArgs.keyFile, err)
}
secret.StringData["keyFile"] = string(key)
}
if secretHelmArgs.caFile != "" {
ca, err := ioutil.ReadFile(secretHelmArgs.caFile)
if err != nil {
return fmt.Errorf("failed to read repository CA file '%s': %w", secretHelmArgs.caFile, err)
}
secret.StringData["caFile"] = string(ca)
if err = populateSecretTLS(&secret, secretHelmArgs.secretTLSFlags); err != nil {
return err
}
if createArgs.export {

View File

@@ -0,0 +1,128 @@
/*
Copyright 2020, 2021 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"fmt"
"io/ioutil"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
corev1 "k8s.io/api/core/v1"
"github.com/fluxcd/flux2/internal/utils"
)
var createSecretTLSCmd = &cobra.Command{
Use: "tls [name]",
Short: "Create or update a Kubernetes secret with TLS certificates",
Long: `
The create secret tls command generates a Kubernetes secret with certificates for use with TLS.`,
Example: `
# Create a TLS secret on disk and encrypt it with Mozilla SOPS.
# Files are expected to be PEM-encoded.
flux create secret tls certs \
--namespace=my-namespace \
--cert-file=./client.crt \
--key-file=./client.key \
--export > certs.yaml
sops --encrypt --encrypted-regex '^(data|stringData)$' \
--in-place certs.yaml
`,
RunE: createSecretTLSCmdRun,
}
type secretTLSFlags struct {
certFile string
keyFile string
caFile string
}
var secretTLSArgs secretTLSFlags
func initSecretTLSFlags(flags *pflag.FlagSet, args *secretTLSFlags) {
flags.StringVar(&args.certFile, "cert-file", "", "TLS authentication cert file path")
flags.StringVar(&args.keyFile, "key-file", "", "TLS authentication key file path")
flags.StringVar(&args.caFile, "ca-file", "", "TLS authentication CA file path")
}
func init() {
flags := createSecretTLSCmd.Flags()
initSecretTLSFlags(flags, &secretTLSArgs)
createSecretCmd.AddCommand(createSecretTLSCmd)
}
func populateSecretTLS(secret *corev1.Secret, args secretTLSFlags) error {
if args.certFile != "" && args.keyFile != "" {
cert, err := ioutil.ReadFile(args.certFile)
if err != nil {
return fmt.Errorf("failed to read repository cert file '%s': %w", args.certFile, err)
}
secret.StringData["certFile"] = string(cert)
key, err := ioutil.ReadFile(args.keyFile)
if err != nil {
return fmt.Errorf("failed to read repository key file '%s': %w", args.keyFile, err)
}
secret.StringData["keyFile"] = string(key)
}
if args.caFile != "" {
ca, err := ioutil.ReadFile(args.caFile)
if err != nil {
return fmt.Errorf("failed to read repository CA file '%s': %w", args.caFile, err)
}
secret.StringData["caFile"] = string(ca)
}
return nil
}
func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("secret name is required")
}
name := args[0]
secret, err := makeSecret(name)
if err != nil {
return err
}
if err = populateSecretTLS(&secret, secretTLSArgs); err != nil {
return err
}
if createArgs.export {
return exportSecret(secret)
}
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err
}
logger.Actionf("secret '%s' created in '%s' namespace", name, rootArgs.namespace)
return nil
}

View File

@@ -41,19 +41,19 @@ import (
"github.com/fluxcd/flux2/internal/utils"
)
type SourceGitFlags struct {
GitURL string
GitBranch string
GitTag string
GitSemver string
GitUsername string
GitPassword string
GitKeyAlgorithm flags.PublicKeyAlgorithm
GitRSABits flags.RSAKeyBits
GitECDSACurve flags.ECDSACurve
GitSecretRef string
GitImplementation flags.GitImplementation
type sourceGitFlags struct {
url string
branch string
tag string
semver string
username string
password string
caFile string
keyAlgorithm flags.PublicKeyAlgorithm
keyRSABits flags.RSAKeyBits
keyECDSACurve flags.ECDSACurve
secretRef string
gitImplementation flags.GitImplementation
}
var createSourceGitCmd = &cobra.Command{
@@ -100,29 +100,30 @@ For private Git repositories, the basic authentication credentials are stored in
RunE: createSourceGitCmdRun,
}
var sourceArgs = NewSourceGitFlags()
var sourceGitArgs = newSourceGitFlags()
func init() {
createSourceGitCmd.Flags().StringVar(&sourceArgs.GitURL, "url", "", "git address, e.g. ssh://git@host/org/repository")
createSourceGitCmd.Flags().StringVar(&sourceArgs.GitBranch, "branch", "master", "git branch")
createSourceGitCmd.Flags().StringVar(&sourceArgs.GitTag, "tag", "", "git tag")
createSourceGitCmd.Flags().StringVar(&sourceArgs.GitSemver, "tag-semver", "", "git tag semver range")
createSourceGitCmd.Flags().StringVarP(&sourceArgs.GitUsername, "username", "u", "", "basic authentication username")
createSourceGitCmd.Flags().StringVarP(&sourceArgs.GitPassword, "password", "p", "", "basic authentication password")
createSourceGitCmd.Flags().Var(&sourceArgs.GitKeyAlgorithm, "ssh-key-algorithm", sourceArgs.GitKeyAlgorithm.Description())
createSourceGitCmd.Flags().Var(&sourceArgs.GitRSABits, "ssh-rsa-bits", sourceArgs.GitRSABits.Description())
createSourceGitCmd.Flags().Var(&sourceArgs.GitECDSACurve, "ssh-ecdsa-curve", sourceArgs.GitECDSACurve.Description())
createSourceGitCmd.Flags().StringVarP(&sourceArgs.GitSecretRef, "secret-ref", "", "", "the name of an existing secret containing SSH or basic credentials")
createSourceGitCmd.Flags().Var(&sourceArgs.GitImplementation, "git-implementation", sourceArgs.GitImplementation.Description())
createSourceGitCmd.Flags().StringVar(&sourceGitArgs.url, "url", "", "git address, e.g. ssh://git@host/org/repository")
createSourceGitCmd.Flags().StringVar(&sourceGitArgs.branch, "branch", "master", "git branch")
createSourceGitCmd.Flags().StringVar(&sourceGitArgs.tag, "tag", "", "git tag")
createSourceGitCmd.Flags().StringVar(&sourceGitArgs.semver, "tag-semver", "", "git tag semver range")
createSourceGitCmd.Flags().StringVarP(&sourceGitArgs.username, "username", "u", "", "basic authentication username")
createSourceGitCmd.Flags().StringVarP(&sourceGitArgs.password, "password", "p", "", "basic authentication password")
createSourceGitCmd.Flags().Var(&sourceGitArgs.keyAlgorithm, "ssh-key-algorithm", sourceGitArgs.keyAlgorithm.Description())
createSourceGitCmd.Flags().Var(&sourceGitArgs.keyRSABits, "ssh-rsa-bits", sourceGitArgs.keyRSABits.Description())
createSourceGitCmd.Flags().Var(&sourceGitArgs.keyECDSACurve, "ssh-ecdsa-curve", sourceGitArgs.keyECDSACurve.Description())
createSourceGitCmd.Flags().StringVar(&sourceGitArgs.secretRef, "secret-ref", "", "the name of an existing secret containing SSH or basic credentials")
createSourceGitCmd.Flags().Var(&sourceGitArgs.gitImplementation, "git-implementation", sourceGitArgs.gitImplementation.Description())
createSourceGitCmd.Flags().StringVar(&sourceGitArgs.caFile, "ca-file", "", "path to TLS CA file used for validating self-signed certificates, requires libgit2")
createSourceCmd.AddCommand(createSourceGitCmd)
}
func NewSourceGitFlags() SourceGitFlags {
return SourceGitFlags{
GitKeyAlgorithm: "rsa",
GitRSABits: 2048,
GitECDSACurve: flags.ECDSACurve{Curve: elliptic.P384()},
func newSourceGitFlags() sourceGitFlags {
return sourceGitFlags{
keyAlgorithm: "rsa",
keyRSABits: 2048,
keyECDSACurve: flags.ECDSACurve{Curve: elliptic.P384()},
}
}
@@ -132,17 +133,21 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
}
name := args[0]
if sourceArgs.GitURL == "" {
if sourceGitArgs.url == "" {
return fmt.Errorf("url is required")
}
if sourceGitArgs.gitImplementation.String() != sourcev1.LibGit2Implementation && sourceGitArgs.caFile != "" {
return fmt.Errorf("specifing a CA file requires --git-implementation=%s", sourcev1.LibGit2Implementation)
}
tmpDir, err := ioutil.TempDir("", name)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
u, err := url.Parse(sourceArgs.GitURL)
u, err := url.Parse(sourceGitArgs.url)
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
@@ -159,7 +164,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
Labels: sourceLabels,
},
Spec: sourcev1.GitRepositorySpec{
URL: sourceArgs.GitURL,
URL: sourceGitArgs.url,
Interval: metav1.Duration{
Duration: createArgs.interval,
},
@@ -167,22 +172,22 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
},
}
if sourceArgs.GitImplementation != "" {
gitRepository.Spec.GitImplementation = sourceArgs.GitImplementation.String()
if sourceGitArgs.gitImplementation != "" {
gitRepository.Spec.GitImplementation = sourceGitArgs.gitImplementation.String()
}
if sourceArgs.GitSemver != "" {
gitRepository.Spec.Reference.SemVer = sourceArgs.GitSemver
} else if sourceArgs.GitTag != "" {
gitRepository.Spec.Reference.Tag = sourceArgs.GitTag
if sourceGitArgs.semver != "" {
gitRepository.Spec.Reference.SemVer = sourceGitArgs.semver
} else if sourceGitArgs.tag != "" {
gitRepository.Spec.Reference.Tag = sourceGitArgs.tag
} else {
gitRepository.Spec.Reference.Branch = sourceArgs.GitBranch
gitRepository.Spec.Reference.Branch = sourceGitArgs.branch
}
if createArgs.export {
if sourceArgs.GitSecretRef != "" {
if sourceGitArgs.secretRef != "" {
gitRepository.Spec.SecretRef = &meta.LocalObjectReference{
Name: sourceArgs.GitSecretRef,
Name: sourceGitArgs.secretRef,
}
}
return exportGit(gitRepository)
@@ -198,11 +203,11 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
withAuth := false
// TODO(hidde): move all auth prep to separate func?
if sourceArgs.GitSecretRef != "" {
if sourceGitArgs.secretRef != "" {
withAuth = true
} else if u.Scheme == "ssh" {
logger.Generatef("generating deploy key pair")
pair, err := generateKeyPair(ctx, sourceArgs.GitKeyAlgorithm, sourceArgs.GitRSABits, sourceArgs.GitECDSACurve)
pair, err := generateKeyPair(ctx, sourceGitArgs.keyAlgorithm, sourceGitArgs.keyRSABits, sourceGitArgs.keyECDSACurve)
if err != nil {
return err
}
@@ -240,7 +245,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return err
}
withAuth = true
} else if sourceArgs.GitUsername != "" && sourceArgs.GitPassword != "" {
} else if sourceGitArgs.username != "" && sourceGitArgs.password != "" {
logger.Actionf("applying secret with basic auth credentials")
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
@@ -249,10 +254,19 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
Labels: sourceLabels,
},
StringData: map[string]string{
"username": sourceArgs.GitUsername,
"password": sourceArgs.GitPassword,
"username": sourceGitArgs.username,
"password": sourceGitArgs.password,
},
}
if sourceGitArgs.caFile != "" {
ca, err := ioutil.ReadFile(sourceGitArgs.caFile)
if err != nil {
return fmt.Errorf("failed to read CA file '%s': %w", sourceGitArgs.caFile, err)
}
secret.StringData["caFile"] = string(ca)
}
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err
}
@@ -267,8 +281,8 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if withAuth {
secretName := name
if sourceArgs.GitSecretRef != "" {
secretName = sourceArgs.GitSecretRef
if sourceGitArgs.secretRef != "" {
secretName = sourceGitArgs.secretRef
}
gitRepository.Spec.SecretRef = &meta.LocalObjectReference{
Name: secretName,

View File

@@ -17,15 +17,8 @@ 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"
"github.com/spf13/cobra"
)
var deleteHelmReleaseCmd = &cobra.Command{
@@ -36,57 +29,12 @@ var deleteHelmReleaseCmd = &cobra.Command{
Example: ` # Delete a Helm release and the Kubernetes resources created by it
flux delete hr podinfo
`,
RunE: deleteHelmReleaseCmdRun,
RunE: deleteCommand{
apiType: helmReleaseType,
object: universalAdapter{&helmv2.HelmRelease{}},
}.run,
}
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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
if !deleteArgs.silent {
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, rootArgs.namespace)
err = kubeClient.Delete(ctx, &helmRelease)
if err != nil {
return err
}
logger.Successf("release deleted")
return nil
}

View File

@@ -20,12 +20,12 @@ import (
"github.com/spf13/cobra"
)
var deleteAutoCmd = &cobra.Command{
Use: "auto",
Short: "Delete automation objects",
Long: "The delete auto sub-commands delete automation objects.",
var deleteImageCmd = &cobra.Command{
Use: "image",
Short: "Delete image automation objects",
Long: "The delete image sub-commands delete image automation objects.",
}
func init() {
deleteCmd.AddCommand(deleteAutoCmd)
deleteCmd.AddCommand(deleteImageCmd)
}

View File

@@ -23,11 +23,11 @@ import (
)
var deleteImagePolicyCmd = &cobra.Command{
Use: "image-policy [name]",
Use: "policy [name]",
Short: "Delete an ImagePolicy object",
Long: "The delete auto image-policy command deletes the given ImagePolicy from the cluster.",
Long: "The delete image policy command deletes the given ImagePolicy from the cluster.",
Example: ` # Delete an image policy
flux delete auto image-policy alpine3.x
flux delete image policy alpine3.x
`,
RunE: deleteCommand{
apiType: imagePolicyType,
@@ -36,5 +36,5 @@ var deleteImagePolicyCmd = &cobra.Command{
}
func init() {
deleteAutoCmd.AddCommand(deleteImagePolicyCmd)
deleteImageCmd.AddCommand(deleteImagePolicyCmd)
}

View File

@@ -23,11 +23,11 @@ import (
)
var deleteImageRepositoryCmd = &cobra.Command{
Use: "image-repository [name]",
Use: "repository [name]",
Short: "Delete an ImageRepository object",
Long: "The delete auto image-repository command deletes the given ImageRepository from the cluster.",
Long: "The delete image repository command deletes the given ImageRepository from the cluster.",
Example: ` # Delete an image repository
flux delete auto image-repository alpine
flux delete image repository alpine
`,
RunE: deleteCommand{
apiType: imageRepositoryType,
@@ -36,5 +36,5 @@ var deleteImageRepositoryCmd = &cobra.Command{
}
func init() {
deleteAutoCmd.AddCommand(deleteImageRepositoryCmd)
deleteImageCmd.AddCommand(deleteImageRepositoryCmd)
}

View File

@@ -23,11 +23,11 @@ import (
)
var deleteImageUpdateCmd = &cobra.Command{
Use: "image-update [name]",
Use: "update [name]",
Short: "Delete an ImageUpdateAutomation object",
Long: "The delete auto image-update command deletes the given ImageUpdateAutomation from the cluster.",
Long: "The delete image update command deletes the given ImageUpdateAutomation from the cluster.",
Example: ` # Delete an image update automation
flux delete auto image-update latest-images
flux delete image update latest-images
`,
RunE: deleteCommand{
apiType: imageUpdateAutomationType,
@@ -36,5 +36,5 @@ var deleteImageUpdateCmd = &cobra.Command{
}
func init() {
deleteAutoCmd.AddCommand(deleteImageUpdateCmd)
deleteImageCmd.AddCommand(deleteImageUpdateCmd)
}

View File

@@ -17,14 +17,8 @@ limitations under the License.
package main
import (
"context"
"fmt"
"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"
)
var deleteKsCmd = &cobra.Command{
@@ -35,57 +29,12 @@ var deleteKsCmd = &cobra.Command{
Example: ` # Delete a kustomization and the Kubernetes resources created by it
flux delete kustomization podinfo
`,
RunE: deleteKsCmdRun,
RunE: deleteCommand{
apiType: kustomizationType,
object: universalAdapter{&kustomizev1.Kustomization{}},
}.run,
}
func init() {
deleteCmd.AddCommand(deleteKsCmd)
}
func deleteKsCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var kustomization kustomizev1.Kustomization
err = kubeClient.Get(ctx, namespacedName, &kustomization)
if err != nil {
return err
}
if !deleteArgs.silent {
if !kustomization.Spec.Suspend {
logger.Waitingf("This action will remove the Kubernetes objects previously applied by the %s kustomization!", name)
}
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this kustomization",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting kustomization %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &kustomization)
if err != nil {
return err
}
logger.Successf("kustomization deleted")
return nil
}

View File

@@ -17,14 +17,8 @@ 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{
@@ -34,54 +28,12 @@ var deleteSourceBucketCmd = &cobra.Command{
Example: ` # Delete a Bucket source
flux delete source bucket podinfo
`,
RunE: deleteSourceBucketCmdRun,
RunE: deleteCommand{
apiType: bucketType,
object: universalAdapter{&sourcev1.Bucket{}},
}.run,
}
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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var bucket sourcev1.Bucket
err = kubeClient.Get(ctx, namespacedName, &bucket)
if err != nil {
return err
}
if !deleteArgs.silent {
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, rootArgs.namespace)
err = kubeClient.Delete(ctx, &bucket)
if err != nil {
return err
}
logger.Successf("source deleted")
return nil
}

View File

@@ -17,14 +17,8 @@ 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 deleteSourceGitCmd = &cobra.Command{
@@ -34,54 +28,12 @@ var deleteSourceGitCmd = &cobra.Command{
Example: ` # Delete a Git repository
flux delete source git podinfo
`,
RunE: deleteSourceGitCmdRun,
RunE: deleteCommand{
apiType: gitRepositoryType,
object: universalAdapter{&sourcev1.GitRepository{}},
}.run,
}
func init() {
deleteSourceCmd.AddCommand(deleteSourceGitCmd)
}
func deleteSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("git name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var git sourcev1.GitRepository
err = kubeClient.Get(ctx, namespacedName, &git)
if err != nil {
return err
}
if !deleteArgs.silent {
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, rootArgs.namespace)
err = kubeClient.Delete(ctx, &git)
if err != nil {
return err
}
logger.Successf("source deleted")
return nil
}

View File

@@ -34,7 +34,10 @@ var deleteSourceHelmCmd = &cobra.Command{
Example: ` # Delete a Helm repository
flux delete source helm podinfo
`,
RunE: deleteSourceHelmCmdRun,
RunE: deleteCommand{
apiType: helmRepositoryType,
object: universalAdapter{&sourcev1.HelmRepository{}},
}.run,
}
func init() {

31
cmd/flux/embed.go Normal file
View File

@@ -0,0 +1,31 @@
package main
import (
"embed"
"fmt"
"io/fs"
"os"
"path"
)
//go:embed manifests/*.yaml
var embeddedManifests embed.FS
func writeEmbeddedManifests(dir string) error {
manifests, err := fs.ReadDir(embeddedManifests, "manifests")
if err != nil {
return err
}
for _, manifest := range manifests {
data, err := fs.ReadFile(embeddedManifests, path.Join("manifests", manifest.Name()))
if err != nil {
return fmt.Errorf("reading file failed: %w", err)
}
err = os.WriteFile(path.Join(dir, manifest.Name()), data, 0666)
if err != nil {
return fmt.Errorf("writing file failed: %w", err)
}
}
return nil
}

View File

@@ -90,6 +90,11 @@ func (get getCommand) run(cmd *cobra.Command, args []string) error {
if !getArgs.allNamespaces {
listOpts = append(listOpts, client.InNamespace(rootArgs.namespace))
}
if len(args) > 0 {
listOpts = append(listOpts, client.MatchingFields{"metadata.name": args[0]})
}
err = kubeClient.List(ctx, get.list.asClientList(), listOpts...)
if err != nil {
return err

View File

@@ -33,9 +33,10 @@ import (
)
var getAlertCmd = &cobra.Command{
Use: "alerts",
Short: "Get Alert statuses",
Long: "The get alert command prints the statuses of the resources.",
Use: "alerts",
Aliases: []string{"alert"},
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
`,

View File

@@ -31,9 +31,10 @@ import (
)
var getAlertProviderCmd = &cobra.Command{
Use: "alert-providers",
Short: "Get Provider statuses",
Long: "The get alert-provider command prints the statuses of the resources.",
Use: "alert-providers",
Aliases: []string{"alert-provider"},
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
`,

View File

@@ -26,7 +26,7 @@ import (
var getHelmReleaseCmd = &cobra.Command{
Use: "helmreleases",
Aliases: []string{"hr"},
Aliases: []string{"hr", "helmrelease"},
Short: "Get HelmRelease statuses",
Long: "The get helmreleases command prints the statuses of the resources.",
Example: ` # List all Helm releases and their status

View File

@@ -21,9 +21,10 @@ import (
)
var getImageCmd = &cobra.Command{
Use: "image",
Short: "Get image automation object status",
Long: "The get image sub-commands print the status of image automation objects.",
Use: "images",
Aliases: []string{"image"},
Short: "Get image automation object status",
Long: "The get image sub-commands print the status of image automation objects.",
}
func init() {

View File

@@ -26,7 +26,7 @@ import (
var getKsCmd = &cobra.Command{
Use: "kustomizations",
Aliases: []string{"ks"},
Aliases: []string{"ks", "kustomization"},
Short: "Get Kustomization statuses",
Long: "The get kustomizations command prints the statuses of the resources.",
Example: ` # List all kustomizations and their status

View File

@@ -33,9 +33,10 @@ import (
)
var getReceiverCmd = &cobra.Command{
Use: "receivers",
Short: "Get Receiver statuses",
Long: "The get receiver command prints the statuses of the resources.",
Use: "receivers",
Aliases: []string{"receiver"},
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
`,

View File

@@ -21,9 +21,10 @@ import (
)
var getSourceCmd = &cobra.Command{
Use: "sources",
Short: "Get source statuses",
Long: "The get source sub-commands print the statuses of the sources.",
Use: "sources",
Aliases: []string{"source"},
Short: "Get source statuses",
Long: "The get source sub-commands print the statuses of the sources.",
}
func init() {

View File

@@ -35,7 +35,7 @@ var getSourceHelmChartCmd = &cobra.Command{
flux get sources chart --all-namespaces
`,
RunE: getCommand{
apiType: bucketType,
apiType: helmChartType,
list: &helmChartListAdapter{&sourcev1.HelmChartList{}},
}.run,
}

View File

@@ -35,7 +35,7 @@ var getSourceGitCmd = &cobra.Command{
flux get sources git --all-namespaces
`,
RunE: getCommand{
apiType: bucketType,
apiType: gitRepositoryType,
list: &gitRepositoryListAdapter{&sourcev1.GitRepositoryList{}},
}.run,
}

View File

@@ -35,7 +35,7 @@ var getSourceHelmCmd = &cobra.Command{
flux get sources helm --all-namespaces
`,
RunE: getCommand{
apiType: bucketType,
apiType: helmRepositoryType,
list: &helmRepositoryListAdapter{&sourcev1.HelmRepositoryList{}},
}.run,
}

View File

@@ -23,6 +23,7 @@ import (
"os"
"path/filepath"
"strings"
"time"
"github.com/spf13/cobra"
@@ -33,15 +34,18 @@ import (
var installCmd = &cobra.Command{
Use: "install",
Short: "Install the toolkit components",
Long: `The install command deploys the toolkit components in the specified namespace.
Short: "Install or upgrade Flux",
Long: `The install command deploys Flux 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
# Install a specific version and a series of components
flux install --dry-run --version=v0.0.7 --components="source-controller,kustomize-controller"
# Install Flux onto tainted Kubernetes nodes
flux install --toleration-keys=node.kubernetes.io/dedicated-to-flux
# Dry-run install with manifests preview
flux install --dry-run --verbose
@@ -51,91 +55,119 @@ If a previous version is installed, then an in-place upgrade will be performed.`
RunE: installCmdRun,
}
var (
installExport bool
installDryRun bool
installManifestsPath string
installVersion string
installDefaultComponents []string
installExtraComponents []string
installRegistry string
installImagePullSecret string
installWatchAllNamespaces bool
installNetworkPolicy bool
installArch flags.Arch
installLogLevel = flags.LogLevel(rootArgs.defaults.LogLevel)
installClusterDomain string
)
type installFlags struct {
export bool
dryRun bool
version string
defaultComponents []string
extraComponents []string
registry string
imagePullSecret string
branch string
watchAllNamespaces bool
networkPolicy bool
manifestsPath string
arch flags.Arch
logLevel flags.LogLevel
tokenAuth bool
clusterDomain string
tolerationKeys []string
}
var installArgs = NewInstallFlags()
func init() {
installCmd.Flags().BoolVar(&installExport, "export", false,
installCmd.Flags().BoolVar(&installArgs.export, "export", false,
"write the install manifests to stdout and exit")
installCmd.Flags().BoolVarP(&installDryRun, "dry-run", "", false,
installCmd.Flags().BoolVarP(&installArgs.dryRun, "dry-run", "", false,
"only print the object that would be applied")
installCmd.Flags().StringVarP(&installVersion, "version", "v", rootArgs.defaults.Version,
"toolkit version")
installCmd.Flags().StringSliceVar(&installDefaultComponents, "components", rootArgs.defaults.Components,
installCmd.Flags().StringVarP(&installArgs.version, "version", "v", "",
"toolkit version, when specified the manifests are downloaded from https://github.com/fluxcd/flux2/releases")
installCmd.Flags().StringSliceVar(&installArgs.defaultComponents, "components", rootArgs.defaults.Components,
"list of components, accepts comma-separated values")
installCmd.Flags().StringSliceVar(&installExtraComponents, "components-extra", nil,
installCmd.Flags().StringSliceVar(&installArgs.extraComponents, "components-extra", nil,
"list of components in addition to those supplied or defaulted, accepts comma-separated values")
installCmd.Flags().StringVar(&installManifestsPath, "manifests", "", "path to the manifest directory")
installCmd.Flags().StringVar(&installRegistry, "registry", rootArgs.defaults.Registry,
installCmd.Flags().StringVar(&installArgs.manifestsPath, "manifests", "", "path to the manifest directory")
installCmd.Flags().StringVar(&installArgs.registry, "registry", rootArgs.defaults.Registry,
"container registry where the toolkit images are published")
installCmd.Flags().StringVar(&installImagePullSecret, "image-pull-secret", "",
installCmd.Flags().StringVar(&installArgs.imagePullSecret, "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", rootArgs.defaults.WatchAllNamespaces,
installCmd.Flags().Var(&installArgs.arch, "arch", installArgs.arch.Description())
installCmd.Flags().BoolVar(&installArgs.watchAllNamespaces, "watch-all-namespaces", rootArgs.defaults.WatchAllNamespaces,
"watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed")
installCmd.Flags().Var(&installLogLevel, "log-level", installLogLevel.Description())
installCmd.Flags().BoolVar(&installNetworkPolicy, "network-policy", rootArgs.defaults.NetworkPolicy,
installCmd.Flags().Var(&installArgs.logLevel, "log-level", installArgs.logLevel.Description())
installCmd.Flags().BoolVar(&installArgs.networkPolicy, "network-policy", rootArgs.defaults.NetworkPolicy,
"deny ingress access to the toolkit controllers from other namespaces using network policies")
installCmd.Flags().StringVar(&installClusterDomain, "cluster-domain", rootArgs.defaults.ClusterDomain, "internal cluster domain")
installCmd.Flags().StringVar(&installArgs.clusterDomain, "cluster-domain", rootArgs.defaults.ClusterDomain, "internal cluster domain")
installCmd.Flags().StringSliceVar(&installArgs.tolerationKeys, "toleration-keys", nil,
"list of toleration keys used to schedule the components pods onto nodes with matching taints")
installCmd.Flags().MarkHidden("manifests")
installCmd.Flags().MarkDeprecated("arch", "multi-arch container image is now available for AMD64, ARMv7 and ARM64")
rootCmd.AddCommand(installCmd)
}
func NewInstallFlags() installFlags {
return installFlags{
logLevel: flags.LogLevel(rootArgs.defaults.LogLevel),
}
}
func installCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
components := append(installArgs.defaultComponents, installArgs.extraComponents...)
err := utils.ValidateComponents(components)
if err != nil {
return err
}
if ver, err := getVersion(installArgs.version); err != nil {
return err
} else {
installArgs.version = ver
}
if !installArgs.export {
logger.Generatef("generating manifests")
}
tmpDir, err := ioutil.TempDir("", rootArgs.namespace)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
if !installExport {
logger.Generatef("generating manifests")
}
components := append(installDefaultComponents, installExtraComponents...)
if err := utils.ValidateComponents(components); err != nil {
return err
manifestsBase := ""
if isEmbeddedVersion(installArgs.version) {
if err := writeEmbeddedManifests(tmpDir); err != nil {
return err
}
manifestsBase = tmpDir
}
opts := install.Options{
BaseURL: installManifestsPath,
Version: installVersion,
BaseURL: installArgs.manifestsPath,
Version: installArgs.version,
Namespace: rootArgs.namespace,
Components: components,
Registry: installRegistry,
ImagePullSecret: installImagePullSecret,
WatchAllNamespaces: installWatchAllNamespaces,
NetworkPolicy: installNetworkPolicy,
LogLevel: installLogLevel.String(),
Registry: installArgs.registry,
ImagePullSecret: installArgs.imagePullSecret,
WatchAllNamespaces: installArgs.watchAllNamespaces,
NetworkPolicy: installArgs.networkPolicy,
LogLevel: installArgs.logLevel.String(),
NotificationController: rootArgs.defaults.NotificationController,
ManifestFile: fmt.Sprintf("%s.yaml", rootArgs.namespace),
Timeout: rootArgs.timeout,
ClusterDomain: installClusterDomain,
ClusterDomain: installArgs.clusterDomain,
TolerationKeys: installArgs.tolerationKeys,
}
if installManifestsPath == "" {
if installArgs.manifestsPath == "" {
opts.BaseURL = install.MakeDefaultOptions().BaseURL
}
manifest, err := install.Generate(opts)
manifest, err := install.Generate(opts, manifestsBase)
if err != nil {
return fmt.Errorf("install failed: %w", err)
}
@@ -146,9 +178,9 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
if rootArgs.verbose {
fmt.Print(manifest.Content)
} else if installExport {
} else if installArgs.export {
fmt.Println("---")
fmt.Println("# GitOps Toolkit revision", installVersion)
fmt.Println("# Flux version:", installArgs.version)
fmt.Println("# Components:", strings.Join(components, ","))
fmt.Print(manifest.Content)
fmt.Println("---")
@@ -163,7 +195,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
}
kubectlArgs := []string{"apply", "-f", filepath.Join(tmpDir, manifest.Path)}
if installDryRun {
if installArgs.dryRun {
kubectlArgs = append(kubectlArgs, "--dry-run=client")
applyOutput = utils.ModeOS
}
@@ -171,21 +203,19 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("install failed")
}
if installDryRun {
if installArgs.dryRun {
logger.Successf("install dry-run finished")
return nil
} else {
logger.Successf("install completed")
}
statusChecker, err := NewStatusChecker(time.Second, time.Minute)
if err != nil {
return fmt.Errorf("install failed: %w", err)
}
logger.Waitingf("verifying installation")
for _, deployment := range components {
kubectlArgs = []string{"-n", rootArgs.namespace, "rollout", "status", "deployment", deployment, "--timeout", rootArgs.timeout.String()}
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
return fmt.Errorf("install failed")
} else {
logger.Successf("%s ready", deployment)
}
if err := statusChecker.Assess(components...); err != nil {
return fmt.Errorf("install failed")
}
logger.Successf("install finished")

View File

@@ -41,7 +41,7 @@ var rootCmd = &cobra.Command{
Example: ` # Check prerequisites
flux check --pre
# Install the latest version of the toolkit
# Install the latest version of Flux
flux install --version=master
# Create a source from a public Git repository
@@ -88,8 +88,8 @@ var rootCmd = &cobra.Command{
# Delete a GitRepository source
flux delete source git webapp-latest
# Uninstall the toolkit and delete CRDs
flux uninstall --crds
# Uninstall Flux and delete CRDs
flux uninstall
`,
}
@@ -115,10 +115,12 @@ func init() {
}
func NewRootFlags() rootFlags {
return rootFlags{
rf := rootFlags{
pollInterval: 2 * time.Second,
defaults: install.MakeDefaultOptions(),
}
rf.defaults.Version = "v" + VERSION
return rf
}
func main() {

View File

@@ -93,17 +93,31 @@ func reconcileHrCmdRun(cmd *cobra.Command, args []string) error {
}
if rhrArgs.syncHrWithSource {
nsCopy := rootArgs.namespace
if helmRelease.Spec.Chart.Spec.SourceRef.Namespace != "" {
rootArgs.namespace = helmRelease.Spec.Chart.Spec.SourceRef.Namespace
}
switch helmRelease.Spec.Chart.Spec.SourceRef.Kind {
case sourcev1.HelmRepositoryKind:
err = reconcileSourceHelmCmdRun(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
err = reconcileCommand{
apiType: helmRepositoryType,
object: helmRepositoryAdapter{&sourcev1.HelmRepository{}},
}.run(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
case sourcev1.GitRepositoryKind:
err = reconcileSourceGitCmdRun(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
err = reconcileCommand{
apiType: gitRepositoryType,
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
}.run(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
case sourcev1.BucketKind:
err = reconcileSourceBucketCmdRun(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
err = reconcileCommand{
apiType: bucketType,
object: bucketAdapter{&sourcev1.Bucket{}},
}.run(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
}
if err != nil {
return err
}
rootArgs.namespace = nsCopy
}
lastHandledReconcileAt := helmRelease.Status.LastHandledReconcileAt

View File

@@ -91,15 +91,26 @@ func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
}
if rksArgs.syncKsWithSource {
nsCopy := rootArgs.namespace
if kustomization.Spec.SourceRef.Namespace != "" {
rootArgs.namespace = kustomization.Spec.SourceRef.Namespace
}
switch kustomization.Spec.SourceRef.Kind {
case sourcev1.GitRepositoryKind:
err = reconcileSourceGitCmdRun(nil, []string{kustomization.Spec.SourceRef.Name})
err = reconcileCommand{
apiType: gitRepositoryType,
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
}.run(nil, []string{kustomization.Spec.SourceRef.Name})
case sourcev1.BucketKind:
err = reconcileSourceBucketCmdRun(nil, []string{kustomization.Spec.SourceRef.Name})
err = reconcileCommand{
apiType: bucketType,
object: bucketAdapter{&sourcev1.Bucket{}},
}.run(nil, []string{kustomization.Spec.SourceRef.Name})
}
if err != nil {
return err
}
rootArgs.namespace = nsCopy
}
lastHandledReconcileAt := kustomization.Status.LastHandledReconcileAt

View File

@@ -19,13 +19,7 @@ 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"
@@ -43,64 +37,16 @@ var reconcileSourceBucketCmd = &cobra.Command{
Example: ` # Trigger a reconciliation for an existing source
flux reconcile source bucket podinfo
`,
RunE: reconcileSourceBucketCmdRun,
RunE: reconcileCommand{
apiType: bucketType,
object: bucketAdapter{&sourcev1.Bucket{}},
}.run,
}
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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.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, rootArgs.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(
rootArgs.pollInterval, rootArgs.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) {
@@ -126,30 +72,10 @@ func isBucketReady(ctx context.Context, kubeClient client.Client,
}
}
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 (obj bucketAdapter) lastHandledReconcileRequest() string {
return obj.Status.GetLastHandledReconcileRequest()
}
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.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
bucket.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, bucket)
})
func (obj bucketAdapter) successMessage() string {
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
}

View File

@@ -17,21 +17,9 @@ 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"
"github.com/spf13/cobra"
)
var reconcileSourceGitCmd = &cobra.Command{
@@ -41,86 +29,20 @@ var reconcileSourceGitCmd = &cobra.Command{
Example: ` # Trigger a git pull for an existing source
flux reconcile source git podinfo
`,
RunE: reconcileSourceGitCmdRun,
RunE: reconcileCommand{
apiType: gitRepositoryType,
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
}.run,
}
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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.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, rootArgs.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(rootArgs.pollInterval, rootArgs.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 (obj gitRepositoryAdapter) lastHandledReconcileRequest() string {
return obj.Status.GetLastHandledReconcileRequest()
}
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.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
repository.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, repository)
})
func (obj gitRepositoryAdapter) successMessage() string {
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
}

View File

@@ -17,22 +17,9 @@ 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"
"github.com/spf13/cobra"
)
var reconcileSourceHelmCmd = &cobra.Command{
@@ -42,86 +29,20 @@ var reconcileSourceHelmCmd = &cobra.Command{
Example: ` # Trigger a reconciliation for an existing source
flux reconcile source helm podinfo
`,
RunE: reconcileSourceHelmCmdRun,
RunE: reconcileCommand{
apiType: helmRepositoryType,
object: helmRepositoryAdapter{&sourcev1.HelmRepository{}},
}.run,
}
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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.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, rootArgs.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(rootArgs.pollInterval, rootArgs.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 (obj helmRepositoryAdapter) lastHandledReconcileRequest() string {
return obj.Status.GetLastHandledReconcileRequest()
}
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.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
repository.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, repository)
})
func (obj helmRepositoryAdapter) successMessage() string {
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
}

View File

@@ -17,20 +17,9 @@ 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"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
"github.com/spf13/cobra"
)
var resumeHrCmd = &cobra.Command{
@@ -42,76 +31,24 @@ finish the apply.`,
Example: ` # Resume reconciliation for an existing Helm release
flux resume hr podinfo
`,
RunE: resumeHrCmdRun,
RunE: resumeCommand{
apiType: helmReleaseType,
object: helmReleaseAdapter{&helmv2.HelmRelease{}},
}.run,
}
func init() {
resumeCmd.AddCommand(resumeHrCmd)
}
func resumeHrCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
logger.Actionf("resuming HelmRelease %s in %s namespace", name, rootArgs.namespace)
helmRelease.Spec.Suspend = false
if err := kubeClient.Update(ctx, &helmRelease); err != nil {
return err
}
logger.Successf("HelmRelease resumed")
logger.Waitingf("waiting for HelmRelease reconciliation")
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isHelmReleaseResumed(ctx, kubeClient, namespacedName, &helmRelease)); err != nil {
return err
}
logger.Successf("HelmRelease reconciliation completed")
logger.Successf("applied revision %s", helmRelease.Status.LastAppliedRevision)
return nil
func (obj helmReleaseAdapter) getObservedGeneration() int64 {
return obj.HelmRelease.Status.ObservedGeneration
}
func isHelmReleaseResumed(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, err
}
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
}
func (obj helmReleaseAdapter) setUnsuspended() {
obj.HelmRelease.Spec.Suspend = false
}
func (obj helmReleaseAdapter) successMessage() string {
return fmt.Sprintf("applied revision %s", obj.Status.LastAppliedRevision)
}

View File

@@ -17,19 +17,10 @@ limitations under the License.
package main
import (
"context"
"fmt"
"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"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var resumeKsCmd = &cobra.Command{
@@ -41,76 +32,24 @@ finish the apply.`,
Example: ` # Resume reconciliation for an existing Kustomization
flux resume ks podinfo
`,
RunE: resumeKsCmdRun,
RunE: resumeCommand{
apiType: kustomizationType,
object: kustomizationAdapter{&kustomizev1.Kustomization{}},
}.run,
}
func init() {
resumeCmd.AddCommand(resumeKsCmd)
}
func resumeKsCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var kustomization kustomizev1.Kustomization
err = kubeClient.Get(ctx, namespacedName, &kustomization)
if err != nil {
return err
}
logger.Actionf("resuming Kustomization %s in %s namespace", name, rootArgs.namespace)
kustomization.Spec.Suspend = false
if err := kubeClient.Update(ctx, &kustomization); err != nil {
return err
}
logger.Successf("Kustomization resumed")
logger.Waitingf("waiting for Kustomization reconciliation")
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isKustomizationResumed(ctx, kubeClient, namespacedName, &kustomization)); err != nil {
return err
}
logger.Successf("Kustomization reconciliation completed")
logger.Successf("applied revision %s", kustomization.Status.LastAppliedRevision)
return nil
func (obj kustomizationAdapter) getObservedGeneration() int64 {
return obj.Kustomization.Status.ObservedGeneration
}
func isKustomizationResumed(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
}
func (obj kustomizationAdapter) setUnsuspended() {
obj.Kustomization.Spec.Suspend = false
}
func (obj kustomizationAdapter) successMessage() string {
return fmt.Sprintf("applied revision %s", obj.Status.LastAppliedRevision)
}

View File

@@ -17,20 +17,8 @@ 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"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/spf13/cobra"
)
var resumeSourceBucketCmd = &cobra.Command{
@@ -40,76 +28,20 @@ var resumeSourceBucketCmd = &cobra.Command{
Example: ` # Resume reconciliation for an existing Bucket
flux resume source bucket podinfo
`,
RunE: resumeSourceBucketCmdRun,
RunE: resumeCommand{
apiType: bucketType,
object: &bucketAdapter{&sourcev1.Bucket{}},
}.run,
}
func init() {
resumeSourceCmd.AddCommand(resumeSourceBucketCmd)
}
func resumeSourceBucketCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var bucket sourcev1.Bucket
err = kubeClient.Get(ctx, namespacedName, &bucket)
if err != nil {
return err
}
logger.Actionf("resuming source %s in %s namespace", name, rootArgs.namespace)
bucket.Spec.Suspend = false
if err := kubeClient.Update(ctx, &bucket); err != nil {
return err
}
logger.Successf("source resumed")
logger.Waitingf("waiting for Bucket reconciliation")
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isBucketResumed(ctx, kubeClient, namespacedName, &bucket)); err != nil {
return err
}
logger.Successf("Bucket reconciliation completed")
logger.Successf("fetched revision %s", bucket.Status.Artifact.Revision)
return nil
func (obj bucketAdapter) getObservedGeneration() int64 {
return obj.Bucket.Status.ObservedGeneration
}
func isBucketResumed(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 (obj bucketAdapter) setUnsuspended() {
obj.Bucket.Spec.Suspend = false
}

View File

@@ -17,20 +17,10 @@ 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"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/spf13/cobra"
)
var resumeSourceHelmChartCmd = &cobra.Command{
@@ -40,76 +30,24 @@ var resumeSourceHelmChartCmd = &cobra.Command{
Example: ` # Resume reconciliation for an existing HelmChart
flux resume source chart podinfo
`,
RunE: resumeSourceHelmChartCmdRun,
RunE: resumeCommand{
apiType: helmChartType,
object: &helmChartAdapter{&sourcev1.HelmChart{}},
}.run,
}
func init() {
resumeSourceCmd.AddCommand(resumeSourceHelmChartCmd)
}
func resumeSourceHelmChartCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.HelmChart
err = kubeClient.Get(ctx, namespacedName, &repository)
if err != nil {
return err
}
logger.Actionf("resuming source %s in %s namespace", name, rootArgs.namespace)
repository.Spec.Suspend = false
if err := kubeClient.Update(ctx, &repository); err != nil {
return err
}
logger.Successf("source resumed")
logger.Waitingf("waiting for HelmChart reconciliation")
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isHelmChartResumed(ctx, kubeClient, namespacedName, &repository)); err != nil {
return err
}
logger.Successf("HelmChart reconciliation completed")
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
return nil
func (obj helmChartAdapter) getObservedGeneration() int64 {
return obj.HelmChart.Status.ObservedGeneration
}
func isHelmChartResumed(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, chart *sourcev1.HelmChart) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, chart)
if err != nil {
return false, err
}
// Confirm the state we are observing is for the current generation
if chart.Generation != chart.Status.ObservedGeneration {
return false, nil
}
if c := apimeta.FindStatusCondition(chart.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 (obj helmChartAdapter) setUnsuspended() {
obj.HelmChart.Spec.Suspend = false
}
func (obj helmChartAdapter) successMessage() string {
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
}

View File

@@ -17,20 +17,8 @@ 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"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/spf13/cobra"
)
var resumeSourceGitCmd = &cobra.Command{
@@ -40,76 +28,20 @@ var resumeSourceGitCmd = &cobra.Command{
Example: ` # Resume reconciliation for an existing GitRepository
flux resume source git podinfo
`,
RunE: resumeSourceGitCmdRun,
RunE: resumeCommand{
apiType: gitRepositoryType,
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
}.run,
}
func init() {
resumeSourceCmd.AddCommand(resumeSourceGitCmd)
}
func resumeSourceGitCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.GitRepository
err = kubeClient.Get(ctx, namespacedName, &repository)
if err != nil {
return err
}
logger.Actionf("resuming source %s in %s namespace", name, rootArgs.namespace)
repository.Spec.Suspend = false
if err := kubeClient.Update(ctx, &repository); err != nil {
return err
}
logger.Successf("source resumed")
logger.Waitingf("waiting for GitRepository reconciliation")
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isGitRepositoryResumed(ctx, kubeClient, namespacedName, &repository)); err != nil {
return err
}
logger.Successf("GitRepository reconciliation completed")
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
return nil
func (obj gitRepositoryAdapter) getObservedGeneration() int64 {
return obj.GitRepository.Status.ObservedGeneration
}
func isGitRepositoryResumed(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, repository *sourcev1.GitRepository) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, repository)
if err != nil {
return false, err
}
// Confirm the state we are observing is for the current generation
if repository.Generation != repository.Status.ObservedGeneration {
return false, nil
}
if c := apimeta.FindStatusCondition(repository.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 (obj gitRepositoryAdapter) setUnsuspended() {
obj.GitRepository.Spec.Suspend = false
}

View File

@@ -17,20 +17,8 @@ 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"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/spf13/cobra"
)
var resumeSourceHelmCmd = &cobra.Command{
@@ -40,76 +28,20 @@ var resumeSourceHelmCmd = &cobra.Command{
Example: ` # Resume reconciliation for an existing HelmRepository
flux resume source helm bitnami
`,
RunE: resumeSourceHelmCmdRun,
RunE: resumeCommand{
apiType: helmRepositoryType,
object: helmRepositoryAdapter{&sourcev1.HelmRepository{}},
}.run,
}
func init() {
resumeSourceCmd.AddCommand(resumeSourceHelmCmd)
}
func resumeSourceHelmCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.HelmRepository
err = kubeClient.Get(ctx, namespacedName, &repository)
if err != nil {
return err
}
logger.Actionf("resuming source %s in %s namespace", name, rootArgs.namespace)
repository.Spec.Suspend = false
if err := kubeClient.Update(ctx, &repository); err != nil {
return err
}
logger.Successf("source resumed")
logger.Waitingf("waiting for HelmRepository reconciliation")
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isHelmRepositoryResumed(ctx, kubeClient, namespacedName, &repository)); err != nil {
return err
}
logger.Successf("HelmRepository reconciliation completed")
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
return nil
func (obj helmRepositoryAdapter) getObservedGeneration() int64 {
return obj.HelmRepository.Status.ObservedGeneration
}
func isHelmRepositoryResumed(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, repository *sourcev1.HelmRepository) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, repository)
if err != nil {
return false, err
}
// Confirm the state we are observing is for the current generation
if repository.Generation != repository.Status.ObservedGeneration {
return false, nil
}
if c := apimeta.FindStatusCondition(repository.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 (obj helmRepositoryAdapter) setUnsuspended() {
obj.HelmRepository.Spec.Suspend = false
}

View File

@@ -19,14 +19,26 @@ package main
import (
"context"
"fmt"
"time"
appsv1 "k8s.io/api/apps/v1"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/cli-utils/pkg/kstatus/polling"
"sigs.k8s.io/cli-utils/pkg/kstatus/polling/aggregator"
"sigs.k8s.io/cli-utils/pkg/kstatus/polling/collector"
"sigs.k8s.io/cli-utils/pkg/kstatus/polling/event"
"sigs.k8s.io/cli-utils/pkg/kstatus/status"
"sigs.k8s.io/cli-utils/pkg/object"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/flux2/internal/utils"
)
// statusable is used to see if a resource is considered ready in the usual way
@@ -39,6 +51,13 @@ type statusable interface {
GetStatusConditions() *[]metav1.Condition
}
type StatusChecker struct {
pollInterval time.Duration
timeout time.Duration
client client.Client
statusPoller *polling.StatusPoller
}
func isReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, object statusable) wait.ConditionFunc {
return func() (bool, error) {
@@ -63,3 +82,99 @@ func isReady(ctx context.Context, kubeClient client.Client,
return false, nil
}
}
func NewStatusChecker(pollInterval time.Duration, timeout time.Duration) (*StatusChecker, error) {
kubeConfig, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return nil, err
}
restMapper, err := apiutil.NewDynamicRESTMapper(kubeConfig)
if err != nil {
return nil, err
}
client, err := client.New(kubeConfig, client.Options{Mapper: restMapper})
if err != nil {
return nil, err
}
return &StatusChecker{
pollInterval: pollInterval,
timeout: timeout,
client: client,
statusPoller: polling.NewStatusPoller(client, restMapper),
}, nil
}
func (sc *StatusChecker) Assess(components ...string) error {
ctx, cancel := context.WithTimeout(context.Background(), sc.timeout)
defer cancel()
objRefs, err := sc.getObjectRefs(components)
if err != nil {
return err
}
opts := polling.Options{PollInterval: sc.pollInterval, UseCache: true}
eventsChan := sc.statusPoller.Poll(ctx, objRefs, opts)
coll := collector.NewResourceStatusCollector(objRefs)
done := coll.ListenWithObserver(eventsChan, collector.ObserverFunc(
func(statusCollector *collector.ResourceStatusCollector, e event.Event) {
var rss []*event.ResourceStatus
for _, rs := range statusCollector.ResourceStatuses {
rss = append(rss, rs)
}
desired := status.CurrentStatus
aggStatus := aggregator.AggregateStatus(rss, desired)
if aggStatus == desired {
cancel()
return
}
}),
)
<-done
if coll.Error != nil || ctx.Err() == context.DeadlineExceeded {
for _, rs := range coll.ResourceStatuses {
if rs.Status != status.CurrentStatus {
if !sc.deploymentExists(rs.Identifier) {
logger.Failuref("%s: deployment not found", rs.Identifier.Name)
} else {
logger.Failuref("%s: unhealthy (timed out waiting for rollout)", rs.Identifier.Name)
}
}
}
return fmt.Errorf("timed out waiting for condition")
}
return nil
}
func (sc *StatusChecker) getObjectRefs(components []string) ([]object.ObjMetadata, error) {
var objRefs []object.ObjMetadata
for _, deployment := range components {
objMeta, err := object.CreateObjMetadata(rootArgs.namespace, deployment, schema.GroupKind{Group: "apps", Kind: "Deployment"})
if err != nil {
return nil, err
}
objRefs = append(objRefs, objMeta)
}
return objRefs, nil
}
func (sc *StatusChecker) objMetadataToString(om object.ObjMetadata) string {
return fmt.Sprintf("%s '%s/%s'", om.GroupKind.Kind, om.Namespace, om.Name)
}
func (sc *StatusChecker) deploymentExists(om object.ObjMetadata) bool {
ctx, cancel := context.WithTimeout(context.Background(), sc.timeout)
defer cancel()
namespacedName := types.NamespacedName{
Namespace: om.Namespace,
Name: om.Name,
}
var existing appsv1.Deployment
err := sc.client.Get(ctx, namespacedName, &existing)
return err == nil
}

View File

@@ -17,14 +17,8 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/flux2/internal/utils"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
"github.com/spf13/cobra"
)
var suspendHrCmd = &cobra.Command{
@@ -35,43 +29,20 @@ var suspendHrCmd = &cobra.Command{
Example: ` # Suspend reconciliation for an existing Helm release
flux suspend hr podinfo
`,
RunE: suspendHrCmdRun,
RunE: suspendCommand{
apiType: helmReleaseType,
object: &helmReleaseAdapter{&helmv2.HelmRelease{}},
}.run,
}
func init() {
suspendCmd.AddCommand(suspendHrCmd)
}
func suspendHrCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
logger.Actionf("suspending HelmRelease %s in %s namespace", name, rootArgs.namespace)
helmRelease.Spec.Suspend = true
if err := kubeClient.Update(ctx, &helmRelease); err != nil {
return err
}
logger.Successf("HelmRelease suspended")
return nil
func (obj helmReleaseAdapter) isSuspended() bool {
return obj.HelmRelease.Spec.Suspend
}
func (obj helmReleaseAdapter) setSuspended() {
obj.HelmRelease.Spec.Suspend = true
}

View File

@@ -17,13 +17,8 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/fluxcd/flux2/internal/utils"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var suspendKsCmd = &cobra.Command{
@@ -34,43 +29,20 @@ var suspendKsCmd = &cobra.Command{
Example: ` # Suspend reconciliation for an existing Kustomization
flux suspend ks podinfo
`,
RunE: suspendKsCmdRun,
RunE: suspendCommand{
apiType: kustomizationType,
object: kustomizationAdapter{&kustomizev1.Kustomization{}},
}.run,
}
func init() {
suspendCmd.AddCommand(suspendKsCmd)
}
func suspendKsCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var kustomization kustomizev1.Kustomization
err = kubeClient.Get(ctx, namespacedName, &kustomization)
if err != nil {
return err
}
logger.Actionf("suspending kustomization %s in %s namespace", name, rootArgs.namespace)
kustomization.Spec.Suspend = true
if err := kubeClient.Update(ctx, &kustomization); err != nil {
return err
}
logger.Successf("kustomization suspended")
return nil
func (obj kustomizationAdapter) isSuspended() bool {
return obj.Kustomization.Spec.Suspend
}
func (obj kustomizationAdapter) setSuspended() {
obj.Kustomization.Spec.Suspend = true
}

View File

@@ -17,13 +17,8 @@ limitations under the License.
package main
import (
"context"
"fmt"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var suspendSourceBucketCmd = &cobra.Command{
@@ -33,43 +28,20 @@ var suspendSourceBucketCmd = &cobra.Command{
Example: ` # Suspend reconciliation for an existing Bucket
flux suspend source bucket podinfo
`,
RunE: suspendSourceBucketCmdRun,
RunE: suspendCommand{
apiType: bucketType,
object: bucketAdapter{&sourcev1.Bucket{}},
}.run,
}
func init() {
suspendSourceCmd.AddCommand(suspendSourceBucketCmd)
}
func suspendSourceBucketCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var bucket sourcev1.Bucket
err = kubeClient.Get(ctx, namespacedName, &bucket)
if err != nil {
return err
}
logger.Actionf("suspending source %s in %s namespace", name, rootArgs.namespace)
bucket.Spec.Suspend = true
if err := kubeClient.Update(ctx, &bucket); err != nil {
return err
}
logger.Successf("source suspended")
return nil
func (obj bucketAdapter) isSuspended() bool {
return obj.Bucket.Spec.Suspend
}
func (obj bucketAdapter) setSuspended() {
obj.Bucket.Spec.Suspend = true
}

View File

@@ -17,13 +17,9 @@ limitations under the License.
package main
import (
"context"
"fmt"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var suspendSourceHelmChartCmd = &cobra.Command{
@@ -33,43 +29,20 @@ var suspendSourceHelmChartCmd = &cobra.Command{
Example: ` # Suspend reconciliation for an existing HelmChart
flux suspend source chart podinfo
`,
RunE: suspendSourceHelmChartCmdRun,
RunE: suspendCommand{
apiType: helmChartType,
object: helmChartAdapter{&sourcev1.HelmChart{}},
}.run,
}
func init() {
suspendSourceCmd.AddCommand(suspendSourceHelmChartCmd)
}
func suspendSourceHelmChartCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var chart sourcev1.HelmChart
err = kubeClient.Get(ctx, namespacedName, &chart)
if err != nil {
return err
}
logger.Actionf("suspending source %s in %s namespace", name, rootArgs.namespace)
chart.Spec.Suspend = true
if err := kubeClient.Update(ctx, &chart); err != nil {
return err
}
logger.Successf("source suspended")
return nil
func (obj helmChartAdapter) isSuspended() bool {
return obj.HelmChart.Spec.Suspend
}
func (obj helmChartAdapter) setSuspended() {
obj.HelmChart.Spec.Suspend = true
}

View File

@@ -17,13 +17,9 @@ limitations under the License.
package main
import (
"context"
"fmt"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var suspendSourceGitCmd = &cobra.Command{
@@ -33,43 +29,20 @@ var suspendSourceGitCmd = &cobra.Command{
Example: ` # Suspend reconciliation for an existing GitRepository
flux suspend source git podinfo
`,
RunE: suspendSourceGitCmdRun,
RunE: suspendCommand{
apiType: gitRepositoryType,
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
}.run,
}
func init() {
suspendSourceCmd.AddCommand(suspendSourceGitCmd)
}
func suspendSourceGitCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.GitRepository
err = kubeClient.Get(ctx, namespacedName, &repository)
if err != nil {
return err
}
logger.Actionf("suspending source %s in %s namespace", name, rootArgs.namespace)
repository.Spec.Suspend = true
if err := kubeClient.Update(ctx, &repository); err != nil {
return err
}
logger.Successf("source suspended")
return nil
func (obj gitRepositoryAdapter) isSuspended() bool {
return obj.GitRepository.Spec.Suspend
}
func (obj gitRepositoryAdapter) setSuspended() {
obj.GitRepository.Spec.Suspend = true
}

View File

@@ -17,13 +17,9 @@ limitations under the License.
package main
import (
"context"
"fmt"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var suspendSourceHelmCmd = &cobra.Command{
@@ -33,43 +29,20 @@ var suspendSourceHelmCmd = &cobra.Command{
Example: ` # Suspend reconciliation for an existing HelmRepository
flux suspend source helm bitnami
`,
RunE: suspendSourceHelmCmdRun,
RunE: suspendCommand{
apiType: helmRepositoryType,
object: helmRepositoryAdapter{&sourcev1.HelmRepository{}},
}.run,
}
func init() {
suspendSourceCmd.AddCommand(suspendSourceHelmCmd)
}
func suspendSourceHelmCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.HelmRepository
err = kubeClient.Get(ctx, namespacedName, &repository)
if err != nil {
return err
}
logger.Actionf("suspending source %s in %s namespace", name, rootArgs.namespace)
repository.Spec.Suspend = true
if err := kubeClient.Update(ctx, &repository); err != nil {
return err
}
logger.Successf("source suspended")
return nil
func (obj helmRepositoryAdapter) isSuspended() bool {
return obj.HelmRepository.Spec.Suspend
}
func (obj helmRepositoryAdapter) setSuspended() {
obj.HelmRepository.Spec.Suspend = true
}

View File

@@ -22,8 +22,12 @@ import (
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
rbacv1 "k8s.io/api/rbac/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/flux2/internal/utils"
@@ -34,33 +38,30 @@ import (
var uninstallCmd = &cobra.Command{
Use: "uninstall",
Short: "Uninstall the toolkit components",
Long: "The uninstall command removes the namespace, cluster roles, cluster role bindings and CRDs from the cluster.",
Example: ` # Dry-run uninstall of all components
flux uninstall --dry-run --namespace=flux-system
Short: "Uninstall Flux and its custom resource definitions",
Long: "The uninstall command removes the Flux components and the toolkit.fluxcd.io resources from the cluster.",
Example: ` # Uninstall Flux components, its custom resources and namespace
flux uninstall --namespace=flux-system
# Uninstall all components and delete custom resource definitions
flux uninstall --resources --crds --namespace=flux-system
# Uninstall Flux but keep the namespace
flux uninstall --namespace=infra --keep-namespace=true
`,
RunE: uninstallCmdRun,
}
type uninstallFlags struct {
crds bool
resources bool
dryRun bool
silent bool
keepNamespace bool
dryRun bool
silent bool
}
var uninstallArgs uninstallFlags
func init() {
uninstallCmd.Flags().BoolVar(&uninstallArgs.resources, "resources", true,
"removes custom resources such as Kustomizations, GitRepositories and HelmRepositories")
uninstallCmd.Flags().BoolVar(&uninstallArgs.crds, "crds", false,
"removes all CRDs previously installed")
uninstallCmd.Flags().BoolVar(&uninstallArgs.keepNamespace, "keep-namespace", false,
"skip namespace deletion")
uninstallCmd.Flags().BoolVar(&uninstallArgs.dryRun, "dry-run", false,
"only print the object that would be deleted")
"only print the objects that would be deleted")
uninstallCmd.Flags().BoolVarP(&uninstallArgs.silent, "silent", "s", false,
"delete components without asking for confirmation")
@@ -68,6 +69,16 @@ func init() {
}
func uninstallCmdRun(cmd *cobra.Command, args []string) error {
if !uninstallArgs.dryRun && !uninstallArgs.silent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete Flux and its custom resource definitions",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
@@ -76,96 +87,227 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
return err
}
if !uninstallArgs.dryRun && !uninstallArgs.silent {
prompt := promptui.Prompt{
Label: fmt.Sprintf("Are you sure you want to delete the %s namespace", rootArgs.namespace),
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting components in %s namespace", rootArgs.namespace)
uninstallComponents(ctx, kubeClient, rootArgs.namespace, uninstallArgs.dryRun)
dryRun := "--dry-run=server"
deleteResources := uninstallArgs.resources || uninstallArgs.crds
logger.Actionf("deleting toolkit.fluxcd.io finalizers in all namespaces")
uninstallFinalizers(ctx, kubeClient, uninstallArgs.dryRun)
// known kinds with finalizers
namespacedKinds := []string{
sourcev1.GitRepositoryKind,
sourcev1.HelmRepositoryKind,
sourcev1.BucketKind,
}
logger.Actionf("deleting toolkit.fluxcd.io custom resource definitions")
uninstallCustomResourceDefinitions(ctx, kubeClient, rootArgs.namespace, uninstallArgs.dryRun)
// suspend bootstrap kustomization to avoid finalizers deadlock
kustomizationName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: rootArgs.namespace,
}
var kustomization kustomizev1.Kustomization
err = kubeClient.Get(ctx, kustomizationName, &kustomization)
if err == nil {
kustomization.Spec.Suspend = true
if err := kubeClient.Update(ctx, &kustomization); err != nil {
return fmt.Errorf("unable to suspend kustomization '%s': %w", kustomizationName.String(), err)
}
}
if err == nil || apierrors.IsNotFound(err) {
namespacedKinds = append(namespacedKinds, kustomizev1.KustomizationKind)
}
// add HelmRelease kind to deletion list if exists
var list helmv2.HelmReleaseList
if err := kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace)); err == nil {
namespacedKinds = append(namespacedKinds, helmv2.HelmReleaseKind)
}
if deleteResources {
logger.Actionf("uninstalling custom resources")
for _, kind := range namespacedKinds {
if err := deleteAll(ctx, kind, uninstallArgs.dryRun); err != nil {
logger.Failuref("kubectl: %s", err.Error())
}
}
}
var kinds []string
if uninstallArgs.crds {
kinds = append(kinds, "crds")
}
kinds = append(kinds, "clusterroles,clusterrolebindings", "namespace")
logger.Actionf("uninstalling components")
for _, kind := range kinds {
kubectlArgs := []string{
"delete", kind,
"-l", fmt.Sprintf("app.kubernetes.io/instance=%s", rootArgs.namespace),
"--ignore-not-found", "--timeout", rootArgs.timeout.String(),
}
if uninstallArgs.dryRun {
kubectlArgs = append(kubectlArgs, dryRun)
}
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
return fmt.Errorf("uninstall failed: %w", err)
}
if !uninstallArgs.keepNamespace {
uninstallNamespace(ctx, kubeClient, rootArgs.namespace, uninstallArgs.dryRun)
}
logger.Successf("uninstall finished")
return nil
}
func deleteAll(ctx context.Context, kind string, dryRun bool) error {
kubectlArgs := []string{
"delete", kind, "--ignore-not-found",
"--all", "--all-namespaces",
"--timeout", rootArgs.timeout.String(),
func uninstallComponents(ctx context.Context, kubeClient client.Client, namespace string, dryRun bool) {
opts, dryRunStr := getDeleteOptions(dryRun)
selector := client.MatchingLabels{"app.kubernetes.io/instance": namespace}
{
var list appsv1.DeploymentList
if err := kubeClient.List(ctx, &list, client.InNamespace(namespace), selector); err == nil {
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("Deployment/%s/%s deletion failed: %s", r.Namespace, r.Name, err.Error())
} else {
logger.Successf("Deployment/%s/%s deleted %s", r.Namespace, r.Name, dryRunStr)
}
}
}
}
if dryRun {
kubectlArgs = append(kubectlArgs, "--dry-run=server")
{
var list corev1.ServiceList
if err := kubeClient.List(ctx, &list, client.InNamespace(namespace), selector); err == nil {
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("Service/%s/%s deletion failed: %s", r.Namespace, r.Name, err.Error())
} else {
logger.Successf("Service/%s/%s deleted %s", r.Namespace, r.Name, dryRunStr)
}
}
}
}
{
var list networkingv1.NetworkPolicyList
if err := kubeClient.List(ctx, &list, client.InNamespace(namespace), selector); err == nil {
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("NetworkPolicy/%s/%s deletion failed: %s", r.Namespace, r.Name, err.Error())
} else {
logger.Successf("NetworkPolicy/%s/%s deleted %s", r.Namespace, r.Name, dryRunStr)
}
}
}
}
{
var list corev1.ServiceAccountList
if err := kubeClient.List(ctx, &list, client.InNamespace(namespace), selector); err == nil {
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("ServiceAccount/%s/%s deletion failed: %s", r.Namespace, r.Name, err.Error())
} else {
logger.Successf("ServiceAccount/%s/%s deleted %s", r.Namespace, r.Name, dryRunStr)
}
}
}
}
{
var list rbacv1.ClusterRoleList
if err := kubeClient.List(ctx, &list, selector); err == nil {
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("ClusterRole/%s deletion failed: %s", r.Name, err.Error())
} else {
logger.Successf("ClusterRole/%s deleted %s", r.Name, dryRunStr)
}
}
}
}
{
var list rbacv1.ClusterRoleBindingList
if err := kubeClient.List(ctx, &list, selector); err == nil {
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("ClusterRoleBinding/%s deletion failed: %s", r.Name, err.Error())
} else {
logger.Successf("ClusterRoleBinding/%s deleted %s", r.Name, dryRunStr)
}
}
}
}
_, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...)
return err
}
func uninstallFinalizers(ctx context.Context, kubeClient client.Client, dryRun bool) {
opts, dryRunStr := getUpdateOptions(dryRun)
{
var list sourcev1.GitRepositoryList
if err := kubeClient.List(ctx, &list, client.InNamespace("")); err == nil {
for _, r := range list.Items {
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
}
}
}
{
var list sourcev1.HelmRepositoryList
if err := kubeClient.List(ctx, &list, client.InNamespace("")); err == nil {
for _, r := range list.Items {
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
}
}
}
{
var list sourcev1.HelmChartList
if err := kubeClient.List(ctx, &list, client.InNamespace("")); err == nil {
for _, r := range list.Items {
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
}
}
}
{
var list sourcev1.BucketList
if err := kubeClient.List(ctx, &list, client.InNamespace("")); err == nil {
for _, r := range list.Items {
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
}
}
}
{
var list kustomizev1.KustomizationList
if err := kubeClient.List(ctx, &list, client.InNamespace("")); err == nil {
for _, r := range list.Items {
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
}
}
}
{
var list helmv2.HelmReleaseList
if err := kubeClient.List(ctx, &list, client.InNamespace("")); err == nil {
for _, r := range list.Items {
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
}
}
}
}
func uninstallCustomResourceDefinitions(ctx context.Context, kubeClient client.Client, namespace string, dryRun bool) {
opts, dryRunStr := getDeleteOptions(dryRun)
selector := client.MatchingLabels{"app.kubernetes.io/instance": namespace}
{
var list apiextensionsv1.CustomResourceDefinitionList
if err := kubeClient.List(ctx, &list, selector); err == nil {
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("CustomResourceDefinition/%s deletion failed: %s", r.Name, err.Error())
} else {
logger.Successf("CustomResourceDefinition/%s deleted %s", r.Name, dryRunStr)
}
}
}
}
}
func uninstallNamespace(ctx context.Context, kubeClient client.Client, namespace string, dryRun bool) {
opts, dryRunStr := getDeleteOptions(dryRun)
ns := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
if err := kubeClient.Delete(ctx, &ns, opts); err != nil {
logger.Failuref("Namespace/%s deletion failed: %s", namespace, err.Error())
} else {
logger.Successf("Namespace/%s deleted %s", namespace, dryRunStr)
}
}
func getDeleteOptions(dryRun bool) (*client.DeleteOptions, string) {
opts := &client.DeleteOptions{}
var dryRunStr string
if dryRun {
client.DryRunAll.ApplyToDelete(opts)
dryRunStr = "(dry run)"
}
return opts, dryRunStr
}
func getUpdateOptions(dryRun bool) (*client.UpdateOptions, string) {
opts := &client.UpdateOptions{}
var dryRunStr string
if dryRun {
client.DryRunAll.ApplyToUpdate(opts)
dryRunStr = "(dry run)"
}
return opts, dryRunStr
}

42
cmd/flux/version.go Normal file
View File

@@ -0,0 +1,42 @@
package main
import (
"fmt"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/install"
)
func getVersion(input string) (string, error) {
if input == "" {
return rootArgs.defaults.Version, nil
}
if isEmbeddedVersion(input) {
return input, nil
}
var err error
if input == install.MakeDefaultOptions().Version {
input, err = install.GetLatestVersion()
if err != nil {
return "", err
}
} else {
if ok, err := install.ExistingVersion(input); err != nil || !ok {
if err == nil {
err = fmt.Errorf("targeted version '%s' does not exist", input)
}
return "", err
}
}
if !utils.CompatibleVersion(VERSION, input) {
return "", fmt.Errorf("targeted version '%s' is not compatible with your current version of flux (%s)", input, VERSION)
}
return input, nil
}
func isEmbeddedVersion(input string) bool {
return input == rootArgs.defaults.Version
}

View File

@@ -12,7 +12,7 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
# Check prerequisites
flux check --pre
# Install the latest version of the toolkit
# Install the latest version of Flux
flux install --version=master
# Create a source from a public Git repository
@@ -59,8 +59,8 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
# Delete a GitRepository source
flux delete source git webapp-latest
# Uninstall the toolkit and delete CRDs
flux uninstall --crds
# Uninstall Flux and delete CRDs
flux uninstall
```
@@ -84,9 +84,9 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
* [flux delete](flux_delete.md) - Delete sources and resources
* [flux export](flux_export.md) - Export resources in YAML format
* [flux get](flux_get.md) - Get sources and resources
* [flux install](flux_install.md) - Install the toolkit components
* [flux install](flux_install.md) - Install or upgrade Flux
* [flux reconcile](flux_reconcile.md) - Reconcile sources and resources
* [flux resume](flux_resume.md) - Resume suspended resources
* [flux suspend](flux_suspend.md) - Suspend resources
* [flux uninstall](flux_uninstall.md) - Uninstall the toolkit components
* [flux uninstall](flux_uninstall.md) - Uninstall Flux and its custom resource definitions

View File

@@ -19,7 +19,8 @@ The bootstrap sub-commands bootstrap the toolkit components on the targeted Git
--network-policy deny ingress access to the toolkit controllers from other namespaces using network policies (default true)
--registry string container registry where the toolkit images are published (default "ghcr.io/fluxcd")
--token-auth when enabled, the personal access token will be used instead of SSH deploy key
-v, --version string toolkit version (default "latest")
--toleration-keys strings list of toleration keys used to schedule the components pods onto nodes with matching taints
-v, --version string toolkit version, when specified the manifests are downloaded from https://github.com/fluxcd/flux2/releases
--watch-all-namespaces watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
```

View File

@@ -51,8 +51,8 @@ flux bootstrap github [flags]
--interval duration sync interval (default 1m0s)
--owner string GitHub user or organization name
--path safeRelativePath path relative to the repository root, when specified the cluster sync will be scoped to this path
--personal is personal repository
--private is private repository (default true)
--personal if true, the owner is assumed to be a GitHub user; otherwise an org
--private if true, the repository is assumed to be private (default true)
--repository string GitHub repository name
--ssh-hostname string GitHub SSH hostname, to be used when the SSH host differs from the HTTPS one
--team stringArray GitHub team to be given maintainer access
@@ -74,8 +74,9 @@ flux bootstrap github [flags]
--registry string container registry where the toolkit images are published (default "ghcr.io/fluxcd")
--timeout duration timeout for this operation (default 5m0s)
--token-auth when enabled, the personal access token will be used instead of SSH deploy key
--toleration-keys strings list of toleration keys used to schedule the components pods onto nodes with matching taints
--verbose print generated objects
-v, --version string toolkit version (default "latest")
-v, --version string toolkit version, when specified the manifests are downloaded from https://github.com/fluxcd/flux2/releases
--watch-all-namespaces watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
```

View File

@@ -48,8 +48,8 @@ flux bootstrap gitlab [flags]
--interval duration sync interval (default 1m0s)
--owner string GitLab user or group name
--path safeRelativePath path relative to the repository root, when specified the cluster sync will be scoped to this path
--personal is personal repository
--private is private repository (default true)
--personal if true, the owner is assumed to be a GitLab user; otherwise a group
--private if true, the repository is assumed to be private (default true)
--repository string GitLab repository name
--ssh-hostname string GitLab SSH hostname, to be used when the SSH host differs from the HTTPS one
```
@@ -70,8 +70,9 @@ flux bootstrap gitlab [flags]
--registry string container registry where the toolkit images are published (default "ghcr.io/fluxcd")
--timeout duration timeout for this operation (default 5m0s)
--token-auth when enabled, the personal access token will be used instead of SSH deploy key
--toleration-keys strings list of toleration keys used to schedule the components pods onto nodes with matching taints
--verbose print generated objects
-v, --version string toolkit version (default "latest")
-v, --version string toolkit version, when specified the manifests are downloaded from https://github.com/fluxcd/flux2/releases
--watch-all-namespaces watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
```

View File

@@ -25,9 +25,10 @@ flux check [flags]
### Options
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
-h, --help help for check
--pre only run pre-installation checks
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
--components-extra strings list of components in addition to those supplied or defaulted, accepts comma-separated values
-h, --help help for check
--pre only run pre-installation checks
```
### Options inherited from parent commands

View File

@@ -32,11 +32,12 @@ flux create helmrelease [name] [flags]
--source=Bucket/podinfo \
--chart=./charts/podinfo
# Create a HelmRelease with values from a local YAML file
# Create a HelmRelease with values from local YAML files
flux create hr podinfo \
--source=HelmRepository/podinfo \
--chart=podinfo \
--values=./my-values.yaml
--values=./my-values1.yaml \
--values=./my-values2.yaml
# Create a HelmRelease with values from a Kubernetes secret
kubectl -n app create secret generic my-secret-values \
@@ -78,7 +79,7 @@ flux create helmrelease [name] [flags]
--service-account string the name of the service account to impersonate when reconciling this HelmRelease
--source helmChartSource source that contains the chart in the format '<kind>/<name>', where kind must be one of: (HelmRepository, GitRepository, Bucket)
--target-namespace string namespace to install this release, defaults to the HelmRelease namespace
--values string local path to the values.yaml file
--values stringArray local path to values.yaml files
--values-from helmReleaseValuesFrom Kubernetes object reference that contains the values.yaml data key in the format '<kind>/<name>', where kind must be one of: (Secret, ConfigMap)
```

View File

@@ -18,10 +18,13 @@ flux create image policy <name> [flags]
### Options
```
--filter-regex string regular expression pattern used to filter the image tags
-h, --help help for policy
--image-ref string the name of an image repository object
--semver string a semver range to apply to tags; e.g., '1.x'
--filter-extract string replacement pattern (using capture groups from --filter-regex) to use for sorting
--filter-regex string regular expression pattern used to filter the image tags
-h, --help help for policy
--image-ref string the name of an image repository object
--select-alpha string use alphabetical sorting to select image; either "asc" meaning select the last, or "desc" meaning select the first
--select-numeric string use numeric sorting to select image; either "asc" meaning select the last, or "desc" meaning select the first
--select-semver string a semver range to apply to tags; e.g., '1.x'
```
### Options inherited from parent commands

View File

@@ -11,9 +11,40 @@ An ImageRepository object specifies an image repository to scan.
flux create image repository <name> [flags]
```
### Examples
```
# Create an ImageRepository object to scan the alpine image repository:
flux create image repository alpine-repo --image alpine --interval 20m
# Create an image repository that uses an image pull secret (assumed to
# have been created already):
flux create image repository myapp-repo \
--secret-ref image-pull \
--image ghcr.io/example.com/myapp --interval 5m
# Create a TLS secret for a local image registry using a self-signed
# host certificate, and use it to scan an image. ca.pem is a file
# containing the CA certificate used to sign the host certificate.
flux create secret tls local-registry-cert --ca-file ./ca.pem
flux create image repository app-repo \
--cert-secret-ref local-registry-cert \
--image local-registry:5000/app --interval 5m
# Create a TLS secret with a client certificate and key, and use it
# to scan a private image registry.
flux create secret tls client-cert \
--cert-file client.crt --key-file client.key
flux create image repository app-repo \
--cert-secret-ref client-cert \
--image registry.example.com/private/app --interval 5m
```
### Options
```
--cert-ref string the name of a secret to use for TLS certificates
-h, --help help for repository
--image string the image repository to scan; e.g., library/alpine
--scan-timeout duration a timeout for scanning; this defaults to the interval if not set

View File

@@ -30,4 +30,5 @@ The create source sub-commands generate Kubernetes secrets specific to Flux.
* [flux create](flux_create.md) - Create or update sources and resources
* [flux create secret git](flux_create_secret_git.md) - Create or update a Kubernetes secret for Git authentication
* [flux create secret helm](flux_create_secret_helm.md) - Create or update a Kubernetes secret for Helm repository authentication
* [flux create secret tls](flux_create_secret_tls.md) - Create or update a Kubernetes secret with TLS certificates

View File

@@ -50,6 +50,7 @@ flux create secret git [name] [flags]
### Options
```
--ca-file string path to TLS CA file used for validating self-signed certificates
-h, --help help for git
-p, --password string basic authentication password
--ssh-ecdsa-curve ecdsaCurve SSH ECDSA public key curve (p256, p384, p521) (default p384)

View File

@@ -0,0 +1,56 @@
## flux create secret tls
Create or update a Kubernetes secret with TLS certificates
### Synopsis
The create secret tls command generates a Kubernetes secret with certificates for use with TLS.
```
flux create secret tls [name] [flags]
```
### Examples
```
# Create a TLS secret on disk and encrypt it with Mozilla SOPS.
# Files are expected to be PEM-encoded.
flux create secret tls certs \
--namespace=my-namespace \
--cert-file=./client.crt \
--key-file=./client.key \
--export > certs.yaml
sops --encrypt --encrypted-regex '^(data|stringData)$' \
--in-place certs.yaml
```
### Options
```
--ca-file string TLS authentication CA file path
--cert-file string TLS authentication cert file path
-h, --help help for tls
--key-file string TLS authentication key file path
```
### Options inherited from parent commands
```
--context string kubernetes context to use
--export export in YAML format to stdout
--interval duration source sync interval (default 1m0s)
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--label strings set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2)
-n, --namespace string the namespace scope for this operation (default "flux-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [flux create secret](flux_create_secret.md) - Create or update Kubernetes secrets

View File

@@ -56,6 +56,7 @@ flux create source git [name] [flags]
```
--branch string git branch (default "master")
--ca-file string path to TLS CA file used for validating self-signed certificates, requires libgit2
--git-implementation gitImplementation the Git implementation to use, available options are: (go-git, libgit2)
-h, --help help for git
-p, --password string basic authentication password

View File

@@ -28,8 +28,8 @@ The delete sub-commands delete sources and resources.
* [flux](flux.md) - Command line utility for assembling Kubernetes CD pipelines
* [flux delete alert](flux_delete_alert.md) - Delete a Alert resource
* [flux delete alert-provider](flux_delete_alert-provider.md) - Delete a Provider resource
* [flux delete auto](flux_delete_auto.md) - Delete automation objects
* [flux delete helmrelease](flux_delete_helmrelease.md) - Delete a HelmRelease resource
* [flux delete image](flux_delete_image.md) - Delete image automation objects
* [flux delete kustomization](flux_delete_kustomization.md) - Delete a Kustomization resource
* [flux delete receiver](flux_delete_receiver.md) - Delete a Receiver resource
* [flux delete source](flux_delete_source.md) - Delete sources

View File

@@ -1,15 +1,15 @@
## flux delete auto
## flux delete image
Delete automation objects
Delete image automation objects
### Synopsis
The delete auto sub-commands delete automation objects.
The delete image sub-commands delete image automation objects.
### Options
```
-h, --help help for auto
-h, --help help for image
```
### Options inherited from parent commands
@@ -26,7 +26,7 @@ The delete auto sub-commands delete automation objects.
### SEE ALSO
* [flux delete](flux_delete.md) - Delete sources and resources
* [flux delete auto image-policy](flux_delete_auto_image-policy.md) - Delete an ImagePolicy object
* [flux delete auto image-repository](flux_delete_auto_image-repository.md) - Delete an ImageRepository object
* [flux delete auto image-update](flux_delete_auto_image-update.md) - Delete an ImageUpdateAutomation object
* [flux delete image policy](flux_delete_image_policy.md) - Delete an ImagePolicy object
* [flux delete image repository](flux_delete_image_repository.md) - Delete an ImageRepository object
* [flux delete image update](flux_delete_image_update.md) - Delete an ImageUpdateAutomation object

View File

@@ -1,27 +1,27 @@
## flux delete auto image-policy
## flux delete image policy
Delete an ImagePolicy object
### Synopsis
The delete auto image-policy command deletes the given ImagePolicy from the cluster.
The delete image policy command deletes the given ImagePolicy from the cluster.
```
flux delete auto image-policy [name] [flags]
flux delete image policy [name] [flags]
```
### Examples
```
# Delete an image policy
flux delete auto image-policy alpine3.x
flux delete image policy alpine3.x
```
### Options
```
-h, --help help for image-policy
-h, --help help for policy
```
### Options inherited from parent commands
@@ -37,5 +37,5 @@ flux delete auto image-policy [name] [flags]
### SEE ALSO
* [flux delete auto](flux_delete_auto.md) - Delete automation objects
* [flux delete image](flux_delete_image.md) - Delete image automation objects

View File

@@ -1,27 +1,27 @@
## flux delete auto image-repository
## flux delete image repository
Delete an ImageRepository object
### Synopsis
The delete auto image-repository command deletes the given ImageRepository from the cluster.
The delete image repository command deletes the given ImageRepository from the cluster.
```
flux delete auto image-repository [name] [flags]
flux delete image repository [name] [flags]
```
### Examples
```
# Delete an image repository
flux delete auto image-repository alpine
flux delete image repository alpine
```
### Options
```
-h, --help help for image-repository
-h, --help help for repository
```
### Options inherited from parent commands
@@ -37,5 +37,5 @@ flux delete auto image-repository [name] [flags]
### SEE ALSO
* [flux delete auto](flux_delete_auto.md) - Delete automation objects
* [flux delete image](flux_delete_image.md) - Delete image automation objects

View File

@@ -1,27 +1,27 @@
## flux delete auto image-update
## flux delete image update
Delete an ImageUpdateAutomation object
### Synopsis
The delete auto image-update command deletes the given ImageUpdateAutomation from the cluster.
The delete image update command deletes the given ImageUpdateAutomation from the cluster.
```
flux delete auto image-update [name] [flags]
flux delete image update [name] [flags]
```
### Examples
```
# Delete an image update automation
flux delete auto image-update latest-images
flux delete image update latest-images
```
### Options
```
-h, --help help for image-update
-h, --help help for update
```
### Options inherited from parent commands
@@ -37,5 +37,5 @@ flux delete auto image-update [name] [flags]
### SEE ALSO
* [flux delete auto](flux_delete_auto.md) - Delete automation objects
* [flux delete image](flux_delete_image.md) - Delete image automation objects

View File

@@ -29,7 +29,7 @@ The get sub-commands print the statuses of sources and resources.
* [flux get alert-providers](flux_get_alert-providers.md) - Get Provider statuses
* [flux get alerts](flux_get_alerts.md) - Get Alert statuses
* [flux get helmreleases](flux_get_helmreleases.md) - Get HelmRelease statuses
* [flux get image](flux_get_image.md) - Get image automation object status
* [flux get images](flux_get_images.md) - Get image automation object status
* [flux get kustomizations](flux_get_kustomizations.md) - Get Kustomization statuses
* [flux get receivers](flux_get_receivers.md) - Get Receiver statuses
* [flux get sources](flux_get_sources.md) - Get source statuses

View File

@@ -1,4 +1,4 @@
## flux get image
## flux get images
Get image automation object status
@@ -9,7 +9,7 @@ The get image sub-commands print the status of image automation objects.
### Options
```
-h, --help help for image
-h, --help help for images
```
### Options inherited from parent commands
@@ -26,7 +26,7 @@ The get image sub-commands print the status of image automation objects.
### SEE ALSO
* [flux get](flux_get.md) - Get sources and resources
* [flux get image policy](flux_get_image_policy.md) - Get ImagePolicy status
* [flux get image repository](flux_get_image_repository.md) - Get ImageRepository status
* [flux get image update](flux_get_image_update.md) - Get ImageUpdateAutomation status
* [flux get images policy](flux_get_images_policy.md) - Get ImagePolicy status
* [flux get images repository](flux_get_images_repository.md) - Get ImageRepository status
* [flux get images update](flux_get_images_update.md) - Get ImageUpdateAutomation status

View File

@@ -1,4 +1,4 @@
## flux get image policy
## flux get images policy
Get ImagePolicy status
@@ -7,7 +7,7 @@ Get ImagePolicy status
The get image policy command prints the status of ImagePolicy objects.
```
flux get image policy [flags]
flux get images policy [flags]
```
### Examples
@@ -40,5 +40,5 @@ flux get image policy [flags]
### SEE ALSO
* [flux get image](flux_get_image.md) - Get image automation object status
* [flux get images](flux_get_images.md) - Get image automation object status

View File

@@ -1,4 +1,4 @@
## flux get image repository
## flux get images repository
Get ImageRepository status
@@ -7,7 +7,7 @@ Get ImageRepository status
The get image repository command prints the status of ImageRepository objects.
```
flux get image repository [flags]
flux get images repository [flags]
```
### Examples
@@ -40,5 +40,5 @@ flux get image repository [flags]
### SEE ALSO
* [flux get image](flux_get_image.md) - Get image automation object status
* [flux get images](flux_get_images.md) - Get image automation object status

View File

@@ -1,4 +1,4 @@
## flux get image update
## flux get images update
Get ImageUpdateAutomation status
@@ -7,7 +7,7 @@ Get ImageUpdateAutomation status
The get image update command prints the status of ImageUpdateAutomation objects.
```
flux get image update [flags]
flux get images update [flags]
```
### Examples
@@ -40,5 +40,5 @@ flux get image update [flags]
### SEE ALSO
* [flux get image](flux_get_image.md) - Get image automation object status
* [flux get images](flux_get_images.md) - Get image automation object status

View File

@@ -1,10 +1,10 @@
## flux install
Install the toolkit components
Install or upgrade Flux
### Synopsis
The install command deploys the toolkit components in the specified namespace.
The install command deploys Flux in the specified namespace.
If a previous version is installed, then an in-place upgrade will be performed.
```
@@ -17,9 +17,12 @@ flux install [flags]
# 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
# Install a specific version and a series of components
flux install --dry-run --version=v0.0.7 --components="source-controller,kustomize-controller"
# Install Flux onto tainted Kubernetes nodes
flux install --toleration-keys=node.kubernetes.io/dedicated-to-flux
# Dry-run install with manifests preview
flux install --dry-run --verbose
@@ -41,7 +44,8 @@ flux install [flags]
--log-level logLevel log level, available options are: (debug, info, error) (default info)
--network-policy deny ingress access to the toolkit controllers from other namespaces using network policies (default true)
--registry string container registry where the toolkit images are published (default "ghcr.io/fluxcd")
-v, --version string toolkit version (default "latest")
--toleration-keys strings list of toleration keys used to schedule the components pods onto nodes with matching taints
-v, --version string toolkit version, when specified the manifests are downloaded from https://github.com/fluxcd/flux2/releases
--watch-all-namespaces watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
```

View File

@@ -1,10 +1,10 @@
## flux uninstall
Uninstall the toolkit components
Uninstall Flux and its custom resource definitions
### Synopsis
The uninstall command removes the namespace, cluster roles, cluster role bindings and CRDs from the cluster.
The uninstall command removes the Flux components and the toolkit.fluxcd.io resources from the cluster.
```
flux uninstall [flags]
@@ -13,22 +13,21 @@ flux uninstall [flags]
### Examples
```
# Dry-run uninstall of all components
flux uninstall --dry-run --namespace=flux-system
# Uninstall Flux components, its custom resources and namespace
flux uninstall --namespace=flux-system
# Uninstall all components and delete custom resource definitions
flux uninstall --resources --crds --namespace=flux-system
# Uninstall Flux but keep the namespace
flux uninstall --namespace=infra --keep-namespace=true
```
### Options
```
--crds removes all CRDs previously installed
--dry-run only print the object that would be deleted
-h, --help help for uninstall
--resources removes custom resources such as Kustomizations, GitRepositories and HelmRepositories (default true)
-s, --silent delete components without asking for confirmation
--dry-run only print the objects that would be deleted
-h, --help help for uninstall
--keep-namespace skip namespace deletion
-s, --silent delete components without asking for confirmation
```
### Options inherited from parent commands

View File

@@ -20,6 +20,7 @@ Features:
- Runs Helm install/upgrade in a specific order, taking into account the depends-on relationship defined in a set of `HelmRelease` objects
- Prunes Helm releases removed from cluster (garbage collection)
- Reports Helm releases statuses (alerting provided by [notification-controller](../notification/controller.md))
- Built-in Kustomize compatible Helm post renderer, providing support for strategic merge, JSON 6902 and images patches
Links:

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