1
0
mirror of synced 2026-03-01 19:26:55 +00:00

Compare commits

..

190 Commits

Author SHA1 Message Date
Stefan Prodan
3dfd0bc2e1 Merge pull request #1117 from fluxcd/update-image-auto-guide]
Add push branch and commit template to image automation guide
2021-03-18 15:52:01 +02:00
Stefan Prodan
10ff99542f Add image update automation diagram
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-03-18 14:20:01 +02:00
Stefan Prodan
2449030ab8 Add push branch and commit template to image automation guide
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-03-18 13:56:42 +02:00
Stefan Prodan
3e85901f40 Merge pull request #1116 from fluxcd/get-all-sources-images
Implement get all for sources and images
2021-03-18 13:30:52 +02:00
Stefan Prodan
73b1576f81 Implement get all for sources and images
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-03-18 13:00:49 +02:00
Stefan Prodan
cdb5b7c9a2 Merge pull request #1113 from fluxcd/create-image-update
Add repo path and push branch to image update cmd
2021-03-18 12:35:08 +02:00
Stefan Prodan
d9331b0c91 Add repo path and push branch to image update cmd
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-03-18 11:10:21 +01:00
Stefan Prodan
b6a8163dd9 Add create image policy examples
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-03-18 11:10:21 +01:00
Stefan Prodan
185252ba48 Update flux logs examples
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-03-18 11:10:21 +01:00
Stefan Prodan
043d37921b Merge pull request #1091 from joebowbeer/patch-1
Fix deployment name in image update guide
2021-03-18 10:43:04 +02:00
Joe Bowbeer
02fb8d9958 Merge branch 'main' into patch-1 2021-03-17 14:29:42 -07:00
Stefan Prodan
cfa6c0a178 Merge pull request #1095 from fluxcd/update-components
Update toolkit components
2021-03-17 14:58:04 +02:00
fluxcdbot
e8b52bf2fc Update toolkit components
- helm-controller to v0.8.2
  https://github.com/fluxcd/helm-controller/blob/v0.8.2/CHANGELOG.md
- kustomize-controller to v0.9.3
  https://github.com/fluxcd/kustomize-controller/blob/v0.9.3/CHANGELOG.md
- source-controller to v0.9.1
  https://github.com/fluxcd/source-controller/blob/v0.9.1/CHANGELOG.md
- notification-controller to v0.10.0
  https://github.com/fluxcd/notification-controller/blob/v0.10.0/CHANGELOG.md
- image-reflector-controller to v0.7.1
  https://github.com/fluxcd/image-reflector-controller/blob/v0.7.1/CHANGELOG.md
- image-automation-controller to v0.7.0
  https://github.com/fluxcd/image-automation-controller/blob/v0.7.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2021-03-17 12:45:22 +00:00
Joe Bowbeer
85fbb780bf Update image-update.md
The filename is podinfo-deployment.yaml

Signed-off-by: Joe Bowbeer <joe.bowbeer@gmail.com>
2021-03-16 18:58:38 -07:00
Hidde Beydals
bd9f9bf518 Merge pull request #1103 from fluxcd/build/fix-go-mod-update
Fix updating of `go.mod` entries for components
2021-03-16 16:31:17 +01:00
Hidde Beydals
077860fff1 Fix updating of go.mod entries for components
We noticed that some of our components had not received `go.mod` updates
while they did receive updates for the versions declared in the YAML
manifests.

Was able to trace this back to a behavior change in Go since `1.16.x`,
resulting in it no longer making automated changes to `go.mod` and
`go.sum`[1]. This is an issue for our updater script as it relies
on `go list -m all`, which now after the first `go mod edit` returns:

```console
$ go list -m all
go: github.com/fluxcd/notification-controller/api@v0.10.0: missing
go.sum entry; to add it:
        go mod download github.com/fluxcd/notification-controller/api
```

To work around the issue without having to repeatedly call `go mod
tidy`, I have opted to simply `grep` on the contents of `go.mod` as a
workaround.

[1]: https://blog.golang.org/go116-module-changes#TOC_3.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-03-16 16:11:29 +01:00
Stefan Prodan
d29a4ee4d2 Merge pull request #1075 from SomtochiAma/formatted-logs
Implement flux logs command
2021-03-16 16:16:36 +02:00
Somtochi Onyekwere
6d2e34e9b2 Add flux logs command
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-03-16 14:59:03 +01:00
Hidde Beydals
0b6969537b Merge pull request #1102 from fluxcd/fix-sshscan-port
Use Host from parsed URL instead of Hostname
2021-03-16 14:17:07 +01:00
Hidde Beydals
dc6b0d0f0d Use Host from parsed URL instead of Hostname
Regression bug introduced in #1001.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-03-16 14:01:46 +01:00
Hidde Beydals
b4dbb178fe Merge pull request #1098 from kingdonb/fixup-hint-1
Fix hint in Flux v1 Migration guide
2021-03-15 17:33:03 +01:00
Kingdon Barrett
4cf5290989 fixup hint in Flux v1 Migration guide
The wrong indenting means the hint body will not display as a hint

Signed-off-by: Kingdon Barrett <kingdon@weave.works>
2021-03-15 11:50:37 -04:00
Hidde Beydals
6ffd2222c2 Merge pull request #1094 from fluxcd/status-pkg
Move `StatusChecker` to separate and generic pkg
2021-03-15 11:57:52 +01:00
Hidde Beydals
e7725911a7 Move StatusChecker to separate and generic pkg
This commit moves the `StatusChecker` to a separate package, while
making it more generic so that it is able to assess the status of any
given set of `object.ObjMetadata` identifiers.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-03-15 11:41:02 +01:00
Hidde Beydals
0c1664cd01 Merge pull request #1093 from fluxcd/build-bootstrap-action-changes 2021-03-15 11:33:31 +01:00
Hidde Beydals
0239307d8e Change repository name used in bootstrap tests
This changes the name of the repository that is used for the GitHub
end-to-end tests to a name that is still traceable to the source
(repository) that created it, by using the format
`<ORIGIN_REPOSITORY_NAME>-<PSEUDO_RAND_SUFFIX>`.

The `PSEUDO_RAND_SUFFIX` is a SHA1 sum of the name of the branch and
commit SHA the tests run for, resulting in a 40 character suffix that
unlike the short commit SHA used before, should not result in collisions.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-03-15 11:20:26 +01:00
Hidde Beydals
9f10b6be1b Replace delete opt on GitHub bootstrap with curl
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-03-15 11:20:26 +01:00
Stefan Prodan
01f613b39e Merge pull request #1036 from scottrigby/migration-timetable
Migration and Support Timetable
2021-03-14 09:52:20 +02:00
Scott Rigby
b775d11a70 Flux Migration and Support Timetable
* Set explicit column widths for timetable

  No need for old Firefox workaround. It appears fine on FF in 2021

  See:
  - https://github.com/squidfunk/mkdocs-material/issues/922
  - https://github.com/squidfunk/mkdocs-material/issues/118

* Hide TOC right column on migration table page

* SDK->GOTK footnote

* Cross-link admonitions between Roadmap and Timetable

  To-do: change structure and file names under migration menu dir when we
  move to fluxcd/website

* Add custom heart admonition

* Link to documentated deprecation of apiextensions.k8s.io/v1beta1
  CustomResourceDefinition

* Fix caret (^^ underlines short status)

* Initial migration and Support Timetable

  Add mkdocs markdown_extensions and sort them alphabetically

Co-authored-by: Stefan Prodan <stefan.prodan@gmail.com>
Signed-off-by: Scott Rigby <scott@r6by.com>
2021-03-13 22:24:21 -05:00
Stefan Prodan
022576697f Merge pull request #1086 from squat/export_source_typo
cmd/flux/export_source*: fix typo in comment
2021-03-12 14:55:01 +02:00
Lucas Servén Marín
065d0b2c06 cmd/flux/export_source*: fix typo in comment
This commit fixes a small typo in the comments for the export source
commands.

Signed-off-by: Lucas Servén Marín <lserven@gmail.com>
2021-03-12 13:41:46 +01:00
Stefan Prodan
ed4718205a Merge pull request #1065 from fluxcd/build-prerequisites
Add Go 1.16 to prerequisites (contributing doc)
2021-03-12 12:45:24 +02:00
Stefan Prodan
a29d0c536d Add Go 1.16 to prerequisites (contributing doc)
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-03-12 12:28:43 +02:00
Hidde Beydals
eaeb8ca5c1 Merge pull request #1025 from gliptak/patch-1
Correct ineffassign
2021-03-10 18:12:20 +01:00
Gábor Lipták
2092c14aca Correct ineffassign
Signed-off-by: Gábor Lipták <gliptak@gmail.com>
2021-03-10 17:10:26 +00:00
Stefan Prodan
69f38b8c77 Merge pull request #1027 from stealthybox/sops-gpg-batch
Improve SOPS GPG guide key management
2021-03-10 10:04:40 +02:00
leigh capili
d2cdd02a57 Parameterize GPG key input and fingerprint
Signed-off-by: leigh capili <leigh@null.net>
2021-03-09 17:11:53 -07:00
leigh capili
095c8323a1 Capitalize SOPS, K8s, and Git
Signed-off-by: leigh capili <leigh@null.net>
2021-03-09 17:11:53 -07:00
leigh capili
accb4c915e Improve SOPS GPG guide key management
- Switch to batch GPG key creation
- Accurately name the cluster's decryption key
- Suggest password-manager backup
- Optionally cleanup secret key from generating machine
- Optionally commit the public key to the repo for team members
- Document SOPS limitations decryption required for editing / appending fields

Signed-off-by: leigh capili <leigh@null.net>
2021-03-09 17:11:52 -07:00
Hidde Beydals
242809f61d Merge pull request #1069 from fluxcd/doc-link-fix
docs: fix link to source-controller documentation
2021-03-09 12:15:06 +01:00
Hidde Beydals
c4907cf6c6 docs: fix link to source-controller documentation
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-03-09 10:16:15 +01:00
Hidde Beydals
a4b9191fa3 Merge pull request #1066 from fluxcd/manifest-bundle-tweaks 2021-03-09 09:14:07 +01:00
Hidde Beydals
5fd3d0bd41 Generate manifests in flux-{go,scm} AUR packages
This commit makes a couple of changes to the `flux-{go,scm}` packages
so that they properly build again:

- The manifests are generated before the compilation of the `flux`
  binary.
- The `makedepends` have been updated to require a version of Go
  `>=1.16` (which is a requirement for `embed`).
- The `makedepends` have been updated to require a `kustomize` version
  `>=3.0` (as we use `transformers`).

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-03-08 19:06:07 +01:00
Hidde Beydals
ba6da23323 Make manifests dir bundle.sh configurable
There was an assumption in this script that it is always executed in Git
repository/directory, this is however not always true, for example when
one downloads the `.tar.gz` that is made available for every release
by GitHub (and used in one of our AUR packages).

This commit changes this, and makes the first argument of `bundle.sh`
configurable, so a custom manifests directory can always be defined
_without_ relying on Git.

Omitting it, or passing an empty string, will still fall back to the
previous behavior of using `git rev-parse --show-toplevel`.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-03-08 18:45:05 +01:00
Hidde Beydals
0328bb14ce Merge pull request #1062 from fluxcd/improve-embedded-manifests-build
Improve build process embedded manifests
2021-03-08 16:25:48 +01:00
Hidde Beydals
2b7a0f3fd4 Improve build process embedded manifests
This commit changes the way the build of manifests is triggered by
making smarter use of the capabilities of Make. The result should be
that the manifests are only regenerated if:

1. There is no `cmd/flux/manifests/` directory.
2. There have been made changes to the YAML files in the `manifests/`
   directory that are newer than the files in `cmd/flux/manifests/`.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-03-08 16:06:44 +01:00
Hidde Beydals
527886bea0 Merge pull request #1060 from fluxcd/aur-pkg-autocomplete-install
Install Bash, Fish, ZSH auto complete in AUR pkgs
2021-03-08 13:35:01 +01:00
Hidde Beydals
98078a0c65 Install Bash, Fish, ZSH auto complete in AUR pkgs
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-03-08 13:16:50 +01:00
Stefan Prodan
ca660b7ba5 Merge pull request #1048 from fluxcd/restore-key-algorithm-default
Restore default key algorithm flag create source
2021-03-05 15:58:56 +02:00
Hidde Beydals
ed93e93b81 Restore default key algorithm flag create source
This was removed by accident in the PR that introduced the new
`manifestgen` packages, and now restored in full glory.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-03-05 14:40:02 +01:00
Stefan Prodan
80419f00db Merge pull request #1043 from fluxcd/update-components
Update toolkit components
2021-03-05 12:11:34 +02:00
fluxcdbot
01946facb3 Update toolkit components
- helm-controller to v0.8.1
  https://github.com/fluxcd/helm-controller/blob/v0.8.1/CHANGELOG.md
- kustomize-controller to v0.9.2
  https://github.com/fluxcd/kustomize-controller/blob/v0.9.2/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2021-03-05 09:47:51 +00:00
Stefan Prodan
08c1bd7653 Merge pull request #1034 from stealthybox/fix-migration-link
Fix anchor on kustomize migration link
2021-03-04 18:23:39 +02:00
leigh capili
ebf9188c6a Fix anchor on kustomize migration link
Signed-off-by: leigh capili <leigh@null.net>
2021-03-04 08:56:22 -07:00
Stefan Prodan
382c6d5885 Merge pull request #1033 from fluxcd/docs-migration-faq
Move the v1 vs v2 FAQ to the migration section
2021-03-04 11:24:46 +02:00
Stefan Prodan
384c60a988 Move the v1 vs v2 FAQ to the migration section
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-03-04 10:44:57 +02:00
Hidde Beydals
0078147587 Merge pull request #1022 from fluxcd/create-kustomization-path-fix
Use path with '/' slashes in created Kustomization
2021-03-02 11:35:35 +01:00
Hidde Beydals
d79bedf2bc Use path with '/' slashes in created Kustomization
This fixes a bug on Windows where the safe relative path would contain
'\' slashes, which are not compatible with the controller.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-03-02 11:13:19 +01:00
Hidde Beydals
14b31b321c Merge pull request #1008 from fluxcd/helm-faq 2021-03-01 21:20:56 +01:00
Stefan Prodan
309b9b52f8 Add Helm Controller standalone FAQ to migration guide
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-03-01 21:07:49 +01:00
Stefan Prodan
5d063e7390 faq: Can I use Flux HelmReleases without GitOps?
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-03-01 21:07:49 +01:00
Hidde Beydals
e7ba9b5624 Merge pull request #1018 from tvories/docs/fish_completions 2021-03-01 17:02:41 +01:00
tvories
81f6fa598f Updated godocs to match readme
Signed-off-by: tvories <taylor@tmtech.me>
2021-03-01 08:49:29 -07:00
tvories
d9eabcdbf7 Removed posix style loading for flux and added .fish filetype to completions file
Signed-off-by: tvories <taylor@tmtech.me>
2021-03-01 08:39:04 -07:00
Hidde Beydals
bb3562427b Merge pull request #1001 from fluxcd/manifestgen-deploysecret-kustomization
Add `sourcesecret` and `kustomization` manifestgen
2021-02-26 17:16:13 +01:00
Hidde Beydals
8a5bba80bf Add sourcesecret and kustomization manifestgen
This includes a change to the `sync` generator to make the deploy
secret name configurable.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-26 16:58:41 +01:00
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
167 changed files with 5751 additions and 1696 deletions

View File

