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