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