From fd33b76ec2ec37892ab0307c7b026cc9b3e70c07 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 9 Mar 2018 08:43:17 -0800 Subject: [PATCH] agent: /v1/catalog/connect/:service --- agent/catalog_endpoint.go | 49 ++++++++++++++++++++++++++++++++++ agent/catalog_endpoint_test.go | 24 +++++++++++++++++ agent/http_oss.go | 1 + 3 files changed, 74 insertions(+) diff --git a/agent/catalog_endpoint.go b/agent/catalog_endpoint.go index 0088741e16..86e4e95ee8 100644 --- a/agent/catalog_endpoint.go +++ b/agent/catalog_endpoint.go @@ -217,6 +217,55 @@ RETRY_ONCE: return out.ServiceNodes, nil } +func (s *HTTPServer) CatalogConnectServiceNodes(resp http.ResponseWriter, req *http.Request) (interface{}, error) { + metrics.IncrCounterWithLabels([]string{"client", "api", "catalog_connect_service_nodes"}, 1, + []metrics.Label{{Name: "node", Value: s.nodeName()}}) + if req.Method != "GET" { + return nil, MethodNotAllowedError{req.Method, []string{"GET"}} + } + + // Set default DC + args := structs.ServiceSpecificRequest{Connect: true} + s.parseSource(req, &args.Source) + args.NodeMetaFilters = s.parseMetaFilter(req) + if done := s.parse(resp, req, &args.Datacenter, &args.QueryOptions); done { + return nil, nil + } + + // Pull out the service name + args.ServiceName = strings.TrimPrefix(req.URL.Path, "/v1/catalog/connect/") + if args.ServiceName == "" { + resp.WriteHeader(http.StatusBadRequest) + fmt.Fprint(resp, "Missing service name") + return nil, nil + } + + // Make the RPC request + var out structs.IndexedServiceNodes + defer setMeta(resp, &out.QueryMeta) + if err := s.agent.RPC("Catalog.ServiceNodes", &args, &out); err != nil { + metrics.IncrCounterWithLabels([]string{"client", "rpc", "error", "catalog_connect_service_nodes"}, 1, + []metrics.Label{{Name: "node", Value: s.nodeName()}}) + return nil, err + } + s.agent.TranslateAddresses(args.Datacenter, out.ServiceNodes) + + // Use empty list instead of nil + if out.ServiceNodes == nil { + out.ServiceNodes = make(structs.ServiceNodes, 0) + } + for i, s := range out.ServiceNodes { + if s.ServiceTags == nil { + clone := *s + clone.ServiceTags = make([]string, 0) + out.ServiceNodes[i] = &clone + } + } + metrics.IncrCounterWithLabels([]string{"client", "api", "success", "catalog_connect_service_nodes"}, 1, + []metrics.Label{{Name: "node", Value: s.nodeName()}}) + return out.ServiceNodes, nil +} + func (s *HTTPServer) CatalogNodeServices(resp http.ResponseWriter, req *http.Request) (interface{}, error) { metrics.IncrCounterWithLabels([]string{"client", "api", "catalog_node_services"}, 1, []metrics.Label{{Name: "node", Value: s.nodeName()}}) diff --git a/agent/catalog_endpoint_test.go b/agent/catalog_endpoint_test.go index 4df9d4275b..71c848edee 100644 --- a/agent/catalog_endpoint_test.go +++ b/agent/catalog_endpoint_test.go @@ -775,6 +775,30 @@ func TestCatalogServiceNodes_ConnectProxy(t *testing.T) { assert.Equal(structs.ServiceKindConnectProxy, nodes[0].ServiceKind) } +func TestCatalogConnectServiceNodes_good(t *testing.T) { + t.Parallel() + + assert := assert.New(t) + a := NewTestAgent(t.Name(), "") + defer a.Shutdown() + + // Register + args := structs.TestRegisterRequestProxy(t) + var out struct{} + assert.Nil(a.RPC("Catalog.Register", args, &out)) + + req, _ := http.NewRequest("GET", fmt.Sprintf( + "/v1/catalog/connect/%s", args.Service.ProxyDestination), nil) + resp := httptest.NewRecorder() + obj, err := a.srv.CatalogConnectServiceNodes(resp, req) + assert.Nil(err) + assertIndex(t, resp) + + nodes := obj.(structs.ServiceNodes) + assert.Len(nodes, 1) + assert.Equal(structs.ServiceKindConnectProxy, nodes[0].ServiceKind) +} + func TestCatalogNodeServices(t *testing.T) { t.Parallel() a := NewTestAgent(t.Name(), "") diff --git a/agent/http_oss.go b/agent/http_oss.go index d3bb7adc46..185c8c1e0c 100644 --- a/agent/http_oss.go +++ b/agent/http_oss.go @@ -33,6 +33,7 @@ func init() { registerEndpoint("/v1/agent/service/deregister/", []string{"PUT"}, (*HTTPServer).AgentDeregisterService) registerEndpoint("/v1/agent/service/maintenance/", []string{"PUT"}, (*HTTPServer).AgentServiceMaintenance) registerEndpoint("/v1/catalog/register", []string{"PUT"}, (*HTTPServer).CatalogRegister) + registerEndpoint("/v1/catalog/connect/", []string{"GET"}, (*HTTPServer).CatalogConnectServiceNodes) registerEndpoint("/v1/catalog/deregister", []string{"PUT"}, (*HTTPServer).CatalogDeregister) registerEndpoint("/v1/catalog/datacenters", []string{"GET"}, (*HTTPServer).CatalogDatacenters) registerEndpoint("/v1/catalog/nodes", []string{"GET"}, (*HTTPServer).CatalogNodes)