From f4ac782e950599540c7af161ef98b1687050ba2e Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 1 Oct 2024 09:18:58 -0600 Subject: [PATCH] feat: kubeconfig path flag (#329) * feat: kubeconfig path flag * fix: GetConfig comment --------- Co-authored-by: Andy Suderman --- cmd/root.go | 27 +++++++++++++++++---------- pkg/containers/images.go | 4 ++-- pkg/helm/cluster.go | 4 ++-- pkg/kube/kube.go | 40 ++++++++++++++++++++++++++++++---------- 4 files changed, 51 insertions(+), 24 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index e795870..9429f62 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -97,6 +97,12 @@ func init() { klog.Exitf("Failed to bind context flag: %v", err) } + rootCmd.PersistentFlags().String("kubeconfig", "", "A path to a kubeconfig file.") + err = viper.BindPFlag("kubeconfig", rootCmd.PersistentFlags().Lookup("kubeconfig")) + if err != nil { + klog.Exitf("Failed to bind kubeconfig flag: %v", err) + } + rootCmd.PersistentFlags().Bool("wide", false, "Output chart name and namespace") err = viper.BindPFlag("wide", rootCmd.PersistentFlags().Lookup("wide")) if err != nil { @@ -252,6 +258,7 @@ var findCmd = &cobra.Command{ klog.V(5).Infof("All Keys: %v", viper.AllKeys()) kubeContext := viper.GetString("context") + kubeConfigPath := viper.GetString("kubeconfig") format := viper.GetString("format") if !(format == output.TableFormat || format == output.JSONFormat) { @@ -259,7 +266,7 @@ var findCmd = &cobra.Command{ } if viper.GetBool("helm") && viper.GetBool("containers") { - output, err := handleHelmAndContainers(kubeContext) + output, err := handleHelmAndContainers(kubeContext, kubeConfigPath) if err != nil { klog.Exit(err) } @@ -276,7 +283,7 @@ var findCmd = &cobra.Command{ } if viper.GetBool("containers") { - output, err := handleContainers(kubeContext) + output, err := handleContainers(kubeContext, kubeConfigPath) if err != nil { klog.Exit(err) } @@ -284,7 +291,7 @@ var findCmd = &cobra.Command{ return } - output, err := handleHelm(kubeContext) + output, err := handleHelm(kubeContext, kubeConfigPath) if err != nil { klog.Exit(err) } @@ -321,7 +328,7 @@ func Execute(VERSION, COMMIT string) { } } -func handleContainers(kubeContext string) (*output.ContainersOutput, error) { +func handleContainers(kubeContext, kubeConfigPath string) (*output.ContainersOutput, error) { // Set up a context we can use to cancel all operations to external container registries if we need to timeout := time.Duration(viper.GetUint16("timeout")) * time.Second ctx, cancel := context.WithTimeout(context.Background(), timeout) @@ -339,7 +346,7 @@ func handleContainers(kubeContext string) (*output.ContainersOutput, error) { case <-ctx.Done(): } }() - iClient := containers.NewClient(kubeContext) + iClient := containers.NewClient(kubeContext, kubeConfigPath) namespace := viper.GetString("namespace") if viper.IsSet("namespace") { klog.V(3).Infof("Scanning namespace %v", namespace) @@ -356,8 +363,8 @@ func handleContainers(kubeContext string) (*output.ContainersOutput, error) { return output.NewContainersOutput(containers.Images, containers.ErrImages, showNonSemver, showErrored, includeAll), nil } -func handleHelm(kubeContext string) (*output.Output, error) { - h := nova_helm.NewHelm(kubeContext) +func handleHelm(kubeContext, kubeConfigPath string) (*output.Output, error) { + h := nova_helm.NewHelm(kubeContext, kubeConfigPath) if viper.IsSet("desired-versions") { klog.V(3).Infof("desired-versions is set - attempting to load them") klog.V(8).Infof("raw desired-versions: %v", viper.Get("desired-versions")) @@ -412,12 +419,12 @@ func handleHelm(kubeContext string) (*output.Output, error) { return &out, nil } -func handleHelmAndContainers(kubeContext string) (*output.HelmAndContainersOutput, error) { - helmOutput, err := handleHelm(kubeContext) +func handleHelmAndContainers(kubeContext, kubeConfigPath string) (*output.HelmAndContainersOutput, error) { + helmOutput, err := handleHelm(kubeContext, kubeConfigPath) if err != nil { return nil, err } - containersOutput, err := handleContainers(kubeContext) + containersOutput, err := handleContainers(kubeContext, kubeConfigPath) if err != nil { return nil, err } diff --git a/pkg/containers/images.go b/pkg/containers/images.go index dbe32cf..0f38ca0 100644 --- a/pkg/containers/images.go +++ b/pkg/containers/images.go @@ -93,9 +93,9 @@ type Tag struct { } // NewClient is a constructor to create a new Client -func NewClient(kubeContext string) *Client { +func NewClient(kubeContext, kubeConfigPath string) *Client { return &Client{ - Kube: kube.GetConfigInstance(kubeContext), + Kube: kube.GetConfigInstance(kubeContext, kubeConfigPath), } } diff --git a/pkg/helm/cluster.go b/pkg/helm/cluster.go index e68011c..cb2f783 100644 --- a/pkg/helm/cluster.go +++ b/pkg/helm/cluster.go @@ -39,9 +39,9 @@ type DesiredVersion struct { } // NewHelm returns a basic helm struct with the version of helm requested -func NewHelm(kubeContext string) *Helm { +func NewHelm(kubeContext, kubeConfigPath string) *Helm { return &Helm{ - Kube: kube.GetConfigInstance(kubeContext), + Kube: kube.GetConfigInstance(kubeContext, kubeConfigPath), } } diff --git a/pkg/kube/kube.go b/pkg/kube/kube.go index ed5bda9..0d685a5 100644 --- a/pkg/kube/kube.go +++ b/pkg/kube/kube.go @@ -15,6 +15,7 @@ package kube import ( + "flag" "sync" "k8s.io/apimachinery/pkg/api/meta" @@ -45,19 +46,38 @@ var ( ) // GetConfigInstance returns a Kubernetes interface based on the current configuration -func GetConfigInstance(context string) *Connection { +func GetConfigInstance(context, kubeConfigPath string) *Connection { once.Do(func() { kubeClient = &Connection{ - Client: getKubeClient(context), - DynamicClient: getDynamicKubeClient(context), - RESTMapper: getRESTMapper(context), + Client: getKubeClient(context, kubeConfigPath), + DynamicClient: getDynamicKubeClient(context, kubeConfigPath), + RESTMapper: getRESTMapper(context, kubeConfigPath), } }) return kubeClient } -func getKubeClient(context string) kubernetes.Interface { - kubeConf, err := config.GetConfigWithContext(context) +// GetConfig returns a *rest.Config based on the current configuration +func GetConfig(context, kubeConfigPath string) (*rest.Config, error) { + + if context != "" { + klog.V(3).Infof("using kube context: %s", context) + } + + fs := flag.NewFlagSet("fs", flag.ContinueOnError) + fs.String("kubeconfig", kubeConfigPath, "") + config.RegisterFlags(fs) + + kubeConfig, err := config.GetConfigWithContext(context) + if err != nil { + return nil, err + } + + return kubeConfig, nil +} + +func getKubeClient(context, kubeConfigPath string) kubernetes.Interface { + kubeConf, err := GetConfig(context, kubeConfigPath) if err != nil { klog.Fatalf("error getting config with context %s: %v", context, err) } @@ -69,8 +89,8 @@ func getKubeClient(context string) kubernetes.Interface { return clientset } -func getDynamicKubeClient(context string) dynamic.Interface { - kubeConf, err := config.GetConfigWithContext(context) +func getDynamicKubeClient(context, kubeConfigPath string) dynamic.Interface { + kubeConf, err := GetConfig(context, kubeConfigPath) if err != nil { klog.Fatalf("error getting config with context %s: %v", context, err) } @@ -81,8 +101,8 @@ func getDynamicKubeClient(context string) dynamic.Interface { return dynamicClient } -func getRESTMapper(context string) meta.RESTMapper { - kubeConf, err := config.GetConfigWithContext(context) +func getRESTMapper(context, kubeConfigPath string) meta.RESTMapper { + kubeConf, err := GetConfig(context, kubeConfigPath) if err != nil { klog.Fatalf("error getting config with context %s: %v", context, err) }