From 465eaa24d3c80f06cae6baf1e966a3cd1b74f3b0 Mon Sep 17 00:00:00 2001 From: Somtochi Onyekwere Date: Wed, 24 Mar 2021 12:31:26 +0100 Subject: [PATCH] Refactor all remaining create, delete, export, get command to use adapter Signed-off-by: Somtochi Onyekwere --- cmd/flux/alert.go | 51 ++++++++++++ cmd/flux/alert_provider.go | 51 ++++++++++++ cmd/flux/create_alert.go | 2 +- cmd/flux/create_alertprovider.go | 2 +- cmd/flux/create_helmrelease.go | 2 +- cmd/flux/create_kustomization.go | 2 +- cmd/flux/create_receiver.go | 2 +- cmd/flux/create_source_bucket.go | 2 +- cmd/flux/create_source_git.go | 2 +- cmd/flux/create_source_helm.go | 2 +- cmd/flux/delete_alert.go | 59 ++------------ cmd/flux/delete_alertprovider.go | 59 ++------------ cmd/flux/delete_receiver.go | 59 ++------------ cmd/flux/delete_source_helm.go | 51 ------------ cmd/flux/export.go | 4 +- cmd/flux/export_alert.go | 78 ++++-------------- cmd/flux/export_alertprovider.go | 77 +++--------------- cmd/flux/export_helmrelease.go | 77 +++--------------- cmd/flux/export_kustomization.go | 78 ++++-------------- cmd/flux/export_receiver.go | 78 ++++-------------- cmd/flux/export_secret.go | 133 +++++++++++++++++++++++++++++++ cmd/flux/export_source_bucket.go | 128 ++++++----------------------- cmd/flux/export_source_git.go | 126 ++++++----------------------- cmd/flux/export_source_helm.go | 126 ++++++----------------------- cmd/flux/get_alert.go | 76 ++++-------------- cmd/flux/get_alertprovider.go | 75 ++++------------- cmd/flux/get_receiver.go | 73 ++++------------- cmd/flux/receiver.go | 51 ++++++++++++ 28 files changed, 498 insertions(+), 1028 deletions(-) create mode 100644 cmd/flux/alert.go create mode 100644 cmd/flux/alert_provider.go create mode 100644 cmd/flux/export_secret.go create mode 100644 cmd/flux/receiver.go diff --git a/cmd/flux/alert.go b/cmd/flux/alert.go new file mode 100644 index 00000000..e0bc2887 --- /dev/null +++ b/cmd/flux/alert.go @@ -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 ( + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// notificationv1.Alert + +var alertType = apiType{ + kind: notificationv1.AlertKind, + humanKind: "alert", +} + +type alertAdapter struct { + *notificationv1.Alert +} + +func (a alertAdapter) asClientObject() client.Object { + return a.Alert +} + +// notificationv1.Alert + +type alertListAdapter struct { + *notificationv1.AlertList +} + +func (a alertListAdapter) asClientList() client.ObjectList { + return a.AlertList +} + +func (a alertListAdapter) len() int { + return len(a.AlertList.Items) +} diff --git a/cmd/flux/alert_provider.go b/cmd/flux/alert_provider.go new file mode 100644 index 00000000..c2722ff0 --- /dev/null +++ b/cmd/flux/alert_provider.go @@ -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 ( + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// notificationv1.Provider + +var alertProviderType = apiType{ + kind: notificationv1.ProviderKind, + humanKind: "alert provider", +} + +type alertProviderAdapter struct { + *notificationv1.Provider +} + +func (a alertProviderAdapter) asClientObject() client.Object { + return a.Provider +} + +// notificationv1.Provider + +type alertProviderListAdapter struct { + *notificationv1.ProviderList +} + +func (a alertProviderListAdapter) asClientList() client.ObjectList { + return a.ProviderList +} + +func (a alertProviderListAdapter) len() int { + return len(a.ProviderList.Items) +} diff --git a/cmd/flux/create_alert.go b/cmd/flux/create_alert.go index 8dbeb807..0718d03a 100644 --- a/cmd/flux/create_alert.go +++ b/cmd/flux/create_alert.go @@ -116,7 +116,7 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error { } if createArgs.export { - return exportAlert(alert) + return printExport(exportAlert(&alert)) } ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) diff --git a/cmd/flux/create_alertprovider.go b/cmd/flux/create_alertprovider.go index dc7164cf..e9099ed9 100644 --- a/cmd/flux/create_alertprovider.go +++ b/cmd/flux/create_alertprovider.go @@ -113,7 +113,7 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error { } if createArgs.export { - return exportAlertProvider(provider) + return printExport(exportAlertProvider(&provider)) } ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) diff --git a/cmd/flux/create_helmrelease.go b/cmd/flux/create_helmrelease.go index d316cfcf..11886b71 100644 --- a/cmd/flux/create_helmrelease.go +++ b/cmd/flux/create_helmrelease.go @@ -219,7 +219,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error { } if createArgs.export { - return exportHelmRelease(helmRelease) + return printExport(exportHelmRelease(&helmRelease)) } ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) diff --git a/cmd/flux/create_kustomization.go b/cmd/flux/create_kustomization.go index f5ca3593..650c2854 100644 --- a/cmd/flux/create_kustomization.go +++ b/cmd/flux/create_kustomization.go @@ -211,7 +211,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error { } if createArgs.export { - return exportKs(kustomization) + return printExport(exportKs(&kustomization)) } ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) diff --git a/cmd/flux/create_receiver.go b/cmd/flux/create_receiver.go index 49ab3b80..9568fd6c 100644 --- a/cmd/flux/create_receiver.go +++ b/cmd/flux/create_receiver.go @@ -125,7 +125,7 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error { } if createArgs.export { - return exportReceiver(receiver) + return printExport(exportReceiver(&receiver)) } ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) diff --git a/cmd/flux/create_source_bucket.go b/cmd/flux/create_source_bucket.go index 212dc685..20063017 100644 --- a/cmd/flux/create_source_bucket.go +++ b/cmd/flux/create_source_bucket.go @@ -144,7 +144,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error { } if createArgs.export { - return exportBucket(*bucket) + return printExport(exportBucket(bucket)) } ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) diff --git a/cmd/flux/create_source_git.go b/cmd/flux/create_source_git.go index e245af6b..0741b968 100644 --- a/cmd/flux/create_source_git.go +++ b/cmd/flux/create_source_git.go @@ -195,7 +195,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error { } if createArgs.export { - return exportGit(gitRepository) + return printExport(exportGit(&gitRepository)) } ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) diff --git a/cmd/flux/create_source_helm.go b/cmd/flux/create_source_helm.go index c9940b22..174e7ed9 100644 --- a/cmd/flux/create_source_helm.go +++ b/cmd/flux/create_source_helm.go @@ -137,7 +137,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error { } if createArgs.export { - return exportHelmRepository(*helmRepository) + return printExport(exportHelmRepository(helmRepository)) } ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) diff --git a/cmd/flux/delete_alert.go b/cmd/flux/delete_alert.go index 0f9ce12e..6788c28b 100644 --- a/cmd/flux/delete_alert.go +++ b/cmd/flux/delete_alert.go @@ -17,15 +17,8 @@ limitations under the License. package main import ( - "context" - "fmt" - - "github.com/manifoldco/promptui" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/types" - - "github.com/fluxcd/flux2/internal/utils" notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" + "github.com/spf13/cobra" ) var deleteAlertCmd = &cobra.Command{ @@ -35,54 +28,12 @@ var deleteAlertCmd = &cobra.Command{ Example: ` # Delete an Alert and the Kubernetes resources created by it flux delete alert main `, - RunE: deleteAlertCmdRun, + RunE: deleteCommand{ + apiType: alertType, + object: universalAdapter{¬ificationv1.Alert{}}, + }.run, } func init() { deleteCmd.AddCommand(deleteAlertCmd) } - -func deleteAlertCmdRun(cmd *cobra.Command, args []string) error { - if len(args) < 1 { - return fmt.Errorf("alert name is required") - } - name := args[0] - - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - namespacedName := types.NamespacedName{ - Namespace: rootArgs.namespace, - Name: name, - } - - var alert notificationv1.Alert - err = kubeClient.Get(ctx, namespacedName, &alert) - if err != nil { - return err - } - - if !deleteArgs.silent { - prompt := promptui.Prompt{ - Label: "Are you sure you want to delete this Alert", - IsConfirm: true, - } - if _, err := prompt.Run(); err != nil { - return fmt.Errorf("aborting") - } - } - - logger.Actionf("deleting alert %s in %s namespace", name, rootArgs.namespace) - err = kubeClient.Delete(ctx, &alert) - if err != nil { - return err - } - logger.Successf("alert deleted") - - return nil -} diff --git a/cmd/flux/delete_alertprovider.go b/cmd/flux/delete_alertprovider.go index 3e58e963..8a2e0377 100644 --- a/cmd/flux/delete_alertprovider.go +++ b/cmd/flux/delete_alertprovider.go @@ -17,15 +17,8 @@ limitations under the License. package main import ( - "context" - "fmt" - - "github.com/manifoldco/promptui" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/types" - - "github.com/fluxcd/flux2/internal/utils" notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" + "github.com/spf13/cobra" ) var deleteAlertProviderCmd = &cobra.Command{ @@ -35,54 +28,12 @@ var deleteAlertProviderCmd = &cobra.Command{ Example: ` # Delete a Provider and the Kubernetes resources created by it flux delete alert-provider slack `, - RunE: deleteAlertProviderCmdRun, + RunE: deleteCommand{ + apiType: alertProviderType, + object: universalAdapter{¬ificationv1.Provider{}}, + }.run, } func init() { deleteCmd.AddCommand(deleteAlertProviderCmd) } - -func deleteAlertProviderCmdRun(cmd *cobra.Command, args []string) error { - if len(args) < 1 { - return fmt.Errorf("provider name is required") - } - name := args[0] - - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - namespacedName := types.NamespacedName{ - Namespace: rootArgs.namespace, - Name: name, - } - - var alertProvider notificationv1.Provider - err = kubeClient.Get(ctx, namespacedName, &alertProvider) - if err != nil { - return err - } - - if !deleteArgs.silent { - prompt := promptui.Prompt{ - Label: "Are you sure you want to delete this Provider", - IsConfirm: true, - } - if _, err := prompt.Run(); err != nil { - return fmt.Errorf("aborting") - } - } - - logger.Actionf("deleting provider %s in %s namespace", name, rootArgs.namespace) - err = kubeClient.Delete(ctx, &alertProvider) - if err != nil { - return err - } - logger.Successf("provider deleted") - - return nil -} diff --git a/cmd/flux/delete_receiver.go b/cmd/flux/delete_receiver.go index deef850e..489640ba 100644 --- a/cmd/flux/delete_receiver.go +++ b/cmd/flux/delete_receiver.go @@ -17,15 +17,8 @@ limitations under the License. package main import ( - "context" - "fmt" - - "github.com/manifoldco/promptui" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/types" - - "github.com/fluxcd/flux2/internal/utils" notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" + "github.com/spf13/cobra" ) var deleteReceiverCmd = &cobra.Command{ @@ -35,54 +28,12 @@ var deleteReceiverCmd = &cobra.Command{ Example: ` # Delete an Receiver and the Kubernetes resources created by it flux delete receiver main `, - RunE: deleteReceiverCmdRun, + RunE: deleteCommand{ + apiType: receiverType, + object: universalAdapter{¬ificationv1.Receiver{}}, + }.run, } func init() { deleteCmd.AddCommand(deleteReceiverCmd) } - -func deleteReceiverCmdRun(cmd *cobra.Command, args []string) error { - if len(args) < 1 { - return fmt.Errorf("receiver name is required") - } - name := args[0] - - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - namespacedName := types.NamespacedName{ - Namespace: rootArgs.namespace, - Name: name, - } - - var receiver notificationv1.Receiver - err = kubeClient.Get(ctx, namespacedName, &receiver) - if err != nil { - return err - } - - if !deleteArgs.silent { - prompt := promptui.Prompt{ - Label: "Are you sure you want to delete this Receiver", - IsConfirm: true, - } - if _, err := prompt.Run(); err != nil { - return fmt.Errorf("aborting") - } - } - - logger.Actionf("deleting receiver %s in %s namespace", name, rootArgs.namespace) - err = kubeClient.Delete(ctx, &receiver) - if err != nil { - return err - } - logger.Successf("receiver deleted") - - return nil -} diff --git a/cmd/flux/delete_source_helm.go b/cmd/flux/delete_source_helm.go index cbe3f86c..a744eaae 100644 --- a/cmd/flux/delete_source_helm.go +++ b/cmd/flux/delete_source_helm.go @@ -17,14 +17,8 @@ limitations under the License. package main import ( - "context" - "fmt" - - "github.com/fluxcd/flux2/internal/utils" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" - "github.com/manifoldco/promptui" "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/types" ) var deleteSourceHelmCmd = &cobra.Command{ @@ -43,48 +37,3 @@ var deleteSourceHelmCmd = &cobra.Command{ func init() { deleteSourceCmd.AddCommand(deleteSourceHelmCmd) } - -func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error { - if len(args) < 1 { - return fmt.Errorf("name is required") - } - name := args[0] - - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - namespacedName := types.NamespacedName{ - Namespace: rootArgs.namespace, - Name: name, - } - - var helmRepository sourcev1.HelmRepository - err = kubeClient.Get(ctx, namespacedName, &helmRepository) - if err != nil { - return err - } - - if !deleteArgs.silent { - prompt := promptui.Prompt{ - Label: "Are you sure you want to delete this source", - IsConfirm: true, - } - if _, err := prompt.Run(); err != nil { - return fmt.Errorf("aborting") - } - } - - logger.Actionf("deleting source %s in %s namespace", name, rootArgs.namespace) - err = kubeClient.Delete(ctx, &helmRepository) - if err != nil { - return err - } - logger.Successf("source deleted") - - return nil -} diff --git a/cmd/flux/export.go b/cmd/flux/export.go index 0b60fba9..99c11db1 100644 --- a/cmd/flux/export.go +++ b/cmd/flux/export.go @@ -20,7 +20,6 @@ import ( "bytes" "context" "fmt" - "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -86,8 +85,7 @@ func (export exportCommand) run(cmd *cobra.Command, args []string) error { } if export.list.len() == 0 { - logger.Failuref("no objects found in %s namespace", rootArgs.namespace) - return nil + return fmt.Errorf("no objects found in %s namespace", rootArgs.namespace) } for i := 0; i < export.list.len(); i++ { diff --git a/cmd/flux/export_alert.go b/cmd/flux/export_alert.go index b6c7cf80..cbb45fa7 100644 --- a/cmd/flux/export_alert.go +++ b/cmd/flux/export_alert.go @@ -17,17 +17,9 @@ limitations under the License. package main import ( - "context" - "fmt" - + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" - - "github.com/fluxcd/flux2/internal/utils" - notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" ) var exportAlertCmd = &cobra.Command{ @@ -40,60 +32,17 @@ var exportAlertCmd = &cobra.Command{ # Export a Alert flux export alert main > main.yaml `, - RunE: exportAlertCmdRun, + RunE: exportCommand{ + object: alertAdapter{¬ificationv1.Alert{}}, + list: alertListAdapter{¬ificationv1.AlertList{}}, + }.run, } func init() { exportCmd.AddCommand(exportAlertCmd) } -func exportAlertCmdRun(cmd *cobra.Command, args []string) error { - if !exportArgs.all && len(args) < 1 { - return fmt.Errorf("name is required") - } - - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - if exportArgs.all { - var list notificationv1.AlertList - err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace)) - if err != nil { - return err - } - - if len(list.Items) == 0 { - logger.Failuref("no alerts found in %s namespace", rootArgs.namespace) - return nil - } - - for _, alert := range list.Items { - if err := exportAlert(alert); err != nil { - return err - } - } - } else { - name := args[0] - namespacedName := types.NamespacedName{ - Namespace: rootArgs.namespace, - Name: name, - } - var alert notificationv1.Alert - err = kubeClient.Get(ctx, namespacedName, &alert) - if err != nil { - return err - } - return exportAlert(alert) - } - return nil -} - -func exportAlert(alert notificationv1.Alert) error { +func exportAlert(alert *notificationv1.Alert) interface{} { gvk := notificationv1.GroupVersion.WithKind("Alert") export := notificationv1.Alert{ TypeMeta: metav1.TypeMeta{ @@ -109,12 +58,13 @@ func exportAlert(alert notificationv1.Alert) error { Spec: alert.Spec, } - data, err := yaml.Marshal(export) - if err != nil { - return err - } + return export +} + +func (ex alertAdapter) export() interface{} { + return exportAlert(ex.Alert) +} - fmt.Println("---") - fmt.Println(resourceToString(data)) - return nil +func (ex alertListAdapter) exportItem(i int) interface{} { + return exportAlert(&ex.AlertList.Items[i]) } diff --git a/cmd/flux/export_alertprovider.go b/cmd/flux/export_alertprovider.go index f3404e03..f144dd93 100644 --- a/cmd/flux/export_alertprovider.go +++ b/cmd/flux/export_alertprovider.go @@ -17,17 +17,9 @@ limitations under the License. package main import ( - "context" - "fmt" - + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" - - "github.com/fluxcd/flux2/internal/utils" - notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" ) var exportAlertProviderCmd = &cobra.Command{ @@ -40,60 +32,17 @@ var exportAlertProviderCmd = &cobra.Command{ # Export a Provider flux export alert-provider slack > slack.yaml `, - RunE: exportAlertProviderCmdRun, + RunE: exportCommand{ + object: alertProviderAdapter{¬ificationv1.Provider{}}, + list: alertProviderListAdapter{¬ificationv1.ProviderList{}}, + }.run, } func init() { exportCmd.AddCommand(exportAlertProviderCmd) } -func exportAlertProviderCmdRun(cmd *cobra.Command, args []string) error { - if !exportArgs.all && len(args) < 1 { - return fmt.Errorf("name is required") - } - - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - if exportArgs.all { - var list notificationv1.ProviderList - err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace)) - if err != nil { - return err - } - - if len(list.Items) == 0 { - logger.Failuref("no alertproviders found in %s namespace", rootArgs.namespace) - return nil - } - - for _, alertProvider := range list.Items { - if err := exportAlertProvider(alertProvider); err != nil { - return err - } - } - } else { - name := args[0] - namespacedName := types.NamespacedName{ - Namespace: rootArgs.namespace, - Name: name, - } - var alertProvider notificationv1.Provider - err = kubeClient.Get(ctx, namespacedName, &alertProvider) - if err != nil { - return err - } - return exportAlertProvider(alertProvider) - } - return nil -} - -func exportAlertProvider(alertProvider notificationv1.Provider) error { +func exportAlertProvider(alertProvider *notificationv1.Provider) interface{} { gvk := notificationv1.GroupVersion.WithKind("Provider") export := notificationv1.Provider{ TypeMeta: metav1.TypeMeta{ @@ -108,13 +57,13 @@ func exportAlertProvider(alertProvider notificationv1.Provider) error { }, Spec: alertProvider.Spec, } + return export +} - data, err := yaml.Marshal(export) - if err != nil { - return err - } +func (ex alertProviderAdapter) export() interface{} { + return exportAlertProvider(ex.Provider) +} - fmt.Println("---") - fmt.Println(resourceToString(data)) - return nil +func (ex alertProviderListAdapter) exportItem(i int) interface{} { + return exportAlertProvider(&ex.ProviderList.Items[i]) } diff --git a/cmd/flux/export_helmrelease.go b/cmd/flux/export_helmrelease.go index 8266ddc8..fb19b659 100644 --- a/cmd/flux/export_helmrelease.go +++ b/cmd/flux/export_helmrelease.go @@ -17,17 +17,9 @@ limitations under the License. package main import ( - "context" - "fmt" - + helmv2 "github.com/fluxcd/helm-controller/api/v2beta1" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" - - "github.com/fluxcd/flux2/internal/utils" - helmv2 "github.com/fluxcd/helm-controller/api/v2beta1" ) var exportHelmReleaseCmd = &cobra.Command{ @@ -41,60 +33,17 @@ var exportHelmReleaseCmd = &cobra.Command{ # Export a HelmRelease flux export hr my-app > app-release.yaml `, - RunE: exportHelmReleaseCmdRun, + RunE: exportCommand{ + object: helmReleaseAdapter{&helmv2.HelmRelease{}}, + list: helmReleaseListAdapter{&helmv2.HelmReleaseList{}}, + }.run, } func init() { exportCmd.AddCommand(exportHelmReleaseCmd) } -func exportHelmReleaseCmdRun(cmd *cobra.Command, args []string) error { - if !exportArgs.all && len(args) < 1 { - return fmt.Errorf("name is required") - } - - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - if exportArgs.all { - var list helmv2.HelmReleaseList - err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace)) - if err != nil { - return err - } - - if len(list.Items) == 0 { - logger.Failuref("no helmrelease found in %s namespace", rootArgs.namespace) - return nil - } - - for _, helmRelease := range list.Items { - if err := exportHelmRelease(helmRelease); err != nil { - return err - } - } - } else { - name := args[0] - namespacedName := types.NamespacedName{ - Namespace: rootArgs.namespace, - Name: name, - } - var helmRelease helmv2.HelmRelease - err = kubeClient.Get(ctx, namespacedName, &helmRelease) - if err != nil { - return err - } - return exportHelmRelease(helmRelease) - } - return nil -} - -func exportHelmRelease(helmRelease helmv2.HelmRelease) error { +func exportHelmRelease(helmRelease *helmv2.HelmRelease) interface{} { gvk := helmv2.GroupVersion.WithKind(helmv2.HelmReleaseKind) export := helmv2.HelmRelease{ TypeMeta: metav1.TypeMeta{ @@ -109,13 +58,13 @@ func exportHelmRelease(helmRelease helmv2.HelmRelease) error { }, Spec: helmRelease.Spec, } + return export +} - data, err := yaml.Marshal(export) - if err != nil { - return err - } +func (ex helmReleaseAdapter) export() interface{} { + return exportHelmRelease(ex.HelmRelease) +} - fmt.Println("---") - fmt.Println(resourceToString(data)) - return nil +func (ex helmReleaseListAdapter) exportItem(i int) interface{} { + return exportHelmRelease(&ex.HelmReleaseList.Items[i]) } diff --git a/cmd/flux/export_kustomization.go b/cmd/flux/export_kustomization.go index e90002e6..39324443 100644 --- a/cmd/flux/export_kustomization.go +++ b/cmd/flux/export_kustomization.go @@ -17,17 +17,9 @@ limitations under the License. package main import ( - "context" - "fmt" - + kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" - - "github.com/fluxcd/flux2/internal/utils" - kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1" ) var exportKsCmd = &cobra.Command{ @@ -41,60 +33,17 @@ var exportKsCmd = &cobra.Command{ # Export a Kustomization flux export kustomization my-app > kustomization.yaml `, - RunE: exportKsCmdRun, + RunE: exportCommand{ + object: kustomizationAdapter{&kustomizev1.Kustomization{}}, + list: kustomizationListAdapter{&kustomizev1.KustomizationList{}}, + }.run, } func init() { exportCmd.AddCommand(exportKsCmd) } -func exportKsCmdRun(cmd *cobra.Command, args []string) error { - if !exportArgs.all && len(args) < 1 { - return fmt.Errorf("kustomization name is required") - } - - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - if exportArgs.all { - var list kustomizev1.KustomizationList - err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace)) - if err != nil { - return err - } - - if len(list.Items) == 0 { - logger.Failuref("no kustomizations found in %s namespace", rootArgs.namespace) - return nil - } - - for _, kustomization := range list.Items { - if err := exportKs(kustomization); err != nil { - return err - } - } - } else { - name := args[0] - namespacedName := types.NamespacedName{ - Namespace: rootArgs.namespace, - Name: name, - } - var kustomization kustomizev1.Kustomization - err = kubeClient.Get(ctx, namespacedName, &kustomization) - if err != nil { - return err - } - return exportKs(kustomization) - } - return nil -} - -func exportKs(kustomization kustomizev1.Kustomization) error { +func exportKs(kustomization *kustomizev1.Kustomization) interface{} { gvk := kustomizev1.GroupVersion.WithKind("Kustomization") export := kustomizev1.Kustomization{ TypeMeta: metav1.TypeMeta{ @@ -110,12 +59,13 @@ func exportKs(kustomization kustomizev1.Kustomization) error { Spec: kustomization.Spec, } - data, err := yaml.Marshal(export) - if err != nil { - return err - } + return export +} + +func (ex kustomizationAdapter) export() interface{} { + return exportKs(ex.Kustomization) +} - fmt.Println("---") - fmt.Println(resourceToString(data)) - return nil +func (ex kustomizationListAdapter) exportItem(i int) interface{} { + return exportKs(&ex.KustomizationList.Items[i]) } diff --git a/cmd/flux/export_receiver.go b/cmd/flux/export_receiver.go index 700d8756..771ceb58 100644 --- a/cmd/flux/export_receiver.go +++ b/cmd/flux/export_receiver.go @@ -17,17 +17,9 @@ limitations under the License. package main import ( - "context" - "fmt" - + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" - - "github.com/fluxcd/flux2/internal/utils" - notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" ) var exportReceiverCmd = &cobra.Command{ @@ -40,60 +32,17 @@ var exportReceiverCmd = &cobra.Command{ # Export a Receiver flux export receiver main > main.yaml `, - RunE: exportReceiverCmdRun, + RunE: exportCommand{ + list: receiverListAdapter{¬ificationv1.ReceiverList{}}, + object: receiverAdapter{¬ificationv1.Receiver{}}, + }.run, } func init() { exportCmd.AddCommand(exportReceiverCmd) } -func exportReceiverCmdRun(cmd *cobra.Command, args []string) error { - if !exportArgs.all && len(args) < 1 { - return fmt.Errorf("name is required") - } - - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - if exportArgs.all { - var list notificationv1.ReceiverList - err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace)) - if err != nil { - return err - } - - if len(list.Items) == 0 { - logger.Failuref("no receivers found in %s namespace", rootArgs.namespace) - return nil - } - - for _, receiver := range list.Items { - if err := exportReceiver(receiver); err != nil { - return err - } - } - } else { - name := args[0] - namespacedName := types.NamespacedName{ - Namespace: rootArgs.namespace, - Name: name, - } - var receiver notificationv1.Receiver - err = kubeClient.Get(ctx, namespacedName, &receiver) - if err != nil { - return err - } - return exportReceiver(receiver) - } - return nil -} - -func exportReceiver(receiver notificationv1.Receiver) error { +func exportReceiver(receiver *notificationv1.Receiver) interface{} { gvk := notificationv1.GroupVersion.WithKind("Receiver") export := notificationv1.Receiver{ TypeMeta: metav1.TypeMeta{ @@ -109,12 +58,13 @@ func exportReceiver(receiver notificationv1.Receiver) error { Spec: receiver.Spec, } - data, err := yaml.Marshal(export) - if err != nil { - return err - } + return export +} + +func (ex receiverAdapter) export() interface{} { + return exportReceiver(ex.Receiver) +} - fmt.Println("---") - fmt.Println(resourceToString(data)) - return nil +func (ex receiverListAdapter) exportItem(i int) interface{} { + return exportReceiver(&ex.ReceiverList.Items[i]) } diff --git a/cmd/flux/export_secret.go b/cmd/flux/export_secret.go new file mode 100644 index 00000000..ab75a156 --- /dev/null +++ b/cmd/flux/export_secret.go @@ -0,0 +1,133 @@ +/* +Copyright 2021 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "context" + "fmt" + "github.com/fluxcd/flux2/internal/utils" + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// exportableWithSecret represents a type that you can fetch from the Kubernetes +// API, get a secretRef from the spec, then tidy up for serialising. +type exportableWithSecret interface { + adapter + exportable + secret() *types.NamespacedName +} + +// exportableWithSecretList represents a type that has a list of values, each of +// which is exportableWithSecret. +type exportableWithSecretList interface { + listAdapter + exportableList + secretItem(i int) *types.NamespacedName +} + +type exportWithSecretCommand struct { + apiType + object exportableWithSecret + list exportableWithSecretList +} + +func (export exportWithSecretCommand) run(cmd *cobra.Command, args []string) error { + if !exportArgs.all && len(args) < 1 { + return fmt.Errorf("name is required") + } + + ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) + defer cancel() + + kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) + if err != nil { + return err + } + + if exportArgs.all { + err = kubeClient.List(ctx, export.list.asClientList(), client.InNamespace(rootArgs.namespace)) + if err != nil { + return err + } + + if export.list.len() == 0 { + return fmt.Errorf("no objects found in %s namespace", rootArgs.namespace) + } + + for i := 0; i < export.list.len(); i++ { + if err = printExport(export.list.exportItem(i)); err != nil { + return err + } + + if exportSourceWithCred { + if export.list.secretItem(i) != nil { + namespacedName := *export.list.secretItem(i) + return printSecretCredentials(ctx, kubeClient, namespacedName) + } + } + } + } else { + name := args[0] + namespacedName := types.NamespacedName{ + Namespace: rootArgs.namespace, + Name: name, + } + err = kubeClient.Get(ctx, namespacedName, export.object.asClientObject()) + if err != nil { + return err + } + + if err := printExport(export.object.export()); err != nil { + return err + } + + if exportSourceWithCred { + if export.object.secret() != nil { + namespacedName := *export.object.secret() + return printSecretCredentials(ctx, kubeClient, namespacedName) + } + } + + } + return nil +} + +func printSecretCredentials(ctx context.Context, kubeClient client.Client, nsName types.NamespacedName) error { + var cred corev1.Secret + err := kubeClient.Get(ctx, nsName, &cred) + if err != nil { + return fmt.Errorf("failed to retrieve secret %s, error: %w", nsName.Name, err) + } + + exported := corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: nsName.Name, + Namespace: nsName.Namespace, + }, + Data: cred.Data, + Type: cred.Type, + } + return printExport(exported) +} diff --git a/cmd/flux/export_source_bucket.go b/cmd/flux/export_source_bucket.go index 2e0e8cdc..8e8c245b 100644 --- a/cmd/flux/export_source_bucket.go +++ b/cmd/flux/export_source_bucket.go @@ -17,18 +17,10 @@ limitations under the License. package main import ( - "context" - "fmt" - + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" "github.com/spf13/cobra" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" - - "github.com/fluxcd/flux2/internal/utils" - sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" ) var exportSourceBucketCmd = &cobra.Command{ @@ -41,70 +33,17 @@ var exportSourceBucketCmd = &cobra.Command{ # Export a Bucket source including the static credentials flux export source bucket my-bucket --with-credentials > source.yaml `, - RunE: exportSourceBucketCmdRun, + RunE: exportWithSecretCommand{ + list: bucketListAdapter{&sourcev1.BucketList{}}, + object: bucketAdapter{&sourcev1.Bucket{}}, + }.run, } func init() { exportSourceCmd.AddCommand(exportSourceBucketCmd) } -func exportSourceBucketCmdRun(cmd *cobra.Command, args []string) error { - if !exportArgs.all && len(args) < 1 { - return fmt.Errorf("name is required") - } - - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - if exportArgs.all { - var list sourcev1.BucketList - err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace)) - if err != nil { - return err - } - - if len(list.Items) == 0 { - logger.Failuref("no source found in %s namespace", rootArgs.namespace) - return nil - } - - for _, bucket := range list.Items { - if err := exportBucket(bucket); err != nil { - return err - } - if exportSourceWithCred { - if err := exportBucketCredentials(ctx, kubeClient, bucket); err != nil { - return err - } - } - } - } else { - name := args[0] - namespacedName := types.NamespacedName{ - Namespace: rootArgs.namespace, - Name: name, - } - var bucket sourcev1.Bucket - err = kubeClient.Get(ctx, namespacedName, &bucket) - if err != nil { - return err - } - if err := exportBucket(bucket); err != nil { - return err - } - if exportSourceWithCred { - return exportBucketCredentials(ctx, kubeClient, bucket) - } - } - return nil -} - -func exportBucket(source sourcev1.Bucket) error { +func exportBucket(source *sourcev1.Bucket) interface{} { gvk := sourcev1.GroupVersion.WithKind(sourcev1.BucketKind) export := sourcev1.Bucket{ TypeMeta: metav1.TypeMeta{ @@ -119,49 +58,34 @@ func exportBucket(source sourcev1.Bucket) error { }, Spec: source.Spec, } - - data, err := yaml.Marshal(export) - if err != nil { - return err - } - - fmt.Println("---") - fmt.Println(resourceToString(data)) - return nil + return export } -func exportBucketCredentials(ctx context.Context, kubeClient client.Client, source sourcev1.Bucket) error { +func getBucketSecret(source *sourcev1.Bucket) *types.NamespacedName { if source.Spec.SecretRef != nil { namespacedName := types.NamespacedName{ Namespace: source.Namespace, Name: source.Spec.SecretRef.Name, } - var cred corev1.Secret - err := kubeClient.Get(ctx, namespacedName, &cred) - if err != nil { - return fmt.Errorf("failed to retrieve secret %s, error: %w", namespacedName.Name, err) - } - - exported := corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: namespacedName.Name, - Namespace: namespacedName.Namespace, - }, - Data: cred.Data, - Type: cred.Type, - } - - data, err := yaml.Marshal(exported) - if err != nil { - return err - } - fmt.Println("---") - fmt.Println(resourceToString(data)) + return &namespacedName } + return nil } + +func (ex bucketAdapter) secret() *types.NamespacedName { + return getBucketSecret(ex.Bucket) +} + +func (ex bucketListAdapter) secretItem(i int) *types.NamespacedName { + return getBucketSecret(&ex.BucketList.Items[i]) +} + +func (ex bucketAdapter) export() interface{} { + return exportBucket(ex.Bucket) +} + +func (ex bucketListAdapter) exportItem(i int) interface{} { + return exportBucket(&ex.BucketList.Items[i]) +} diff --git a/cmd/flux/export_source_git.go b/cmd/flux/export_source_git.go index e8062fac..ebe2352d 100644 --- a/cmd/flux/export_source_git.go +++ b/cmd/flux/export_source_git.go @@ -17,18 +17,10 @@ limitations under the License. package main import ( - "context" - "fmt" - + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" "github.com/spf13/cobra" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" - - "github.com/fluxcd/flux2/internal/utils" - sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" ) var exportSourceGitCmd = &cobra.Command{ @@ -41,70 +33,17 @@ var exportSourceGitCmd = &cobra.Command{ # Export a GitRepository source including the SSH key pair or basic auth credentials flux export source git my-private-repo --with-credentials > source.yaml `, - RunE: exportSourceGitCmdRun, + RunE: exportWithSecretCommand{ + object: gitRepositoryAdapter{&sourcev1.GitRepository{}}, + list: gitRepositoryListAdapter{&sourcev1.GitRepositoryList{}}, + }.run, } func init() { exportSourceCmd.AddCommand(exportSourceGitCmd) } -func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error { - if !exportArgs.all && len(args) < 1 { - return fmt.Errorf("name is required") - } - - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - if exportArgs.all { - var list sourcev1.GitRepositoryList - err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace)) - if err != nil { - return err - } - - if len(list.Items) == 0 { - logger.Failuref("no source found in %s namespace", rootArgs.namespace) - return nil - } - - for _, repository := range list.Items { - if err := exportGit(repository); err != nil { - return err - } - if exportSourceWithCred { - if err := exportGitCredentials(ctx, kubeClient, repository); err != nil { - return err - } - } - } - } else { - name := args[0] - namespacedName := types.NamespacedName{ - Namespace: rootArgs.namespace, - Name: name, - } - var repository sourcev1.GitRepository - err = kubeClient.Get(ctx, namespacedName, &repository) - if err != nil { - return err - } - if err := exportGit(repository); err != nil { - return err - } - if exportSourceWithCred { - return exportGitCredentials(ctx, kubeClient, repository) - } - } - return nil -} - -func exportGit(source sourcev1.GitRepository) error { +func exportGit(source *sourcev1.GitRepository) interface{} { gvk := sourcev1.GroupVersion.WithKind(sourcev1.GitRepositoryKind) export := sourcev1.GitRepository{ TypeMeta: metav1.TypeMeta{ @@ -120,48 +59,33 @@ func exportGit(source sourcev1.GitRepository) error { Spec: source.Spec, } - data, err := yaml.Marshal(export) - if err != nil { - return err - } - - fmt.Println("---") - fmt.Println(resourceToString(data)) - return nil + return export } -func exportGitCredentials(ctx context.Context, kubeClient client.Client, source sourcev1.GitRepository) error { +func getGitSecret(source *sourcev1.GitRepository) *types.NamespacedName { if source.Spec.SecretRef != nil { namespacedName := types.NamespacedName{ Namespace: source.Namespace, Name: source.Spec.SecretRef.Name, } - var cred corev1.Secret - err := kubeClient.Get(ctx, namespacedName, &cred) - if err != nil { - return fmt.Errorf("failed to retrieve secret %s, error: %w", namespacedName.Name, err) - } + return &namespacedName + } - exported := corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: namespacedName.Name, - Namespace: namespacedName.Namespace, - }, - Data: cred.Data, - Type: cred.Type, - } + return nil +} - data, err := yaml.Marshal(exported) - if err != nil { - return err - } +func (ex gitRepositoryAdapter) secret() *types.NamespacedName { + return getGitSecret(ex.GitRepository) +} - fmt.Println("---") - fmt.Println(resourceToString(data)) - } - return nil +func (ex gitRepositoryListAdapter) secretItem(i int) *types.NamespacedName { + return getGitSecret(&ex.GitRepositoryList.Items[i]) +} + +func (ex gitRepositoryAdapter) export() interface{} { + return exportGit(ex.GitRepository) +} + +func (ex gitRepositoryListAdapter) exportItem(i int) interface{} { + return exportGit(&ex.GitRepositoryList.Items[i]) } diff --git a/cmd/flux/export_source_helm.go b/cmd/flux/export_source_helm.go index e8e51f93..53f79ae7 100644 --- a/cmd/flux/export_source_helm.go +++ b/cmd/flux/export_source_helm.go @@ -17,18 +17,10 @@ limitations under the License. package main import ( - "context" - "fmt" - + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" "github.com/spf13/cobra" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" - - "github.com/fluxcd/flux2/internal/utils" - sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" ) var exportSourceHelmCmd = &cobra.Command{ @@ -41,70 +33,17 @@ var exportSourceHelmCmd = &cobra.Command{ # Export a HelmRepository source including the basic auth credentials flux export source helm my-private-repo --with-credentials > source.yaml `, - RunE: exportSourceHelmCmdRun, + RunE: exportWithSecretCommand{ + list: helmRepositoryListAdapter{&sourcev1.HelmRepositoryList{}}, + object: helmRepositoryAdapter{&sourcev1.HelmRepository{}}, + }.run, } func init() { exportSourceCmd.AddCommand(exportSourceHelmCmd) } -func exportSourceHelmCmdRun(cmd *cobra.Command, args []string) error { - if !exportArgs.all && len(args) < 1 { - return fmt.Errorf("name is required") - } - - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - if exportArgs.all { - var list sourcev1.HelmRepositoryList - err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace)) - if err != nil { - return err - } - - if len(list.Items) == 0 { - logger.Failuref("no source found in %s namespace", rootArgs.namespace) - return nil - } - - for _, repository := range list.Items { - if err := exportHelmRepository(repository); err != nil { - return err - } - if exportSourceWithCred { - if err := exportHelmCredentials(ctx, kubeClient, repository); err != nil { - return err - } - } - } - } else { - name := args[0] - namespacedName := types.NamespacedName{ - Namespace: rootArgs.namespace, - Name: name, - } - var repository sourcev1.HelmRepository - err = kubeClient.Get(ctx, namespacedName, &repository) - if err != nil { - return err - } - if err := exportHelmRepository(repository); err != nil { - return err - } - if exportSourceWithCred { - return exportHelmCredentials(ctx, kubeClient, repository) - } - } - return nil -} - -func exportHelmRepository(source sourcev1.HelmRepository) error { +func exportHelmRepository(source *sourcev1.HelmRepository) interface{} { gvk := sourcev1.GroupVersion.WithKind(sourcev1.HelmRepositoryKind) export := sourcev1.HelmRepository{ TypeMeta: metav1.TypeMeta{ @@ -119,49 +58,32 @@ func exportHelmRepository(source sourcev1.HelmRepository) error { }, Spec: source.Spec, } - - data, err := yaml.Marshal(export) - if err != nil { - return err - } - - fmt.Println("---") - fmt.Println(resourceToString(data)) - return nil + return export } -func exportHelmCredentials(ctx context.Context, kubeClient client.Client, source sourcev1.HelmRepository) error { +func getHelmSecret(source *sourcev1.HelmRepository) *types.NamespacedName { if source.Spec.SecretRef != nil { namespacedName := types.NamespacedName{ Namespace: source.Namespace, Name: source.Spec.SecretRef.Name, } - var cred corev1.Secret - err := kubeClient.Get(ctx, namespacedName, &cred) - if err != nil { - return fmt.Errorf("failed to retrieve secret %s, error: %w", namespacedName.Name, err) - } + return &namespacedName + } + return nil +} - exported := corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: namespacedName.Name, - Namespace: namespacedName.Namespace, - }, - Data: cred.Data, - Type: cred.Type, - } +func (ex helmRepositoryAdapter) secret() *types.NamespacedName { + return getHelmSecret(ex.HelmRepository) +} - data, err := yaml.Marshal(exported) - if err != nil { - return err - } +func (ex helmRepositoryListAdapter) secretItem(i int) *types.NamespacedName { + return getHelmSecret(&ex.HelmRepositoryList.Items[i]) +} - fmt.Println("---") - fmt.Println(resourceToString(data)) - } - return nil +func (ex helmRepositoryAdapter) export() interface{} { + return exportHelmRepository(ex.HelmRepository) +} + +func (ex helmRepositoryListAdapter) exportItem(i int) interface{} { + return exportHelmRepository(&ex.HelmRepositoryList.Items[i]) } diff --git a/cmd/flux/get_alert.go b/cmd/flux/get_alert.go index 5d4ab78d..e6c4a615 100644 --- a/cmd/flux/get_alert.go +++ b/cmd/flux/get_alert.go @@ -17,19 +17,11 @@ limitations under the License. package main import ( - "context" - "os" "strconv" "strings" - "github.com/spf13/cobra" - apimeta "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/fluxcd/flux2/internal/utils" notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" - "github.com/fluxcd/pkg/apis/meta" + "github.com/spf13/cobra" ) var getAlertCmd = &cobra.Command{ @@ -40,64 +32,26 @@ var getAlertCmd = &cobra.Command{ Example: ` # List all Alerts and their status flux get alerts `, - RunE: getAlertCmdRun, + RunE: getCommand{ + apiType: alertType, + list: &alertListAdapter{¬ificationv1.AlertList{}}, + }.run, } func init() { getCmd.AddCommand(getAlertCmd) } -func getAlertCmdRun(cmd *cobra.Command, args []string) error { - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - var listOpts []client.ListOption - if !getArgs.allNamespaces { - listOpts = append(listOpts, client.InNamespace(rootArgs.namespace)) - } - var list notificationv1.AlertList - err = kubeClient.List(ctx, &list, listOpts...) - if err != nil { - return err - } - - if len(list.Items) == 0 { - logger.Failuref("no alerts found in %s namespace", rootArgs.namespace) - return nil - } +func (s alertListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string { + item := s.Items[i] + status, msg := statusAndMessage(item.Status.Conditions) + return append(nameColumns(&item, includeNamespace, includeKind), status, msg, strings.Title(strconv.FormatBool(item.Spec.Suspend))) +} - header := []string{"Name", "Ready", "Message", "Suspended"} - if getArgs.allNamespaces { - header = append([]string{"Namespace"}, header...) - } - var rows [][]string - for _, alert := range list.Items { - row := []string{} - if c := apimeta.FindStatusCondition(alert.Status.Conditions, meta.ReadyCondition); c != nil { - row = []string{ - alert.GetName(), - string(c.Status), - c.Message, - strings.Title(strconv.FormatBool(alert.Spec.Suspend)), - } - } else { - row = []string{ - alert.GetName(), - string(metav1.ConditionFalse), - "waiting to be reconciled", - strings.Title(strconv.FormatBool(alert.Spec.Suspend)), - } - } - if getArgs.allNamespaces { - row = append([]string{alert.Namespace}, row...) - } - rows = append(rows, row) +func (s alertListAdapter) headers(includeNamespace bool) []string { + headers := []string{"Name", "Ready", "Message", "Suspended"} + if includeNamespace { + return append(namespaceHeader, headers...) } - utils.PrintTable(os.Stdout, header, rows) - return nil + return headers } diff --git a/cmd/flux/get_alertprovider.go b/cmd/flux/get_alertprovider.go index 3cf58e3c..f0c5b8fe 100644 --- a/cmd/flux/get_alertprovider.go +++ b/cmd/flux/get_alertprovider.go @@ -17,17 +17,8 @@ limitations under the License. package main import ( - "context" - "os" - - "github.com/spf13/cobra" - apimeta "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/fluxcd/flux2/internal/utils" notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" - "github.com/fluxcd/pkg/apis/meta" + "github.com/spf13/cobra" ) var getAlertProviderCmd = &cobra.Command{ @@ -38,62 +29,26 @@ var getAlertProviderCmd = &cobra.Command{ Example: ` # List all Providers and their status flux get alert-providers `, - RunE: getAlertProviderCmdRun, + RunE: getCommand{ + apiType: alertProviderType, + list: alertProviderListAdapter{¬ificationv1.ProviderList{}}, + }.run, } func init() { getCmd.AddCommand(getAlertProviderCmd) } -func getAlertProviderCmdRun(cmd *cobra.Command, args []string) error { - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - var listOpts []client.ListOption - if !getArgs.allNamespaces { - listOpts = append(listOpts, client.InNamespace(rootArgs.namespace)) - } - var list notificationv1.ProviderList - err = kubeClient.List(ctx, &list, listOpts...) - if err != nil { - return err - } - - if len(list.Items) == 0 { - logger.Failuref("no providers found in %s namespace", rootArgs.namespace) - return nil - } +func (s alertProviderListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string { + item := s.Items[i] + status, msg := statusAndMessage(item.Status.Conditions) + return append(nameColumns(&item, includeNamespace, includeKind), status, msg) +} - header := []string{"Name", "Ready", "Message"} - if getArgs.allNamespaces { - header = append([]string{"Namespace"}, header...) - } - var rows [][]string - for _, provider := range list.Items { - row := []string{} - if c := apimeta.FindStatusCondition(provider.Status.Conditions, meta.ReadyCondition); c != nil { - row = []string{ - provider.GetName(), - string(c.Status), - c.Message, - } - } else { - row = []string{ - provider.GetName(), - string(metav1.ConditionFalse), - "waiting to be reconciled", - } - } - if getArgs.allNamespaces { - row = append([]string{provider.Namespace}, row...) - } - rows = append(rows, row) +func (s alertProviderListAdapter) headers(includeNamespace bool) []string { + headers := []string{"Name", "Ready", "Message"} + if includeNamespace { + return append(namespaceHeader, headers...) } - utils.PrintTable(os.Stdout, header, rows) - return nil + return headers } diff --git a/cmd/flux/get_receiver.go b/cmd/flux/get_receiver.go index 422bb8dd..d58ced0c 100644 --- a/cmd/flux/get_receiver.go +++ b/cmd/flux/get_receiver.go @@ -17,19 +17,11 @@ limitations under the License. package main import ( - "context" - "os" "strconv" "strings" - "github.com/spf13/cobra" - apimeta "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/fluxcd/flux2/internal/utils" notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" - "github.com/fluxcd/pkg/apis/meta" + "github.com/spf13/cobra" ) var getReceiverCmd = &cobra.Command{ @@ -40,61 +32,26 @@ var getReceiverCmd = &cobra.Command{ Example: ` # List all Receiver and their status flux get receivers `, - RunE: getReceiverCmdRun, + RunE: getCommand{ + apiType: receiverType, + list: receiverListAdapter{¬ificationv1.ReceiverList{}}, + }.run, } func init() { getCmd.AddCommand(getReceiverCmd) } -func getReceiverCmdRun(cmd *cobra.Command, args []string) error { - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - - kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) - if err != nil { - return err - } - - var listOpts []client.ListOption - if !getArgs.allNamespaces { - listOpts = append(listOpts, client.InNamespace(rootArgs.namespace)) - } - var list notificationv1.ReceiverList - err = kubeClient.List(ctx, &list, listOpts...) - if err != nil { - return err - } - - if len(list.Items) == 0 { - logger.Failuref("no receivers found in %s namespace", rootArgs.namespace) - return nil - } +func (s receiverListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string { + item := s.Items[i] + status, msg := statusAndMessage(item.Status.Conditions) + return append(nameColumns(&item, includeNamespace, includeKind), status, msg, strings.Title(strconv.FormatBool(item.Spec.Suspend))) +} - header := []string{"Name", "Ready", "Message", "Suspended"} - if getArgs.allNamespaces { - header = append([]string{"Namespace"}, header...) - } - var rows [][]string - for _, receiver := range list.Items { - var row []string - if c := apimeta.FindStatusCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil { - row = []string{ - receiver.GetName(), - string(c.Status), - c.Message, - strings.Title(strconv.FormatBool(receiver.Spec.Suspend)), - } - } else { - row = []string{ - receiver.GetName(), - string(metav1.ConditionFalse), - "waiting to be reconciled", - strings.Title(strconv.FormatBool(receiver.Spec.Suspend)), - } - } - rows = append(rows, row) +func (s receiverListAdapter) headers(includeNamespace bool) []string { + headers := []string{"Name", "Ready", "Message", "Suspended"} + if includeNamespace { + return append(namespaceHeader, headers...) } - utils.PrintTable(os.Stdout, header, rows) - return nil + return headers } diff --git a/cmd/flux/receiver.go b/cmd/flux/receiver.go new file mode 100644 index 00000000..3de4cbb3 --- /dev/null +++ b/cmd/flux/receiver.go @@ -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 ( + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// notificationv1.Receiver + +var receiverType = apiType{ + kind: notificationv1.ReceiverKind, + humanKind: "receiver", +} + +type receiverAdapter struct { + *notificationv1.Receiver +} + +func (a receiverAdapter) asClientObject() client.Object { + return a.Receiver +} + +// notificationv1.Receiver + +type receiverListAdapter struct { + *notificationv1.ReceiverList +} + +func (a receiverListAdapter) asClientList() client.ObjectList { + return a.ReceiverList +} + +func (a receiverListAdapter) len() int { + return len(a.ReceiverList.Items) +}