github.com/uber/kraken@v0.1.4/tracker/cmd/cmd.go (about)

     1  // Copyright (c) 2016-2019 Uber Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package cmd
    15  
    16  import (
    17  	"flag"
    18  
    19  	"github.com/uber/kraken/lib/healthcheck"
    20  	"github.com/uber/kraken/lib/upstream"
    21  	"github.com/uber/kraken/metrics"
    22  	"github.com/uber/kraken/nginx"
    23  	"github.com/uber/kraken/origin/blobclient"
    24  	"github.com/uber/kraken/tracker/originstore"
    25  	"github.com/uber/kraken/tracker/peerhandoutpolicy"
    26  	"github.com/uber/kraken/tracker/peerstore"
    27  	"github.com/uber/kraken/tracker/trackerserver"
    28  	"github.com/uber/kraken/utils/configutil"
    29  	"github.com/uber/kraken/utils/log"
    30  
    31  	"github.com/andres-erbsen/clock"
    32  	"github.com/uber-go/tally"
    33  	"go.uber.org/zap"
    34  )
    35  
    36  // Flags define tracker CLI flags.
    37  type Flags struct {
    38  	Port          int
    39  	ConfigFile    string
    40  	KrakenCluster string
    41  	SecretsFile   string
    42  }
    43  
    44  // ParseFlags parses tracker CLI flags.
    45  func ParseFlags() *Flags {
    46  	var flags Flags
    47  	flag.IntVar(
    48  		&flags.Port, "port", 0, "port to listen on")
    49  	flag.StringVar(
    50  		&flags.ConfigFile, "config", "", "configuration file path")
    51  	flag.StringVar(
    52  		&flags.KrakenCluster, "cluster", "", "cluster name (e.g. prod01-zone1)")
    53  	flag.StringVar(
    54  		&flags.SecretsFile, "secrets", "", "path to a secrets YAML file to load into configuration")
    55  	flag.Parse()
    56  	return &flags
    57  }
    58  
    59  type options struct {
    60  	config  *Config
    61  	metrics tally.Scope
    62  	logger  *zap.Logger
    63  }
    64  
    65  // Option defines an optional Run parameter.
    66  type Option func(*options)
    67  
    68  // WithConfig ignores config/secrets flags and directly uses the provided config
    69  // struct.
    70  func WithConfig(c Config) Option {
    71  	return func(o *options) { o.config = &c }
    72  }
    73  
    74  // WithMetrics ignores metrics config and directly uses the provided tally scope.
    75  func WithMetrics(s tally.Scope) Option {
    76  	return func(o *options) { o.metrics = s }
    77  }
    78  
    79  // WithLogger ignores logging config and directly uses the provided logger.
    80  func WithLogger(l *zap.Logger) Option {
    81  	return func(o *options) { o.logger = l }
    82  }
    83  
    84  // Run runs the tracker.
    85  func Run(flags *Flags, opts ...Option) {
    86  	var overrides options
    87  	for _, o := range opts {
    88  		o(&overrides)
    89  	}
    90  
    91  	var config Config
    92  	if overrides.config != nil {
    93  		config = *overrides.config
    94  	} else {
    95  		if err := configutil.Load(flags.ConfigFile, &config); err != nil {
    96  			panic(err)
    97  		}
    98  		if flags.SecretsFile != "" {
    99  			if err := configutil.Load(flags.SecretsFile, &config); err != nil {
   100  				panic(err)
   101  			}
   102  		}
   103  	}
   104  
   105  	if overrides.logger != nil {
   106  		log.SetGlobalLogger(overrides.logger.Sugar())
   107  	} else {
   108  		zlog := log.ConfigureLogger(config.ZapLogging)
   109  		defer zlog.Sync()
   110  	}
   111  
   112  	stats := overrides.metrics
   113  	if stats == nil {
   114  		s, closer, err := metrics.New(config.Metrics, flags.KrakenCluster)
   115  		if err != nil {
   116  			log.Fatalf("Failed to init metrics: %s", err)
   117  		}
   118  		stats = s
   119  		defer closer.Close()
   120  	}
   121  
   122  	go metrics.EmitVersion(stats)
   123  
   124  	peerStore, err := peerstore.NewRedisStore(config.PeerStore.Redis, clock.New())
   125  	if err != nil {
   126  		log.Fatalf("Could not create PeerStore: %s", err)
   127  	}
   128  
   129  	tls, err := config.TLS.BuildClient()
   130  	if err != nil {
   131  		log.Fatalf("Error building client tls config: %s", err)
   132  	}
   133  
   134  	origins, err := config.Origin.Build(upstream.WithHealthCheck(healthcheck.Default(tls)))
   135  	if err != nil {
   136  		log.Fatalf("Error building origin host list: %s", err)
   137  	}
   138  
   139  	originStore := originstore.New(
   140  		config.OriginStore, clock.New(), origins, blobclient.NewProvider(blobclient.WithTLS(tls)))
   141  
   142  	policy, err := peerhandoutpolicy.NewPriorityPolicy(stats, config.PeerHandoutPolicy.Priority)
   143  	if err != nil {
   144  		log.Fatalf("Could not load peer handout policy: %s", err)
   145  	}
   146  
   147  	r := blobclient.NewClientResolver(blobclient.NewProvider(blobclient.WithTLS(tls)), origins)
   148  	originCluster := blobclient.NewClusterClient(r)
   149  
   150  	server := trackerserver.New(
   151  		config.TrackerServer, stats, policy, peerStore, originStore, originCluster)
   152  	go func() {
   153  		log.Fatal(server.ListenAndServe())
   154  	}()
   155  
   156  	log.Info("Starting nginx...")
   157  	log.Fatal(nginx.Run(config.Nginx, map[string]interface{}{
   158  		"port": flags.Port,
   159  		"server": nginx.GetServer(
   160  			config.TrackerServer.Listener.Net, config.TrackerServer.Listener.Addr)},
   161  		nginx.WithTLS(config.TLS)))
   162  }