From 051ac8eb0bb55b72493dbdb55bede9356d7ce0d5 Mon Sep 17 00:00:00 2001 From: Daniel Malon Date: Fri, 2 Jan 2015 21:10:05 +0000 Subject: [PATCH 1/2] advertise specific address for a service Enable setting a specific address in a service definition for advertise. If no specific address is given it will fallback to the node address and reassemble the old behaviour. --- command/agent/dns.go | 18 +++++--- command/agent/structs.go | 12 ++--- consul/catalog_endpoint_test.go | 12 ++--- consul/fsm_test.go | 8 ++-- consul/state_store.go | 30 ++++++++----- consul/state_store_test.go | 78 +++++++++++++++++---------------- consul/structs/structs.go | 14 +++--- consul/structs/structs_test.go | 1 + 8 files changed, 96 insertions(+), 77 deletions(-) diff --git a/command/agent/dns.go b/command/agent/dns.go index 41f8df57ba6e..c5118d88e337 100644 --- a/command/agent/dns.go +++ b/command/agent/dns.go @@ -409,17 +409,17 @@ RPC: } // Add the node record - records := d.formatNodeRecord(&out.NodeServices.Node, req.Question[0].Name, - qType, d.config.NodeTTL) + records := d.formatNodeRecord(&out.NodeServices.Node, out.NodeServices.Node.Address, + req.Question[0].Name, qType, d.config.NodeTTL) if records != nil { resp.Answer = append(resp.Answer, records...) } } // formatNodeRecord takes a Node and returns an A, AAAA, or CNAME record -func (d *DNSServer) formatNodeRecord(node *structs.Node, qName string, qType uint16, ttl time.Duration) (records []dns.RR) { +func (d *DNSServer) formatNodeRecord(node *structs.Node, addr, qName string, qType uint16, ttl time.Duration) (records []dns.RR) { // Parse the IP - ip := net.ParseIP(node.Address) + ip := net.ParseIP(addr) var ipv4 net.IP if ip != nil { ipv4 = ip.To4() @@ -457,7 +457,7 @@ func (d *DNSServer) formatNodeRecord(node *structs.Node, qName string, qType uin Class: dns.ClassINET, Ttl: uint32(ttl / time.Second), }, - Target: dns.Fqdn(node.Address), + Target: dns.Fqdn(addr), } records = append(records, cnRec) @@ -584,13 +584,17 @@ func (d *DNSServer) serviceNodeRecords(nodes structs.CheckServiceNodes, req, res // Avoid duplicate entries, possible if a node has // the same service on multiple ports, etc. addr := node.Node.Address + if node.Service.Address != "" { + addr = node.Service.Address + } + if _, ok := handled[addr]; ok { continue } handled[addr] = struct{}{} // Add the node record - records := d.formatNodeRecord(&node.Node, qName, qType, ttl) + records := d.formatNodeRecord(&node.Node, addr, qName, qType, ttl) if records != nil { resp.Answer = append(resp.Answer, records...) } @@ -625,7 +629,7 @@ func (d *DNSServer) serviceSRVRecords(dc string, nodes structs.CheckServiceNodes resp.Answer = append(resp.Answer, srvRec) // Add the extra record - records := d.formatNodeRecord(&node.Node, srvRec.Target, dns.TypeANY, ttl) + records := d.formatNodeRecord(&node.Node, node.Node.Address, srvRec.Target, dns.TypeANY, ttl) if records != nil { resp.Extra = append(resp.Extra, records...) } diff --git a/command/agent/structs.go b/command/agent/structs.go index e2028237106d..86629e543f7d 100644 --- a/command/agent/structs.go +++ b/command/agent/structs.go @@ -6,11 +6,12 @@ import ( // ServiceDefinition is used to JSON decode the Service definitions type ServiceDefinition struct { - ID string - Name string - Tags []string - Port int - Check CheckType + ID string + Name string + Tags []string + Address string + Port int + Check CheckType } func (s *ServiceDefinition) NodeService() *structs.NodeService { @@ -18,6 +19,7 @@ func (s *ServiceDefinition) NodeService() *structs.NodeService { ID: s.ID, Service: s.Name, Tags: s.Tags, + Address: s.Address, Port: s.Port, } if ns.ID == "" && ns.Service != "" { diff --git a/consul/catalog_endpoint_test.go b/consul/catalog_endpoint_test.go index e2674f12b9e6..b84c9438ac1f 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"}, 5000}) + s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000}) 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"}, 5000}) + s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000}) }() // 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"}, 5000}) + s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000}) // 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"}, 5000}) + s1.fsm.State().EnsureService(2, "foo", &structs.NodeService{"db", "db", []string{"primary"}, "127.0.0.1", 5000}) 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"}, 5000}) - s1.fsm.State().EnsureService(3, "foo", &structs.NodeService{"web", "web", nil, 80}) + 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}) 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 db01580e4226..e37ed78892f8 100644 --- a/consul/fsm_test.go +++ b/consul/fsm_test.go @@ -337,10 +337,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, 80}) - fsm.state.EnsureService(4, "foo", &structs.NodeService{"db", "db", []string{"primary"}, 5000}) - fsm.state.EnsureService(5, "baz", &structs.NodeService{"web", "web", nil, 80}) - fsm.state.EnsureService(6, "baz", &structs.NodeService{"db", "db", []string{"secondary"}, 5000}) + 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.EnsureCheck(7, &structs.HealthCheck{ Node: "foo", CheckID: "web", diff --git a/consul/state_store.go b/consul/state_store.go index 273311435fc9..966a6c390b9b 100644 --- a/consul/state_store.go +++ b/consul/state_store.go @@ -500,11 +500,12 @@ func (s *StateStore) ensureServiceTxn(index uint64, node string, ns *structs.Nod // Create the entry entry := structs.ServiceNode{ - Node: node, - ServiceID: ns.ID, - ServiceName: ns.Service, - ServiceTags: ns.Tags, - ServicePort: ns.Port, + Node: node, + ServiceID: ns.ID, + ServiceName: ns.Service, + ServiceTags: ns.Tags, + ServiceAddress: ns.Address, + ServicePort: ns.Port, } // Ensure the service entry is set @@ -568,6 +569,7 @@ func (s *StateStore) parseNodeServices(tables MDBTables, tx *MDBTxn, name string ID: service.ServiceID, Service: service.ServiceName, Tags: service.ServiceTags, + Address: service.ServiceAddress, Port: service.ServicePort, } ns.Services[srv.ID] = srv @@ -743,13 +745,17 @@ func (s *StateStore) parseServiceNodes(tx *MDBTxn, table *MDBTable, res []interf for i, r := range res { srv := r.(*structs.ServiceNode) - // Get the address of the node - nodeRes, err := table.GetTxn(tx, "id", srv.Node) - if err != nil || len(nodeRes) != 1 { - s.logger.Printf("[ERR] consul.state: Failed to join service node %#v with node: %v", *srv, err) - continue + if srv.ServiceAddress != "" { + srv.Address = srv.ServiceAddress + } else { + // Get the address of the node + nodeRes, err := table.GetTxn(tx, "id", srv.Node) + if err != nil || len(nodeRes) != 1 { + s.logger.Printf("[ERR] consul.state: Failed to join service node %#v with node: %v", *srv, err) + continue + } + srv.Address = nodeRes[0].(*structs.Node).Address } - srv.Address = nodeRes[0].(*structs.Node).Address nodes[i] = *srv } @@ -952,6 +958,7 @@ func (s *StateStore) parseCheckServiceNodes(tx *MDBTxn, res []interface{}, err e ID: srv.ServiceID, Service: srv.ServiceName, Tags: srv.ServiceTags, + Address: srv.ServiceAddress, Port: srv.ServicePort, } nodes[i].Checks = checks @@ -1026,6 +1033,7 @@ func (s *StateStore) parseNodeInfo(tx *MDBTxn, res []interface{}, err error) str ID: service.ServiceID, Service: service.ServiceName, Tags: service.ServiceTags, + Address: service.ServiceAddress, Port: service.ServicePort, } info.Services = append(info.Services, srv) diff --git a/consul/state_store_test.go b/consul/state_store_test.go index 888b4a343249..49d88ba06531 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}, Check: &structs.HealthCheck{ Node: "foo", CheckID: "api", @@ -149,15 +149,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}); 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}); 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}); err != nil { t.Fatalf("err: %v", err) } @@ -194,15 +194,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}); 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}); 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}); err != nil { t.Fatalf("err: %v", err) } @@ -247,7 +247,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}); err != nil { t.Fatalf("err: %v", err) } @@ -295,11 +295,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}); 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}); err != nil { t.Fatalf("err: %v", err) } @@ -332,7 +332,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}); err != nil { t.Fatalf("err: %v", err) } @@ -391,15 +391,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}); 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}); 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}); err != nil { t.Fatalf("err: %v", err) } @@ -441,23 +441,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}); 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}); 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}); 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}); 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}); err != nil { t.Fatalf("err: %v", err) } @@ -532,15 +532,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}); 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}); 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}); err != nil { t.Fatalf("err: %v", err) } @@ -580,15 +580,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}); 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}); 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}); err != nil { t.Fatalf("err: %v", err) } @@ -656,15 +656,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}); 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}); 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}); err != nil { t.Fatalf("err: %v", err) } @@ -818,10 +818,10 @@ func TestStoreSnapshot(t *testing.T) { } // Make some changes! - if err := store.EnsureService(22, "foo", &structs.NodeService{"db", "db", []string{"slave"}, 8000}); err != nil { + if err := store.EnsureService(22, "foo", &structs.NodeService{"db", "db", []string{"slave"}, "", 8000}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(23, "bar", &structs.NodeService{"db", "db", []string{"master"}, 8000}); err != nil { + if err := store.EnsureService(23, "bar", &structs.NodeService{"db", "db", []string{"master"}, "", 8000}); err != nil { t.Fatalf("err: %v", err) } if err := store.EnsureNode(24, structs.Node{"baz", "127.0.0.3"}); err != nil { @@ -926,7 +926,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}); err != nil { t.Fatalf("err: %v", err) } check := &structs.HealthCheck{ @@ -1022,7 +1022,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}); err != nil { t.Fatalf("err: %v", err) } check := &structs.HealthCheck{ @@ -1072,7 +1072,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}); err != nil { t.Fatalf("err: %v", err) } check := &structs.HealthCheck{ @@ -1153,7 +1153,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}); err != nil { t.Fatalf("err: %v", err) } check := &structs.HealthCheck{ @@ -1196,6 +1196,7 @@ func TestSS_Register_Deregister_Query(t *testing.T) { "statsite-box-stats", "statsite-box-stats", nil, + "", 0} if err := store.EnsureService(2, "foo", srv); err != nil { t.Fatalf("err: %v", err) @@ -1205,6 +1206,7 @@ func TestSS_Register_Deregister_Query(t *testing.T) { "statsite-share-stats", "statsite-share-stats", nil, + "", 0} if err := store.EnsureService(3, "foo", srv); err != nil { t.Fatalf("err: %v", err) @@ -1233,7 +1235,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}); err != nil { t.Fatalf("err: %v", err) } check := &structs.HealthCheck{ @@ -1292,13 +1294,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}); 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}); err != nil { t.Fatalf("err: %v", err) } @@ -2066,7 +2068,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}); err != nil { t.Fatalf("err: %v", err) } check := &structs.HealthCheck{ diff --git a/consul/structs/structs.go b/consul/structs/structs.go index 2072780f3696..5bef05584403 100644 --- a/consul/structs/structs.go +++ b/consul/structs/structs.go @@ -216,12 +216,13 @@ type Services map[string][]string // ServiceNode represents a node that is part of a service type ServiceNode struct { - Node string - Address string - ServiceID string - ServiceName string - ServiceTags []string - ServicePort int + Node string + Address string + ServiceID string + ServiceName string + ServiceTags []string + ServiceAddress string + ServicePort int } type ServiceNodes []ServiceNode @@ -230,6 +231,7 @@ type NodeService struct { ID string Service string Tags []string + Address string Port int } type NodeServices struct { diff --git a/consul/structs/structs_test.go b/consul/structs/structs_test.go index cb7808731a29..4a2215cf8b4c 100644 --- a/consul/structs/structs_test.go +++ b/consul/structs/structs_test.go @@ -12,6 +12,7 @@ func TestEncodeDecode(t *testing.T) { Address: "baz", Service: &NodeService{ Service: "test", + Address: "127.0.0.2", }, } buf, err := Encode(RegisterRequestType, arg) From bd65cbb7d79e45b5b077457643dc4be1f6e0177a Mon Sep 17 00:00:00 2001 From: Daniel Malon Date: Mon, 5 Jan 2015 22:48:30 +0000 Subject: [PATCH 2/2] use the service specific address in SRV response --- command/agent/dns.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/command/agent/dns.go b/command/agent/dns.go index c5118d88e337..81e91b8e90c0 100644 --- a/command/agent/dns.go +++ b/command/agent/dns.go @@ -628,8 +628,14 @@ func (d *DNSServer) serviceSRVRecords(dc string, nodes structs.CheckServiceNodes } resp.Answer = append(resp.Answer, srvRec) + // Determine advertised address + addr := node.Node.Address + if node.Service.Address != "" { + addr = node.Service.Address + } + // Add the extra record - records := d.formatNodeRecord(&node.Node, node.Node.Address, srvRec.Target, dns.TypeANY, ttl) + records := d.formatNodeRecord(&node.Node, addr, srvRec.Target, dns.TypeANY, ttl) if records != nil { resp.Extra = append(resp.Extra, records...) }