skip_leave_on_int's default changes based on agent mode

`skip_leave_on_int`'s behavior now changes based on whether or not the agent is acting as a client or server.

Fixes: 1687
This commit is contained in:
Sean Chittenden 2016-03-31 17:45:14 -07:00
parent cbe0910dc8
commit 5994c9efbf
5 changed files with 90 additions and 24 deletions

View File

@ -175,6 +175,17 @@ func (c *Command) readConfig() *Config {
return nil return nil
} }
// Make sure SkipLeaveOnInt is set to the right default based on the
// agent's mode (client or server)
if config.SkipLeaveOnInt == nil {
config.SkipLeaveOnInt = new(bool)
if config.Server {
*config.SkipLeaveOnInt = true
} else {
*config.SkipLeaveOnInt = false
}
}
// Ensure we have a data directory // Ensure we have a data directory
if config.DataDir == "" && !dev { if config.DataDir == "" && !dev {
c.Ui.Error("Must specify data directory using -data-dir") c.Ui.Error("Must specify data directory using -data-dir")
@ -810,7 +821,7 @@ WAIT:
// Check if we should do a graceful leave // Check if we should do a graceful leave
graceful := false graceful := false
if sig == os.Interrupt && !config.SkipLeaveOnInt { if sig == os.Interrupt && !(*config.SkipLeaveOnInt) {
graceful = true graceful = true
} else if sig == syscall.SIGTERM && config.LeaveOnTerm { } else if sig == syscall.SIGTERM && config.LeaveOnTerm {
graceful = true graceful = true

View File

@ -110,17 +110,17 @@ func TestRetryJoin(t *testing.T) {
} }
func TestReadCliConfig(t *testing.T) { func TestReadCliConfig(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "consul")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.RemoveAll(tmpDir)
shutdownCh := make(chan struct{}) shutdownCh := make(chan struct{})
defer close(shutdownCh) defer close(shutdownCh)
// Test config parse // Test config parse
{ {
tmpDir, err := ioutil.TempDir("", "consul")
if err != nil {
t.Fatalf("err: %s", err)
}
cmd := &Command{ cmd := &Command{
args: []string{ args: []string{
"-data-dir", tmpDir, "-data-dir", tmpDir,
@ -137,12 +137,59 @@ func TestReadCliConfig(t *testing.T) {
} }
} }
// Test SkipLeaveOnInt default for server mode
{
ui := new(cli.MockUi)
cmd := &Command{
args: []string{
"-node", `"server1"`,
"-server",
"-data-dir", tmpDir,
},
ShutdownCh: shutdownCh,
Ui: ui,
}
config := cmd.readConfig()
if config == nil {
t.Fatalf(`Expected non-nil config object: %s`, ui.ErrorWriter.String())
}
if config.Server != true {
t.Errorf(`Expected -server to be true`)
}
if (*config.SkipLeaveOnInt) != true {
t.Errorf(`Expected SkipLeaveOnInt to be true in server mode`)
}
}
// Test SkipLeaveOnInt default for client mode
{
ui := new(cli.MockUi)
cmd := &Command{
args: []string{
"-data-dir", tmpDir,
"-node", `"client"`,
},
ShutdownCh: shutdownCh,
Ui: ui,
}
config := cmd.readConfig()
if config == nil {
t.Fatalf(`Expected non-nil config object: %s`, ui.ErrorWriter.String())
}
if config.Server != false {
t.Errorf(`Expected server to be false`)
}
if *config.SkipLeaveOnInt != false {
t.Errorf(`Expected SkipLeaveOnInt to be false in client mode`)
}
}
// Test empty node name // Test empty node name
{ {
cmd := &Command{ cmd := &Command{
args: []string{ args: []string{"-node", `""`},
"-node", `""`,
},
ShutdownCh: shutdownCh, ShutdownCh: shutdownCh,
Ui: new(cli.MockUi), Ui: new(cli.MockUi),
} }

View File

@ -227,9 +227,10 @@ type Config struct {
// the TERM signal. Defaults false. This can be changed on reload. // the TERM signal. Defaults false. This can be changed on reload.
LeaveOnTerm bool `mapstructure:"leave_on_terminate"` LeaveOnTerm bool `mapstructure:"leave_on_terminate"`
// SkipLeaveOnInt controls if Serf skips a graceful leave when receiving // SkipLeaveOnInt controls if Serf skips a graceful leave when
// the INT signal. Defaults false. This can be changed on reload. // receiving the INT signal. Defaults false on clients, true on
SkipLeaveOnInt bool `mapstructure:"skip_leave_on_interrupt"` // servers. This can be changed on reload.
SkipLeaveOnInt *bool `mapstructure:"skip_leave_on_interrupt"`
Telemetry Telemetry `mapstructure:"telemetry"` Telemetry Telemetry `mapstructure:"telemetry"`
@ -1018,8 +1019,8 @@ func MergeConfig(a, b *Config) *Config {
if b.LeaveOnTerm == true { if b.LeaveOnTerm == true {
result.LeaveOnTerm = true result.LeaveOnTerm = true
} }
if b.SkipLeaveOnInt == true { if b.SkipLeaveOnInt != nil {
result.SkipLeaveOnInt = true result.SkipLeaveOnInt = b.SkipLeaveOnInt
} }
if b.Telemetry.DisableHostname == true { if b.Telemetry.DisableHostname == true {
result.Telemetry.DisableHostname = true result.Telemetry.DisableHostname = true

View File

@ -74,8 +74,8 @@ func TestDecodeConfig(t *testing.T) {
t.Fatalf("bad: %#v", config) t.Fatalf("bad: %#v", config)
} }
if config.SkipLeaveOnInt != DefaultConfig().SkipLeaveOnInt { if config.SkipLeaveOnInt != nil {
t.Fatalf("bad: %#v", config) t.Fatalf("bad: expected nil SkipLeaveOnInt")
} }
if config.LeaveOnTerm != DefaultConfig().LeaveOnTerm { if config.LeaveOnTerm != DefaultConfig().LeaveOnTerm {
@ -290,7 +290,7 @@ func TestDecodeConfig(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
if config.SkipLeaveOnInt != true { if *config.SkipLeaveOnInt != true {
t.Fatalf("bad: %#v", config) t.Fatalf("bad: %#v", config)
} }
@ -1239,7 +1239,7 @@ func TestMergeConfig(t *testing.T) {
AdvertiseAddr: "127.0.0.1", AdvertiseAddr: "127.0.0.1",
Server: false, Server: false,
LeaveOnTerm: false, LeaveOnTerm: false,
SkipLeaveOnInt: false, SkipLeaveOnInt: new(bool),
EnableDebug: false, EnableDebug: false,
CheckUpdateIntervalRaw: "8m", CheckUpdateIntervalRaw: "8m",
RetryIntervalRaw: "10s", RetryIntervalRaw: "10s",
@ -1294,7 +1294,7 @@ func TestMergeConfig(t *testing.T) {
}, },
Server: true, Server: true,
LeaveOnTerm: true, LeaveOnTerm: true,
SkipLeaveOnInt: true, SkipLeaveOnInt: new(bool),
EnableDebug: true, EnableDebug: true,
VerifyIncoming: true, VerifyIncoming: true,
VerifyOutgoing: true, VerifyOutgoing: true,
@ -1368,6 +1368,7 @@ func TestMergeConfig(t *testing.T) {
}, },
Reap: Bool(true), Reap: Bool(true),
} }
*b.SkipLeaveOnInt = true
c := MergeConfig(a, b) c := MergeConfig(a, b)

View File

@ -621,11 +621,17 @@ Consul will not enable TLS for the HTTP API unless the `https` port has been ass
at or above the default to encourage clients to send infrequent heartbeats. at or above the default to encourage clients to send infrequent heartbeats.
Defaults to 10s. Defaults to 10s.
* <a name="skip_leave_on_interrupt"></a><a href="#skip_leave_on_interrupt">`skip_leave_on_interrupt`</a> * <a name="skip_leave_on_interrupt"></a><a
This is similar to [`leave_on_terminate`](#leave_on_terminate) but href="#skip_leave_on_interrupt">`skip_leave_on_interrupt`</a> This is
only affects interrupt handling. By default, an interrupt (such as hitting similar to [`leave_on_terminate`](#leave_on_terminate) but only affects
Control-C in a shell) causes Consul to gracefully leave. Setting this to true interrupt handling. When Consul receives an interrupt signal (such as
disables that. Defaults to false. hitting Control-C in a terminal), Consul will gracefully leave the cluster.
Setting this to `true` disables that behavior. The default behavior for
this feature varies based on whether or not the agent is running as a
client or a server. On agents in client-mode, this defaults to `false` and
for agents in server-mode, this defaults to `true` (i.e. Ctrl-C on a server
will keep the server in the cluster and therefore quorum, and Ctrl-C on a
client will gracefully leave).
* <a name="start_join"></a><a href="#start_join">`start_join`</a> An array of strings specifying addresses * <a name="start_join"></a><a href="#start_join">`start_join`</a> An array of strings specifying addresses
of nodes to [`-join`](#_join) upon startup. of nodes to [`-join`](#_join) upon startup.