diff --git a/.changelog/22189.txt b/.changelog/22189.txt new file mode 100644 index 00000000000..f7936e2a1b8 --- /dev/null +++ b/.changelog/22189.txt @@ -0,0 +1,3 @@ +```release-note:improvement +http: Add peer query param on catalog service API +``` diff --git a/agent/catalog_endpoint.go b/agent/catalog_endpoint.go index 8af4654b90f..4847f052c8a 100644 --- a/agent/catalog_endpoint.go +++ b/agent/catalog_endpoint.go @@ -354,6 +354,8 @@ func (s *HTTPHandlers) catalogServiceNodes(resp http.ResponseWriter, req *http.R return nil, nil } + s.parsePeerName(req, &args) + // Check for a tag params := req.URL.Query() if _, ok := params["tag"]; ok { diff --git a/agent/catalog_endpoint_test.go b/agent/catalog_endpoint_test.go index af1f2d36e30..c5a61f3d64a 100644 --- a/agent/catalog_endpoint_test.go +++ b/agent/catalog_endpoint_test.go @@ -964,6 +964,76 @@ func TestCatalogServiceNodes_Filter(t *testing.T) { require.Len(t, nodes, 1) } +func TestCatalogServiceNodes_PeerFilter(t *testing.T) { + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + t.Parallel() + a := StartTestAgent(t, TestAgent{HCL: "", Overrides: `peering = { test_allow_peer_registrations = true }`}) + defer a.Shutdown() + + peerName := "test" + queryPath := "/v1/catalog/service/api?filter=" + url.QueryEscape("ServiceMeta.somekey == somevalue") + peerQuerySuffix(peerName) + + // Make sure an empty list is returned, not a nil + { + req, _ := http.NewRequest("GET", queryPath, nil) + resp := httptest.NewRecorder() + obj, err := a.srv.CatalogServiceNodes(resp, req) + require.NoError(t, err) + + assertIndex(t, resp) + + nodes := obj.(structs.ServiceNodes) + require.Empty(t, nodes) + } + + // Register node + args := &structs.RegisterRequest{ + Datacenter: "dc1", + Node: "foo", + Address: "127.0.0.1", + PeerName: peerName, + Service: &structs.NodeService{ + Service: "api", + Meta: map[string]string{ + "somekey": "somevalue", + }, + }, + } + + var out struct{} + require.NoError(t, a.RPC(context.Background(), "Catalog.Register", args, &out)) + + // Register a second service for the node + args = &structs.RegisterRequest{ + Datacenter: "dc1", + Node: "foo", + Address: "127.0.0.1", + PeerName: peerName, + Service: &structs.NodeService{ + ID: "api2", + Service: "api", + Meta: map[string]string{ + "somekey": "notvalue", + }, + }, + SkipNodeUpdate: true, + } + + require.NoError(t, a.RPC(context.Background(), "Catalog.Register", args, &out)) + + req, _ := http.NewRequest("GET", queryPath, nil) + resp := httptest.NewRecorder() + obj, err := a.srv.CatalogServiceNodes(resp, req) + require.NoError(t, err) + assertIndex(t, resp) + + nodes := obj.(structs.ServiceNodes) + require.Len(t, nodes, 1) +} + func TestCatalogServiceNodes_WanTranslation(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") diff --git a/website/content/api-docs/catalog.mdx b/website/content/api-docs/catalog.mdx index f773353483a..c2f2cebf4ef 100644 --- a/website/content/api-docs/catalog.mdx +++ b/website/content/api-docs/catalog.mdx @@ -551,6 +551,8 @@ The table below shows this endpoint's support for - `filter` `(string: "")` - Specifies the expression used to filter the queries results prior to returning the data. +- `peer` `(string: "")` - Specifies the imported service's peer. Applies only to imported services. + - `merge-central-config` - Include this flag in a request for `connect-proxy` kind or `*-gateway` kind services to return a fully resolved service definition that includes merged values from the [proxy-defaults/global](/consul/docs/connect/config-entries/proxy-defaults) and