github.com/werf/3p-helm@v2.8.1+incompatible/cmd/tiller/tiller.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors All rights reserved. 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/tiller" 18 19 import ( 20 "crypto/tls" 21 "flag" 22 "fmt" 23 "io/ioutil" 24 "log" 25 "net" 26 "net/http" 27 "os" 28 "path/filepath" 29 "strconv" 30 "strings" 31 "time" 32 33 goprom "github.com/grpc-ecosystem/go-grpc-prometheus" 34 "google.golang.org/grpc" 35 "google.golang.org/grpc/credentials" 36 "google.golang.org/grpc/keepalive" 37 38 "k8s.io/helm/pkg/kube" 39 "k8s.io/helm/pkg/proto/hapi/services" 40 "k8s.io/helm/pkg/storage" 41 "k8s.io/helm/pkg/storage/driver" 42 "k8s.io/helm/pkg/tiller" 43 "k8s.io/helm/pkg/tiller/environment" 44 "k8s.io/helm/pkg/tlsutil" 45 "k8s.io/helm/pkg/version" 46 ) 47 48 const ( 49 // tlsEnableEnvVar names the environment variable that enables TLS. 50 tlsEnableEnvVar = "TILLER_TLS_ENABLE" 51 // tlsVerifyEnvVar names the environment variable that enables 52 // TLS, as well as certificate verification of the remote. 53 tlsVerifyEnvVar = "TILLER_TLS_VERIFY" 54 // tlsCertsEnvVar names the environment variable that points to 55 // the directory where Tiller's TLS certificates are located. 56 tlsCertsEnvVar = "TILLER_TLS_CERTS" 57 // historyMaxEnvVar is the name of the env var for setting max history. 58 historyMaxEnvVar = "TILLER_HISTORY_MAX" 59 60 storageMemory = "memory" 61 storageConfigMap = "configmap" 62 storageSecret = "secret" 63 64 probeAddr = ":44135" 65 traceAddr = ":44136" 66 67 // defaultMaxHistory sets the maximum number of releases to 0: unlimited 68 defaultMaxHistory = 0 69 ) 70 71 var ( 72 grpcAddr = flag.String("listen", ":44134", "address:port to listen on") 73 enableTracing = flag.Bool("trace", false, "enable rpc tracing") 74 store = flag.String("storage", storageConfigMap, "storage driver to use. One of 'configmap', 'memory', or 'secret'") 75 remoteReleaseModules = flag.Bool("experimental-release", false, "enable experimental release modules") 76 tlsEnable = flag.Bool("tls", tlsEnableEnvVarDefault(), "enable TLS") 77 tlsVerify = flag.Bool("tls-verify", tlsVerifyEnvVarDefault(), "enable TLS and verify remote certificate") 78 keyFile = flag.String("tls-key", tlsDefaultsFromEnv("tls-key"), "path to TLS private key file") 79 certFile = flag.String("tls-cert", tlsDefaultsFromEnv("tls-cert"), "path to TLS certificate file") 80 caCertFile = flag.String("tls-ca-cert", tlsDefaultsFromEnv("tls-ca-cert"), "trust certificates signed by this CA") 81 maxHistory = flag.Int("history-max", historyMaxFromEnv(), "maximum number of releases kept in release history, with 0 meaning no limit") 82 printVersion = flag.Bool("version", false, "print the version number") 83 84 // rootServer is the root gRPC server. 85 // 86 // Each gRPC service registers itself to this server during init(). 87 rootServer *grpc.Server 88 89 // env is the default environment. 90 // 91 // Any changes to env should be done before rootServer.Serve() is called. 92 env = environment.New() 93 94 logger *log.Logger 95 ) 96 97 func main() { 98 // TODO: use spf13/cobra for tiller instead of flags 99 flag.Parse() 100 101 if *printVersion { 102 fmt.Println(version.GetVersion()) 103 os.Exit(0) 104 } 105 106 if *enableTracing { 107 log.SetFlags(log.Lshortfile) 108 } 109 logger = newLogger("main") 110 111 start() 112 } 113 114 func start() { 115 116 clientset, err := kube.New(nil).ClientSet() 117 if err != nil { 118 logger.Fatalf("Cannot initialize Kubernetes connection: %s", err) 119 } 120 121 switch *store { 122 case storageMemory: 123 env.Releases = storage.Init(driver.NewMemory()) 124 case storageConfigMap: 125 cfgmaps := driver.NewConfigMaps(clientset.Core().ConfigMaps(namespace())) 126 cfgmaps.Log = newLogger("storage/driver").Printf 127 128 env.Releases = storage.Init(cfgmaps) 129 env.Releases.Log = newLogger("storage").Printf 130 case storageSecret: 131 secrets := driver.NewSecrets(clientset.Core().Secrets(namespace())) 132 secrets.Log = newLogger("storage/driver").Printf 133 134 env.Releases = storage.Init(secrets) 135 env.Releases.Log = newLogger("storage").Printf 136 } 137 138 if *maxHistory > 0 { 139 env.Releases.MaxHistory = *maxHistory 140 } 141 142 kubeClient := kube.New(nil) 143 kubeClient.Log = newLogger("kube").Printf 144 env.KubeClient = kubeClient 145 146 if *tlsEnable || *tlsVerify { 147 opts := tlsutil.Options{CertFile: *certFile, KeyFile: *keyFile} 148 if *tlsVerify { 149 opts.CaCertFile = *caCertFile 150 } 151 } 152 153 var opts []grpc.ServerOption 154 if *tlsEnable || *tlsVerify { 155 cfg, err := tlsutil.ServerConfig(tlsOptions()) 156 if err != nil { 157 logger.Fatalf("Could not create server TLS configuration: %v", err) 158 } 159 opts = append(opts, grpc.Creds(credentials.NewTLS(cfg))) 160 opts = append(opts, grpc.KeepaliveParams(keepalive.ServerParameters{ 161 MaxConnectionIdle: 10 * time.Minute, 162 // If needed, we can configure the max connection age 163 })) 164 } 165 166 rootServer = tiller.NewServer(opts...) 167 168 lstn, err := net.Listen("tcp", *grpcAddr) 169 if err != nil { 170 logger.Fatalf("Server died: %s", err) 171 } 172 173 logger.Printf("Starting Tiller %s (tls=%t)", version.GetVersion(), *tlsEnable || *tlsVerify) 174 logger.Printf("GRPC listening on %s", *grpcAddr) 175 logger.Printf("Probes listening on %s", probeAddr) 176 logger.Printf("Storage driver is %s", env.Releases.Name()) 177 logger.Printf("Max history per release is %d", *maxHistory) 178 179 if *enableTracing { 180 startTracing(traceAddr) 181 } 182 183 srvErrCh := make(chan error) 184 probeErrCh := make(chan error) 185 go func() { 186 svc := tiller.NewReleaseServer(env, clientset, *remoteReleaseModules) 187 svc.Log = newLogger("tiller").Printf 188 services.RegisterReleaseServiceServer(rootServer, svc) 189 if err := rootServer.Serve(lstn); err != nil { 190 srvErrCh <- err 191 } 192 }() 193 194 go func() { 195 mux := newProbesMux() 196 197 // Register gRPC server to prometheus to initialized matrix 198 goprom.Register(rootServer) 199 addPrometheusHandler(mux) 200 201 if err := http.ListenAndServe(probeAddr, mux); err != nil { 202 probeErrCh <- err 203 } 204 }() 205 206 select { 207 case err := <-srvErrCh: 208 logger.Fatalf("Server died: %s", err) 209 case err := <-probeErrCh: 210 logger.Printf("Probes server died: %s", err) 211 } 212 } 213 214 func newLogger(prefix string) *log.Logger { 215 if len(prefix) > 0 { 216 prefix = fmt.Sprintf("[%s] ", prefix) 217 } 218 return log.New(os.Stderr, prefix, log.Flags()) 219 } 220 221 // namespace returns the namespace of tiller 222 func namespace() string { 223 if ns := os.Getenv("TILLER_NAMESPACE"); ns != "" { 224 return ns 225 } 226 227 // Fall back to the namespace associated with the service account token, if available 228 if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { 229 if ns := strings.TrimSpace(string(data)); len(ns) > 0 { 230 return ns 231 } 232 } 233 234 return environment.DefaultTillerNamespace 235 } 236 237 func tlsOptions() tlsutil.Options { 238 opts := tlsutil.Options{CertFile: *certFile, KeyFile: *keyFile} 239 if *tlsVerify { 240 opts.CaCertFile = *caCertFile 241 242 // We want to force the client to not only provide a cert, but to 243 // provide a cert that we can validate. 244 // http://www.bite-code.com/2015/06/25/tls-mutual-auth-in-golang/ 245 opts.ClientAuth = tls.RequireAndVerifyClientCert 246 } 247 return opts 248 } 249 250 func tlsDefaultsFromEnv(name string) (value string) { 251 switch certsDir := os.Getenv(tlsCertsEnvVar); name { 252 case "tls-key": 253 return filepath.Join(certsDir, "tls.key") 254 case "tls-cert": 255 return filepath.Join(certsDir, "tls.crt") 256 case "tls-ca-cert": 257 return filepath.Join(certsDir, "ca.crt") 258 } 259 return "" 260 } 261 262 func historyMaxFromEnv() int { 263 val := os.Getenv(historyMaxEnvVar) 264 if val == "" { 265 return defaultMaxHistory 266 } 267 ret, err := strconv.Atoi(val) 268 if err != nil { 269 log.Printf("Invalid max history %q. Defaulting to 0.", val) 270 return defaultMaxHistory 271 } 272 return ret 273 } 274 275 func tlsEnableEnvVarDefault() bool { return os.Getenv(tlsEnableEnvVar) != "" } 276 func tlsVerifyEnvVarDefault() bool { return os.Getenv(tlsVerifyEnvVar) != "" }