diff --git a/agent/agent_endpoint.go b/agent/agent_endpoint.go index f9e02f8f11ad2..23bfa49c88444 100644 --- a/agent/agent_endpoint.go +++ b/agent/agent_endpoint.go @@ -621,6 +621,21 @@ func (s *HTTPHandlers) AgentMembers(resp http.ResponseWriter, req *http.Request) } } + // filter the members by parsed filter expression + var filterExpression string + s.parseFilter(req, &filterExpression) + if filterExpression != "" { + filter, err := bexpr.CreateFilter(filterExpression, nil, members) + if err != nil { + return nil, err + } + raw, err := filter.Execute(members) + if err != nil { + return nil, err + } + members = raw.([]serf.Member) + } + total := len(members) if err := s.agent.filterMembers(token, &members); err != nil { return nil, err diff --git a/api/agent.go b/api/agent.go index f45929cb5b7a9..b09ed1c1cd75d 100644 --- a/api/agent.go +++ b/api/agent.go @@ -274,6 +274,8 @@ type MembersOpts struct { // Segment is the LAN segment to show members for. Setting this to the // AllSegments value above will show members in all segments. Segment string + + Filter string } // AgentServiceRegistration is used to register a new service @@ -790,6 +792,10 @@ func (a *Agent) MembersOpts(opts MembersOpts) ([]*AgentMember, error) { r.params.Set("wan", "1") } + if opts.Filter != "" { + r.params.Set("filter", opts.Filter) + } + _, resp, err := a.c.doRequest(r) if err != nil { return nil, err diff --git a/api/agent_test.go b/api/agent_test.go index ebf738154781a..dce525ebc322c 100644 --- a/api/agent_test.go +++ b/api/agent_test.go @@ -155,6 +155,16 @@ func TestAPI_AgentMembersOpts(t *testing.T) { if len(members) != 2 { t.Fatalf("bad: %v", members) } + + members, err = agent.MembersOpts(MembersOpts{ + WAN: true, + Filter: `Tags["dc"] == dc2`, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + + require.Equal(t, 1, len(members)) } func TestAPI_AgentMembers(t *testing.T) { diff --git a/command/members/members.go b/command/members/members.go index e6be185e53286..9895837f6484d 100644 --- a/command/members/members.go +++ b/command/members/members.go @@ -33,6 +33,7 @@ type cmd struct { wan bool statusFilter string segment string + filter string } func New(ui cli.Ui) *cmd { @@ -54,6 +55,7 @@ func (c *cmd) init() { c.flags.StringVar(&c.segment, "segment", consulapi.AllSegments, "(Enterprise-only) If provided, output is filtered to only nodes in"+ "the given segment.") + c.flags.StringVar(&c.filter, "filter", "", "Filter to use with the request") c.http = &flags.HTTPFlags{} flags.Merge(c.flags, c.http.ClientFlags()) @@ -83,6 +85,7 @@ func (c *cmd) Run(args []string) int { opts := consulapi.MembersOpts{ Segment: c.segment, WAN: c.wan, + Filter: c.filter, } members, err := client.Agent().MembersOpts(opts) if err != nil {