diff --git a/internal/clientcache/cmd/search/search.go b/internal/clientcache/cmd/search/search.go index fab49ed16..8f4725c03 100644 --- a/internal/clientcache/cmd/search/search.go +++ b/internal/clientcache/cmd/search/search.go @@ -70,6 +70,11 @@ func (c *SearchCommand) Flags() *base.FlagSets { Target: &c.flagQuery, Usage: `If set, specifies the resource search query`, }) + f.StringVar(&base.StringVar{ + Name: "filter", + Target: &c.FlagFilter, + Usage: "The filter operates against each item in the response. Using single quotes is recommended as filters contain double quotes. The format is the same as the filters used when performing a list. See https://www.boundaryproject.io/docs/concepts/filtering/resource-listing for details on filters when listing.", + }) f.StringVar(&base.StringVar{ Name: "resource", Target: &c.flagResource, @@ -155,6 +160,7 @@ func (c *SearchCommand) Search(ctx context.Context) (*api.Response, *daemon.Sear } tf := filterBy{ + flagFilter: c.FlagFilter, flagQuery: c.flagQuery, resource: c.flagResource, authTokenId: strings.Join(tSlice[:2], "_"), @@ -187,6 +193,7 @@ func search(ctx context.Context, daemonPath string, fb filterBy, opt ...client.O q.Add("auth_token_id", fb.authTokenId) q.Add("resource", fb.resource) q.Add("query", fb.flagQuery) + q.Add("filter", fb.flagFilter) if fb.forceRefresh { q.Add("force_refresh", "true") } @@ -337,6 +344,7 @@ func printSessionListTable(items []*sessions.Session) string { } type filterBy struct { + flagFilter string flagQuery string authTokenId string resource string diff --git a/internal/clientcache/cmd/search/search_test.go b/internal/clientcache/cmd/search/search_test.go index 2536bdc1c..875d5c020 100644 --- a/internal/clientcache/cmd/search/search_test.go +++ b/internal/clientcache/cmd/search/search_test.go @@ -225,6 +225,34 @@ func TestSearch(t *testing.T) { assert.Len(t, r.Targets, 1) }) + t.Run("full target response from filter", func(t *testing.T) { + resp, r, apiErr, err := search(ctx, srv.BaseDotDir(), filterBy{ + authTokenId: at.Id, + flagFilter: `"/item/id" matches "ttcp"`, + resource: "targets", + }) + require.NoError(t, err) + assert.NoError(t, err) + assert.Nil(t, apiErr) + assert.NotNil(t, resp) + assert.NotNil(t, r) + assert.Len(t, r.Targets, 2) + }) + t.Run("partial target response from filter", func(t *testing.T) { + resp, r, apiErr, err := search(ctx, srv.BaseDotDir(), filterBy{ + authTokenId: at.Id, + flagFilter: `"/item/id" matches "ttcp_1234567890"`, + resource: "targets", + }) + require.NoError(t, err) + assert.NoError(t, err) + assert.Nil(t, apiErr) + assert.NotNil(t, resp) + assert.NotNil(t, r) + assert.Len(t, r.Sessions, 0) + assert.Len(t, r.Targets, 1) + }) + t.Run("session response from list", func(t *testing.T) { resp, r, apiErr, err := search(ctx, srv.BaseDotDir(), filterBy{ authTokenId: at.Id, @@ -264,4 +292,30 @@ func TestSearch(t *testing.T) { assert.NotNil(t, r) assert.Len(t, r.Sessions, 1) }) + t.Run("full session response from filter", func(t *testing.T) { + resp, r, apiErr, err := search(ctx, srv.BaseDotDir(), filterBy{ + authTokenId: at.Id, + flagFilter: `"/item/id" matches "sess"`, + resource: "sessions", + }) + require.NoError(t, err) + assert.NoError(t, err) + assert.Nil(t, apiErr) + assert.NotNil(t, resp) + assert.NotNil(t, r) + assert.Len(t, r.Sessions, 2) + }) + t.Run("partial session response from filter", func(t *testing.T) { + resp, r, apiErr, err := search(ctx, srv.BaseDotDir(), filterBy{ + authTokenId: at.Id, + flagFilter: `"/item/id" matches "sess_1234567890"`, + resource: "sessions", + }) + require.NoError(t, err) + assert.NoError(t, err) + assert.Nil(t, apiErr) + assert.NotNil(t, resp) + assert.NotNil(t, r) + assert.Len(t, r.Sessions, 1) + }) } diff --git a/internal/clientcache/internal/daemon/server.go b/internal/clientcache/internal/daemon/server.go index 6149cb186..506c9da1a 100644 --- a/internal/clientcache/internal/daemon/server.go +++ b/internal/clientcache/internal/daemon/server.go @@ -239,8 +239,8 @@ func (s *CacheServer) Serve(ctx context.Context, cmd Commander, opt ...Option) e s.infoKeys = append(s.infoKeys, "Max Search Refresh Timeout") s.info["Refresh Interval"] = DefaultRefreshInterval.String() s.infoKeys = append(s.infoKeys, "Refresh Interval") - s.info["Full Fetch Interval"] = DefaultRecheckSupportInterval.String() - s.infoKeys = append(s.infoKeys, "Full Fetch Interval") + s.info["Recheck Support Interval"] = DefaultRecheckSupportInterval.String() + s.infoKeys = append(s.infoKeys, "Recheck Support Interval") ticOptions := []Option{} if s.conf.RefreshInterval > 0 {