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