From fa04c24978250c777d951869a25fd4227a0fbab9 Mon Sep 17 00:00:00 2001 From: James Phillips Date: Wed, 12 Apr 2017 22:05:38 -0700 Subject: [PATCH] Adds a new -disable-host-node-id option to help when testing with containers. Fixes #2877. --- command/agent/agent.go | 5 +++ command/agent/agent_test.go | 38 ++++++++++++++++++- command/agent/command.go | 4 ++ command/agent/config.go | 8 ++++ command/agent/config_test.go | 25 +++++++----- .../source/docs/agent/options.html.markdown | 26 ++++++++----- 6 files changed, 85 insertions(+), 21 deletions(-) diff --git a/command/agent/agent.go b/command/agent/agent.go index 141725d5c3..8a2a5684dc 100644 --- a/command/agent/agent.go +++ b/command/agent/agent.go @@ -630,6 +630,11 @@ func (a *Agent) makeRandomID() (string, error) { // high for us if this changes, so we will persist it either way. This will let // gopsutil change implementations without affecting in-place upgrades of nodes. func (a *Agent) makeNodeID() (string, error) { + // If they've disabled host-based IDs then just make a random one. + if a.config.DisableHostNodeID { + return a.makeRandomID() + } + // Try to get a stable ID associated with the host itself. info, err := host.Info() if err != nil { diff --git a/command/agent/agent_test.go b/command/agent/agent_test.go index b23327c665..145019fde8 100644 --- a/command/agent/agent_test.go +++ b/command/agent/agent_test.go @@ -318,7 +318,7 @@ func TestAgent_ReconnectConfigSettings(t *testing.T) { }() } -func TestAgent_NodeID(t *testing.T) { +func TestAgent_setupNodeID(t *testing.T) { c := nextConfig() c.NodeID = "" dir, agent := makeAgent(t, c) @@ -384,6 +384,42 @@ func TestAgent_NodeID(t *testing.T) { } } +func TestAgent_makeNodeID(t *testing.T) { + c := nextConfig() + c.NodeID = "" + dir, agent := makeAgent(t, c) + defer os.RemoveAll(dir) + defer agent.Shutdown() + + // We should get a valid host-based ID initially. + id, err := agent.makeNodeID() + if err != nil { + t.Fatalf("err: %v", err) + } + if _, err := uuid.ParseUUID(string(id)); err != nil { + t.Fatalf("err: %v", err) + } + + // Calling again should yield the same ID since it's host-based. + another, err := agent.makeNodeID() + if err != nil { + t.Fatalf("err: %v", err) + } + if id != another { + t.Fatalf("bad: %s vs %s", id, another) + } + + // Turn off host-based IDs and try again. We should get a random ID. + agent.config.DisableHostNodeID = true + another, err = agent.makeNodeID() + if err != nil { + t.Fatalf("err: %v", err) + } + if id == another { + t.Fatalf("bad: %s vs %s", id, another) + } +} + func TestAgent_AddService(t *testing.T) { dir, agent := makeAgent(t, nextConfig()) defer os.RemoveAll(dir) diff --git a/command/agent/command.go b/command/agent/command.go index 78ae49ffa0..a13d0adf80 100644 --- a/command/agent/command.go +++ b/command/agent/command.go @@ -100,6 +100,10 @@ func (c *Command) readConfig() *Config { f.StringVar((*string)(&cmdConfig.NodeID), "node-id", "", "A unique ID for this node across space and time. Defaults to a randomly-generated ID"+ " that persists in the data-dir.") + f.BoolVar(&cmdConfig.DisableHostNodeID, "disable-host-node-id", false, + "Setting this to true will prevent Consul from using information from the"+ + " host to generate a node ID, and will cause Consul to generate a"+ + " random node ID instead.") f.StringVar(&dcDeprecated, "dc", "", "Datacenter of the agent (deprecated: use 'datacenter' instead).") f.StringVar(&cmdConfig.Datacenter, "datacenter", "", "Datacenter of the agent.") f.StringVar(&cmdConfig.DataDir, "data-dir", "", "Path to a data directory to store agent state.") diff --git a/command/agent/config.go b/command/agent/config.go index 41c60f4750..a0f41eff10 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -358,6 +358,11 @@ type Config struct { // to a randomly-generated ID that persists in the data-dir. NodeID types.NodeID `mapstructure:"node_id"` + // DisableHostNodeID will prevent Consul from using information from the + // host to generate a node ID, and will cause Consul to generate a + // random ID instead. + DisableHostNodeID bool `mapstructure:"disable_host_node_id"` + // Node name is the name we use to advertise. Defaults to hostname. NodeName string `mapstructure:"node_name"` @@ -1371,6 +1376,9 @@ func MergeConfig(a, b *Config) *Config { if b.NodeID != "" { result.NodeID = b.NodeID } + if b.DisableHostNodeID == true { + result.DisableHostNodeID = b.DisableHostNodeID + } if b.NodeName != "" { result.NodeName = b.NodeName } diff --git a/command/agent/config_test.go b/command/agent/config_test.go index c0063e3d3d..7216c6c473 100644 --- a/command/agent/config_test.go +++ b/command/agent/config_test.go @@ -59,8 +59,8 @@ func TestDecodeConfig(t *testing.T) { t.Fatalf("bad: %#v", config) } - // Without a protocol - input = `{"node_id": "bar", "node_name": "foo", "datacenter": "dc2"}` + // Node info + input = `{"node_id": "bar", "disable_host_node_id": true, "node_name": "foo", "datacenter": "dc2"}` config, err = DecodeConfig(bytes.NewReader([]byte(input))) if err != nil { t.Fatalf("err: %s", err) @@ -74,6 +74,10 @@ func TestDecodeConfig(t *testing.T) { t.Fatalf("bad: %#v", config) } + if config.DisableHostNodeID != true { + t.Fatalf("bad: %#v", config) + } + if config.Datacenter != "dc2" { t.Fatalf("bad: %#v", config) } @@ -1652,14 +1656,15 @@ func TestMergeConfig(t *testing.T) { UDPAnswerLimit: 4, RecursorTimeout: 30 * time.Second, }, - Domain: "other", - LogLevel: "info", - NodeID: "bar", - NodeName: "baz", - ClientAddr: "127.0.0.2", - BindAddr: "127.0.0.2", - AdvertiseAddr: "127.0.0.2", - AdvertiseAddrWan: "127.0.0.2", + Domain: "other", + LogLevel: "info", + NodeID: "bar", + DisableHostNodeID: true, + NodeName: "baz", + ClientAddr: "127.0.0.2", + BindAddr: "127.0.0.2", + AdvertiseAddr: "127.0.0.2", + AdvertiseAddrWan: "127.0.0.2", Ports: PortConfig{ DNS: 1, HTTP: 2, diff --git a/website/source/docs/agent/options.html.markdown b/website/source/docs/agent/options.html.markdown index add252a391..9c3b09904b 100644 --- a/website/source/docs/agent/options.html.markdown +++ b/website/source/docs/agent/options.html.markdown @@ -151,17 +151,22 @@ will exit with an error at startup. the use of filesystem locking, meaning some types of mounted folders (e.g. VirtualBox shared folders) may not be suitable. +* `-datacenter` - This flag controls the datacenter in + which the agent is running. If not provided, + it defaults to "dc1". Consul has first-class support for multiple datacenters, but + it relies on proper configuration. Nodes in the same datacenter should be on a single + LAN. + * `-dev` - Enable development server mode. This is useful for quickly starting a Consul agent with all persistence options turned off, enabling an in-memory server which can be used for rapid prototyping or developing against the API. This mode is **not** intended for production use as it does not write any data to disk. -* `-datacenter` - This flag controls the datacenter in - which the agent is running. If not provided, - it defaults to "dc1". Consul has first-class support for multiple datacenters, but - it relies on proper configuration. Nodes in the same datacenter should be on a single - LAN. +* `-disable-host-node-id` - Setting + this to true will prevent Consul from using information from the host to generate a deterministic node ID, + and will instead generate a random node ID which will be persisted in the data directory. This is useful + when running multiple Consul agents on the same host for testing. This defaults to false. * `-dns-port` - the DNS port to listen on. This overrides the default port 8600. This is available in Consul 0.7 and later. @@ -295,11 +300,9 @@ will exit with an error at startup. changes. This must be in the form of a hex string, 36 characters long, such as `adf4238a-882b-9ddc-4a9d-5b6758e4159e`. If this isn't supplied, which is the most common case, then the agent will generate an identifier at startup and persist it in the data directory - so that it will remain the same across agent restarts. This is currently only exposed via - /v1/agent/self, - /v1/catalog, and - /v1/health endpoints, but future versions of - Consul will use this to better manage cluster changes, especially for Consul servers. + so that it will remain the same across agent restarts. Information from the host will be used to + generate a deterministic node ID if possible, unless [`-disable-host-node-id`](#_disable_host_node_id) is + set to true. * `-node-meta` - Available in Consul 0.7.3 and later, this specifies an arbitrary metadata key/value pair to associate with the node, of the form `key:value`. @@ -636,6 +639,9 @@ Consul will not enable TLS for the HTTP API unless the `https` port has been ass `disable_anonymous_signature` Disables providing an anonymous signature for de-duplication with the update check. See [`disable_update_check`](#disable_update_check). +* `disable_host_node_id` + Equivalent to the [`-disable-host-node-id` command-line flag](#_disable_host_node_id). + * `disable_remote_exec` Disables support for remote execution. When set to true, the agent will ignore any incoming remote exec requests. In versions of Consul prior to 0.8, this defaulted to false. In Consul