Additional statistics as described in https://github.com/fleetdm/fleet/pull/20091 : `aiFeaturesDisabled`: Whether server_settings.ai_features_disabled is set to true in the config. `maintenanceWindowsEnabled`: Whether at least one team has integrations.google_calendar.enable_calendar_events set to true `maintenanceWindowsConfigured`: Maintenance windows are considered "configured" if: configuration has value set for integrations.google_calendar[0].domain configuration has value set for integrations.google_calendar[0].api_key_json `numHostsFleetDesktopEnabled`: The number of hosts with Fleet desktop installed.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
- Added additional statistics items for AI features, maintenance window, and Fleet Desktop
|
||||
@@ -116,6 +116,10 @@ func TestMaybeSendStatistics(t *testing.T) {
|
||||
HostsEnrolledByOsqueryVersion: []fleet.HostsCountByOsqueryVersion{},
|
||||
StoredErrors: []byte(`[]`),
|
||||
Organization: "Fleet",
|
||||
AIFeaturesDisabled: true,
|
||||
MaintenanceWindowsEnabled: true,
|
||||
MaintenanceWindowsConfigured: true,
|
||||
NumHostsFleetDesktopEnabled: 1984,
|
||||
}, true, nil
|
||||
}
|
||||
recorded := false
|
||||
@@ -134,7 +138,7 @@ func TestMaybeSendStatistics(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.True(t, recorded)
|
||||
require.True(t, cleanedup)
|
||||
assert.Equal(t, `{"anonymousIdentifier":"ident","fleetVersion":"1.2.3","licenseTier":"premium","organization":"Fleet","numHostsEnrolled":999,"numUsers":99,"numSoftwareVersions":100,"numHostSoftwares":101,"numSoftwareTitles":102,"numHostSoftwareInstalledPaths":103,"numSoftwareCPEs":104,"numSoftwareCVEs":105,"numTeams":9,"numPolicies":0,"numLabels":3,"softwareInventoryEnabled":true,"vulnDetectionEnabled":true,"systemUsersEnabled":true,"hostsStatusWebHookEnabled":true,"mdmMacOsEnabled":false,"hostExpiryEnabled":false,"mdmWindowsEnabled":false,"liveQueryDisabled":false,"numWeeklyActiveUsers":111,"numWeeklyPolicyViolationDaysActual":0,"numWeeklyPolicyViolationDaysPossible":0,"hostsEnrolledByOperatingSystem":{"linux":[{"version":"1.2.3","numEnrolled":22}]},"hostsEnrolledByOrbitVersion":[],"hostsEnrolledByOsqueryVersion":[],"storedErrors":[],"numHostsNotResponding":0}`, requestBody)
|
||||
assert.Equal(t, `{"anonymousIdentifier":"ident","fleetVersion":"1.2.3","licenseTier":"premium","organization":"Fleet","numHostsEnrolled":999,"numUsers":99,"numSoftwareVersions":100,"numHostSoftwares":101,"numSoftwareTitles":102,"numHostSoftwareInstalledPaths":103,"numSoftwareCPEs":104,"numSoftwareCVEs":105,"numTeams":9,"numPolicies":0,"numLabels":3,"softwareInventoryEnabled":true,"vulnDetectionEnabled":true,"systemUsersEnabled":true,"hostsStatusWebHookEnabled":true,"mdmMacOsEnabled":false,"hostExpiryEnabled":false,"mdmWindowsEnabled":false,"liveQueryDisabled":false,"numWeeklyActiveUsers":111,"numWeeklyPolicyViolationDaysActual":0,"numWeeklyPolicyViolationDaysPossible":0,"hostsEnrolledByOperatingSystem":{"linux":[{"version":"1.2.3","numEnrolled":22}]},"hostsEnrolledByOrbitVersion":[],"hostsEnrolledByOsqueryVersion":[],"storedErrors":[],"numHostsNotResponding":0,"aiFeaturesDisabled":true,"maintenanceWindowsEnabled":true,"maintenanceWindowsConfigured":true,"numHostsFleetDesktopEnabled":1984}`, requestBody)
|
||||
}
|
||||
|
||||
func TestMaybeSendStatisticsSkipsSendingIfNotNeeded(t *testing.T) {
|
||||
|
||||
@@ -102,7 +102,11 @@ Below is the JSON payload that is sent to Fleet Device Management Inc:
|
||||
},
|
||||
...
|
||||
],
|
||||
"numHostsNotResponding": 9
|
||||
"numHostsNotResponding": 9,
|
||||
"aiFeaturesDisabled": true,
|
||||
"maintenanceWindowsEnabled": true,
|
||||
"maintenanceWindowsConfigured": true,
|
||||
"numHostsFleetDesktopEnabled": 999
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -5035,6 +5035,18 @@ func amountHostsByOsqueryVersionDB(ctx context.Context, db sqlx.QueryerContext)
|
||||
return counts, nil
|
||||
}
|
||||
|
||||
func numHostsFleetDesktopEnabledDB(ctx context.Context, db sqlx.QueryerContext) (int, error) {
|
||||
var count int
|
||||
const stmt = `
|
||||
SELECT count(*) FROM host_orbit_info WHERE desktop_version IS NOT NULL
|
||||
`
|
||||
if err := sqlx.GetContext(ctx, db, &count, stmt); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (ds *Datastore) GetMatchingHostSerials(ctx context.Context, serials []string) (map[string]*fleet.Host, error) {
|
||||
result := map[string]*fleet.Host{}
|
||||
if len(serials) == 0 {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/license"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/ptr"
|
||||
"github.com/fleetdm/fleet/v4/server/version"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/jmoiron/sqlx"
|
||||
@@ -98,6 +99,10 @@ func (ds *Datastore) ShouldSendStatistics(ctx context.Context, frequency time.Du
|
||||
if err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "amount hosts by osquery version")
|
||||
}
|
||||
numHostsFleetDesktopEnabled, err := numHostsFleetDesktopEnabledDB(ctx, ds.reader(ctx))
|
||||
if err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "number of hosts with Fleet desktop installed")
|
||||
}
|
||||
|
||||
stats.NumHostsEnrolled = amountEnrolledHosts
|
||||
stats.NumUsers = amountUsers
|
||||
@@ -130,6 +135,23 @@ func (ds *Datastore) ShouldSendStatistics(ctx context.Context, frequency time.Du
|
||||
if lic != nil && lic.IsPremium() {
|
||||
stats.Organization = lic.Organization
|
||||
}
|
||||
stats.AIFeaturesDisabled = appConfig.ServerSettings.AIFeaturesDisabled
|
||||
stats.MaintenanceWindowsConfigured = len(appConfig.Integrations.GoogleCalendar) > 0 && appConfig.Integrations.GoogleCalendar[0].Domain != "" && len(appConfig.Integrations.GoogleCalendar[0].ApiKey) > 0
|
||||
|
||||
stats.MaintenanceWindowsEnabled = false
|
||||
teams, err := ds.ListTeams(ctx, fleet.TeamFilter{User: &fleet.User{
|
||||
GlobalRole: ptr.String(fleet.RoleAdmin),
|
||||
}}, fleet.ListOptions{})
|
||||
if err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "list teams")
|
||||
}
|
||||
for _, team := range teams {
|
||||
if team.Config.Integrations.GoogleCalendar != nil && team.Config.Integrations.GoogleCalendar.Enable {
|
||||
stats.MaintenanceWindowsEnabled = true
|
||||
break
|
||||
}
|
||||
}
|
||||
stats.NumHostsFleetDesktopEnabled = numHostsFleetDesktopEnabled
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,10 @@ func testStatisticsShouldSend(t *testing.T, ds *Datastore) {
|
||||
assert.Equal(t, false, stats.HostExpiryEnabled)
|
||||
assert.Equal(t, false, stats.MDMWindowsEnabled)
|
||||
assert.Equal(t, false, stats.LiveQueryDisabled)
|
||||
assert.Equal(t, false, stats.AIFeaturesDisabled)
|
||||
assert.Equal(t, false, stats.MaintenanceWindowsEnabled)
|
||||
assert.Equal(t, false, stats.MaintenanceWindowsConfigured)
|
||||
assert.Equal(t, 0, stats.NumHostsFleetDesktopEnabled)
|
||||
|
||||
firstIdentifier := stats.AnonymousIdentifier
|
||||
|
||||
@@ -227,6 +231,10 @@ func testStatisticsShouldSend(t *testing.T, ds *Datastore) {
|
||||
assert.Equal(t, `[{"count":10,"loc":["a","b","c"]}]`, string(stats.StoredErrors))
|
||||
assert.Equal(t, []fleet.HostsCountByOsqueryVersion{{OsqueryVersion: "4.9.0", NumHosts: 1}}, stats.HostsEnrolledByOsqueryVersion)
|
||||
assert.Equal(t, []fleet.HostsCountByOrbitVersion{{OrbitVersion: "1.1.0", NumHosts: 1}}, stats.HostsEnrolledByOrbitVersion)
|
||||
assert.Equal(t, false, stats.AIFeaturesDisabled)
|
||||
assert.Equal(t, false, stats.MaintenanceWindowsEnabled)
|
||||
assert.Equal(t, false, stats.MaintenanceWindowsConfigured)
|
||||
assert.Equal(t, 1, stats.NumHostsFleetDesktopEnabled)
|
||||
|
||||
err = ds.RecordStatisticsSent(ctx)
|
||||
require.NoError(t, err)
|
||||
@@ -332,6 +340,10 @@ func testStatisticsShouldSend(t *testing.T, ds *Datastore) {
|
||||
{Version: "", NumEnrolled: 1},
|
||||
}, stats.HostsEnrolledByOperatingSystem[""])
|
||||
assert.Equal(t, `[{"count":10,"loc":["a","b","c"]}]`, string(stats.StoredErrors))
|
||||
assert.Equal(t, false, stats.AIFeaturesDisabled)
|
||||
assert.Equal(t, false, stats.MaintenanceWindowsEnabled)
|
||||
assert.Equal(t, false, stats.MaintenanceWindowsConfigured)
|
||||
assert.Equal(t, 1, stats.NumHostsFleetDesktopEnabled)
|
||||
|
||||
// Create multiple new sessions for a single user
|
||||
_, err = ds.NewSession(ctx, u1.ID, "session_key2")
|
||||
@@ -366,6 +378,10 @@ func testStatisticsShouldSend(t *testing.T, ds *Datastore) {
|
||||
assert.Equal(t, 0, stats.NumWeeklyPolicyViolationDaysActual)
|
||||
assert.Equal(t, 0, stats.NumWeeklyPolicyViolationDaysPossible)
|
||||
assert.Equal(t, `[{"count":10,"loc":["a","b","c"]}]`, string(stats.StoredErrors))
|
||||
assert.Equal(t, false, stats.AIFeaturesDisabled)
|
||||
assert.Equal(t, false, stats.MaintenanceWindowsEnabled)
|
||||
assert.Equal(t, false, stats.MaintenanceWindowsConfigured)
|
||||
assert.Equal(t, 1, stats.NumHostsFleetDesktopEnabled)
|
||||
|
||||
// Add host to test hosts not responding stats
|
||||
_, err = ds.NewHost(ctx, &fleet.Host{
|
||||
|
||||
@@ -47,6 +47,16 @@ type StatisticsPayload struct {
|
||||
StoredErrors json.RawMessage `json:"storedErrors"`
|
||||
// NumHostsNotResponding is a count of hosts that connect to Fleet successfully but fail to submit results for distributed queries.
|
||||
NumHostsNotResponding int `json:"numHostsNotResponding"`
|
||||
// Whether server_settings.ai_features_disabled is set to true in the config.
|
||||
AIFeaturesDisabled bool `json:"aiFeaturesDisabled"`
|
||||
// Whether at least one team has integrations.google_calendar.enable_calendar_events set to true
|
||||
MaintenanceWindowsEnabled bool `json:"maintenanceWindowsEnabled"`
|
||||
// Maintenance windows are considered "configured" if:
|
||||
// configuration has value set for integrations.google_calendar[0].domain
|
||||
// configuration has value set for integrations.google_calendar[0].api_key_json
|
||||
MaintenanceWindowsConfigured bool `json:"maintenanceWindowsConfigured"`
|
||||
// The number of hosts with Fleet desktop installed.
|
||||
NumHostsFleetDesktopEnabled int `json:"numHostsFleetDesktopEnabled"`
|
||||
}
|
||||
|
||||
type HostsCountByOrbitVersion struct {
|
||||
|
||||
Reference in New Issue
Block a user