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

Compare commits

...

60 Commits

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

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

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

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

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

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

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

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

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

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

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

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

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-15 17:20:16 +01:00
127 changed files with 2030 additions and 1918 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,9 +20,10 @@ import (
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/pkg/apis/meta"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
) )
@@ -78,11 +79,11 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
var policy = imagev1.ImagePolicy{ var policy = imagev1.ImagePolicy{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: objectName, Name: objectName,
Namespace: namespace, Namespace: rootArgs.namespace,
Labels: labels, Labels: labels,
}, },
Spec: imagev1.ImagePolicySpec{ Spec: imagev1.ImagePolicySpec{
ImageRepositoryRef: corev1.LocalObjectReference{ ImageRepositoryRef: meta.LocalObjectReference{
Name: imagePolicyArgs.imageRef, Name: imagePolicyArgs.imageRef,
}, },
}, },
@@ -103,7 +104,7 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
} }
} }
if export { if createArgs.export {
return printExport(exportImagePolicy(&policy)) return printExport(exportImagePolicy(&policy))
} }

View File

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

View File

@@ -20,9 +20,10 @@ import (
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/pkg/apis/meta"
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha1" autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha1"
) )
@@ -80,20 +81,17 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
var update = autov1.ImageUpdateAutomation{ var update = autov1.ImageUpdateAutomation{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: objectName, Name: objectName,
Namespace: namespace, Namespace: rootArgs.namespace,
Labels: labels, Labels: labels,
}, },
Spec: autov1.ImageUpdateAutomationSpec{ Spec: autov1.ImageUpdateAutomationSpec{
Checkout: autov1.GitCheckoutSpec{ Checkout: autov1.GitCheckoutSpec{
GitRepositoryRef: corev1.LocalObjectReference{ GitRepositoryRef: meta.LocalObjectReference{
Name: imageUpdateArgs.gitRepoRef, Name: imageUpdateArgs.gitRepoRef,
}, },
Branch: imageUpdateArgs.branch, Branch: imageUpdateArgs.branch,
}, },
Interval: metav1.Duration{Duration: interval}, Interval: metav1.Duration{Duration: createArgs.interval},
Update: autov1.UpdateStrategy{
Setters: &autov1.SettersStrategy{},
},
Commit: autov1.CommitSpec{ Commit: autov1.CommitSpec{
AuthorName: imageUpdateArgs.authorName, AuthorName: imageUpdateArgs.authorName,
AuthorEmail: imageUpdateArgs.authorEmail, AuthorEmail: imageUpdateArgs.authorEmail,
@@ -102,7 +100,7 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
}, },
} }
if export { if createArgs.export {
return printExport(exportImageUpdate(&update)) return printExport(exportImageUpdate(&update))
} }

View File

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

View File

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

View File

@@ -39,6 +39,21 @@ func init() {
createCmd.AddCommand(createSecretCmd) 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,
},
}, nil
}
func upsertSecret(ctx context.Context, kubeClient client.Client, secret corev1.Secret) error { func upsertSecret(ctx context.Context, kubeClient client.Client, secret corev1.Secret) error {
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: secret.GetNamespace(), Namespace: secret.GetNamespace(),

View File

@@ -24,8 +24,6 @@ import (
"time" "time"
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/flux2/internal/flags" "github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils" "github.com/fluxcd/flux2/internal/utils"
@@ -71,60 +69,61 @@ For Git over HTTP/S, the provided basic authentication credentials are stored in
RunE: createSecretGitCmdRun, RunE: createSecretGitCmdRun,
} }
var ( type secretGitFlags struct {
secretGitURL string url string
secretGitUsername string username string
secretGitPassword string password string
secretGitKeyAlgorithm flags.PublicKeyAlgorithm = "rsa" keyAlgorithm flags.PublicKeyAlgorithm
secretGitRSABits flags.RSAKeyBits = 2048 rsaBits flags.RSAKeyBits
secretGitECDSACurve = flags.ECDSACurve{Curve: elliptic.P384()} ecdsaCurve flags.ECDSACurve
) }
var secretGitArgs = NewSecretGitFlags()
func init() { func init() {
createSecretGitCmd.Flags().StringVar(&secretGitURL, "url", "", "git address, e.g. ssh://git@host/org/repository") createSecretGitCmd.Flags().StringVar(&secretGitArgs.url, "url", "", "git address, e.g. ssh://git@host/org/repository")
createSecretGitCmd.Flags().StringVarP(&secretGitUsername, "username", "u", "", "basic authentication username") createSecretGitCmd.Flags().StringVarP(&secretGitArgs.username, "username", "u", "", "basic authentication username")
createSecretGitCmd.Flags().StringVarP(&secretGitPassword, "password", "p", "", "basic authentication password") createSecretGitCmd.Flags().StringVarP(&secretGitArgs.password, "password", "p", "", "basic authentication password")
createSecretGitCmd.Flags().Var(&secretGitKeyAlgorithm, "ssh-key-algorithm", secretGitKeyAlgorithm.Description()) createSecretGitCmd.Flags().Var(&secretGitArgs.keyAlgorithm, "ssh-key-algorithm", secretGitArgs.keyAlgorithm.Description())
createSecretGitCmd.Flags().Var(&secretGitRSABits, "ssh-rsa-bits", secretGitRSABits.Description()) createSecretGitCmd.Flags().Var(&secretGitArgs.rsaBits, "ssh-rsa-bits", secretGitArgs.rsaBits.Description())
createSecretGitCmd.Flags().Var(&secretGitECDSACurve, "ssh-ecdsa-curve", secretGitECDSACurve.Description()) createSecretGitCmd.Flags().Var(&secretGitArgs.ecdsaCurve, "ssh-ecdsa-curve", secretGitArgs.ecdsaCurve.Description())
createSecretCmd.AddCommand(createSecretGitCmd) createSecretCmd.AddCommand(createSecretGitCmd)
} }
func NewSecretGitFlags() secretGitFlags {
return secretGitFlags{
keyAlgorithm: "rsa",
rsaBits: 2048,
ecdsaCurve: flags.ECDSACurve{Curve: elliptic.P384()},
}
}
func createSecretGitCmdRun(cmd *cobra.Command, args []string) error { func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 { if len(args) < 1 {
return fmt.Errorf("secret name is required") return fmt.Errorf("secret name is required")
} }
name := args[0] name := args[0]
secret, err := makeSecret(name)
if secretGitURL == "" {
return fmt.Errorf("url is required")
}
u, err := url.Parse(secretGitURL)
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
secretLabels, err := parseLabels()
if err != nil { if err != nil {
return err return err
} }
ctx, cancel := context.WithTimeout(context.Background(), timeout) if secretGitArgs.url == "" {
defer cancel() return fmt.Errorf("url is required")
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: secretLabels,
},
} }
u, err := url.Parse(secretGitArgs.url)
if err != nil {
return fmt.Errorf("git URL parse failed: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
switch u.Scheme { switch u.Scheme {
case "ssh": case "ssh":
pair, err := generateKeyPair(ctx, secretGitKeyAlgorithm, secretGitRSABits, secretGitECDSACurve) pair, err := generateKeyPair(ctx, secretGitArgs.keyAlgorithm, secretGitArgs.rsaBits, secretGitArgs.ecdsaCurve)
if err != nil { if err != nil {
return err return err
} }
@@ -140,28 +139,28 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
"known_hosts": hostKey, "known_hosts": hostKey,
} }
if !export { if !createArgs.export {
logger.Generatef("deploy key: %s", string(pair.PublicKey)) logger.Generatef("deploy key: %s", string(pair.PublicKey))
} }
case "http", "https": case "http", "https":
if secretGitUsername == "" || secretGitPassword == "" { if secretGitArgs.username == "" || secretGitArgs.password == "" {
return fmt.Errorf("for Git over HTTP/S the username and password are required") 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 // TODO: add cert data when it's implemented in source-controller
secret.Data = map[string][]byte{ secret.Data = map[string][]byte{
"username": []byte(secretGitUsername), "username": []byte(secretGitArgs.username),
"password": []byte(secretGitPassword), "password": []byte(secretGitArgs.password),
} }
default: default:
return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme) return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme)
} }
if export { if createArgs.export {
return exportSecret(secret) return exportSecret(secret)
} }
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext) kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil { if err != nil {
return err return err
} }
@@ -169,7 +168,7 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
if err := upsertSecret(ctx, kubeClient, secret); err != nil { if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err return err
} }
logger.Actionf("secret '%s' created in '%s' namespace", name, namespace) logger.Actionf("secret '%s' created in '%s' namespace", name, rootArgs.namespace)
return nil return nil
} }

