Skip to content

Commit

Permalink
fix(helm): fix flag parsing once and for all
Browse files Browse the repository at this point in the history
  • Loading branch information
adamreese committed Jul 14, 2017
1 parent 1261f71 commit a29e610
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 97 deletions.
4 changes: 1 addition & 3 deletions cmd/helm/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ import (
"testing"

"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/proto/hapi/chart"
)

Expand Down Expand Up @@ -87,7 +85,7 @@ func TestCreateStarterCmd(t *testing.T) {
if err != nil {
t.Fatal(err)
}
old := helmpath.Home(environment.DefaultHelmHome)
old := settings.Home
settings.Home = thome
defer func() {
settings.Home = old
Expand Down
4 changes: 1 addition & 3 deletions cmd/helm/fetch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ import (
"regexp"
"testing"

"k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/repo/repotest"
)

Expand All @@ -34,7 +32,7 @@ func TestFetchCmd(t *testing.T) {
if err != nil {
t.Fatal(err)
}
old := helmpath.Home(environment.DefaultHelmHome)
old := settings.Home
settings.Home = hh
defer func() {
settings.Home = old
Expand Down
61 changes: 16 additions & 45 deletions cmd/helm/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import (
helm_env "k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/helm/portforwarder"
"k8s.io/helm/pkg/kube"
tiller_env "k8s.io/helm/pkg/tiller/environment"
"k8s.io/helm/pkg/tlsutil"
)

Expand All @@ -46,7 +45,6 @@ var (
tlsVerify bool // enable TLS and verify remote certificates
tlsEnable bool // enable TLS

kubeContext string
tillerTunnel *kube.Tunnel
settings helm_env.EnvSettings
)
Expand Down Expand Up @@ -75,57 +73,25 @@ Environment:
$KUBECONFIG set an alternative Kubernetes configuration file (default "~/.kube/config")
`

func setFlagFromEnv(name, envar string, cmd *cobra.Command) {
if cmd.Flags().Changed(name) {
return
}
if v, ok := os.LookupEnv(envar); ok {
cmd.Flags().Set(name, v)
}
}

func setFlagsFromEnv(flags map[string]string, cmd *cobra.Command) {
for name, envar := range flags {
setFlagFromEnv(name, envar, cmd)
}
}

func addRootFlags(cmd *cobra.Command) {
pf := cmd.PersistentFlags()
pf.StringVar((*string)(&settings.Home), "home", helm_env.DefaultHelmHome, "location of your Helm config. Overrides $HELM_HOME")
pf.StringVar(&settings.TillerHost, "host", "", "address of Tiller. Overrides $HELM_HOST")
pf.StringVar(&kubeContext, "kube-context", "", "name of the kubeconfig context to use")
pf.BoolVar(&settings.Debug, "debug", false, "enable verbose output")
pf.StringVar(&settings.TillerNamespace, "tiller-namespace", tiller_env.DefaultTillerNamespace, "namespace of Tiller")
}

func initRootFlags(cmd *cobra.Command) {
setFlagsFromEnv(map[string]string{
"debug": helm_env.DebugEnvVar,
"home": helm_env.HomeEnvVar,
"host": helm_env.HostEnvVar,
"tiller-namespace": tiller_env.TillerNamespaceEnvVar,
}, cmd.Root())

tlsCaCertFile = os.ExpandEnv(tlsCaCertFile)
tlsCertFile = os.ExpandEnv(tlsCertFile)
tlsKeyFile = os.ExpandEnv(tlsKeyFile)
}

func newRootCmd() *cobra.Command {
func newRootCmd(args []string) *cobra.Command {
cmd := &cobra.Command{
Use: "helm",
Short: "The Helm package manager for Kubernetes.",
Long: globalUsage,
SilenceUsage: true,
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
initRootFlags(cmd)
PersistentPreRun: func(*cobra.Command, []string) {
tlsCaCertFile = os.ExpandEnv(tlsCaCertFile)
tlsCertFile = os.ExpandEnv(tlsCertFile)
tlsKeyFile = os.ExpandEnv(tlsKeyFile)
},
PersistentPostRun: func(*cobra.Command, []string) {
teardown()
},
}
addRootFlags(cmd)
flags := cmd.PersistentFlags()

settings.AddFlags(flags)

out := cmd.OutOrStdout()

cmd.AddCommand(
Expand Down Expand Up @@ -167,6 +133,11 @@ func newRootCmd() *cobra.Command {
markDeprecated(newRepoUpdateCmd(out), "use 'helm repo update'\n"),
)

flags.Parse(args)

// set defaults from environment
settings.Init(flags)

// Find and add plugins
loadPlugins(cmd, out)

Expand All @@ -179,7 +150,7 @@ func init() {
}

func main() {
cmd := newRootCmd()
cmd := newRootCmd(os.Args[1:])
if err := cmd.Execute(); err != nil {
os.Exit(1)
}
Expand All @@ -192,7 +163,7 @@ func markDeprecated(cmd *cobra.Command, notice string) *cobra.Command {

func setupConnection(c *cobra.Command, args []string) error {
if settings.TillerHost == "" {
config, client, err := getKubeClient(kubeContext)
config, client, err := getKubeClient(settings.KubeContext)
if err != nil {
return err
}
Expand Down
12 changes: 9 additions & 3 deletions cmd/helm/helm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"os"
"path/filepath"
"regexp"
"strings"
"testing"

"github.com/golang/protobuf/ptypes/timestamp"
Expand Down Expand Up @@ -232,8 +233,13 @@ func ensureTestHome(home helmpath.Home, t *testing.T) error {
}

func TestRootCmd(t *testing.T) {
oldhome := os.Getenv("HELM_HOME")
defer os.Setenv("HELM_HOME", oldhome)
// reset env
defer func(origEnv []string) {
for _, pair := range origEnv {
kv := strings.SplitN(pair, "=", 2)
os.Setenv(kv[0], kv[1])
}
}(os.Environ())

tests := []struct {
name string
Expand Down Expand Up @@ -287,7 +293,7 @@ func TestRootCmd(t *testing.T) {
os.Setenv(k, v)
}

cmd := newRootCmd()
cmd := newRootCmd(tt.args)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tt.args)
cmd.Run = func(*cobra.Command, []string) {}
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ func (i *initCmd) run() error {

if !i.clientOnly {
if i.kubeClient == nil {
_, c, err := getKubeClient(kubeContext)
_, c, err := getKubeClient(settings.KubeContext)
if err != nil {
return fmt.Errorf("could not get kubernetes client: %s", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ func generateName(nameTemplate string) (string, error) {
}

func defaultNamespace() string {
if ns, _, err := kube.GetConfig(kubeContext).Namespace(); err == nil {
if ns, _, err := kube.GetConfig(settings.KubeContext).Namespace(); err == nil {
return ns
}
return "default"
Expand Down
16 changes: 2 additions & 14 deletions cmd/helm/load_plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ import (
"strings"

"github.com/spf13/cobra"
"github.com/spf13/pflag"

helm_env "k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/plugin"
)

Expand All @@ -38,20 +36,11 @@ import (
func loadPlugins(baseCmd *cobra.Command, out io.Writer) {

// If HELM_NO_PLUGINS is set to 1, do not load plugins.
if os.Getenv(helm_env.PluginDisableEnvVar) == "1" {
if os.Getenv("HELM_NO_PLUGINS") == "1" {
return
}

// manually handel processing of HELM_HOME and --home
helmHome := "$HOME/.helm"
if h, ok := os.LookupEnv("HELM_HOME"); ok {
helmHome = h
}

fs := pflag.NewFlagSet("homer", pflag.ContinueOnError)
fs.StringVar((*string)(&settings.Home), "home", helmHome, "location of your Helm config. Overrides $HELM_HOME")
fs.Parse(os.Args)

// debug("HELM_PLUGIN_DIRS=%s", settings.PluginDirs())
found, err := findPlugins(settings.PluginDirs())
if err != nil {
fmt.Fprintf(os.Stderr, "failed to load plugins: %s", err)
Expand All @@ -63,7 +52,6 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) {
if err := cmd.Parent().ParseFlags(k); err != nil {
return nil, err
}
initRootFlags(cmd)
return u, nil
}

Expand Down
5 changes: 2 additions & 3 deletions cmd/helm/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"strings"
"testing"

helm_env "k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/plugin"

Expand Down Expand Up @@ -152,10 +151,10 @@ func TestLoadPlugins_HelmNoPlugins(t *testing.T) {
// Set helm home to point to testdata
old := settings.Home
settings.Home = "testdata/helmhome"
os.Setenv(helm_env.PluginDisableEnvVar, "1")
cleanup := resetEnv("HELM_NO_PLUGINS", "1")
defer func() {
settings.Home = old
os.Unsetenv(helm_env.PluginDisableEnvVar)
cleanup()
}()

out := bytes.NewBuffer(nil)
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func newResetCmd(client helm.Interface, out io.Writer) *cobra.Command {
// runReset uninstalls tiller from Kubernetes Cluster and deletes local config
func (d *resetCmd) run() error {
if d.kubeClient == nil {
_, c, err := getInternalKubeClient(kubeContext)
_, c, err := getInternalKubeClient(settings.KubeContext)
if err != nil {
return fmt.Errorf("could not get kubernetes client: %s", err)
}
Expand Down
61 changes: 47 additions & 14 deletions pkg/helm/environment/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,9 @@ import (
"os"
"path/filepath"

"k8s.io/helm/pkg/helm/helmpath"
)
"github.com/spf13/pflag"

const (
// HomeEnvVar is the HELM_HOME environment variable key.
HomeEnvVar = "HELM_HOME"
// PluginEnvVar is the HELM_PLUGIN environment variable key.
PluginEnvVar = "HELM_PLUGIN"
// PluginDisableEnvVar is the HELM_NO_PLUGINS environment variable key.
PluginDisableEnvVar = "HELM_NO_PLUGINS"
// HostEnvVar is the HELM_HOST environment variable key.
HostEnvVar = "HELM_HOST"
// DebugEnvVar is the HELM_DEBUG environment variable key.
DebugEnvVar = "HELM_DEBUG"
"k8s.io/helm/pkg/helm/helmpath"
)

// DefaultHelmHome is the default HELM_HOME.
Expand All @@ -55,12 +44,56 @@ type EnvSettings struct {
Home helmpath.Home
// Debug indicates whether or not Helm is running in Debug mode.
Debug bool
// KubeContext is the name of the kubeconfig context.
KubeContext string
}

// AddFlags binds flags to the given flagset.
func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) {
fs.StringVar((*string)(&s.Home), "home", DefaultHelmHome, "location of your Helm config. Overrides $HELM_HOME")
fs.StringVar(&s.TillerHost, "host", "", "address of Tiller. Overrides $HELM_HOST")
fs.StringVar(&s.KubeContext, "kube-context", "", "name of the kubeconfig context to use")
fs.BoolVar(&s.Debug, "debug", false, "enable verbose output")
fs.StringVar(&s.TillerNamespace, "tiller-namespace", "kube-system", "namespace of Tiller")
}

// Init sets values from the environment.
func (s *EnvSettings) Init(fs *pflag.FlagSet) {
for name, envar := range envMap {
setFlagFromEnv(name, envar, fs)
}
}

// PluginDirs is the path to the plugin directories.
func (s EnvSettings) PluginDirs() string {
if d := os.Getenv(PluginEnvVar); d != "" {
if d, ok := os.LookupEnv("HELM_PLUGIN"); ok {
return d
}
return s.Home.Plugins()
}

// envMap maps flag names to envvars
var envMap = map[string]string{
"debug": "HELM_DEBUG",
"home": "HELM_HOME",
"host": "HELM_HOST",
"tiller-namespace": "TILLER_NAMESPACE",
}

func setFlagFromEnv(name, envar string, fs *pflag.FlagSet) {
if fs.Changed(name) {
return
}
if v, ok := os.LookupEnv(envar); ok {
fs.Set(name, v)
}
}

// Deprecated
const (
HomeEnvVar = "HELM_HOME"
PluginEnvVar = "HELM_PLUGIN"
PluginDisableEnvVar = "HELM_NO_PLUGINS"
HostEnvVar = "HELM_HOST"
DebugEnvVar = "HELM_DEBUG"
)
Loading

0 comments on commit a29e610

Please sign in to comment.