fix(pkg/cli): ensure correct configuration from kubeconfig file

Bind Helm flags to Kubernetes configuration loader to get a merged
config with kubeconfig.

Fixes: #7539

Signed-off-by: Adam Reese <adam@reese.io>
pull/7982/head
Adam Reese 5 years ago
parent 9ced0165ab
commit 4a0dfbe53b
No known key found for this signature in database
GPG Key ID: 06F35E60A7A18DD6

@ -43,9 +43,7 @@ import (
// FeatureGateOCI is the feature gate for checking if `helm chart` and `helm registry` commands should work // FeatureGateOCI is the feature gate for checking if `helm chart` and `helm registry` commands should work
const FeatureGateOCI = gates.Gate("HELM_EXPERIMENTAL_OCI") const FeatureGateOCI = gates.Gate("HELM_EXPERIMENTAL_OCI")
var ( var settings = cli.New()
settings = cli.New()
)
func init() { func init() {
log.SetFlags(log.Lshortfile) log.SetFlags(log.Lshortfile)
@ -72,13 +70,16 @@ func main() {
actionConfig := new(action.Configuration) actionConfig := new(action.Configuration)
cmd := newRootCmd(actionConfig, os.Stdout, os.Args[1:]) cmd := newRootCmd(actionConfig, os.Stdout, os.Args[1:])
helmDriver := os.Getenv("HELM_DRIVER") // run when each command's execute method is called
if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), helmDriver, debug); err != nil { cobra.OnInitialize(func() {
log.Fatal(err) helmDriver := os.Getenv("HELM_DRIVER")
} if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), helmDriver, debug); err != nil {
if helmDriver == "memory" { log.Fatal(err)
loadReleasesInMemory(actionConfig) }
} if helmDriver == "memory" {
loadReleasesInMemory(actionConfig)
}
})
if err := cmd.Execute(); err != nil { if err := cmd.Execute(); err != nil {
debug("%+v", err) debug("%+v", err)

@ -26,21 +26,17 @@ import (
"fmt" "fmt"
"os" "os"
"strconv" "strconv"
"sync"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/genericclioptions"
"helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v3/pkg/helmpath"
"helm.sh/helm/v3/pkg/kube"
) )
// EnvSettings describes all of the environment settings. // EnvSettings describes all of the environment settings.
type EnvSettings struct { type EnvSettings struct {
namespace string namespace string
config genericclioptions.RESTClientGetter config *genericclioptions.ConfigFlags
configOnce sync.Once
// KubeConfig is the path to the kubeconfig file // KubeConfig is the path to the kubeconfig file
KubeConfig string KubeConfig string
@ -63,8 +59,7 @@ type EnvSettings struct {
} }
func New() *EnvSettings { func New() *EnvSettings {
env := &EnvSettings{
env := EnvSettings{
namespace: os.Getenv("HELM_NAMESPACE"), namespace: os.Getenv("HELM_NAMESPACE"),
KubeContext: os.Getenv("HELM_KUBECONTEXT"), KubeContext: os.Getenv("HELM_KUBECONTEXT"),
KubeToken: os.Getenv("HELM_KUBETOKEN"), KubeToken: os.Getenv("HELM_KUBETOKEN"),
@ -75,7 +70,16 @@ func New() *EnvSettings {
RepositoryCache: envOr("HELM_REPOSITORY_CACHE", helmpath.CachePath("repository")), RepositoryCache: envOr("HELM_REPOSITORY_CACHE", helmpath.CachePath("repository")),
} }
env.Debug, _ = strconv.ParseBool(os.Getenv("HELM_DEBUG")) env.Debug, _ = strconv.ParseBool(os.Getenv("HELM_DEBUG"))
return &env
// bind to kubernetes config flags
env.config = &genericclioptions.ConfigFlags{
Namespace: &env.namespace,
Context: &env.KubeContext,
BearerToken: &env.KubeToken,
APIServer: &env.KubeAPIServer,
KubeConfig: &env.KubeConfig,
}
return env
} }
// AddFlags binds flags to the given flagset. // AddFlags binds flags to the given flagset.
@ -107,42 +111,27 @@ func (s *EnvSettings) EnvVars() map[string]string {
"HELM_REPOSITORY_CACHE": s.RepositoryCache, "HELM_REPOSITORY_CACHE": s.RepositoryCache,
"HELM_REPOSITORY_CONFIG": s.RepositoryConfig, "HELM_REPOSITORY_CONFIG": s.RepositoryConfig,
"HELM_NAMESPACE": s.Namespace(), "HELM_NAMESPACE": s.Namespace(),
"HELM_KUBECONTEXT": s.KubeContext,
"HELM_KUBETOKEN": s.KubeToken,
"HELM_KUBEAPISERVER": s.KubeAPIServer,
}
// broken, these are populated from helm flags and not kubeconfig.
"HELM_KUBECONTEXT": s.KubeContext,
"HELM_KUBETOKEN": s.KubeToken,
"HELM_KUBEAPISERVER": s.KubeAPIServer,
}
if s.KubeConfig != "" { if s.KubeConfig != "" {
envvars["KUBECONFIG"] = s.KubeConfig envvars["KUBECONFIG"] = s.KubeConfig
} }
return envvars return envvars
} }
//Namespace gets the namespace from the configuration // Namespace gets the namespace from the configuration
func (s *EnvSettings) Namespace() string { func (s *EnvSettings) Namespace() string {
if s.namespace != "" { if ns, _, err := s.config.ToRawKubeConfigLoader().Namespace(); err == nil {
return s.namespace
}
if ns, _, err := s.RESTClientGetter().ToRawKubeConfigLoader().Namespace(); err == nil {
return ns return ns
} }
return "default" return "default"
} }
//RESTClientGetter gets the kubeconfig from EnvSettings // RESTClientGetter gets the kubeconfig from EnvSettings
func (s *EnvSettings) RESTClientGetter() genericclioptions.RESTClientGetter { func (s *EnvSettings) RESTClientGetter() genericclioptions.RESTClientGetter {
s.configOnce.Do(func() {
clientConfig := kube.GetConfig(s.KubeConfig, s.KubeContext, s.namespace)
if s.KubeToken != "" {
clientConfig.BearerToken = &s.KubeToken
}
if s.KubeAPIServer != "" {
clientConfig.APIServer = &s.KubeAPIServer
}
s.config = clientConfig
})
return s.config return s.config
} }

