Make SearchHosts behave the same as the filtering in ListHosts (#4295)

This commit is contained in:
Tomas Touceda 2022-02-22 10:19:51 -03:00 committed by GitHub
parent 2ab1b9ec85
commit 4034a7ab59
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 24 additions and 33 deletions

View file

@ -0,0 +1 @@
* Make target search behave the same as host search

View file

@ -771,33 +771,19 @@ func (ds *Datastore) MarkHostsSeen(ctx context.Context, hostIDs []uint, t time.T
// SearchHosts performs a search on the hosts table using the following criteria:
// - Use the provided team filter.
// - Full-text search with the "query" argument (if query == "", then no fulltext matching is executed).
// Full-text search is used even if "query" is a short or stopword.
// (what defines a short word is the "ft_min_word_len" VARIABLE, set to 4 by default in Fleet deployments).
// - Search hostname, uuid, hardware_serial, and primary_ip using LIKE (mimics ListHosts behavior)
// - An optional list of IDs to omit from the search.
func (ds *Datastore) SearchHosts(ctx context.Context, filter fleet.TeamFilter, query string, omit ...uint) ([]*fleet.Host, error) {
var sqlb strings.Builder
sqlb.WriteString(`SELECT
func (ds *Datastore) SearchHosts(ctx context.Context, filter fleet.TeamFilter, matchQuery string, omit ...uint) ([]*fleet.Host, error) {
query := `SELECT
h.*,
COALESCE(hst.seen_time, h.created_at) AS seen_time
FROM hosts h
LEFT JOIN host_seen_times hst
ON (h.id=hst.host_id) WHERE`)
ON (h.id=hst.host_id) WHERE TRUE `
var args []interface{}
if len(query) > 0 {
sqlb.WriteString(` (
MATCH (hostname, uuid) AGAINST (? IN BOOLEAN MODE)
OR MATCH (primary_ip, primary_mac) AGAINST (? IN BOOLEAN MODE)
) AND`)
// Transform query argument and append the truncation operator "*" for MATCH.
// From Oracle docs: "If a word is specified with the truncation operator, it is not
// stripped from a boolean query, even if it is too short or a stopword."
hostQuery := transformQueryWithSuffix(query, "*")
// Needs quotes to avoid each "." marking a word boundary.
// TODO(lucas): Currently matching the primary_mac doesn't work, see #1959.
ipQuery := `"` + query + `"`
args = append(args, hostQuery, ipQuery)
if len(matchQuery) > 0 {
query, args = hostSearchLike(query, args, matchQuery, hostSearchColumns...)
}
var in interface{}
// use -1 if there are no values to omit.
@ -807,17 +793,17 @@ func (ds *Datastore) SearchHosts(ctx context.Context, filter fleet.TeamFilter, q
in = -1
}
args = append(args, in)
sqlb.WriteString(" id NOT IN (?) AND ")
sqlb.WriteString(ds.whereFilterHostsByTeams(filter, "h"))
sqlb.WriteString(` ORDER BY h.id DESC LIMIT 10`)
query += " AND id NOT IN (?) AND "
query += ds.whereFilterHostsByTeams(filter, "h")
query += ` ORDER BY h.id DESC LIMIT 10`
sql, args, err := sqlx.In(sqlb.String(), args...)
query, args, err := sqlx.In(query, args...)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "searching default hosts")
}
sql = ds.reader.Rebind(sql)
query = ds.reader.Rebind(query)
hosts := []*fleet.Host{}
if err := sqlx.SelectContext(ctx, ds.reader, &hosts, sql, args...); err != nil {
if err := sqlx.SelectContext(ctx, ds.reader, &hosts, query, args...); err != nil {
return nil, ctxerr.Wrap(ctx, err, "searching hosts")
}
return hosts, nil

View file

@ -877,7 +877,7 @@ func testHostsSearch(t *testing.T, ds *Datastore) {
SeenTime: time.Now(),
NodeKey: "1",
UUID: "1",
Hostname: "foo.local",
Hostname: "fo.local",
})
require.NoError(t, err)
@ -923,19 +923,23 @@ func testHostsSearch(t *testing.T, ds *Datastore) {
_, err = ds.SearchHosts(context.Background(), filter, "")
require.NoError(t, err)
hosts, err := ds.SearchHosts(context.Background(), filter, "foo")
hosts, err := ds.SearchHosts(context.Background(), filter, "fo")
require.NoError(t, err)
assert.Len(t, hosts, 2)
host, err := ds.SearchHosts(context.Background(), filter, "foo", h3.ID)
hosts, err = ds.SearchHosts(context.Background(), filter, "fo.")
require.NoError(t, err)
require.Len(t, host, 1)
assert.Equal(t, "foo.local", host[0].Hostname)
assert.Len(t, hosts, 1)
host, err = ds.SearchHosts(context.Background(), filter, "foo", h3.ID, h2.ID)
host, err := ds.SearchHosts(context.Background(), filter, "fo", h3.ID)
require.NoError(t, err)
require.Len(t, host, 1)
assert.Equal(t, "foo.local", host[0].Hostname)
assert.Equal(t, "fo.local", host[0].Hostname)
host, err = ds.SearchHosts(context.Background(), filter, "fo", h3.ID, h2.ID)
require.NoError(t, err)
require.Len(t, host, 1)
assert.Equal(t, "fo.local", host[0].Hostname)
host, err = ds.SearchHosts(context.Background(), filter, "abc")
require.NoError(t, err)