From de5e70930ac812b7fb000131bb12f9ed466ad3de Mon Sep 17 00:00:00 2001 From: silenceshell Date: Thu, 30 Nov 2017 14:25:11 +0800 Subject: [PATCH] feat(helm): add --port flag to helm when 'helm --port port-number [cmd]' is run, this will set the local port for portforward tunnel to port-number. Closes #2212 --- cmd/helm/helm.go | 2 +- cmd/helm/plugin_test.go | 2 ++ pkg/helm/environment/environment.go | 4 ++++ pkg/helm/environment/environment_test.go | 15 +++++++++++---- pkg/helm/portforwarder/portforwarder.go | 4 ++-- pkg/kube/tunnel.go | 14 +++++++++----- pkg/plugin/plugin.go | 3 +++ 7 files changed, 32 insertions(+), 12 deletions(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index b262e577b..f61df1f1e 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -173,7 +173,7 @@ func setupConnection(c *cobra.Command, args []string) error { return err } - tunnel, err := portforwarder.New(settings.TillerNamespace, client, config) + tunnel, err := portforwarder.New(settings.TillerNamespace, client, config, settings.TunnelLocalPort) if err != nil { return err } diff --git a/cmd/helm/plugin_test.go b/cmd/helm/plugin_test.go index 2a4a0e9aa..927152b75 100644 --- a/cmd/helm/plugin_test.go +++ b/cmd/helm/plugin_test.go @@ -20,6 +20,7 @@ import ( "os" "path/filepath" "runtime" + "strconv" "strings" "testing" @@ -179,6 +180,7 @@ func TestSetupEnv(t *testing.T) { {"HELM_PATH_STARTER", settings.Home.Starters()}, {"TILLER_HOST", settings.TillerHost}, {"TILLER_NAMESPACE", settings.TillerNamespace}, + {"TUNNEL_LOCAL_PORT", strconv.Itoa(settings.TunnelLocalPort)}, } { if got := os.Getenv(tt.name); got != tt.expect { t.Errorf("Expected $%s=%q, got %q", tt.name, tt.expect, got) diff --git a/pkg/helm/environment/environment.go b/pkg/helm/environment/environment.go index b8bcf0def..835aac9e7 100644 --- a/pkg/helm/environment/environment.go +++ b/pkg/helm/environment/environment.go @@ -39,6 +39,8 @@ var DefaultHelmHome = filepath.Join(homedir.HomeDir(), ".helm") type EnvSettings struct { // TillerHost is the host and port of Tiller. TillerHost string + // TunnelLocalPort is the local port for portforward tunnel. + TunnelLocalPort int // TillerNamespace is the namespace in which Tiller runs. TillerNamespace string // Home is the local path to the Helm home directory. @@ -59,6 +61,7 @@ func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&s.KubeConfig, "kubeconfig", "", "path to kubeconfig file. Overrides $KUBECONFIG") fs.BoolVar(&s.Debug, "debug", false, "enable verbose output") fs.StringVar(&s.TillerNamespace, "tiller-namespace", "kube-system", "namespace of Tiller") + fs.IntVar(&s.TunnelLocalPort, "port", 0, "local port for portforward tunnel. Overrides $TUNNEL_LOCAL_PORT") } // Init sets values from the environment. @@ -83,6 +86,7 @@ var envMap = map[string]string{ "host": "HELM_HOST", "kubeconfig": "KUBECONFIG", "tiller-namespace": "TILLER_NAMESPACE", + "port": "TUNNEL_LOCAL_PORT", } func setFlagFromEnv(name, envar string, fs *pflag.FlagSet) { diff --git a/pkg/helm/environment/environment_test.go b/pkg/helm/environment/environment_test.go index 8f0caa388..a555b42a2 100644 --- a/pkg/helm/environment/environment_test.go +++ b/pkg/helm/environment/environment_test.go @@ -37,6 +37,7 @@ func TestEnvSettings(t *testing.T) { // expected values home, host, ns, kcontext, plugins string debug bool + port int }{ { name: "defaults", @@ -47,30 +48,33 @@ func TestEnvSettings(t *testing.T) { }, { name: "with flags set", - args: []string{"--home", "/foo", "--host=here", "--debug", "--tiller-namespace=myns"}, + args: []string{"--home", "/foo", "--host=here", "--debug", "--tiller-namespace=myns", "--port=44443"}, home: "/foo", plugins: helmpath.Home("/foo").Plugins(), host: "here", ns: "myns", debug: true, + port: 44443, }, { name: "with envvars set", args: []string{}, - envars: map[string]string{"HELM_HOME": "/bar", "HELM_HOST": "there", "HELM_DEBUG": "1", "TILLER_NAMESPACE": "yourns"}, + envars: map[string]string{"HELM_HOME": "/bar", "HELM_HOST": "there", "HELM_DEBUG": "1", "TILLER_NAMESPACE": "yourns", "TUNNEL_LOCAL_PORT": "44444"}, home: "/bar", plugins: helmpath.Home("/bar").Plugins(), host: "there", ns: "yourns", debug: true, + port: 44444, }, { name: "with flags and envvars set", - args: []string{"--home", "/foo", "--host=here", "--debug", "--tiller-namespace=myns"}, - envars: map[string]string{"HELM_HOME": "/bar", "HELM_HOST": "there", "HELM_DEBUG": "1", "TILLER_NAMESPACE": "yourns", "HELM_PLUGIN": "glade"}, + args: []string{"--home", "/foo", "--host=here", "--debug", "--tiller-namespace=myns", "--port=44443"}, + envars: map[string]string{"HELM_HOME": "/bar", "HELM_HOST": "there", "HELM_DEBUG": "1", "TILLER_NAMESPACE": "yourns", "HELM_PLUGIN": "glade", "TUNNEL_LOCAL_PORT": "44444"}, home: "/foo", plugins: "glade", host: "here", + port: 44443, ns: "myns", debug: true, }, @@ -102,6 +106,9 @@ func TestEnvSettings(t *testing.T) { if settings.TillerHost != tt.host { t.Errorf("expected host %q, got %q", tt.host, settings.TillerHost) } + if settings.TunnelLocalPort != tt.port { + t.Errorf("expected port %d, got %d", tt.port, settings.TunnelLocalPort) + } if settings.Debug != tt.debug { t.Errorf("expected debug %t, got %t", tt.debug, settings.Debug) } diff --git a/pkg/helm/portforwarder/portforwarder.go b/pkg/helm/portforwarder/portforwarder.go index 87f697a74..d25a953dc 100644 --- a/pkg/helm/portforwarder/portforwarder.go +++ b/pkg/helm/portforwarder/portforwarder.go @@ -34,14 +34,14 @@ var ( ) // New creates a new and initialized tunnel. -func New(namespace string, client kubernetes.Interface, config *rest.Config) (*kube.Tunnel, error) { +func New(namespace string, client kubernetes.Interface, config *rest.Config, localPort int) (*kube.Tunnel, error) { podName, err := getTillerPodName(client.CoreV1(), namespace) if err != nil { return nil, err } const tillerPort = 44134 t := kube.NewTunnel(client.Core().RESTClient(), config, namespace, podName, tillerPort) - return t, t.ForwardPort() + return t, t.ForwardPort(localPort) } func getTillerPodName(client corev1.PodsGetter, namespace string) (string, error) { diff --git a/pkg/kube/tunnel.go b/pkg/kube/tunnel.go index 08280f25d..852e1dfa9 100644 --- a/pkg/kube/tunnel.go +++ b/pkg/kube/tunnel.go @@ -62,7 +62,7 @@ func (t *Tunnel) Close() { } // ForwardPort opens a tunnel to a kubernetes pod -func (t *Tunnel) ForwardPort() error { +func (t *Tunnel) ForwardPort(localPort int) error { // Build a url to the portforward endpoint // example: http://localhost:8080/api/v1/namespaces/helm/pods/tiller-deploy-9itlq/portforward u := t.client.Post(). @@ -77,11 +77,15 @@ func (t *Tunnel) ForwardPort() error { } dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", u) - local, err := getAvailablePort() - if err != nil { - return fmt.Errorf("could not find an available port: %s", err) + if localPort == 0 { + local, err := getAvailablePort() + if err != nil { + return fmt.Errorf("could not find an available port: %s", err) + } + t.Local = local + } else { + t.Local = localPort } - t.Local = local ports := []string{fmt.Sprintf("%d:%d", t.Local, t.Remote)} diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index b3458c2d8..2efa434b5 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -19,6 +19,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strconv" "strings" helm_env "k8s.io/helm/pkg/helm/environment" @@ -190,6 +191,8 @@ func SetupPluginEnv(settings helm_env.EnvSettings, "TILLER_HOST": settings.TillerHost, "TILLER_NAMESPACE": settings.TillerNamespace, + + "TUNNEL_LOCAL_PORT": strconv.Itoa(settings.TunnelLocalPort), } { os.Setenv(key, val) }