diff --git a/changes/issue-744-ignore-nonexistent-labels b/changes/issue-744-ignore-nonexistent-labels new file mode 100644 index 0000000000..150105dfa3 --- /dev/null +++ b/changes/issue-744-ignore-nonexistent-labels @@ -0,0 +1 @@ +* When a label is removed, ignore label query executions for that label. diff --git a/server/datastore/mysql/labels.go b/server/datastore/mysql/labels.go index 04f9292044..66587bb6d1 100644 --- a/server/datastore/mysql/labels.go +++ b/server/datastore/mysql/labels.go @@ -361,7 +361,7 @@ func (d *Datastore) RecordLabelQueryExecutions(host *fleet.Host, results map[uin // Complete inserts if necessary if len(vals) > 0 { sql := ` - INSERT INTO label_membership (updated_at, label_id, host_id) VALUES + INSERT IGNORE INTO label_membership (updated_at, label_id, host_id) VALUES ` sql += strings.Join(bindvars, ",") + ` diff --git a/server/datastore/mysql/labels_test.go b/server/datastore/mysql/labels_test.go index 71b1981ca4..f2af343c6e 100644 --- a/server/datastore/mysql/labels_test.go +++ b/server/datastore/mysql/labels_test.go @@ -65,21 +65,21 @@ func TestLabels(t *testing.T) { newLabels := []*fleet.LabelSpec{ // Note these are intentionally out of order - &fleet.LabelSpec{ + { Name: "label3", Query: "query3", Platform: "darwin", }, - &fleet.LabelSpec{ + { Name: "label1", Query: "query1", }, - &fleet.LabelSpec{ + { Name: "label2", Query: "query2", Platform: "darwin", }, - &fleet.LabelSpec{ + { Name: "label4", Query: "query4", Platform: "darwin", @@ -129,7 +129,7 @@ func TestLabels(t *testing.T) { // A new label targeting another platform should not effect the labels for // this host err = db.ApplyLabelSpecs([]*fleet.LabelSpec{ - &fleet.LabelSpec{ + { Name: "label5", Platform: "not-matching", Query: "query5", @@ -142,7 +142,7 @@ func TestLabels(t *testing.T) { // If a new label is added, all labels should be returned err = db.ApplyLabelSpecs([]*fleet.LabelSpec{ - &fleet.LabelSpec{ + { Name: "label6", Platform: "", Query: "query6", @@ -677,3 +677,29 @@ func TestLabelQueriesForCentOSHost(t *testing.T) { require.Len(t, queries, 1) assert.Equal(t, "select 1;", queries[fmt.Sprint(label.ID)]) } + +func TestRecordNonexistentQueryLabelExecution(t *testing.T) { + db := CreateMySQLDS(t) + defer db.Close() + + h1, err := db.NewHost(&fleet.Host{ + DetailUpdatedAt: time.Now(), + LabelUpdatedAt: time.Now(), + SeenTime: time.Now(), + OsqueryHostID: "1", + NodeKey: "1", + UUID: "1", + Hostname: "foo.local", + }) + require.Nil(t, err) + + l1 := &fleet.LabelSpec{ + ID: 1, + Name: "label foo", + Query: "query1", + } + err = db.ApplyLabelSpecs([]*fleet.LabelSpec{l1}) + require.Nil(t, err) + + require.NoError(t, db.RecordLabelQueryExecutions(h1, map[uint]*bool{99999: ptr.Bool(true)}, time.Now())) +}