Skip to content

Commit 19d53aa

Browse files
committed
health: ensure /v1/health/service/:service endpoint returns the most recent results when a filter is used
This is two bugs in two subsystems (blocking queries ; streaming) that make the overall endpoint behave brokenly in the same way to the end user. Simple reproduction (streaming): 1. Register a service with a tag. curl -sL --request PUT 'http://localhost:8500/v1/agent/service/register' \ --header 'Content-Type: application/json' \ --data-raw '{ "ID": "ID1", "Name": "test", "Tags":[ "a" ], "EnableTagOverride": true }' 2. Do an initial filter query that matches on the tag. curl -sLi --get 'http://localhost:8500/v1/health/service/test' --data-urlencode 'filter=a in Service.Tags' 3. Note you get one result. Use the `X-Consul-Index` header to establish a blocking query in another terminal, this should not return yet. curl -sLi --get 'http://localhost:8500/v1/health/service/test?index=$INDEX' --data-urlencode 'filter=a in Service.Tags' 4. Re-register that service with a different tag. curl -sL --request PUT 'http://localhost:8500/v1/agent/service/register' \ --header 'Content-Type: application/json' \ --data-raw '{ "ID": "ID1", "Name": "test", "Tags":[ "b" ], "EnableTagOverride": true }' 5. Your blocking query from (3) should return with a header `X-Consul-Query-Backend: streaming` and empty results if it works correctly `[]`. To reproduce for non-streaming, simply add `&near=_agent` to your read queries and ensure `X-Consul-Query-Backend: blocking-query` shows up in the results.
1 parent 3f9b31e commit 19d53aa

File tree

2 files changed

+15
-8
lines changed

2 files changed

+15
-8
lines changed

Diff for: agent/consul/health_endpoint.go

+11-5
Original file line numberDiff line numberDiff line change
@@ -236,21 +236,22 @@ func (h *Health) ServiceNodes(args *structs.ServiceSpecificRequest, reply *struc
236236
&args.QueryOptions,
237237
&reply.QueryMeta,
238238
func(ws memdb.WatchSet, state *state.Store) error {
239+
var thisReply structs.IndexedCheckServiceNodes
240+
239241
index, nodes, err := f(ws, state, args)
240242
if err != nil {
241243
return err
242244
}
243245

244-
reply.Index, reply.Nodes = index, nodes
245246
if len(args.NodeMetaFilters) > 0 {
246-
reply.Nodes = nodeMetaFilter(args.NodeMetaFilters, reply.Nodes)
247+
nodes = nodeMetaFilter(args.NodeMetaFilters, nodes)
247248
}
248249

249-
raw, err := filter.Execute(reply.Nodes)
250+
raw, err := filter.Execute(nodes)
250251
if err != nil {
251252
return err
252253
}
253-
reply.Nodes = raw.(structs.CheckServiceNodes)
254+
nodes = raw.(structs.CheckServiceNodes)
254255

255256
// Note: we filter the results with ACLs *after* applying the user-supplied
256257
// bexpr filter, to ensure QueryMeta.ResultsFilteredByACLs does not include
@@ -259,7 +260,12 @@ func (h *Health) ServiceNodes(args *structs.ServiceSpecificRequest, reply *struc
259260
return err
260261
}
261262

262-
return h.srv.sortNodesByDistanceFrom(args.Source, reply.Nodes)
263+
if err := h.srv.sortNodesByDistanceFrom(args.Source, nodes); err != nil {
264+
return err
265+
}
266+
267+
reply.Index, reply.Nodes = index, nodes
268+
return nil
263269
})
264270

265271
// Provide some metrics

Diff for: agent/rpcclient/health/view.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,12 @@ func (s *healthView) Update(events []*pbsubscribe.Event) error {
8080
return errors.New("check service node was unexpectedly nil")
8181
}
8282
passed, err := s.filter.Evaluate(*csn)
83-
switch {
84-
case err != nil:
83+
if err != nil {
8584
return err
86-
case passed:
85+
} else if passed {
8786
s.state[id] = *csn
87+
} else {
88+
delete(s.state, id)
8889
}
8990

9091
case pbsubscribe.CatalogOp_Deregister:

0 commit comments

Comments
 (0)