command: when generating envoy bootstrap configs use the datacenter returned from the agent services endpoint (#9229)

Fixes #9215
This commit is contained in:
R.B. Boyer 2020-11-19 15:27:31 -06:00 committed by GitHub
parent 22a0ab69ae
commit 7bcbc59dea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 44 additions and 22 deletions

3
.changelog/9229.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
command: when generating envoy bootstrap configs use the datacenter returned from the agent services endpoint
```

View File

@ -170,7 +170,7 @@ func (s *HTTPHandlers) AgentReload(resp http.ResponseWriter, req *http.Request)
return nil, s.agent.ReloadConfig() return nil, s.agent.ReloadConfig()
} }
func buildAgentService(s *structs.NodeService) api.AgentService { func buildAgentService(s *structs.NodeService, dc string) api.AgentService {
weights := api.AgentWeights{Passing: 1, Warning: 1} weights := api.AgentWeights{Passing: 1, Warning: 1}
if s.Weights != nil { if s.Weights != nil {
if s.Weights.Passing > 0 { if s.Weights.Passing > 0 {
@ -200,6 +200,7 @@ func buildAgentService(s *structs.NodeService) api.AgentService {
CreateIndex: s.CreateIndex, CreateIndex: s.CreateIndex,
ModifyIndex: s.ModifyIndex, ModifyIndex: s.ModifyIndex,
Weights: weights, Weights: weights,
Datacenter: dc,
} }
if as.Tags == nil { if as.Tags == nil {
@ -253,9 +254,11 @@ func (s *HTTPHandlers) AgentServices(resp http.ResponseWriter, req *http.Request
// anyway. // anyway.
agentSvcs := make(map[string]*api.AgentService) agentSvcs := make(map[string]*api.AgentService)
dc := s.agent.config.Datacenter
// Use empty list instead of nil // Use empty list instead of nil
for id, s := range services { for id, s := range services {
agentService := buildAgentService(s) agentService := buildAgentService(s, dc)
agentSvcs[id.ID] = &agentService agentSvcs[id.ID] = &agentService
} }
@ -303,6 +306,8 @@ func (s *HTTPHandlers) AgentService(resp http.ResponseWriter, req *http.Request)
sid := structs.NewServiceID(id, &entMeta) sid := structs.NewServiceID(id, &entMeta)
dc := s.agent.config.Datacenter
resultHash, service, err := s.agent.LocalBlockingQuery(false, hash, queryOpts.MaxQueryTime, resultHash, service, err := s.agent.LocalBlockingQuery(false, hash, queryOpts.MaxQueryTime,
func(ws memdb.WatchSet) (string, interface{}, error) { func(ws memdb.WatchSet) (string, interface{}, error) {
@ -330,7 +335,7 @@ func (s *HTTPHandlers) AgentService(resp http.ResponseWriter, req *http.Request)
} }
// Calculate the content hash over the response, minus the hash field // Calculate the content hash over the response, minus the hash field
aSvc := buildAgentService(svc) aSvc := buildAgentService(svc, dc)
reply := &aSvc reply := &aSvc
rawHash, err := hashstructure.Hash(reply, nil) rawHash, err := hashstructure.Hash(reply, nil)
@ -768,6 +773,8 @@ func (s *HTTPHandlers) AgentHealthServiceByID(resp http.ResponseWriter, req *htt
sid := structs.NewServiceID(serviceID, &entMeta) sid := structs.NewServiceID(serviceID, &entMeta)
dc := s.agent.config.Datacenter
if service := s.agent.State.Service(sid); service != nil { if service := s.agent.State.Service(sid); service != nil {
if authz != nil && authz.ServiceRead(service.Service, &authzContext) != acl.Allow { if authz != nil && authz.ServiceRead(service.Service, &authzContext) != acl.Allow {
return nil, acl.ErrPermissionDenied return nil, acl.ErrPermissionDenied
@ -776,7 +783,7 @@ func (s *HTTPHandlers) AgentHealthServiceByID(resp http.ResponseWriter, req *htt
if returnTextPlain(req) { if returnTextPlain(req) {
return status, CodeWithPayloadError{StatusCode: code, Reason: status, ContentType: "text/plain"} return status, CodeWithPayloadError{StatusCode: code, Reason: status, ContentType: "text/plain"}
} }
serviceInfo := buildAgentService(service) serviceInfo := buildAgentService(service, dc)
result := &api.AgentServiceChecksInfo{ result := &api.AgentServiceChecksInfo{
AggregatedStatus: status, AggregatedStatus: status,
Checks: healthChecks, Checks: healthChecks,
@ -822,6 +829,8 @@ func (s *HTTPHandlers) AgentHealthServiceByName(resp http.ResponseWriter, req *h
return nil, acl.ErrPermissionDenied return nil, acl.ErrPermissionDenied
} }
dc := s.agent.config.Datacenter
code := http.StatusNotFound code := http.StatusNotFound
status := fmt.Sprintf("ServiceName %s Not Found", serviceName) status := fmt.Sprintf("ServiceName %s Not Found", serviceName)
services := s.agent.State.Services(&entMeta) services := s.agent.State.Services(&entMeta)
@ -831,7 +840,7 @@ func (s *HTTPHandlers) AgentHealthServiceByName(resp http.ResponseWriter, req *h
sid := structs.NewServiceID(service.ID, &entMeta) sid := structs.NewServiceID(service.ID, &entMeta)
scode, sstatus, healthChecks := agentHealthService(sid, s) scode, sstatus, healthChecks := agentHealthService(sid, s)
serviceInfo := buildAgentService(service) serviceInfo := buildAgentService(service, dc)
res := api.AgentServiceChecksInfo{ res := api.AgentServiceChecksInfo{
AggregatedStatus: sstatus, AggregatedStatus: sstatus,
Checks: healthChecks, Checks: healthChecks,

View File

@ -367,6 +367,7 @@ func TestAgent_Service(t *testing.T) {
}, },
Meta: map[string]string{}, Meta: map[string]string{},
Tags: []string{}, Tags: []string{},
Datacenter: "dc1",
} }
fillAgentServiceEnterpriseMeta(expectedResponse, structs.DefaultEnterpriseMeta()) fillAgentServiceEnterpriseMeta(expectedResponse, structs.DefaultEnterpriseMeta())
@ -393,6 +394,7 @@ func TestAgent_Service(t *testing.T) {
}, },
Meta: map[string]string{}, Meta: map[string]string{},
Tags: []string{}, Tags: []string{},
Datacenter: "dc1",
} }
fillAgentServiceEnterpriseMeta(expectWebResponse, structs.DefaultEnterpriseMeta()) fillAgentServiceEnterpriseMeta(expectWebResponse, structs.DefaultEnterpriseMeta())

View File

@ -93,6 +93,8 @@ type AgentService struct {
// to include the Namespace in the hash. When we do, then we are in for lots of fun with tests. // to include the Namespace in the hash. When we do, then we are in for lots of fun with tests.
// For now though, ignoring it works well enough. // For now though, ignoring it works well enough.
Namespace string `json:",omitempty" bexpr:"-" hash:"ignore"` Namespace string `json:",omitempty" bexpr:"-" hash:"ignore"`
// Datacenter is only ever returned and is ignored if presented.
Datacenter string `json:",omitempty" bexpr:"-" hash:"ignore"`
} }
// AgentServiceChecksInfo returns information about a Service and its checks // AgentServiceChecksInfo returns information about a Service and its checks

View File

@ -728,6 +728,7 @@ func TestAPI_AgentService(t *testing.T) {
}, },
Meta: map[string]string{}, Meta: map[string]string{},
Namespace: defaultNamespace, Namespace: defaultNamespace,
Datacenter: "dc1",
} }
require.Equal(expect, got) require.Equal(expect, got)
require.Equal(expect.ContentHash, qm.LastContentHash) require.Equal(expect.ContentHash, qm.LastContentHash)

View File

@ -478,6 +478,7 @@ func (c *cmd) templateArgs() (*BootstrapTplArgs, error) {
LocalAgentClusterName: xds.LocalAgentClusterName, LocalAgentClusterName: xds.LocalAgentClusterName,
Namespace: httpCfg.Namespace, Namespace: httpCfg.Namespace,
EnvoyVersion: c.envoyVersion, EnvoyVersion: c.envoyVersion,
Datacenter: httpCfg.Datacenter,
}, nil }, nil
} }
@ -529,15 +530,11 @@ func (c *cmd) generateConfig() ([]byte, error) {
// cluster is using namespaces regardless. // cluster is using namespaces regardless.
args.Namespace = svc.Namespace args.Namespace = svc.Namespace
} }
agent, err := c.client.Agent().Self()
if err != nil { if svc.Datacenter != "" {
return nil, fmt.Errorf("failed to fetch agent config: %v", err) // The agent will definitely have the definitive answer here.
args.Datacenter = svc.Datacenter
} }
dc, ok := agent["Config"]["Datacenter"].(string)
if !ok {
return nil, fmt.Errorf("failed to fetch datacenter from agent. DC is: %T", agent["Config"]["Datacenter"])
}
args.Datacenter = dc
if !c.disableCentralConfig { if !c.disableCentralConfig {
// Parse the bootstrap config // Parse the bootstrap config

View File

@ -994,6 +994,7 @@ func testMockAgentGatewayConfig(namespacesEnabled bool) http.HandlerFunc {
Kind: kind, Kind: kind,
ID: string(kind), ID: string(kind),
Service: string(kind), Service: string(kind),
Datacenter: "dc1",
}, },
} }
@ -1036,6 +1037,7 @@ func testMockAgentProxyConfig(cfg map[string]interface{}, namespacesEnabled bool
DestinationServiceID: serviceID, DestinationServiceID: serviceID,
Config: cfg, Config: cfg,
}, },
Datacenter: "dc1",
} }
if namespacesEnabled { if namespacesEnabled {

View File

@ -74,6 +74,7 @@ $ curl \
"Port": 8000, "Port": 8000,
"Address": "", "Address": "",
"EnableTagOverride": false, "EnableTagOverride": false,
"Datacenter": "dc1",
"Weights": { "Weights": {
"Passing": 10, "Passing": 10,
"Warning": 1 "Warning": 1
@ -185,6 +186,7 @@ $ curl \
"Warning": 1 "Warning": 1
}, },
"EnableTagOverride": false, "EnableTagOverride": false,
"Datacenter": "dc1",
"ContentHash": "4ecd29c7bc647ca8", "ContentHash": "4ecd29c7bc647ca8",
"Proxy": { "Proxy": {
"DestinationServiceName": "web", "DestinationServiceName": "web",
@ -304,6 +306,7 @@ curl localhost:8500/v1/agent/health/service/name/web
"Meta": null, "Meta": null,
"Port": 80, "Port": 80,
"EnableTagOverride": false, "EnableTagOverride": false,
"Datacenter": "dc1",
"Connect": { "Connect": {
"Native": false, "Native": false,
"Proxy": null "Proxy": null
@ -331,6 +334,7 @@ curl localhost:8500/v1/agent/health/service/name/web
"Meta": null, "Meta": null,
"Port": 80, "Port": 80,
"EnableTagOverride": false, "EnableTagOverride": false,
"Datacenter": "dc1",
"Connect": { "Connect": {
"Native": false, "Native": false,
"Proxy": null "Proxy": null
@ -380,6 +384,7 @@ curl localhost:8500/v1/agent/health/service/id/web2
"Meta": null, "Meta": null,
"Port": 80, "Port": 80,
"EnableTagOverride": false, "EnableTagOverride": false,
"Datacenter": "dc1",
"Connect": { "Connect": {
"Native": false, "Native": false,
"Proxy": null "Proxy": null
@ -425,6 +430,7 @@ curl localhost:8500/v1/agent/health/service/id/web1
"Meta": null, "Meta": null,
"Port": 80, "Port": 80,
"EnableTagOverride": false, "EnableTagOverride": false,
"Datacenter": "dc1",
"Connect": { "Connect": {
"Native": false, "Native": false,
"Proxy": null "Proxy": null