Filter hosts and label counts by teams (#949)

- Add TeamFilter to relevant host and label methods.
- Pass appropriate filter in service methods.

The dashboard should now show the appropriate hosts for a user's team membership.
This commit is contained in:
Zach Wasserman 2021-06-03 18:53:43 -07:00 committed by GitHub
parent b3bafdce24
commit e4358a92bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 173 additions and 123 deletions

View File

@ -250,28 +250,29 @@ func testListHosts(t *testing.T, ds kolide.Datastore) {
hosts = append(hosts, host)
}
hosts2, err := ds.ListHosts(kolide.HostListOptions{})
filter := kolide.TeamFilter{User: test.UserAdmin}
hosts2, err := ds.ListHosts(filter, kolide.HostListOptions{})
require.Nil(t, err)
assert.Equal(t, len(hosts), len(hosts2))
// Test with logic for only a few hosts
hosts2, err = ds.ListHosts(kolide.HostListOptions{ListOptions: kolide.ListOptions{PerPage: 4, Page: 0}})
hosts2, err = ds.ListHosts(filter, kolide.HostListOptions{ListOptions: kolide.ListOptions{PerPage: 4, Page: 0}})
require.Nil(t, err)
assert.Equal(t, 4, len(hosts2))
err = ds.DeleteHost(hosts[0].ID)
require.Nil(t, err)
hosts2, err = ds.ListHosts(kolide.HostListOptions{})
hosts2, err = ds.ListHosts(filter, kolide.HostListOptions{})
require.Nil(t, err)
assert.Equal(t, len(hosts)-1, len(hosts2))
hosts, err = ds.ListHosts(kolide.HostListOptions{})
hosts, err = ds.ListHosts(filter, kolide.HostListOptions{})
require.Nil(t, err)
require.Equal(t, len(hosts2), len(hosts))
err = ds.SaveHost(hosts[0])
require.Nil(t, err)
hosts2, err = ds.ListHosts(kolide.HostListOptions{})
hosts2, err = ds.ListHosts(filter, kolide.HostListOptions{})
require.Nil(t, err)
require.Equal(t, hosts[0].ID, hosts2[0].ID)
}
@ -288,25 +289,27 @@ func testListHostsFilterAdditional(t *testing.T, ds kolide.Datastore) {
})
require.Nil(t, err)
filter := kolide.TeamFilter{User: test.UserAdmin}
// Add additional
additional := json.RawMessage(`{"field1": "v1", "field2": "v2"}`)
h.Additional = &additional
require.NoError(t, ds.SaveHostAdditional(h))
hosts, err := ds.ListHosts(kolide.HostListOptions{})
hosts, err := ds.ListHosts(filter, kolide.HostListOptions{})
require.Nil(t, err)
assert.Nil(t, hosts[0].Additional)
hosts, err = ds.ListHosts(kolide.HostListOptions{AdditionalFilters: []string{"field1", "field2"}})
hosts, err = ds.ListHosts(filter, kolide.HostListOptions{AdditionalFilters: []string{"field1", "field2"}})
require.Nil(t, err)
assert.Equal(t, &additional, hosts[0].Additional)
hosts, err = ds.ListHosts(kolide.HostListOptions{AdditionalFilters: []string{"*"}})
hosts, err = ds.ListHosts(filter, kolide.HostListOptions{AdditionalFilters: []string{"*"}})
require.Nil(t, err)
assert.Equal(t, &additional, hosts[0].Additional)
additional = json.RawMessage(`{"field1": "v1", "missing": null}`)
hosts, err = ds.ListHosts(kolide.HostListOptions{AdditionalFilters: []string{"field1", "missing"}})
hosts, err = ds.ListHosts(filter, kolide.HostListOptions{AdditionalFilters: []string{"field1", "missing"}})
require.Nil(t, err)
assert.Equal(t, &additional, hosts[0].Additional)
}
@ -328,19 +331,21 @@ func testListHostsStatus(t *testing.T, ds kolide.Datastore) {
}
}
hosts, err := ds.ListHosts(kolide.HostListOptions{StatusFilter: "online"})
filter := kolide.TeamFilter{User: test.UserAdmin}
hosts, err := ds.ListHosts(filter, kolide.HostListOptions{StatusFilter: "online"})
require.Nil(t, err)
assert.Equal(t, 1, len(hosts))
hosts, err = ds.ListHosts(kolide.HostListOptions{StatusFilter: "offline"})
hosts, err = ds.ListHosts(filter, kolide.HostListOptions{StatusFilter: "offline"})
require.Nil(t, err)
assert.Equal(t, 9, len(hosts))
hosts, err = ds.ListHosts(kolide.HostListOptions{StatusFilter: "mia"})
hosts, err = ds.ListHosts(filter, kolide.HostListOptions{StatusFilter: "mia"})
require.Nil(t, err)
assert.Equal(t, 0, len(hosts))
hosts, err = ds.ListHosts(kolide.HostListOptions{StatusFilter: "new"})
hosts, err = ds.ListHosts(filter, kolide.HostListOptions{StatusFilter: "new"})
require.Nil(t, err)
assert.Equal(t, 10, len(hosts))
}
@ -364,47 +369,49 @@ func testListHostsQuery(t *testing.T, ds kolide.Datastore) {
hosts = append(hosts, host)
}
gotHosts, err := ds.ListHosts(kolide.HostListOptions{})
filter := kolide.TeamFilter{User: test.UserAdmin}
gotHosts, err := ds.ListHosts(filter, kolide.HostListOptions{})
require.Nil(t, err)
assert.Equal(t, len(hosts), len(gotHosts))
gotHosts, err = ds.ListHosts(kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "00"}})
gotHosts, err = ds.ListHosts(filter, kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "00"}})
require.Nil(t, err)
assert.Equal(t, 10, len(gotHosts))
gotHosts, err = ds.ListHosts(kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "000"}})
gotHosts, err = ds.ListHosts(filter, kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "000"}})
require.Nil(t, err)
assert.Equal(t, 1, len(gotHosts))
gotHosts, err = ds.ListHosts(kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "192.168."}})
gotHosts, err = ds.ListHosts(filter, kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "192.168."}})
require.Nil(t, err)
assert.Equal(t, 10, len(gotHosts))
gotHosts, err = ds.ListHosts(kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "192.168.1.1"}})
gotHosts, err = ds.ListHosts(filter, kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "192.168.1.1"}})
require.Nil(t, err)
assert.Equal(t, 1, len(gotHosts))
gotHosts, err = ds.ListHosts(kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "hostname%00"}})
gotHosts, err = ds.ListHosts(filter, kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "hostname%00"}})
require.Nil(t, err)
assert.Equal(t, 10, len(gotHosts))
gotHosts, err = ds.ListHosts(kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "hostname%003"}})
gotHosts, err = ds.ListHosts(filter, kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "hostname%003"}})
require.Nil(t, err)
assert.Equal(t, 1, len(gotHosts))
gotHosts, err = ds.ListHosts(kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "uuid_"}})
gotHosts, err = ds.ListHosts(filter, kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "uuid_"}})
require.Nil(t, err)
assert.Equal(t, 10, len(gotHosts))
gotHosts, err = ds.ListHosts(kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "uuid_006"}})
gotHosts, err = ds.ListHosts(filter, kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "uuid_006"}})
require.Nil(t, err)
assert.Equal(t, 1, len(gotHosts))
gotHosts, err = ds.ListHosts(kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "serial"}})
gotHosts, err = ds.ListHosts(filter, kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "serial"}})
require.Nil(t, err)
assert.Equal(t, 10, len(gotHosts))
gotHosts, err = ds.ListHosts(kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "serial009"}})
gotHosts, err = ds.ListHosts(filter, kolide.HostListOptions{ListOptions: kolide.ListOptions{MatchQuery: "serial009"}})
require.Nil(t, err)
assert.Equal(t, 1, len(gotHosts))
}
@ -551,8 +558,7 @@ func testSearchHosts(t *testing.T, ds kolide.Datastore) {
}
func testSearchHostsLimit(t *testing.T, ds kolide.Datastore) {
user := &kolide.User{GlobalRole: ptr.String(kolide.RoleAdmin)}
filter := kolide.TeamFilter{User: user}
filter := kolide.TeamFilter{User: test.UserAdmin}
for i := 0; i < 15; i++ {
_, err := ds.NewHost(&kolide.Host{
@ -573,14 +579,10 @@ func testSearchHostsLimit(t *testing.T, ds kolide.Datastore) {
}
func testGenerateHostStatusStatistics(t *testing.T, ds kolide.Datastore) {
if ds.Name() == "inmem" {
fmt.Println("Busted test skipped for inmem")
return
}
filter := kolide.TeamFilter{User: test.UserAdmin}
mockClock := clock.NewMockClock()
online, offline, mia, new, err := ds.GenerateHostStatusStatistics(mockClock.Now())
online, offline, mia, new, err := ds.GenerateHostStatusStatistics(filter, mockClock.Now())
assert.Nil(t, err)
assert.Equal(t, uint(0), online)
assert.Equal(t, uint(0), offline)
@ -640,14 +642,14 @@ func testGenerateHostStatusStatistics(t *testing.T, ds kolide.Datastore) {
})
require.Nil(t, err)
online, offline, mia, new, err = ds.GenerateHostStatusStatistics(mockClock.Now())
online, offline, mia, new, err = ds.GenerateHostStatusStatistics(filter, mockClock.Now())
assert.Nil(t, err)
assert.Equal(t, uint(2), online)
assert.Equal(t, uint(1), offline)
assert.Equal(t, uint(1), mia)
assert.Equal(t, uint(4), new)
online, offline, mia, new, err = ds.GenerateHostStatusStatistics(mockClock.Now().Add(1 * time.Hour))
online, offline, mia, new, err = ds.GenerateHostStatusStatistics(filter, mockClock.Now().Add(1*time.Hour))
assert.Nil(t, err)
assert.Equal(t, uint(0), online)
assert.Equal(t, uint(3), offline)
@ -811,7 +813,8 @@ func testHostIDsByName(t *testing.T, ds kolide.Datastore) {
require.Nil(t, err)
}
hosts, err := ds.HostIDsByName([]string{"foo.2.local", "foo.1.local", "foo.5.local"})
filter := kolide.TeamFilter{User: test.UserAdmin}
hosts, err := ds.HostIDsByName(filter, []string{"foo.2.local", "foo.1.local", "foo.5.local"})
require.Nil(t, err)
sort.Slice(hosts, func(i, j int) bool { return hosts[i] < hosts[j] })
assert.Equal(t, hosts, []uint{2, 3, 6})

View File

@ -335,9 +335,10 @@ func testListHostsInLabel(t *testing.T, db kolide.Datastore) {
err = db.ApplyLabelSpecs([]*kolide.LabelSpec{l1})
require.Nil(t, err)
{
filter := kolide.TeamFilter{User: test.UserAdmin}
hosts, err := db.ListHostsInLabel(l1.ID, kolide.HostListOptions{})
{
hosts, err := db.ListHostsInLabel(filter, l1.ID, kolide.HostListOptions{})
require.Nil(t, err)
assert.Len(t, hosts, 0)
}
@ -348,7 +349,7 @@ func testListHostsInLabel(t *testing.T, db kolide.Datastore) {
}
{
hosts, err := db.ListHostsInLabel(l1.ID, kolide.HostListOptions{})
hosts, err := db.ListHostsInLabel(filter, l1.ID, kolide.HostListOptions{})
require.Nil(t, err)
assert.Len(t, hosts, 3)
}
@ -408,11 +409,13 @@ func testListUniqueHostsInLabels(t *testing.T, db kolide.Datastore) {
assert.Nil(t, err)
}
uniqueHosts, err := db.ListUniqueHostsInLabels([]uint{l1.ID, l2.ID})
filter := kolide.TeamFilter{User: test.UserAdmin}
uniqueHosts, err := db.ListUniqueHostsInLabels(filter, []uint{l1.ID, l2.ID})
assert.Nil(t, err)
assert.Equal(t, len(hosts), len(uniqueHosts))
labels, err := db.ListLabels(kolide.ListOptions{})
labels, err := db.ListLabels(filter, kolide.ListOptions{})
require.Nil(t, err)
require.Len(t, labels, 2)

View File

@ -60,7 +60,7 @@ func (d *Datastore) Host(id uint) (*kolide.Host, error) {
return host, nil
}
func (d *Datastore) ListHosts(opt kolide.HostListOptions) ([]*kolide.Host, error) {
func (d *Datastore) ListHosts(filter kolide.TeamFilter, opt kolide.HostListOptions) ([]*kolide.Host, error) {
d.mtx.Lock()
defer d.mtx.Unlock()
@ -132,7 +132,7 @@ func (d *Datastore) ListHosts(opt kolide.HostListOptions) ([]*kolide.Host, error
return hosts, nil
}
func (d *Datastore) GenerateHostStatusStatistics(now time.Time) (online, offline, mia, new uint, err error) {
func (d *Datastore) GenerateHostStatusStatistics(filter kolide.TeamFilter, now time.Time) (online, offline, mia, new uint, err error) {
d.mtx.Lock()
defer d.mtx.Unlock()

View File

@ -115,7 +115,7 @@ func (d *Datastore) Label(lid uint) (*kolide.Label, error) {
return label, nil
}
func (d *Datastore) ListLabels(opt kolide.ListOptions) ([]*kolide.Label, error) {
func (d *Datastore) ListLabels(filter kolide.TeamFilter, opt kolide.ListOptions) ([]*kolide.Label, error) {
d.mtx.Lock()
defer d.mtx.Unlock()
// We need to sort by keys to provide reliable ordering
@ -177,7 +177,7 @@ func (d *Datastore) SearchLabels(filter kolide.TeamFilter, query string, omit ..
return results, nil
}
func (d *Datastore) ListHostsInLabel(lid uint, opt kolide.HostListOptions) ([]*kolide.Host, error) {
func (d *Datastore) ListHostsInLabel(filter kolide.TeamFilter, lid uint, opt kolide.HostListOptions) ([]*kolide.Host, error) {
var hosts []*kolide.Host
d.mtx.Lock()
@ -192,7 +192,7 @@ func (d *Datastore) ListHostsInLabel(lid uint, opt kolide.HostListOptions) ([]*k
return hosts, nil
}
func (d *Datastore) ListUniqueHostsInLabels(labels []uint) ([]*kolide.Host, error) {
func (d *Datastore) ListUniqueHostsInLabels(filter kolide.TeamFilter, labels []uint) ([]*kolide.Host, error) {
var hosts []*kolide.Host
labelSet := map[uint]bool{}

View File

@ -282,7 +282,7 @@ func (d *Datastore) Host(id uint) (*kolide.Host, error) {
return host, nil
}
func (d *Datastore) ListHosts(opt kolide.HostListOptions) ([]*kolide.Host, error) {
func (d *Datastore) ListHosts(filter kolide.TeamFilter, opt kolide.HostListOptions) ([]*kolide.Host, error) {
sql := `SELECT
h.id,
h.osquery_host_id,
@ -345,9 +345,10 @@ func (d *Datastore) ListHosts(opt kolide.HostListOptions) ([]*kolide.Host, error
`
}
sql += `FROM hosts h LEFT JOIN teams t ON (h.team_id = t.id)
WHERE TRUE
`
sql += fmt.Sprintf(`FROM hosts h LEFT JOIN teams t ON (h.team_id = t.id)
WHERE TRUE AND %s
`, d.whereFilterHostsByTeams(filter, "h"),
)
switch opt.StatusFilter {
case "new":
sql += "AND DATE_ADD(h.created_at, INTERVAL 1 DAY) >= ?"
@ -388,19 +389,21 @@ func (d *Datastore) CleanupIncomingHosts(now time.Time) error {
return nil
}
func (d *Datastore) GenerateHostStatusStatistics(now time.Time) (online, offline, mia, new uint, e error) {
func (d *Datastore) GenerateHostStatusStatistics(filter kolide.TeamFilter, now time.Time) (online, offline, mia, new uint, e error) {
// The logic in this function should remain synchronized with
// host.Status and CountHostsInTargets
sqlStatement := fmt.Sprintf(`
SELECT
COALESCE(SUM(CASE WHEN DATE_ADD(seen_time, INTERVAL 30 DAY) <= ? THEN 1 ELSE 0 END), 0) mia,
COALESCE(SUM(CASE WHEN DATE_ADD(seen_time, INTERVAL LEAST(distributed_interval, config_tls_refresh) + %d SECOND) <= ? AND DATE_ADD(seen_time, INTERVAL 30 DAY) >= ? THEN 1 ELSE 0 END), 0) offline,
COALESCE(SUM(CASE WHEN DATE_ADD(seen_time, INTERVAL LEAST(distributed_interval, config_tls_refresh) + %d SECOND) > ? THEN 1 ELSE 0 END), 0) online,
COALESCE(SUM(CASE WHEN DATE_ADD(created_at, INTERVAL 1 DAY) >= ? THEN 1 ELSE 0 END), 0) new
FROM hosts
LIMIT 1;
`, kolide.OnlineIntervalBuffer, kolide.OnlineIntervalBuffer)
SELECT
COALESCE(SUM(CASE WHEN DATE_ADD(seen_time, INTERVAL 30 DAY) <= ? THEN 1 ELSE 0 END), 0) mia,
COALESCE(SUM(CASE WHEN DATE_ADD(seen_time, INTERVAL LEAST(distributed_interval, config_tls_refresh) + %d SECOND) <= ? AND DATE_ADD(seen_time, INTERVAL 30 DAY) >= ? THEN 1 ELSE 0 END), 0) offline,
COALESCE(SUM(CASE WHEN DATE_ADD(seen_time, INTERVAL LEAST(distributed_interval, config_tls_refresh) + %d SECOND) > ? THEN 1 ELSE 0 END), 0) online,
COALESCE(SUM(CASE WHEN DATE_ADD(created_at, INTERVAL 1 DAY) >= ? THEN 1 ELSE 0 END), 0) new
FROM hosts WHERE %s
LIMIT 1;
`, kolide.OnlineIntervalBuffer, kolide.OnlineIntervalBuffer,
d.whereFilterHostsByTeams(filter, "hosts"),
)
counts := struct {
MIA uint `db:"mia"`
@ -704,15 +707,16 @@ func (d *Datastore) SearchHosts(filter kolide.TeamFilter, query string, omit ...
}
func (d *Datastore) HostIDsByName(hostnames []string) ([]uint, error) {
func (d *Datastore) HostIDsByName(filter kolide.TeamFilter, hostnames []string) ([]uint, error) {
if len(hostnames) == 0 {
return []uint{}, nil
}
sqlStatement := `
SELECT id FROM hosts
WHERE host_name IN (?)
`
sqlStatement := fmt.Sprintf(`
SELECT id FROM hosts
WHERE host_name IN (?) AND %s
`, d.whereFilterHostsByTeams(filter, "hosts"),
)
sql, args, err := sqlx.In(sqlStatement, hostnames)
if err != nil {

View File

@ -243,11 +243,14 @@ func (d *Datastore) Label(lid uint) (*kolide.Label, error) {
}
// ListLabels returns all labels limited or sorted by kolide.ListOptions.
func (d *Datastore) ListLabels(opt kolide.ListOptions) ([]*kolide.Label, error) {
query := `
SELECT *, (SELECT COUNT(1) FROM label_membership WHERE label_id = id) AS host_count
FROM labels
`
func (d *Datastore) ListLabels(filter kolide.TeamFilter, opt kolide.ListOptions) ([]*kolide.Label, error) {
query := fmt.Sprintf(`
SELECT *,
(SELECT COUNT(1) FROM label_membership lm JOIN hosts h ON (lm.host_id = h.id) WHERE label_id = l.id AND %s) AS host_count
FROM labels l
`, d.whereFilterHostsByTeams(filter, "h"),
)
query = appendListOptionsToSQL(query, opt)
labels := []*kolide.Label{}
@ -389,14 +392,16 @@ func (d *Datastore) ListLabelsForHost(hid uint) ([]*kolide.Label, error) {
// ListHostsInLabel returns a list of kolide.Host that are associated
// with kolide.Label referened by Label ID
func (d *Datastore) ListHostsInLabel(lid uint, opt kolide.HostListOptions) ([]*kolide.Host, error) {
sql := `
SELECT h.*
FROM label_membership lm
JOIN hosts h
ON lm.host_id = h.id
WHERE lm.label_id = ?
`
func (d *Datastore) ListHostsInLabel(filter kolide.TeamFilter, lid uint, opt kolide.HostListOptions) ([]*kolide.Host, error) {
sql := fmt.Sprintf(`
SELECT h.*
FROM label_membership lm
JOIN hosts h
ON lm.host_id = h.id
WHERE lm.label_id = ? AND %s
`, d.whereFilterHostsByTeams(filter, "h"),
)
params := []interface{}{lid}
sql, params = searchLike(sql, params, opt.MatchQuery, hostSearchColumns...)
@ -410,18 +415,20 @@ func (d *Datastore) ListHostsInLabel(lid uint, opt kolide.HostListOptions) ([]*k
return hosts, nil
}
func (d *Datastore) ListUniqueHostsInLabels(labels []uint) ([]*kolide.Host, error) {
func (d *Datastore) ListUniqueHostsInLabels(filter kolide.TeamFilter, labels []uint) ([]*kolide.Host, error) {
if len(labels) == 0 {
return []*kolide.Host{}, nil
}
sqlStatement := `
SELECT DISTINCT h.*
FROM label_membership lm
JOIN hosts h
ON lm.host_id = h.id
WHERE lm.label_id IN (?)
`
sqlStatement := fmt.Sprintf(`
SELECT DISTINCT h.*
FROM label_membership lm
JOIN hosts h
ON lm.host_id = h.id
WHERE lm.label_id IN (?) AND %s
`, d.whereFilterHostsByTeams(filter, "h"),
)
query, args, err := sqlx.In(sqlStatement, labels)
if err != nil {
return nil, errors.Wrap(err, "building query listing unique hosts in labels")

View File

@ -47,7 +47,7 @@ type HostStore interface {
// provided host enrollment cooldown, by returning an error if the host has
// enrolled within the cooldown period.
EnrollHost(osqueryHostId, nodeKey string, teamID *uint, cooldown time.Duration) (*Host, error)
ListHosts(opt HostListOptions) ([]*Host, error)
ListHosts(filter TeamFilter, opt HostListOptions) ([]*Host, error)
// AuthenticateHost authenticates and returns host metadata by node key.
// This method should not return the host "additional" information as this
// is not typically necessary for the operations performed by the osquery
@ -66,9 +66,9 @@ type HostStore interface {
CleanupIncomingHosts(now time.Time) error
// GenerateHostStatusStatistics retrieves the count of online, offline,
// MIA and new hosts.
GenerateHostStatusStatistics(now time.Time) (online, offline, mia, new uint, err error)
GenerateHostStatusStatistics(filter TeamFilter, now time.Time) (online, offline, mia, new uint, err error)
// HostIDsByName Retrieve the IDs associated with the given hostnames
HostIDsByName(hostnames []string) ([]uint, error)
HostIDsByName(filter TeamFilter, hostnames []string) ([]uint, error)
// HostByIdentifier returns one host matching the provided identifier.
// Possible matches can be on osquery_host_identifier, node_key, UUID, or
// hostname.

View File

@ -21,7 +21,7 @@ type LabelStore interface {
SaveLabel(label *Label) (*Label, error)
DeleteLabel(name string) error
Label(lid uint) (*Label, error)
ListLabels(opt ListOptions) ([]*Label, error)
ListLabels(filter TeamFilter, opt ListOptions) ([]*Label, error)
// LabelQueriesForHost returns the label queries that should be executed
// for the given host. The cutoff is the minimum timestamp a query
@ -41,12 +41,12 @@ type LabelStore interface {
// ListHostsInLabel returns a slice of hosts in the label with the
// given ID.
ListHostsInLabel(lid uint, opt HostListOptions) ([]*Host, error)
ListHostsInLabel(filter TeamFilter, lid uint, opt HostListOptions) ([]*Host, error)
// ListUniqueHostsInLabels returns a slice of all of the hosts in the
// given label IDs. A host will only appear once in the results even if
// it is in multiple of the provided labels.
ListUniqueHostsInLabels(labels []uint) ([]*Host, error)
ListUniqueHostsInLabels(filter TeamFilter, labels []uint) ([]*Host, error)
SearchLabels(filter TeamFilter, query string, omit ...uint) ([]*Label, error)

View File

@ -20,7 +20,7 @@ type HostFunc func(id uint) (*kolide.Host, error)
type HostByIdentifierFunc func(identifier string) (*kolide.Host, error)
type ListHostsFunc func(opt kolide.HostListOptions) ([]*kolide.Host, error)
type ListHostsFunc func(filter kolide.TeamFilter, opt kolide.HostListOptions) ([]*kolide.Host, error)
type EnrollHostFunc func(osqueryHostId, nodeKey string, teamID *uint, cooldown time.Duration) (*kolide.Host, error)
@ -34,11 +34,11 @@ type CleanupIncomingHostsFunc func(t time.Time) error
type SearchHostsFunc func(filter kolide.TeamFilter, query string, omit ...uint) ([]*kolide.Host, error)
type GenerateHostStatusStatisticsFunc func(now time.Time) (online uint, offline uint, mia uint, new uint, err error)
type GenerateHostStatusStatisticsFunc func(filter kolide.TeamFilter, now time.Time) (online uint, offline uint, mia uint, new uint, err error)
type DistributedQueriesForHostFunc func(host *kolide.Host) (map[uint]string, error)
type HostIDsByNameFunc func(hostnames []string) ([]uint, error)
type HostIDsByNameFunc func(filter kolide.TeamFilter, hostnames []string) ([]uint, error)
type AddHostsToTeamFunc func(teamID *uint, hostIDs []uint) error
@ -122,9 +122,9 @@ func (s *HostStore) HostByIdentifier(identifier string) (*kolide.Host, error) {
return s.HostByIdentifierFunc(identifier)
}
func (s *HostStore) ListHosts(opt kolide.HostListOptions) ([]*kolide.Host, error) {
func (s *HostStore) ListHosts(filter kolide.TeamFilter, opt kolide.HostListOptions) ([]*kolide.Host, error) {
s.ListHostsFuncInvoked = true
return s.ListHostsFunc(opt)
return s.ListHostsFunc(filter, opt)
}
func (s *HostStore) EnrollHost(osqueryHostId, nodeKey string, teamID *uint, cooldown time.Duration) (*kolide.Host, error) {
@ -157,9 +157,9 @@ func (s *HostStore) SearchHosts(filter kolide.TeamFilter, query string, omit ...
return s.SearchHostsFunc(filter, query, omit...)
}
func (s *HostStore) GenerateHostStatusStatistics(now time.Time) (online uint, offline uint, mia uint, new uint, err error) {
func (s *HostStore) GenerateHostStatusStatistics(filter kolide.TeamFilter, now time.Time) (online uint, offline uint, mia uint, new uint, err error) {
s.GenerateHostStatusStatisticsFuncInvoked = true
return s.GenerateHostStatusStatisticsFunc(now)
return s.GenerateHostStatusStatisticsFunc(filter, now)
}
func (s *HostStore) DistributedQueriesForHost(host *kolide.Host) (map[uint]string, error) {
@ -167,9 +167,9 @@ func (s *HostStore) DistributedQueriesForHost(host *kolide.Host) (map[uint]strin
return s.DistributedQueriesForHostFunc(host)
}
func (s *HostStore) HostIDsByName(hostnames []string) ([]uint, error) {
func (s *HostStore) HostIDsByName(filter kolide.TeamFilter, hostnames []string) ([]uint, error) {
s.HostIDsByNameFuncInvoked = true
return s.HostIDsByNameFunc(hostnames)
return s.HostIDsByNameFunc(filter, hostnames)
}
func (s *HostStore) AddHostsToTeam(teamID *uint, hostIDs []uint) error {

View File

@ -24,7 +24,7 @@ type DeleteLabelFunc func(name string) error
type LabelFunc func(lid uint) (*kolide.Label, error)
type ListLabelsFunc func(opt kolide.ListOptions) ([]*kolide.Label, error)
type ListLabelsFunc func(filter kolide.TeamFilter, opt kolide.ListOptions) ([]*kolide.Label, error)
type LabelQueriesForHostFunc func(host *kolide.Host, cutoff time.Time) (map[string]string, error)
@ -32,9 +32,9 @@ type RecordLabelQueryExecutionsFunc func(host *kolide.Host, results map[uint]boo
type ListLabelsForHostFunc func(hid uint) ([]*kolide.Label, error)
type ListHostsInLabelFunc func(lid uint, opt kolide.HostListOptions) ([]*kolide.Host, error)
type ListHostsInLabelFunc func(filter kolide.TeamFilter, lid uint, opt kolide.HostListOptions) ([]*kolide.Host, error)
type ListUniqueHostsInLabelsFunc func(labels []uint) ([]*kolide.Host, error)
type ListUniqueHostsInLabelsFunc func(filter kolide.TeamFilter, labels []uint) ([]*kolide.Host, error)
type SearchLabelsFunc func(filter kolide.TeamFilter, query string, omit ...uint) ([]*kolide.Label, error)
@ -122,9 +122,9 @@ func (s *LabelStore) Label(lid uint) (*kolide.Label, error) {
return s.LabelFunc(lid)
}
func (s *LabelStore) ListLabels(opt kolide.ListOptions) ([]*kolide.Label, error) {
func (s *LabelStore) ListLabels(filter kolide.TeamFilter, opt kolide.ListOptions) ([]*kolide.Label, error) {
s.ListLabelsFuncInvoked = true
return s.ListLabelsFunc(opt)
return s.ListLabelsFunc(filter, opt)
}
func (s *LabelStore) LabelQueriesForHost(host *kolide.Host, cutoff time.Time) (map[string]string, error) {
@ -142,14 +142,14 @@ func (s *LabelStore) ListLabelsForHost(hid uint) ([]*kolide.Label, error) {
return s.ListLabelsForHostFunc(hid)
}
func (s *LabelStore) ListHostsInLabel(lid uint, opt kolide.HostListOptions) ([]*kolide.Host, error) {
func (s *LabelStore) ListHostsInLabel(filter kolide.TeamFilter, lid uint, opt kolide.HostListOptions) ([]*kolide.Host, error) {
s.ListHostsInLabelFuncInvoked = true
return s.ListHostsInLabelFunc(lid, opt)
return s.ListHostsInLabelFunc(filter, lid, opt)
}
func (s *LabelStore) ListUniqueHostsInLabels(labels []uint) ([]*kolide.Host, error) {
func (s *LabelStore) ListUniqueHostsInLabels(filter kolide.TeamFilter, labels []uint) ([]*kolide.Host, error) {
s.ListUniqueHostsInLabelsFuncInvoked = true
return s.ListUniqueHostsInLabelsFunc(labels)
return s.ListUniqueHostsInLabelsFunc(filter, labels)
}
func (s *LabelStore) SearchLabels(filter kolide.TeamFilter, query string, omit ...uint) ([]*kolide.Label, error) {

View File

@ -16,7 +16,13 @@ import (
)
func (svc Service) NewDistributedQueryCampaignByNames(ctx context.Context, queryString string, queryID *uint, hosts []string, labels []string) (*kolide.DistributedQueryCampaign, error) {
hostIDs, err := svc.ds.HostIDsByName(hosts)
vc, ok := viewer.FromContext(ctx)
if !ok {
return nil, kolide.ErrNoContext
}
filter := kolide.TeamFilter{User: vc.User, IncludeObserver: true}
hostIDs, err := svc.ds.HostIDsByName(filter, hosts)
if err != nil {
return nil, errors.Wrap(err, "finding host IDs")
}
@ -26,8 +32,6 @@ func (svc Service) NewDistributedQueryCampaignByNames(ctx context.Context, query
return nil, errors.Wrap(err, "finding label IDs")
}
// TODO handle teams
targets := kolide.HostTargets{HostIDs: hostIDs, LabelIDs: labelIDs}
return svc.NewDistributedQueryCampaign(ctx, queryString, queryID, targets)
}
@ -69,6 +73,8 @@ func (svc Service) NewDistributedQueryCampaign(ctx context.Context, queryString
return nil, errors.Wrap(err, "new query")
}
filter := kolide.TeamFilter{User: vc.User, IncludeObserver: query.ObserverCanRun}
campaign, err := svc.ds.NewDistributedQueryCampaign(&kolide.DistributedQueryCampaign{
QueryID: query.ID,
Status: kolide.QueryWaiting,
@ -114,8 +120,6 @@ func (svc Service) NewDistributedQueryCampaign(ctx context.Context, queryString
}
}
filter := kolide.TeamFilter{User: vc.User}
hostIDs, err := svc.ds.HostIDsInTargets(filter, targets)
if err != nil {
return nil, errors.Wrap(err, "get target IDs")

View File

@ -3,6 +3,7 @@ package service
import (
"context"
"github.com/fleetdm/fleet/server/contexts/viewer"
"github.com/fleetdm/fleet/server/kolide"
"github.com/pkg/errors"
)
@ -12,7 +13,13 @@ func (svc Service) ListHosts(ctx context.Context, opt kolide.HostListOptions) ([
return nil, err
}
return svc.ds.ListHosts(opt)
vc, ok := viewer.FromContext(ctx)
if !ok {
return nil, kolide.ErrNoContext
}
filter := kolide.TeamFilter{User: vc.User, IncludeObserver: true}
return svc.ds.ListHosts(filter, opt)
}
func (svc Service) GetHost(ctx context.Context, id uint) (*kolide.HostDetail, error) {
@ -73,8 +80,13 @@ func (svc Service) GetHostSummary(ctx context.Context) (*kolide.HostSummary, err
if err := svc.authz.Authorize(ctx, &kolide.Host{}, kolide.ActionList); err != nil {
return nil, err
}
vc, ok := viewer.FromContext(ctx)
if !ok {
return nil, kolide.ErrNoContext
}
filter := kolide.TeamFilter{User: vc.User, IncludeObserver: true}
online, offline, mia, new, err := svc.ds.GenerateHostStatusStatistics(svc.clock.Now())
online, offline, mia, new, err := svc.ds.GenerateHostStatusStatistics(filter, svc.clock.Now())
if err != nil {
return nil, err
}
@ -131,6 +143,11 @@ func (svc Service) AddHostsToTeamByFilter(ctx context.Context, teamID *uint, opt
if err := svc.authz.Authorize(ctx, &kolide.Team{}, kolide.ActionWrite); err != nil {
return err
}
vc, ok := viewer.FromContext(ctx)
if !ok {
return kolide.ErrNoContext
}
filter := kolide.TeamFilter{User: vc.User, IncludeObserver: true}
if opt.StatusFilter != "" && lid != nil {
return kolide.NewInvalidArgumentError("status", "may not be provided with label_id")
@ -142,9 +159,9 @@ func (svc Service) AddHostsToTeamByFilter(ctx context.Context, teamID *uint, opt
var hosts []*kolide.Host
var err error
if lid != nil {
hosts, err = svc.ds.ListHostsInLabel(*lid, opt)
hosts, err = svc.ds.ListHostsInLabel(filter, *lid, opt)
} else {
hosts, err = svc.ds.ListHosts(opt)
hosts, err = svc.ds.ListHosts(filter, opt)
}
if err != nil {
return err

View File

@ -48,7 +48,8 @@ func TestDeleteHost(t *testing.T) {
err = svc.DeleteHost(test.UserContext(test.UserAdmin), host.ID)
assert.Nil(t, err)
hosts, err := ds.ListHosts(kolide.HostListOptions{})
filter := kolide.TeamFilter{User: test.UserAdmin}
hosts, err := ds.ListHosts(filter, kolide.HostListOptions{})
assert.Nil(t, err)
assert.Len(t, hosts, 0)
@ -113,7 +114,7 @@ func TestAddHostsToTeamByFilter(t *testing.T) {
expectedHostIDs := []uint{1, 2, 4}
expectedTeam := (*uint)(nil)
ds.ListHostsFunc = func(opt kolide.HostListOptions) ([]*kolide.Host, error) {
ds.ListHostsFunc = func(filter kolide.TeamFilter, opt kolide.HostListOptions) ([]*kolide.Host, error) {
var hosts []*kolide.Host
for _, id := range expectedHostIDs {
hosts = append(hosts, &kolide.Host{ID: id})
@ -137,7 +138,7 @@ func TestAddHostsToTeamByFilterLabel(t *testing.T) {
expectedTeam := ptr.Uint(1)
expectedLabel := ptr.Uint(2)
ds.ListHostsInLabelFunc = func(lid uint, opt kolide.HostListOptions) ([]*kolide.Host, error) {
ds.ListHostsInLabelFunc = func(filter kolide.TeamFilter, lid uint, opt kolide.HostListOptions) ([]*kolide.Host, error) {
assert.Equal(t, *expectedLabel, lid)
var hosts []*kolide.Host
for _, id := range expectedHostIDs {
@ -157,7 +158,7 @@ func TestAddHostsToTeamByFilterEmptyHosts(t *testing.T) {
ds := new(mock.Store)
svc := newTestService(ds, nil, nil)
ds.ListHostsFunc = func(opt kolide.HostListOptions) ([]*kolide.Host, error) {
ds.ListHostsFunc = func(filter kolide.TeamFilter, opt kolide.HostListOptions) ([]*kolide.Host, error) {
return []*kolide.Host{}, nil
}
ds.AddHostsToTeamFunc = func(teamID *uint, hostIDs []uint) error {

View File

@ -3,6 +3,7 @@ package service
import (
"context"
"github.com/fleetdm/fleet/server/contexts/viewer"
"github.com/fleetdm/fleet/server/kolide"
"github.com/pkg/errors"
)
@ -94,8 +95,13 @@ func (svc *Service) ListLabels(ctx context.Context, opt kolide.ListOptions) ([]*
if err := svc.authz.Authorize(ctx, &kolide.Label{}, kolide.ActionRead); err != nil {
return nil, err
}
vc, ok := viewer.FromContext(ctx)
if !ok {
return nil, kolide.ErrNoContext
}
filter := kolide.TeamFilter{User: vc.User, IncludeObserver: true}
return svc.ds.ListLabels(opt)
return svc.ds.ListLabels(filter, opt)
}
func (svc *Service) GetLabel(ctx context.Context, id uint) (*kolide.Label, error) {
@ -130,8 +136,13 @@ func (svc *Service) ListHostsInLabel(ctx context.Context, lid uint, opt kolide.H
if err := svc.authz.Authorize(ctx, &kolide.Label{}, kolide.ActionRead); err != nil {
return nil, err
}
vc, ok := viewer.FromContext(ctx)
if !ok {
return nil, kolide.ErrNoContext
}
filter := kolide.TeamFilter{User: vc.User, IncludeObserver: true}
return svc.ds.ListHostsInLabel(lid, opt)
return svc.ds.ListHostsInLabel(filter, lid, opt)
}
func (svc *Service) ListLabelsForHost(ctx context.Context, hid uint) ([]*kolide.Label, error) {