@@ -8,18 +8,20 @@ pkgdesc="Open and extensible continuous delivery solution for Kubernetes"
url="https://fluxcd.io/"
arch=("x86_64" "armv6h" "armv7h" "aarch64")
license=("APACHE")
optdepends=("kubectl")
optdepends=('kubectl: for apply actions on the Kubernetes cluster',
'bash-completion: auto-completion for flux in Bash',
'zsh-completions: auto-completion for flux in ZSH')
source_x86_64=(
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_amd64.tar.gz"
"${pkgname}-${pkgver}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_amd64.tar.gz"
)
source_armv6h=(
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_arm.tar.gz"
"${pkgname}-${pkgver}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_arm.tar.gz"
)
source_armv7h=(
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_arm.tar.gz"
"${pkgname}-${pkgver}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_arm.tar.gz"
)
source_aarch64=(
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_arm64.tar.gz"
"${pkgname}-${pkgver}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_arm64.tar.gz"
)
sha256sums_x86_64=(
${SHA256SUM_AMD64}
@@ -33,7 +35,12 @@ sha256sums_armv7h=(
sha256sums_aarch64=(
${SHA256SUM_ARM64}
)
_srcname=flux
package() {
install -Dm755 flux "$pkgdir/usr/bin/flux"
install -Dm755 ${_srcname} "${pkgdir}/usr/bin/${_srcname}"
"${pkgdir}/usr/bin/${_srcname}" completion bash | install -Dm644 /dev/stdin "${pkgdir}/usr/share/bash-completion/completions/${_srcname}"
"${pkgdir}/usr/bin/${_srcname}" completion fish | install -Dm644 /dev/stdin "${pkgdir}/usr/share/fish/vendor_completions.d/${_srcname}.fish"
"${pkgdir}/usr/bin/${_srcname}" completion zsh | install -Dm644 /dev/stdin "${pkgdir}/usr/share/zsh/site-functions/_${_srcname}"
}

View File

@@ -12,32 +12,40 @@ provides=("flux-bin")
conflicts=("flux-bin")
replaces=("flux-cli")
depends=("glibc")
makedepends=("go")
optdepends=("kubectl")
makedepends=('go>=1.16', 'kustomize>=3.0')
optdepends=('kubectl: for apply actions on the Kubernetes cluster',
'bash-completion: auto-completion for flux in Bash',
'zsh-completions: auto-completion for flux in ZSH')
source=(
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/archive/v$pkgver.tar.gz"
"${pkgname}-${pkgver}.tar.gz::https://github.com/fluxcd/flux2/archive/v${pkgver}.tar.gz"
)
sha256sums=(
${SHA256SUM}
)
_srcname=flux
build() {
cd "flux2-$pkgver"
cd "flux2-${pkgver}"
export CGO_LDFLAGS="$LDFLAGS"
export CGO_CFLAGS="$CFLAGS"
export CGO_CXXFLAGS="$CXXFLAGS"
export CGO_CPPFLAGS="$CPPFLAGS"
export GOFLAGS="-buildmode=pie -trimpath -ldflags=-linkmode=external -mod=readonly -modcacherw"
go build -ldflags "-X main.VERSION=$pkgver" -o flux-bin ./cmd/flux
export GOFLAGS="-buildmode=pie -trimpath -mod=readonly -modcacherw"
./manifests/scripts/bundle.sh "${PWD}/manifests" "${PWD}/cmd/flux/manifests"
go build -ldflags "-linkmode=external -X main.VERSION=${pkgver}" -o ${_srcname} ./cmd/flux
}
check() {
cd "flux2-$pkgver"
cd "flux2-${pkgver}"
make test
}
package() {
cd "flux2-$pkgver"
install -Dm755 flux-bin "$pkgdir/usr/bin/flux"
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
cd "flux2-${pkgver}"
install -Dm755 ${_srcname} "${pkgdir}/usr/bin/${_srcname}"
install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
"${pkgdir}/usr/bin/${_srcname}" completion bash | install -Dm644 /dev/stdin "${pkgdir}/usr/share/bash-completion/completions/${_srcname}"
"${pkgdir}/usr/bin/${_srcname}" completion fish | install -Dm644 /dev/stdin "${pkgdir}/usr/share/fish/vendor_completions.d/${_srcname}.fish"
"${pkgdir}/usr/bin/${_srcname}" completion zsh | install -Dm644 /dev/stdin "${pkgdir}/usr/share/zsh/site-functions/_${_srcname}"
}

View File

@@ -11,12 +11,15 @@ license=("APACHE")
provides=("flux-bin")
conflicts=("flux-bin")
depends=("glibc")
makedepends=("go")
optdepends=("kubectl")
makedepends=('go>=1.16', 'kustomize>=3.0')
optdepends=('kubectl: for apply actions on the Kubernetes cluster',
'bash-completion: auto-completion for flux in Bash',
'zsh-completions: auto-completion for flux in ZSH')
source=(
"git+https://github.com/fluxcd/flux2.git"
)
md5sums=('SKIP')
_srcname=flux
pkgver() {
cd "flux2"
@@ -29,8 +32,9 @@ build() {
export CGO_CFLAGS="$CFLAGS"
export CGO_CXXFLAGS="$CXXFLAGS"
export CGO_CPPFLAGS="$CPPFLAGS"
export GOFLAGS="-buildmode=pie -trimpath -ldflags=-linkmode=external -mod=readonly -modcacherw"
go build -ldflags "-X main.VERSION=$pkgver" -o flux-bin ./cmd/flux
export GOFLAGS="-buildmode=pie -trimpath -mod=readonly -modcacherw"
make cmd/flux/manifests
go build -ldflags "-linkmode=external -X main.VERSION=${pkgver}" -o ${_srcname} ./cmd/flux
}
check() {
@@ -40,6 +44,10 @@ check() {
package() {
cd "flux2"
install -Dm755 flux-bin "$pkgdir/usr/bin/flux"
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
install -Dm755 ${_srcname} "${pkgdir}/usr/bin/${_srcname}"
install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
"${pkgdir}/usr/bin/${_srcname}" completion bash | install -Dm644 /dev/stdin "${pkgdir}/usr/share/bash-completion/completions/${_srcname}"
"${pkgdir}/usr/bin/${_srcname}" completion fish | install -Dm644 /dev/stdin "${pkgdir}/usr/share/fish/vendor_completions.d/${_srcname}.fish"
"${pkgdir}/usr/bin/${_srcname}" completion zsh | install -Dm644 /dev/stdin "${pkgdir}/usr/share/zsh/site-functions/_${_srcname}"
}

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,58 +17,69 @@ 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 cmd/flux/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
run: |
REPOSITORY_NAME=${{ github.event.repository.name }}
BRANCH_NAME=${GITHUB_REF##*/}
COMMIT_SHA=$(git rev-parse HEAD)
PSEUDO_RAND_SUFFIX=$(echo "${BRANCH_NAME}-${COMMIT_SHA}" | shasum | awk '{print $1}')
TEST_REPO_NAME="${REPOSITORY_NAME}-${PSEUDO_RAND_SUFFIX}"
echo "::set-output name=test_repo_name::$TEST_REPO_NAME"
- 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 }} \
--repository=${{ steps.vars.outputs.test_repo_name }} \
--branch=main \
--path=test-cluster
env:
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 }} \
--repository=${{ steps.vars.outputs.test_repo_name }} \
--branch=main \
--path=test-cluster
env:
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 }} \
--repository=${{ steps.vars.outputs.test_repo_name }} \
--branch=main \
--path=test-cluster
env:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
- name: delete repository
run: |
./bin/flux bootstrap github --manifests ./manifests/install/ \
--owner=fluxcd-testing \
--repository=flux-test-${{ steps.vars.outputs.sha_short }} \
--branch=main \
--path=test-cluster \
--delete
curl \
-X DELETE \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token ${GITHUB_TOKEN}" \
--fail --silent \
https://api.github.com/repos/fluxcd-testing/${{ steps.vars.outputs.test_repo_name }}
env:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
- name: Debug failure

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,13 +16,13 @@ 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:
@@ -33,6 +33,8 @@ jobs:
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
@@ -43,43 +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: |
./bin/flux create secret git git-ssh-test \
/tmp/flux create secret git git-ssh-test \
--url ssh://git@github.com/stefanprodan/podinfo
./bin/flux create secret git git-https-test \
/tmp/flux create secret git git-https-test \
--url https://github.com/stefanprodan/podinfo \
--username=test --password=test
./bin/flux create secret helm helm-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 \
@@ -90,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 cmd/flux/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 cmd/flux/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,13 +24,13 @@ 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
if [[ ! -z $(grep "github.com/fluxcd/$1/api" go.mod | awk '{print $2}') ]]; then
# bump go mod
go mod edit -require="github.com/fluxcd/$1/api@${RELEASE_VERSION}"
fi

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

