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 }