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