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) != "" }