github.com/manicqin/nomad@v0.9.5/command/agent/command.go (about) 1 package agent 2 3 import ( 4 "flag" 5 "fmt" 6 "io" 7 "log" 8 "os" 9 "os/signal" 10 "path/filepath" 11 "reflect" 12 "sort" 13 "strconv" 14 "strings" 15 "syscall" 16 "time" 17 18 metrics "github.com/armon/go-metrics" 19 "github.com/armon/go-metrics/circonus" 20 "github.com/armon/go-metrics/datadog" 21 "github.com/armon/go-metrics/prometheus" 22 "github.com/hashicorp/consul/lib" 23 checkpoint "github.com/hashicorp/go-checkpoint" 24 discover "github.com/hashicorp/go-discover" 25 hclog "github.com/hashicorp/go-hclog" 26 gsyslog "github.com/hashicorp/go-syslog" 27 "github.com/hashicorp/logutils" 28 "github.com/hashicorp/nomad/helper" 29 flaghelper "github.com/hashicorp/nomad/helper/flag-helpers" 30 gatedwriter "github.com/hashicorp/nomad/helper/gated-writer" 31 "github.com/hashicorp/nomad/helper/logging" 32 "github.com/hashicorp/nomad/helper/winsvc" 33 "github.com/hashicorp/nomad/nomad/structs/config" 34 "github.com/hashicorp/nomad/version" 35 "github.com/mitchellh/cli" 36 "github.com/posener/complete" 37 ) 38 39 // gracefulTimeout controls how long we wait before forcefully terminating 40 const gracefulTimeout = 5 * time.Second 41 42 // Command is a Command implementation that runs a Nomad agent. 43 // The command will not end unless a shutdown message is sent on the 44 // ShutdownCh. If two messages are sent on the ShutdownCh it will forcibly 45 // exit. 46 type Command struct { 47 Version *version.VersionInfo 48 Ui cli.Ui 49 ShutdownCh <-chan struct{} 50 51 args []string 52 agent *Agent 53 httpServer *HTTPServer 54 logFilter *logutils.LevelFilter 55 logOutput io.Writer 56 retryJoinErrCh chan struct{} 57 } 58 59 func (c *Command) readConfig() *Config { 60 var dev *devModeConfig 61 var configPath []string 62 var servers string 63 var meta []string 64 65 // Make a new, empty config. 66 cmdConfig := &Config{ 67 Client: &ClientConfig{}, 68 Consul: &config.ConsulConfig{}, 69 Ports: &Ports{}, 70 Server: &ServerConfig{ 71 ServerJoin: &ServerJoin{}, 72 }, 73 Vault: &config.VaultConfig{}, 74 ACL: &ACLConfig{}, 75 } 76 77 flags := flag.NewFlagSet("agent", flag.ContinueOnError) 78 flags.Usage = func() { c.Ui.Error(c.Help()) } 79 80 // Role options 81 var devMode bool 82 var devConnectMode bool 83 flags.BoolVar(&devMode, "dev", false, "") 84 flags.BoolVar(&devConnectMode, "dev-connect", false, "") 85 flags.BoolVar(&cmdConfig.Server.Enabled, "server", false, "") 86 flags.BoolVar(&cmdConfig.Client.Enabled, "client", false, "") 87 88 // Server-only options 89 flags.IntVar(&cmdConfig.Server.BootstrapExpect, "bootstrap-expect", 0, "") 90 flags.StringVar(&cmdConfig.Server.EncryptKey, "encrypt", "", "gossip encryption key") 91 flags.IntVar(&cmdConfig.Server.RaftProtocol, "raft-protocol", 0, "") 92 flags.BoolVar(&cmdConfig.Server.RejoinAfterLeave, "rejoin", false, "") 93 flags.Var((*flaghelper.StringFlag)(&cmdConfig.Server.ServerJoin.StartJoin), "join", "") 94 flags.Var((*flaghelper.StringFlag)(&cmdConfig.Server.ServerJoin.RetryJoin), "retry-join", "") 95 flags.IntVar(&cmdConfig.Server.ServerJoin.RetryMaxAttempts, "retry-max", 0, "") 96 flags.Var((flaghelper.FuncDurationVar)(func(d time.Duration) error { 97 cmdConfig.Server.ServerJoin.RetryInterval = d 98 return nil 99 }), "retry-interval", "") 100 101 // Client-only options 102 flags.StringVar(&cmdConfig.Client.StateDir, "state-dir", "", "") 103 flags.StringVar(&cmdConfig.Client.AllocDir, "alloc-dir", "", "") 104 flags.StringVar(&cmdConfig.Client.NodeClass, "node-class", "", "") 105 flags.StringVar(&cmdConfig.Client.Token, "token", "", "") 106 flags.StringVar(&servers, "servers", "", "") 107 flags.Var((*flaghelper.StringFlag)(&meta), "meta", "") 108 flags.StringVar(&cmdConfig.Client.NetworkInterface, "network-interface", "", "") 109 flags.IntVar(&cmdConfig.Client.NetworkSpeed, "network-speed", 0, "") 110 111 // General options 112 flags.Var((*flaghelper.StringFlag)(&configPath), "config", "config") 113 flags.StringVar(&cmdConfig.BindAddr, "bind", "", "") 114 flags.StringVar(&cmdConfig.Region, "region", "", "") 115 flags.StringVar(&cmdConfig.DataDir, "data-dir", "", "") 116 flags.StringVar(&cmdConfig.PluginDir, "plugin-dir", "", "") 117 flags.StringVar(&cmdConfig.Datacenter, "dc", "", "") 118 flags.StringVar(&cmdConfig.LogLevel, "log-level", "", "") 119 flags.BoolVar(&cmdConfig.LogJson, "log-json", false, "") 120 flags.StringVar(&cmdConfig.NodeName, "node", "", "") 121 122 // Consul options 123 flags.StringVar(&cmdConfig.Consul.Auth, "consul-auth", "", "") 124 flags.Var((flaghelper.FuncBoolVar)(func(b bool) error { 125 cmdConfig.Consul.AutoAdvertise = &b 126 return nil 127 }), "consul-auto-advertise", "") 128 flags.StringVar(&cmdConfig.Consul.CAFile, "consul-ca-file", "", "") 129 flags.StringVar(&cmdConfig.Consul.CertFile, "consul-cert-file", "", "") 130 flags.StringVar(&cmdConfig.Consul.KeyFile, "consul-key-file", "", "") 131 flags.Var((flaghelper.FuncBoolVar)(func(b bool) error { 132 cmdConfig.Consul.ChecksUseAdvertise = &b 133 return nil 134 }), "consul-checks-use-advertise", "") 135 flags.Var((flaghelper.FuncBoolVar)(func(b bool) error { 136 cmdConfig.Consul.ClientAutoJoin = &b 137 return nil 138 }), "consul-client-auto-join", "") 139 flags.StringVar(&cmdConfig.Consul.ClientServiceName, "consul-client-service-name", "", "") 140 flags.StringVar(&cmdConfig.Consul.ClientHTTPCheckName, "consul-client-http-check-name", "", "") 141 flags.StringVar(&cmdConfig.Consul.ServerServiceName, "consul-server-service-name", "", "") 142 flags.StringVar(&cmdConfig.Consul.ServerHTTPCheckName, "consul-server-http-check-name", "", "") 143 flags.StringVar(&cmdConfig.Consul.ServerSerfCheckName, "consul-server-serf-check-name", "", "") 144 flags.StringVar(&cmdConfig.Consul.ServerRPCCheckName, "consul-server-rpc-check-name", "", "") 145 flags.Var((flaghelper.FuncBoolVar)(func(b bool) error { 146 cmdConfig.Consul.ServerAutoJoin = &b 147 return nil 148 }), "consul-server-auto-join", "") 149 flags.Var((flaghelper.FuncBoolVar)(func(b bool) error { 150 cmdConfig.Consul.EnableSSL = &b 151 return nil 152 }), "consul-ssl", "") 153 flags.StringVar(&cmdConfig.Consul.Token, "consul-token", "", "") 154 flags.Var((flaghelper.FuncBoolVar)(func(b bool) error { 155 cmdConfig.Consul.VerifySSL = &b 156 return nil 157 }), "consul-verify-ssl", "") 158 flags.StringVar(&cmdConfig.Consul.Addr, "consul-address", "", "") 159 160 // Vault options 161 flags.Var((flaghelper.FuncBoolVar)(func(b bool) error { 162 cmdConfig.Vault.Enabled = &b 163 return nil 164 }), "vault-enabled", "") 165 flags.Var((flaghelper.FuncBoolVar)(func(b bool) error { 166 cmdConfig.Vault.AllowUnauthenticated = &b 167 return nil 168 }), "vault-allow-unauthenticated", "") 169 flags.StringVar(&cmdConfig.Vault.Token, "vault-token", "", "") 170 flags.StringVar(&cmdConfig.Vault.Addr, "vault-address", "", "") 171 flags.StringVar(&cmdConfig.Vault.Namespace, "vault-namespace", "", "") 172 flags.StringVar(&cmdConfig.Vault.Role, "vault-create-from-role", "", "") 173 flags.StringVar(&cmdConfig.Vault.TLSCaFile, "vault-ca-file", "", "") 174 flags.StringVar(&cmdConfig.Vault.TLSCaPath, "vault-ca-path", "", "") 175 flags.StringVar(&cmdConfig.Vault.TLSCertFile, "vault-cert-file", "", "") 176 flags.StringVar(&cmdConfig.Vault.TLSKeyFile, "vault-key-file", "", "") 177 flags.Var((flaghelper.FuncBoolVar)(func(b bool) error { 178 cmdConfig.Vault.TLSSkipVerify = &b 179 return nil 180 }), "vault-tls-skip-verify", "") 181 flags.StringVar(&cmdConfig.Vault.TLSServerName, "vault-tls-server-name", "", "") 182 183 // ACL options 184 flags.BoolVar(&cmdConfig.ACL.Enabled, "acl-enabled", false, "") 185 flags.StringVar(&cmdConfig.ACL.ReplicationToken, "acl-replication-token", "", "") 186 187 if err := flags.Parse(c.args); err != nil { 188 return nil 189 } 190 191 // Split the servers. 192 if servers != "" { 193 cmdConfig.Client.Servers = strings.Split(servers, ",") 194 } 195 196 // Parse the meta flags. 197 metaLength := len(meta) 198 if metaLength != 0 { 199 cmdConfig.Client.Meta = make(map[string]string, metaLength) 200 for _, kv := range meta { 201 parts := strings.SplitN(kv, "=", 2) 202 if len(parts) != 2 { 203 c.Ui.Error(fmt.Sprintf("Error parsing Client.Meta value: %v", kv)) 204 return nil 205 } 206 cmdConfig.Client.Meta[parts[0]] = parts[1] 207 } 208 } 209 210 // Load the configuration 211 dev, err := newDevModeConfig(devMode, devConnectMode) 212 if err != nil { 213 c.Ui.Error(err.Error()) 214 return nil 215 } 216 var config *Config 217 if dev != nil { 218 config = DevConfig(dev) 219 } else { 220 config = DefaultConfig() 221 } 222 223 // Merge in the enterprise overlay 224 config.Merge(DefaultEntConfig()) 225 226 for _, path := range configPath { 227 current, err := LoadConfig(path) 228 if err != nil { 229 c.Ui.Error(fmt.Sprintf( 230 "Error loading configuration from %s: %s", path, err)) 231 return nil 232 } 233 234 // The user asked us to load some config here but we didn't find any, 235 // so we'll complain but continue. 236 if current == nil || reflect.DeepEqual(current, &Config{}) { 237 c.Ui.Warn(fmt.Sprintf("No configuration loaded from %s", path)) 238 } 239 240 if config == nil { 241 config = current 242 } else { 243 config = config.Merge(current) 244 } 245 } 246 247 // Ensure the sub-structs at least exist 248 if config.Client == nil { 249 config.Client = &ClientConfig{} 250 } 251 if config.Server == nil { 252 config.Server = &ServerConfig{} 253 } 254 255 // Merge any CLI options over config file options 256 config = config.Merge(cmdConfig) 257 258 // Set the version info 259 config.Version = c.Version 260 261 // Normalize binds, ports, addresses, and advertise 262 if err := config.normalizeAddrs(); err != nil { 263 c.Ui.Error(err.Error()) 264 return nil 265 } 266 267 // Check to see if we should read the Vault token from the environment 268 if config.Vault.Token == "" { 269 config.Vault.Token = os.Getenv("VAULT_TOKEN") 270 } 271 272 // Check to see if we should read the Vault namespace from the environment 273 if config.Vault.Namespace == "" { 274 config.Vault.Namespace = os.Getenv("VAULT_NAMESPACE") 275 } 276 277 // Default the plugin directory to be under that of the data directory if it 278 // isn't explicitly specified. 279 if config.PluginDir == "" && config.DataDir != "" { 280 config.PluginDir = filepath.Join(config.DataDir, "plugins") 281 } 282 283 if !c.isValidConfig(config, cmdConfig) { 284 return nil 285 } 286 287 return config 288 } 289 290 func (c *Command) isValidConfig(config, cmdConfig *Config) bool { 291 292 // Check that the server is running in at least one mode. 293 if !(config.Server.Enabled || config.Client.Enabled) { 294 c.Ui.Error("Must specify either server, client or dev mode for the agent.") 295 return false 296 } 297 298 // Set up the TLS configuration properly if we have one. 299 // XXX chelseakomlo: set up a TLSConfig New method which would wrap 300 // constructor-type actions like this. 301 if config.TLSConfig != nil && !config.TLSConfig.IsEmpty() { 302 if err := config.TLSConfig.SetChecksum(); err != nil { 303 c.Ui.Error(fmt.Sprintf("WARNING: Error when parsing TLS configuration: %v", err)) 304 } 305 } 306 307 if config.Server.EncryptKey != "" { 308 if _, err := config.Server.EncryptBytes(); err != nil { 309 c.Ui.Error(fmt.Sprintf("Invalid encryption key: %s", err)) 310 return false 311 } 312 keyfile := filepath.Join(config.DataDir, serfKeyring) 313 if _, err := os.Stat(keyfile); err == nil { 314 c.Ui.Warn("WARNING: keyring exists but -encrypt given, using keyring") 315 } 316 } 317 318 // Verify the paths are absolute. 319 dirs := map[string]string{ 320 "data-dir": config.DataDir, 321 "plugin-dir": config.PluginDir, 322 "alloc-dir": config.Client.AllocDir, 323 "state-dir": config.Client.StateDir, 324 } 325 for k, dir := range dirs { 326 if dir == "" { 327 continue 328 } 329 330 if !filepath.IsAbs(dir) { 331 c.Ui.Error(fmt.Sprintf("%s must be given as an absolute path: got %v", k, dir)) 332 return false 333 } 334 } 335 336 if config.Client.Enabled { 337 for k := range config.Client.Meta { 338 if !helper.IsValidInterpVariable(k) { 339 c.Ui.Error(fmt.Sprintf("Invalid Client.Meta key: %v", k)) 340 return false 341 } 342 } 343 } 344 345 if config.DevMode { 346 // Skip the rest of the validation for dev mode 347 return true 348 } 349 350 // Ensure that we have the directories we need to run. 351 if config.Server.Enabled && config.DataDir == "" { 352 c.Ui.Error("Must specify data directory") 353 return false 354 } 355 356 // The config is valid if the top-level data-dir is set or if both 357 // alloc-dir and state-dir are set. 358 if config.Client.Enabled && config.DataDir == "" { 359 if config.Client.AllocDir == "" || config.Client.StateDir == "" || config.PluginDir == "" { 360 c.Ui.Error("Must specify the state, alloc dir, and plugin dir if data-dir is omitted.") 361 return false 362 } 363 } 364 365 // Check the bootstrap flags 366 if !config.Server.Enabled && cmdConfig.Server.BootstrapExpect > 0 { 367 // report an error if BootstrapExpect is set in CLI but server is disabled 368 c.Ui.Error("Bootstrap requires server mode to be enabled") 369 return false 370 } 371 if config.Server.Enabled && config.Server.BootstrapExpect == 1 { 372 c.Ui.Error("WARNING: Bootstrap mode enabled! Potentially unsafe operation.") 373 } 374 375 return true 376 } 377 378 // setupLoggers is used to setup the logGate, and our logOutput 379 func (c *Command) setupLoggers(config *Config) (*gatedwriter.Writer, io.Writer) { 380 // Setup logging. First create the gated log writer, which will 381 // store logs until we're ready to show them. Then create the level 382 // filter, filtering logs of the specified level. 383 logGate := &gatedwriter.Writer{ 384 Writer: &cli.UiWriter{Ui: c.Ui}, 385 } 386 387 c.logFilter = LevelFilter() 388 c.logFilter.MinLevel = logutils.LogLevel(strings.ToUpper(config.LogLevel)) 389 c.logFilter.Writer = logGate 390 if !ValidateLevelFilter(c.logFilter.MinLevel, c.logFilter) { 391 c.Ui.Error(fmt.Sprintf( 392 "Invalid log level: %s. Valid log levels are: %v", 393 c.logFilter.MinLevel, c.logFilter.Levels)) 394 return nil, nil 395 } 396 397 // Create a log writer, and wrap a logOutput around it 398 writers := []io.Writer{c.logFilter} 399 400 // Check if syslog is enabled 401 if config.EnableSyslog { 402 l, err := gsyslog.NewLogger(gsyslog.LOG_NOTICE, config.SyslogFacility, "nomad") 403 if err != nil { 404 c.Ui.Error(fmt.Sprintf("Syslog setup failed: %v", err)) 405 return nil, nil 406 } 407 writers = append(writers, &SyslogWrapper{l, c.logFilter}) 408 } 409 410 // Check if file logging is enabled 411 if config.LogFile != "" { 412 dir, fileName := filepath.Split(config.LogFile) 413 414 // if a path is provided, but has no filename, then a default is used. 415 if fileName == "" { 416 fileName = "nomad.log" 417 } 418 419 // Try to enter the user specified log rotation duration first 420 var logRotateDuration time.Duration 421 if config.LogRotateDuration != "" { 422 duration, err := time.ParseDuration(config.LogRotateDuration) 423 if err != nil { 424 c.Ui.Error(fmt.Sprintf("Failed to parse log rotation duration: %v", err)) 425 return nil, nil 426 } 427 logRotateDuration = duration 428 } else { 429 // Default to 24 hrs if no rotation period is specified 430 logRotateDuration = 24 * time.Hour 431 } 432 433 logFile := &logFile{ 434 logFilter: c.logFilter, 435 fileName: fileName, 436 logPath: dir, 437 duration: logRotateDuration, 438 MaxBytes: config.LogRotateBytes, 439 MaxFiles: config.LogRotateMaxFiles, 440 } 441 442 writers = append(writers, logFile) 443 } 444 445 c.logOutput = io.MultiWriter(writers...) 446 log.SetOutput(c.logOutput) 447 return logGate, c.logOutput 448 } 449 450 // setupAgent is used to start the agent and various interfaces 451 func (c *Command) setupAgent(config *Config, logger hclog.InterceptLogger, logOutput io.Writer, inmem *metrics.InmemSink) error { 452 c.Ui.Output("Starting Nomad agent...") 453 agent, err := NewAgent(config, logger, logOutput, inmem) 454 if err != nil { 455 c.Ui.Error(fmt.Sprintf("Error starting agent: %s", err)) 456 return err 457 } 458 c.agent = agent 459 460 // Setup the HTTP server 461 http, err := NewHTTPServer(agent, config) 462 if err != nil { 463 agent.Shutdown() 464 c.Ui.Error(fmt.Sprintf("Error starting http server: %s", err)) 465 return err 466 } 467 c.httpServer = http 468 469 // If DisableUpdateCheck is not enabled, set up update checking 470 // (DisableUpdateCheck is false by default) 471 if config.DisableUpdateCheck != nil && !*config.DisableUpdateCheck { 472 version := config.Version.Version 473 if config.Version.VersionPrerelease != "" { 474 version += fmt.Sprintf("-%s", config.Version.VersionPrerelease) 475 } 476 updateParams := &checkpoint.CheckParams{ 477 Product: "nomad", 478 Version: version, 479 } 480 if !config.DisableAnonymousSignature { 481 updateParams.SignatureFile = filepath.Join(config.DataDir, "checkpoint-signature") 482 } 483 484 // Schedule a periodic check with expected interval of 24 hours 485 checkpoint.CheckInterval(updateParams, 24*time.Hour, c.checkpointResults) 486 487 // Do an immediate check within the next 30 seconds 488 go func() { 489 time.Sleep(lib.RandomStagger(30 * time.Second)) 490 c.checkpointResults(checkpoint.Check(updateParams)) 491 }() 492 } 493 494 return nil 495 } 496 497 // checkpointResults is used to handler periodic results from our update checker 498 func (c *Command) checkpointResults(results *checkpoint.CheckResponse, err error) { 499 if err != nil { 500 c.Ui.Error(fmt.Sprintf("Failed to check for updates: %v", err)) 501 return 502 } 503 if results.Outdated { 504 c.Ui.Error(fmt.Sprintf("Newer Nomad version available: %s (currently running: %s)", results.CurrentVersion, c.Version.VersionNumber())) 505 } 506 for _, alert := range results.Alerts { 507 switch alert.Level { 508 case "info": 509 c.Ui.Info(fmt.Sprintf("Bulletin [%s]: %s (%s)", alert.Level, alert.Message, alert.URL)) 510 default: 511 c.Ui.Error(fmt.Sprintf("Bulletin [%s]: %s (%s)", alert.Level, alert.Message, alert.URL)) 512 } 513 } 514 } 515 516 func (c *Command) AutocompleteFlags() complete.Flags { 517 configFilePredictor := complete.PredictOr( 518 complete.PredictFiles("*.json"), 519 complete.PredictFiles("*.hcl")) 520 521 return map[string]complete.Predictor{ 522 "-dev": complete.PredictNothing, 523 "-dev-connect": complete.PredictNothing, 524 "-server": complete.PredictNothing, 525 "-client": complete.PredictNothing, 526 "-bootstrap-expect": complete.PredictAnything, 527 "-encrypt": complete.PredictAnything, 528 "-raft-protocol": complete.PredictAnything, 529 "-rejoin": complete.PredictNothing, 530 "-join": complete.PredictAnything, 531 "-retry-join": complete.PredictAnything, 532 "-retry-max": complete.PredictAnything, 533 "-state-dir": complete.PredictDirs("*"), 534 "-alloc-dir": complete.PredictDirs("*"), 535 "-node-class": complete.PredictAnything, 536 "-servers": complete.PredictAnything, 537 "-meta": complete.PredictAnything, 538 "-config": configFilePredictor, 539 "-bind": complete.PredictAnything, 540 "-region": complete.PredictAnything, 541 "-data-dir": complete.PredictDirs("*"), 542 "-plugin-dir": complete.PredictDirs("*"), 543 "-dc": complete.PredictAnything, 544 "-log-level": complete.PredictAnything, 545 "-json-logs": complete.PredictNothing, 546 "-node": complete.PredictAnything, 547 "-consul-auth": complete.PredictAnything, 548 "-consul-auto-advertise": complete.PredictNothing, 549 "-consul-ca-file": complete.PredictAnything, 550 "-consul-cert-file": complete.PredictAnything, 551 "-consul-key-file": complete.PredictAnything, 552 "-consul-checks-use-advertise": complete.PredictNothing, 553 "-consul-client-auto-join": complete.PredictNothing, 554 "-consul-client-service-name": complete.PredictAnything, 555 "-consul-client-http-check-name": complete.PredictAnything, 556 "-consul-server-service-name": complete.PredictAnything, 557 "-consul-server-http-check-name": complete.PredictAnything, 558 "-consul-server-serf-check-name": complete.PredictAnything, 559 "-consul-server-rpc-check-name": complete.PredictAnything, 560 "-consul-server-auto-join": complete.PredictNothing, 561 "-consul-ssl": complete.PredictNothing, 562 "-consul-verify-ssl": complete.PredictNothing, 563 "-consul-address": complete.PredictAnything, 564 "-vault-enabled": complete.PredictNothing, 565 "-vault-allow-unauthenticated": complete.PredictNothing, 566 "-vault-token": complete.PredictAnything, 567 "-vault-address": complete.PredictAnything, 568 "-vault-create-from-role": complete.PredictAnything, 569 "-vault-ca-file": complete.PredictAnything, 570 "-vault-ca-path": complete.PredictAnything, 571 "-vault-cert-file": complete.PredictAnything, 572 "-vault-key-file": complete.PredictAnything, 573 "-vault-tls-skip-verify": complete.PredictNothing, 574 "-vault-tls-server-name": complete.PredictAnything, 575 "-acl-enabled": complete.PredictNothing, 576 "-acl-replication-token": complete.PredictAnything, 577 } 578 } 579 580 func (c *Command) AutocompleteArgs() complete.Predictor { 581 return nil 582 } 583 584 func (c *Command) Run(args []string) int { 585 c.Ui = &cli.PrefixedUi{ 586 OutputPrefix: "==> ", 587 InfoPrefix: " ", 588 ErrorPrefix: "==> ", 589 Ui: c.Ui, 590 } 591 592 // Parse our configs 593 c.args = args 594 config := c.readConfig() 595 if config == nil { 596 return 1 597 } 598 599 // Setup the log outputs 600 logGate, logOutput := c.setupLoggers(config) 601 if logGate == nil { 602 return 1 603 } 604 605 // Create logger 606 logger := hclog.NewInterceptLogger(&hclog.LoggerOptions{ 607 Name: "agent", 608 Level: hclog.LevelFromString(config.LogLevel), 609 Output: logOutput, 610 JSONFormat: config.LogJson, 611 }) 612 613 // Swap out UI implementation if json logging is enabled 614 if config.LogJson { 615 c.Ui = &logging.HcLogUI{Log: logger} 616 } 617 618 // Log config files 619 if len(config.Files) > 0 { 620 c.Ui.Output(fmt.Sprintf("Loaded configuration from %s", strings.Join(config.Files, ", "))) 621 } else { 622 c.Ui.Output("No configuration files loaded") 623 } 624 625 // Initialize the telemetry 626 inmem, err := c.setupTelemetry(config) 627 if err != nil { 628 c.Ui.Error(fmt.Sprintf("Error initializing telemetry: %s", err)) 629 return 1 630 } 631 632 // Create the agent 633 if err := c.setupAgent(config, logger, logOutput, inmem); err != nil { 634 logGate.Flush() 635 return 1 636 } 637 defer c.agent.Shutdown() 638 639 // Shutdown the HTTP server at the end 640 defer func() { 641 if c.httpServer != nil { 642 c.httpServer.Shutdown() 643 } 644 }() 645 646 // Join startup nodes if specified 647 if err := c.startupJoin(config); err != nil { 648 c.Ui.Error(err.Error()) 649 return 1 650 } 651 652 // Compile agent information for output later 653 info := make(map[string]string) 654 info["version"] = config.Version.VersionNumber() 655 info["client"] = strconv.FormatBool(config.Client.Enabled) 656 info["log level"] = config.LogLevel 657 info["server"] = strconv.FormatBool(config.Server.Enabled) 658 info["region"] = fmt.Sprintf("%s (DC: %s)", config.Region, config.Datacenter) 659 info["bind addrs"] = c.getBindAddrSynopsis() 660 info["advertise addrs"] = c.getAdvertiseAddrSynopsis() 661 662 // Sort the keys for output 663 infoKeys := make([]string, 0, len(info)) 664 for key := range info { 665 infoKeys = append(infoKeys, key) 666 } 667 sort.Strings(infoKeys) 668 669 // Agent configuration output 670 padding := 18 671 c.Ui.Output("Nomad agent configuration:\n") 672 for _, k := range infoKeys { 673 c.Ui.Info(fmt.Sprintf( 674 "%s%s: %s", 675 strings.Repeat(" ", padding-len(k)), 676 strings.Title(k), 677 info[k])) 678 } 679 c.Ui.Output("") 680 681 // Output the header that the server has started 682 c.Ui.Output("Nomad agent started! Log data will stream in below:\n") 683 684 // Enable log streaming 685 logGate.Flush() 686 687 // Start retry join process 688 if err := c.handleRetryJoin(config); err != nil { 689 c.Ui.Error(err.Error()) 690 return 1 691 } 692 693 // Wait for exit 694 return c.handleSignals() 695 } 696 697 // handleRetryJoin is used to start retry joining if it is configured. 698 func (c *Command) handleRetryJoin(config *Config) error { 699 c.retryJoinErrCh = make(chan struct{}) 700 701 if config.Server.Enabled && len(config.Server.RetryJoin) != 0 { 702 joiner := retryJoiner{ 703 discover: &discover.Discover{}, 704 errCh: c.retryJoinErrCh, 705 logger: c.agent.logger.Named("joiner"), 706 serverJoin: c.agent.server.Join, 707 serverEnabled: true, 708 } 709 710 if err := joiner.Validate(config); err != nil { 711 return err 712 } 713 714 // Remove the duplicate fields 715 if len(config.Server.RetryJoin) != 0 { 716 config.Server.ServerJoin.RetryJoin = config.Server.RetryJoin 717 config.Server.RetryJoin = nil 718 } 719 if config.Server.RetryMaxAttempts != 0 { 720 config.Server.ServerJoin.RetryMaxAttempts = config.Server.RetryMaxAttempts 721 config.Server.RetryMaxAttempts = 0 722 } 723 if config.Server.RetryInterval != 0 { 724 config.Server.ServerJoin.RetryInterval = config.Server.RetryInterval 725 config.Server.RetryInterval = 0 726 } 727 728 c.agent.logger.Warn("using deprecated retry_join fields. Upgrade configuration to use server_join") 729 } 730 731 if config.Server.Enabled && 732 config.Server.ServerJoin != nil && 733 len(config.Server.ServerJoin.RetryJoin) != 0 { 734 735 joiner := retryJoiner{ 736 discover: &discover.Discover{}, 737 errCh: c.retryJoinErrCh, 738 logger: c.agent.logger.Named("joiner"), 739 serverJoin: c.agent.server.Join, 740 serverEnabled: true, 741 } 742 743 if err := joiner.Validate(config); err != nil { 744 return err 745 } 746 747 go joiner.RetryJoin(config.Server.ServerJoin) 748 } 749 750 if config.Client.Enabled && 751 config.Client.ServerJoin != nil && 752 len(config.Client.ServerJoin.RetryJoin) != 0 { 753 joiner := retryJoiner{ 754 discover: &discover.Discover{}, 755 errCh: c.retryJoinErrCh, 756 logger: c.agent.logger.Named("joiner"), 757 clientJoin: c.agent.client.SetServers, 758 clientEnabled: true, 759 } 760 761 if err := joiner.Validate(config); err != nil { 762 return err 763 } 764 765 go joiner.RetryJoin(config.Client.ServerJoin) 766 } 767 768 return nil 769 } 770 771 // handleSignals blocks until we get an exit-causing signal 772 func (c *Command) handleSignals() int { 773 signalCh := make(chan os.Signal, 4) 774 signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGPIPE) 775 776 // Wait for a signal 777 WAIT: 778 var sig os.Signal 779 select { 780 case s := <-signalCh: 781 sig = s 782 case <-winsvc.ShutdownChannel(): 783 sig = os.Interrupt 784 case <-c.ShutdownCh: 785 sig = os.Interrupt 786 case <-c.retryJoinErrCh: 787 return 1 788 } 789 790 // Skip any SIGPIPE signal and don't try to log it (See issues #1798, #3554) 791 if sig == syscall.SIGPIPE { 792 goto WAIT 793 } 794 795 c.Ui.Output(fmt.Sprintf("Caught signal: %v", sig)) 796 797 // Check if this is a SIGHUP 798 if sig == syscall.SIGHUP { 799 c.handleReload() 800 goto WAIT 801 } 802 803 // Check if we should do a graceful leave 804 graceful := false 805 if sig == os.Interrupt && c.agent.GetConfig().LeaveOnInt { 806 graceful = true 807 } else if sig == syscall.SIGTERM && c.agent.GetConfig().LeaveOnTerm { 808 graceful = true 809 } 810 811 // Bail fast if not doing a graceful leave 812 if !graceful { 813 return 1 814 } 815 816 // Attempt a graceful leave 817 gracefulCh := make(chan struct{}) 818 c.Ui.Output("Gracefully shutting down agent...") 819 go func() { 820 if err := c.agent.Leave(); err != nil { 821 c.Ui.Error(fmt.Sprintf("Error: %s", err)) 822 return 823 } 824 close(gracefulCh) 825 }() 826 827 // Wait for leave or another signal 828 select { 829 case <-signalCh: 830 return 1 831 case <-time.After(gracefulTimeout): 832 return 1 833 case <-gracefulCh: 834 return 0 835 } 836 } 837 838 // reloadHTTPServer shuts down the existing HTTP server and restarts it. This 839 // is helpful when reloading the agent configuration. 840 func (c *Command) reloadHTTPServer() error { 841 c.agent.logger.Info("reloading HTTP server with new TLS configuration") 842 843 c.httpServer.Shutdown() 844 845 http, err := NewHTTPServer(c.agent, c.agent.config) 846 if err != nil { 847 return err 848 } 849 c.httpServer = http 850 851 return nil 852 } 853 854 // handleReload is invoked when we should reload our configs, e.g. SIGHUP 855 func (c *Command) handleReload() { 856 c.Ui.Output("Reloading configuration...") 857 newConf := c.readConfig() 858 if newConf == nil { 859 c.Ui.Error(fmt.Sprintf("Failed to reload configs")) 860 return 861 } 862 863 // Change the log level 864 minLevel := logutils.LogLevel(strings.ToUpper(newConf.LogLevel)) 865 if ValidateLevelFilter(minLevel, c.logFilter) { 866 c.logFilter.SetMinLevel(minLevel) 867 } else { 868 c.Ui.Error(fmt.Sprintf( 869 "Invalid log level: %s. Valid log levels are: %v", 870 minLevel, c.logFilter.Levels)) 871 872 // Keep the current log level 873 newConf.LogLevel = c.agent.GetConfig().LogLevel 874 } 875 876 shouldReloadAgent, shouldReloadHTTP := c.agent.ShouldReload(newConf) 877 if shouldReloadAgent { 878 c.agent.logger.Debug("starting reload of agent config") 879 err := c.agent.Reload(newConf) 880 if err != nil { 881 c.agent.logger.Error("failed to reload the config", "error", err) 882 return 883 } 884 } 885 886 if s := c.agent.Server(); s != nil { 887 c.agent.logger.Debug("starting reload of server config") 888 sconf, err := convertServerConfig(newConf) 889 if err != nil { 890 c.agent.logger.Error("failed to convert server config", "error", err) 891 return 892 } 893 894 // Finalize the config to get the agent objects injected in 895 c.agent.finalizeServerConfig(sconf) 896 897 // Reload the config 898 if err := s.Reload(sconf); err != nil { 899 c.agent.logger.Error("reloading server config failed", "error", err) 900 return 901 } 902 } 903 904 if s := c.agent.Client(); s != nil { 905 c.agent.logger.Debug("starting reload of client config") 906 clientConfig, err := convertClientConfig(newConf) 907 if err != nil { 908 c.agent.logger.Error("failed to convert client config", "error", err) 909 return 910 } 911 912 // Finalize the config to get the agent objects injected in 913 if err := c.agent.finalizeClientConfig(clientConfig); err != nil { 914 c.agent.logger.Error("failed to finalize client config", "error", err) 915 return 916 } 917 918 if err := c.agent.Client().Reload(clientConfig); err != nil { 919 c.agent.logger.Error("reloading client config failed", "error", err) 920 return 921 } 922 } 923 924 // reload HTTP server after we have reloaded both client and server, in case 925 // we error in either of the above cases. For example, reloading the http 926 // server to a TLS connection could succeed, while reloading the server's rpc 927 // connections could fail. 928 if shouldReloadHTTP { 929 err := c.reloadHTTPServer() 930 if err != nil { 931 c.agent.httpLogger.Error("reloading config failed", "error", err) 932 return 933 } 934 } 935 } 936 937 // setupTelemetry is used ot setup the telemetry sub-systems 938 func (c *Command) setupTelemetry(config *Config) (*metrics.InmemSink, error) { 939 /* Setup telemetry 940 Aggregate on 10 second intervals for 1 minute. Expose the 941 metrics over stderr when there is a SIGUSR1 received. 942 */ 943 inm := metrics.NewInmemSink(10*time.Second, time.Minute) 944 metrics.DefaultInmemSignal(inm) 945 946 var telConfig *Telemetry 947 if config.Telemetry == nil { 948 telConfig = &Telemetry{} 949 } else { 950 telConfig = config.Telemetry 951 } 952 953 metricsConf := metrics.DefaultConfig("nomad") 954 metricsConf.EnableHostname = !telConfig.DisableHostname 955 956 // Prefer the hostname as a label. 957 metricsConf.EnableHostnameLabel = !telConfig.DisableHostname && 958 !telConfig.DisableTaggedMetrics && !telConfig.BackwardsCompatibleMetrics 959 960 if telConfig.UseNodeName { 961 metricsConf.HostName = config.NodeName 962 metricsConf.EnableHostname = true 963 } 964 965 allowedPrefixes, blockedPrefixes, err := telConfig.PrefixFilters() 966 if err != nil { 967 return inm, err 968 } 969 970 metricsConf.AllowedPrefixes = allowedPrefixes 971 metricsConf.BlockedPrefixes = blockedPrefixes 972 973 if telConfig.FilterDefault != nil { 974 metricsConf.FilterDefault = *telConfig.FilterDefault 975 } 976 977 // Configure the statsite sink 978 var fanout metrics.FanoutSink 979 if telConfig.StatsiteAddr != "" { 980 sink, err := metrics.NewStatsiteSink(telConfig.StatsiteAddr) 981 if err != nil { 982 return inm, err 983 } 984 fanout = append(fanout, sink) 985 } 986 987 // Configure the statsd sink 988 if telConfig.StatsdAddr != "" { 989 sink, err := metrics.NewStatsdSink(telConfig.StatsdAddr) 990 if err != nil { 991 return inm, err 992 } 993 fanout = append(fanout, sink) 994 } 995 996 // Configure the prometheus sink 997 if telConfig.PrometheusMetrics { 998 promSink, err := prometheus.NewPrometheusSink() 999 if err != nil { 1000 return inm, err 1001 } 1002 fanout = append(fanout, promSink) 1003 } 1004 1005 // Configure the prometheus pushserver sink 1006 if telConfig.PrometheusPushAddr != "" { 1007 nodeName := config.NodeName 1008 if nodeName == "" { 1009 nodeName = "nomad" 1010 } 1011 sink, err := prometheus.NewPrometheusPushSink(telConfig.PrometheusPushAddr, 1012 telConfig.prometheusPushInterval, nodeName) 1013 if err != nil { 1014 return inm, err 1015 } 1016 fanout = append(fanout, sink) 1017 } 1018 1019 // Configure the datadog sink 1020 if telConfig.DataDogAddr != "" { 1021 sink, err := datadog.NewDogStatsdSink(telConfig.DataDogAddr, config.NodeName) 1022 if err != nil { 1023 return inm, err 1024 } 1025 sink.SetTags(telConfig.DataDogTags) 1026 fanout = append(fanout, sink) 1027 } 1028 1029 // Configure the Circonus sink 1030 if telConfig.CirconusAPIToken != "" || telConfig.CirconusCheckSubmissionURL != "" { 1031 cfg := &circonus.Config{} 1032 cfg.Interval = telConfig.CirconusSubmissionInterval 1033 cfg.CheckManager.API.TokenKey = telConfig.CirconusAPIToken 1034 cfg.CheckManager.API.TokenApp = telConfig.CirconusAPIApp 1035 cfg.CheckManager.API.URL = telConfig.CirconusAPIURL 1036 cfg.CheckManager.Check.SubmissionURL = telConfig.CirconusCheckSubmissionURL 1037 cfg.CheckManager.Check.ID = telConfig.CirconusCheckID 1038 cfg.CheckManager.Check.ForceMetricActivation = telConfig.CirconusCheckForceMetricActivation 1039 cfg.CheckManager.Check.InstanceID = telConfig.CirconusCheckInstanceID 1040 cfg.CheckManager.Check.SearchTag = telConfig.CirconusCheckSearchTag 1041 cfg.CheckManager.Check.Tags = telConfig.CirconusCheckTags 1042 cfg.CheckManager.Check.DisplayName = telConfig.CirconusCheckDisplayName 1043 cfg.CheckManager.Broker.ID = telConfig.CirconusBrokerID 1044 cfg.CheckManager.Broker.SelectTag = telConfig.CirconusBrokerSelectTag 1045 1046 if cfg.CheckManager.Check.DisplayName == "" { 1047 cfg.CheckManager.Check.DisplayName = "Nomad" 1048 } 1049 1050 if cfg.CheckManager.API.TokenApp == "" { 1051 cfg.CheckManager.API.TokenApp = "nomad" 1052 } 1053 1054 if cfg.CheckManager.Check.SearchTag == "" { 1055 cfg.CheckManager.Check.SearchTag = "service:nomad" 1056 } 1057 1058 sink, err := circonus.NewCirconusSink(cfg) 1059 if err != nil { 1060 return inm, err 1061 } 1062 sink.Start() 1063 fanout = append(fanout, sink) 1064 } 1065 1066 // Initialize the global sink 1067 if len(fanout) > 0 { 1068 fanout = append(fanout, inm) 1069 metrics.NewGlobal(metricsConf, fanout) 1070 } else { 1071 metricsConf.EnableHostname = false 1072 metrics.NewGlobal(metricsConf, inm) 1073 } 1074 1075 return inm, nil 1076 } 1077 1078 func (c *Command) startupJoin(config *Config) error { 1079 // Nothing to do 1080 if !config.Server.Enabled { 1081 return nil 1082 } 1083 1084 // Validate both old and new aren't being set 1085 old := len(config.Server.StartJoin) 1086 var new int 1087 if config.Server.ServerJoin != nil { 1088 new = len(config.Server.ServerJoin.StartJoin) 1089 } 1090 if old != 0 && new != 0 { 1091 return fmt.Errorf("server_join and start_join cannot both be defined; prefer setting the server_join stanza") 1092 } 1093 1094 // Nothing to do 1095 if old+new == 0 { 1096 return nil 1097 } 1098 1099 // Combine the lists and join 1100 joining := config.Server.StartJoin 1101 if new != 0 { 1102 joining = append(joining, config.Server.ServerJoin.StartJoin...) 1103 } 1104 1105 c.Ui.Output("Joining cluster...") 1106 n, err := c.agent.server.Join(joining) 1107 if err != nil { 1108 return err 1109 } 1110 1111 c.Ui.Output(fmt.Sprintf("Join completed. Synced with %d initial agents", n)) 1112 return nil 1113 } 1114 1115 // getBindAddrSynopsis returns a string that describes the addresses the agent 1116 // is bound to. 1117 func (c *Command) getBindAddrSynopsis() string { 1118 if c == nil || c.agent == nil || c.agent.config == nil || c.agent.config.normalizedAddrs == nil { 1119 return "" 1120 } 1121 1122 b := new(strings.Builder) 1123 fmt.Fprintf(b, "HTTP: %s", c.agent.config.normalizedAddrs.HTTP) 1124 1125 if c.agent.server != nil { 1126 if c.agent.config.normalizedAddrs.RPC != "" { 1127 fmt.Fprintf(b, "; RPC: %s", c.agent.config.normalizedAddrs.RPC) 1128 } 1129 if c.agent.config.normalizedAddrs.Serf != "" { 1130 fmt.Fprintf(b, "; Serf: %s", c.agent.config.normalizedAddrs.Serf) 1131 } 1132 } 1133 1134 return b.String() 1135 } 1136 1137 // getAdvertiseAddrSynopsis returns a string that describes the addresses the agent 1138 // is advertising. 1139 func (c *Command) getAdvertiseAddrSynopsis() string { 1140 if c == nil || c.agent == nil || c.agent.config == nil || c.agent.config.AdvertiseAddrs == nil { 1141 return "" 1142 } 1143 1144 b := new(strings.Builder) 1145 fmt.Fprintf(b, "HTTP: %s", c.agent.config.AdvertiseAddrs.HTTP) 1146 1147 if c.agent.server != nil { 1148 if c.agent.config.AdvertiseAddrs.RPC != "" { 1149 fmt.Fprintf(b, "; RPC: %s", c.agent.config.AdvertiseAddrs.RPC) 1150 } 1151 if c.agent.config.AdvertiseAddrs.Serf != "" { 1152 fmt.Fprintf(b, "; Serf: %s", c.agent.config.AdvertiseAddrs.Serf) 1153 } 1154 } 1155 1156 return b.String() 1157 } 1158 1159 func (c *Command) Synopsis() string { 1160 return "Runs a Nomad agent" 1161 } 1162 1163 func (c *Command) Help() string { 1164 helpText := ` 1165 Usage: nomad agent [options] 1166 1167 Starts the Nomad agent and runs until an interrupt is received. 1168 The agent may be a client and/or server. 1169 1170 The Nomad agent's configuration primarily comes from the config 1171 files used, but a subset of the options may also be passed directly 1172 as CLI arguments, listed below. 1173 1174 General Options (clients and servers): 1175 1176 -bind=<addr> 1177 The address the agent will bind to for all of its various network 1178 services. The individual services that run bind to individual 1179 ports on this address. Defaults to the loopback 127.0.0.1. 1180 1181 -config=<path> 1182 The path to either a single config file or a directory of config 1183 files to use for configuring the Nomad agent. This option may be 1184 specified multiple times. If multiple config files are used, the 1185 values from each will be merged together. During merging, values 1186 from files found later in the list are merged over values from 1187 previously parsed files. 1188 1189 -data-dir=<path> 1190 The data directory used to store state and other persistent data. 1191 On client machines this is used to house allocation data such as 1192 downloaded artifacts used by drivers. On server nodes, the data 1193 dir is also used to store the replicated log. 1194 1195 -plugin-dir=<path> 1196 The plugin directory is used to discover Nomad plugins. If not specified, 1197 the plugin directory defaults to be that of <data-dir>/plugins/. 1198 1199 -dc=<datacenter> 1200 The name of the datacenter this Nomad agent is a member of. By 1201 default this is set to "dc1". 1202 1203 -log-level=<level> 1204 Specify the verbosity level of Nomad's logs. Valid values include 1205 DEBUG, INFO, and WARN, in decreasing order of verbosity. The 1206 default is INFO. 1207 1208 -log-json 1209 Output logs in a JSON format. The default is false. 1210 1211 -node=<name> 1212 The name of the local agent. This name is used to identify the node 1213 in the cluster. The name must be unique per region. The default is 1214 the current hostname of the machine. 1215 1216 -region=<region> 1217 Name of the region the Nomad agent will be a member of. By default 1218 this value is set to "global". 1219 1220 -dev 1221 Start the agent in development mode. This enables a pre-configured 1222 dual-role agent (client + server) which is useful for developing 1223 or testing Nomad. No other configuration is required to start the 1224 agent in this mode, but you may pass an optional comma-separated 1225 list of mode configurations: 1226 1227 -dev-connect 1228 Start the agent in development mode, but bind to a public network 1229 interface rather than localhost for using Consul Connect. This 1230 mode is supported only on Linux as root. 1231 1232 Server Options: 1233 1234 -server 1235 Enable server mode for the agent. Agents in server mode are 1236 clustered together and handle the additional responsibility of 1237 leader election, data replication, and scheduling work onto 1238 eligible client nodes. 1239 1240 -bootstrap-expect=<num> 1241 Configures the expected number of servers nodes to wait for before 1242 bootstrapping the cluster. Once <num> servers have joined each other, 1243 Nomad initiates the bootstrap process. 1244 1245 -encrypt=<key> 1246 Provides the gossip encryption key 1247 1248 -join=<address> 1249 Address of an agent to join at start time. Can be specified 1250 multiple times. 1251 1252 -raft-protocol=<num> 1253 The Raft protocol version to use. Used for enabling certain Autopilot 1254 features. Defaults to 2. 1255 1256 -retry-join=<address> 1257 Address of an agent to join at start time with retries enabled. 1258 Can be specified multiple times. 1259 1260 -retry-max=<num> 1261 Maximum number of join attempts. Defaults to 0, which will retry 1262 indefinitely. 1263 1264 -retry-interval=<dur> 1265 Time to wait between join attempts. 1266 1267 -rejoin 1268 Ignore a previous leave and attempts to rejoin the cluster. 1269 1270 Client Options: 1271 1272 -client 1273 Enable client mode for the agent. Client mode enables a given node to be 1274 evaluated for allocations. If client mode is not enabled, no work will be 1275 scheduled to the agent. 1276 1277 -state-dir 1278 The directory used to store state and other persistent data. If not 1279 specified a subdirectory under the "-data-dir" will be used. 1280 1281 -alloc-dir 1282 The directory used to store allocation data such as downloaded artifacts as 1283 well as data produced by tasks. If not specified, a subdirectory under the 1284 "-data-dir" will be used. 1285 1286 -servers 1287 A list of known server addresses to connect to given as "host:port" and 1288 delimited by commas. 1289 1290 -node-class 1291 Mark this node as a member of a node-class. This can be used to label 1292 similar node types. 1293 1294 -token 1295 The SecretID of an ACL token to use to authenticate RPC requests with server 1296 1297 -meta 1298 User specified metadata to associated with the node. Each instance of -meta 1299 parses a single KEY=VALUE pair. Repeat the meta flag for each key/value pair 1300 to be added. 1301 1302 -network-interface 1303 Forces the network fingerprinter to use the specified network interface. 1304 1305 -network-speed 1306 The default speed for network interfaces in MBits if the link speed can not 1307 be determined dynamically. 1308 1309 ACL Options: 1310 1311 -acl-enabled 1312 Specifies whether the agent should enable ACLs. 1313 1314 -acl-replication-token 1315 The replication token for servers to use when replicating from the 1316 authoritative region. The token must be a valid management token from the 1317 authoritative region. 1318 1319 Consul Options: 1320 1321 -consul-address=<addr> 1322 Specifies the address to the local Consul agent, given in the format host:port. 1323 Supports Unix sockets with the format: unix:///tmp/consul/consul.sock 1324 1325 -consul-auth=<auth> 1326 Specifies the HTTP Basic Authentication information to use for access to the 1327 Consul Agent, given in the format username:password. 1328 1329 -consul-auto-advertise 1330 Specifies if Nomad should advertise its services in Consul. The services 1331 are named according to server_service_name and client_service_name. Nomad 1332 servers and clients advertise their respective services, each tagged 1333 appropriately with either http or rpc tag. Nomad servers also advertise a 1334 serf tagged service. 1335 1336 -consul-ca-file=<path> 1337 Specifies an optional path to the CA certificate used for Consul communication. 1338 This defaults to the system bundle if unspecified. 1339 1340 -consul-cert-file=<path> 1341 Specifies the path to the certificate used for Consul communication. If this 1342 is set then you need to also set key_file. 1343 1344 -consul-checks-use-advertise 1345 Specifies if Consul heath checks should bind to the advertise address. By 1346 default, this is the bind address. 1347 1348 -consul-client-auto-join 1349 Specifies if the Nomad clients should automatically discover servers in the 1350 same region by searching for the Consul service name defined in the 1351 server_service_name option. 1352 1353 -consul-client-service-name=<name> 1354 Specifies the name of the service in Consul for the Nomad clients. 1355 1356 -consul-client-http-check-name=<name> 1357 Specifies the HTTP health check name in Consul for the Nomad clients. 1358 1359 -consul-key-file=<path> 1360 Specifies the path to the private key used for Consul communication. If this 1361 is set then you need to also set cert_file. 1362 1363 -consul-server-service-name=<name> 1364 Specifies the name of the service in Consul for the Nomad servers. 1365 1366 -consul-server-http-check-name=<name> 1367 Specifies the HTTP health check name in Consul for the Nomad servers. 1368 1369 -consul-server-serf-check-name=<name> 1370 Specifies the Serf health check name in Consul for the Nomad servers. 1371 1372 -consul-server-rpc-check-name=<name> 1373 Specifies the RPC health check name in Consul for the Nomad servers. 1374 1375 -consul-server-auto-join 1376 Specifies if the Nomad servers should automatically discover and join other 1377 Nomad servers by searching for the Consul service name defined in the 1378 server_service_name option. This search only happens if the server does not 1379 have a leader. 1380 1381 -consul-ssl 1382 Specifies if the transport scheme should use HTTPS to communicate with the 1383 Consul agent. 1384 1385 -consul-token=<token> 1386 Specifies the token used to provide a per-request ACL token. 1387 1388 -consul-verify-ssl 1389 Specifies if SSL peer verification should be used when communicating to the 1390 Consul API client over HTTPS. 1391 1392 Vault Options: 1393 1394 -vault-enabled 1395 Whether to enable or disable Vault integration. 1396 1397 -vault-address=<addr> 1398 The address to communicate with Vault. This should be provided with the http:// 1399 or https:// prefix. 1400 1401 -vault-token=<token> 1402 The Vault token used to derive tokens from Vault on behalf of clients. 1403 This only needs to be set on Servers. Overrides the Vault token read from 1404 the VAULT_TOKEN environment variable. 1405 1406 -vault-create-from-role=<role> 1407 The role name to create tokens for tasks from. 1408 1409 -vault-allow-unauthenticated 1410 Whether to allow jobs to be submitted that request Vault Tokens but do not 1411 authentication. The flag only applies to Servers. 1412 1413 -vault-ca-file=<path> 1414 The path to a PEM-encoded CA cert file to use to verify the Vault server SSL 1415 certificate. 1416 1417 -vault-ca-path=<path> 1418 The path to a directory of PEM-encoded CA cert files to verify the Vault server 1419 certificate. 1420 1421 -vault-cert-file=<token> 1422 The path to the certificate for Vault communication. 1423 1424 -vault-key-file=<addr> 1425 The path to the private key for Vault communication. 1426 1427 -vault-tls-skip-verify=<token> 1428 Enables or disables SSL certificate verification. 1429 1430 -vault-tls-server-name=<token> 1431 Used to set the SNI host when connecting over TLS. 1432 ` 1433 return strings.TrimSpace(helpText) 1434 }