Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tagged addresses for services #5965

Merged
merged 7 commits into from
Jun 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions agent/agent_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,15 @@ func buildAgentService(s *structs.NodeService, proxies map[string]*local.Managed
}
weights.Warning = s.Weights.Warning
}

var taggedAddrs map[string]api.ServiceAddress
if len(s.TaggedAddresses) > 0 {
taggedAddrs = make(map[string]api.ServiceAddress)
for k, v := range s.TaggedAddresses {
taggedAddrs[k] = v.ToAPIServiceAddress()
}
}

as := api.AgentService{
Kind: api.ServiceKind(s.Kind),
ID: s.ID,
Expand All @@ -174,6 +183,7 @@ func buildAgentService(s *structs.NodeService, proxies map[string]*local.Managed
Meta: s.Meta,
Port: s.Port,
Address: s.Address,
TaggedAddresses: taggedAddrs,
EnableTagOverride: s.EnableTagOverride,
CreateIndex: s.CreateIndex,
ModifyIndex: s.ModifyIndex,
Expand Down Expand Up @@ -887,6 +897,9 @@ func (s *HTTPServer) AgentRegisterService(resp http.ResponseWriter, req *http.Re
// DON'T Recurse into these opaque config maps or we might mangle user's
// keys. Note empty canonical is a special sentinel to prevent recursion.
"Meta": "",

"tagged_addresses": "TaggedAddresses",

// upstreams is an array but this prevents recursion into config field of
// any item in the array.
"Proxy.Config": "",
Expand Down
20 changes: 20 additions & 0 deletions agent/agent_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2503,6 +2503,16 @@ func TestAgent_RegisterService_TranslateKeys(t *testing.T) {
"name":"test",
"port":8000,
"enable_tag_override": true,
"tagged_addresses": {
"lan": {
"address": "1.2.3.4",
"port": 5353
},
"wan": {
"address": "2.3.4.5",
"port": 53
}
},
"meta": {
"some": "meta",
"enable_tag_override": "meta is 'opaque' so should not get translated"
Expand Down Expand Up @@ -2595,6 +2605,16 @@ func TestAgent_RegisterService_TranslateKeys(t *testing.T) {
svc := &structs.NodeService{
ID: "test",
Service: "test",
TaggedAddresses: map[string]structs.ServiceAddress{
"lan": {
Address: "1.2.3.4",
Port: 5353,
},
"wan": {
Address: "2.3.4.5",
Port: 53,
},
},
Meta: map[string]string{
"some": "meta",
"enable_tag_override": "meta is 'opaque' so should not get translated",
Expand Down
4 changes: 2 additions & 2 deletions agent/catalog_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ RETRY_ONCE:
goto RETRY_ONCE
}
out.ConsistencyLevel = args.QueryOptions.ConsistencyLevel()
if out.NodeServices != nil && out.NodeServices.Node != nil {
s.agent.TranslateAddresses(args.Datacenter, out.NodeServices.Node)
if out.NodeServices != nil {
s.agent.TranslateAddresses(args.Datacenter, out.NodeServices)
}

// TODO: The NodeServices object in IndexedNodeServices is a pointer to
Expand Down
126 changes: 62 additions & 64 deletions agent/catalog_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -769,13 +769,10 @@ func TestCatalogServiceNodes_WanTranslation(t *testing.T) {

// Wait for the WAN join.
addr := fmt.Sprintf("127.0.0.1:%d", a1.Config.SerfPortWAN)
if _, err := a2.srv.agent.JoinWAN([]string{addr}); err != nil {
t.Fatalf("err: %v", err)
}
_, err := a2.srv.agent.JoinWAN([]string{addr})
require.NoError(t, err)
retry.Run(t, func(r *retry.R) {
if got, want := len(a1.WANMembers()), 2; got < want {
r.Fatalf("got %d WAN members want at least %d", got, want)
}
require.Len(r, a1.WANMembers(), 2)
})

// Register a node with DC2.
Expand All @@ -789,51 +786,51 @@ func TestCatalogServiceNodes_WanTranslation(t *testing.T) {
},
Service: &structs.NodeService{
Service: "http_wan_translation_test",
Address: "127.0.0.1",
Port: 8080,
TaggedAddresses: map[string]structs.ServiceAddress{
"wan": structs.ServiceAddress{
Address: "1.2.3.4",
Port: 80,
},
},
},
}

var out struct{}
if err := a2.RPC("Catalog.Register", args, &out); err != nil {
t.Fatalf("err: %v", err)
}
require.NoError(t, a2.RPC("Catalog.Register", args, &out))
}

// Query for the node in DC2 from DC1.
req, _ := http.NewRequest("GET", "/v1/catalog/service/http_wan_translation_test?dc=dc2", nil)
resp1 := httptest.NewRecorder()
obj1, err1 := a1.srv.CatalogServiceNodes(resp1, req)
if err1 != nil {
t.Fatalf("err: %v", err1)
}
assertIndex(t, resp1)
require.NoError(t, err1)
require.NoError(t, checkIndex(resp1))

// Expect that DC1 gives us a WAN address (since the node is in DC2).
nodes1 := obj1.(structs.ServiceNodes)
if len(nodes1) != 1 {
t.Fatalf("bad: %v", obj1)
}
nodes1, ok := obj1.(structs.ServiceNodes)
require.True(t, ok, "obj1 is not a structs.ServiceNodes")
require.Len(t, nodes1, 1)
node1 := nodes1[0]
if node1.Address != "127.0.0.2" {
t.Fatalf("bad: %v", node1)
}
require.Equal(t, node1.Address, "127.0.0.2")
require.Equal(t, node1.ServiceAddress, "1.2.3.4")
require.Equal(t, node1.ServicePort, 80)

// Query DC2 from DC2.
resp2 := httptest.NewRecorder()
obj2, err2 := a2.srv.CatalogServiceNodes(resp2, req)
if err2 != nil {
t.Fatalf("err: %v", err2)
}
assertIndex(t, resp2)
require.NoError(t, err2)
require.NoError(t, checkIndex(resp2))

// Expect that DC2 gives us a local address (since the node is in DC2).
nodes2 := obj2.(structs.ServiceNodes)
if len(nodes2) != 1 {
t.Fatalf("bad: %v", obj2)
}
nodes2, ok := obj2.(structs.ServiceNodes)
require.True(t, ok, "obj2 is not a structs.ServiceNodes")
require.Len(t, nodes2, 1)
node2 := nodes2[0]
if node2.Address != "127.0.0.1" {
t.Fatalf("bad: %v", node2)
}
require.Equal(t, node2.Address, "127.0.0.1")
require.Equal(t, node2.ServiceAddress, "127.0.0.1")
require.Equal(t, node2.ServicePort, 8080)
}

func TestCatalogServiceNodes_DistanceSort(t *testing.T) {
Expand Down Expand Up @@ -1150,13 +1147,10 @@ func TestCatalogNodeServices_WanTranslation(t *testing.T) {

// Wait for the WAN join.
addr := fmt.Sprintf("127.0.0.1:%d", a1.Config.SerfPortWAN)
if _, err := a2.srv.agent.JoinWAN([]string{addr}); err != nil {
t.Fatalf("err: %v", err)
}
_, err := a2.srv.agent.JoinWAN([]string{addr})
require.NoError(t, err)
retry.Run(t, func(r *retry.R) {
if got, want := len(a1.WANMembers()), 2; got < want {
r.Fatalf("got %d WAN members want at least %d", got, want)
}
require.Len(r, a1.WANMembers(), 2)
})

// Register a node with DC2.
Expand All @@ -1170,49 +1164,53 @@ func TestCatalogNodeServices_WanTranslation(t *testing.T) {
},
Service: &structs.NodeService{
Service: "http_wan_translation_test",
Address: "127.0.0.1",
Port: 8080,
TaggedAddresses: map[string]structs.ServiceAddress{
"wan": structs.ServiceAddress{
Address: "1.2.3.4",
Port: 80,
},
},
},
}

var out struct{}
if err := a2.RPC("Catalog.Register", args, &out); err != nil {
t.Fatalf("err: %v", err)
}
require.NoError(t, a2.RPC("Catalog.Register", args, &out))
}

// Query for the node in DC2 from DC1.
req, _ := http.NewRequest("GET", "/v1/catalog/node/foo?dc=dc2", nil)
resp1 := httptest.NewRecorder()
obj1, err1 := a1.srv.CatalogNodeServices(resp1, req)
if err1 != nil {
t.Fatalf("err: %v", err1)
}
assertIndex(t, resp1)
require.NoError(t, err1)
require.NoError(t, checkIndex(resp1))

// Expect that DC1 gives us a WAN address (since the node is in DC2).
services1 := obj1.(*structs.NodeServices)
if len(services1.Services) != 1 {
t.Fatalf("bad: %v", obj1)
}
service1 := services1.Node
if service1.Address != "127.0.0.2" {
t.Fatalf("bad: %v", service1)
}
service1, ok := obj1.(*structs.NodeServices)
require.True(t, ok, "obj1 is not a *structs.NodeServices")
require.NotNil(t, service1.Node)
require.Equal(t, service1.Node.Address, "127.0.0.2")
require.Len(t, service1.Services, 1)
ns1, ok := service1.Services["http_wan_translation_test"]
require.True(t, ok, "Missing service http_wan_translation_test")
require.Equal(t, "1.2.3.4", ns1.Address)
require.Equal(t, 80, ns1.Port)

// Query DC2 from DC2.
resp2 := httptest.NewRecorder()
obj2, err2 := a2.srv.CatalogNodeServices(resp2, req)
if err2 != nil {
t.Fatalf("err: %v", err2)
}
assertIndex(t, resp2)
require.NoError(t, err2)
require.NoError(t, checkIndex(resp2))

// Expect that DC2 gives us a private address (since the node is in DC2).
services2 := obj2.(*structs.NodeServices)
if len(services2.Services) != 1 {
t.Fatalf("bad: %v", obj2)
}
service2 := services2.Node
if service2.Address != "127.0.0.1" {
t.Fatalf("bad: %v", service2)
}
service2 := obj2.(*structs.NodeServices)
require.True(t, ok, "obj2 is not a *structs.NodeServices")
require.NotNil(t, service2.Node)
require.Equal(t, service2.Node.Address, "127.0.0.1")
require.Len(t, service2.Services, 1)
ns2, ok := service2.Services["http_wan_translation_test"]
require.True(t, ok, "Missing service http_wan_translation_test")
require.Equal(t, ns2.Address, "127.0.0.1")
require.Equal(t, ns2.Port, 8080)
}
21 changes: 21 additions & 0 deletions agent/config/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,26 @@ func (b *Builder) checkVal(v *CheckDefinition) *structs.CheckDefinition {
}
}

func (b *Builder) svcTaggedAddresses(v map[string]ServiceAddress) map[string]structs.ServiceAddress {
if len(v) <= 0 {
return nil
}

svcAddrs := make(map[string]structs.ServiceAddress)
for addrName, addrConf := range v {
addr := structs.ServiceAddress{}
if addrConf.Address != nil {
addr.Address = *addrConf.Address
}
if addrConf.Port != nil {
addr.Port = *addrConf.Port
}

svcAddrs[addrName] = addr
}
return svcAddrs
}

func (b *Builder) serviceVal(v *ServiceDefinition) *structs.ServiceDefinition {
if v == nil {
return nil
Expand Down Expand Up @@ -1215,6 +1235,7 @@ func (b *Builder) serviceVal(v *ServiceDefinition) *structs.ServiceDefinition {
Name: b.stringVal(v.Name),
Tags: v.Tags,
Address: b.stringVal(v.Address),
TaggedAddresses: b.svcTaggedAddresses(v.TaggedAddresses),
Meta: meta,
Port: b.intVal(v.Port),
Token: b.stringVal(v.Token),
Expand Down
30 changes: 18 additions & 12 deletions agent/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,19 +360,25 @@ type ServiceWeights struct {
Warning *int `json:"warning,omitempty" hcl:"warning" mapstructure:"warning"`
}

type ServiceAddress struct {
Address *string `json:"address,omitempty" hcl:"address" mapstructure:"address"`
Port *int `json:"port,omitempty" hcl:"port" mapstructure:"port"`
}

type ServiceDefinition struct {
Kind *string `json:"kind,omitempty" hcl:"kind" mapstructure:"kind"`
ID *string `json:"id,omitempty" hcl:"id" mapstructure:"id"`
Name *string `json:"name,omitempty" hcl:"name" mapstructure:"name"`
Tags []string `json:"tags,omitempty" hcl:"tags" mapstructure:"tags"`
Address *string `json:"address,omitempty" hcl:"address" mapstructure:"address"`
Meta map[string]string `json:"meta,omitempty" hcl:"meta" mapstructure:"meta"`
Port *int `json:"port,omitempty" hcl:"port" mapstructure:"port"`
Check *CheckDefinition `json:"check,omitempty" hcl:"check" mapstructure:"check"`
Checks []CheckDefinition `json:"checks,omitempty" hcl:"checks" mapstructure:"checks"`
Token *string `json:"token,omitempty" hcl:"token" mapstructure:"token"`
Weights *ServiceWeights `json:"weights,omitempty" hcl:"weights" mapstructure:"weights"`
EnableTagOverride *bool `json:"enable_tag_override,omitempty" hcl:"enable_tag_override" mapstructure:"enable_tag_override"`
Kind *string `json:"kind,omitempty" hcl:"kind" mapstructure:"kind"`
ID *string `json:"id,omitempty" hcl:"id" mapstructure:"id"`
Name *string `json:"name,omitempty" hcl:"name" mapstructure:"name"`
Tags []string `json:"tags,omitempty" hcl:"tags" mapstructure:"tags"`
Address *string `json:"address,omitempty" hcl:"address" mapstructure:"address"`
TaggedAddresses map[string]ServiceAddress `json:"tagged_addresses,omitempty" hcl:"tagged_addresses" mapstructure:"tagged_addresses"`
Meta map[string]string `json:"meta,omitempty" hcl:"meta" mapstructure:"meta"`
Port *int `json:"port,omitempty" hcl:"port" mapstructure:"port"`
Check *CheckDefinition `json:"check,omitempty" hcl:"check" mapstructure:"check"`
Checks []CheckDefinition `json:"checks,omitempty" hcl:"checks" mapstructure:"checks"`
Token *string `json:"token,omitempty" hcl:"token" mapstructure:"token"`
Weights *ServiceWeights `json:"weights,omitempty" hcl:"weights" mapstructure:"weights"`
EnableTagOverride *bool `json:"enable_tag_override,omitempty" hcl:"enable_tag_override" mapstructure:"enable_tag_override"`
// DEPRECATED (ProxyDestination) - remove this when removing ProxyDestination
ProxyDestination *string `json:"proxy_destination,omitempty" hcl:"proxy_destination" mapstructure:"proxy_destination"`
Proxy *ServiceProxy `json:"proxy,omitempty" hcl:"proxy" mapstructure:"proxy"`
Expand Down
Loading