diff --git a/changes/issue-3591-fix-usage-stats b/changes/issue-3591-fix-usage-stats new file mode 100644 index 000000000..c7a8ca689 --- /dev/null +++ b/changes/issue-3591-fix-usage-stats @@ -0,0 +1 @@ +* Fix anonymous usage statistics to send missing `numLabels` field \ No newline at end of file diff --git a/cmd/fleet/serve_test.go b/cmd/fleet/serve_test.go index 236d85f1d..e2251d0b7 100644 --- a/cmd/fleet/serve_test.go +++ b/cmd/fleet/serve_test.go @@ -47,6 +47,7 @@ func TestMaybeSendStatistics(t *testing.T) { NumUsers: 99, NumTeams: 9, NumPolicies: 0, + NumLabels: 3, SoftwareInventoryEnabled: true, VulnDetectionEnabled: true, SystemUsersEnabled: true, @@ -62,7 +63,7 @@ func TestMaybeSendStatistics(t *testing.T) { err := trySendStatistics(context.Background(), ds, fleet.StatisticsFrequency, ts.URL, &fleet.LicenseInfo{Tier: "premium"}) require.NoError(t, err) assert.True(t, recorded) - assert.Equal(t, `{"anonymousIdentifier":"ident","fleetVersion":"1.2.3","licenseTier":"premium","numHostsEnrolled":999,"numUsers":99,"numTeams":9,"numPolicies":0,"softwareInventoryEnabled":true,"vulnDetectionEnabled":true,"systemUsersEnabled":true,"hostsStatusWebHookEnabled":true}`, requestBody) + assert.Equal(t, `{"anonymousIdentifier":"ident","fleetVersion":"1.2.3","licenseTier":"premium","numHostsEnrolled":999,"numUsers":99,"numTeams":9,"numPolicies":0,"numLabels":3,"softwareInventoryEnabled":true,"vulnDetectionEnabled":true,"systemUsersEnabled":true,"hostsStatusWebHookEnabled":true}`, requestBody) } func TestMaybeSendStatisticsSkipsSendingIfNotNeeded(t *testing.T) { diff --git a/server/datastore/mysql/labels.go b/server/datastore/mysql/labels.go index ce645e6e0..bdbe4e878 100644 --- a/server/datastore/mysql/labels.go +++ b/server/datastore/mysql/labels.go @@ -775,3 +775,12 @@ func (d *Datastore) AsyncBatchUpdateLabelTimestamp(ctx context.Context, ids []ui return ctxerr.Wrap(ctx, err, "update hosts.label_updated_at") }) } + +func amountLabelsDB(db sqlx.Queryer) (int, error) { + var amount int + err := sqlx.Get(db, &amount, `SELECT count(*) FROM labels`) + if err != nil { + return 0, err + } + return amount, nil +} diff --git a/server/datastore/mysql/statistics.go b/server/datastore/mysql/statistics.go index 0fa0ba088..237188820 100644 --- a/server/datastore/mysql/statistics.go +++ b/server/datastore/mysql/statistics.go @@ -32,7 +32,11 @@ func (d *Datastore) ShouldSendStatistics(ctx context.Context, frequency time.Dur } amountPolicies, err := amountPoliciesDB(d.writer) if err != nil { - return fleet.StatisticsPayload{}, false, ctxerr.Wrap(ctx, err, "amount teams") + return fleet.StatisticsPayload{}, false, ctxerr.Wrap(ctx, err, "amount policies") + } + amountLabels, err := amountLabelsDB(d.writer) + if err != nil { + return fleet.StatisticsPayload{}, false, ctxerr.Wrap(ctx, err, "amount labels") } appConfig, err := d.AppConfig(ctx) if err != nil { @@ -59,6 +63,7 @@ func (d *Datastore) ShouldSendStatistics(ctx context.Context, frequency time.Dur NumUsers: amountUsers, NumTeams: amountTeams, NumPolicies: amountPolicies, + NumLabels: amountLabels, SoftwareInventoryEnabled: appConfig.HostSettings.EnableSoftwareInventory, VulnDetectionEnabled: appConfig.VulnerabilitySettings.DatabasesPath != "", SystemUsersEnabled: appConfig.HostSettings.EnableHostUsers, @@ -82,8 +87,9 @@ func (d *Datastore) ShouldSendStatistics(ctx context.Context, frequency time.Dur NumUsers: amountUsers, NumTeams: amountTeams, NumPolicies: amountPolicies, + NumLabels: amountLabels, SoftwareInventoryEnabled: appConfig.HostSettings.EnableSoftwareInventory, - VulnDetectionEnabled: &appConfig.VulnerabilitySettings.DatabasesPath != nil, + VulnDetectionEnabled: appConfig.VulnerabilitySettings.DatabasesPath != "", SystemUsersEnabled: appConfig.HostSettings.EnableHostUsers, HostsStatusWebHookEnabled: appConfig.WebhookSettings.HostStatusWebhook.Enable, }, true, nil diff --git a/server/datastore/mysql/statistics_test.go b/server/datastore/mysql/statistics_test.go index 762228927..73df9a469 100644 --- a/server/datastore/mysql/statistics_test.go +++ b/server/datastore/mysql/statistics_test.go @@ -70,6 +70,15 @@ func testStatisticsShouldSend(t *testing.T, ds *Datastore) { }) require.NoError(t, err) + // Create new label for test + _, err = ds.NewLabel(context.Background(), &fleet.Label{ + Name: "testlabel", + Query: "select 1;", + Platform: "darwin", + Description: "test label description", + }) + require.NoError(t, err) + // Create new app config for test config, err := ds.NewAppConfig(context.Background(), &fleet.AppConfig{ OrgInfo: fleet.OrgInfo{ @@ -80,7 +89,7 @@ func testStatisticsShouldSend(t *testing.T, ds *Datastore) { require.NoError(t, err) config.HostSettings.EnableSoftwareInventory = false config.HostSettings.EnableHostUsers = false - config.VulnerabilitySettings.DatabasesPath = "foo/bar" + config.VulnerabilitySettings.DatabasesPath = "" config.WebhookSettings.HostStatusWebhook.Enable = true err = ds.SaveAppConfig(context.Background(), config) @@ -99,9 +108,10 @@ func testStatisticsShouldSend(t *testing.T, ds *Datastore) { assert.Equal(t, stats.NumUsers, 1) assert.Equal(t, stats.NumTeams, 1) assert.Equal(t, stats.NumPolicies, 1) + assert.Equal(t, stats.NumLabels, 1) assert.Equal(t, stats.SoftwareInventoryEnabled, false) assert.Equal(t, stats.SystemUsersEnabled, false) - assert.Equal(t, stats.VulnDetectionEnabled, true) + assert.Equal(t, stats.VulnDetectionEnabled, false) assert.Equal(t, stats.HostsStatusWebHookEnabled, true) firstIdentifier := stats.AnonymousIdentifier diff --git a/server/fleet/statistics.go b/server/fleet/statistics.go index d8ff4d271..1bdb0e883 100644 --- a/server/fleet/statistics.go +++ b/server/fleet/statistics.go @@ -10,6 +10,7 @@ type StatisticsPayload struct { NumUsers int `json:"numUsers"` NumTeams int `json:"numTeams"` NumPolicies int `json:"numPolicies"` + NumLabels int `json:"numLabels"` SoftwareInventoryEnabled bool `json:"softwareInventoryEnabled"` VulnDetectionEnabled bool `json:"vulnDetectionEnabled"` SystemUsersEnabled bool `json:"systemUsersEnabled"`