mirror of https://github.com/status-im/consul.git
member cli: add -filter expression to flags (#18223)
* member cli: add -filter expression to flags * changelog * update doc * Add test cases * use quote
This commit is contained in:
parent
090e869a55
commit
31d2813714
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:feature
|
||||||
|
cli: `consul members` command uses `-filter` expression to filter members based on bexpr.
|
||||||
|
```
|
|
@ -619,6 +619,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)
|
total := len(members)
|
||||||
if err := s.agent.filterMembers(token, &members); err != nil {
|
if err := s.agent.filterMembers(token, &members); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -274,6 +274,8 @@ type MembersOpts struct {
|
||||||
// Segment is the LAN segment to show members for. Setting this to the
|
// Segment is the LAN segment to show members for. Setting this to the
|
||||||
// AllSegments value above will show members in all segments.
|
// AllSegments value above will show members in all segments.
|
||||||
Segment string
|
Segment string
|
||||||
|
|
||||||
|
Filter string
|
||||||
}
|
}
|
||||||
|
|
||||||
// AgentServiceRegistration is used to register a new service
|
// 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")
|
r.params.Set("wan", "1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.Filter != "" {
|
||||||
|
r.params.Set("filter", opts.Filter)
|
||||||
|
}
|
||||||
|
|
||||||
_, resp, err := a.c.doRequest(r)
|
_, resp, err := a.c.doRequest(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -155,6 +155,31 @@ func TestAPI_AgentMembersOpts(t *testing.T) {
|
||||||
if len(members) != 2 {
|
if len(members) != 2 {
|
||||||
t.Fatalf("bad: %v", members)
|
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))
|
||||||
|
|
||||||
|
members, err = agent.MembersOpts(MembersOpts{
|
||||||
|
WAN: true,
|
||||||
|
Filter: `Tags["dc"] == "not-Exist"`,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
require.Equal(t, 0, len(members))
|
||||||
|
|
||||||
|
_, err = agent.MembersOpts(MembersOpts{
|
||||||
|
WAN: true,
|
||||||
|
Filter: `Tags["dc"] == invalid-bexpr-value`,
|
||||||
|
})
|
||||||
|
require.ErrorContains(t, err, "Failed to create boolean expression evaluator")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPI_AgentMembers(t *testing.T) {
|
func TestAPI_AgentMembers(t *testing.T) {
|
||||||
|
|
|
@ -33,6 +33,7 @@ type cmd struct {
|
||||||
wan bool
|
wan bool
|
||||||
statusFilter string
|
statusFilter string
|
||||||
segment string
|
segment string
|
||||||
|
filter string
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ui cli.Ui) *cmd {
|
func New(ui cli.Ui) *cmd {
|
||||||
|
@ -54,6 +55,7 @@ func (c *cmd) init() {
|
||||||
c.flags.StringVar(&c.segment, "segment", consulapi.AllSegments,
|
c.flags.StringVar(&c.segment, "segment", consulapi.AllSegments,
|
||||||
"(Enterprise-only) If provided, output is filtered to only nodes in"+
|
"(Enterprise-only) If provided, output is filtered to only nodes in"+
|
||||||
"the given segment.")
|
"the given segment.")
|
||||||
|
c.flags.StringVar(&c.filter, "filter", "", "Filter to use with the request")
|
||||||
|
|
||||||
c.http = &flags.HTTPFlags{}
|
c.http = &flags.HTTPFlags{}
|
||||||
flags.Merge(c.flags, c.http.ClientFlags())
|
flags.Merge(c.flags, c.http.ClientFlags())
|
||||||
|
@ -83,6 +85,7 @@ func (c *cmd) Run(args []string) int {
|
||||||
opts := consulapi.MembersOpts{
|
opts := consulapi.MembersOpts{
|
||||||
Segment: c.segment,
|
Segment: c.segment,
|
||||||
WAN: c.wan,
|
WAN: c.wan,
|
||||||
|
Filter: c.filter,
|
||||||
}
|
}
|
||||||
members, err := client.Agent().MembersOpts(opts)
|
members, err := client.Agent().MembersOpts(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -48,6 +48,12 @@ Usage: `consul members [options]`
|
||||||
in the WAN gossip pool. These are generally all the server nodes in
|
in the WAN gossip pool. These are generally all the server nodes in
|
||||||
each datacenter.
|
each datacenter.
|
||||||
|
|
||||||
|
- `-filter=<filter>` - Expression to use for filtering the results,
|
||||||
|
e.g., `-filter='Tags["dc"] == dc2'`.
|
||||||
|
See the [`/catalog/nodes` API documentation](/consul/api-docs/catalog#filtering) for a
|
||||||
|
description of what is filterable.
|
||||||
|
|
||||||
|
|
||||||
#### Enterprise Options
|
#### Enterprise Options
|
||||||
|
|
||||||
@include 'http_api_partition_options.mdx'
|
@include 'http_api_partition_options.mdx'
|
||||||
|
|
Loading…
Reference in New Issue