From 6a835939b8314593f55bd25a4540ea7e73591a47 Mon Sep 17 00:00:00 2001 From: Shawn Cook Date: Tue, 18 Aug 2015 10:34:55 -0700 Subject: [PATCH 01/11] EnableTagDrift in NodeService struct --- command/agent/config_test.go | 11 +++++++++++ command/agent/local.go | 1 + command/agent/structs.go | 28 +++++++++++++++------------- consul/structs/structs.go | 11 ++++++----- testutil/server.go | 2 ++ 5 files changed, 35 insertions(+), 18 deletions(-) diff --git a/command/agent/config_test.go b/command/agent/config_test.go index ed2a2921e065..ba84348dd201 100644 --- a/command/agent/config_test.go +++ b/command/agent/config_test.go @@ -683,9 +683,19 @@ func TestDecodeConfig(t *testing.T) { t.Fatalf("err: %s", err) } + // EnableTagDrift + input = `{"enable_tag_drift": true}` + config, err = DecodeConfig(bytes.NewReader([]byte(input))) + if err != nil { + t.Fatalf("err: %s", err) + } + if !config.DisableUpdateCheck { t.Fatalf("bad: %#v", config) } + if !config.EnableTagDrift { + t.Fatalf("bad: %#v", config) + } if !config.DisableAnonymousSignature { t.Fatalf("bad: %#v", config) } @@ -1189,6 +1199,7 @@ func TestMergeConfig(t *testing.T) { StatsitePrefix: "stats_prefix", StatsdAddr: "127.0.0.1:7251", DisableUpdateCheck: true, + EnableTagDrift: true, DisableAnonymousSignature: true, HTTPAPIResponseHeaders: map[string]string{ "Access-Control-Allow-Origin": "*", diff --git a/command/agent/local.go b/command/agent/local.go index dbe38e79d025..1ba9cbedc533 100644 --- a/command/agent/local.go +++ b/command/agent/local.go @@ -379,6 +379,7 @@ func (l *localState) setSyncState() error { } // If our definition is different, we need to update it + l.logger.Printf("[ERR] services: %v", service) equal := reflect.DeepEqual(existing, service) l.serviceStatus[id] = syncStatus{inSync: equal} } diff --git a/command/agent/structs.go b/command/agent/structs.go index 1d0e41e8bc68..3809699eedb5 100644 --- a/command/agent/structs.go +++ b/command/agent/structs.go @@ -6,23 +6,25 @@ import ( // ServiceDefinition is used to JSON decode the Service definitions type ServiceDefinition struct { - ID string - Name string - Tags []string - Address string - Port int - Check CheckType - Checks CheckTypes - Token string + ID string + Name string + Tags []string + Address string + Port int + Check CheckType + Checks CheckTypes + Token string + EnableTagDrift bool } func (s *ServiceDefinition) NodeService() *structs.NodeService { ns := &structs.NodeService{ - ID: s.ID, - Service: s.Name, - Tags: s.Tags, - Address: s.Address, - Port: s.Port, + ID: s.ID, + Service: s.Name, + Tags: s.Tags, + Address: s.Address, + Port: s.Port, + EnableTagDrift: s.EnableTagDrift, } if ns.ID == "" && ns.Service != "" { ns.ID = ns.Service diff --git a/consul/structs/structs.go b/consul/structs/structs.go index 60d980028a1f..ec1976bf796c 100644 --- a/consul/structs/structs.go +++ b/consul/structs/structs.go @@ -245,11 +245,12 @@ type ServiceNodes []ServiceNode // NodeService is a service provided by a node type NodeService struct { - ID string - Service string - Tags []string - Address string - Port int + ID string + Service string + Tags []string + Address string + Port int + EnableTagDrift bool } type NodeServices struct { Node Node diff --git a/testutil/server.go b/testutil/server.go index 66b4f9509770..c02317effe3d 100644 --- a/testutil/server.go +++ b/testutil/server.go @@ -55,6 +55,7 @@ type TestServerConfig struct { DataDir string `json:"data_dir,omitempty"` Datacenter string `json:"datacenter,omitempty"` DisableCheckpoint bool `json:"disable_update_check"` + EnableTagDrift bool `json:"enable_tag_drift"` LogLevel string `json:"log_level,omitempty"` Bind string `json:"bind_addr,omitempty"` Addresses *TestAddressConfig `json:"addresses,omitempty"` @@ -77,6 +78,7 @@ func defaultServerConfig() *TestServerConfig { return &TestServerConfig{ NodeName: fmt.Sprintf("node%d", idx), DisableCheckpoint: true, + EnableTagDrift: true, Bootstrap: true, Server: true, LogLevel: "debug", From 152eca3a37d4e1076ef0e16cffbb61a18c4030fc Mon Sep 17 00:00:00 2001 From: Shawn Cook Date: Tue, 18 Aug 2015 10:41:17 -0700 Subject: [PATCH 02/11] Remove from testutil/server.go --- testutil/server.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/testutil/server.go b/testutil/server.go index c02317effe3d..66b4f9509770 100644 --- a/testutil/server.go +++ b/testutil/server.go @@ -55,7 +55,6 @@ type TestServerConfig struct { DataDir string `json:"data_dir,omitempty"` Datacenter string `json:"datacenter,omitempty"` DisableCheckpoint bool `json:"disable_update_check"` - EnableTagDrift bool `json:"enable_tag_drift"` LogLevel string `json:"log_level,omitempty"` Bind string `json:"bind_addr,omitempty"` Addresses *TestAddressConfig `json:"addresses,omitempty"` @@ -78,7 +77,6 @@ func defaultServerConfig() *TestServerConfig { return &TestServerConfig{ NodeName: fmt.Sprintf("node%d", idx), DisableCheckpoint: true, - EnableTagDrift: true, Bootstrap: true, Server: true, LogLevel: "debug", From a0f8c0a2a056e1077bdfebcb2cdaa58762258898 Mon Sep 17 00:00:00 2001 From: Shawn Cook Date: Tue, 18 Aug 2015 10:42:25 -0700 Subject: [PATCH 03/11] Remove from command/agent/config_test.go --- command/agent/config_test.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/command/agent/config_test.go b/command/agent/config_test.go index ba84348dd201..ed2a2921e065 100644 --- a/command/agent/config_test.go +++ b/command/agent/config_test.go @@ -683,19 +683,9 @@ func TestDecodeConfig(t *testing.T) { t.Fatalf("err: %s", err) } - // EnableTagDrift - input = `{"enable_tag_drift": true}` - config, err = DecodeConfig(bytes.NewReader([]byte(input))) - if err != nil { - t.Fatalf("err: %s", err) - } - if !config.DisableUpdateCheck { t.Fatalf("bad: %#v", config) } - if !config.EnableTagDrift { - t.Fatalf("bad: %#v", config) - } if !config.DisableAnonymousSignature { t.Fatalf("bad: %#v", config) } @@ -1199,7 +1189,6 @@ func TestMergeConfig(t *testing.T) { StatsitePrefix: "stats_prefix", StatsdAddr: "127.0.0.1:7251", DisableUpdateCheck: true, - EnableTagDrift: true, DisableAnonymousSignature: true, HTTPAPIResponseHeaders: map[string]string{ "Access-Control-Allow-Origin": "*", From 96785edd9a6eca327567262b63966030371fea9f Mon Sep 17 00:00:00 2001 From: Shawn Cook Date: Tue, 18 Aug 2015 14:03:48 -0700 Subject: [PATCH 04/11] Add EnableTagDrift logic to command/agent/local.go --- command/agent/local.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/command/agent/local.go b/command/agent/local.go index 1ba9cbedc533..483bdd668a59 100644 --- a/command/agent/local.go +++ b/command/agent/local.go @@ -379,7 +379,12 @@ func (l *localState) setSyncState() error { } // If our definition is different, we need to update it - l.logger.Printf("[ERR] services: %v", service) + if existing.EnableTagDrift { + l.logger.Printf("[DEBUG] Tag drift enabled.") + existing.Tags = service.Tags + } else { + l.logger.Printf("[DEBUG] Tag drift disabled.") + } equal := reflect.DeepEqual(existing, service) l.serviceStatus[id] = syncStatus{inSync: equal} } From ab91590bcb9ead3b0d2e73a28f4cea7246a11a5f Mon Sep 17 00:00:00 2001 From: Shawn Cook Date: Thu, 20 Aug 2015 09:09:26 -0700 Subject: [PATCH 05/11] Update tests - NodeService init needs bool --- command/exec_test.go | 2 +- consul/catalog_endpoint_test.go | 12 ++--- consul/fsm_test.go | 8 ++-- consul/state_store_test.go | 82 +++++++++++++++++---------------- 4 files changed, 53 insertions(+), 51 deletions(-) diff --git a/command/exec_test.go b/command/exec_test.go index 4377756a0cd4..36c5a1d85197 100644 --- a/command/exec_test.go +++ b/command/exec_test.go @@ -27,7 +27,7 @@ func TestExecCommandRun(t *testing.T) { code := c.Run(args) if code != 0 { - t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String()) + t.Fatalf("bad: %d. Error:%#v (std)Output:%#v", code, ui.ErrorWriter.String(), ui.OutputWriter.String()) } if !strings.Contains(ui.OutputWriter.String(), "load") { diff --git a/consul/catalog_endpoint_test.go b/consul/catalog_endpoint_test.go index 4b627abc8cb6..7f927a4e9b9f 100644 --- a/consul/catalog_endpoint_test.go +++ b/consul/catalog_endpoint_test.go @@ -490,7 +490,7 @@ func TestCatalogListServices(t *testing.T) { // Just add a node s1.fsm.State().EnsureNode(1, structs.Node{"foo", "127.0.0.1"}) - s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000}) + s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000, false}) if err := client.Call("Catalog.ListServices", &args, &out); err != nil { t.Fatalf("err: %v", err) @@ -544,7 +544,7 @@ func TestCatalogListServices_Blocking(t *testing.T) { go func() { time.Sleep(100 * time.Millisecond) s1.fsm.State().EnsureNode(1, structs.Node{"foo", "127.0.0.1"}) - s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000}) + s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000, false}) }() // Re-run the query @@ -625,7 +625,7 @@ func TestCatalogListServices_Stale(t *testing.T) { // Inject a fake service s1.fsm.State().EnsureNode(1, structs.Node{"foo", "127.0.0.1"}) - s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000}) + s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000, false}) // Run the query, do not wait for leader! if err := client.Call("Catalog.ListServices", &args, &out); err != nil { @@ -666,7 +666,7 @@ func TestCatalogListServiceNodes(t *testing.T) { // Just add a node s1.fsm.State().EnsureNode(1, structs.Node{"foo", "127.0.0.1"}) - s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000}) + s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000, false}) if err := client.Call("Catalog.ServiceNodes", &args, &out); err != nil { t.Fatalf("err: %v", err) @@ -709,8 +709,8 @@ func TestCatalogNodeServices(t *testing.T) { // Just add a node s1.fsm.State().EnsureNode(1, structs.Node{"foo", "127.0.0.1"}) - s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000}) - s1.fsm.State().EnsureService(3, "foo", &structs.NodeService{"web", "web", nil, "127.0.0.1", 80}) + s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000, false}) + s1.fsm.State().EnsureService(3, "foo", &structs.NodeService{"web", "web", nil, "127.0.0.1", 80, false}) if err := client.Call("Catalog.NodeServices", &args, &out); err != nil { t.Fatalf("err: %v", err) diff --git a/consul/fsm_test.go b/consul/fsm_test.go index e08de2369a9d..28594de41843 100644 --- a/consul/fsm_test.go +++ b/consul/fsm_test.go @@ -343,10 +343,10 @@ func TestFSM_SnapshotRestore(t *testing.T) { // Add some state fsm.state.EnsureNode(1, structs.Node{"foo", "127.0.0.1"}) fsm.state.EnsureNode(2, structs.Node{"baz", "127.0.0.2"}) - fsm.state.EnsureService(3, "foo", &structs.NodeService{"web", "web", nil, "127.0.0.1", 80}) - fsm.state.EnsureService(4, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000}) - fsm.state.EnsureService(5, "baz", &structs.NodeService{"web", "web", nil, "127.0.0.2", 80}) - fsm.state.EnsureService(6, "baz", &structs.NodeService{"db", "db", []string{"secondary"}, "127.0.0.2", 5000}) + fsm.state.EnsureService(3, "foo", &structs.NodeService{"web", "web", nil, "127.0.0.1", 80, false}) + fsm.state.EnsureService(4, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000, false}) + fsm.state.EnsureService(5, "baz", &structs.NodeService{"web", "web", nil, "127.0.0.2", 80, false}) + fsm.state.EnsureService(6, "baz", &structs.NodeService{"db", "db", []string{"secondary"}, "127.0.0.2", 5000, false}) fsm.state.EnsureCheck(7, &structs.HealthCheck{ Node: "foo", CheckID: "web", diff --git a/consul/state_store_test.go b/consul/state_store_test.go index 97592c11d5ea..13a0044ba57b 100644 --- a/consul/state_store_test.go +++ b/consul/state_store_test.go @@ -24,7 +24,7 @@ func TestEnsureRegistration(t *testing.T) { reg := &structs.RegisterRequest{ Node: "foo", Address: "127.0.0.1", - Service: &structs.NodeService{"api", "api", nil, "", 5000}, + Service: &structs.NodeService{"api", "api", nil, "", 5000, false}, Check: &structs.HealthCheck{ Node: "foo", CheckID: "api", @@ -189,15 +189,15 @@ func TestEnsureService(t *testing.T) { t.Fatalf("err: %v", err) } - if err := store.EnsureService(11, "foo", &structs.NodeService{"api", "api", nil, "", 5000}); err != nil { + if err := store.EnsureService(11, "foo", &structs.NodeService{"api", "api", nil, "", 5000, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(12, "foo", &structs.NodeService{"api", "api", nil, "", 5001}); err != nil { + if err := store.EnsureService(12, "foo", &structs.NodeService{"api", "api", nil, "", 5001, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(13, "foo", &structs.NodeService{"db", "db", []string{"master"}, "", 8000}); err != nil { + if err := store.EnsureService(13, "foo", &structs.NodeService{"db", "db", []string{"master"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } @@ -234,15 +234,15 @@ func TestEnsureService_DuplicateNode(t *testing.T) { t.Fatalf("err: %v", err) } - if err := store.EnsureService(11, "foo", &structs.NodeService{"api1", "api", nil, "", 5000}); err != nil { + if err := store.EnsureService(11, "foo", &structs.NodeService{"api1", "api", nil, "", 5000, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(12, "foo", &structs.NodeService{"api2", "api", nil, "", 5001}); err != nil { + if err := store.EnsureService(12, "foo", &structs.NodeService{"api2", "api", nil, "", 5001, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(13, "foo", &structs.NodeService{"api3", "api", nil, "", 5002}); err != nil { + if err := store.EnsureService(13, "foo", &structs.NodeService{"api3", "api", nil, "", 5002, false}); err != nil { t.Fatalf("err: %v", err) } @@ -287,7 +287,7 @@ func TestDeleteNodeService(t *testing.T) { t.Fatalf("err: %v", err) } - if err := store.EnsureService(12, "foo", &structs.NodeService{"api", "api", nil, "", 5000}); err != nil { + if err := store.EnsureService(12, "foo", &structs.NodeService{"api", "api", nil, "", 5000, false}); err != nil { t.Fatalf("err: %v", err) } @@ -335,11 +335,11 @@ func TestDeleteNodeService_One(t *testing.T) { t.Fatalf("err: %v", err) } - if err := store.EnsureService(12, "foo", &structs.NodeService{"api", "api", nil, "", 5000}); err != nil { + if err := store.EnsureService(12, "foo", &structs.NodeService{"api", "api", nil, "", 5000, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(13, "foo", &structs.NodeService{"api2", "api", nil, "", 5001}); err != nil { + if err := store.EnsureService(13, "foo", &structs.NodeService{"api2", "api", nil, "", 5001, false}); err != nil { t.Fatalf("err: %v", err) } @@ -372,7 +372,7 @@ func TestDeleteNode(t *testing.T) { t.Fatalf("err: %v", err) } - if err := store.EnsureService(21, "foo", &structs.NodeService{"api", "api", nil, "", 5000}); err != nil { + if err := store.EnsureService(21, "foo", &structs.NodeService{"api", "api", nil, "", 5000, false}); err != nil { t.Fatalf("err: %v", err) } @@ -431,15 +431,15 @@ func TestGetServices(t *testing.T) { t.Fatalf("err: %v", err) } - if err := store.EnsureService(32, "foo", &structs.NodeService{"api", "api", nil, "", 5000}); err != nil { + if err := store.EnsureService(32, "foo", &structs.NodeService{"api", "api", nil, "", 5000, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(33, "foo", &structs.NodeService{"db", "db", []string{"master"}, "", 8000}); err != nil { + if err := store.EnsureService(33, "foo", &structs.NodeService{"db", "db", []string{"master"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(34, "bar", &structs.NodeService{"db", "db", []string{"slave"}, "", 8000}); err != nil { + if err := store.EnsureService(34, "bar", &structs.NodeService{"db", "db", []string{"slave"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } @@ -481,23 +481,23 @@ func TestServiceNodes(t *testing.T) { t.Fatalf("err: %v", err) } - if err := store.EnsureService(12, "foo", &structs.NodeService{"api", "api", nil, "", 5000}); err != nil { + if err := store.EnsureService(12, "foo", &structs.NodeService{"api", "api", nil, "", 5000, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(13, "bar", &structs.NodeService{"api", "api", nil, "", 5000}); err != nil { + if err := store.EnsureService(13, "bar", &structs.NodeService{"api", "api", nil, "", 5000, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(14, "foo", &structs.NodeService{"db", "db", []string{"master"}, "", 8000}); err != nil { + if err := store.EnsureService(14, "foo", &structs.NodeService{"db", "db", []string{"master"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(15, "bar", &structs.NodeService{"db", "db", []string{"slave"}, "", 8000}); err != nil { + if err := store.EnsureService(15, "bar", &structs.NodeService{"db", "db", []string{"slave"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(16, "bar", &structs.NodeService{"db2", "db", []string{"slave"}, "", 8001}); err != nil { + if err := store.EnsureService(16, "bar", &structs.NodeService{"db2", "db", []string{"slave"}, "", 8001, false}); err != nil { t.Fatalf("err: %v", err) } @@ -572,15 +572,15 @@ func TestServiceTagNodes(t *testing.T) { t.Fatalf("err: %v", err) } - if err := store.EnsureService(17, "foo", &structs.NodeService{"db", "db", []string{"master"}, "", 8000}); err != nil { + if err := store.EnsureService(17, "foo", &structs.NodeService{"db", "db", []string{"master"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(18, "foo", &structs.NodeService{"db2", "db", []string{"slave"}, "", 8001}); err != nil { + if err := store.EnsureService(18, "foo", &structs.NodeService{"db2", "db", []string{"slave"}, "", 8001, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(19, "bar", &structs.NodeService{"db", "db", []string{"slave"}, "", 8000}); err != nil { + if err := store.EnsureService(19, "bar", &structs.NodeService{"db", "db", []string{"slave"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } @@ -620,15 +620,15 @@ func TestServiceTagNodes_MultipleTags(t *testing.T) { t.Fatalf("err: %v", err) } - if err := store.EnsureService(17, "foo", &structs.NodeService{"db", "db", []string{"master", "v2"}, "", 8000}); err != nil { + if err := store.EnsureService(17, "foo", &structs.NodeService{"db", "db", []string{"master", "v2"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(18, "foo", &structs.NodeService{"db2", "db", []string{"slave", "v2", "dev"}, "", 8001}); err != nil { + if err := store.EnsureService(18, "foo", &structs.NodeService{"db2", "db", []string{"slave", "v2", "dev"}, "", 8001, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(19, "bar", &structs.NodeService{"db", "db", []string{"slave", "v2"}, "", 8000}); err != nil { + if err := store.EnsureService(19, "bar", &structs.NodeService{"db", "db", []string{"slave", "v2"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } @@ -696,15 +696,15 @@ func TestStoreSnapshot(t *testing.T) { t.Fatalf("err: %v", err) } - if err := store.EnsureService(10, "foo", &structs.NodeService{"db", "db", []string{"master"}, "", 8000}); err != nil { + if err := store.EnsureService(10, "foo", &structs.NodeService{"db", "db", []string{"master"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(11, "foo", &structs.NodeService{"db2", "db", []string{"slave"}, "", 8001}); err != nil { + if err := store.EnsureService(11, "foo", &structs.NodeService{"db2", "db", []string{"slave"}, "", 8001, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(12, "bar", &structs.NodeService{"db", "db", []string{"slave"}, "", 8000}); err != nil { + if err := store.EnsureService(12, "bar", &structs.NodeService{"db", "db", []string{"slave"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } @@ -889,10 +889,10 @@ func TestStoreSnapshot(t *testing.T) { } // Make some changes! - if err := store.EnsureService(23, "foo", &structs.NodeService{"db", "db", []string{"slave"}, "", 8000}); err != nil { + if err := store.EnsureService(23, "foo", &structs.NodeService{"db", "db", []string{"slave"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(24, "bar", &structs.NodeService{"db", "db", []string{"master"}, "", 8000}); err != nil { + if err := store.EnsureService(24, "bar", &structs.NodeService{"db", "db", []string{"master"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } if err := store.EnsureNode(25, structs.Node{"baz", "127.0.0.3"}); err != nil { @@ -1019,7 +1019,7 @@ func TestEnsureCheck(t *testing.T) { if err := store.EnsureNode(1, structs.Node{"foo", "127.0.0.1"}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000}); err != nil { + if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } check := &structs.HealthCheck{ @@ -1115,7 +1115,7 @@ func TestDeleteNodeCheck(t *testing.T) { if err := store.EnsureNode(1, structs.Node{"foo", "127.0.0.1"}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000}); err != nil { + if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } check := &structs.HealthCheck{ @@ -1165,7 +1165,7 @@ func TestCheckServiceNodes(t *testing.T) { if err := store.EnsureNode(1, structs.Node{"foo", "127.0.0.1"}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000}); err != nil { + if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } check := &structs.HealthCheck{ @@ -1246,7 +1246,7 @@ func BenchmarkCheckServiceNodes(t *testing.B) { if err := store.EnsureNode(1, structs.Node{"foo", "127.0.0.1"}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000}); err != nil { + if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } check := &structs.HealthCheck{ @@ -1290,7 +1290,8 @@ func TestSS_Register_Deregister_Query(t *testing.T) { "statsite-box-stats", nil, "", - 0} + 0, + false} if err := store.EnsureService(2, "foo", srv); err != nil { t.Fatalf("err: %v", err) } @@ -1300,7 +1301,8 @@ func TestSS_Register_Deregister_Query(t *testing.T) { "statsite-share-stats", nil, "", - 0} + 0, + false} if err := store.EnsureService(3, "foo", srv); err != nil { t.Fatalf("err: %v", err) } @@ -1328,7 +1330,7 @@ func TestNodeInfo(t *testing.T) { if err := store.EnsureNode(1, structs.Node{"foo", "127.0.0.1"}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000}); err != nil { + if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } check := &structs.HealthCheck{ @@ -1387,13 +1389,13 @@ func TestNodeDump(t *testing.T) { if err := store.EnsureNode(1, structs.Node{"foo", "127.0.0.1"}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000}); err != nil { + if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } if err := store.EnsureNode(3, structs.Node{"baz", "127.0.0.2"}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(4, "baz", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000}); err != nil { + if err := store.EnsureService(4, "baz", &structs.NodeService{"db1", "db", []string{"master"}, "", 8000, false}); err != nil { t.Fatalf("err: %v", err) } @@ -2577,7 +2579,7 @@ func TestSessionInvalidate_DeleteNodeService(t *testing.T) { if err := store.EnsureNode(11, structs.Node{"foo", "127.0.0.1"}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(12, "foo", &structs.NodeService{"api", "api", nil, "", 5000}); err != nil { + if err := store.EnsureService(12, "foo", &structs.NodeService{"api", "api", nil, "", 5000, false}); err != nil { t.Fatalf("err: %v", err) } check := &structs.HealthCheck{ From 35f276f25ddfa1147ba9410b7d98e33b245afcd9 Mon Sep 17 00:00:00 2001 From: Shawn Cook Date: Thu, 10 Sep 2015 14:08:16 -0700 Subject: [PATCH 06/11] Add test cases TestAgentAntiEntropy_EnableTagDrift --- command/agent/local_test.go | 96 +++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/command/agent/local_test.go b/command/agent/local_test.go index 997860279345..e149d4be3926 100644 --- a/command/agent/local_test.go +++ b/command/agent/local_test.go @@ -169,6 +169,102 @@ func TestAgentAntiEntropy_Services(t *testing.T) { } } +func TestAgentAntiEntropy_EnableTagDrift(t *testing.T) { + conf := nextConfig() + dir, agent := makeAgent(t, conf) + defer os.RemoveAll(dir) + defer agent.Shutdown() + + testutil.WaitForLeader(t, agent.RPC, "dc1") + + args := &structs.RegisterRequest{ + Datacenter: "dc1", + Node: agent.config.NodeName, + Address: "127.0.0.1", + } + var out struct{} + + // EnableTagDrift = true + srv1 := &structs.NodeService{ + ID: "svc_id1", + Service: "svc1", + Tags: []string{"tag1"}, + Port: 6100, + EnableTagDrift: true, + } + agent.state.AddService(srv1, "") + srv1_mod := new(structs.NodeService) + *srv1_mod = *srv1 + srv1_mod.Port = 7100 + srv1_mod.Tags = []string{"tag1_mod"} + args.Service = srv1_mod + if err := agent.RPC("Catalog.Register", args, &out); err != nil { + t.Fatalf("err: %v", err) + } + + // EnableTagDrift = false + srv2 := &structs.NodeService{ + ID: "svc_id2", + Service: "svc2", + Tags: []string{"tag2"}, + Port: 6200, + EnableTagDrift: false, + } + agent.state.AddService(srv2, "") + srv2_mod := new(structs.NodeService) + *srv2_mod = *srv2 + srv2_mod.Port = 7200 + srv2_mod.Tags = []string{"tag2_mod"} + args.Service = srv2_mod + if err := agent.RPC("Catalog.Register", args, &out); err != nil { + t.Fatalf("err: %v", err) + } + + // Trigger anti-entropy run and wait + agent.StartSync() + time.Sleep(200 * time.Millisecond) + + // Verify that we are in sync + req := structs.NodeSpecificRequest{ + Datacenter: "dc1", + Node: agent.config.NodeName, + } + var services structs.IndexedNodeServices + if err := agent.RPC("Catalog.NodeServices", &req, &services); err != nil { + t.Fatalf("err: %v", err) + } + + // All the services should match + for id, serv := range services.NodeServices.Services { + switch id { + case "svc_id1": + if serv.ID!="svc_id1" || + serv.Service!="svc1" || + serv.Port!=6100 || + !reflect.DeepEqual(serv.Tags, []string{"tag1_mod"}) { + t.Fatalf("bad: %v %v", serv, srv1) + } + case "svc_id2": + if serv.ID!="svc_id2" || + serv.Service!="svc2" || + serv.Port!=6200 || + !reflect.DeepEqual(serv.Tags, []string{"tag2"}) { + t.Fatalf("bad: %v %v", serv, srv2) + } + case "consul": + // ignore + default: + t.Fatalf("unexpected service: %v", id) + } + } + + for name, status := range agent.state.serviceStatus { + if !status.inSync { + t.Fatalf("should be in sync: %v %v", name, status) + } + } +} + func TestAgentAntiEntropy_Services_WithChecks(t *testing.T) { conf := nextConfig() dir, agent := makeAgent(t, conf) From d7ce0b3c6b54ab2c443bc3bb43ff23e963927f34 Mon Sep 17 00:00:00 2001 From: Shawn Cook Date: Fri, 11 Sep 2015 08:32:59 -0700 Subject: [PATCH 07/11] Remove debug lines --- command/agent/local.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/command/agent/local.go b/command/agent/local.go index 483bdd668a59..849eb9ae5e09 100644 --- a/command/agent/local.go +++ b/command/agent/local.go @@ -380,10 +380,7 @@ func (l *localState) setSyncState() error { // If our definition is different, we need to update it if existing.EnableTagDrift { - l.logger.Printf("[DEBUG] Tag drift enabled.") existing.Tags = service.Tags - } else { - l.logger.Printf("[DEBUG] Tag drift disabled.") } equal := reflect.DeepEqual(existing, service) l.serviceStatus[id] = syncStatus{inSync: equal} From 66fd8fb2a099d470f21a1b820873202463aed8c2 Mon Sep 17 00:00:00 2001 From: Shawn Cook Date: Fri, 11 Sep 2015 08:35:29 -0700 Subject: [PATCH 08/11] Rename EnableTagOverride and update formatting --- command/agent/local.go | 2 +- command/agent/local_test.go | 50 ++++++++++++++++++------------------- command/agent/structs.go | 30 +++++++++++----------- consul/structs/structs.go | 12 ++++----- 4 files changed, 47 insertions(+), 47 deletions(-) diff --git a/command/agent/local.go b/command/agent/local.go index 849eb9ae5e09..4e6a944a8c97 100644 --- a/command/agent/local.go +++ b/command/agent/local.go @@ -379,7 +379,7 @@ func (l *localState) setSyncState() error { } // If our definition is different, we need to update it - if existing.EnableTagDrift { + if existing.EnableTagOverride { existing.Tags = service.Tags } equal := reflect.DeepEqual(existing, service) diff --git a/command/agent/local_test.go b/command/agent/local_test.go index e149d4be3926..4b7b566e267b 100644 --- a/command/agent/local_test.go +++ b/command/agent/local_test.go @@ -169,28 +169,28 @@ func TestAgentAntiEntropy_Services(t *testing.T) { } } -func TestAgentAntiEntropy_EnableTagDrift(t *testing.T) { +func TestAgentAntiEntropy_EnableTagOverride(t *testing.T) { conf := nextConfig() dir, agent := makeAgent(t, conf) defer os.RemoveAll(dir) defer agent.Shutdown() testutil.WaitForLeader(t, agent.RPC, "dc1") - + args := &structs.RegisterRequest{ Datacenter: "dc1", Node: agent.config.NodeName, Address: "127.0.0.1", } var out struct{} - - // EnableTagDrift = true + + // EnableTagOverride = true srv1 := &structs.NodeService{ - ID: "svc_id1", - Service: "svc1", - Tags: []string{"tag1"}, - Port: 6100, - EnableTagDrift: true, + ID: "svc_id1", + Service: "svc1", + Tags: []string{"tag1"}, + Port: 6100, + EnableTagOverride: true, } agent.state.AddService(srv1, "") srv1_mod := new(structs.NodeService) @@ -201,14 +201,14 @@ func TestAgentAntiEntropy_EnableTagDrift(t *testing.T) { if err := agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } - - // EnableTagDrift = false + + // EnableTagOverride = false srv2 := &structs.NodeService{ - ID: "svc_id2", - Service: "svc2", - Tags: []string{"tag2"}, - Port: 6200, - EnableTagDrift: false, + ID: "svc_id2", + Service: "svc2", + Tags: []string{"tag2"}, + Port: 6200, + EnableTagOverride: false, } agent.state.AddService(srv2, "") srv2_mod := new(structs.NodeService) @@ -219,7 +219,7 @@ func TestAgentAntiEntropy_EnableTagDrift(t *testing.T) { if err := agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } - + // Trigger anti-entropy run and wait agent.StartSync() time.Sleep(200 * time.Millisecond) @@ -238,18 +238,18 @@ func TestAgentAntiEntropy_EnableTagDrift(t *testing.T) { for id, serv := range services.NodeServices.Services { switch id { case "svc_id1": - if serv.ID!="svc_id1" || - serv.Service!="svc1" || - serv.Port!=6100 || + if serv.ID != "svc_id1" || + serv.Service != "svc1" || + serv.Port != 6100 || !reflect.DeepEqual(serv.Tags, []string{"tag1_mod"}) { - t.Fatalf("bad: %v %v", serv, srv1) + t.Fatalf("bad: %v %v", serv, srv1) } case "svc_id2": - if serv.ID!="svc_id2" || - serv.Service!="svc2" || - serv.Port!=6200 || + if serv.ID != "svc_id2" || + serv.Service != "svc2" || + serv.Port != 6200 || !reflect.DeepEqual(serv.Tags, []string{"tag2"}) { - t.Fatalf("bad: %v %v", serv, srv2) + t.Fatalf("bad: %v %v", serv, srv2) } case "consul": // ignore diff --git a/command/agent/structs.go b/command/agent/structs.go index 3809699eedb5..5ebc3b4559a8 100644 --- a/command/agent/structs.go +++ b/command/agent/structs.go @@ -6,25 +6,25 @@ import ( // ServiceDefinition is used to JSON decode the Service definitions type ServiceDefinition struct { - ID string - Name string - Tags []string - Address string - Port int - Check CheckType - Checks CheckTypes - Token string - EnableTagDrift bool + ID string + Name string + Tags []string + Address string + Port int + Check CheckType + Checks CheckTypes + Token string + EnableTagOverride bool } func (s *ServiceDefinition) NodeService() *structs.NodeService { ns := &structs.NodeService{ - ID: s.ID, - Service: s.Name, - Tags: s.Tags, - Address: s.Address, - Port: s.Port, - EnableTagDrift: s.EnableTagDrift, + ID: s.ID, + Service: s.Name, + Tags: s.Tags, + Address: s.Address, + Port: s.Port, + EnableTagOverride: s.EnableTagOverride, } if ns.ID == "" && ns.Service != "" { ns.ID = ns.Service diff --git a/consul/structs/structs.go b/consul/structs/structs.go index ec1976bf796c..3f2faf5d568c 100644 --- a/consul/structs/structs.go +++ b/consul/structs/structs.go @@ -245,12 +245,12 @@ type ServiceNodes []ServiceNode // NodeService is a service provided by a node type NodeService struct { - ID string - Service string - Tags []string - Address string - Port int - EnableTagDrift bool + ID string + Service string + Tags []string + Address string + Port int + EnableTagOverride bool } type NodeServices struct { Node Node From 4caf049c4cdd92149c38dc6e98c987a27516a1fd Mon Sep 17 00:00:00 2001 From: Shawn Cook Date: Fri, 11 Sep 2015 09:32:54 -0700 Subject: [PATCH 09/11] Update documentation for service definition --- .../source/docs/agent/services.html.markdown | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/website/source/docs/agent/services.html.markdown b/website/source/docs/agent/services.html.markdown index 1b589b31b0fc..b9e13645bd21 100644 --- a/website/source/docs/agent/services.html.markdown +++ b/website/source/docs/agent/services.html.markdown @@ -26,6 +26,7 @@ A service definition that is a script looks like: "tags": ["master"], "address": "127.0.0.1", "port": 8000, + "enableTagOverride": false, "checks": [ { "script": "/usr/local/bin/check_redis.py", @@ -37,9 +38,9 @@ A service definition that is a script looks like: ``` A service definition must include a `name` and may optionally provide -an `id`, `tags`, `address`, `port`, and `check`. The `id` is set to the `name` if not -provided. It is required that all services have a unique ID per node, so if names -might conflict then unique IDs should be provided. +an `id`, `tags`, `address`, `port`, `check`, and `enableTagOverride`. The `id` is +set to the `name` if not provided. It is required that all services have a unique +ID per node, so if names might conflict then unique IDs should be provided. The `tags` property is a list of values that are opaque to Consul but can be used to distinguish between "master" or "slave" nodes, different versions, or any other service @@ -73,6 +74,24 @@ from `1`. Note: there is more information about [checks here](/docs/agent/checks.html). +The `enableTagOverride` can optionally specified to disable the antientropy feature for +this service. If `enableTagOverride` is set to TRUE then external agents can +reregister this service and modify the tags. Subsequent local sync operations +by this agent will ignore the updated tags. For instance: If an external agent +modified both the tags and the port for this service and `enableTagOverride` +was set to TRUE then after the next sync cycle the service's port would revert +to the original value but the tags would maintain the updated value. As a +counter example: If an external agent modified both the tags and port for this +service and `enableTagOverride` was set to FALSE then after the next sync +cycle the service's port AND the tags would revert to the original value and +all modifications would be lost. It's important to note that this applies only +to the locally registered service. If you have multiple nodes all registering +the same service their `enableTagOverride` configuration and all other service +configuration items are independant of one another. Updating the tags for +the service registered on one node is independant of the same service (by name) +registered on another node. If `enableTagOverride` is not specified the default +value is false. + To configure a service, either provide it as a `-config-file` option to the agent or place it inside the `-config-dir` of the agent. The file must end in the ".json" extension to be loaded by Consul. Check definitions can From 598526eba280b1f06260c0e63090273d3f6179e9 Mon Sep 17 00:00:00 2001 From: Shawn Cook Date: Fri, 11 Sep 2015 14:27:54 -0700 Subject: [PATCH 10/11] Docs - add verbage to anti-entropy page. --- website/source/docs/agent/services.html.markdown | 3 ++- .../docs/internals/anti-entropy.html.markdown | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/website/source/docs/agent/services.html.markdown b/website/source/docs/agent/services.html.markdown index b9e13645bd21..c64cb68ee681 100644 --- a/website/source/docs/agent/services.html.markdown +++ b/website/source/docs/agent/services.html.markdown @@ -90,7 +90,8 @@ the same service their `enableTagOverride` configuration and all other service configuration items are independant of one another. Updating the tags for the service registered on one node is independant of the same service (by name) registered on another node. If `enableTagOverride` is not specified the default -value is false. +value is false. See [anti-entropy syncs](/docs/internals/anti-entropy.html) +for more info. To configure a service, either provide it as a `-config-file` option to the agent or place it inside the `-config-dir` of the agent. The file must diff --git a/website/source/docs/internals/anti-entropy.html.markdown b/website/source/docs/internals/anti-entropy.html.markdown index 50d42819c679..69a78bbe9440 100644 --- a/website/source/docs/internals/anti-entropy.html.markdown +++ b/website/source/docs/internals/anti-entropy.html.markdown @@ -135,3 +135,17 @@ fashion. If an error is encountered during an anti-entropy run, the error is logged and the agent continues to run. The anti-entropy mechanism is run periodically to automatically recover from these types of transient failures. + +### EnableTagOverride + +Synchronization of service registration can be partially modified to allow +external agents change the tag value of a service. This can be useful in +situations where an external monitoring service needs to be the source of +truth for tag information. For instance: Redis DB and its monitoring service +Redis Sentinel have this kind of relationship. Redis instances are responsible +for much of their configuration, but Sentinels determine whether the Redis +instance is a master or a slave. Using the Consul service configuration item +[EnableTagOverride](/docs/agent/services.html) you can instruct the Consul +agent on which the Redis DB is running to NOT update the tags during anti-entropy +synchronization. For more information see [Services](/docs/agent/services.html) +page. From 1f330add02be26eb4c0eeb743ea3a2f4cfbf2cd0 Mon Sep 17 00:00:00 2001 From: Shawn Cook Date: Fri, 11 Sep 2015 15:26:30 -0700 Subject: [PATCH 11/11] Doc changes in response to review. --- website/source/docs/agent/services.html.markdown | 8 ++++---- website/source/docs/internals/anti-entropy.html.markdown | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/website/source/docs/agent/services.html.markdown b/website/source/docs/agent/services.html.markdown index c64cb68ee681..1575c7d293f9 100644 --- a/website/source/docs/agent/services.html.markdown +++ b/website/source/docs/agent/services.html.markdown @@ -74,10 +74,10 @@ from `1`. Note: there is more information about [checks here](/docs/agent/checks.html). -The `enableTagOverride` can optionally specified to disable the antientropy feature for -this service. If `enableTagOverride` is set to TRUE then external agents can -reregister this service and modify the tags. Subsequent local sync operations -by this agent will ignore the updated tags. For instance: If an external agent +The `enableTagOverride` can optionally be specified to disable the anti-entropy +feature for this service. If enableTagOverride is set to TRUE then external +agents can update this service in the [catalog](/docs/agent/http/catalog.html) and modify the tags. Subsequent +local sync operations by this agent will ignore the updated tags. For instance: If an external agent modified both the tags and the port for this service and `enableTagOverride` was set to TRUE then after the next sync cycle the service's port would revert to the original value but the tags would maintain the updated value. As a diff --git a/website/source/docs/internals/anti-entropy.html.markdown b/website/source/docs/internals/anti-entropy.html.markdown index 69a78bbe9440..664303835332 100644 --- a/website/source/docs/internals/anti-entropy.html.markdown +++ b/website/source/docs/internals/anti-entropy.html.markdown @@ -138,8 +138,8 @@ automatically recover from these types of transient failures. ### EnableTagOverride -Synchronization of service registration can be partially modified to allow -external agents change the tag value of a service. This can be useful in +Synchronization of service registration can be partially modified to allow +external agents to change the tags for a service. This can be useful in situations where an external monitoring service needs to be the source of truth for tag information. For instance: Redis DB and its monitoring service Redis Sentinel have this kind of relationship. Redis instances are responsible