Skip to content

Commit

Permalink
Merge eaf50ef into backport/gh-17642-watch-checks-tag/allegedly-worka…
Browse files Browse the repository at this point in the history
…ble-stud
  • Loading branch information
hc-github-team-consul-core authored Jun 29, 2023
2 parents d91c5db + eaf50ef commit ad627c4
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 31 deletions.
6 changes: 6 additions & 0 deletions agent/consul/health_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1767,5 +1767,11 @@ func TestHealth_RPC_Filter(t *testing.T) {
out = new(structs.IndexedHealthChecks)
require.NoError(t, msgpackrpc.CallWithCodec(codec, "Health.ChecksInState", &args, out))
require.Len(t, out.HealthChecks, 1)

args.State = api.HealthAny
args.Filter = "connect in ServiceTags and v2 in ServiceTags"
out = new(structs.IndexedHealthChecks)
require.NoError(t, msgpackrpc.CallWithCodec(codec, "Health.ChecksInState", &args, out))
require.Len(t, out.HealthChecks, 1)
})
}
13 changes: 13 additions & 0 deletions agent/health_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package agent

import (
"fmt"
"net/http"
"net/url"
"strconv"
Expand Down Expand Up @@ -37,6 +38,18 @@ func (s *HTTPHandlers) HealthChecksInState(resp http.ResponseWriter, req *http.R
return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Missing check state"}
}

// build tag filter
params := req.URL.Query()
if tags, ok := params["tag"]; ok {
for i, tag := range tags {
expr := fmt.Sprintf(`%s in ServiceTags`, tag)
if i < len(tags)-1 {
expr += " and "
}
args.Filter += expr
}
}

// Make the RPC request
var out structs.IndexedHealthChecks
defer setMeta(resp, &out.QueryMeta)
Expand Down
13 changes: 13 additions & 0 deletions api/health.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,12 @@ func (h *Health) service(service string, tags []string, passingOnly bool, q *Que
// State is used to retrieve all the checks in a given state.
// The wildcard "any" state can also be used for all checks.
func (h *Health) State(state string, q *QueryOptions) (HealthChecks, *QueryMeta, error) {
return h.StateTags(state, nil, q)
}

// StateTags is used to retrieve all the checks in a given state and tags.
// The wildcard "any" state can also be used for all checks.
func (h *Health) StateTags(state string, tags []string, q *QueryOptions) (HealthChecks, *QueryMeta, error) {
switch state {
case HealthAny:
case HealthWarning:
Expand All @@ -376,6 +382,13 @@ func (h *Health) State(state string, q *QueryOptions) (HealthChecks, *QueryMeta,
}
r := h.c.newRequest("GET", "/v1/health/state/"+state)
r.setQueryOptions(q)

if len(tags) > 0 {
for _, tag := range tags {
r.params.Add("tag", tag)
}
}

rtt, resp, err := h.c.doRequest(r)
if err != nil {
return nil, nil, err
Expand Down
31 changes: 1 addition & 30 deletions api/watch/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,48 +204,19 @@ func checksWatch(params map[string]interface{}) (WatcherFunc, error) {
var meta *consulapi.QueryMeta
var err error
if state != "" {
checks, meta, err = health.State(state, &opts)
checks, meta, err = health.StateTags(state, tags, &opts)
} else {
checks, meta, err = health.Checks(service, &opts)
}
if err != nil {
return nil, nil, err
}
if len(tags) > 0 {
checks = filterChecksByTags(checks, tags)
}

return WaitIndexVal(meta.LastIndex), checks, err
}
return fn, nil
}

// filterChecksByTags filters HealthChecks by the tags
func filterChecksByTags(checks consulapi.HealthChecks, tags []string) consulapi.HealthChecks {
filteredChecks := consulapi.HealthChecks{}

for _, check := range checks {
// the check is appended to the filteredChecks if its tags
// contain every tag in tags
svcTagMap := map[string]struct{}{}
for _, svcTag := range check.ServiceTags {
svcTagMap[svcTag] = struct{}{}
}

count := 0
for _, tag := range tags {
if _, ok := svcTagMap[tag]; ok {
count++
}

if count == len(tags) {
filteredChecks = append(filteredChecks, check)
}
}
}
return filteredChecks
}

// eventWatch is used to watch for events, optionally filtering on name
func eventWatch(params map[string]interface{}) (WatcherFunc, error) {
// The stale setting doesn't apply to events.
Expand Down
2 changes: 1 addition & 1 deletion api/watch/funcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,7 @@ func TestChecksWatch_Service_Tags(t *testing.T) {
notifyCh = make(chan struct{})
)

plan := mustParse(t, `{"type":"checks", "tag":["a", "b"]}`)
plan := mustParse(t, `{"type":"checks", "tag":["b", "a"]}`)
plan.Handler = func(idx uint64, raw interface{}) {
if raw == nil {
return // ignore
Expand Down

0 comments on commit ad627c4

Please sign in to comment.