github.com/uber/kraken@v0.1.4/build-index/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/build-index/tagclient"
    20  	"github.com/uber/kraken/build-index/tagserver"
    21  	"github.com/uber/kraken/build-index/tagstore"
    22  	"github.com/uber/kraken/build-index/tagtype"
    23  	"github.com/uber/kraken/lib/backend"
    24  	"github.com/uber/kraken/lib/healthcheck"
    25  	"github.com/uber/kraken/lib/hostlist"
    26  	"github.com/uber/kraken/lib/persistedretry"
    27  	"github.com/uber/kraken/lib/persistedretry/tagreplication"
    28  	"github.com/uber/kraken/lib/persistedretry/writeback"
    29  	"github.com/uber/kraken/lib/store"
    30  	"github.com/uber/kraken/lib/upstream"
    31  	"github.com/uber/kraken/localdb"
    32  	"github.com/uber/kraken/metrics"
    33  	"github.com/uber/kraken/nginx"
    34  	"github.com/uber/kraken/origin/blobclient"
    35  	"github.com/uber/kraken/utils/configutil"
    36  	"github.com/uber/kraken/utils/log"
    37  
    38  	"github.com/uber-go/tally"
    39  	"go.uber.org/zap"
    40  )
    41  
    42  // Flags defines build-index CLI flags.
    43  type Flags struct {
    44  	Port          int
    45  	ConfigFile    string
    46  	KrakenCluster string
    47  	SecretsFile   string
    48  }
    49  
    50  // ParseFlags parses build-index CLI flags.
    51  func ParseFlags() *Flags {
    52  	var flags Flags
    53  	flag.IntVar(
    54  		&flags.Port, "port", 0, "tag server port")
    55  	flag.StringVar(
    56  		&flags.ConfigFile, "config", "", "configuration file path")
    57  	flag.StringVar(
    58  		&flags.KrakenCluster, "cluster", "", "cluster name (e.g. prod01-zone1)")
    59  	flag.StringVar(
    60  		&flags.SecretsFile, "secrets", "", "path to a secrets YAML file to load into configuration")
    61  	flag.Parse()
    62  	return &flags
    63  }
    64  
    65  type options struct {
    66  	config  *Config
    67  	metrics tally.Scope
    68  	logger  *zap.Logger
    69  }
    70  
    71  // Option defines an optional Run parameter.
    72  type Option func(*options)
    73  
    74  // WithConfig ignores config/secrets flags and directly uses the provided config
    75  // struct.
    76  func WithConfig(c Config) Option {
    77  	return func(o *options) { o.config = &c }
    78  }
    79  
    80  // WithMetrics ignores metrics config and directly uses the provided tally scope.
    81  func WithMetrics(s tally.Scope) Option {
    82  	return func(o *options) { o.metrics = s }
    83  }
    84  
    85  // WithLogger ignores logging config and directly uses the provided logger.
    86  func WithLogger(l *zap.Logger) Option {
    87  	return func(o *options) { o.logger = l }
    88  }
    89  
    90  // Run runs the build-index.
    91  func Run(flags *Flags, opts ...Option) {
    92  	if flags.Port == 0 {
    93  		panic("must specify non-zero port")
    94  	}
    95  
    96  	var overrides options
    97  	for _, o := range opts {
    98  		o(&overrides)
    99  	}
   100  
   101  	var config Config
   102  	if overrides.config != nil {
   103  		config = *overrides.config
   104  	} else {
   105  		if err := configutil.Load(flags.ConfigFile, &config); err != nil {
   106  			panic(err)
   107  		}
   108  		if flags.SecretsFile != "" {
   109  			if err := configutil.Load(flags.SecretsFile, &config); err != nil {
   110  				panic(err)
   111  			}
   112  		}
   113  	}
   114  
   115  	if overrides.logger != nil {
   116  		log.SetGlobalLogger(overrides.logger.Sugar())
   117  	} else {
   118  		zlog := log.ConfigureLogger(config.ZapLogging)
   119  		defer zlog.Sync()
   120  	}
   121  
   122  	stats := overrides.metrics
   123  	if stats == nil {
   124  		s, closer, err := metrics.New(config.Metrics, flags.KrakenCluster)
   125  		if err != nil {
   126  			log.Fatalf("Failed to init metrics: %s", err)
   127  		}
   128  		stats = s
   129  		defer closer.Close()
   130  	}
   131  
   132  	go metrics.EmitVersion(stats)
   133  
   134  	ss, err := store.NewSimpleStore(config.Store, stats)
   135  	if err != nil {
   136  		log.Fatalf("Error creating simple store: %s", err)
   137  	}
   138  
   139  	backends, err := backend.NewManager(config.Backends, config.Auth)
   140  	if err != nil {
   141  		log.Fatalf("Error creating backend manager: %s", err)
   142  	}
   143  
   144  	tls, err := config.TLS.BuildClient()
   145  	if err != nil {
   146  		log.Fatalf("Error building client tls config: %s", err)
   147  	}
   148  
   149  	origins, err := config.Origin.Build(upstream.WithHealthCheck(healthcheck.Default(tls)))
   150  	if err != nil {
   151  		log.Fatalf("Error building origin host list: %s", err)
   152  	}
   153  
   154  	r := blobclient.NewClientResolver(blobclient.NewProvider(blobclient.WithTLS(tls)), origins)
   155  	originClient := blobclient.NewClusterClient(r)
   156  
   157  	localOriginDNS, err := config.Origin.StableAddr()
   158  	if err != nil {
   159  		log.Fatalf("Error getting stable origin addr: %s", err)
   160  	}
   161  
   162  	localDB, err := localdb.New(config.LocalDB)
   163  	if err != nil {
   164  		log.Fatalf("Error creating local db: %s", err)
   165  	}
   166  
   167  	cluster, err := config.Cluster.Build(upstream.WithHealthCheck(healthcheck.Default(tls)))
   168  	if err != nil {
   169  		log.Fatalf("Error building cluster host list: %s", err)
   170  	}
   171  	neighbors, err := hostlist.StripLocal(cluster, flags.Port)
   172  	if err != nil {
   173  		log.Fatalf("Error stripping local machine from cluster list: %s", err)
   174  	}
   175  
   176  	remotes, err := config.Remotes.Build()
   177  	if err != nil {
   178  		log.Fatalf("Error building remotes from configuration: %s", err)
   179  	}
   180  
   181  	tagReplicationExecutor := tagreplication.NewExecutor(
   182  		stats,
   183  		originClient,
   184  		tagclient.NewProvider(tls))
   185  	tagReplicationStore, err := tagreplication.NewStore(localDB, remotes)
   186  	if err != nil {
   187  		log.Fatalf("Error creating tag replication store: %s", err)
   188  	}
   189  	tagReplicationManager, err := persistedretry.NewManager(
   190  		config.TagReplication,
   191  		stats,
   192  		tagReplicationStore,
   193  		tagReplicationExecutor)
   194  	if err != nil {
   195  		log.Fatalf("Error creating tag replication manager: %s", err)
   196  	}
   197  
   198  	writeBackManager, err := persistedretry.NewManager(
   199  		config.WriteBack,
   200  		stats,
   201  		writeback.NewStore(localDB),
   202  		writeback.NewExecutor(stats, ss, backends))
   203  	if err != nil {
   204  		log.Fatalf("Error creating write-back manager: %s", err)
   205  	}
   206  
   207  	tagStore := tagstore.New(config.TagStore, stats, ss, backends, writeBackManager)
   208  
   209  	depResolver, err := tagtype.NewMap(config.TagTypes, originClient)
   210  	if err != nil {
   211  		log.Fatalf("Error creating tag type manager: %s", err)
   212  	}
   213  
   214  	server := tagserver.New(
   215  		config.TagServer,
   216  		stats,
   217  		backends,
   218  		localOriginDNS,
   219  		originClient,
   220  		neighbors,
   221  		tagStore,
   222  		remotes,
   223  		tagReplicationManager,
   224  		tagclient.NewProvider(tls),
   225  		depResolver)
   226  	go func() {
   227  		log.Fatal(server.ListenAndServe())
   228  	}()
   229  
   230  	log.Info("Starting nginx...")
   231  	log.Fatal(nginx.Run(
   232  		config.Nginx,
   233  		map[string]interface{}{
   234  			"port":   flags.Port,
   235  			"server": nginx.GetServer(config.TagServer.Listener.Net, config.TagServer.Listener.Addr),
   236  		},
   237  		nginx.WithTLS(config.TLS)))
   238  }