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 }