From c91851a52163b08693a3e1e4bbdb4bdf0e6a9b1c Mon Sep 17 00:00:00 2001 From: "Dom @ DellEMC" Date: Tue, 26 Nov 2024 08:48:58 -0500 Subject: [PATCH] add: Allow config and pre-processed configuration to leverage environment variables ($K3D_CONFIG env var) (#1446) --- cmd/cluster/clusterCreate.go | 11 ++--- cmd/cluster/clusterDelete.go | 87 ++++++++++++++++++++---------------- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/cmd/cluster/clusterCreate.go b/cmd/cluster/clusterCreate.go index 8fbd28fa9..bd11b408c 100644 --- a/cmd/cluster/clusterCreate.go +++ b/cmd/cluster/clusterCreate.go @@ -47,8 +47,6 @@ import ( "github.com/k3d-io/k3d/v5/version" ) -var configFile string - const clusterCreateDescription = ` Create a new k3s cluster with containerized nodes (k3s in docker). Every cluster will consist of one or more containers: @@ -72,13 +70,15 @@ var ( func initConfig() error { // Viper for pre-processed config options ppViper.SetEnvPrefix("K3D") + ppViper.AutomaticEnv() + ppViper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) if l.Log().GetLevel() >= logrus.DebugLevel { c, _ := yaml.Marshal(ppViper.AllSettings()) l.Log().Debugf("Additional CLI Configuration:\n%s", c) } - return cliconfig.InitViperWithConfigFile(cfgViper, configFile) + return cliconfig.InitViperWithConfigFile(cfgViper, ppViper.GetString("config")) } // NewCmdClusterCreate returns a new cobra command @@ -123,7 +123,7 @@ func NewCmdClusterCreate() *cobra.Command { l.Log().Fatalf("error processing/sanitizing simple config: %v", err) } - clusterConfig, err := config.TransformSimpleToClusterConfig(cmd.Context(), runtimes.SelectedRuntime, simpleCfg, configFile) + clusterConfig, err := config.TransformSimpleToClusterConfig(cmd.Context(), runtimes.SelectedRuntime, simpleCfg, ppViper.GetString("config")) if err != nil { l.Log().Fatalln(err) } @@ -208,7 +208,8 @@ func NewCmdClusterCreate() *cobra.Command { * Config File * ***************/ - cmd.Flags().StringVarP(&configFile, "config", "c", "", "Path of a config file to use") + cmd.Flags().StringP("config", "c", "", "Path of a config file to use") + _ = ppViper.BindPFlag("config", cmd.Flags().Lookup("config")) if err := cmd.MarkFlagFilename("config", "yaml", "yml"); err != nil { l.Log().Fatalln("Failed to mark flag 'config' as filename flag") } diff --git a/cmd/cluster/clusterDelete.go b/cmd/cluster/clusterDelete.go index 07f6c57d1..847516bd9 100644 --- a/cmd/cluster/clusterDelete.go +++ b/cmd/cluster/clusterDelete.go @@ -22,10 +22,12 @@ THE SOFTWARE. package cluster import ( + "context" "errors" "fmt" "os" "path" + "strings" "github.com/k3d-io/k3d/v5/cmd/util" cliconfig "github.com/k3d-io/k3d/v5/cmd/util/config" @@ -35,13 +37,31 @@ import ( "github.com/k3d-io/k3d/v5/pkg/runtimes" k3d "github.com/k3d-io/k3d/v5/pkg/types" k3dutil "github.com/k3d-io/k3d/v5/pkg/util" + "github.com/sirupsen/logrus" + "sigs.k8s.io/yaml" "github.com/spf13/cobra" "github.com/spf13/viper" ) -var clusterDeleteConfigFile string -var clusterDeleteCfgViper = viper.New() +var ( + clusterDeleteCfgViper = viper.New() + clusterDeletePpViper = viper.New() +) + +func initClusterDeleteConfig() error { + // Viper for pre-processed config options + clusterDeletePpViper.SetEnvPrefix("K3D") + clusterDeletePpViper.AutomaticEnv() + clusterDeletePpViper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + + if l.Log().GetLevel() >= logrus.DebugLevel { + c, _ := yaml.Marshal(clusterDeletePpViper.AllSettings()) + l.Log().Debugf("Additional CLI Configuration:\n%s", c) + } + + return cliconfig.InitViperWithConfigFile(clusterDeleteCfgViper, clusterDeletePpViper.GetString("config")) +} // NewCmdClusterDelete returns a new cobra command func NewCmdClusterDelete() *cobra.Command { @@ -54,7 +74,7 @@ func NewCmdClusterDelete() *cobra.Command { Args: cobra.MinimumNArgs(0), // 0 or n arguments; 0 = default cluster name ValidArgsFunction: util.ValidArgsAvailableClusters, PreRunE: func(cmd *cobra.Command, args []string) error { - return cliconfig.InitViperWithConfigFile(clusterDeleteCfgViper, clusterDeleteConfigFile) + return initClusterDeleteConfig() }, Run: func(cmd *cobra.Command, args []string) { clusters := parseDeleteClusterCmd(cmd, args) @@ -99,7 +119,8 @@ func NewCmdClusterDelete() *cobra.Command { * Config File * ***************/ - cmd.Flags().StringVarP(&clusterDeleteConfigFile, "config", "c", "", "Path of a config file to use") + cmd.Flags().StringP("config", "c", "", "Path of a config file to use") + _ = clusterDeletePpViper.BindPFlag("config", cmd.Flags().Lookup("config")) if err := cmd.MarkFlagFilename("config", "yaml", "yml"); err != nil { l.Log().Fatalln("Failed to mark flag 'config' as filename flag") } @@ -110,66 +131,54 @@ func NewCmdClusterDelete() *cobra.Command { // parseDeleteClusterCmd parses the command input into variables required to delete clusters func parseDeleteClusterCmd(cmd *cobra.Command, args []string) []*k3d.Cluster { - var clusters []*k3d.Cluster - // --all all, err := cmd.Flags().GetBool("all") if err != nil { l.Log().Fatalln(err) } - // --config - if clusterDeleteConfigFile != "" { - // not allowed with --all or more args - if len(args) > 0 || all { - l.Log().Fatalln("failed to delete cluster: cannot use `--config` flag with additional arguments or `--all`") - } - - cfg, err := config.SimpleConfigFromViper(clusterDeleteCfgViper) - if err != nil { - l.Log().Fatalln(err) - } - - if cfg.Name == "" { - l.Log().Fatalln("failed to delete cluster via config file: no name in config file") - } - - c, err := client.ClusterGet(cmd.Context(), runtimes.SelectedRuntime, &k3d.Cluster{Name: cfg.Name}) - if errors.Is(err, client.ClusterGetNoNodesFoundError) { - l.Log().Infof("No nodes found for cluster '%s', nothing to delete.", cfg.Name) - return nil - } - - clusters = append(clusters, c) - return clusters - } - // --all was set if all { l.Log().Infoln("Deleting all clusters...") - clusters, err = client.ClusterList(cmd.Context(), runtimes.SelectedRuntime) + clusters, err := client.ClusterList(cmd.Context(), runtimes.SelectedRuntime) if err != nil { l.Log().Fatalln(err) } return clusters } - // args only - clusternames := []string{k3d.DefaultClusterName} + // args if len(args) != 0 { - clusternames = args + return getClusters(cmd.Context(), args...) + } + + // --config + if clusterDeletePpViper.GetString("config") != "" { + cfg, err := config.SimpleConfigFromViper(clusterDeleteCfgViper) + if err != nil { + l.Log().Fatalln(err) + } + if cfg.Name != "" { + return getClusters(cmd.Context(), cfg.Name) + } } + // default + return getClusters(cmd.Context(), k3d.DefaultClusterName) +} + +func getClusters(ctx context.Context, clusternames ...string) []*k3d.Cluster { + var clusters []*k3d.Cluster for _, name := range clusternames { - c, err := client.ClusterGet(cmd.Context(), runtimes.SelectedRuntime, &k3d.Cluster{Name: name}) + c, err := client.ClusterGet(ctx, runtimes.SelectedRuntime, &k3d.Cluster{Name: name}) if err != nil { - if err == client.ClusterGetNoNodesFoundError { + if errors.Is(err, client.ClusterGetNoNodesFoundError) { + l.Log().Infof("No nodes found for cluster '%s', nothing to delete.", name) continue } l.Log().Fatalln(err) } clusters = append(clusters, c) } - return clusters }