Update new sched query stats if there's already some (#1918)
* Update new sched query stats if there's already some * IGNORE if the sched query is not present * Make tests less flaky
This commit is contained in:
@@ -0,0 +1 @@
|
||||
* Properly record scheduled query statistics after the first recording.
|
||||
@@ -209,7 +209,18 @@ func (d *Datastore) saveHostPackStats(host *fleet.Host) error {
|
||||
user_time,
|
||||
wall_time
|
||||
)
|
||||
VALUES %s
|
||||
VALUES %s ON DUPLICATE KEY UPDATE
|
||||
scheduled_query_id = VALUES(scheduled_query_id),
|
||||
host_id = VALUES(host_id),
|
||||
average_memory = VALUES(average_memory),
|
||||
denylisted = VALUES(denylisted),
|
||||
executions = VALUES(executions),
|
||||
schedule_interval = VALUES(schedule_interval),
|
||||
last_executed = VALUES(last_executed),
|
||||
output_size = VALUES(output_size),
|
||||
system_time = VALUES(system_time),
|
||||
user_time = VALUES(user_time),
|
||||
wall_time = VALUES(wall_time)
|
||||
`, values)
|
||||
if _, err := tx.Exec(sql, args...); err != nil {
|
||||
return errors.Wrap(err, "insert pack stats")
|
||||
|
||||
@@ -249,6 +249,152 @@ func TestSaveHostPackStats(t *testing.T) {
|
||||
require.Len(t, host.PackStats, 2)
|
||||
}
|
||||
|
||||
func TestSaveHostPackStatsOverwrites(t *testing.T) {
|
||||
ds := CreateMySQLDS(t)
|
||||
defer ds.Close()
|
||||
|
||||
host, err := ds.NewHost(&fleet.Host{
|
||||
DetailUpdatedAt: time.Now(),
|
||||
LabelUpdatedAt: time.Now(),
|
||||
SeenTime: time.Now(),
|
||||
NodeKey: "1",
|
||||
UUID: "1",
|
||||
Hostname: "foo.local",
|
||||
PrimaryIP: "192.168.1.1",
|
||||
PrimaryMac: "30-65-EC-6F-C4-58",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, host)
|
||||
|
||||
// Pack and query must exist for stats to save successfully
|
||||
pack1 := test.NewPack(t, ds, "test1")
|
||||
query1 := test.NewQuery(t, ds, "time", "select * from time", 0, true)
|
||||
squery1 := test.NewScheduledQuery(t, ds, pack1.ID, query1.ID, 30, true, true, "time-scheduled")
|
||||
pack2 := test.NewPack(t, ds, "test2")
|
||||
squery2 := test.NewScheduledQuery(t, ds, pack2.ID, query1.ID, 30, true, true, "time-scheduled")
|
||||
query2 := test.NewQuery(t, ds, "processes", "select * from processes", 0, true)
|
||||
|
||||
execTime1 := time.Unix(1620325191, 0).UTC()
|
||||
|
||||
host.PackStats = []fleet.PackStats{
|
||||
{
|
||||
PackName: "test1",
|
||||
QueryStats: []fleet.ScheduledQueryStats{
|
||||
{
|
||||
ScheduledQueryName: squery1.Name,
|
||||
ScheduledQueryID: squery1.ID,
|
||||
QueryName: query1.Name,
|
||||
PackName: pack1.Name,
|
||||
PackID: pack1.ID,
|
||||
AverageMemory: 8000,
|
||||
Denylisted: false,
|
||||
Executions: 164,
|
||||
Interval: 30,
|
||||
LastExecuted: execTime1,
|
||||
OutputSize: 1337,
|
||||
SystemTime: 150,
|
||||
UserTime: 180,
|
||||
WallTime: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
PackName: "test2",
|
||||
QueryStats: []fleet.ScheduledQueryStats{
|
||||
{
|
||||
ScheduledQueryName: squery2.Name,
|
||||
ScheduledQueryID: squery2.ID,
|
||||
QueryName: query2.Name,
|
||||
PackName: pack2.Name,
|
||||
PackID: pack2.ID,
|
||||
AverageMemory: 431,
|
||||
Denylisted: true,
|
||||
Executions: 1,
|
||||
Interval: 30,
|
||||
LastExecuted: execTime1,
|
||||
OutputSize: 134,
|
||||
SystemTime: 1656,
|
||||
UserTime: 18453,
|
||||
WallTime: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
require.NoError(t, ds.SaveHost(host))
|
||||
|
||||
host, err = ds.Host(host.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
sort.Slice(host.PackStats, func(i, j int) bool {
|
||||
return host.PackStats[i].PackName < host.PackStats[j].PackName
|
||||
})
|
||||
|
||||
require.Len(t, host.PackStats, 2)
|
||||
assert.Equal(t, host.PackStats[0].PackName, "test1")
|
||||
assert.Equal(t, execTime1, host.PackStats[0].QueryStats[0].LastExecuted)
|
||||
|
||||
execTime2 := execTime1.Add(24 * time.Hour)
|
||||
|
||||
host.PackStats = []fleet.PackStats{
|
||||
{
|
||||
PackName: "test1",
|
||||
QueryStats: []fleet.ScheduledQueryStats{
|
||||
{
|
||||
ScheduledQueryName: squery1.Name,
|
||||
ScheduledQueryID: squery1.ID,
|
||||
QueryName: query1.Name,
|
||||
PackName: pack1.Name,
|
||||
PackID: pack1.ID,
|
||||
AverageMemory: 8000,
|
||||
Denylisted: false,
|
||||
Executions: 164,
|
||||
Interval: 30,
|
||||
LastExecuted: execTime2,
|
||||
OutputSize: 1337,
|
||||
SystemTime: 150,
|
||||
UserTime: 180,
|
||||
WallTime: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
PackName: "test2",
|
||||
QueryStats: []fleet.ScheduledQueryStats{
|
||||
{
|
||||
ScheduledQueryName: squery2.Name,
|
||||
ScheduledQueryID: squery2.ID,
|
||||
QueryName: query2.Name,
|
||||
PackName: pack2.Name,
|
||||
PackID: pack2.ID,
|
||||
AverageMemory: 431,
|
||||
Denylisted: true,
|
||||
Executions: 1,
|
||||
Interval: 30,
|
||||
LastExecuted: execTime1,
|
||||
OutputSize: 134,
|
||||
SystemTime: 1656,
|
||||
UserTime: 18453,
|
||||
WallTime: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
require.NoError(t, ds.SaveHost(host))
|
||||
|
||||
gotHost, err := ds.Host(host.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
sort.Slice(gotHost.PackStats, func(i, j int) bool {
|
||||
return gotHost.PackStats[i].PackName < gotHost.PackStats[j].PackName
|
||||
})
|
||||
|
||||
require.Len(t, gotHost.PackStats, 2)
|
||||
assert.Equal(t, gotHost.PackStats[0].PackName, "test1")
|
||||
assert.Equal(t, execTime2, gotHost.PackStats[0].QueryStats[0].LastExecuted)
|
||||
}
|
||||
|
||||
func TestIgnoresTeamPackStats(t *testing.T) {
|
||||
ds := CreateMySQLDS(t)
|
||||
defer ds.Close()
|
||||
|
||||
@@ -3,6 +3,7 @@ package mysql
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -310,6 +311,7 @@ func TestLoadSupportsTonsOfCVEs(t *testing.T) {
|
||||
require.NoError(t, ds.SaveHostSoftware(host))
|
||||
require.NoError(t, ds.LoadHostSoftware(host))
|
||||
|
||||
sort.Slice(host.Software, func(i, j int) bool { return host.Software[i].Name < host.Software[j].Name })
|
||||
require.NoError(t, ds.AddCPEForSoftware(host.Software[0], "somecpe"))
|
||||
require.NoError(t, ds.AddCPEForSoftware(host.Software[1], "someothercpewithoutvulns"))
|
||||
for i := 0; i < 1000; i++ {
|
||||
@@ -324,7 +326,7 @@ func TestLoadSupportsTonsOfCVEs(t *testing.T) {
|
||||
|
||||
for _, software := range host.Software {
|
||||
switch software.Name {
|
||||
case "foo":
|
||||
case "bar":
|
||||
assert.Equal(t, "somecpe", software.GenerateCPE)
|
||||
require.Len(t, software.Vulnerabilities, 1000)
|
||||
assert.True(t, strings.HasPrefix(software.Vulnerabilities[0].CVE, "cve-"))
|
||||
@@ -332,10 +334,10 @@ func TestLoadSupportsTonsOfCVEs(t *testing.T) {
|
||||
"https://nvd.nist.gov/vuln/detail/"+software.Vulnerabilities[0].CVE,
|
||||
software.Vulnerabilities[0].DetailsLink,
|
||||
)
|
||||
case "bar":
|
||||
case "blah":
|
||||
assert.Len(t, software.Vulnerabilities, 0)
|
||||
assert.Equal(t, "someothercpewithoutvulns", software.GenerateCPE)
|
||||
case "blah":
|
||||
case "foo":
|
||||
assert.Len(t, software.Vulnerabilities, 0)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user