View File

@@ -19,11 +19,8 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"io/ioutil"
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/flux2/internal/utils" "github.com/fluxcd/flux2/internal/utils"
) )
@@ -55,21 +52,18 @@ The create secret helm command generates a Kubernetes secret with basic authenti
RunE: createSecretHelmCmdRun, RunE: createSecretHelmCmdRun,
} }
var ( type secretHelmFlags struct {
secretHelmUsername string username string
secretHelmPassword string password string
secretHelmCertFile string secretTLSFlags
secretHelmKeyFile string }
secretHelmCAFile string
) var secretHelmArgs secretHelmFlags
func init() { func init() {
createSecretHelmCmd.Flags().StringVarP(&secretHelmUsername, "username", "u", "", "basic authentication username") createSecretHelmCmd.Flags().StringVarP(&secretHelmArgs.username, "username", "u", "", "basic authentication username")
createSecretHelmCmd.Flags().StringVarP(&secretHelmPassword, "password", "p", "", "basic authentication password") createSecretHelmCmd.Flags().StringVarP(&secretHelmArgs.password, "password", "p", "", "basic authentication password")
createSecretHelmCmd.Flags().StringVar(&secretHelmCertFile, "cert-file", "", "TLS authentication cert file path") initSecretTLSFlags(createSecretHelmCmd.Flags(), &secretHelmArgs.secretTLSFlags)
createSecretHelmCmd.Flags().StringVar(&secretHelmKeyFile, "key-file", "", "TLS authentication key file path")
createSecretHelmCmd.Flags().StringVar(&secretHelmCAFile, "ca-file", "", "TLS authentication CA file path")
createSecretCmd.AddCommand(createSecretHelmCmd) createSecretCmd.AddCommand(createSecretHelmCmd)
} }
@@ -78,56 +72,28 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("secret name is required") return fmt.Errorf("secret name is required")
} }
name := args[0] name := args[0]
secret, err := makeSecret(name)
secretLabels, err := parseLabels()
if err != nil { if err != nil {
return err return err
} }
secret := corev1.Secret{ if secretHelmArgs.username != "" && secretHelmArgs.password != "" {
ObjectMeta: metav1.ObjectMeta{ secret.StringData["username"] = secretHelmArgs.username
Name: name, secret.StringData["password"] = secretHelmArgs.password
Namespace: namespace,
Labels: secretLabels,
},
StringData: map[string]string{},
} }
if secretHelmUsername != "" && secretHelmPassword != "" { if err = populateSecretTLS(&secret, secretHelmArgs.secretTLSFlags); err != nil {
secret.StringData["username"] = secretHelmUsername return err
secret.StringData["password"] = secretHelmPassword
} }
if secretHelmCertFile != "" && secretHelmKeyFile != "" { if createArgs.export {
cert, err := ioutil.ReadFile(secretHelmCertFile)
if err != nil {
return fmt.Errorf("failed to read repository cert file '%s': %w", secretHelmCertFile, err)
}
secret.StringData["certFile"] = string(cert)
key, err := ioutil.ReadFile(secretHelmKeyFile)
if err != nil {
return fmt.Errorf("failed to read repository key file '%s': %w", secretHelmKeyFile, err)
}
secret.StringData["keyFile"] = string(key)
}
if secretHelmCAFile != "" {
ca, err := ioutil.ReadFile(secretHelmCAFile)
if err != nil {
return fmt.Errorf("failed to read repository CA file '%s': %w", secretHelmCAFile, err)
}
secret.StringData["caFile"] = string(ca)
}
if export {
return exportSecret(secret) return exportSecret(secret)
} }
ctx, cancel := context.WithTimeout(context.Background(), timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext) kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil { if err != nil {
return err return err
} }
@@ -135,7 +101,7 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
if err := upsertSecret(ctx, kubeClient, secret); err != nil { if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err return err
} }
logger.Actionf("secret '%s' created in '%s' namespace", name, namespace) logger.Actionf("secret '%s' created in '%s' namespace", name, rootArgs.namespace)
return nil return nil
} }

View File

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

View File

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

View File

@@ -34,12 +34,28 @@ import (
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils"
) )
type SourceGitFlags struct {
GitURL string
GitBranch string
GitTag string
GitSemver string
GitUsername string
GitPassword string
GitKeyAlgorithm flags.PublicKeyAlgorithm
GitRSABits flags.RSAKeyBits
GitECDSACurve flags.ECDSACurve
GitSecretRef string
GitImplementation flags.GitImplementation
}
var createSourceGitCmd = &cobra.Command{ var createSourceGitCmd = &cobra.Command{
Use: "git [name]", Use: "git [name]",
Short: "Create or update a GitRepository source", Short: "Create or update a GitRepository source",
@@ -84,44 +100,39 @@ For private Git repositories, the basic authentication credentials are stored in
RunE: createSourceGitCmdRun, RunE: createSourceGitCmdRun,
} }
var ( var sourceArgs = NewSourceGitFlags()
sourceGitURL string
sourceGitBranch string
sourceGitTag string
sourceGitSemver string
sourceGitUsername string
sourceGitPassword string
sourceGitKeyAlgorithm flags.PublicKeyAlgorithm = "rsa"
sourceGitRSABits flags.RSAKeyBits = 2048
sourceGitECDSACurve = flags.ECDSACurve{Curve: elliptic.P384()}
sourceGitSecretRef string
sourceGitImplementation flags.GitImplementation
)
func init() { func init() {
createSourceGitCmd.Flags().StringVar(&sourceGitURL, "url", "", "git address, e.g. ssh://git@host/org/repository") createSourceGitCmd.Flags().StringVar(&sourceArgs.GitURL, "url", "", "git address, e.g. ssh://git@host/org/repository")
createSourceGitCmd.Flags().StringVar(&sourceGitBranch, "branch", "master", "git branch") createSourceGitCmd.Flags().StringVar(&sourceArgs.GitBranch, "branch", "master", "git branch")
createSourceGitCmd.Flags().StringVar(&sourceGitTag, "tag", "", "git tag") createSourceGitCmd.Flags().StringVar(&sourceArgs.GitTag, "tag", "", "git tag")
createSourceGitCmd.Flags().StringVar(&sourceGitSemver, "tag-semver", "", "git tag semver range") createSourceGitCmd.Flags().StringVar(&sourceArgs.GitSemver, "tag-semver", "", "git tag semver range")
createSourceGitCmd.Flags().StringVarP(&sourceGitUsername, "username", "u", "", "basic authentication username") createSourceGitCmd.Flags().StringVarP(&sourceArgs.GitUsername, "username", "u", "", "basic authentication username")
createSourceGitCmd.Flags().StringVarP(&sourceGitPassword, "password", "p", "", "basic authentication password") createSourceGitCmd.Flags().StringVarP(&sourceArgs.GitPassword, "password", "p", "", "basic authentication password")
createSourceGitCmd.Flags().Var(&sourceGitKeyAlgorithm, "ssh-key-algorithm", sourceGitKeyAlgorithm.Description()) createSourceGitCmd.Flags().Var(&sourceArgs.GitKeyAlgorithm, "ssh-key-algorithm", sourceArgs.GitKeyAlgorithm.Description())
createSourceGitCmd.Flags().Var(&sourceGitRSABits, "ssh-rsa-bits", sourceGitRSABits.Description()) createSourceGitCmd.Flags().Var(&sourceArgs.GitRSABits, "ssh-rsa-bits", sourceArgs.GitRSABits.Description())
createSourceGitCmd.Flags().Var(&sourceGitECDSACurve, "ssh-ecdsa-curve", sourceGitECDSACurve.Description()) createSourceGitCmd.Flags().Var(&sourceArgs.GitECDSACurve, "ssh-ecdsa-curve", sourceArgs.GitECDSACurve.Description())
createSourceGitCmd.Flags().StringVarP(&sourceGitSecretRef, "secret-ref", "", "", "the name of an existing secret containing SSH or basic credentials") createSourceGitCmd.Flags().StringVarP(&sourceArgs.GitSecretRef, "secret-ref", "", "", "the name of an existing secret containing SSH or basic credentials")
createSourceGitCmd.Flags().Var(&sourceGitImplementation, "git-implementation", sourceGitImplementation.Description()) createSourceGitCmd.Flags().Var(&sourceArgs.GitImplementation, "git-implementation", sourceArgs.GitImplementation.Description())
createSourceCmd.AddCommand(createSourceGitCmd) createSourceCmd.AddCommand(createSourceGitCmd)
} }
func NewSourceGitFlags() SourceGitFlags {
return SourceGitFlags{
GitKeyAlgorithm: "rsa",
GitRSABits: 2048,
GitECDSACurve: flags.ECDSACurve{Curve: elliptic.P384()},
}
}
func createSourceGitCmdRun(cmd *cobra.Command, args []string) error { func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 { if len(args) < 1 {
return fmt.Errorf("GitRepository source name is required") return fmt.Errorf("GitRepository source name is required")
} }
name := args[0] name := args[0]
if sourceGitURL == "" { if sourceArgs.GitURL == "" {
return fmt.Errorf("url is required") return fmt.Errorf("url is required")
} }
@@ -131,7 +142,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
u, err := url.Parse(sourceGitURL) u, err := url.Parse(sourceArgs.GitURL)
if err != nil { if err != nil {
return fmt.Errorf("git URL parse failed: %w", err) return fmt.Errorf("git URL parse failed: %w", err)
} }
@@ -144,54 +155,54 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
gitRepository := sourcev1.GitRepository{ gitRepository := sourcev1.GitRepository{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: namespace, Namespace: rootArgs.namespace,
Labels: sourceLabels, Labels: sourceLabels,
}, },
Spec: sourcev1.GitRepositorySpec{ Spec: sourcev1.GitRepositorySpec{
URL: sourceGitURL, URL: sourceArgs.GitURL,
Interval: metav1.Duration{ Interval: metav1.Duration{
Duration: interval, Duration: createArgs.interval,
}, },
Reference: &sourcev1.GitRepositoryRef{}, Reference: &sourcev1.GitRepositoryRef{},
}, },
} }
if sourceGitImplementation != "" { if sourceArgs.GitImplementation != "" {
gitRepository.Spec.GitImplementation = sourceGitImplementation.String() gitRepository.Spec.GitImplementation = sourceArgs.GitImplementation.String()
} }
if sourceGitSemver != "" { if sourceArgs.GitSemver != "" {
gitRepository.Spec.Reference.SemVer = sourceGitSemver gitRepository.Spec.Reference.SemVer = sourceArgs.GitSemver
} else if sourceGitTag != "" { } else if sourceArgs.GitTag != "" {
gitRepository.Spec.Reference.Tag = sourceGitTag gitRepository.Spec.Reference.Tag = sourceArgs.GitTag
} else { } else {
gitRepository.Spec.Reference.Branch = sourceGitBranch gitRepository.Spec.Reference.Branch = sourceArgs.GitBranch
} }
if export { if createArgs.export {
if sourceGitSecretRef != "" { if sourceArgs.GitSecretRef != "" {
gitRepository.Spec.SecretRef = &corev1.LocalObjectReference{ gitRepository.Spec.SecretRef = &meta.LocalObjectReference{
Name: sourceGitSecretRef, Name: sourceArgs.GitSecretRef,
} }
} }
return exportGit(gitRepository) return exportGit(gitRepository)
} }
ctx, cancel := context.WithTimeout(context.Background(), timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext) kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil { if err != nil {
return err return err
} }
withAuth := false withAuth := false
// TODO(hidde): move all auth prep to separate func? // TODO(hidde): move all auth prep to separate func?
if sourceGitSecretRef != "" { if sourceArgs.GitSecretRef != "" {
withAuth = true withAuth = true
} else if u.Scheme == "ssh" { } else if u.Scheme == "ssh" {
logger.Generatef("generating deploy key pair") logger.Generatef("generating deploy key pair")
pair, err := generateKeyPair(ctx, sourceGitKeyAlgorithm, sourceGitRSABits, sourceGitECDSACurve) pair, err := generateKeyPair(ctx, sourceArgs.GitKeyAlgorithm, sourceArgs.GitRSABits, sourceArgs.GitECDSACurve)
if err != nil { if err != nil {
return err return err
} }
@@ -216,7 +227,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
secret := corev1.Secret{ secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: namespace, Namespace: rootArgs.namespace,
Labels: sourceLabels, Labels: sourceLabels,
}, },
StringData: map[string]string{ StringData: map[string]string{
@@ -229,17 +240,17 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return err return err
} }
withAuth = true withAuth = true
} else if sourceGitUsername != "" && sourceGitPassword != "" { } else if sourceArgs.GitUsername != "" && sourceArgs.GitPassword != "" {
logger.Actionf("applying secret with basic auth credentials") logger.Actionf("applying secret with basic auth credentials")
secret := corev1.Secret{ secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: namespace, Namespace: rootArgs.namespace,
Labels: sourceLabels, Labels: sourceLabels,
}, },
StringData: map[string]string{ StringData: map[string]string{
"username": sourceGitUsername, "username": sourceArgs.GitUsername,
"password": sourceGitPassword, "password": sourceArgs.GitPassword,
}, },
} }
if err := upsertSecret(ctx, kubeClient, secret); err != nil { if err := upsertSecret(ctx, kubeClient, secret); err != nil {
@@ -256,10 +267,10 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if withAuth { if withAuth {
secretName := name secretName := name
if sourceGitSecretRef != "" { if sourceArgs.GitSecretRef != "" {
secretName = sourceGitSecretRef secretName = sourceArgs.GitSecretRef
} }
gitRepository.Spec.SecretRef = &corev1.LocalObjectReference{ gitRepository.Spec.SecretRef = &meta.LocalObjectReference{
Name: secretName, Name: secretName,
} }
} }
@@ -271,7 +282,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
} }
logger.Waitingf("waiting for GitRepository source reconciliation") logger.Waitingf("waiting for GitRepository source reconciliation")
if err := wait.PollImmediate(pollInterval, timeout, if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isGitRepositoryReady(ctx, kubeClient, namespacedName, &gitRepository)); err != nil { isGitRepositoryReady(ctx, kubeClient, namespacedName, &gitRepository)); err != nil {
return err return err
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,15 +17,8 @@ limitations under the License.
package main package main
import ( import (
"context"
"fmt"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/flux2/internal/utils"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1" helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
"github.com/spf13/cobra"
) )
var deleteHelmReleaseCmd = &cobra.Command{ var deleteHelmReleaseCmd = &cobra.Command{
@@ -36,57 +29,12 @@ var deleteHelmReleaseCmd = &cobra.Command{
Example: ` # Delete a Helm release and the Kubernetes resources created by it Example: ` # Delete a Helm release and the Kubernetes resources created by it
flux delete hr podinfo flux delete hr podinfo
`, `,
RunE: deleteHelmReleaseCmdRun, RunE: deleteCommand{
apiType: helmReleaseType,
object: universalAdapter{&helmv2.HelmRelease{}},
}.run,
} }
func init() { func init() {
deleteCmd.AddCommand(deleteHelmReleaseCmd) deleteCmd.AddCommand(deleteHelmReleaseCmd)
} }
func deleteHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("release name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
if !deleteSilent {
if !helmRelease.Spec.Suspend {
logger.Waitingf("This action will remove the Kubernetes objects previously applied by the %s Helm release!", name)
}
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this Helm release",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting release %s in %s namespace", name, namespace)
err = kubeClient.Delete(ctx, &helmRelease)
if err != nil {
return err
}
logger.Successf("release deleted")
return nil
}

View File

@@ -17,14 +17,8 @@ limitations under the License.
package main package main
import ( import (
"context"
"fmt"
"github.com/fluxcd/flux2/internal/utils"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
) )
var deleteKsCmd = &cobra.Command{ var deleteKsCmd = &cobra.Command{
@@ -35,57 +29,12 @@ var deleteKsCmd = &cobra.Command{
Example: ` # Delete a kustomization and the Kubernetes resources created by it Example: ` # Delete a kustomization and the Kubernetes resources created by it
flux delete kustomization podinfo flux delete kustomization podinfo
`, `,
RunE: deleteKsCmdRun, RunE: deleteCommand{
apiType: kustomizationType,
object: universalAdapter{&kustomizev1.Kustomization{}},
}.run,
} }
func init() { func init() {
deleteCmd.AddCommand(deleteKsCmd) deleteCmd.AddCommand(deleteKsCmd)
} }
func deleteKsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("kustomization name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var kustomization kustomizev1.Kustomization
err = kubeClient.Get(ctx, namespacedName, &kustomization)
if err != nil {
return err
}
if !deleteSilent {
if !kustomization.Spec.Suspend {
logger.Waitingf("This action will remove the Kubernetes objects previously applied by the %s kustomization!", name)
}
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this kustomization",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting kustomization %s in %s namespace", name, namespace)
err = kubeClient.Delete(ctx, &kustomization)
if err != nil {
return err
}
logger.Successf("kustomization deleted")
return nil
}

View File

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

View File

@@ -17,14 +17,8 @@ limitations under the License.
package main package main
import ( import (
"context"
"fmt"
"github.com/fluxcd/flux2/internal/utils"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
) )
var deleteSourceBucketCmd = &cobra.Command{ var deleteSourceBucketCmd = &cobra.Command{
@@ -34,54 +28,12 @@ var deleteSourceBucketCmd = &cobra.Command{
Example: ` # Delete a Bucket source Example: ` # Delete a Bucket source
flux delete source bucket podinfo flux delete source bucket podinfo
`, `,
RunE: deleteSourceBucketCmdRun, RunE: deleteCommand{
apiType: bucketType,
object: universalAdapter{&sourcev1.Bucket{}},
}.run,
} }
func init() { func init() {
deleteSourceCmd.AddCommand(deleteSourceBucketCmd) deleteSourceCmd.AddCommand(deleteSourceBucketCmd)
} }
func deleteSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var bucket sourcev1.Bucket
err = kubeClient.Get(ctx, namespacedName, &bucket)
if err != nil {
return err
}
if !deleteSilent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this source",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting source %s in %s namespace", name, namespace)
err = kubeClient.Delete(ctx, &bucket)
if err != nil {
return err
}
logger.Successf("source deleted")
return nil
}

View File

@@ -17,14 +17,8 @@ limitations under the License.
package main package main
import ( import (
"context"
"fmt"
"github.com/fluxcd/flux2/internal/utils"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
) )
var deleteSourceGitCmd = &cobra.Command{ var deleteSourceGitCmd = &cobra.Command{
@@ -34,54 +28,12 @@ var deleteSourceGitCmd = &cobra.Command{
Example: ` # Delete a Git repository Example: ` # Delete a Git repository
flux delete source git podinfo flux delete source git podinfo
`, `,
RunE: deleteSourceGitCmdRun, RunE: deleteCommand{
apiType: gitRepositoryType,
object: universalAdapter{&sourcev1.GitRepository{}},
}.run,
} }
func init() { func init() {
deleteSourceCmd.AddCommand(deleteSourceGitCmd) deleteSourceCmd.AddCommand(deleteSourceGitCmd)
} }
func deleteSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("git name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var git sourcev1.GitRepository
err = kubeClient.Get(ctx, namespacedName, &git)
if err != nil {
return err
}
if !deleteSilent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this source",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting source %s in %s namespace", name, namespace)
err = kubeClient.Delete(ctx, &git)
if err != nil {
return err
}
logger.Successf("source deleted")
return nil
}

View File

@@ -34,7 +34,10 @@ var deleteSourceHelmCmd = &cobra.Command{
Example: ` # Delete a Helm repository Example: ` # Delete a Helm repository
flux delete source helm podinfo flux delete source helm podinfo
`, `,
RunE: deleteSourceHelmCmdRun, RunE: deleteCommand{
apiType: helmRepositoryType,
object: universalAdapter{&sourcev1.HelmRepository{}},
}.run,
} }
func init() { func init() {
@@ -47,16 +50,16 @@ func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
} }
name := args[0] name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext) kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil { if err != nil {
return err return err
} }
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: namespace, Namespace: rootArgs.namespace,
Name: name, Name: name,
} }
@@ -66,7 +69,7 @@ func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
return err return err
} }
if !deleteSilent { if !deleteArgs.silent {
prompt := promptui.Prompt{ prompt := promptui.Prompt{
Label: "Are you sure you want to delete this source", Label: "Are you sure you want to delete this source",
IsConfirm: true, IsConfirm: true,
@@ -76,7 +79,7 @@ func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
} }
} }
logger.Actionf("deleting source %s in %s namespace", name, namespace) logger.Actionf("deleting source %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &helmRepository) err = kubeClient.Delete(ctx, &helmRepository)
if err != nil { if err != nil {
return err return err

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

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

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

View File

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

View File

@@ -69,16 +69,16 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
} }
name := args[0] name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext) kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil { if err != nil {
return err return err
} }
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: namespace, Namespace: rootArgs.namespace,
Name: name, Name: name,
} }
@@ -91,7 +91,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
return fmt.Errorf("resource is suspended") return fmt.Errorf("resource is suspended")
} }
logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, namespace) logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, rootArgs.namespace)
if err := requestReconciliation(ctx, kubeClient, namespacedName, reconcile.object); err != nil { if err := requestReconciliation(ctx, kubeClient, namespacedName, reconcile.object); err != nil {
return err return err
} }
@@ -99,7 +99,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
lastHandledReconcileAt := reconcile.object.lastHandledReconcileRequest() lastHandledReconcileAt := reconcile.object.lastHandledReconcileRequest()
logger.Waitingf("waiting for %s reconciliation", reconcile.kind) logger.Waitingf("waiting for %s reconciliation", reconcile.kind)
if err := wait.PollImmediate(pollInterval, timeout, if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
reconciliationHandled(ctx, kubeClient, namespacedName, reconcile.object, lastHandledReconcileAt)); err != nil { reconciliationHandled(ctx, kubeClient, namespacedName, reconcile.object, lastHandledReconcileAt)); err != nil {
return err return err
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,10 +2,6 @@
Generates bash completion scripts Generates bash completion scripts
### Synopsis
Generates bash completion scripts
``` ```
flux completion bash [flags] flux completion bash [flags]
``` ```

View File

@@ -2,10 +2,6 @@
Generates fish completion scripts Generates fish completion scripts
### Synopsis
Generates fish completion scripts
``` ```
flux completion fish [flags] flux completion fish [flags]
``` ```

View File

@@ -2,10 +2,6 @@
Generates powershell completion scripts Generates powershell completion scripts
### Synopsis
Generates powershell completion scripts
``` ```
flux completion powershell [flags] flux completion powershell [flags]
``` ```

View File

@@ -2,10 +2,6 @@
Generates zsh completion scripts Generates zsh completion scripts
### Synopsis
Generates zsh completion scripts
``` ```
flux completion zsh [flags] flux completion zsh [flags]
``` ```

View File

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

View File

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

View File

@@ -0,0 +1,16 @@
# Image reflector and automation controllers
The image-reflector-controller and image-automation-controller work together to update a Git
repository when new container images are available.
- The image-reflector-controller scans image repositories and reflects the image metadata in
Kubernetes resources.
- The image-automation-controller updates YAML files based on the latest images scanned, and commits
the changes to a given Git repository.
Links:
- Source code [fluxcd/image-reflector-controller](https://github.com/fluxcd/image-reflector-controller)
- Reflector [specification docs](https://github.com/fluxcd/image-reflector-controller/tree/main/docs/spec)
- Source code [fluxcd/image-automation-controller](https://github.com/fluxcd/image-automation-controller)
- Automation [specification docs](https://github.com/fluxcd/image-automation-controller/tree/main/docs/spec)

View File

@@ -24,3 +24,7 @@ A reference for each component and API type is linked below.
- [Provider CRD](notification/provider.md) - [Provider CRD](notification/provider.md)
- [Alert CRD](notification/alert.md) - [Alert CRD](notification/alert.md)
- [Receiver CRD](notification/receiver.md) - [Receiver CRD](notification/receiver.md)
- [Image automation controllers](image/controller.md)
- [ImageRepository CRD](image/imagerepositories.md)
- [ImagePolicy CRD](image/imagepolicies.md)
- [ImageUpdateAutomation CRD](image/imageupdateautomation.md)

View File

@@ -88,8 +88,7 @@ There is a new `spec.suspend` field, that if set to `true` causes the Helm Contr
We have added support for making Helm releases to other clusters. If the `spec.kubeConfig` field in the `HelmRelease` is set, Helm actions will run against the default cluster specified in that KubeConfig instead of the local cluster that is responsible for the reconciliation of the `HelmRelease`. We have added support for making Helm releases to other clusters. If the `spec.kubeConfig` field in the `HelmRelease` is set, Helm actions will run against the default cluster specified in that KubeConfig instead of the local cluster that is responsible for the reconciliation of the `HelmRelease`.
The Helm storage is stored on the remote cluster in a namespace that equals to the namespace of the `HelmRelease`, the release itself is made in either this namespace, or the configured `spec.targetNamespace`. In any case, both are expected to exist, and can for example be created using the [Kustomize Controller](https://toolkit.fluxcd.io/components/kustomize/controller/) which has the same cross-cluster support. The Helm storage is stored on the remote cluster in a namespace that equals to the namespace of the `HelmRelease`, or the configured `spec.storageNamespace`. The release itself is made in a namespace that equals to the namespace of the `HelmRelease`, or the configured `spec.targetNamespace`. The namespaces are expected to exist, and can for example be created using the [Kustomize Controller](https://toolkit.fluxcd.io/components/kustomize/controller/) which has the same cross-cluster support.
Other references to Kubernetes resources in the `HelmRelease`, like `ValuesReference` resources, are expected to exist on the reconciling cluster. Other references to Kubernetes resources in the `HelmRelease`, like `ValuesReference` resources, are expected to exist on the reconciling cluster.
### Added support for notifications and webhooks ### Added support for notifications and webhooks
@@ -681,7 +680,7 @@ The recommended migration steps for a single `HelmRelease` are as follows:
1. Ensure the Helm Operator is not running, as otherwise the Helm Controller and Helm Operator will fight over the release. 1. Ensure the Helm Operator is not running, as otherwise the Helm Controller and Helm Operator will fight over the release.
1. Create a [`GitRepository` or `HelmRepository` resource for the `HelmRelease`](#defining-the-helm-chart), including any `Secret` that may be required to access the source. Note that it is possible for multiple `HelmRelease` resources to share a `GitRepository` or `HelmRepository` resource. 1. Create a [`GitRepository` or `HelmRepository` resource for the `HelmRelease`](#defining-the-helm-chart), including any `Secret` that may be required to access the source. Note that it is possible for multiple `HelmRelease` resources to share a `GitRepository` or `HelmRepository` resource.
1. Create a new `HelmRelease` resource ([with the `helm.toolkit.fluxcd.io` group domain](#the-helmrelease-custom-resource-group-domain-changed)), define the `spec.releaseName` (and `spec.targetNamespace` if applicable) to match that of the existing release, and rewrite the configuration to adhere to the [API spec changes](#api-spec-changes). 1. Create a new `HelmRelease` resource ([with the `helm.toolkit.fluxcd.io` group domain](#the-helmrelease-custom-resource-group-domain-changed)), define the `spec.releaseName` (plus the `spec.targetNamespace` and `spec.storageNamespace` if applicable) to match that of the existing release, and rewrite the configuration to adhere to the [API spec changes](#api-spec-changes).
1. Confirm the Helm Controller successfully upgrades the release. 1. Confirm the Helm Controller successfully upgrades the release.
### Example ### Example

View File

@@ -11,9 +11,8 @@ For a container image you can configure Flux to:
- apply the changes in-cluster and rollout the container image - apply the changes in-cluster and rollout the container image
!!! warning "Alpha version" !!! warning "Alpha version"
Note that the image update feature is currently alpha and, it only supports **semver** filters. Note that the image update feature is currently alpha,
In the future we plan to add support for other filtering options. see the [roadmap](../roadmap/index.md) for more details.
Please see the [roadmap](../roadmap/index.md) for more details.
For production environments, this feature allows you to automatically deploy application patches For production environments, this feature allows you to automatically deploy application patches
(CVEs and bug fixes), and keep a record of all deployments in Git history. (CVEs and bug fixes), and keep a record of all deployments in Git history.
@@ -185,6 +184,10 @@ spec:
If you want to include pre-release e.g. `1.0.0-rc.1`, If you want to include pre-release e.g. `1.0.0-rc.1`,
you can define a range like: `^1.x-0` or `>1.0.0-rc <2.0.0-rc`. you can define a range like: `^1.x-0` or `>1.0.0-rc <2.0.0-rc`.
!!! hint "Other policy examples"
For policies that make use of CalVer, build IDs or alphabetical sorting,
have a look at [the examples](../components/image/imagepolicies.md#examples).
Commit and push changes to main branch: Commit and push changes to main branch:
```sh ```sh

View File

@@ -242,9 +242,7 @@ mkdir -p ./clusters/my-cluster/flux-system
Generate the Flux manifests with: Generate the Flux manifests with:
```sh ```sh
# on ARM64/AARCH64 clusters use --arch=arm64
flux install --version=latest \ flux install --version=latest \
--arch=amd64 \
--export > ./clusters/my-cluster/flux-system/gotk-components.yaml --export > ./clusters/my-cluster/flux-system/gotk-components.yaml
``` ```
@@ -388,7 +386,6 @@ Kubernetes manifests that can be used to install or upgrade Flux:
```hcl ```hcl
data "flux_install" "main" { data "flux_install" "main" {
target_path = "clusters/my-cluster" target_path = "clusters/my-cluster"
arch = "amd64"
network_policy = false network_policy = false
version = "latest" version = "latest"
} }

View File

@@ -106,8 +106,10 @@ secrets by iterating over all the private keys until it finds one that works.
### Using various cloud providers ### Using various cloud providers
When using AWS/GCP KMS, you'll have to bind an IAM Role with access to the KMS When using AWS/GCP KMS, you don't have to include the gpg `secretRef` under
keys to the `default` service account of the `flux-system` namespace for `spec.provider` (you can skip the `--decryption-secret` flag when running `flux create kustomization`),
instead you'll have to bind an IAM Role with access to the KMS
keys to the `kustomize-controller` service account of the `flux-system` namespace for
kustomize-controller to be able to fetch keys from KMS. kustomize-controller to be able to fetch keys from KMS.
#### AWS #### AWS
@@ -144,13 +146,12 @@ or with [add-pod-identity](https://github.com/Azure/aad-pod-identity).
Please ensure that the GKE cluster has Workload Identity enabled. Please ensure that the GKE cluster has Workload Identity enabled.
1. Create a service account with the role `Cloud KMS CryptoKey Encrypter/Decrypter`. 1. Create a service account with the role `Cloud KMS CryptoKey Encrypter/Decrypter`.
2. Create an IAM policy binding between the GCP service account to the `default` service account of the `flux-system`. 2. Create an IAM policy binding between the GCP service account to the `kustomize-controller` service account of the `flux-system`.
3. Annotate the `default` service account in the `flux-system` with the GCP service account. 3. Annotate the `kustomize-controller` service account in the `flux-system` with the GCP service account.
```sh ```sh
kubectl annotate serviceaccount \ kubectl annotate serviceaccount kustomize-controller \
--namespace flux-system \ --namespace flux-system \
default \
iam.gke.io/gcp-service-account=<name-of-serviceaccount>@project-id.iam.gserviceaccount.com iam.gke.io/gcp-service-account=<name-of-serviceaccount>@project-id.iam.gserviceaccount.com
``` ```

View File

@@ -84,20 +84,8 @@ Depending on what you want to do, some of the following bits might be your first
- And if you are completely new to Flux v2 and the GitOps Toolkit, take a look at our [Get Started guide](get-started/index.md) and give us feedback - And if you are completely new to Flux v2 and the GitOps Toolkit, take a look at our [Get Started guide](get-started/index.md) and give us feedback
- Check out [how to contribute](contributing/index.md) to the project - Check out [how to contribute](contributing/index.md) to the project
### Upcoming Events ### Events
- 25 Jan 2021 - [GitOps Core Concepts & How to Teach Your Teams with Leigh Capili](https://www.meetup.com/GitOps-Community/events/275625806/)
### Featured Talks Check out our **[events calendar](https://fluxcd.io/community/#talks)**, both with upcoming talks you can attend or past events videos you can watch.
- 11 Jan 2021 - [Helm + GitOps = ⚡️⚡️⚡️ with Scott Rigby](https://youtu.be/YG8jMFrYQvM)
- 14 Dec 2020 - [The Power of GitOps with Flux and Flagger (GitOps Hands-On) with Leigh Capili](https://youtu.be/cB7iXeNLteE)
- 30 Nov 2020 - [The Power of GItOps with Flux 2 - Part 3 with Leigh Capili](https://youtu.be/N_K5g7o9JKg)
- 24 Nov 2020 - [Flux CD v2 with GitOps Toolkit - Kubernetes Deployment and Sync Mechanism](https://youtu.be/R6OeIgb7lUI)
- 02 Nov 2020 - [The Power of GitOps with Flux & GitOps Toolkit - Part 2 with Leigh Capili](https://youtu.be/fC2YCxQRUwU)
- 28 Oct 2020 - [The Kubelist Podcast: Flux with Michael Bridgen](https://www.heavybit.com/library/podcasts/the-kubelist-podcast/ep-5-flux-with-michael-bridgen-of-weaveworks/)
- 19 Oct 2020 - [The Power of GitOps with Flux & GitOps Toolkit - Part 1 with Leigh Capili](https://youtu.be/0v5bjysXTL8)
- 12 Oct 2020 - [Rawkode Live: Introduction to GitOps Toolkit with Stefan Prodan](https://youtu.be/HqTzuOBP0eY)
- 04 Sep 2020 - [KubeCon Europe: The road to Flux v2 and Progressive Delivery with Stefan Prodan & Hidde Beydals](https://youtu.be/8v94nUkXsxU)
- 25 June 2020 - [Cloud Native Nordics: Introduction to GitOps & GitOps Toolkit with Alexis Richardson & Stefan Prodan](https://youtu.be/qQBtSkgl7tI)
- 07 May 2020 - [GitOps Days - Community Special: GitOps Toolkit Experimentation with Stefan Prodan](https://youtu.be/WHzxunv4DKk?t=6521)
We look forward to seeing you with us! We look forward to seeing you with us!

View File

@@ -16,12 +16,20 @@ Repositories subject to semver releases:
1. [fluxcd/helm-controller](https://github.com/fluxcd/helm-controller) 1. [fluxcd/helm-controller](https://github.com/fluxcd/helm-controller)
- modules: `api` - modules: `api`
- dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/pkg/*` - dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/pkg/*`
1. [fluxcd/image-reflector-controller](https://github.com/fluxcd/image-reflector-controller)
- modules: `api`
- dependencies: `github.com/fluxcd/pkg/*`
1. [fluxcd/image-automation-controller](https://github.com/fluxcd/image-automation-controller)
- modules: `api`
- dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/image-reflector-controller/api`, `github.com/fluxcd/pkg/*`
1. [fluxcd/notification-controller](https://github.com/fluxcd/notification-controller) 1. [fluxcd/notification-controller](https://github.com/fluxcd/notification-controller)
- modules: `api` - modules: `api`
- dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/pkg/*` - dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/pkg/*`
1. [fluxcd/flux2](https://github.com/fluxcd/flux2) 1. [fluxcd/flux2](https://github.com/fluxcd/flux2)
- modules: `manifestgen` - modules: `manifestgen`
- dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/kustomize-controller/api`, `github.com/fluxcd/helm-controller/api`, `github.com/fluxcd/notification-controller/api`,`github.com/fluxcd/pkg/*` - dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/kustomize-controller/api`, `github.com/fluxcd/helm-controller/api`, `github.com/fluxcd/image-reflector-controller/api`, `github.com/fluxcd/image-automation-controller/api`, `github.com/fluxcd/notification-controller/api`, `github.com/fluxcd/pkg/*`
1. [fluxcd/terraform-provider-flux](https://github.com/fluxcd/terraform-provider-flux)
- dependencies: `github.com/fluxcd/flux2/pkg/manifestgen`
## Release procedure ## Release procedure
@@ -77,16 +85,17 @@ Flux has the following Kubernetes dependencies:
**Note** that all `k8s.io/*` packages must the have the same version in `go.mod` e.g.: **Note** that all `k8s.io/*` packages must the have the same version in `go.mod` e.g.:
``` ```
k8s.io/api v0.19.2 k8s.io/api v0.20.2
k8s.io/apiextensions-apiserver v0.19.2 k8s.io/apiextensions-apiserver v0.20.2
k8s.io/apimachinery v0.19.2 k8s.io/apimachinery v0.20.2
k8s.io/cli-runtime v0.19.2 k8s.io/cli-runtime v0.20.2
k8s.io/client-go v0.19.2 k8s.io/client-go v0.20.2
``` ```
The specialised reconcilers depend on: The specialised reconcilers depend on:
- kustomize-controller: `sigs.k8s.io/kustomize/api` - kustomize-controller: `sigs.k8s.io/kustomize/api`
- image-automation-controller: `sigs.k8s.io/kustomize/kyaml`
- helm-controller: `helm.sh/helm/v3` - helm-controller: `helm.sh/helm/v3`
**Note** that the `k8s.io/*` version must be compatible with both `kustomize/api` and `helm/v3`. **Note** that the `k8s.io/*` version must be compatible with both `kustomize/api` and `helm/v3`.
@@ -111,7 +120,7 @@ Upgrade procedure:
1. Update the `github.com/fluxcd/pkg/runtime` version in `source-controller/go.mod` 1. Update the `github.com/fluxcd/pkg/runtime` version in `source-controller/go.mod`
1. Release the `api` package 1. Release the `api` package
`fluxcd/<kustomize|helm|notification>-controller`: `fluxcd/<kustomize|helm|notification|image-automation>-controller`:
1. Update the `github.com/fluxcd/source-controller/api` version in `controller/api/go.mod` and `controller/go.mod` 1. Update the `github.com/fluxcd/source-controller/api` version in `controller/api/go.mod` and `controller/go.mod`
1. Update the `github.com/fluxcd/pkg/apis/meta` version in `controller/api/go.mod` and `controller/go.mod` 1. Update the `github.com/fluxcd/pkg/apis/meta` version in `controller/api/go.mod` and `controller/go.mod`
@@ -121,6 +130,10 @@ Upgrade procedure:
`fluxcd/flux2`: `fluxcd/flux2`:
1. Update the `github.com/fluxcd/*-controller/api` version in `flux2/go.mod` 1. Update the `github.com/fluxcd/*-controller/api` version in `flux2/go.mod` (automated with [GitHub Actions](../../.github/workflows/update.yml))
1. Update the `github.com/fluxcd/pkg/*` version in `flux2/go.mod` 1. Update the `github.com/fluxcd/pkg/*` version in `flux2/go.mod`
1. Update the `k8s.io/*` and `github.com/fluxcd/pkg/runtime` version in `flux2/go.mod` 1. Update the `k8s.io/*` and `github.com/fluxcd/pkg/runtime` version in `flux2/go.mod`
`fluxcd/terraform-provider-flux`:
1. Update the `github.com/fluxcd/flux2` version in `terraform-provider-flux/go.mod` (automated with [GitHub Actions](https://github.com/fluxcd/terraform-provider-flux/blob/main/.github/workflows/update.yaml))

31
go.mod
View File

@@ -5,26 +5,27 @@ go 1.15
require ( require (
github.com/blang/semver/v4 v4.0.0 github.com/blang/semver/v4 v4.0.0
github.com/cyphar/filepath-securejoin v0.2.2 github.com/cyphar/filepath-securejoin v0.2.2
github.com/fluxcd/helm-controller/api v0.5.1 github.com/fluxcd/helm-controller/api v0.6.1
github.com/fluxcd/image-automation-controller/api v0.3.0 github.com/fluxcd/image-automation-controller/api v0.4.0
github.com/fluxcd/image-reflector-controller/api v0.2.0 github.com/fluxcd/image-reflector-controller/api v0.4.1
github.com/fluxcd/kustomize-controller/api v0.6.2 github.com/fluxcd/kustomize-controller/api v0.7.2
github.com/fluxcd/notification-controller/api v0.6.1 github.com/fluxcd/notification-controller/api v0.7.1
github.com/fluxcd/pkg/apis/meta v0.5.0 github.com/fluxcd/pkg/apis/meta v0.7.0
github.com/fluxcd/pkg/git v0.2.1 github.com/fluxcd/pkg/git v0.2.3
github.com/fluxcd/pkg/runtime v0.6.2 github.com/fluxcd/pkg/runtime v0.8.0
github.com/fluxcd/pkg/ssh v0.0.5 github.com/fluxcd/pkg/ssh v0.0.5
github.com/fluxcd/pkg/untar v0.0.5 github.com/fluxcd/pkg/untar v0.0.5
github.com/fluxcd/source-controller/api v0.6.1 github.com/fluxcd/source-controller/api v0.7.1
github.com/google/go-containerregistry v0.2.0 github.com/google/go-containerregistry v0.2.0
github.com/manifoldco/promptui v0.7.0 github.com/manifoldco/promptui v0.7.0
github.com/olekukonko/tablewriter v0.0.4 github.com/olekukonko/tablewriter v0.0.4
github.com/spf13/cobra v1.0.0 github.com/spf13/cobra v1.1.1
k8s.io/api v0.19.4 github.com/spf13/pflag v1.0.5
k8s.io/apiextensions-apiserver v0.19.4 k8s.io/api v0.20.2
k8s.io/apimachinery v0.19.4 k8s.io/apiextensions-apiserver v0.20.2
k8s.io/client-go v0.19.4 k8s.io/apimachinery v0.20.2
sigs.k8s.io/controller-runtime v0.7.0 k8s.io/client-go v0.20.2
sigs.k8s.io/controller-runtime v0.8.0
sigs.k8s.io/kustomize/api v0.7.0 sigs.k8s.io/kustomize/api v0.7.0
sigs.k8s.io/yaml v1.2.0 sigs.k8s.io/yaml v1.2.0
) )

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