@@ -48,11 +48,13 @@ you might want to take a look at the [introductory talk and demo](https://www.yo
This project is composed of:
- [/f/flux2](https://github.com/fluxcd/flux2): The Flux CLI
- [/f/source-manager](https://github.com/fluxcd/source-controller): Kubernetes operator for managing sources
- [/f/kustomize-controller](https://github.com/fluxcd/kustomize-controller): Kubernetes operator for building GitOps pipelines with Kustomize
- [/f/helm-controller](https://github.com/fluxcd/helm-controller): Kubernetes operator for building GitOps pipelines with Helm
- [/f/notification-controller](https://github.com/fluxcd/notification-controller): Kubernetes operator for handling inbound and outbound events
- [flux2](https://github.com/fluxcd/flux2): The Flux CLI
- [source-manager](https://github.com/fluxcd/source-controller): Kubernetes operator for managing sources (Git and Helm repositories, S3-compatible Buckets)
- [kustomize-controller](https://github.com/fluxcd/kustomize-controller): Kubernetes operator for building GitOps pipelines with Kustomize
- [helm-controller](https://github.com/fluxcd/helm-controller): Kubernetes operator for building GitOps pipelines with Helm
- [notification-controller](https://github.com/fluxcd/notification-controller): Kubernetes operator for handling inbound and outbound events
- [image-reflector-controller](https://github.com/fluxcd/image-reflector-controller): Kubernetes operator for scanning container registries
- [image-automation-controller](https://github.com/fluxcd/image-automation-controller): Kubernetes operator for patches container image tags in Git
### Understanding the code
@@ -63,6 +65,12 @@ for source changes.
### How to run the test suite
Prerequisites:
* go >= 1.16
* kubectl >= 1.18
* kustomize >= 3.1
You can run the unit tests by simply doing
```bash

View File

@@ -1,4 +1,7 @@
VERSION?=$(shell grep 'VERSION' cmd/flux/main.go | awk '{ print $$4 }' | tr -d '"')
EMBEDDED_MANIFESTS_TARGET=cmd/flux/manifests
rwildcard=$(foreach d,$(wildcard $(addsuffix *,$(1))),$(call rwildcard,$(d)/,$(2)) $(filter $(subst *,%,$(2)),$(d)))
all: test build
@@ -11,10 +14,13 @@ fmt:
vet:
go vet ./...
test: tidy fmt vet docs
test: $(EMBEDDED_MANIFESTS_TARGET) tidy fmt vet docs
go test ./... -coverprofile cover.out
build:
$(EMBEDDED_MANIFESTS_TARGET): $(call rwildcard,manifests/,*.yaml *.json)
./manifests/scripts/bundle.sh
build: $(EMBEDDED_MANIFESTS_TARGET)
CGO_ENABLED=0 go build -o ./bin/flux ./cmd/flux
install:
@@ -22,7 +28,7 @@ install:
.PHONY: docs
docs:
rm docs/cmd/*
rm -rf docs/cmd/*
mkdir -p ./docs/cmd && go run ./cmd/flux/ docgen
install-dev:

View File

@@ -60,13 +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 should need help, please refer to our **[Support page](https://fluxcd.io/support/)**.
If you need help, please refer to our **[Support page](https://fluxcd.io/support/)**.
## GitOps Toolkit
@@ -96,17 +95,24 @@ 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
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.
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.
- 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).
- 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))
@@ -115,6 +121,7 @@ Need help or want to contribute? Please see the links below. The Flux project is
### 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,15 +10,20 @@ 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

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

@@ -19,13 +19,11 @@ package main
import (
"context"
"fmt"
"net/url"
"path/filepath"
"time"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -36,7 +34,9 @@ import (
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/install"
kus "github.com/fluxcd/flux2/pkg/manifestgen/kustomization"
"github.com/fluxcd/flux2/pkg/manifestgen/sync"
"github.com/fluxcd/flux2/pkg/status"
)
var bootstrapCmd = &cobra.Command{
@@ -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,6 +126,20 @@ 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,
@@ -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)
}
@@ -159,19 +177,24 @@ func generateInstallManifests(targetPath, namespace, tmpDir string, localManifes
func applyInstallManifests(ctx context.Context, manifestPath string, components []string) error {
kubectlArgs := []string{"apply", "-f", manifestPath}
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
return fmt.Errorf("install failed")
return fmt.Errorf("install failed: %w", err)
}
statusChecker, err := NewStatusChecker(time.Second, time.Minute)
kubeConfig, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return fmt.Errorf("install failed: %w", err)
}
statusChecker, err := status.NewStatusChecker(kubeConfig, time.Second, rootArgs.timeout, logger)
if err != nil {
return fmt.Errorf("install failed: %w", err)
}
componentRefs, err := buildComponentObjectRefs(components...)
if err != nil {
return fmt.Errorf("install failed: %w", err)
}
logger.Waitingf("verifying installation")
if err := statusChecker.Assess(components...); err != nil {
if err := statusChecker.Assess(componentRefs...); err != nil {
return fmt.Errorf("install failed")
}
return nil
}
@@ -182,6 +205,7 @@ func generateSyncManifests(url, branch, name, namespace, targetPath, tmpDir stri
URL: url,
Branch: branch,
Interval: interval,
Secret: namespace,
TargetPath: targetPath,
ManifestFile: sync.MakeDefaultOptions().ManifestFile,
}
@@ -196,9 +220,19 @@ func generateSyncManifests(url, branch, name, namespace, targetPath, tmpDir stri
return "", err
}
outputDir := filepath.Dir(output)
if err := utils.GenerateKustomizationYaml(outputDir); err != nil {
kusOpts := kus.MakeDefaultOptions()
kusOpts.BaseDir = tmpDir
kusOpts.TargetPath = filepath.Dir(manifest.Path)
kustomization, err := kus.Generate(kusOpts)
if err != nil {
return "", err
}
if _, err = kustomization.WriteFile(tmpDir); err != nil {
return "", err
}
return outputDir, nil
}
@@ -251,35 +285,6 @@ func shouldCreateDeployKey(ctx context.Context, kubeClient client.Client, namesp
return false
}
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)
if err != nil {
return "", err
}
hostKey, err := scanHostKey(ctx, url)
if err != nil {
return "", err
}
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
Namespace: namespace,
},
StringData: map[string]string{
"identity": string(pair.PrivateKey),
"identity.pub": string(pair.PublicKey),
"known_hosts": string(hostKey),
},
}
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return "", err
}
return string(pair.PublicKey), nil
}
func checkIfBootstrapPathDiffers(ctx context.Context, kubeClient client.Client, namespace string, path string) (string, bool) {
namespacedName := types.NamespacedName{
Name: namespace,

View File

@@ -26,14 +26,14 @@ import (
"path/filepath"
"time"
"github.com/fluxcd/pkg/git"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/pkg/git"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret"
)
var bootstrapGitHubCmd = &cobra.Command{
@@ -80,7 +80,6 @@ type githubFlags struct {
hostname string
path flags.SafeRelativePath
teams []string
delete bool
sshHostname string
}
@@ -94,16 +93,13 @@ 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")
bootstrapGitHubCmd.Flags().Var(&githubArgs.path, "path", "path relative to the repository root, when specified the cluster sync will be scoped to this path")
bootstrapGitHubCmd.Flags().BoolVar(&githubArgs.delete, "delete", false, "delete repository (used for testing only)")
bootstrapGitHubCmd.Flags().MarkHidden("delete")
bootstrapCmd.AddCommand(bootstrapGitHubCmd)
}
@@ -125,13 +121,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
}
@@ -151,14 +159,6 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
}
defer os.RemoveAll(tmpDir)
if githubArgs.delete {
if err := provider.DeleteRepository(ctx, repository); err != nil {
return err
}
logger.Successf("repository deleted")
return nil
}
// create GitHub repository if doesn't exists
logger.Actionf("connecting to %s", githubArgs.hostname)
changed, err := provider.CreateRepository(ctx, repository)
@@ -190,13 +190,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
}
@@ -223,44 +232,48 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("install completed")
}
repoURL := repository.GetURL()
repoURL := repository.GetSSH()
secretOpts := sourcesecret.Options{
Name: rootArgs.namespace,
Namespace: rootArgs.namespace,
}
if bootstrapArgs.tokenAuth {
// setup HTTPS token auth
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: rootArgs.namespace,
Namespace: rootArgs.namespace,
},
StringData: map[string]string{
"username": "git",
"password": ghToken,
},
// Setup HTTPS token auth
repoURL = repository.GetURL()
secretOpts.Username = "git"
secretOpts.Password = ghToken
} else if shouldCreateDeployKey(ctx, kubeClient, rootArgs.namespace) {
// Setup SSH auth
u, err := url.Parse(repoURL)
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
secretOpts.SSHHostname = u.Host
secretOpts.PrivateKeyAlgorithm = sourcesecret.RSAPrivateKeyAlgorithm
secretOpts.RSAKeyBits = 2048
}
secret, err := sourcesecret.Generate(secretOpts)
if err != nil {
return err
}
var s corev1.Secret
if err := yaml.Unmarshal([]byte(secret.Content), &s); err != nil {
return err
}
if len(s.StringData) > 0 {
logger.Actionf("configuring deploy key")
if err := upsertSecret(ctx, kubeClient, s); err != nil {
return err
}
} else {
// setup SSH deploy key
repoURL = repository.GetSSH()
if shouldCreateDeployKey(ctx, kubeClient, rootArgs.namespace) {
logger.Actionf("configuring deploy key")
u, err := url.Parse(repository.GetSSH())
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
key, err := generateDeployKey(ctx, kubeClient, u, rootArgs.namespace)
if err != nil {
return fmt.Errorf("generating deploy key failed: %w", err)
}
if ppk, ok := s.StringData[sourcesecret.PublicKeySecretKey]; ok {
keyName := "flux"
if githubArgs.path != "" {
keyName = fmt.Sprintf("flux-%s", githubArgs.path)
}
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
if changed, err := provider.AddDeployKey(ctx, repository, ppk, keyName); err != nil {
return err
} else if changed {
logger.Successf("deploy key configured")
@@ -270,13 +283,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

@@ -29,12 +29,13 @@ import (
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
"github.com/fluxcd/pkg/git"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret"
)
var bootstrapGitLabCmd = &cobra.Command{
@@ -89,8 +90,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 +132,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 +177,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
}
@@ -202,44 +219,48 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("install completed")
}
repoURL := repository.GetURL()
repoURL := repository.GetSSH()
secretOpts := sourcesecret.Options{
Name: rootArgs.namespace,
Namespace: rootArgs.namespace,
}
if bootstrapArgs.tokenAuth {
// setup HTTPS token auth
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: rootArgs.namespace,
Namespace: rootArgs.namespace,
},
StringData: map[string]string{
"username": "git",
"password": glToken,
},
// Setup HTTPS token auth
repoURL = repository.GetURL()
secretOpts.Username = "git"
secretOpts.Password = glToken
} else if shouldCreateDeployKey(ctx, kubeClient, rootArgs.namespace) {
// Setup SSH auth
u, err := url.Parse(repoURL)
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
secretOpts.SSHHostname = u.Host
secretOpts.PrivateKeyAlgorithm = sourcesecret.RSAPrivateKeyAlgorithm
secretOpts.RSAKeyBits = 2048
}
secret, err := sourcesecret.Generate(secretOpts)
if err != nil {
return err
}
var s corev1.Secret
if err := yaml.Unmarshal([]byte(secret.Content), &s); err != nil {
return err
}
if len(s.StringData) > 0 {
logger.Actionf("configuring deploy key")
if err := upsertSecret(ctx, kubeClient, s); err != nil {
return err
}
} else {
// setup SSH deploy key
repoURL = repository.GetSSH()
if shouldCreateDeployKey(ctx, kubeClient, rootArgs.namespace) {
logger.Actionf("configuring deploy key")
u, err := url.Parse(repoURL)
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
key, err := generateDeployKey(ctx, kubeClient, u, rootArgs.namespace)
if err != nil {
return fmt.Errorf("generating deploy key failed: %w", err)
}
if ppk, ok := s.StringData[sourcesecret.PublicKeySecretKey]; ok {
keyName := "flux"
if gitlabArgs.path != "" {
keyName = fmt.Sprintf("flux-%s", gitlabArgs.path)
}
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
if changed, err := provider.AddDeployKey(ctx, repository, ppk, keyName); err != nil {
return err
} else if changed {
logger.Successf("deploy key configured")
@@ -249,13 +270,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,14 +21,20 @@ 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"
"github.com/fluxcd/flux2/pkg/status"
)
var checkCmd = &cobra.Command{
@@ -74,11 +80,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
}
@@ -101,7 +109,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")
@@ -117,58 +147,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
}
@@ -176,23 +206,34 @@ func componentsCheck() bool {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
statusChecker, err := NewStatusChecker(time.Second, 30*time.Second)
kubeConfig, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return false
}
statusChecker, err := status.NewStatusChecker(kubeConfig, time.Second, rootArgs.timeout, logger)
if err != nil {
return false
}
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return false
}
ok := true
deployments := append(checkArgs.components, checkArgs.extraComponents...)
for _, deployment := range deployments {
if err := statusChecker.Assess(deployment); err != nil {
ok = false
} else {
logger.Successf("%s: 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 ref, err := buildComponentObjectRefs(d.Name); err == nil {
if err := statusChecker.Assess(ref...); err != nil {
ok = false
}
}
for _, c := range d.Spec.Template.Spec.Containers {
logger.Actionf(c.Image)
}
}
}
return ok

View File

@@ -25,13 +25,9 @@ import (
var completionFishCmd = &cobra.Command{
Use: "fish",
Short: "Generates fish completion scripts",
Example: `To load completion run
Example: `To configure your fish shell to load completions for each session write this script to your completions dir:
. <(flux completion fish)
To configure your fish shell to load completions for each session write this script to your completions dir:
flux completion fish > ~/.config/fish/completions/flux
flux completion fish > ~/.config/fish/completions/flux.fish
See http://fishshell.com/docs/current/index.html#completion-own for more details
`,

View File

@@ -25,6 +25,7 @@ import (
"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"
@@ -198,7 +199,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
if valuesMap == nil {
valuesMap = jsonMap
} else {
valuesMap = utils.MergeMaps(valuesMap, jsonMap)
valuesMap = transform.MergeMaps(valuesMap, jsonMap)
}
}

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"
@@ -28,7 +32,7 @@ import (
)
var createImagePolicyCmd = &cobra.Command{
Use: "policy <name>",
Use: "policy [name]",
Short: "Create or update an ImagePolicy object",
Long: `The create image policy command generates an ImagePolicy resource.
An ImagePolicy object calculates a "latest image" given an image
@@ -36,12 +40,28 @@ repository and a policy, e.g., semver.
The image that sorts highest according to the policy is recorded in
the status of the object.`,
Example: ` # Create an ImagePolicy to select the latest stable release
flux create image policy podinfo \
--image-ref=podinfo \
--select-semver=">=1.0.0"
# Create an ImagePolicy to select the latest main branch build tagged as "${GIT_BRANCH}-${GIT_SHA:0:7}-$(date +%s)"
flux create image policy podinfo \
--image-ref=podinfo \
--select-numeric=asc \
--filter-regex='^main-[a-f0-9]+-(?P<ts>[0-9]+)' \
--filter-extract='$ts'
`,
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 +69,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 +113,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 +171,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

@@ -30,7 +30,7 @@ import (
)
var createImageRepositoryCmd = &cobra.Command{
Use: "repository <name>",
Use: "repository [name]",
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.`,

View File

@@ -28,19 +28,38 @@ import (
)
var createImageUpdateCmd = &cobra.Command{
Use: "update <name>",
Use: "update [name]",
Short: "Create or update an ImageUpdateAutomation object",
Long: `The create image update command generates an ImageUpdateAutomation resource.
An ImageUpdateAutomation object specifies an automated update to images
mentioned in YAMLs in a git repository.`,
Example: ` # Configure image updates for the main repository created by flux bootstrap
flux create image update flux-system \
--git-repo-ref=flux-system \
--git-repo-path="./clusters/my-cluster" \
--checkout-branch=main \
--author-name=flux \
--author-email=flux@example.com \
--commit-template="{{range .Updated.Images}}{{println .}}{{end}}"
# Configure image updates to push changes to a different branch, if the branch doesn't exists it will be created
flux create image update flux-system \
--git-repo-ref=flux-system \
--git-repo-path="./clusters/my-cluster" \
--checkout-branch=main \
--push-branch=image-updates \
--author-name=flux \
--author-email=flux@example.com \
--commit-template="{{range .Updated.Images}}{{println .}}{{end}}"
`,
RunE: createImageUpdateRun,
}
type imageUpdateFlags struct {
// git checkout spec
gitRepoRef string
branch string
// commit spec
gitRepoRef string
gitRepoPath string
checkoutBranch string
pushBranch string
commitTemplate string
authorName string
authorEmail string
@@ -50,8 +69,10 @@ var imageUpdateArgs = imageUpdateFlags{}
func init() {
flags := createImageUpdateCmd.Flags()
flags.StringVar(&imageUpdateArgs.gitRepoRef, "git-repo-ref", "", "the name of a GitRepository resource with details of the upstream git repository")
flags.StringVar(&imageUpdateArgs.branch, "branch", "", "the branch to checkout and push commits to")
flags.StringVar(&imageUpdateArgs.gitRepoRef, "git-repo-ref", "", "the name of a GitRepository resource with details of the upstream Git repository")
flags.StringVar(&imageUpdateArgs.gitRepoPath, "git-repo-path", "", "path to the directory containing the manifests to be updated, defaults to the repository root")
flags.StringVar(&imageUpdateArgs.checkoutBranch, "checkout-branch", "", "the branch to checkout")
flags.StringVar(&imageUpdateArgs.pushBranch, "push-branch", "", "the branch to push commits to, defaults to the checkout branch if not specified")
flags.StringVar(&imageUpdateArgs.commitTemplate, "commit-template", "", "a template for commit messages")
flags.StringVar(&imageUpdateArgs.authorName, "author-name", "", "the name to use for commit author")
flags.StringVar(&imageUpdateArgs.authorEmail, "author-email", "", "the email to use for commit author")
@@ -69,8 +90,16 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("a reference to a GitRepository is required (--git-repo-ref)")
}
if imageUpdateArgs.branch == "" {
return fmt.Errorf("the Git repository branch is required (--branch)")
if imageUpdateArgs.checkoutBranch == "" {
return fmt.Errorf("the Git repository branch is required (--checkout-branch)")
}
if imageUpdateArgs.authorName == "" {
return fmt.Errorf("the author name is required (--author-name)")
}
if imageUpdateArgs.authorEmail == "" {
return fmt.Errorf("the author email is required (--author-email)")
}
labels, err := parseLabels()
@@ -89,9 +118,11 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
GitRepositoryRef: meta.LocalObjectReference{
Name: imageUpdateArgs.gitRepoRef,
},
Branch: imageUpdateArgs.branch,
Branch: imageUpdateArgs.checkoutBranch,
},
Interval: metav1.Duration{
Duration: createArgs.interval,
},
Interval: metav1.Duration{Duration: createArgs.interval},
Commit: autov1.CommitSpec{
AuthorName: imageUpdateArgs.authorName,
AuthorEmail: imageUpdateArgs.authorEmail,
@@ -100,6 +131,19 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
},
}
if imageUpdateArgs.pushBranch != "" {
update.Spec.Push = &autov1.PushSpec{
Branch: imageUpdateArgs.pushBranch,
}
}
if imageUpdateArgs.gitRepoPath != "" {
update.Spec.Update = &autov1.UpdateStrategy{
Path: imageUpdateArgs.gitRepoPath,
Strategy: autov1.UpdateStrategySetters,
}
}
if createArgs.export {
return printExport(exportImageUpdate(&update))
}

View File

@@ -19,6 +19,7 @@ package main
import (
"context"
"fmt"
"path/filepath"
"strings"
"time"
@@ -142,7 +143,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
Interval: metav1.Duration{
Duration: createArgs.interval,
},
Path: kustomizationArgs.path.String(),
Path: filepath.ToSlash(kustomizationArgs.path.String()),
Prune: kustomizationArgs.prune,
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Kind: kustomizationArgs.source.Kind,

View File

@@ -18,15 +18,12 @@ package main
import (
"context"
"fmt"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
)
var createSecretCmd = &cobra.Command{
@@ -39,23 +36,6 @@ 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(),
@@ -81,19 +61,3 @@ func upsertSecret(ctx context.Context, kubeClient client.Client, secret corev1.S
}
return nil
}
func exportSecret(secret corev1.Secret) error {
secret.TypeMeta = metav1.TypeMeta{
APIVersion: "v1",
Kind: "Secret",
}
data, err := yaml.Marshal(secret)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
return nil
}

View File

@@ -21,13 +21,14 @@ import (
"crypto/elliptic"
"fmt"
"net/url"
"time"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/ssh"
"github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret"
)
var createSecretGitCmd = &cobra.Command{
@@ -76,6 +77,7 @@ type secretGitFlags struct {
keyAlgorithm flags.PublicKeyAlgorithm
rsaBits flags.RSAKeyBits
ecdsaCurve flags.ECDSACurve
caFile string
}
var secretGitArgs = NewSecretGitFlags()
@@ -87,13 +89,14 @@ 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)
}
func NewSecretGitFlags() secretGitFlags {
return secretGitFlags{
keyAlgorithm: "rsa",
keyAlgorithm: flags.PublicKeyAlgorithm(sourcesecret.RSAPrivateKeyAlgorithm),
rsaBits: 2048,
ecdsaCurve: flags.ECDSACurve{Curve: elliptic.P384()},
}
@@ -104,11 +107,6 @@ 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")
}
@@ -118,88 +116,63 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("git URL parse failed: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
switch u.Scheme {
case "ssh":
pair, err := generateKeyPair(ctx, secretGitArgs.keyAlgorithm, secretGitArgs.rsaBits, secretGitArgs.ecdsaCurve)
if err != nil {
return err
}
hostKey, err := scanHostKey(ctx, u)
if err != nil {
return err
}
secret.StringData = map[string]string{
"identity": string(pair.PrivateKey),
"identity.pub": string(pair.PublicKey),
"known_hosts": string(hostKey),
}
if !createArgs.export {
logger.Generatef("deploy key: %s", string(pair.PublicKey))
}
case "http", "https":
if secretGitArgs.username == "" || secretGitArgs.password == "" {
return fmt.Errorf("for Git over HTTP/S the username and password are required")
}
// TODO: add cert data when it's implemented in source-controller
secret.StringData = map[string]string{
"username": secretGitArgs.username,
"password": secretGitArgs.password,
}
default:
return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme)
}
if createArgs.export {
return exportSecret(secret)
}
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
labels, err := parseLabels()
if err != nil {
return err
}
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
opts := sourcesecret.Options{
Name: name,
Namespace: rootArgs.namespace,
Labels: labels,
ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
}
switch u.Scheme {
case "ssh":
opts.SSHHostname = u.Host
opts.PrivateKeyAlgorithm = sourcesecret.PrivateKeyAlgorithm(secretGitArgs.keyAlgorithm)
opts.RSAKeyBits = int(secretGitArgs.rsaBits)
opts.ECDSACurve = secretGitArgs.ecdsaCurve.Curve
case "http", "https":
if secretGitArgs.username == "" || secretGitArgs.password == "" {
return fmt.Errorf("for Git over HTTP/S the username and password are required")
}
opts.Username = secretGitArgs.username
opts.Password = secretGitArgs.password
opts.CAFilePath = secretGitArgs.caFile
default:
return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme)
}
secret, err := sourcesecret.Generate(opts)
if err != nil {
return err
}
if createArgs.export {
fmt.Println(secret.Content)
return nil
}
var s corev1.Secret
if err := yaml.Unmarshal([]byte(secret.Content), &s); err != nil {
return err
}
if ppk, ok := s.StringData[sourcesecret.PublicKeySecretKey]; ok {
logger.Generatef("deploy key: %s", ppk)
}
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, s); err != nil {
return err
}
logger.Actionf("secret '%s' created in '%s' namespace", name, rootArgs.namespace)
return nil
}
func generateKeyPair(ctx context.Context, alg flags.PublicKeyAlgorithm, rsa flags.RSAKeyBits, ecdsa flags.ECDSACurve) (*ssh.KeyPair, error) {
var keyGen ssh.KeyPairGenerator
switch algorithm := alg.String(); algorithm {
case "rsa":
keyGen = ssh.NewRSAGenerator(int(rsa))
case "ecdsa":
keyGen = ssh.NewECDSAGenerator(ecdsa.Curve)
case "ed25519":
keyGen = ssh.NewEd25519Generator()
default:
return nil, fmt.Errorf("unsupported public key algorithm: %s", algorithm)
}
pair, err := keyGen.Generate()
if err != nil {
return nil, fmt.Errorf("key pair generation failed, error: %w", err)
}
return pair, nil
}
func scanHostKey(ctx context.Context, url *url.URL) ([]byte, error) {
host := url.Host
if url.Port() == "" {
host = host + ":22"
}
hostKey, err := ssh.ScanHostKey(host, 30*time.Second)
if err != nil {
return nil, fmt.Errorf("SSH key scan for host %s failed, error: %w", host, err)
}
return hostKey, nil
}

View File

@@ -21,8 +21,11 @@ import (
"fmt"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret"
)
var createSecretHelmCmd = &cobra.Command{
@@ -30,8 +33,8 @@ var createSecretHelmCmd = &cobra.Command{
Short: "Create or update a Kubernetes secret for Helm repository authentication",
Long: `
The create secret helm command generates a Kubernetes secret with basic authentication credentials.`,
Example: ` # Create a Helm authentication secret on disk and encrypt it with Mozilla SOPS
Example: `
# Create a Helm authentication secret on disk and encrypt it with Mozilla SOPS
flux create secret helm repo-auth \
--namespace=my-namespace \
--username=my-username \
@@ -72,36 +75,45 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("secret name is required")
}
name := args[0]
secret, err := makeSecret(name)
labels, err := parseLabels()
if err != nil {
return err
}
if secretHelmArgs.username != "" && secretHelmArgs.password != "" {
secret.StringData["username"] = secretHelmArgs.username
secret.StringData["password"] = secretHelmArgs.password
opts := sourcesecret.Options{
Name: name,
Namespace: rootArgs.namespace,
Labels: labels,
Username: secretHelmArgs.username,
Password: secretHelmArgs.password,
CAFilePath: secretHelmArgs.caFile,
CertFilePath: secretHelmArgs.certFile,
KeyFilePath: secretHelmArgs.keyFile,
}
if err = populateSecretTLS(&secret, secretHelmArgs.secretTLSFlags); err != nil {
secret, err := sourcesecret.Generate(opts)
if err != nil {
return err
}
if createArgs.export {
return exportSecret(secret)
fmt.Println(secret.Content)
return nil
}
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 {
var s corev1.Secret
if err := yaml.Unmarshal([]byte(secret.Content), &s); err != nil {
return err
}
if err := upsertSecret(ctx, kubeClient, s); err != nil {
return err
}
logger.Actionf("secret '%s' created in '%s' namespace", name, rootArgs.namespace)
return nil
}

View File

@@ -19,13 +19,14 @@ package main
import (
"context"
"fmt"
"io/ioutil"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret"
)
var createSecretTLSCmd = &cobra.Command{
@@ -68,61 +69,48 @@ func init() {
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)
labels, err := parseLabels()
if err != nil {
return err
}
if err = populateSecretTLS(&secret, secretTLSArgs); err != nil {
opts := sourcesecret.Options{
Name: name,
Namespace: rootArgs.namespace,
Labels: labels,
CAFilePath: secretTLSArgs.caFile,
CertFilePath: secretTLSArgs.certFile,
KeyFilePath: secretTLSArgs.keyFile,
}
secret, err := sourcesecret.Generate(opts)
if err != nil {
return err
}
if createArgs.export {
return exportSecret(secret)
fmt.Println(secret.Content)
return nil
}
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 {
var s corev1.Secret
if err := yaml.Unmarshal([]byte(secret.Content), &s); err != nil {
return err
}
if err := upsertSecret(ctx, kubeClient, s); err != nil {
return err
}
logger.Actionf("secret '%s' created in '%s' namespace", name, rootArgs.namespace)
return nil
}

View File

@@ -24,6 +24,8 @@ import (
"net/url"
"os"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
@@ -33,27 +35,26 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret"
)
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 +101,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: flags.PublicKeyAlgorithm(sourcesecret.RSAPrivateKeyAlgorithm),
keyRSABits: 2048,
keyECDSACurve: flags.ECDSACurve{Curve: elliptic.P384()},
}
}
@@ -132,20 +134,27 @@ 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)
}
if u.Scheme != "ssh" && u.Scheme != "http" && u.Scheme != "https" {
return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme)
}
sourceLabels, err := parseLabels()
if err != nil {
@@ -159,7 +168,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,24 +176,25 @@ 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 sourceGitArgs.secretRef != "" {
gitRepository.Spec.SecretRef = &meta.LocalObjectReference{
Name: sourceGitArgs.secretRef,
}
}
if createArgs.export {
if sourceArgs.GitSecretRef != "" {
gitRepository.Spec.SecretRef = &meta.LocalObjectReference{
Name: sourceArgs.GitSecretRef,
}
}
return exportGit(gitRepository)
}
@@ -196,82 +206,54 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return err
}
withAuth := false
// TODO(hidde): move all auth prep to separate func?
if sourceArgs.GitSecretRef != "" {
withAuth = true
} else if u.Scheme == "ssh" {
logger.Generatef("generating deploy key pair")
pair, err := generateKeyPair(ctx, sourceArgs.GitKeyAlgorithm, sourceArgs.GitRSABits, sourceArgs.GitECDSACurve)
if err != nil {
return err
}
logger.Successf("deploy key: %s", pair.PublicKey)
prompt := promptui.Prompt{
Label: "Have you added the deploy key to your repository",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
logger.Actionf("collecting preferred public key from SSH server")
hostKey, err := scanHostKey(ctx, u)
if err != nil {
return err
}
logger.Successf("collected public key from SSH server:\n%s", hostKey)
logger.Actionf("applying secret with keys")
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
StringData: map[string]string{
"identity": string(pair.PrivateKey),
"identity.pub": string(pair.PublicKey),
"known_hosts": string(hostKey),
},
}
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err
}
withAuth = true
} else if sourceArgs.GitUsername != "" && sourceArgs.GitPassword != "" {
logger.Actionf("applying secret with basic auth credentials")
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
StringData: map[string]string{
"username": sourceArgs.GitUsername,
"password": sourceArgs.GitPassword,
},
}
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err
}
withAuth = true
}
if withAuth {
logger.Successf("authentication configured")
}
logger.Generatef("generating GitRepository source")
if withAuth {
secretName := name
if sourceArgs.GitSecretRef != "" {
secretName = sourceArgs.GitSecretRef
if sourceGitArgs.secretRef == "" {
secretOpts := sourcesecret.Options{
Name: name,
Namespace: rootArgs.namespace,
ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
}
gitRepository.Spec.SecretRef = &meta.LocalObjectReference{
Name: secretName,
switch u.Scheme {
case "ssh":
secretOpts.SSHHostname = u.Host
secretOpts.PrivateKeyAlgorithm = sourcesecret.PrivateKeyAlgorithm(sourceGitArgs.keyAlgorithm)
secretOpts.RSAKeyBits = int(sourceGitArgs.keyRSABits)
secretOpts.ECDSACurve = sourceGitArgs.keyECDSACurve.Curve
case "https":
secretOpts.Username = sourceGitArgs.username
secretOpts.Password = sourceGitArgs.password
secretOpts.CAFilePath = sourceGitArgs.caFile
}
secret, err := sourcesecret.Generate(secretOpts)
if err != nil {
return err
}
var s corev1.Secret
if err = yaml.Unmarshal([]byte(secret.Content), &s); err != nil {
return err
}
if len(s.StringData) > 0 {
if hk, ok := s.StringData[sourcesecret.KnownHostsSecretKey]; ok {
logger.Successf("collected public key from SSH server:\n%s", hk)
}
if ppk, ok := s.StringData[sourcesecret.PublicKeySecretKey]; ok {
logger.Generatef("deploy key: %s", ppk)
prompt := promptui.Prompt{
Label: "Have you added the deploy key to your repository",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("applying secret with repository credentials")
if err := upsertSecret(ctx, kubeClient, s); err != nil {
return err
}
gitRepository.Spec.SecretRef = &meta.LocalObjectReference{
Name: s.Name,
}
logger.Successf("authentication configured")
}
}

View File

@@ -32,10 +32,12 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret"
)
var createSourceHelmCmd = &cobra.Command{
@@ -149,46 +151,27 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
logger.Generatef("generating HelmRepository source")
if sourceHelmArgs.secretRef == "" {
secretName := fmt.Sprintf("helm-%s", name)
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: rootArgs.namespace,
Labels: sourceLabels,
},
StringData: map[string]string{},
secretOpts := sourcesecret.Options{
Name: secretName,
Namespace: rootArgs.namespace,
Username: sourceHelmArgs.username,
Password: sourceHelmArgs.password,
CertFilePath: sourceHelmArgs.certFile,
KeyFilePath: sourceHelmArgs.keyFile,
CAFilePath: sourceHelmArgs.caFile,
ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
}
if sourceHelmArgs.username != "" && sourceHelmArgs.password != "" {
secret.StringData["username"] = sourceHelmArgs.username
secret.StringData["password"] = sourceHelmArgs.password
secret, err := sourcesecret.Generate(secretOpts)
if err != nil {
return err
}
if sourceHelmArgs.certFile != "" && sourceHelmArgs.keyFile != "" {
cert, err := ioutil.ReadFile(sourceHelmArgs.certFile)
if err != nil {
return fmt.Errorf("failed to read repository cert file '%s': %w", sourceHelmArgs.certFile, err)
}
secret.StringData["certFile"] = string(cert)
key, err := ioutil.ReadFile(sourceHelmArgs.keyFile)
if err != nil {
return fmt.Errorf("failed to read repository key file '%s': %w", sourceHelmArgs.keyFile, err)
}
secret.StringData["keyFile"] = string(key)
var s corev1.Secret
if err = yaml.Unmarshal([]byte(secret.Content), &s); err != nil {
return err
}
if sourceHelmArgs.caFile != "" {
ca, err := ioutil.ReadFile(sourceHelmArgs.caFile)
if err != nil {
return fmt.Errorf("failed to read repository CA file '%s': %w", sourceHelmArgs.caFile, err)
}
secret.StringData["caFile"] = string(ca)
}
if len(secret.StringData) > 0 {
if len(s.StringData) > 0 {
logger.Actionf("applying secret with repository credentials")
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
if err := upsertSecret(ctx, kubeClient, s); err != nil {
return err
}
helmRepository.Spec.SecretRef = &meta.LocalObjectReference{

View File

@@ -34,7 +34,7 @@ import (
var exportSourceBucketCmd = &cobra.Command{
Use: "bucket [name]",
Short: "Export Bucket sources in YAML format",
Long: "The export source git command exports on or all Bucket sources in YAML format.",
Long: "The export source git command exports one or all Bucket sources in YAML format.",
Example: ` # Export all Bucket sources
flux export source bucket --all > sources.yaml

View File

@@ -34,7 +34,7 @@ import (
var exportSourceGitCmd = &cobra.Command{
Use: "git [name]",
Short: "Export GitRepository sources in YAML format",
Long: "The export source git command exports on or all GitRepository sources in YAML format.",
Long: "The export source git command exports one or all GitRepository sources in YAML format.",
Example: ` # Export all GitRepository sources
flux export source git --all > sources.yaml

View File

@@ -34,7 +34,7 @@ import (
var exportSourceHelmCmd = &cobra.Command{
Use: "helm [name]",
Short: "Export HelmRepository sources in YAML format",
Long: "The export source git command exports on or all HelmRepository sources in YAML format.",
Long: "The export source git command exports one or all HelmRepository sources in YAML format.",
Example: ` # Export all HelmRepository sources
flux export source helm --all > sources.yaml

View File

@@ -18,7 +18,9 @@ package main
import (
"context"
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
@@ -32,8 +34,8 @@ import (
var getCmd = &cobra.Command{
Use: "get",
Short: "Get sources and resources",
Long: "The get sub-commands print the statuses of sources and resources.",
Short: "Get the resources and their status",
Long: "The get sub-commands print the statuses of Flux resources.",
}
type GetFlags struct {
@@ -50,7 +52,7 @@ func init() {
type summarisable interface {
listAdapter
summariseItem(i int, includeNamespace bool) []string
summariseItem(i int, includeNamespace bool, includeKind bool) []string
headers(includeNamespace bool) []string
}
@@ -63,11 +65,17 @@ func statusAndMessage(conditions []metav1.Condition) (string, string) {
return string(metav1.ConditionFalse), "waiting to be reconciled"
}
func nameColumns(item named, includeNamespace bool) []string {
if includeNamespace {
return []string{item.GetNamespace(), item.GetName()}
func nameColumns(item named, includeNamespace bool, includeKind bool) []string {
name := item.GetName()
if includeKind {
name = fmt.Sprintf("%s/%s",
strings.ToLower(item.GetObjectKind().GroupVersionKind().Kind),
item.GetName())
}
return []string{item.GetName()}
if includeNamespace {
return []string{item.GetNamespace(), name}
}
return []string{name}
}
var namespaceHeader = []string{"Namespace"}
@@ -100,17 +108,25 @@ func (get getCommand) run(cmd *cobra.Command, args []string) error {
return err
}
getAll := cmd.Use == "all"
if get.list.len() == 0 {
logger.Failuref("no %s objects found in %s namespace", get.kind, rootArgs.namespace)
if !getAll {
logger.Failuref("no %s objects found in %s namespace", get.kind, rootArgs.namespace)
}
return nil
}
header := get.list.headers(getArgs.allNamespaces)
var rows [][]string
for i := 0; i < get.list.len(); i++ {
row := get.list.summariseItem(i, getArgs.allNamespaces)
row := get.list.summariseItem(i, getArgs.allNamespaces, getAll)
rows = append(rows, row)
}
utils.PrintTable(os.Stdout, header, rows)
if getAll {
fmt.Println()
}
return nil
}

View File

@@ -42,11 +42,11 @@ func init() {
getCmd.AddCommand(getHelmReleaseCmd)
}
func (a helmReleaseListAdapter) summariseItem(i int, includeNamespace bool) []string {
func (a helmReleaseListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := a.Items[i]
revision := item.Status.LastAppliedRevision
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace),
return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}

66
cmd/flux/get_image_all.go Normal file
View File

@@ -0,0 +1,66 @@
/*
Copyright 2021 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha1"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
"github.com/spf13/cobra"
)
var getImageAllCmd = &cobra.Command{
Use: "all",
Short: "Get all image statuses",
Long: "The get image sub-commands print the statuses of all image objects.",
Example: ` # List all image objects in a namespace
flux get images all --namespace=flux-system
# List all image objects in all namespaces
flux get images all --all-namespaces
`,
RunE: func(cmd *cobra.Command, args []string) error {
c := getCommand{
apiType: imageRepositoryType,
list: imageRepositoryListAdapter{&imagev1.ImageRepositoryList{}},
}
if err := c.run(cmd, args); err != nil {
logger.Failuref(err.Error())
}
c = getCommand{
apiType: imagePolicyType,
list: &imagePolicyListAdapter{&imagev1.ImagePolicyList{}},
}
if err := c.run(cmd, args); err != nil {
logger.Failuref(err.Error())
}
c = getCommand{
apiType: imageUpdateAutomationType,
list: &imageUpdateAutomationListAdapter{&autov1.ImageUpdateAutomationList{}},
}
if err := c.run(cmd, args); err != nil {
logger.Failuref(err.Error())
}
return nil
},
}
func init() {
getImageCmd.AddCommand(getImageAllCmd)
}

View File

@@ -42,10 +42,10 @@ func init() {
getImageCmd.AddCommand(getImagePolicyCmd)
}
func (s imagePolicyListAdapter) summariseItem(i int, includeNamespace bool) []string {
func (s imagePolicyListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := s.Items[i]
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace), status, msg, item.Status.LatestImage)
return append(nameColumns(&item, includeNamespace, includeKind), status, msg, item.Status.LatestImage)
}
func (s imagePolicyListAdapter) headers(includeNamespace bool) []string {

View File

@@ -46,14 +46,14 @@ func init() {
getImageCmd.AddCommand(getImageRepositoryCmd)
}
func (s imageRepositoryListAdapter) summariseItem(i int, includeNamespace bool) []string {
func (s imageRepositoryListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := s.Items[i]
status, msg := statusAndMessage(item.Status.Conditions)
var lastScan string
if item.Status.LastScanResult != nil {
lastScan = item.Status.LastScanResult.ScanTime.Time.Format(time.RFC3339)
}
return append(nameColumns(&item, includeNamespace),
return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, lastScan, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}

View File

@@ -46,14 +46,14 @@ func init() {
getImageCmd.AddCommand(getImageUpdateCmd)
}
func (s imageUpdateAutomationListAdapter) summariseItem(i int, includeNamespace bool) []string {
func (s imageUpdateAutomationListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := s.Items[i]
status, msg := statusAndMessage(item.Status.Conditions)
var lastRun string
if item.Status.LastAutomationRunTime != nil {
lastRun = item.Status.LastAutomationRunTime.Time.Format(time.RFC3339)
}
return append(nameColumns(&item, includeNamespace), status, msg, lastRun, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
return append(nameColumns(&item, includeNamespace, includeKind), status, msg, lastRun, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}
func (s imageUpdateAutomationListAdapter) headers(includeNamespace bool) []string {

View File

@@ -42,11 +42,11 @@ func init() {
getCmd.AddCommand(getKsCmd)
}
func (a kustomizationListAdapter) summariseItem(i int, includeNamespace bool) []string {
func (a kustomizationListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := a.Items[i]
revision := item.Status.LastAppliedRevision
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace),
return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}

View File

@@ -77,7 +77,7 @@ func getReceiverCmdRun(cmd *cobra.Command, args []string) error {
}
var rows [][]string
for _, receiver := range list.Items {
row := []string{}
var row []string
if c := apimeta.FindStatusCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil {
row = []string{
receiver.GetName(),

View File

@@ -0,0 +1,73 @@
/*
Copyright 2021 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/spf13/cobra"
)
var getSourceAllCmd = &cobra.Command{
Use: "all",
Short: "Get all source statuses",
Long: "The get sources all command print the statuses of all sources.",
Example: ` # List all sources in a namespace
flux get sources all --namespace=flux-system
# List all sources in all namespaces
flux get sources all --all-namespaces
`,
RunE: func(cmd *cobra.Command, args []string) error {
c := getCommand{
apiType: bucketType,
list: &bucketListAdapter{&sourcev1.BucketList{}},
}
if err := c.run(cmd, args); err != nil {
logger.Failuref(err.Error())
}
c = getCommand{
apiType: gitRepositoryType,
list: &gitRepositoryListAdapter{&sourcev1.GitRepositoryList{}},
}
if err := c.run(cmd, args); err != nil {
logger.Failuref(err.Error())
}
c = getCommand{
apiType: helmRepositoryType,
list: &helmRepositoryListAdapter{&sourcev1.HelmRepositoryList{}},
}
if err := c.run(cmd, args); err != nil {
logger.Failuref(err.Error())
}
c = getCommand{
apiType: helmChartType,
list: &helmChartListAdapter{&sourcev1.HelmChartList{}},
}
if err := c.run(cmd, args); err != nil {
logger.Failuref(err.Error())
}
return nil
},
}
func init() {
getSourceCmd.AddCommand(getSourceAllCmd)
}

View File

@@ -44,14 +44,14 @@ func init() {
getSourceCmd.AddCommand(getSourceBucketCmd)
}
func (a *bucketListAdapter) summariseItem(i int, includeNamespace bool) []string {
func (a *bucketListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := a.Items[i]
var revision string
if item.GetArtifact() != nil {
revision = item.GetArtifact().Revision
}
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace),
return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}

View File

@@ -44,14 +44,14 @@ func init() {
getSourceCmd.AddCommand(getSourceHelmChartCmd)
}
func (a *helmChartListAdapter) summariseItem(i int, includeNamespace bool) []string {
func (a *helmChartListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := a.Items[i]
var revision string
if item.GetArtifact() != nil {
revision = item.GetArtifact().Revision
}
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace),
return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}

View File

@@ -44,14 +44,14 @@ func init() {
getSourceCmd.AddCommand(getSourceGitCmd)
}
func (a *gitRepositoryListAdapter) summariseItem(i int, includeNamespace bool) []string {
func (a *gitRepositoryListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := a.Items[i]
var revision string
if item.GetArtifact() != nil {
revision = item.GetArtifact().Revision
}
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace),
return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}

View File

@@ -44,14 +44,14 @@ func init() {
getSourceCmd.AddCommand(getSourceHelmCmd)
}
func (a *helmRepositoryListAdapter) summariseItem(i int, includeNamespace bool) []string {
func (a *helmRepositoryListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := a.Items[i]
var revision string
if item.GetArtifact() != nil {
revision = item.GetArtifact().Revision
}
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace),
return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
}

View File

@@ -30,19 +30,23 @@ import (
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/install"
"github.com/fluxcd/flux2/pkg/status"
)
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
@@ -52,91 +56,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)
}
@@ -147,9 +179,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("---")
@@ -164,26 +196,33 @@ 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
}
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
return fmt.Errorf("install failed")
return fmt.Errorf("install failed: %w", err)
}
if installDryRun {
if installArgs.dryRun {
logger.Successf("install dry-run finished")
return nil
}
statusChecker, err := NewStatusChecker(time.Second, time.Minute)
kubeConfig, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return fmt.Errorf("install failed: %w", err)
}
statusChecker, err := status.NewStatusChecker(kubeConfig, time.Second, rootArgs.timeout, logger)
if err != nil {
return fmt.Errorf("install failed: %w", err)
}
componentRefs, err := buildComponentObjectRefs(components...)
if err != nil {
return fmt.Errorf("install failed: %w", err)
}
logger.Waitingf("verifying installation")
if err := statusChecker.Assess(components...); err != nil {
if err := statusChecker.Assess(componentRefs...); err != nil {
return fmt.Errorf("install failed")
}

261
cmd/flux/logs.go Normal file
View File

@@ -0,0 +1,261 @@
/*
Copyright 2021 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"bufio"
"context"
"encoding/json"
"fmt"
"html/template"
"io"
"os"
"strings"
"sync"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
)
var logsCmd = &cobra.Command{
Use: "logs",
Short: "Display formatted logs for Flux components",
Long: "The logs command displays formatted logs from various Flux components.",
Example: ` # Print the reconciliation logs of all Flux custom resources in your cluster
flux logs --all-namespaces
# Stream logs for a particular log level
flux logs --follow --level=error --all-namespaces
# Filter logs by kind, name and namespace
flux logs --kind=Kustomization --name=podinfo --namespace=default
# Print logs when Flux is installed in a different namespace than flux-system
flux logs --flux-namespace=my-namespace
`,
RunE: logsCmdRun,
}
type logsFlags struct {
logLevel flags.LogLevel
follow bool
tail int64
kind string
name string
fluxNamespace string
allNamespaces bool
}
var logsArgs = &logsFlags{
tail: -1,
}
func init() {
logsCmd.Flags().Var(&logsArgs.logLevel, "level", logsArgs.logLevel.Description())
logsCmd.Flags().StringVarP(&logsArgs.kind, "kind", "", logsArgs.kind, "displays errors of a particular toolkit kind e.g GitRepository")
logsCmd.Flags().StringVarP(&logsArgs.name, "name", "", logsArgs.name, "specifies the name of the object logs to be displayed")
logsCmd.Flags().BoolVarP(&logsArgs.follow, "follow", "f", logsArgs.follow, "specifies if the logs should be streamed")
logsCmd.Flags().Int64VarP(&logsArgs.tail, "tail", "", logsArgs.tail, "lines of recent log file to display")
logsCmd.Flags().StringVarP(&logsArgs.fluxNamespace, "flux-namespace", "", rootArgs.defaults.Namespace, "the namespace where the Flux components are running")
logsCmd.Flags().BoolVarP(&logsArgs.allNamespaces, "all-namespaces", "A", false, "displays logs for objects across all namespaces")
rootCmd.AddCommand(logsCmd)
}
func logsCmdRun(cmd *cobra.Command, args []string) error {
fluxSelector := fmt.Sprintf("app.kubernetes.io/instance=%s", logsArgs.fluxNamespace)
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
var pods []corev1.Pod
cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
clientset, err := kubernetes.NewForConfig(cfg)
if err != nil {
return err
}
if len(args) > 0 {
return fmt.Errorf("no argument required")
}
pods, err = getPods(ctx, clientset, fluxSelector)
if err != nil {
return err
}
logOpts := &corev1.PodLogOptions{
Follow: logsArgs.follow,
}
if logsArgs.tail > -1 {
logOpts.TailLines = &logsArgs.tail
}
var requests []rest.ResponseWrapper
for _, pod := range pods {
req := clientset.CoreV1().Pods(logsArgs.fluxNamespace).GetLogs(pod.Name, logOpts)
requests = append(requests, req)
}
if logsArgs.follow && len(requests) > 1 {
return parallelPodLogs(ctx, requests)
}
return podLogs(ctx, requests)
}
func getPods(ctx context.Context, c *kubernetes.Clientset, label string) ([]corev1.Pod, error) {
var ret []corev1.Pod
opts := metav1.ListOptions{
LabelSelector: label,
}
deployList, err := c.AppsV1().Deployments(logsArgs.fluxNamespace).List(ctx, opts)
if err != nil {
return ret, err
}
for _, deploy := range deployList.Items {
label := deploy.Spec.Template.Labels
opts := metav1.ListOptions{
LabelSelector: createLabelStringFromMap(label),
}
podList, err := c.CoreV1().Pods(logsArgs.fluxNamespace).List(ctx, opts)
if err != nil {
return ret, err
}
ret = append(ret, podList.Items...)
}
return ret, nil
}
func parallelPodLogs(ctx context.Context, requests []rest.ResponseWrapper) error {
reader, writer := io.Pipe()
wg := &sync.WaitGroup{}
wg.Add(len(requests))
var mutex = &sync.Mutex{}
for _, request := range requests {
go func(req rest.ResponseWrapper) {
defer wg.Done()
if err := logRequest(mutex, ctx, req, os.Stdout); err != nil {
writer.CloseWithError(err)
return
}
}(request)
}
go func() {
wg.Wait()
writer.Close()
}()
_, err := io.Copy(os.Stdout, reader)
return err
}
func podLogs(ctx context.Context, requests []rest.ResponseWrapper) error {
mutex := &sync.Mutex{}
for _, req := range requests {
if err := logRequest(mutex, ctx, req, os.Stdout); err != nil {
return err
}
}
return nil
}
func createLabelStringFromMap(m map[string]string) string {
var strArr []string
for key, val := range m {
pair := fmt.Sprintf("%v=%v", key, val)
strArr = append(strArr, pair)
}
return strings.Join(strArr, ",")
}
func logRequest(mu *sync.Mutex, ctx context.Context, request rest.ResponseWrapper, w io.Writer) error {
stream, err := request.Stream(ctx)
if err != nil {
return err
}
defer stream.Close()
scanner := bufio.NewScanner(stream)
const logTmpl = "{{.Timestamp}} {{.Level}} {{.Kind}}{{if .Name}}/{{.Name}}.{{.Namespace}}{{end}} - {{.Message}} {{.Error}}\n"
t, err := template.New("log").Parse(logTmpl)
if err != nil {
return fmt.Errorf("unable to create template, err: %s", err)
}
for scanner.Scan() {
line := scanner.Text()
if !strings.HasPrefix(line, "{") {
continue
}
var l ControllerLogEntry
if err := json.Unmarshal([]byte(line), &l); err != nil {
logger.Failuref("parse error: %s", err)
break
}
mu.Lock()
filterPrintLog(t, &l)
mu.Unlock()
}
return nil
}
func filterPrintLog(t *template.Template, l *ControllerLogEntry) {
if logsArgs.logLevel != "" && logsArgs.logLevel != l.Level ||
logsArgs.kind != "" && strings.ToLower(logsArgs.kind) != strings.ToLower(l.Kind) ||
logsArgs.name != "" && strings.ToLower(logsArgs.name) != strings.ToLower(l.Name) ||
!logsArgs.allNamespaces && strings.ToLower(rootArgs.namespace) != strings.ToLower(l.Namespace) {
return
}
err := t.Execute(os.Stdout, l)
if err != nil {
logger.Failuref("log template error: %s", err)
}
}
type ControllerLogEntry struct {
Timestamp string `json:"ts"`
Level flags.LogLevel `json:"level"`
Message string `json:"msg"`
Error string `json:"error,omitempty"`
Logger string `json:"logger"`
Kind string `json:"reconciler kind,omitempty"`
Name string `json:"name,omitempty"`
Namespace string `json:"namespace,omitempty"`
}

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

@@ -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

@@ -17,6 +17,7 @@ limitations under the License.
package main
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
)
@@ -62,6 +63,7 @@ func (c universalAdapter) asClientObject() client.Object {
type named interface {
GetName() string
GetNamespace() string
GetObjectKind() schema.ObjectKind
SetName(string)
SetNamespace(string)
}

View File

@@ -70,7 +70,7 @@ func (a helmChartAdapter) asClientObject() client.Object {
return a.HelmChart
}
// sourcev1.ImagePolicyList
// sourcev1.HelmChartList
type helmChartListAdapter struct {
*sourcev1.HelmChartList

View File

@@ -19,24 +19,15 @@ 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/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
)
@@ -50,13 +41,6 @@ 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) {
@@ -82,74 +66,7 @@ func isReady(ctx context.Context, kubeClient client.Client,
}
}
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) {
func buildComponentObjectRefs(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"})
@@ -160,20 +77,3 @@ func (sc *StatusChecker) getObjectRefs(components []string) ([]object.ObjMetadat
}
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

@@ -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
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -94,4 +94,29 @@ body {
.progress-0plus .progress-bar {
background-color: #ff1744;
}
}
/* Custom admonitions */
/* See https://squidfunk.github.io/mkdocs-material/reference/admonitions */
:root {
--md-admonition-icon--heart: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M14 20.408c-.492.308-.903.546-1.192.709-.153.086-.308.17-.463.252h-.002a.75.75 0 0 1-.686 0 16.709 16.709 0 0 1-.465-.252 31.147 31.147 0 0 1-4.803-3.34C3.8 15.572 1 12.331 1 8.513 1 5.052 3.829 2.5 6.736 2.5 9.03 2.5 10.881 3.726 12 5.605 13.12 3.726 14.97 2.5 17.264 2.5 20.17 2.5 23 5.052 23 8.514c0 3.818-2.801 7.06-5.389 9.262A31.146 31.146 0 0 1 14 20.408z"/></svg>')
}
.md-typeset .admonition.heart,
.md-typeset details.heart {
border-color: rgb(233, 30, 99);
}
.md-typeset .heart > .admonition-title,
.md-typeset .heart > summary {
background-color: rgba(233, 30, 99, 0.1);
}
.md-typeset .heart > .admonition-title::before,
.md-typeset .heart > summary::before {
background-color: rgb(233, 30, 99);
-webkit-mask-image: var(--md-admonition-icon--heart);
mask-image: var(--md-admonition-icon--heart);
}
.timetable-explicit-col-widths th:nth-child(1) { width: 4%; }
.timetable-explicit-col-widths th:nth-child(2) { width: 32%; }
.timetable-explicit-col-widths th:nth-child(3) { width: 32%; }
.timetable-explicit-col-widths th:nth-child(4) { width: 32%; }

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
```
@@ -83,10 +83,11 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
* [flux create](flux_create.md) - Create or update sources and resources
* [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 get](flux_get.md) - Get the resources and their status
* [flux install](flux_install.md) - Install or upgrade Flux
* [flux logs](flux_logs.md) - Display formatted logs for Flux components
* [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

@@ -9,13 +9,9 @@ flux completion fish [flags]
### Examples
```
To load completion run
. <(flux completion fish)
To configure your fish shell to load completions for each session write this script to your completions dir:
flux completion fish > ~/.config/fish/completions/flux
flux completion fish > ~/.config/fish/completions/flux.fish
See http://fishshell.com/docs/current/index.html#completion-own for more details

View File

@@ -12,16 +12,36 @@ The image that sorts highest according to the policy is recorded in
the status of the object.
```
flux create image policy <name> [flags]
flux create image policy [name] [flags]
```
### Examples
```
# Create an ImagePolicy to select the latest stable release
flux create image policy podinfo \
--image-ref=podinfo \
--select-semver=">=1.0.0"
# Create an ImagePolicy to select the latest main branch build tagged as "${GIT_BRANCH}-${GIT_SHA:0:7}-$(date +%s)"
flux create image policy podinfo \
--image-ref=podinfo \
--select-numeric=asc \
--filter-regex='^main-[a-f0-9]+-(?P<ts>[0-9]+)' \
--filter-extract='$ts'
```
### 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

@@ -8,7 +8,7 @@ The create image repository command generates an ImageRepository resource.
An ImageRepository object specifies an image repository to scan.
```
flux create image repository <name> [flags]
flux create image repository [name] [flags]
```
### Examples

View File

@@ -9,7 +9,31 @@ An ImageUpdateAutomation object specifies an automated update to images
mentioned in YAMLs in a git repository.
```
flux create image update <name> [flags]
flux create image update [name] [flags]
```
### Examples
```
# Configure image updates for the main repository created by flux bootstrap
flux create image update flux-system \
--git-repo-ref=flux-system \
--git-repo-path="./clusters/my-cluster" \
--checkout-branch=main \
--author-name=flux \
--author-email=flux@example.com \
--commit-template="{{range .Updated.Images}}{{println .}}{{end}}"
# Configure image updates to push changes to a different branch, if the branch doesn't exists it will be created
flux create image update flux-system \
--git-repo-ref=flux-system \
--git-repo-path="./clusters/my-cluster" \
--checkout-branch=main \
--push-branch=image-updates \
--author-name=flux \
--author-email=flux@example.com \
--commit-template="{{range .Updated.Images}}{{println .}}{{end}}"
```
### Options
@@ -17,10 +41,12 @@ flux create image update <name> [flags]
```
--author-email string the email to use for commit author
--author-name string the name to use for commit author
--branch string the branch to checkout and push commits to
--checkout-branch string the branch to checkout
--commit-template string a template for commit messages
--git-repo-ref string the name of a GitRepository resource with details of the upstream git repository
--git-repo-path string path to the directory containing the manifests to be updated, defaults to the repository root
--git-repo-ref string the name of a GitRepository resource with details of the upstream Git repository
-h, --help help for update
--push-branch string the branch to push commits to, defaults to the checkout branch if not specified
```
### Options inherited from parent commands

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

@@ -14,8 +14,8 @@ flux create secret helm [name] [flags]
### Examples
```
# Create a Helm authentication secret on disk and encrypt it with Mozilla SOPS
# Create a Helm authentication secret on disk and encrypt it with Mozilla SOPS
flux create secret helm repo-auth \
--namespace=my-namespace \
--username=my-username \

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

@@ -4,7 +4,7 @@ Export Bucket sources in YAML format
### Synopsis
The export source git command exports on or all Bucket sources in YAML format.
The export source git command exports one or all Bucket sources in YAML format.
```
flux export source bucket [name] [flags]

View File

@@ -4,7 +4,7 @@ Export GitRepository sources in YAML format
### Synopsis
The export source git command exports on or all GitRepository sources in YAML format.
The export source git command exports one or all GitRepository sources in YAML format.
```
flux export source git [name] [flags]

View File

@@ -4,7 +4,7 @@ Export HelmRepository sources in YAML format
### Synopsis
The export source git command exports on or all HelmRepository sources in YAML format.
The export source git command exports one or all HelmRepository sources in YAML format.
```
flux export source helm [name] [flags]

View File

@@ -1,10 +1,10 @@
## flux get
Get sources and resources
Get the resources and their status
### Synopsis
The get sub-commands print the statuses of sources and resources.
The get sub-commands print the statuses of Flux resources.
### Options

View File

@@ -37,5 +37,5 @@ flux get alert-providers [flags]
### SEE ALSO
* [flux get](flux_get.md) - Get sources and resources
* [flux get](flux_get.md) - Get the resources and their status

View File

@@ -37,5 +37,5 @@ flux get alerts [flags]
### SEE ALSO
* [flux get](flux_get.md) - Get sources and resources
* [flux get](flux_get.md) - Get the resources and their status

View File

@@ -37,5 +37,5 @@ flux get helmreleases [flags]
### SEE ALSO
* [flux get](flux_get.md) - Get sources and resources
* [flux get](flux_get.md) - Get the resources and their status

View File

@@ -25,7 +25,8 @@ 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](flux_get.md) - Get the resources and their status
* [flux get images all](flux_get_images_all.md) - Get all image statuses
* [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

@@ -0,0 +1,44 @@
## flux get images all
Get all image statuses
### Synopsis
The get image sub-commands print the statuses of all image objects.
```
flux get images all [flags]
```
### Examples
```
# List all image objects in a namespace
flux get images all --namespace=flux-system
# List all image objects in all namespaces
flux get images all --all-namespaces
```
### Options
```
-h, --help help for all
```
### Options inherited from parent commands
```
-A, --all-namespaces list the requested object(s) across all namespaces
--context string kubernetes context to use
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
-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 get images](flux_get_images.md) - Get image automation object status

View File

@@ -37,5 +37,5 @@ flux get kustomizations [flags]
### SEE ALSO
* [flux get](flux_get.md) - Get sources and resources
* [flux get](flux_get.md) - Get the resources and their status

View File

@@ -37,5 +37,5 @@ flux get receivers [flags]
### SEE ALSO
* [flux get](flux_get.md) - Get sources and resources
* [flux get](flux_get.md) - Get the resources and their status

View File

@@ -25,7 +25,8 @@ The get source sub-commands print the statuses of the sources.
### SEE ALSO
* [flux get](flux_get.md) - Get sources and resources
* [flux get](flux_get.md) - Get the resources and their status
* [flux get sources all](flux_get_sources_all.md) - Get all source statuses
* [flux get sources bucket](flux_get_sources_bucket.md) - Get Bucket source statuses
* [flux get sources chart](flux_get_sources_chart.md) - Get HelmChart statuses
* [flux get sources git](flux_get_sources_git.md) - Get GitRepository source statuses

View File

@@ -0,0 +1,44 @@
## flux get sources all
Get all source statuses
### Synopsis
The get sources all command print the statuses of all sources.
```
flux get sources all [flags]
```
### Examples
```
# List all sources in a namespace
flux get sources all --namespace=flux-system
# List all sources in all namespaces
flux get sources all --all-namespaces
```
### Options
```
-h, --help help for all
```
### Options inherited from parent commands
```
-A, --all-namespaces list the requested object(s) across all namespaces
--context string kubernetes context to use
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
-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 get sources](flux_get_sources.md) - Get source statuses

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)
```

56
docs/cmd/flux_logs.md Normal file
View File

@@ -0,0 +1,56 @@
## flux logs
Display formatted logs for Flux components
### Synopsis
The logs command displays formatted logs from various Flux components.
```
flux logs [flags]
```
### Examples
```
# Print the reconciliation logs of all Flux custom resources in your cluster
flux logs --all-namespaces
# Stream logs for a particular log level
flux logs --follow --level=error --all-namespaces
# Filter logs by kind, name and namespace
flux logs --kind=Kustomization --name=podinfo --namespace=default
# Print logs when Flux is installed in a different namespace than flux-system
flux logs --flux-namespace=my-namespace
```
### Options
```
-A, --all-namespaces displays logs for objects across all namespaces
--flux-namespace string the namespace where the Flux components are running (default "flux-system")
-f, --follow specifies if the logs should be streamed
-h, --help help for logs
--kind string displays errors of a particular toolkit kind e.g GitRepository
--level logLevel log level, available options are: (debug, info, error)
--name string specifies the name of the object logs to be displayed
--tail int lines of recent log file to display (default -1)
```
### Options inherited from parent commands
```
--context string kubernetes context to use
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
-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](flux.md) - Command line utility for assembling Kubernetes CD pipelines

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:

View File

@@ -8,6 +8,8 @@ repository when new container images are available.
- The image-automation-controller updates YAML files based on the latest images scanned, and commits
the changes to a given Git repository.
![](../../_files/image-update-automation.png)
Links:
- Source code [fluxcd/image-reflector-controller](https://github.com/fluxcd/image-reflector-controller)

View File

@@ -28,7 +28,7 @@ is produced.
All sources are specified as Custom Resources in a Kubernetes cluster, examples
of sources are `GitRepository`, `HelmRepository` and `Bucket` resources.
For more information, take a look at [the source controller documentation](../components/source/source.md).
For more information, take a look at [the source controller documentation](../components/source/controller.md).
## Reconciliation

View File

@@ -0,0 +1,42 @@
# Advanced debugging
This guide covers more advanced debugging topics such as collecting
runtime profiling data from GitOps Toolkit components.
As a user, this page normally should be a last resort, but you may
be asked by a maintainer to share a [collected profile](#collecting-a-profile)
to debug e.g. performance issues.
## Pprof
The [GitOps Toolkit components](../components/index.md) serve [`pprof`](https://golang.org/pkg/net/http/pprof/)
runtime profiling data on their metrics HTTP server (default `:8080`).
### Endpoints
| Endpoint | Path |
|-------------|------------------------|
| Index | `/debug/pprof/` |
| CPU profile | `/debug/pprof/profile` |
| Symbol | `/debug/pprof/symbol` |
| Trace | `/debug/pprof/trace` |
### Collecting a profile
To collect a profile, port-forward to the component's metrics endpoint
and collect the data from the [endpoint](#endpoints) of choice:
```console
$ kubectl port-forward -n <namespace> deploy/<component> 8080
$ curl -Sk -v http://localhost:8080/debug/pprof/heap > heap.out
```
The collected profile [can be analyzed using `go`](https://blog.golang.org/pprof),
or shared with one of the maintainers.
## Resource usage
As `kubectl top` gives a limited (and at times inaccurate) overview of
resource usage, it is often better to make use of the Grafana metrics
to gather insights. See [monitoring](../guides/monitoring.md) for a
guide on how to visualize this data with a Grafana dashboard.

View File

@@ -150,6 +150,23 @@ The kustomize-controller creates `kustomization.yaml` files similar to:
cd ./deploy/prod && kustomize create --autodetect --recursive
```
### What is the behavior of Kustomize used by Flux
We referred to the Kustomization CLI flags here, so that you can replicate the same behavior using the CLI.
The behavior of Kustomize used by the controller is currently configured as following:
- `--allow_id_changes` is set to false, so it does not change any resource IDs.
- `--enable_kyaml` is disabled by default, so it currently used `k8sdeps` to process YAMLs.
- `--enable_alpha_plugins` is disabled by default, so it uses only the built-in plugins.
- `--load_restrictor` is set to `LoadRestrictionsNone`, so it allows loading files outside the dir containing `kustomization.yaml`.
- `--reorder` resources is done in the `legacy` mode, so the output will have namespaces and cluster roles/role bindings first, CRDs before CRs, and webhooks last.
!!! hint "`kustomization.yaml` validation"
To validate changes before committing and/or merging, [a validation
utility script is available](https://github.com/fluxcd/flux2-kustomize-helm-example/blob/main/scripts/validate.sh),
it runs `kustomize` locally or in CI with the same set of flags as
the controller and validates the output using `kubeval`.
## Helm questions
### How to debug "not ready" errors?
@@ -181,95 +198,76 @@ NAMESPACE NAME READY MESSAGE
default default-podinfo False no chart version found for podinfo-9.0.0
```
### Can I use Flux HelmReleases without GitOps?
Yes, you can install the Flux components directly on a cluster
and manage Helm releases with `kubectl`.
Install the controllers needed for Helm operations with `flux`:
```sh
flux install \
--namespace=flux-system \
--network-policy=false \
--components=source-controller,helm-controller
```
Create a Helm release with `kubectl`:
```sh
cat << EOF | kubectl apply -f -
---
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
name: bitnami
namespace: flux-system
spec:
interval: 30m
url: https://charts.bitnami.com/bitnami
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: metrics-server
namespace: kube-system
spec:
interval: 60m
releaseName: metrics-server
chart:
spec:
chart: metrics-server
version: "^5.x"
sourceRef:
kind: HelmRepository
name: bitnami
namespace: flux-system
values:
apiService:
create: true
EOF
```
Based on the above definition, Flux will upgrade the release automatically
when Bitnami publishes a new version of the metrics-server chart.
## Flux v1 vs v2 questions
### What does Flux v2 mean for Flux?
### What are the differences between v1 and v2?
Flux v1 is a monolithic do-it-all operator; Flux v2 separates the functionalities into specialized controllers, collectively called the GitOps Toolkit.
Flux v1 is a monolithic do-it-all operator;
Flux v2 separates the functionalities into specialized controllers, collectively called the GitOps Toolkit.
You can install and operate Flux v2 simply using the `flux` command. You can easily pick and choose the functionality you need and extend it to serve your own purposes.
You can find a detailed comparison of Flux v1 and v2 features in the [migration FAQ](../guides/faq-migration.md).
The timeline we are looking at right now is:
### How can I migrate from v1 to v2?
1. Put Flux v1 into maintenance mode (no new features being added; bugfixes and CVEs patched only).
1. Continue work on the [Flux v2 roadmap](https://toolkit.fluxcd.io/roadmap/).
1. We will provide transition guides for specific user groups, e.g. users of Flux v1 in read-only mode, or of Helm Operator v1, etc. once the functionality is integrated into Flux v2 and it's deemed "ready".
1. Once the use-cases of Flux v1 are covered, we will continue supporting Flux v1 for 6 months. This will be the transition period before it's considered unsupported.
The Flux community has created guides and example repositories
to help you migrate to Flux v2:
### Why did you rewrite Flux?
Flux v2 implements its functionality in individual controllers, which allowed us to address long-standing feature requests much more easily.
By basing these controllers on modern Kubernetes tooling (`controller-runtime` libraries), they can be dynamically configured with Kubernetes custom resources either by cluster admins or by other automated tools -- and you get greatly increased observability.
This gave us the opportunity to build Flux v2 with the top Flux v1 feature requests in mind:
- Supporting multiple source Git repositories
- Operational insight through health checks, events and alerts
- Multi-tenancy capabilities, like applying each source repository with its own set of permissions
On top of that, testing the individual components and understanding the codebase becomes a lot easier.
### What are significant new differences between Flux v1 and Flux v2?
#### Reconciliation
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Limited to a single Git repository | Multiple Git repositories
Declarative config via arguments in the Flux deployment | `GitRepository` custom resource, which produces an artifact which can be reconciled by other controllers
Follow `HEAD` of Git branches | Supports Git branches, pinning on commits and tags, follow SemVer tag ranges
Suspending of reconciliation by downscaling Flux deployment | Reconciliation can be paused per resource by suspending the `GitRepository`
Credentials config via Arguments and/or Secret volume mounts in the Flux pod | Credentials config per `GitRepository` resource: SSH private key, HTTP/S username/password/token, OpenPGP public keys
#### `kustomize` support
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Declarative config through `.flux.yaml` files in the Git repository | Declarative config through a `Kustomization` custom resource, consuming the artifact from the GitRepository
Manifests are generated via shell exec and then reconciled by `fluxd` | Generation, server-side validation, and reconciliation is handled by a specialised `kustomize-controller`
Reconciliation using the service account of the Flux deployment | Support for service account impersonation
Garbage collection needs cluster role binding for Flux to query the Kubernetes discovery API | Garbage collection needs no cluster role binding or access to Kubernetes discovery API
Support for custom commands and generators executed by fluxd in a POSIX shell | No support for custom commands
#### Helm integration
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Declarative config in a single Helm custom resource | Declarative config through `HelmRepository`, `GitRepository`, `Bucket`, `HelmChart` and `HelmRelease` custom resources
Chart synchronisation embedded in the operator | Extensive release configuration options, and a reconciliation interval per source
Support for fixed SemVer versions from Helm repositories | Support for SemVer ranges for `HelmChart` resources
Git repository synchronisation on a global interval | Planned support for charts from GitRepository sources
Limited observability via the status object of the HelmRelease resource | Better observability via the HelmRelease status object, Kubernetes events, and notifications
Resource heavy, relatively slow | Better performance
Chart changes from Git sources are determined from Git metadata | Chart changes must be accompanied by a version bump in `Chart.yaml` to produce a new artifact
#### Notifications, webhooks, observability
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Emits "custom Flux events" to a webhook endpoint | Emits Kubernetes events for included custom resources
RPC endpoint can be configured to a 3rd party solution like FluxCloud to be forwarded as notifications to e.g. Slack | Flux v2 components can be configured to POST the events to a `notification-controller` endpoint. Selective forwarding of POSTed events as notifications using `Provider` and `Alert` custom resources.
Webhook receiver is a side-project | Webhook receiver, handling a wide range of platforms, is included
Unstructured logging | Structured logging for all components
Custom Prometheus metrics | Generic / common `controller-runtime` Prometheus metrics
### How can I get involved?
There are a variety of ways and we look forward to having you on board building the future of GitOps together:
- [Discuss the direction](https://github.com/fluxcd/flux2/discussions) of Flux v2 with us
- Join us in #flux-dev on the [CNCF Slack](https://slack.cncf.io)
- Check out our [contributor docs](https://toolkit.fluxcd.io/contributing/)
- Take a look at the [roadmap for Flux v2](https://toolkit.fluxcd.io/roadmap/)
### Are there any breaking changes?
- In Flux v1 Kustomize support was implemented through `.flux.yaml` files in the Git repository. As indicated in the comparison table above, while this approach worked, we found it to be error-prone and hard to debug. The new [Kustomization CR](https://github.com/fluxcd/kustomize-controller/blob/master/docs/spec/v1alpha1/kustomization.md) should make troubleshooting much easier. Unfortunately we needed to drop the support for custom commands as running arbitrary shell scripts in-cluster poses serious security concerns.
- Helm users: we redesigned the `HelmRelease` API and the automation will work quite differently, so upgrading to `HelmRelease` v2 will require a little work from you, but you will gain more flexibility, better observability and performance.
### Is the GitOps Toolkit related to the GitOps Engine?
In an announcement in August 2019, the expectation was set that the Flux project would integrate the GitOps Engine, then being factored out of ArgoCD. Since the result would be backward-incompatible, it would require a major version bump: Flux v2.
After experimentation and considerable thought, we (the maintainers) have found a path to Flux v2 that we think better serves our vision of GitOps: the GitOps Toolkit. In consequence, we do not now plan to integrate GitOps Engine into Flux.
- [Migrate from Flux v1](https://toolkit.fluxcd.io/guides/flux-v1-migration/)
- [Migrate from `.flux.yaml` and kustomize](https://toolkit.fluxcd.io/guides/flux-v1-migration/#flux-with-kustomize)
- [Migrate from Flux v1 automated container image updates](https://toolkit.fluxcd.io/guides/flux-v1-automation-migration/)
- [How to manage multi-tenant clusters with Flux v2](https://github.com/fluxcd/flux2-multi-tenancy)
- [Migrate from Helm Operator to Flux v2](https://toolkit.fluxcd.io/guides/helm-operator-migration/)
- [How to structure your HelmReleases](https://github.com/fluxcd/flux2-kustomize-helm-example)

View File

@@ -0,0 +1,92 @@
## Flux v1 vs v2 questions
### What does Flux v2 mean for Flux?
Flux v1 is a monolithic do-it-all operator; Flux v2 separates the functionalities into specialized controllers, collectively called the GitOps Toolkit.
You can install and operate Flux v2 simply using the `flux` command. You can easily pick and choose the functionality you need and extend it to serve your own purposes.
The timeline we are looking at right now is:
1. Put Flux v1 into maintenance mode (no new features being added; bugfixes and CVEs patched only).
1. Continue work on the [Flux v2 roadmap](https://toolkit.fluxcd.io/roadmap/).
1. We will provide transition guides for specific user groups, e.g. users of Flux v1 in read-only mode, or of Helm Operator v1, etc. once the functionality is integrated into Flux v2 and it's deemed "ready".
1. Once the use-cases of Flux v1 are covered, we will continue supporting Flux v1 for 6 months. This will be the transition period before it's considered unsupported.
### Why did you rewrite Flux?
Flux v2 implements its functionality in individual controllers, which allowed us to address long-standing feature requests much more easily.
By basing these controllers on modern Kubernetes tooling (`controller-runtime` libraries), they can be dynamically configured with Kubernetes custom resources either by cluster admins or by other automated tools -- and you get greatly increased observability.
This gave us the opportunity to build Flux v2 with the top Flux v1 feature requests in mind:
- Supporting multiple source Git repositories
- Operational insight through health checks, events and alerts
- Multi-tenancy capabilities, like applying each source repository with its own set of permissions
On top of that, testing the individual components and understanding the codebase becomes a lot easier.
### What are significant new differences between Flux v1 and Flux v2?
#### Reconciliation
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Limited to a single Git repository | Multiple Git repositories
Declarative config via arguments in the Flux deployment | `GitRepository` custom resource, which produces an artifact which can be reconciled by other controllers
Follow `HEAD` of Git branches | Supports Git branches, pinning on commits and tags, follow SemVer tag ranges
Suspending of reconciliation by downscaling Flux deployment | Reconciliation can be paused per resource by suspending the `GitRepository`
Credentials config via Arguments and/or Secret volume mounts in the Flux pod | Credentials config per `GitRepository` resource: SSH private key, HTTP/S username/password/token, OpenPGP public keys
#### `kustomize` support
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Declarative config through `.flux.yaml` files in the Git repository | Declarative config through a `Kustomization` custom resource, consuming the artifact from the GitRepository
Manifests are generated via shell exec and then reconciled by `fluxd` | Generation, server-side validation, and reconciliation is handled by a specialised `kustomize-controller`
Reconciliation using the service account of the Flux deployment | Support for service account impersonation
Garbage collection needs cluster role binding for Flux to query the Kubernetes discovery API | Garbage collection needs no cluster role binding or access to Kubernetes discovery API
Support for custom commands and generators executed by fluxd in a POSIX shell | No support for custom commands
#### Helm integration
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Declarative config in a single Helm custom resource | Declarative config through `HelmRepository`, `GitRepository`, `Bucket`, `HelmChart` and `HelmRelease` custom resources
Chart synchronisation embedded in the operator | Extensive release configuration options, and a reconciliation interval per source
Support for fixed SemVer versions from Helm repositories | Support for SemVer ranges for `HelmChart` resources
Git repository synchronisation on a global interval | Planned support for charts from GitRepository sources
Limited observability via the status object of the HelmRelease resource | Better observability via the HelmRelease status object, Kubernetes events, and notifications
Resource heavy, relatively slow | Better performance
Chart changes from Git sources are determined from Git metadata | Chart changes must be accompanied by a version bump in `Chart.yaml` to produce a new artifact
#### Notifications, webhooks, observability
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Emits "custom Flux events" to a webhook endpoint | Emits Kubernetes events for included custom resources
RPC endpoint can be configured to a 3rd party solution like FluxCloud to be forwarded as notifications to e.g. Slack | Flux v2 components can be configured to POST the events to a `notification-controller` endpoint. Selective forwarding of POSTed events as notifications using `Provider` and `Alert` custom resources.
Webhook receiver is a side-project | Webhook receiver, handling a wide range of platforms, is included
Unstructured logging | Structured logging for all components
Custom Prometheus metrics | Generic / common `controller-runtime` Prometheus metrics
### Are there any breaking changes?
- In Flux v1 Kustomize support was implemented through `.flux.yaml` files in the Git repository. As indicated in the comparison table above, while this approach worked, we found it to be error-prone and hard to debug. The new [Kustomization CR](https://github.com/fluxcd/kustomize-controller/blob/master/docs/spec/v1alpha1/kustomization.md) should make troubleshooting much easier. Unfortunately we needed to drop the support for custom commands as running arbitrary shell scripts in-cluster poses serious security concerns.
- Helm users: we redesigned the `HelmRelease` API and the automation will work quite differently, so upgrading to `HelmRelease` v2 will require a little work from you, but you will gain more flexibility, better observability and performance.
### Is the GitOps Toolkit related to the GitOps Engine?
In an announcement in August 2019, the expectation was set that the Flux project would integrate the GitOps Engine, then being factored out of ArgoCD. Since the result would be backward-incompatible, it would require a major version bump: Flux v2.
After experimentation and considerable thought, we (the maintainers) have found a path to Flux v2 that we think better serves our vision of GitOps: the GitOps Toolkit. In consequence, we do not now plan to integrate GitOps Engine into Flux.
### How can I get involved?
There are a variety of ways and we look forward to having you on board building the future of GitOps together:
- [Discuss the direction](https://github.com/fluxcd/flux2/discussions) of Flux v2 with us
- Join us in #flux-dev on the [CNCF Slack](https://slack.cncf.io)
- Check out our [contributor docs](https://toolkit.fluxcd.io/contributing/)
- Take a look at the [roadmap for Flux v2](https://toolkit.fluxcd.io/roadmap/)

View File

@@ -0,0 +1,771 @@
<!-- -*- fill-column: 100 -*- -->
# Migrating image update automation to Flux v2
"Image Update Automation" is a process in which Flux makes commits to your Git repository when it
detects that there is a new image to be used in a workload (e.g., a Deployment). In Flux v2 this
works quite differently to how it worked in Flux v1. This guide explains the differences and how to
port your cluster configuration from v1 to v2. There is also a [tutorial for using image update
automation with a new cluster][image-update-tute].
## Overview of changes between v1 and v2
In Flux v1, image update automation (from here, just "automation") was built into the Flux daemon,
which scanned everything it found in the cluster and updated the Git repository it was syncing.
In Flux v2,
- automation is controlled with custom resources, not annotations
- ordering images by build time is not supported (there is [a section
below](#how-to-migrate-annotations-to-image-policies) explaining what to do instead)
- the fields to update in files are marked explicitly, rather than inferred from annotations.
#### Automation is now controlled by custom resources
Flux v2 breaks down the functions in Flux v1's daemon into controllers, with each having a specific
area of concern. Automation is now done by two controllers: one which scans image repositories to
find the latest images, and one which uses that information to commit changes to git
repositories. These are in turn separate to the syncing controllers.
This means that automation in Flux v2 is governed by custom resources. In Flux v1 the daemon scanned
everything, and looked at annotations on the resources to determine what to update. Automation in v2
is more explicit than in v1 -- you have to mention exactly which images you want to be scanned, and
which fields you want to be updated.
A consequence of using custom resources is that with Flux v2 you can have an arbitrary number of
automations, targeting different Git repositories if you wish, and updating different sets of
images. If you run a multitenant cluster, the tenants can define automation in their own namespaces,
for their own Git repositories.
#### Selecting an image is more flexible
The ways in which you choose to select an image have changed. In Flux v1, you generally supply a
filter pattern, and the latest image is the image with the most recent build time out of those
filtered. In Flux v2, you choose an ordering, and separately specify a filter for the tags to
consider. These are dealt with in detail below.
Selecting an image by build time is no longer supported. This is the implicit default in Flux v1. In
Flux v2, you will need to tag images so that they sort in the order you would like -- [see
below](#how-to-use-sortable-image-tags) for how to do this conveniently.
#### Fields to update are explicitly marked
Lastly, in Flux v2 the fields to update in files are marked explicitly. In Flux v1 they are inferred
from the type of the resource, along with the annotations given. The approach in Flux v1 was limited
to the types that had been programmed in, whereas Flux v2 can update any Kubernetes object (and some
files that aren't Kubernetes objects, like `kustomization.yaml`).
## Preparing for migration
It is best to complete migration of your system to _Flux v2 syncing_ first, using the [Flux v1
migration guide][flux-v1-migration]. This will remove Flux v1 from the system, along with its image
automation. You can then reintroduce automation with Flux v2 by following the instructions in this
guide.
It is safe to leave the annotations for Flux v1 in files while you reintroduce automation, because
Flux v2 will ignore them.
To migrate to Flux v2 automation, you will need to do three things:
- make sure you are running the automation controllers; then,
- declare the automation with an `ImageUpdateAutomation` object; and,
- migrate each manifest by translate Flux v1 annotations to Flux v2 `ImageRepository` and
`ImagePolicy` objects, and putting update markers in the manifest file.
### Where to keep `ImageRepository`, `ImagePolicy` and `ImageUpdateAutomation` manifests
This guide assumes you want to manage automation itself via Flux. In the following sections,
manifests for the objects controlling automation are saved in files, committed to Git, and applied
in the cluster with Flux.
A Flux v2 installation will typically have a Git repository structured like this:
```
<...>/flux-system/
gotk-components.yaml
gotk-sync.yaml
<...>/app/
# deployments etc.
```
The `<...>` is the path to a particular cluster's definitions -- this may be simply `.`, or
something like `clusters/my-cluster`. To get the files in the right place, set a variable for this
path:
```bash
$ CLUSTER_PATH=<...> # e.g., "." or "clusters/my-cluster", or ...
$ AUTO_PATH=$CLUSTER_PATH/automation
$ mkdir ./$AUTO_PATH
```
The file `$CLUSTER_PATH/flux-system/gotk-components.yaml` has definitions of all the Flux v2
controllers and custom resource definitions. The file `gotk-sync.yaml` defines a `GitRepository` and
a `Kustomization` which will sync manifests under `$CLUSTER_PATH/`.
To these will be added definitions for automation objects. This guide puts manifest files for
automation in `$CLUSTER_PATH/automation/`, but there is no particular structure required
by Flux. The automation objects do not have to be in the same namespace as the objects to be
updated.
#### Migration on a branch
This guide assumes you will commit changes to the branch that is synced by Flux, as this is the
simplest way to understand.
It may be less disruptive to put migration changes on a branch, then merging when you have completed
the migration. You would need to either change the `GitRepository` to point at the migration branch,
or have separate `GitRepository` and `Kustomization` objects for the migrated parts of your Git
repository. The main thing to avoid is syncing the same objects in two different places; e.g., avoid
having Kustomizations that sync both the unmigrated and migrated application configuration.
### Installing the command-line tool `flux`
The command-line tool `flux` will be used below; see [these instructions][install-cli] for how to
install it.
## Running the automation controllers
The first thing to do is to deploy the automation controllers to your cluster. The best way to
proceed will depend on the approach you took when following the [Flux read-only migration
guide][flux-v1-migration].
- If you used `flux bootstrap` to create a new Git repository, then ported your cluster
configuration to that repository, use [After `flux bootstrap`](#after-flux-bootstrap);
- If you used `flux install` to install the controllers directly, use [After migrating Flux v1 in
place](#after-migrating-flux-v1-in-place);
- If you used `flux install` and exported the configuration to a file, use [After committing Flux
v2 configuration to Git](#after-committing-a-flux-v2-configuration-to-git).
### After `flux bootstrap`
When starting from scratch, you are likely to have used `flux bootstrap`. Rerun the command, and
include the image automation controllers in your starting configuration with the flag
`--components-extra`, [as shown in the installation guide][flux-bootstrap].
This will commit changes to your Git repository and sync them in the cluster.
```bash
flux check --components-extra=image-reflector-controller,image-automation-controller
```
Now jump to the section [Migrating each manifest to Flux v2](#migrating-each-manifest-to-flux-v2).
### After migrating Flux v1 in place
If you followed the [Flux v1 migration guide][flux-v1-migration], you will already be running some
Flux v2 controllers. The automation controllers are currently considered an optional extra to those,
but are installed and run in much the same way. You may or may not have committed the Flux v2
configuration to your Git repository. If you did, go to the section [After committing Flux v2
configuration to Git](#after-committing-flux-v2-configuration-to-git).
If _not_, you will be installing directly to the cluster:
```bash
$ flux install --components-extra=image-reflector-controller,image-automation-controller
```
It is safe to repeat the installation command, or to run it after using `flux bootstrap`, so long as
you repeat any arguments you supplied the first time.
Now jump ahead to [Migrating each manifest to Flux v2](#migrating-each-manifest-to-flux-v2).
#### After committing a Flux v2 configuration to Git
If you added the Flux v2 configuration to your git repository, assuming it's in the file
`$CLUSTER_PATH/flux-system/gotk-components.yaml` as used in the guide, use `flux install` and write
it back to that file:
```bash
$ flux install \
--components-extra=image-reflector-controller,image-automation-controller \
--export > "$CLUSTER_PATH/flux-system/gotk-components.yaml"
```
Commit changes to the `$CLUSTER_PATH/flux-system/gotk-components.yaml` file and sync the cluster:
```bash
$ git add $CLUSTER_PATH/flux-system/gotk-components.yaml
$ git commit -s -m "Add image automation controllers to Flux config"
$ git push
$ flux reconcile kustomization --with-source flux-system
```
## Controlling automation with an `ImageUpdateAutomation` object
In Flux v1, automation was run by default. With Flux v2, you have to explicitly tell the controller
which Git repository to update and how to do so. These are defined in an `ImageUpdateAutomation`
object; but first, you need a `GitRepository` with write access, for the automation to use.
If you followed the [Flux v1 read-only migration guide][flux-v1-migration], you will have a
`GitRepository` defined in the namespace `flux-system`, for syncing to use. This `GitRepository`
will have _read_ access to the Git repository by default, and automation needs _write_ access to
push commits.
To give it write access, you can replace the secret it refers to. How to do this will depend on what
kind of authentication you used to install Flux v2.
### Replacing the Git credentials secret
The secret with Git credentials will be named in the `.spec.secretRef.name` field of the
`GitRepository` object. Say your `GitRepository` is in the _namespace_ `flux-system` and _named_
`flux-system` (these are the defaults if you used `flux bootstrap`); you can retrieve the secret
name and Git URL with:
```bash
$ FLUX_NS=flux-system
$ GIT_NAME=flux-system
$ SECRET_NAME=$(kubectl -n $FLUX_NS get gitrepository $GIT_NAME -o jsonpath={.spec.secretRef.name})
$ GIT_URL=$(kubectl -n $FLUX_NS get gitrepository $GIT_NAME -o jsonpath='{.spec.url}')
$ echo $SECRET_NAME $GIT_URL # make sure they have values
```
If you're not sure which kind of credentials you're using, look at the secret:
```bash
$ kubectl -n $FLUX_NS describe secret $SECRET_NAME
```
An entry at `.data.identity` indicates that you are using an SSH key (the [first
section](#replacing-an-ssh-key-secret) below); an entry at `.data.username` indicates you are using
a username and password or token (the [second section](#replacing-a-usernamepassword-secret)
below).
#### Replacing an SSH key secret
When using an SSH (deploy) key, create a new key:
```bash
$ flux create secret git -n $FLUX_NS $SECRET_NAME --url=$GIT_URL
```
You will need to copy the public key that's printed out, and install that as a deploy key for your
Git repo **making sure to check the 'All write access' box** (or otherwise give the key write
permissions). Remove the old deploy key.
#### Replacing a username/password secret
When you're using a username and password to authenticate, you may be able to change the permissions
associated with that account.
If not, you will need to create a new access token (e.g., ["Personal Access Token"][github-pat] in
GitHub). In this case, once you have the new token you can replace the secret with the following:
```bash
$ flux create secret git -n $FLUX_NS $SECRET_NAME \
--username <username> --password <token> --url $GIT_URL
```
#### Checking the new credentials
To check if your replaced credentials still work, try syncing the `GitRepository` object:
```bash
$ flux reconcile source git -n $FLUX_NS $GIT_NAME
► annotating GitRepository flux-system in flux-system namespace
✔ GitRepository annotated
◎ waiting for GitRepository reconciliation
✔ GitRepository reconciliation completed
✔ fetched revision main/d537304e8f5f41f1584ca1e807df5b5752b2577e
```
When this is successful, it tells you the new credentials have at least read access.
### Making an automation object
To set automation running, you create an [`ImageUpdateAutomation`][auto-ref] object. Each object
will update a Git repository, according to the image policies in the namespace.
Here is an `ImageUpdateAutomation` manifest for the example (note: you will have to supply your own
value for at least the host part of the email address):
```yaml
$ # the environment variables $AUTO_PATH and $GIT_NAME are set above
$ FLUXBOT_EMAIL=fluxbot@example.com # supply your own host or address here
$ flux create image update my-app-auto \
--author-name FluxBot --author-email "$FLUXBOT_EMAIL" \
--git-repo-ref $GIT_NAME --branch main \
--interval 5m \
--export > ./$AUTO_PATH/my-app-auto.yaml
$ cat my-app-auto.yaml
---
apiVersion: image.toolkit.fluxcd.io/v1alpha1
kind: ImageUpdateAutomation
metadata:
name: my-app-auto
namespace: flux-system
spec:
checkout:
branch: main
gitRepositoryRef:
name: flux-system
commit:
authorEmail: fluxbot@example.com
authorName: FluxBot
interval: 5m0s
```
#### Commit and check that the automation object works
Commit the manifeat file and push:
```bash
$ git add ./$AUTO_PATH/my-app-auto.yaml
$ git commit -s -m "Add image update automation"
$ git push
# ...
```
Then sync and check the object status:
```bash
$ flux reconcile kustomization --with-source flux-system
► annotating GitRepository flux-system in flux-system namespace
✔ GitRepository annotated
◎ waiting for GitRepository reconciliation
✔ GitRepository reconciliation completed
✔ fetched revision main/401dd3b550f82581c7d12bb79ade389089c6422f
► annotating Kustomization flux-system in flux-system namespace
✔ Kustomization annotated
◎ waiting for Kustomization reconciliation
✔ Kustomization reconciliation completed
✔ reconciled revision main/401dd3b550f82581c7d12bb79ade389089c6422f
$ flux get image update
NAME READY MESSAGE LAST RUN SUSPENDED
my-app-auto True no updates made 2021-02-08T14:53:43Z False
```
Read on to the next section to see how to change each manifest file to work with Flux v2.
## Migrating each manifest to Flux v2
In Flux v1, the annotation
fluxcd.io/automated: "true"
switches automation on for a manifest (a description of a Kubernetes object). For each manifest that
has that annotation, you will need to create custom resources to scan for the latest image, and to
replace the annotations with field markers.
The following sections explain these steps, using this example Deployment manifest which is
initially annotated to work with Flux v1:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: default
annotations:
fluxcd.io/automated: "true"
fluxcd.io/tag.app: semver:^5.0
selector:
matchLabels:
app: podinfo
spec:
template:
metadata:
labels:
app: podinfo
spec:
containers:
- name: app
image: ghcr.io/stefanprodan/podinfo:5.0.0
```
!!! warning
A YAML file may have more than one manifest in it, separated with
`---`. Be careful to account for each manifest in a file.
You may wish to try migrating the automation of just one file or manifest and follow it through to
the end of the guide, before returning here to do the remainder.
### How to migrate annotations to image policies
For each image repository that is the subject of automation you will need to create an
`ImageRepository` object, so that the image repository is scanned for tags. The image repository in
the example deployment is `ghcr.io/stefanprodan/podinfo`, which is the image reference minus its
tag:
```yaml
$ cat $CLUSTER_PATH/app/my-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: default
annotations:
fluxcd.io/automated: "true"
fluxcd.io/tag.app: semver:^5.0
selector:
matchLabels:
app: podinfo
spec:
template:
metadata:
labels:
app: podinfo
spec:
containers:
- name: app
image: ghcr.io/stefanprodan/podinfo:5.0.0 # <-- image reference
```
The command-line tool `flux` will help create a manifest for you. Note that the output is redirected
to a file under `$AUTO_PATH`, so it can be added to the Git repository and synced to the cluster.
```bash
$ # the environment variable $AUTO_PATH was set earlier
$ flux create image repository podinfo-image \
--image ghcr.io/stefanprodan/podinfo \
--interval 5m \
--export > ./$AUTO_PATH/podinfo-image.yaml
$ cat ./$AUTO_PATH/podinfo-image.yaml
---
apiVersion: image.toolkit.fluxcd.io/v1alpha1
kind: ImageRepository
metadata:
name: podinfo-image
namespace: flux-system
spec:
image: ghcr.io/stefanprodan/podinfo
interval: 5m0s
```
!!! hint
If you are using the same image repository in several manifests, you only need one
`ImageRepository` object for it.
##### Using image registry credentials for scanning
When your image repositories are private, you supply Kubernetes with "image pull secrets" with
credentials for accessing the image registry (e.g., DockerHub). The image reflector controller needs
the same kind of credentials to scan image repositories.
There are several ways that image pull secrets can be made available for the image reflector
controller. The [image update tutorial][image-update-tute-creds] describes how to create or arrange
secrets for scanning to use. Also see later in the tutorial for [instructions specific to some cloud
platforms][image-update-tute-clouds].
##### Committing and checking the ImageRepository
Add the `ImageRepository` manifest to the Git index and commit it:
```bash
$ git add ./$AUTO_PATH/podinfo-image.yaml
$ git commit -s -m "Add image repository object for podinfo"
$ git push
# ...
```
Now you can sync the new commit, and check that the object is working:
```bash
$ flux reocncile kustomization --with-source flux-system
► annotating GitRepository flux-system in flux-system namespace
✔ GitRepository annotated
◎ waiting for GitRepository reconciliation
✔ GitRepository reconciliation completed
✔ fetched revision main/fd2fe8a61d4537bcfa349e4d1dbc480ea699ba8a
► annotating Kustomization flux-system in flux-system namespace
✔ Kustomization annotated
◎ waiting for Kustomization reconciliation
✔ Kustomization reconciliation completed
✔ reconciled revision main/fd2fe8a61d4537bcfa349e4d1dbc480ea699ba8a
$ flux get image repository podinfo-image
NAME READY MESSAGE LAST SCAN SUSPENDED
podinfo-image True successful scan, found 16 tags 2021-02-08T14:31:38Z False
```
#### Replacing automation annotations
For each _field_ that's being updated by automation, you'll need an `ImagePolicy` object to describe
how to select an image for the field value. In the example, the field `.image` in the container
named `"app"` is the field being updated.
In Flux v1, annotations describe how to select the image to update to, using a prefix. In the
example, the prefix is `semver:`:
```yaml
annotations:
fluxcd.io/automated: "true"
fluxcd.io/tag.app: semver:^5.0
```
These are the prefixes supported in Flux v1, and what to use in Flux v2:
| Flux v1 prefix | Meaning | Flux v2 equivalent |
|----------------|---------|--------------------|
| `glob:` | Filter for tags matching the glob pattern, then select the newest by build time | [Use sortable tags](#how-to-use-sortable-image-tags) |
| `regex:` | Filter for tags matching the regular expression, then select the newest by build time |[Use sortable tags](#how-to-use-sortable-image-tags) |
| `semver:` | Filter for tags that represent versions, and select the highest version in the given range | [Use semver ordering](#how-to-use-semver-image-tags) |
#### How to use sortable image tags
To give image tags a useful ordering, you can use a timestamp or serial number as part of each
image's tag, then sort either alphabetically or numerically.
This is a change from Flux v1, in which the build time was fetched from each image's config, and
didn't need to be included in the image tag. Therefore, this is likely to require a change to your
build process.
The guide [How to make sortable image tags][image-tags-guide] explains how to change your build
process to tag images with a timestamp. This will mean Flux v2 can sort the tags to find the most
recently built image.
##### Filtering the tags in an `ImagePolicy`
The recommended format for image tags using a timestamp is:
<branch>-<sha1>-<timestamp>
The timestamp (or serial number) is the part of the tag that you want to order on. The SHA1 is there
so you can trace an image back to the commit from which it was built. You don't need the branch for
sorting, but you may want to include only builds from a specific branch.
Say you want to filter for only images that are from `main` branch, and pick the most recent. Your
`ImagePolicy` would look like this:
```yaml
apiVersion: image.toolkit.fluxcd.io/v1alpha1
kind: ImagePolicy
metadata:
name: my-app-policy
namespace: flux-system
spec:
imageRepositoryRef:
name: podinfo-image
filterTags:
pattern: '^main-[a-f0-9]+-(?P<ts>[0-9]+)'
extract: '$ts'
policy:
numerical:
order: asc
```
The `.spec.pattern` field gives a regular expression that a tag must match to be included. The
`.spec.extract` field gives a replacement pattern that can refer back to capture groups in the
filter pattern. The extracted values are sorted to find the selected image tag. In this case, the
timestamp part of the tag will be extracted and sorted numerically in ascending order. See [the
reference docs][imagepolicy-ref] for more examples.
Once you have made sure you have image tags and an `ImagePolicy` that works, jump ahead to [Checking
the ImagePolicy works](#checking-that-the-image-policy-works).
### How to use SemVer image tags
The other kind of sorting is by [SemVer][semver], picking the highest version from among those
included by the filter. A semver range will also filter for tags that fit in the range. For example,
```yaml
semver:
range: ^5.0
```
includes only tags that have a major version of `5`, and selects whichever is the highest.
This can be combined with a regular expression pattern, to filter on other parts of the tags. For
example, you might put a target environment as well as the version in your image tags, like
`dev-v1.0.3`.
Then you would use an `ImagePolicy` similar to this one:
```yaml
apiVersion: image.toolkit.fluxcd.io/v1alpha1
kind: ImagePolicy
metadata:
name: my-app-policy
namespace: flux-system
spec:
imageRepositoryRef:
name: podinfo-image
filterTags:
pattern: '^dev-v(?P<version>.*)'
extract: '$version'
policy:
semver:
range: '^1.0'
```
Continue on to the next sections to see an example, and how to check that your `ImagePolicy` works.
#### An `ImagePolicy` for the example
The example Deployment has annotations using `semver:` as a prefix, so the policy object also uses
semver:
```bash
$ # the environment variable $AUTO_PATH was set earlier
$ flux create image policy my-app-policy \
--image-ref podinfo-image \
--semver '^5.0' \
--export > ./$AUTO_PATH/my-app-policy.yaml
$ cat ./$AUTO_PATH/my-app-policy.yaml
---
apiVersion: image.toolkit.fluxcd.io/v1alpha1
kind: ImagePolicy
metadata:
name: my-app-policy
namespace: flux-system
spec:
imageRepositoryRef:
name: podinfo-image
policy:
semver:
range: ^5.0
```
#### Checking that the `ImagePolicy` works
Commit the manifest file, and push:
```bash
$ git add ./$AUTO_PATH/my-app-policy.yaml
$ git commit -s -m "Add image policy for my-app"
$ git push
# ...
```
Then you can reconcile and check that the image policy works:
```bash
$ flux reconcile kustomization --with-source flux-system
► annotating GitRepository flux-system in flux-system namespace
✔ GitRepository annotated
◎ waiting for GitRepository reconciliation
✔ GitRepository reconciliation completed
✔ fetched revision main/7dcf50222499be8c97e22cd37e26bbcda8f70b95
► annotating Kustomization flux-system in flux-system namespace
✔ Kustomization annotated
◎ waiting for Kustomization reconciliation
✔ Kustomization reconciliation completed
✔ reconciled revision main/7dcf50222499be8c97e22cd37e26bbcda8f70b95
$ flux get image policy flux-system
NAME READY MESSAGE LATEST IMAGE
my-app-policy True Latest image tag for 'ghcr.io/stefanprodan/podinfo' resolved to: 5.1.4 ghcr.io/stefanprodan/podinfo:5.1.4
```
### How to mark up files for update
The last thing to do in each manifest is to mark the fields that you want to be updated.
In Flux v1, the annotations in a manifest determines the fields to be updated. In the example, the
annotations target the image used by the container `app`:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: default
annotations:
fluxcd.io/automated: "true"
fluxcd.io/tag.app: semver:^5.0 # <-- `.app` here
selector:
matchLabels:
app: podinfo
spec:
template:
metadata:
labels:
app: podinfo
spec:
containers:
- name: app # <-- targets `app` here
image: ghcr.io/stefanprodan/podinfo:5.0.0
```
This works straight-forwardly for Deployment manifests, but when it comes to `HelmRelease`
manifests, it [gets complicated][helm-auto], and it doesn't work at all for many kinds of resources.
For Flux v2, you mark the field you want to be updated directly, with the namespaced name of the
image policy to apply. This is the example Deployment, marked up for Flux v2:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: default
name: my-app
selector:
matchLabels:
app: podinfo
spec:
template:
metadata:
labels:
app: podinfo
spec:
containers:
- name: app
image: ghcr.io/stefanprodan/podinfo:5.0.0 # {"$imagepolicy": "flux-system:my-app-policy"}
```
The value `flux-system:my-app-policy` names the policy that selects the desired image.
This works in the same way for `DaemonSet` and `CronJob` manifests. For `HelmRelease` manifests, put
the marker alongside the part of the `values` that has the image tag. If the image tag is a separate
field, you can put `:tag` on the end of the name, to replace the value with just the selected
image's tag. The [image automation guide][image-update-tute-custom] has examples for `HelmRelease`
and other custom resources.
### Committing the marker change and checking that automation works
Referring to the image policy created earlier, you can see the example Deployment does not use the
most recent image. When you commit the manifest file with the update marker added, you would expect
automation to update the file.
Commit the change that adds an update marker:
```bash
$ git add app/my-app.yaml # the filename of the example
$ git commit -s -m "Add update marker to my-app manifest"
$ git push
# ...
```
Now to check that the automation makes a change:
```bash
$ flux reconcile image update my-app-auto
► annotating ImageUpdateAutomation my-app-auto in flux-system namespace
✔ ImageUpdateAutomation annotated
◎ waiting for ImageUpdateAutomation reconciliation
✔ ImageUpdateAutomation reconciliation completed
✔ committed and pushed a92a4b654f520c00cb6c46b2d5e4fb4861aa58fc
```
## Troubleshooting
If a change was not pushed by the image automation, there's several things you can check:
- it's possible it made a change that is not reported in the latest status -- pull from the origin
and check the commit log
- check that the name used in the marker corresponds to the namespace and name of an `ImagePolicy`
- check that the `ImageUpdateAutomation` is in the same namespace as the `ImagePolicy` objects
named in markers
- check that the image policy and the image repository are both reported as `Ready`
- check that the credentials referenced by the `GitRepository` object have write permission, and
create new credentials if necessary.
As a fallback, you can scan the logs of the automation controller to see if it logged errors:
```bash
$ kubectl logs -n flux-system deploy/image-automation-controller
```
Once you are satisfied that it is working, you can migrate the rest of the manifests using the steps
from ["Migrating each manifest to Flux v2"](#migrating-each-manifest-to-flux-v2) above.
[image-update-tute]: https://toolkit.fluxcd.io/guides/image-update/
[imagepolicy-ref]: https://toolkit.fluxcd.io/components/image/imagepolicies/
[helm-auto]: https://docs.fluxcd.io/en/1.21.1/references/helm-operator-integration/#automated-image-detection
[image-update-tute-custom]: https://toolkit.fluxcd.io/guides/image-update/#configure-image-update-for-custom-resources
[flux-v1-migration]: https://toolkit.fluxcd.io/guides/flux-v1-migration/
[install-cli]: https://toolkit.fluxcd.io/get-started/#install-the-flux-cli
[flux-bootstrap]: https://toolkit.fluxcd.io/guides/installation/#bootstrap
[github-pat]: https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token
[auto-object-ref]: https://toolkit.fluxcd.io/components/image/imageupdateautomations/
[image-update-tute-creds]: https://toolkit.fluxcd.io/guides/image-update/#configure-image-scanning
[image-update-tute-clouds]: https://toolkit.fluxcd.io/guides/image-update/#imagerepository-cloud-providers-authentication
[image-tags-guide]: https://toolkit.fluxcd.io/guides/sortable-image-tags/
[auto-ref]: https://toolkit.fluxcd.io/components/image/imageupdateautomations/
[semver]: https://semver.org

View File

@@ -1,12 +1,21 @@
# Migrate from Flux v1 to v2
This guide walks you through migrating from Flux v1 to v2.
Read the [FAQ](../faq/index.md) to find out what differences are between v1 and v2.
Read the [FAQ](faq-migration.md) to find out what differences are between v1 and v2.
!!! info "Automated image updates"
The image automation feature is under development in Flux v2.
Please consult the [roadmap](../roadmap/index.md) for more details.
!!! info "Feature parity"
"Feature parity" does not mean Flux v2 works exactly the same as v1 (or is
backward-compatible); it means you can accomplish the same results, while
accounting for the fact that it's a system with a substantially different
design.
This may at times mean that you have to make adjustments to the way your
current cluster configuration is structured. If you are in this situation
and need help, please refer to the [support page](https://fluxcd.io/support/).
## Prerequisites
You will need a Kubernetes cluster version **1.16** or newer
@@ -53,6 +62,13 @@ to define the state of your fleet of Kubernetes clusters.
For a detailed walk-through of the bootstrap procedure please see the [installation guide](installation.md).
!!! warning "`flux bootstrap` target"
`flux bootstrap` should not be run against a Git branch or path
that is already being synchronized by Flux v1, as this will make
them fight over the resources. Instead, bootstrap to a **new Git
repository, branch or path**, and continue with moving the
manifests.
After you've installed Flux v2 on your cluster using bootstrap,
you can delete the Flux v1 from your clusters and move the manifests from the
Flux v1 repository to the bootstrap one.
@@ -109,7 +125,6 @@ Install Flux v2 in the `flux-system` namespace:
```console
$ flux install \
--arch=amd64 \
--network-policy=true \
--watch-all-namespaces=true \
--namespace=flux-system
@@ -227,7 +242,7 @@ Configure the reconciliation of the `prod` overlay on your cluster:
```sh
flux create kustomization app \
--source=app \
--source=GitRepository/app \
--path="./overlays/prod" \
--prune=true \
--interval=10m

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