mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
add new status to host summary endpoint (#1057)
new_count shows all hosts that have been added to kolide in the last 24 hours
This commit is contained in:
parent
5f6f9388cd
commit
eac718e937
6 changed files with 76 additions and 20 deletions
|
|
@ -501,11 +501,12 @@ func testDistributedQueriesForHost(t *testing.T, ds kolide.Datastore) {
|
||||||
func testGenerateHostStatusStatistics(t *testing.T, ds kolide.Datastore) {
|
func testGenerateHostStatusStatistics(t *testing.T, ds kolide.Datastore) {
|
||||||
mockClock := clock.NewMockClock()
|
mockClock := clock.NewMockClock()
|
||||||
|
|
||||||
online, offline, mia, err := ds.GenerateHostStatusStatistics(mockClock.Now())
|
online, offline, mia, new, err := ds.GenerateHostStatusStatistics(mockClock.Now())
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, uint(0), online)
|
assert.Equal(t, uint(0), online)
|
||||||
assert.Equal(t, uint(0), offline)
|
assert.Equal(t, uint(0), offline)
|
||||||
assert.Equal(t, uint(0), mia)
|
assert.Equal(t, uint(0), mia)
|
||||||
|
assert.Equal(t, uint(0), new)
|
||||||
|
|
||||||
// Online
|
// Online
|
||||||
_, err = ds.NewHost(&kolide.Host{
|
_, err = ds.NewHost(&kolide.Host{
|
||||||
|
|
@ -515,6 +516,9 @@ func testGenerateHostStatusStatistics(t *testing.T, ds kolide.Datastore) {
|
||||||
NodeKey: "1",
|
NodeKey: "1",
|
||||||
DetailUpdateTime: mockClock.Now(),
|
DetailUpdateTime: mockClock.Now(),
|
||||||
SeenTime: mockClock.Now(),
|
SeenTime: mockClock.Now(),
|
||||||
|
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||||
|
CreateTimestamp: kolide.CreateTimestamp{CreatedAt: mockClock.Now()},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
|
@ -526,6 +530,9 @@ func testGenerateHostStatusStatistics(t *testing.T, ds kolide.Datastore) {
|
||||||
NodeKey: "2",
|
NodeKey: "2",
|
||||||
DetailUpdateTime: mockClock.Now().Add(-1 * time.Minute),
|
DetailUpdateTime: mockClock.Now().Add(-1 * time.Minute),
|
||||||
SeenTime: mockClock.Now().Add(-1 * time.Minute),
|
SeenTime: mockClock.Now().Add(-1 * time.Minute),
|
||||||
|
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||||
|
CreateTimestamp: kolide.CreateTimestamp{CreatedAt: mockClock.Now()},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
|
@ -537,6 +544,9 @@ func testGenerateHostStatusStatistics(t *testing.T, ds kolide.Datastore) {
|
||||||
NodeKey: "3",
|
NodeKey: "3",
|
||||||
DetailUpdateTime: mockClock.Now().Add(-1 * time.Hour),
|
DetailUpdateTime: mockClock.Now().Add(-1 * time.Hour),
|
||||||
SeenTime: mockClock.Now().Add(-1 * time.Hour),
|
SeenTime: mockClock.Now().Add(-1 * time.Hour),
|
||||||
|
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||||
|
CreateTimestamp: kolide.CreateTimestamp{CreatedAt: mockClock.Now()},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
|
@ -548,14 +558,18 @@ func testGenerateHostStatusStatistics(t *testing.T, ds kolide.Datastore) {
|
||||||
NodeKey: "4",
|
NodeKey: "4",
|
||||||
DetailUpdateTime: mockClock.Now().Add(-35 * (24 * time.Hour)),
|
DetailUpdateTime: mockClock.Now().Add(-35 * (24 * time.Hour)),
|
||||||
SeenTime: mockClock.Now().Add(-35 * (24 * time.Hour)),
|
SeenTime: mockClock.Now().Add(-35 * (24 * time.Hour)),
|
||||||
|
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||||
|
CreateTimestamp: kolide.CreateTimestamp{CreatedAt: mockClock.Now()},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
online, offline, mia, err = ds.GenerateHostStatusStatistics(mockClock.Now())
|
online, offline, mia, new, err = ds.GenerateHostStatusStatistics(mockClock.Now())
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, uint(2), online)
|
assert.Equal(t, uint(2), online)
|
||||||
assert.Equal(t, uint(1), offline)
|
assert.Equal(t, uint(1), offline)
|
||||||
assert.Equal(t, uint(1), mia)
|
assert.Equal(t, uint(1), mia)
|
||||||
|
assert.Equal(t, uint(4), new)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMarkHostSeen(t *testing.T, ds kolide.Datastore) {
|
func testMarkHostSeen(t *testing.T, ds kolide.Datastore) {
|
||||||
|
|
|
||||||
|
|
@ -114,11 +114,15 @@ func (d *Datastore) ListHosts(opt kolide.ListOptions) ([]*kolide.Host, error) {
|
||||||
return hosts, nil
|
return hosts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Datastore) GenerateHostStatusStatistics(now time.Time) (online, offline, mia uint, err error) {
|
func (d *Datastore) GenerateHostStatusStatistics(now time.Time) (online, offline, mia, new uint, err error) {
|
||||||
d.mtx.Lock()
|
d.mtx.Lock()
|
||||||
defer d.mtx.Unlock()
|
defer d.mtx.Unlock()
|
||||||
|
|
||||||
for _, host := range d.hosts {
|
for _, host := range d.hosts {
|
||||||
|
if host.IsNew(now) {
|
||||||
|
new++
|
||||||
|
}
|
||||||
|
|
||||||
status := host.Status(now)
|
status := host.Status(now)
|
||||||
switch status {
|
switch status {
|
||||||
case kolide.StatusMIA:
|
case kolide.StatusMIA:
|
||||||
|
|
@ -130,7 +134,7 @@ func (d *Datastore) GenerateHostStatusStatistics(now time.Time) (online, offline
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return online, offline, mia, nil
|
return online, offline, mia, new, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Datastore) EnrollHost(osQueryHostID string, nodeKeySize int) (*kolide.Host, error) {
|
func (d *Datastore) EnrollHost(osQueryHostID string, nodeKeySize int) (*kolide.Host, error) {
|
||||||
|
|
|
||||||
|
|
@ -283,7 +283,7 @@ func (d *Datastore) ListHosts(opt kolide.ListOptions) ([]*kolide.Host, error) {
|
||||||
return hosts, nil
|
return hosts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Datastore) GenerateHostStatusStatistics(now time.Time) (online, offline, mia uint, e error) {
|
func (d *Datastore) GenerateHostStatusStatistics(now time.Time) (online, offline, mia, new uint, e error) {
|
||||||
sqlStatement := `
|
sqlStatement := `
|
||||||
SELECT (
|
SELECT (
|
||||||
SELECT count(id)
|
SELECT count(id)
|
||||||
|
|
@ -300,7 +300,12 @@ func (d *Datastore) GenerateHostStatusStatistics(now time.Time) (online, offline
|
||||||
SELECT count(id)
|
SELECT count(id)
|
||||||
FROM hosts
|
FROM hosts
|
||||||
WHERE DATE_ADD(seen_time, INTERVAL 30 MINUTE) > ?
|
WHERE DATE_ADD(seen_time, INTERVAL 30 MINUTE) > ?
|
||||||
) AS online
|
) AS online,
|
||||||
|
(
|
||||||
|
SELECT count(id)
|
||||||
|
FROM hosts
|
||||||
|
WHERE DATE_ADD(created_at, INTERVAL 1 DAY) >= ?
|
||||||
|
) AS new
|
||||||
FROM hosts
|
FROM hosts
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
`
|
`
|
||||||
|
|
@ -309,8 +314,9 @@ func (d *Datastore) GenerateHostStatusStatistics(now time.Time) (online, offline
|
||||||
MIA uint `db:"mia"`
|
MIA uint `db:"mia"`
|
||||||
Offline uint `db:"offline"`
|
Offline uint `db:"offline"`
|
||||||
Online uint `db:"online"`
|
Online uint `db:"online"`
|
||||||
|
New uint `db:"new"`
|
||||||
}{}
|
}{}
|
||||||
err := d.db.Get(&counts, sqlStatement, now, now, now, now)
|
err := d.db.Get(&counts, sqlStatement, now, now, now, now, now)
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
e = errors.Wrap(err, "generating host statistics")
|
e = errors.Wrap(err, "generating host statistics")
|
||||||
return
|
return
|
||||||
|
|
@ -319,7 +325,8 @@ func (d *Datastore) GenerateHostStatusStatistics(now time.Time) (online, offline
|
||||||
mia = counts.MIA
|
mia = counts.MIA
|
||||||
offline = counts.Offline
|
offline = counts.Offline
|
||||||
online = counts.Online
|
online = counts.Online
|
||||||
return online, offline, mia, nil
|
new = counts.New
|
||||||
|
return online, offline, mia, new, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimized network interface fetch for sets of hosts. Instead of looping
|
// Optimized network interface fetch for sets of hosts. Instead of looping
|
||||||
|
|
|
||||||
|
|
@ -9,18 +9,26 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// StatusOnline host is active
|
// StatusOnline host is active.
|
||||||
StatusOnline string = "online"
|
StatusOnline = "online"
|
||||||
// StatusOffline no communication with host for OfflineDuration
|
|
||||||
StatusOffline string = "offline"
|
// StatusOffline no communication with host for OfflineDuration.
|
||||||
// StatusMIA no communition with host for MIADuration
|
StatusOffline = "offline"
|
||||||
StatusMIA string = "mia"
|
|
||||||
|
// StatusMIA no communication with host for MIADuration.
|
||||||
|
StatusMIA = "mia"
|
||||||
|
|
||||||
|
// NewDuration if a host has been created within this time period it's
|
||||||
|
// considered new.
|
||||||
|
NewDuration = 24 * time.Hour
|
||||||
|
|
||||||
// OfflineDuration if a host hasn't been in communition for this
|
// OfflineDuration if a host hasn't been in communition for this
|
||||||
// period it is considered offline
|
// period it is considered offline.
|
||||||
OfflineDuration time.Duration = 30 * time.Minute
|
OfflineDuration = 30 * time.Minute
|
||||||
|
|
||||||
// OfflineDuration if a host hasn't been in communition for this
|
// OfflineDuration if a host hasn't been in communition for this
|
||||||
// period it is considered MIA
|
// period it is considered MIA.
|
||||||
MIADuration time.Duration = 30 * 24 * time.Hour
|
MIADuration = 30 * 24 * time.Hour
|
||||||
)
|
)
|
||||||
|
|
||||||
type HostStore interface {
|
type HostStore interface {
|
||||||
|
|
@ -32,7 +40,7 @@ type HostStore interface {
|
||||||
EnrollHost(osqueryHostId string, nodeKeySize int) (*Host, error)
|
EnrollHost(osqueryHostId string, nodeKeySize int) (*Host, error)
|
||||||
AuthenticateHost(nodeKey string) (*Host, error)
|
AuthenticateHost(nodeKey string) (*Host, error)
|
||||||
MarkHostSeen(host *Host, t time.Time) error
|
MarkHostSeen(host *Host, t time.Time) error
|
||||||
GenerateHostStatusStatistics(now time.Time) (online, offline, mia uint, err error)
|
GenerateHostStatusStatistics(now time.Time) (online, offline, mia, new uint, err error)
|
||||||
SearchHosts(query string, omit ...uint) ([]*Host, error)
|
SearchHosts(query string, omit ...uint) ([]*Host, error)
|
||||||
// DistributedQueriesForHost retrieves the distributed queries that the
|
// DistributedQueriesForHost retrieves the distributed queries that the
|
||||||
// given host should run. The result map is a mapping from campaign ID
|
// given host should run. The result map is a mapping from campaign ID
|
||||||
|
|
@ -92,6 +100,7 @@ type HostSummary struct {
|
||||||
OnlineCount uint `json:"online_count"`
|
OnlineCount uint `json:"online_count"`
|
||||||
OfflineCount uint `json:"offline_count"`
|
OfflineCount uint `json:"offline_count"`
|
||||||
MIACount uint `json:"mia_count"`
|
MIACount uint `json:"mia_count"`
|
||||||
|
NewCount uint `json:"new_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetPrimaryNetwork will determine if the PrimaryNetworkInterfaceID
|
// ResetPrimaryNetwork will determine if the PrimaryNetworkInterfaceID
|
||||||
|
|
@ -148,3 +157,12 @@ func (h *Host) Status(now time.Time) string {
|
||||||
return StatusOnline
|
return StatusOnline
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Host) IsNew(now time.Time) bool {
|
||||||
|
withDuration := h.CreatedAt.Add(NewDuration)
|
||||||
|
if withDuration.After(now) ||
|
||||||
|
withDuration.Equal(now) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,3 +61,15 @@ func TestHostStatus(t *testing.T) {
|
||||||
host.SeenTime = mockClock.Now().Add(-35 * (24 * time.Hour)) // 35 days
|
host.SeenTime = mockClock.Now().Add(-35 * (24 * time.Hour)) // 35 days
|
||||||
assert.Equal(t, StatusMIA, host.Status(mockClock.Now()))
|
assert.Equal(t, StatusMIA, host.Status(mockClock.Now()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHostIsNew(t *testing.T) {
|
||||||
|
mockClock := clock.NewMockClock()
|
||||||
|
|
||||||
|
host := Host{}
|
||||||
|
|
||||||
|
host.CreatedAt = mockClock.Now().AddDate(0, 0, -1)
|
||||||
|
assert.True(t, host.IsNew(mockClock.Now()))
|
||||||
|
|
||||||
|
host.CreatedAt = mockClock.Now().AddDate(0, 0, -2)
|
||||||
|
assert.False(t, host.IsNew(mockClock.Now()))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ func (svc service) GetHost(ctx context.Context, id uint) (*kolide.Host, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc service) GetHostSummary(ctx context.Context) (*kolide.HostSummary, error) {
|
func (svc service) GetHostSummary(ctx context.Context) (*kolide.HostSummary, error) {
|
||||||
online, offline, mia, err := svc.ds.GenerateHostStatusStatistics(svc.clock.Now())
|
online, offline, mia, new, err := svc.ds.GenerateHostStatusStatistics(svc.clock.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +22,7 @@ func (svc service) GetHostSummary(ctx context.Context) (*kolide.HostSummary, err
|
||||||
OnlineCount: online,
|
OnlineCount: online,
|
||||||
OfflineCount: offline,
|
OfflineCount: offline,
|
||||||
MIACount: mia,
|
MIACount: mia,
|
||||||
|
NewCount: new,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue