2017-10-17 10:55:04 +00:00
|
|
|
package agent
|
2013-12-19 20:18:06 +00:00
|
|
|
|
|
|
|
import (
|
2017-10-17 10:55:04 +00:00
|
|
|
"flag"
|
2013-12-20 01:14:46 +00:00
|
|
|
"fmt"
|
2013-12-21 00:39:32 +00:00
|
|
|
"io"
|
2017-06-08 08:00:31 +00:00
|
|
|
"log"
|
2013-12-21 00:39:32 +00:00
|
|
|
"os"
|
|
|
|
"os/signal"
|
2014-09-02 21:23:43 +00:00
|
|
|
"path/filepath"
|
2013-12-19 20:18:06 +00:00
|
|
|
"strings"
|
2013-12-21 00:39:32 +00:00
|
|
|
"syscall"
|
|
|
|
"time"
|
2014-06-16 21:36:12 +00:00
|
|
|
|
pkg refactor
command/agent/* -> agent/*
command/consul/* -> agent/consul/*
command/agent/command{,_test}.go -> command/agent{,_test}.go
command/base/command.go -> command/base.go
command/base/* -> command/*
commands.go -> command/commands.go
The script which did the refactor is:
(
cd $GOPATH/src/github.com/hashicorp/consul
git mv command/agent/command.go command/agent.go
git mv command/agent/command_test.go command/agent_test.go
git mv command/agent/flag_slice_value{,_test}.go command/
git mv command/agent .
git mv command/base/command.go command/base.go
git mv command/base/config_util{,_test}.go command/
git mv commands.go command/
git mv consul agent
rmdir command/base/
gsed -i -e 's|package agent|package command|' command/agent{,_test}.go
gsed -i -e 's|package agent|package command|' command/flag_slice_value{,_test}.go
gsed -i -e 's|package base|package command|' command/base.go command/config_util{,_test}.go
gsed -i -e 's|package main|package command|' command/commands.go
gsed -i -e 's|base.Command|BaseCommand|' command/commands.go
gsed -i -e 's|agent.Command|AgentCommand|' command/commands.go
gsed -i -e 's|\tCommand:|\tBaseCommand:|' command/commands.go
gsed -i -e 's|base\.||' command/commands.go
gsed -i -e 's|command\.||' command/commands.go
gsed -i -e 's|command|c|' main.go
gsed -i -e 's|range Commands|range command.Commands|' main.go
gsed -i -e 's|Commands: Commands|Commands: command.Commands|' main.go
gsed -i -e 's|base\.BoolValue|BoolValue|' command/operator_autopilot_set.go
gsed -i -e 's|base\.DurationValue|DurationValue|' command/operator_autopilot_set.go
gsed -i -e 's|base\.StringValue|StringValue|' command/operator_autopilot_set.go
gsed -i -e 's|base\.UintValue|UintValue|' command/operator_autopilot_set.go
gsed -i -e 's|\bCommand\b|BaseCommand|' command/base.go
gsed -i -e 's|BaseCommand Options|Command Options|' command/base.go
gsed -i -e 's|base.Command|BaseCommand|' command/*.go
gsed -i -e 's|c\.Command|c.BaseCommand|g' command/*.go
gsed -i -e 's|\tCommand:|\tBaseCommand:|' command/*_test.go
gsed -i -e 's|base\.||' command/*_test.go
gsed -i -e 's|\bCommand\b|AgentCommand|' command/agent{,_test}.go
gsed -i -e 's|cmd.AgentCommand|cmd.BaseCommand|' command/agent.go
gsed -i -e 's|cli.AgentCommand = new(Command)|cli.Command = new(AgentCommand)|' command/agent_test.go
gsed -i -e 's|exec.AgentCommand|exec.Command|' command/agent_test.go
gsed -i -e 's|exec.BaseCommand|exec.Command|' command/agent_test.go
gsed -i -e 's|NewTestAgent|agent.NewTestAgent|' command/agent_test.go
gsed -i -e 's|= TestConfig|= agent.TestConfig|' command/agent_test.go
gsed -i -e 's|: RetryJoin|: agent.RetryJoin|' command/agent_test.go
gsed -i -e 's|\.\./\.\./|../|' command/config_util_test.go
gsed -i -e 's|\bverifyUniqueListeners|VerifyUniqueListeners|' agent/config{,_test}.go command/agent.go
gsed -i -e 's|\bserfLANKeyring\b|SerfLANKeyring|g' agent/{agent,keyring,testagent}.go command/agent.go
gsed -i -e 's|\bserfWANKeyring\b|SerfWANKeyring|g' agent/{agent,keyring,testagent}.go command/agent.go
gsed -i -e 's|\bNewAgent\b|agent.New|g' command/agent{,_test}.go
gsed -i -e 's|\bNewAgent|New|' agent/{acl_test,agent,testagent}.go
gsed -i -e 's|\bAgent\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bBool\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bConfig\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bDefaultConfig\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bDevConfig\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bMergeConfig\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bReadConfigPaths\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bParseMetaPair\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bSerfLANKeyring\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bSerfWANKeyring\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|circonus\.agent|circonus|g' command/agent{,_test}.go
gsed -i -e 's|logger\.agent|logger|g' command/agent{,_test}.go
gsed -i -e 's|metrics\.agent|metrics|g' command/agent{,_test}.go
gsed -i -e 's|// agent.Agent|// agent|' command/agent{,_test}.go
gsed -i -e 's|a\.agent\.Config|a.Config|' command/agent{,_test}.go
gsed -i -e 's|agent\.AppendSliceValue|AppendSliceValue|' command/{configtest,validate}.go
gsed -i -e 's|consul/consul|agent/consul|' GNUmakefile
gsed -i -e 's|\.\./test|../../test|' agent/consul/server_test.go
# fix imports
f=$(grep -rl 'github.com/hashicorp/consul/command/agent' * | grep '\.go')
gsed -i -e 's|github.com/hashicorp/consul/command/agent|github.com/hashicorp/consul/agent|' $f
goimports -w $f
f=$(grep -rl 'github.com/hashicorp/consul/consul' * | grep '\.go')
gsed -i -e 's|github.com/hashicorp/consul/consul|github.com/hashicorp/consul/agent/consul|' $f
goimports -w $f
goimports -w command/*.go main.go
)
2017-06-09 22:28:28 +00:00
|
|
|
"github.com/hashicorp/consul/agent"
|
2017-09-25 18:40:42 +00:00
|
|
|
"github.com/hashicorp/consul/agent/config"
|
2017-10-17 10:55:04 +00:00
|
|
|
"github.com/hashicorp/consul/command/flags"
|
2016-01-29 19:42:34 +00:00
|
|
|
"github.com/hashicorp/consul/lib"
|
2016-11-04 04:14:56 +00:00
|
|
|
"github.com/hashicorp/consul/logger"
|
2018-06-20 18:30:17 +00:00
|
|
|
"github.com/hashicorp/consul/service_os"
|
2014-09-02 21:23:43 +00:00
|
|
|
"github.com/hashicorp/go-checkpoint"
|
2016-11-30 18:29:42 +00:00
|
|
|
multierror "github.com/hashicorp/go-multierror"
|
2014-06-16 21:36:12 +00:00
|
|
|
"github.com/hashicorp/logutils"
|
|
|
|
"github.com/mitchellh/cli"
|
2018-10-03 19:37:53 +00:00
|
|
|
"google.golang.org/grpc/grpclog"
|
2013-12-19 20:18:06 +00:00
|
|
|
)
|
|
|
|
|
2017-10-17 10:55:04 +00:00
|
|
|
func New(ui cli.Ui, revision, version, versionPre, versionHuman string, shutdownCh <-chan struct{}) *cmd {
|
|
|
|
ui = &cli.PrefixedUi{
|
|
|
|
OutputPrefix: "==> ",
|
|
|
|
InfoPrefix: " ",
|
|
|
|
ErrorPrefix: "==> ",
|
|
|
|
Ui: ui,
|
|
|
|
}
|
|
|
|
|
|
|
|
c := &cmd{
|
|
|
|
UI: ui,
|
|
|
|
revision: revision,
|
|
|
|
version: version,
|
|
|
|
versionPrerelease: versionPre,
|
|
|
|
versionHuman: versionHuman,
|
|
|
|
shutdownCh: shutdownCh,
|
|
|
|
}
|
|
|
|
c.init()
|
|
|
|
return c
|
|
|
|
}
|
2014-06-09 18:57:15 +00:00
|
|
|
|
pkg refactor
command/agent/* -> agent/*
command/consul/* -> agent/consul/*
command/agent/command{,_test}.go -> command/agent{,_test}.go
command/base/command.go -> command/base.go
command/base/* -> command/*
commands.go -> command/commands.go
The script which did the refactor is:
(
cd $GOPATH/src/github.com/hashicorp/consul
git mv command/agent/command.go command/agent.go
git mv command/agent/command_test.go command/agent_test.go
git mv command/agent/flag_slice_value{,_test}.go command/
git mv command/agent .
git mv command/base/command.go command/base.go
git mv command/base/config_util{,_test}.go command/
git mv commands.go command/
git mv consul agent
rmdir command/base/
gsed -i -e 's|package agent|package command|' command/agent{,_test}.go
gsed -i -e 's|package agent|package command|' command/flag_slice_value{,_test}.go
gsed -i -e 's|package base|package command|' command/base.go command/config_util{,_test}.go
gsed -i -e 's|package main|package command|' command/commands.go
gsed -i -e 's|base.Command|BaseCommand|' command/commands.go
gsed -i -e 's|agent.Command|AgentCommand|' command/commands.go
gsed -i -e 's|\tCommand:|\tBaseCommand:|' command/commands.go
gsed -i -e 's|base\.||' command/commands.go
gsed -i -e 's|command\.||' command/commands.go
gsed -i -e 's|command|c|' main.go
gsed -i -e 's|range Commands|range command.Commands|' main.go
gsed -i -e 's|Commands: Commands|Commands: command.Commands|' main.go
gsed -i -e 's|base\.BoolValue|BoolValue|' command/operator_autopilot_set.go
gsed -i -e 's|base\.DurationValue|DurationValue|' command/operator_autopilot_set.go
gsed -i -e 's|base\.StringValue|StringValue|' command/operator_autopilot_set.go
gsed -i -e 's|base\.UintValue|UintValue|' command/operator_autopilot_set.go
gsed -i -e 's|\bCommand\b|BaseCommand|' command/base.go
gsed -i -e 's|BaseCommand Options|Command Options|' command/base.go
gsed -i -e 's|base.Command|BaseCommand|' command/*.go
gsed -i -e 's|c\.Command|c.BaseCommand|g' command/*.go
gsed -i -e 's|\tCommand:|\tBaseCommand:|' command/*_test.go
gsed -i -e 's|base\.||' command/*_test.go
gsed -i -e 's|\bCommand\b|AgentCommand|' command/agent{,_test}.go
gsed -i -e 's|cmd.AgentCommand|cmd.BaseCommand|' command/agent.go
gsed -i -e 's|cli.AgentCommand = new(Command)|cli.Command = new(AgentCommand)|' command/agent_test.go
gsed -i -e 's|exec.AgentCommand|exec.Command|' command/agent_test.go
gsed -i -e 's|exec.BaseCommand|exec.Command|' command/agent_test.go
gsed -i -e 's|NewTestAgent|agent.NewTestAgent|' command/agent_test.go
gsed -i -e 's|= TestConfig|= agent.TestConfig|' command/agent_test.go
gsed -i -e 's|: RetryJoin|: agent.RetryJoin|' command/agent_test.go
gsed -i -e 's|\.\./\.\./|../|' command/config_util_test.go
gsed -i -e 's|\bverifyUniqueListeners|VerifyUniqueListeners|' agent/config{,_test}.go command/agent.go
gsed -i -e 's|\bserfLANKeyring\b|SerfLANKeyring|g' agent/{agent,keyring,testagent}.go command/agent.go
gsed -i -e 's|\bserfWANKeyring\b|SerfWANKeyring|g' agent/{agent,keyring,testagent}.go command/agent.go
gsed -i -e 's|\bNewAgent\b|agent.New|g' command/agent{,_test}.go
gsed -i -e 's|\bNewAgent|New|' agent/{acl_test,agent,testagent}.go
gsed -i -e 's|\bAgent\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bBool\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bConfig\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bDefaultConfig\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bDevConfig\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bMergeConfig\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bReadConfigPaths\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bParseMetaPair\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bSerfLANKeyring\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bSerfWANKeyring\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|circonus\.agent|circonus|g' command/agent{,_test}.go
gsed -i -e 's|logger\.agent|logger|g' command/agent{,_test}.go
gsed -i -e 's|metrics\.agent|metrics|g' command/agent{,_test}.go
gsed -i -e 's|// agent.Agent|// agent|' command/agent{,_test}.go
gsed -i -e 's|a\.agent\.Config|a.Config|' command/agent{,_test}.go
gsed -i -e 's|agent\.AppendSliceValue|AppendSliceValue|' command/{configtest,validate}.go
gsed -i -e 's|consul/consul|agent/consul|' GNUmakefile
gsed -i -e 's|\.\./test|../../test|' agent/consul/server_test.go
# fix imports
f=$(grep -rl 'github.com/hashicorp/consul/command/agent' * | grep '\.go')
gsed -i -e 's|github.com/hashicorp/consul/command/agent|github.com/hashicorp/consul/agent|' $f
goimports -w $f
f=$(grep -rl 'github.com/hashicorp/consul/consul' * | grep '\.go')
gsed -i -e 's|github.com/hashicorp/consul/consul|github.com/hashicorp/consul/agent/consul|' $f
goimports -w $f
goimports -w command/*.go main.go
)
2017-06-09 22:28:28 +00:00
|
|
|
// AgentCommand is a Command implementation that runs a Consul agent.
|
2013-12-19 20:18:06 +00:00
|
|
|
// The command will not end unless a shutdown message is sent on the
|
|
|
|
// ShutdownCh. If two messages are sent on the ShutdownCh it will forcibly
|
|
|
|
// exit.
|
2017-10-17 10:55:04 +00:00
|
|
|
type cmd struct {
|
|
|
|
UI cli.Ui
|
|
|
|
flags *flag.FlagSet
|
|
|
|
http *flags.HTTPFlags
|
2017-10-17 13:44:20 +00:00
|
|
|
help string
|
2017-10-17 10:55:04 +00:00
|
|
|
revision string
|
|
|
|
version string
|
|
|
|
versionPrerelease string
|
|
|
|
versionHuman string
|
|
|
|
shutdownCh <-chan struct{}
|
|
|
|
flagArgs config.Flags
|
2016-07-20 01:38:15 +00:00
|
|
|
logFilter *logutils.LevelFilter
|
|
|
|
logOutput io.Writer
|
2017-06-08 08:00:31 +00:00
|
|
|
logger *log.Logger
|
2013-12-21 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
2017-10-17 10:55:04 +00:00
|
|
|
func (c *cmd) init() {
|
|
|
|
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
|
|
|
|
config.AddFlags(c.flags, &c.flagArgs)
|
2017-10-17 22:00:01 +00:00
|
|
|
c.help = flags.Usage(help, c.flags)
|
2017-10-17 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *cmd) Run(args []string) int {
|
|
|
|
code := c.run(args)
|
|
|
|
if c.logger != nil {
|
2018-03-21 15:56:14 +00:00
|
|
|
c.logger.Println("[INFO] agent: Exit code:", code)
|
2017-10-17 10:55:04 +00:00
|
|
|
}
|
|
|
|
return code
|
|
|
|
}
|
2017-05-10 15:45:17 +00:00
|
|
|
|
2017-10-17 10:55:04 +00:00
|
|
|
// readConfig is responsible for setup of our configuration using
|
|
|
|
// the command line and any file configs
|
|
|
|
func (c *cmd) readConfig() *config.RuntimeConfig {
|
|
|
|
b, err := config.NewBuilder(c.flagArgs)
|
2017-09-25 18:40:42 +00:00
|
|
|
if err != nil {
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Error(err.Error())
|
2017-01-11 19:41:12 +00:00
|
|
|
return nil
|
|
|
|
}
|
2017-09-25 18:40:42 +00:00
|
|
|
cfg, err := b.BuildAndValidate()
|
|
|
|
if err != nil {
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Error(err.Error())
|
2017-07-27 20:59:58 +00:00
|
|
|
return nil
|
|
|
|
}
|
2017-09-25 18:40:42 +00:00
|
|
|
for _, w := range b.Warnings {
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Warn(w)
|
2017-07-28 03:06:31 +00:00
|
|
|
}
|
2017-09-25 18:40:42 +00:00
|
|
|
return &cfg
|
2013-12-21 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
2014-09-02 21:23:43 +00:00
|
|
|
// checkpointResults is used to handler periodic results from our update checker
|
2017-10-17 10:55:04 +00:00
|
|
|
func (c *cmd) checkpointResults(results *checkpoint.CheckResponse, err error) {
|
2014-09-02 21:23:43 +00:00
|
|
|
if err != nil {
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Error(fmt.Sprintf("Failed to check for updates: %v", err))
|
2014-09-02 21:23:43 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if results.Outdated {
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Error(fmt.Sprintf("Newer Consul version available: %s (currently running: %s)", results.CurrentVersion, c.version))
|
2014-09-02 21:23:43 +00:00
|
|
|
}
|
|
|
|
for _, alert := range results.Alerts {
|
|
|
|
switch alert.Level {
|
|
|
|
case "info":
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Info(fmt.Sprintf("Bulletin [%s]: %s (%s)", alert.Level, alert.Message, alert.URL))
|
2014-09-02 21:23:43 +00:00
|
|
|
default:
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Error(fmt.Sprintf("Bulletin [%s]: %s (%s)", alert.Level, alert.Message, alert.URL))
|
2014-09-02 21:23:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-17 10:55:04 +00:00
|
|
|
func (c *cmd) startupUpdateCheck(config *config.RuntimeConfig) {
|
2017-06-02 13:29:40 +00:00
|
|
|
version := config.Version
|
|
|
|
if config.VersionPrerelease != "" {
|
|
|
|
version += fmt.Sprintf("-%s", config.VersionPrerelease)
|
|
|
|
}
|
|
|
|
updateParams := &checkpoint.CheckParams{
|
|
|
|
Product: "consul",
|
|
|
|
Version: version,
|
|
|
|
}
|
|
|
|
if !config.DisableAnonymousSignature {
|
|
|
|
updateParams.SignatureFile = filepath.Join(config.DataDir, "checkpoint-signature")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Schedule a periodic check with expected interval of 24 hours
|
2017-10-17 10:55:04 +00:00
|
|
|
checkpoint.CheckInterval(updateParams, 24*time.Hour, c.checkpointResults)
|
2017-06-02 13:29:40 +00:00
|
|
|
|
|
|
|
// Do an immediate check within the next 30 seconds
|
|
|
|
go func() {
|
|
|
|
time.Sleep(lib.RandomStagger(30 * time.Second))
|
2017-10-17 10:55:04 +00:00
|
|
|
c.checkpointResults(checkpoint.Check(updateParams))
|
2017-06-02 13:29:40 +00:00
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2014-04-11 23:59:16 +00:00
|
|
|
// startupJoin is invoked to handle any joins specified to take place at start time
|
2017-10-17 10:55:04 +00:00
|
|
|
func (c *cmd) startupJoin(agent *agent.Agent, cfg *config.RuntimeConfig) error {
|
2017-09-25 18:40:42 +00:00
|
|
|
if len(cfg.StartJoinAddrsLAN) == 0 {
|
2014-04-11 23:59:16 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Output("Joining cluster...")
|
2017-09-25 18:40:42 +00:00
|
|
|
n, err := agent.JoinLAN(cfg.StartJoinAddrsLAN)
|
2014-04-11 23:59:16 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Info(fmt.Sprintf("Join completed. Synced with %d initial agents", n))
|
2014-04-11 23:59:16 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-11-17 22:14:59 +00:00
|
|
|
// startupJoinWan is invoked to handle any joins -wan specified to take place at start time
|
2017-10-17 10:55:04 +00:00
|
|
|
func (c *cmd) startupJoinWan(agent *agent.Agent, cfg *config.RuntimeConfig) error {
|
2017-09-25 18:40:42 +00:00
|
|
|
if len(cfg.StartJoinAddrsWAN) == 0 {
|
2014-11-14 15:02:42 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Output("Joining -wan cluster...")
|
2017-09-25 18:40:42 +00:00
|
|
|
n, err := agent.JoinWAN(cfg.StartJoinAddrsWAN)
|
2014-11-14 15:02:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Info(fmt.Sprintf("Join -wan completed. Synced with %d initial agents", n))
|
2014-11-14 15:02:42 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-10-17 10:55:04 +00:00
|
|
|
func (c *cmd) run(args []string) int {
|
2013-12-21 00:39:32 +00:00
|
|
|
// Parse our configs
|
2018-05-31 23:59:51 +00:00
|
|
|
if err := c.flags.Parse(args); err != nil {
|
|
|
|
if !strings.Contains(err.Error(), "help requested") {
|
|
|
|
c.UI.Error(fmt.Sprintf("error parsing flags: %v", err))
|
|
|
|
}
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
c.flagArgs.Args = c.flags.Args()
|
2017-10-17 10:55:04 +00:00
|
|
|
config := c.readConfig()
|
2013-12-21 00:39:32 +00:00
|
|
|
if config == nil {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup the log outputs
|
2016-11-04 04:14:56 +00:00
|
|
|
logConfig := &logger.Config{
|
2018-08-29 20:56:58 +00:00
|
|
|
LogLevel: config.LogLevel,
|
|
|
|
EnableSyslog: config.EnableSyslog,
|
|
|
|
SyslogFacility: config.SyslogFacility,
|
|
|
|
LogFilePath: config.LogFile,
|
|
|
|
LogRotateDuration: config.LogRotateDuration,
|
|
|
|
LogRotateBytes: config.LogRotateBytes,
|
2016-11-04 04:14:56 +00:00
|
|
|
}
|
2017-10-17 10:55:04 +00:00
|
|
|
logFilter, logGate, logWriter, logOutput, ok := logger.Setup(logConfig, c.UI)
|
2016-11-04 04:14:56 +00:00
|
|
|
if !ok {
|
2013-12-21 00:39:32 +00:00
|
|
|
return 1
|
|
|
|
}
|
2017-10-17 10:55:04 +00:00
|
|
|
c.logFilter = logFilter
|
|
|
|
c.logOutput = logOutput
|
|
|
|
c.logger = log.New(logOutput, "", log.LstdFlags)
|
2013-12-21 00:39:32 +00:00
|
|
|
|
2018-10-03 19:37:53 +00:00
|
|
|
// Setup gRPC logger to use the same output/filtering
|
|
|
|
grpclog.SetLoggerV2(logger.NewGRPCLogger(logConfig, c.logger))
|
|
|
|
|
2018-06-14 12:52:48 +00:00
|
|
|
memSink, err := lib.InitTelemetry(config.Telemetry)
|
2017-08-08 08:31:38 +00:00
|
|
|
if err != nil {
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Error(err.Error())
|
2017-06-02 13:30:03 +00:00
|
|
|
return 1
|
2014-02-20 22:59:54 +00:00
|
|
|
}
|
2014-02-20 21:51:51 +00:00
|
|
|
|
2013-12-21 00:39:32 +00:00
|
|
|
// Create the agent
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Output("Starting Consul agent...")
|
2019-06-27 20:22:07 +00:00
|
|
|
agent, err := agent.New(config, c.logger)
|
2017-05-19 09:53:41 +00:00
|
|
|
if err != nil {
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Error(fmt.Sprintf("Error creating agent: %s", err))
|
2017-05-19 15:51:39 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
agent.LogOutput = logOutput
|
|
|
|
agent.LogWriter = logWriter
|
2017-08-08 08:31:38 +00:00
|
|
|
agent.MemSink = memSink
|
2017-06-02 13:35:06 +00:00
|
|
|
|
2019-06-27 20:22:07 +00:00
|
|
|
segment := config.SegmentName
|
|
|
|
if config.ServerMode {
|
|
|
|
segment = "<all>"
|
|
|
|
}
|
|
|
|
|
|
|
|
c.UI.Info(fmt.Sprintf(" Version: '%s'", c.versionHuman))
|
|
|
|
c.UI.Info(fmt.Sprintf(" Node ID: '%s'", config.NodeID))
|
|
|
|
c.UI.Info(fmt.Sprintf(" Node name: '%s'", config.NodeName))
|
|
|
|
c.UI.Info(fmt.Sprintf(" Datacenter: '%s' (Segment: '%s')", config.Datacenter, segment))
|
|
|
|
c.UI.Info(fmt.Sprintf(" Server: %v (Bootstrap: %v)", config.ServerMode, config.Bootstrap))
|
|
|
|
c.UI.Info(fmt.Sprintf(" Client Addr: %v (HTTP: %d, HTTPS: %d, gRPC: %d, DNS: %d)", config.ClientAddrs,
|
|
|
|
config.HTTPPort, config.HTTPSPort, config.GRPCPort, config.DNSPort))
|
|
|
|
c.UI.Info(fmt.Sprintf(" Cluster Addr: %v (LAN: %d, WAN: %d)", config.AdvertiseAddrLAN,
|
|
|
|
config.SerfPortLAN, config.SerfPortWAN))
|
|
|
|
c.UI.Info(fmt.Sprintf(" Encrypt: Gossip: %v, TLS-Outgoing: %v, TLS-Incoming: %v, Auto-Encrypt-TLS: %t",
|
|
|
|
config.EncryptKey, config.VerifyOutgoing, config.VerifyIncoming, config.AutoEncryptTLS || config.AutoEncryptAllowTLS))
|
|
|
|
|
|
|
|
// Enable log streaming
|
|
|
|
c.UI.Info("")
|
|
|
|
c.UI.Output("Log data will now stream in as it occurs:\n")
|
|
|
|
logGate.Flush()
|
|
|
|
|
|
|
|
// wait for signal
|
|
|
|
signalCh := make(chan os.Signal, 10)
|
|
|
|
stopCh := make(chan struct{})
|
|
|
|
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGPIPE)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
var sig os.Signal
|
|
|
|
select {
|
|
|
|
case s := <-signalCh:
|
|
|
|
sig = s
|
|
|
|
case <-stopCh:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch sig {
|
|
|
|
case syscall.SIGPIPE:
|
|
|
|
continue
|
|
|
|
|
|
|
|
case syscall.SIGHUP:
|
|
|
|
err := fmt.Errorf("cannot reload before agent started")
|
|
|
|
c.logger.Printf("[ERR] agent: Caught signal: %s err: %s\n", sig, err)
|
|
|
|
|
|
|
|
default:
|
|
|
|
c.logger.Println("[INFO] agent: Caught signal: ", sig)
|
|
|
|
agent.InterruptStartCh <- struct{}{}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
err = agent.Start()
|
|
|
|
signal.Stop(signalCh)
|
|
|
|
select {
|
|
|
|
case stopCh <- struct{}{}:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
if err != nil {
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Error(fmt.Sprintf("Error starting agent: %s", err))
|
2013-12-20 01:14:46 +00:00
|
|
|
return 1
|
|
|
|
}
|
2017-06-20 07:29:20 +00:00
|
|
|
|
|
|
|
// shutdown agent before endpoints
|
|
|
|
defer agent.ShutdownEndpoints()
|
|
|
|
defer agent.ShutdownAgent()
|
2017-05-19 09:53:41 +00:00
|
|
|
|
2019-05-07 15:15:34 +00:00
|
|
|
if !config.DisableUpdateCheck && !config.DevMode {
|
2017-10-17 10:55:04 +00:00
|
|
|
c.startupUpdateCheck(config)
|
2013-12-23 19:38:51 +00:00
|
|
|
}
|
2015-08-25 23:40:55 +00:00
|
|
|
|
2017-10-17 10:55:04 +00:00
|
|
|
if err := c.startupJoin(agent, config); err != nil {
|
|
|
|
c.UI.Error(err.Error())
|
2014-04-11 23:59:16 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2017-10-17 10:55:04 +00:00
|
|
|
if err := c.startupJoinWan(agent, config); err != nil {
|
|
|
|
c.UI.Error(err.Error())
|
2014-11-14 15:02:42 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2014-01-16 01:14:50 +00:00
|
|
|
// Let the agent know we've finished registration
|
2017-06-02 10:17:55 +00:00
|
|
|
agent.StartSync()
|
2017-05-22 11:13:44 +00:00
|
|
|
|
2017-10-17 10:55:04 +00:00
|
|
|
c.UI.Output("Consul agent running!")
|
2013-12-21 00:39:32 +00:00
|
|
|
|
2017-06-02 13:35:06 +00:00
|
|
|
// wait for signal
|
2019-06-27 20:22:07 +00:00
|
|
|
signalCh = make(chan os.Signal, 10)
|
2016-11-30 17:42:10 +00:00
|
|
|
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGPIPE)
|
2013-12-21 00:39:32 +00:00
|
|
|
|
2017-06-02 13:04:34 +00:00
|
|
|
for {
|
|
|
|
var sig os.Signal
|
|
|
|
var reloadErrCh chan error
|
|
|
|
select {
|
|
|
|
case s := <-signalCh:
|
|
|
|
sig = s
|
|
|
|
case ch := <-agent.ReloadCh():
|
|
|
|
sig = syscall.SIGHUP
|
|
|
|
reloadErrCh = ch
|
2018-06-20 18:30:17 +00:00
|
|
|
case <-service_os.Shutdown_Channel():
|
|
|
|
sig = os.Interrupt
|
2017-10-17 10:55:04 +00:00
|
|
|
case <-c.shutdownCh:
|
2017-06-02 13:04:34 +00:00
|
|
|
sig = os.Interrupt
|
|
|
|
case err := <-agent.RetryJoinCh():
|
2018-03-21 15:56:14 +00:00
|
|
|
c.logger.Println("[ERR] agent: Retry join failed: ", err)
|
2017-06-02 13:04:34 +00:00
|
|
|
return 1
|
|
|
|
case <-agent.ShutdownCh():
|
pkg refactor
command/agent/* -> agent/*
command/consul/* -> agent/consul/*
command/agent/command{,_test}.go -> command/agent{,_test}.go
command/base/command.go -> command/base.go
command/base/* -> command/*
commands.go -> command/commands.go
The script which did the refactor is:
(
cd $GOPATH/src/github.com/hashicorp/consul
git mv command/agent/command.go command/agent.go
git mv command/agent/command_test.go command/agent_test.go
git mv command/agent/flag_slice_value{,_test}.go command/
git mv command/agent .
git mv command/base/command.go command/base.go
git mv command/base/config_util{,_test}.go command/
git mv commands.go command/
git mv consul agent
rmdir command/base/
gsed -i -e 's|package agent|package command|' command/agent{,_test}.go
gsed -i -e 's|package agent|package command|' command/flag_slice_value{,_test}.go
gsed -i -e 's|package base|package command|' command/base.go command/config_util{,_test}.go
gsed -i -e 's|package main|package command|' command/commands.go
gsed -i -e 's|base.Command|BaseCommand|' command/commands.go
gsed -i -e 's|agent.Command|AgentCommand|' command/commands.go
gsed -i -e 's|\tCommand:|\tBaseCommand:|' command/commands.go
gsed -i -e 's|base\.||' command/commands.go
gsed -i -e 's|command\.||' command/commands.go
gsed -i -e 's|command|c|' main.go
gsed -i -e 's|range Commands|range command.Commands|' main.go
gsed -i -e 's|Commands: Commands|Commands: command.Commands|' main.go
gsed -i -e 's|base\.BoolValue|BoolValue|' command/operator_autopilot_set.go
gsed -i -e 's|base\.DurationValue|DurationValue|' command/operator_autopilot_set.go
gsed -i -e 's|base\.StringValue|StringValue|' command/operator_autopilot_set.go
gsed -i -e 's|base\.UintValue|UintValue|' command/operator_autopilot_set.go
gsed -i -e 's|\bCommand\b|BaseCommand|' command/base.go
gsed -i -e 's|BaseCommand Options|Command Options|' command/base.go
gsed -i -e 's|base.Command|BaseCommand|' command/*.go
gsed -i -e 's|c\.Command|c.BaseCommand|g' command/*.go
gsed -i -e 's|\tCommand:|\tBaseCommand:|' command/*_test.go
gsed -i -e 's|base\.||' command/*_test.go
gsed -i -e 's|\bCommand\b|AgentCommand|' command/agent{,_test}.go
gsed -i -e 's|cmd.AgentCommand|cmd.BaseCommand|' command/agent.go
gsed -i -e 's|cli.AgentCommand = new(Command)|cli.Command = new(AgentCommand)|' command/agent_test.go
gsed -i -e 's|exec.AgentCommand|exec.Command|' command/agent_test.go
gsed -i -e 's|exec.BaseCommand|exec.Command|' command/agent_test.go
gsed -i -e 's|NewTestAgent|agent.NewTestAgent|' command/agent_test.go
gsed -i -e 's|= TestConfig|= agent.TestConfig|' command/agent_test.go
gsed -i -e 's|: RetryJoin|: agent.RetryJoin|' command/agent_test.go
gsed -i -e 's|\.\./\.\./|../|' command/config_util_test.go
gsed -i -e 's|\bverifyUniqueListeners|VerifyUniqueListeners|' agent/config{,_test}.go command/agent.go
gsed -i -e 's|\bserfLANKeyring\b|SerfLANKeyring|g' agent/{agent,keyring,testagent}.go command/agent.go
gsed -i -e 's|\bserfWANKeyring\b|SerfWANKeyring|g' agent/{agent,keyring,testagent}.go command/agent.go
gsed -i -e 's|\bNewAgent\b|agent.New|g' command/agent{,_test}.go
gsed -i -e 's|\bNewAgent|New|' agent/{acl_test,agent,testagent}.go
gsed -i -e 's|\bAgent\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bBool\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bConfig\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bDefaultConfig\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bDevConfig\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bMergeConfig\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bReadConfigPaths\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bParseMetaPair\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bSerfLANKeyring\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|\bSerfWANKeyring\b|agent.&|g' command/agent{,_test}.go
gsed -i -e 's|circonus\.agent|circonus|g' command/agent{,_test}.go
gsed -i -e 's|logger\.agent|logger|g' command/agent{,_test}.go
gsed -i -e 's|metrics\.agent|metrics|g' command/agent{,_test}.go
gsed -i -e 's|// agent.Agent|// agent|' command/agent{,_test}.go
gsed -i -e 's|a\.agent\.Config|a.Config|' command/agent{,_test}.go
gsed -i -e 's|agent\.AppendSliceValue|AppendSliceValue|' command/{configtest,validate}.go
gsed -i -e 's|consul/consul|agent/consul|' GNUmakefile
gsed -i -e 's|\.\./test|../../test|' agent/consul/server_test.go
# fix imports
f=$(grep -rl 'github.com/hashicorp/consul/command/agent' * | grep '\.go')
gsed -i -e 's|github.com/hashicorp/consul/command/agent|github.com/hashicorp/consul/agent|' $f
goimports -w $f
f=$(grep -rl 'github.com/hashicorp/consul/consul' * | grep '\.go')
gsed -i -e 's|github.com/hashicorp/consul/consul|github.com/hashicorp/consul/agent/consul|' $f
goimports -w $f
goimports -w command/*.go main.go
)
2017-06-09 22:28:28 +00:00
|
|
|
// agent is already down!
|
2017-06-02 13:04:34 +00:00
|
|
|
return 0
|
|
|
|
}
|
2013-12-21 00:39:32 +00:00
|
|
|
|
2017-06-02 13:04:34 +00:00
|
|
|
switch sig {
|
|
|
|
case syscall.SIGPIPE:
|
|
|
|
continue
|
2016-11-30 17:42:10 +00:00
|
|
|
|
2017-06-02 13:04:34 +00:00
|
|
|
case syscall.SIGHUP:
|
2018-03-21 15:56:14 +00:00
|
|
|
c.logger.Println("[INFO] agent: Caught signal: ", sig)
|
2017-03-29 06:46:58 +00:00
|
|
|
|
2017-10-17 10:55:04 +00:00
|
|
|
conf, err := c.handleReload(agent, config)
|
2017-06-02 13:04:34 +00:00
|
|
|
if conf != nil {
|
2017-06-02 13:35:06 +00:00
|
|
|
config = conf
|
2017-06-02 13:04:34 +00:00
|
|
|
}
|
|
|
|
if err != nil {
|
2018-03-21 15:56:14 +00:00
|
|
|
c.logger.Println("[ERR] agent: Reload config failed: ", err)
|
2017-06-02 13:04:34 +00:00
|
|
|
}
|
|
|
|
// Send result back if reload was called via HTTP
|
|
|
|
if reloadErrCh != nil {
|
|
|
|
reloadErrCh <- err
|
|
|
|
}
|
2013-12-21 00:39:32 +00:00
|
|
|
|
2017-06-02 13:04:34 +00:00
|
|
|
default:
|
2018-03-21 15:56:14 +00:00
|
|
|
c.logger.Println("[INFO] agent: Caught signal: ", sig)
|
2013-12-21 00:39:32 +00:00
|
|
|
|
2017-09-25 18:40:42 +00:00
|
|
|
graceful := (sig == os.Interrupt && !(config.SkipLeaveOnInt)) || (sig == syscall.SIGTERM && (config.LeaveOnTerm))
|
2017-06-02 13:04:34 +00:00
|
|
|
if !graceful {
|
2018-03-21 15:56:14 +00:00
|
|
|
c.logger.Println("[INFO] agent: Graceful shutdown disabled. Exiting")
|
2017-06-02 13:04:34 +00:00
|
|
|
return 1
|
|
|
|
}
|
2013-12-21 00:39:32 +00:00
|
|
|
|
2018-03-21 15:56:14 +00:00
|
|
|
c.logger.Println("[INFO] agent: Gracefully shutting down agent...")
|
2017-06-02 13:04:34 +00:00
|
|
|
gracefulCh := make(chan struct{})
|
|
|
|
go func() {
|
|
|
|
if err := agent.Leave(); err != nil {
|
2018-03-21 15:56:14 +00:00
|
|
|
c.logger.Println("[ERR] agent: Error on leave:", err)
|
2017-06-02 13:04:34 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
close(gracefulCh)
|
|
|
|
}()
|
|
|
|
|
2017-06-07 11:12:34 +00:00
|
|
|
gracefulTimeout := 15 * time.Second
|
2017-06-02 13:04:34 +00:00
|
|
|
select {
|
|
|
|
case <-signalCh:
|
2018-03-21 15:56:14 +00:00
|
|
|
c.logger.Printf("[INFO] agent: Caught second signal %v. Exiting\n", sig)
|
2017-06-02 13:04:34 +00:00
|
|
|
return 1
|
|
|
|
case <-time.After(gracefulTimeout):
|
2018-03-21 15:56:14 +00:00
|
|
|
c.logger.Println("[INFO] agent: Timeout on graceful leave. Exiting")
|
2017-06-02 13:04:34 +00:00
|
|
|
return 1
|
|
|
|
case <-gracefulCh:
|
2018-03-21 15:56:14 +00:00
|
|
|
c.logger.Println("[INFO] agent: Graceful exit completed")
|
2017-06-02 13:04:34 +00:00
|
|
|
return 0
|
|
|
|
}
|
2013-12-21 00:39:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// handleReload is invoked when we should reload our configs, e.g. SIGHUP
|
2017-10-17 10:55:04 +00:00
|
|
|
func (c *cmd) handleReload(agent *agent.Agent, cfg *config.RuntimeConfig) (*config.RuntimeConfig, error) {
|
2018-03-21 15:56:14 +00:00
|
|
|
c.logger.Println("[INFO] agent: Reloading configuration...")
|
2016-11-30 18:29:42 +00:00
|
|
|
var errs error
|
2017-10-17 10:55:04 +00:00
|
|
|
newCfg := c.readConfig()
|
2017-06-02 12:56:49 +00:00
|
|
|
if newCfg == nil {
|
2016-11-30 18:29:42 +00:00
|
|
|
errs = multierror.Append(errs, fmt.Errorf("Failed to reload configs"))
|
2017-05-22 11:17:31 +00:00
|
|
|
return cfg, errs
|
2014-02-07 20:03:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Change the log level
|
2017-06-02 12:56:49 +00:00
|
|
|
minLevel := logutils.LogLevel(strings.ToUpper(newCfg.LogLevel))
|
2017-10-17 10:55:04 +00:00
|
|
|
if logger.ValidateLevelFilter(minLevel, c.logFilter) {
|
|
|
|
c.logFilter.SetMinLevel(minLevel)
|
2014-02-07 20:03:14 +00:00
|
|
|
} else {
|
2016-11-30 18:29:42 +00:00
|
|
|
errs = multierror.Append(fmt.Errorf(
|
2014-02-07 20:03:14 +00:00
|
|
|
"Invalid log level: %s. Valid log levels are: %v",
|
2017-10-17 10:55:04 +00:00
|
|
|
minLevel, c.logFilter.Levels))
|
2014-02-07 20:03:14 +00:00
|
|
|
|
|
|
|
// Keep the current log level
|
2017-06-02 12:56:49 +00:00
|
|
|
newCfg.LogLevel = cfg.LogLevel
|
2014-02-07 20:03:14 +00:00
|
|
|
}
|
|
|
|
|
2017-06-24 19:52:41 +00:00
|
|
|
if err := agent.ReloadConfig(newCfg); err != nil {
|
|
|
|
errs = multierror.Append(fmt.Errorf(
|
|
|
|
"Failed to reload configs: %v", err))
|
2014-08-21 20:09:13 +00:00
|
|
|
}
|
2017-06-24 19:52:41 +00:00
|
|
|
|
2018-05-31 23:59:51 +00:00
|
|
|
return newCfg, errs
|
2015-08-26 01:27:07 +00:00
|
|
|
}
|
|
|
|
|
2017-10-17 13:44:20 +00:00
|
|
|
func (c *cmd) Synopsis() string {
|
|
|
|
return synopsis
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *cmd) Help() string {
|
|
|
|
return c.help
|
|
|
|
}
|
|
|
|
|
|
|
|
const synopsis = "Runs a Consul agent"
|
|
|
|
const help = `
|
|
|
|
Usage: consul agent [options]
|
2013-12-19 20:18:06 +00:00
|
|
|
|
|
|
|
Starts the Consul agent and runs until an interrupt is received. The
|
2017-10-17 13:44:20 +00:00
|
|
|
agent represents a single node in a cluster.
|
|
|
|
`
|