github.com/Beeketing/helm@v2.12.1+incompatible/cmd/helm/helm.go (about)

     1  /*
     2  Copyright The Helm Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package main // import "k8s.io/helm/cmd/helm"
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  	"log"
    23  	"os"
    24  	"strings"
    25  
    26  	"github.com/spf13/cobra"
    27  	"google.golang.org/grpc/grpclog"
    28  	"google.golang.org/grpc/status"
    29  	"k8s.io/client-go/kubernetes"
    30  	"k8s.io/client-go/rest"
    31  
    32  	// Import to initialize client auth plugins.
    33  	_ "k8s.io/client-go/plugin/pkg/client/auth"
    34  
    35  	"k8s.io/helm/pkg/helm"
    36  	helm_env "k8s.io/helm/pkg/helm/environment"
    37  	"k8s.io/helm/pkg/helm/portforwarder"
    38  	"k8s.io/helm/pkg/kube"
    39  	"k8s.io/helm/pkg/tlsutil"
    40  )
    41  
    42  var (
    43  	tillerTunnel *kube.Tunnel
    44  	settings     helm_env.EnvSettings
    45  )
    46  
    47  var globalUsage = `The Kubernetes package manager
    48  
    49  To begin working with Helm, run the 'helm init' command:
    50  
    51  	$ helm init
    52  
    53  This will install Tiller to your running Kubernetes cluster.
    54  It will also set up any necessary local configuration.
    55  
    56  Common actions from this point include:
    57  
    58  - helm search:    search for charts
    59  - helm fetch:     download a chart to your local directory to view
    60  - helm install:   upload the chart to Kubernetes
    61  - helm list:      list releases of charts
    62  
    63  Environment:
    64    $HELM_HOME           set an alternative location for Helm files. By default, these are stored in ~/.helm
    65    $HELM_HOST           set an alternative Tiller host. The format is host:port
    66    $HELM_NO_PLUGINS     disable plugins. Set HELM_NO_PLUGINS=1 to disable plugins.
    67    $TILLER_NAMESPACE    set an alternative Tiller namespace (default "kube-system")
    68    $KUBECONFIG          set an alternative Kubernetes configuration file (default "~/.kube/config")
    69    $HELM_TLS_CA_CERT    path to TLS CA certificate used to verify the Helm client and Tiller server certificates (default "$HELM_HOME/ca.pem")
    70    $HELM_TLS_CERT       path to TLS client certificate file for authenticating to Tiller (default "$HELM_HOME/cert.pem")
    71    $HELM_TLS_KEY        path to TLS client key file for authenticating to Tiller (default "$HELM_HOME/key.pem")
    72    $HELM_TLS_VERIFY     enable TLS connection between Helm and Tiller and verify Tiller server certificate (default "false")
    73    $HELM_TLS_ENABLE     enable TLS connection between Helm and Tiller (default "false")
    74    $HELM_KEY_PASSPHRASE set HELM_KEY_PASSPHRASE to the passphrase of your PGP private key. If set, you will not be prompted for
    75                         the passphrase while signing helm charts
    76  
    77  `
    78  
    79  func newRootCmd(args []string) *cobra.Command {
    80  	cmd := &cobra.Command{
    81  		Use:          "helm",
    82  		Short:        "The Helm package manager for Kubernetes.",
    83  		Long:         globalUsage,
    84  		SilenceUsage: true,
    85  		PersistentPreRun: func(*cobra.Command, []string) {
    86  			if settings.TLSCaCertFile == helm_env.DefaultTLSCaCert || settings.TLSCaCertFile == "" {
    87  				settings.TLSCaCertFile = settings.Home.TLSCaCert()
    88  			} else {
    89  				settings.TLSCaCertFile = os.ExpandEnv(settings.TLSCaCertFile)
    90  			}
    91  			if settings.TLSCertFile == helm_env.DefaultTLSCert || settings.TLSCertFile == "" {
    92  				settings.TLSCertFile = settings.Home.TLSCert()
    93  			} else {
    94  				settings.TLSCertFile = os.ExpandEnv(settings.TLSCertFile)
    95  			}
    96  			if settings.TLSKeyFile == helm_env.DefaultTLSKeyFile || settings.TLSKeyFile == "" {
    97  				settings.TLSKeyFile = settings.Home.TLSKey()
    98  			} else {
    99  				settings.TLSKeyFile = os.ExpandEnv(settings.TLSKeyFile)
   100  			}
   101  		},
   102  		PersistentPostRun: func(*cobra.Command, []string) {
   103  			teardown()
   104  		},
   105  	}
   106  	flags := cmd.PersistentFlags()
   107  
   108  	settings.AddFlags(flags)
   109  
   110  	out := cmd.OutOrStdout()
   111  
   112  	cmd.AddCommand(
   113  		// chart commands
   114  		newCreateCmd(out),
   115  		newDependencyCmd(out),
   116  		newFetchCmd(out),
   117  		newInspectCmd(out),
   118  		newLintCmd(out),
   119  		newPackageCmd(out),
   120  		newRepoCmd(out),
   121  		newSearchCmd(out),
   122  		newServeCmd(out),
   123  		newVerifyCmd(out),
   124  
   125  		// release commands
   126  		newDeleteCmd(nil, out),
   127  		newGetCmd(nil, out),
   128  		newHistoryCmd(nil, out),
   129  		newInstallCmd(nil, out),
   130  		newListCmd(nil, out),
   131  		newRollbackCmd(nil, out),
   132  		newStatusCmd(nil, out),
   133  		newUpgradeCmd(nil, out),
   134  
   135  		newReleaseTestCmd(nil, out),
   136  		newResetCmd(nil, out),
   137  		newVersionCmd(nil, out),
   138  
   139  		newCompletionCmd(out),
   140  		newHomeCmd(out),
   141  		newInitCmd(out),
   142  		newPluginCmd(out),
   143  		newTemplateCmd(out),
   144  
   145  		// Hidden documentation generator command: 'helm docs'
   146  		newDocsCmd(out),
   147  
   148  		// Deprecated
   149  		markDeprecated(newRepoUpdateCmd(out), "use 'helm repo update'\n"),
   150  	)
   151  
   152  	flags.Parse(args)
   153  
   154  	// set defaults from environment
   155  	settings.Init(flags)
   156  
   157  	// Find and add plugins
   158  	loadPlugins(cmd, out)
   159  
   160  	return cmd
   161  }
   162  
   163  func init() {
   164  	// Tell gRPC not to log to console.
   165  	grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags))
   166  }
   167  
   168  func main() {
   169  	cmd := newRootCmd(os.Args[1:])
   170  	if err := cmd.Execute(); err != nil {
   171  		switch e := err.(type) {
   172  		case pluginError:
   173  			os.Exit(e.code)
   174  		default:
   175  			os.Exit(1)
   176  		}
   177  	}
   178  }
   179  
   180  func markDeprecated(cmd *cobra.Command, notice string) *cobra.Command {
   181  	cmd.Deprecated = notice
   182  	return cmd
   183  }
   184  
   185  func setupConnection() error {
   186  	if settings.TillerHost == "" {
   187  		config, client, err := getKubeClient(settings.KubeContext, settings.KubeConfig)
   188  		if err != nil {
   189  			return err
   190  		}
   191  
   192  		tillerTunnel, err = portforwarder.New(settings.TillerNamespace, client, config)
   193  		if err != nil {
   194  			return err
   195  		}
   196  
   197  		settings.TillerHost = fmt.Sprintf("127.0.0.1:%d", tillerTunnel.Local)
   198  		debug("Created tunnel using local port: '%d'\n", tillerTunnel.Local)
   199  	}
   200  
   201  	// Set up the gRPC config.
   202  	debug("SERVER: %q\n", settings.TillerHost)
   203  
   204  	// Plugin support.
   205  	return nil
   206  }
   207  
   208  func teardown() {
   209  	if tillerTunnel != nil {
   210  		tillerTunnel.Close()
   211  	}
   212  }
   213  
   214  func checkArgsLength(argsReceived int, requiredArgs ...string) error {
   215  	expectedNum := len(requiredArgs)
   216  	if argsReceived != expectedNum {
   217  		arg := "arguments"
   218  		if expectedNum == 1 {
   219  			arg = "argument"
   220  		}
   221  		return fmt.Errorf("This command needs %v %s: %s", expectedNum, arg, strings.Join(requiredArgs, ", "))
   222  	}
   223  	return nil
   224  }
   225  
   226  // prettyError unwraps or rewrites certain errors to make them more user-friendly.
   227  func prettyError(err error) error {
   228  	// Add this check can prevent the object creation if err is nil.
   229  	if err == nil {
   230  		return nil
   231  	}
   232  	// If it's grpc's error, make it more user-friendly.
   233  	if s, ok := status.FromError(err); ok {
   234  		return fmt.Errorf(s.Message())
   235  	}
   236  	// Else return the original error.
   237  	return err
   238  }
   239  
   240  // configForContext creates a Kubernetes REST client configuration for a given kubeconfig context.
   241  func configForContext(context string, kubeconfig string) (*rest.Config, error) {
   242  	config, err := kube.GetConfig(context, kubeconfig).ClientConfig()
   243  	if err != nil {
   244  		return nil, fmt.Errorf("could not get Kubernetes config for context %q: %s", context, err)
   245  	}
   246  	return config, nil
   247  }
   248  
   249  // getKubeClient creates a Kubernetes config and client for a given kubeconfig context.
   250  func getKubeClient(context string, kubeconfig string) (*rest.Config, kubernetes.Interface, error) {
   251  	config, err := configForContext(context, kubeconfig)
   252  	if err != nil {
   253  		return nil, nil, err
   254  	}
   255  	client, err := kubernetes.NewForConfig(config)
   256  	if err != nil {
   257  		return nil, nil, fmt.Errorf("could not get Kubernetes client: %s", err)
   258  	}
   259  	return config, client, nil
   260  }
   261  
   262  // ensureHelmClient returns a new helm client impl. if h is not nil.
   263  func ensureHelmClient(h helm.Interface) helm.Interface {
   264  	if h != nil {
   265  		return h
   266  	}
   267  	return newClient()
   268  }
   269  
   270  func newClient() helm.Interface {
   271  	options := []helm.Option{helm.Host(settings.TillerHost), helm.ConnectTimeout(settings.TillerConnectionTimeout)}
   272  
   273  	if settings.TLSVerify || settings.TLSEnable {
   274  		debug("Host=%q, Key=%q, Cert=%q, CA=%q\n", settings.TLSServerName, settings.TLSKeyFile, settings.TLSCertFile, settings.TLSCaCertFile)
   275  		tlsopts := tlsutil.Options{
   276  			ServerName:         settings.TLSServerName,
   277  			KeyFile:            settings.TLSKeyFile,
   278  			CertFile:           settings.TLSCertFile,
   279  			InsecureSkipVerify: true,
   280  		}
   281  		if settings.TLSVerify {
   282  			tlsopts.CaCertFile = settings.TLSCaCertFile
   283  			tlsopts.InsecureSkipVerify = false
   284  		}
   285  		tlscfg, err := tlsutil.ClientConfig(tlsopts)
   286  		if err != nil {
   287  			fmt.Fprintln(os.Stderr, err)
   288  			os.Exit(2)
   289  		}
   290  		options = append(options, helm.WithTLS(tlscfg))
   291  	}
   292  	return helm.NewClient(options...)
   293  }