@ -53,9 +53,10 @@ func TestProviders(t *testing.T) {
} }
func TestAll(t *testing.T) { func TestAll(t *testing.T) {
all := All(&cli.EnvSettings{ env := cli.New()
PluginsDirectory: pluginDir, env.PluginsDirectory = pluginDir
})
all := All(env)
if len(all) != 3 { if len(all) != 3 {
t.Errorf("expected 3 providers (default plus two plugins), got %d", len(all)) t.Errorf("expected 3 providers (default plus two plugins), got %d", len(all))
} }
@ -66,9 +67,10 @@ func TestAll(t *testing.T) {
} }
func TestByScheme(t *testing.T) { func TestByScheme(t *testing.T) {
g := All(&cli.EnvSettings{ env := cli.New()
PluginsDirectory: pluginDir, env.PluginsDirectory = pluginDir
})
g := All(env)
if _, err := g.ByScheme("test"); err != nil { if _, err := g.ByScheme("test"); err != nil {
t.Error(err) t.Error(err)
} }

@ -122,7 +122,7 @@ func TestDownload(t *testing.T) {
})) }))
defer srv.Close() defer srv.Close()
g, err := All(new(cli.EnvSettings)).ByScheme("http") g, err := All(cli.New()).ByScheme("http")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

@ -24,9 +24,9 @@ import (
) )
func TestCollectPlugins(t *testing.T) { func TestCollectPlugins(t *testing.T) {
env := &cli.EnvSettings{ env := cli.New()
PluginsDirectory: pluginDir, env.PluginsDirectory = pluginDir
}
p, err := collectPlugins(env) p, err := collectPlugins(env)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -54,9 +54,8 @@ func TestPluginGetter(t *testing.T) {
t.Skip("TODO: refactor this test to work on windows") t.Skip("TODO: refactor this test to work on windows")
} }
env := &cli.EnvSettings{ env := cli.New()
PluginsDirectory: pluginDir, env.PluginsDirectory = pluginDir
}
pg := NewPluginGetter("echo", env, "test", ".") pg := NewPluginGetter("echo", env, "test", ".")
g, err := pg() g, err := pg()
if err != nil { if err != nil {
@ -80,9 +79,9 @@ func TestPluginSubCommands(t *testing.T) {
t.Skip("TODO: refactor this test to work on windows") t.Skip("TODO: refactor this test to work on windows")
} }
env := &cli.EnvSettings{ env := cli.New()
PluginsDirectory: pluginDir, env.PluginsDirectory = pluginDir
}
pg := NewPluginGetter("echo -n", env, "test", ".") pg := NewPluginGetter("echo -n", env, "test", ".")
g, err := pg() g, err := pg()
if err != nil { if err != nil {

@ -19,6 +19,8 @@ package kube // import "helm.sh/helm/v3/pkg/kube"
import "k8s.io/cli-runtime/pkg/genericclioptions" import "k8s.io/cli-runtime/pkg/genericclioptions"
// GetConfig returns a Kubernetes client config. // GetConfig returns a Kubernetes client config.
//
// Deprecated
func GetConfig(kubeconfig, context, namespace string) *genericclioptions.ConfigFlags { func GetConfig(kubeconfig, context, namespace string) *genericclioptions.ConfigFlags {
cf := genericclioptions.NewConfigFlags(true) cf := genericclioptions.NewConfigFlags(true)
cf.Namespace = &namespace cf.Namespace = &namespace

@ -305,9 +305,8 @@ func TestSetupEnv(t *testing.T) {
name := "pequod" name := "pequod"
base := filepath.Join("testdata/helmhome/helm/plugins", name) base := filepath.Join("testdata/helmhome/helm/plugins", name)
s := &cli.EnvSettings{ s := cli.New()
PluginsDirectory: "testdata/helmhome/helm/plugins", s.PluginsDirectory = "testdata/helmhome/helm/plugins"
}
SetupPluginEnv(s, name, base) SetupPluginEnv(s, name, base)
for _, tt := range []struct { for _, tt := range []struct {

Loading…
Cancel
Save