Aggregate munki and mdm data (#3886)
* Aggregate munki and mdm data * Update doc * Use reader to read * Reader to read * Address review comments
This commit is contained in:
@@ -1256,6 +1256,142 @@ func (d *Datastore) GetMDM(ctx context.Context, hostID uint) (bool, string, bool
|
||||
}
|
||||
return dest.Enrolled, dest.ServerURL, dest.InstalledFromDep, nil
|
||||
}
|
||||
func (d *Datastore) AggregatedMunkiVersion(ctx context.Context, teamID *uint) ([]fleet.AggregatedMunkiVersion, error) {
|
||||
id := uint(0)
|
||||
|
||||
if teamID != nil {
|
||||
id = *teamID
|
||||
}
|
||||
var versions []fleet.AggregatedMunkiVersion
|
||||
var versionsJson []byte
|
||||
err := sqlx.GetContext(ctx, d.reader, &versionsJson, `select json_value from aggregated_stats where id=? and type='munki_versions'`, id)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
// not having stats is not an error
|
||||
return nil, nil
|
||||
}
|
||||
return nil, ctxerr.Wrap(ctx, err, "selecting munki versions")
|
||||
}
|
||||
if err := json.Unmarshal(versionsJson, &versions); err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, "unmarshaling munki versions")
|
||||
}
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
func (d *Datastore) AggregatedMDMStatus(ctx context.Context, teamID *uint) (fleet.AggregatedMDMStatus, error) {
|
||||
id := uint(0)
|
||||
|
||||
if teamID != nil {
|
||||
id = *teamID
|
||||
}
|
||||
|
||||
var status fleet.AggregatedMDMStatus
|
||||
var statusJson []byte
|
||||
err := sqlx.GetContext(ctx, d.reader, &statusJson, `select json_value from aggregated_stats where id=? and type='mdm_status'`, id)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
// not having stats is not an error
|
||||
return fleet.AggregatedMDMStatus{}, nil
|
||||
}
|
||||
return fleet.AggregatedMDMStatus{}, ctxerr.Wrap(ctx, err, "selecting mdm status")
|
||||
}
|
||||
if err := json.Unmarshal(statusJson, &status); err != nil {
|
||||
return fleet.AggregatedMDMStatus{}, ctxerr.Wrap(ctx, err, "unmarshaling mdm status")
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
||||
func (d *Datastore) GenerateAggregatedMunkiAndMDM(ctx context.Context) error {
|
||||
var ids []uint
|
||||
if err := sqlx.SelectContext(ctx, d.reader, &ids, `SELECT id FROM teams`); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "list teams")
|
||||
}
|
||||
|
||||
for _, id := range ids {
|
||||
if err := d.generateAggregatedMunkiVersion(ctx, &id); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "generating aggregated munki version")
|
||||
}
|
||||
if err := d.generateAggregatedMDMStatus(ctx, &id); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "generating aggregated mdm status")
|
||||
}
|
||||
}
|
||||
|
||||
if err := d.generateAggregatedMunkiVersion(ctx, nil); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "generating aggregated munki version")
|
||||
}
|
||||
if err := d.generateAggregatedMDMStatus(ctx, nil); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "generating aggregated mdm status")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Datastore) generateAggregatedMunkiVersion(ctx context.Context, teamID *uint) error {
|
||||
id := uint(0)
|
||||
|
||||
var versions []fleet.AggregatedMunkiVersion
|
||||
query := `SELECT count(*) as hosts_count, hm.version FROM host_munki_info hm`
|
||||
args := []interface{}{}
|
||||
if teamID != nil {
|
||||
args = append(args, *teamID)
|
||||
query += ` JOIN hosts h ON (h.id=hm.host_id) WHERE h.team_id=?`
|
||||
id = *teamID
|
||||
}
|
||||
query += ` GROUP BY hm.version`
|
||||
err := sqlx.SelectContext(ctx, d.reader, &versions, query, args...)
|
||||
if err != nil {
|
||||
return ctxerr.Wrapf(ctx, err, "getting aggregated data from host_munki")
|
||||
}
|
||||
versionsJson, err := json.Marshal(versions)
|
||||
if err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "marshaling stats")
|
||||
}
|
||||
|
||||
_, err = d.writer.ExecContext(ctx,
|
||||
`INSERT INTO aggregated_stats(id, type, json_value) VALUES(?, ?, ?) ON DUPLICATE KEY UPDATE json_value=VALUES(json_value)`,
|
||||
id, "munki_versions", versionsJson,
|
||||
)
|
||||
if err != nil {
|
||||
return ctxerr.Wrapf(ctx, err, "inserting stats for munki_versions id %d", id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Datastore) generateAggregatedMDMStatus(ctx context.Context, teamID *uint) error {
|
||||
id := uint(0)
|
||||
|
||||
var status fleet.AggregatedMDMStatus
|
||||
query := `SELECT
|
||||
COUNT(DISTINCT host_id) as hosts_count,
|
||||
COALESCE(SUM(CASE WHEN NOT enrolled THEN 1 ELSE 0 END), 0) as unenrolled_hosts_count,
|
||||
COALESCE(SUM(CASE WHEN enrolled AND installed_from_dep THEN 1 ELSE 0 END), 0) as enrolled_automated_hosts_count,
|
||||
COALESCE(SUM(CASE WHEN enrolled AND NOT installed_from_dep THEN 1 ELSE 0 END), 0) as enrolled_manual_hosts_count
|
||||
FROM host_mdm hm
|
||||
`
|
||||
args := []interface{}{}
|
||||
if teamID != nil {
|
||||
args = append(args, *teamID)
|
||||
query += ` JOIN hosts h ON (h.id=hm.host_id) WHERE h.team_id=?`
|
||||
id = *teamID
|
||||
}
|
||||
err := sqlx.GetContext(ctx, d.reader, &status, query, args...)
|
||||
if err != nil {
|
||||
return ctxerr.Wrapf(ctx, err, "getting aggregated data from host_mdm")
|
||||
}
|
||||
|
||||
statusJson, err := json.Marshal(status)
|
||||
if err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "marshaling stats")
|
||||
}
|
||||
|
||||
_, err = d.writer.ExecContext(ctx,
|
||||
`INSERT INTO aggregated_stats(id, type, json_value) VALUES(?, ?, ?) ON DUPLICATE KEY UPDATE json_value=VALUES(json_value)`,
|
||||
id, "mdm_status", statusJson,
|
||||
)
|
||||
if err != nil {
|
||||
return ctxerr.Wrapf(ctx, err, "inserting stats for mdm_status id %d", id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HostLite will load the primary data of the host with the given id.
|
||||
// We define "primary data" as all host information except the
|
||||
|
||||
@@ -106,6 +106,7 @@ func TestHosts(t *testing.T) {
|
||||
{"ListHostDeviceMapping", testHostsListHostDeviceMapping},
|
||||
{"ReplaceHostDeviceMapping", testHostsReplaceHostDeviceMapping},
|
||||
{"HostMDMAndMunki", testHostMDMAndMunki},
|
||||
{"AggregatedHostMDMAndMunki", testAggregatedHostMDMAndMunki},
|
||||
{"HostLite", testHostsLite},
|
||||
{"UpdateOsqueryIntervals", testUpdateOsqueryIntervals},
|
||||
{"UpdateRefetchRequested", testUpdateRefetchRequested},
|
||||
@@ -3334,6 +3335,105 @@ func testHostMDMAndMunki(t *testing.T, ds *Datastore) {
|
||||
assert.True(t, installedFromDep)
|
||||
}
|
||||
|
||||
func testAggregatedHostMDMAndMunki(t *testing.T, ds *Datastore) {
|
||||
// Make sure things work before data is generated
|
||||
versions, err := ds.AggregatedMunkiVersion(context.Background(), nil)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, versions, 0)
|
||||
status, err := ds.AggregatedMDMStatus(context.Background(), nil)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, status)
|
||||
|
||||
// Make sure generation works when there's no mdm or munki data
|
||||
require.NoError(t, ds.GenerateAggregatedMunkiAndMDM(context.Background()))
|
||||
|
||||
// And after generating without any data, it all looks reasonable
|
||||
versions, err = ds.AggregatedMunkiVersion(context.Background(), nil)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, versions, 0)
|
||||
status, err = ds.AggregatedMDMStatus(context.Background(), nil)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, status)
|
||||
|
||||
// So now we try with data
|
||||
require.NoError(t, ds.SetOrUpdateMunkiVersion(context.Background(), 123, "1.2.3"))
|
||||
require.NoError(t, ds.SetOrUpdateMunkiVersion(context.Background(), 999, "9.0"))
|
||||
require.NoError(t, ds.SetOrUpdateMunkiVersion(context.Background(), 342, "1.2.3"))
|
||||
|
||||
require.NoError(t, ds.GenerateAggregatedMunkiAndMDM(context.Background()))
|
||||
|
||||
versions, err = ds.AggregatedMunkiVersion(context.Background(), nil)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, versions, 2)
|
||||
assert.ElementsMatch(t, versions, []fleet.AggregatedMunkiVersion{
|
||||
{
|
||||
HostMunkiInfo: fleet.HostMunkiInfo{Version: "1.2.3"},
|
||||
HostsCount: 2,
|
||||
},
|
||||
{
|
||||
HostMunkiInfo: fleet.HostMunkiInfo{Version: "9.0"},
|
||||
HostsCount: 1,
|
||||
},
|
||||
})
|
||||
|
||||
require.NoError(t, ds.SetOrUpdateMDMData(context.Background(), 432, true, "url", false))
|
||||
require.NoError(t, ds.SetOrUpdateMDMData(context.Background(), 123, true, "url", false))
|
||||
require.NoError(t, ds.SetOrUpdateMDMData(context.Background(), 124, true, "url", false))
|
||||
require.NoError(t, ds.SetOrUpdateMDMData(context.Background(), 455, true, "url2", true))
|
||||
require.NoError(t, ds.SetOrUpdateMDMData(context.Background(), 999, false, "url3", true))
|
||||
require.NoError(t, ds.SetOrUpdateMDMData(context.Background(), 875, false, "url3", true))
|
||||
|
||||
require.NoError(t, ds.GenerateAggregatedMunkiAndMDM(context.Background()))
|
||||
|
||||
status, err = ds.AggregatedMDMStatus(context.Background(), nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 6, status.HostsCount)
|
||||
assert.Equal(t, 2, status.UnenrolledHostsCount)
|
||||
assert.Equal(t, 3, status.EnrolledManualHostsCount)
|
||||
assert.Equal(t, 1, status.EnrolledAutomatedHostsCount)
|
||||
|
||||
// Team filters
|
||||
team1, err := ds.NewTeam(context.Background(), &fleet.Team{
|
||||
Name: "team1" + t.Name(),
|
||||
Description: "desc team1",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
team2, err := ds.NewTeam(context.Background(), &fleet.Team{
|
||||
Name: "team2" + t.Name(),
|
||||
Description: "desc team2",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
h1 := test.NewHost(t, ds, "h1"+t.Name(), "192.168.1.10", "1", "1", time.Now())
|
||||
h2 := test.NewHost(t, ds, "h2"+t.Name(), "192.168.1.11", "2", "2", time.Now())
|
||||
|
||||
require.NoError(t, ds.AddHostsToTeam(context.Background(), &team1.ID, []uint{h1.ID}))
|
||||
require.NoError(t, ds.AddHostsToTeam(context.Background(), &team2.ID, []uint{h2.ID}))
|
||||
|
||||
require.NoError(t, ds.SetOrUpdateMDMData(context.Background(), h1.ID, true, "url", false))
|
||||
require.NoError(t, ds.SetOrUpdateMDMData(context.Background(), h2.ID, true, "url", false))
|
||||
require.NoError(t, ds.SetOrUpdateMunkiVersion(context.Background(), h1.ID, "1.2.3"))
|
||||
require.NoError(t, ds.SetOrUpdateMunkiVersion(context.Background(), h2.ID, "1.2.3"))
|
||||
|
||||
require.NoError(t, ds.GenerateAggregatedMunkiAndMDM(context.Background()))
|
||||
|
||||
versions, err = ds.AggregatedMunkiVersion(context.Background(), &team1.ID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, versions, 1)
|
||||
assert.ElementsMatch(t, versions, []fleet.AggregatedMunkiVersion{
|
||||
{
|
||||
HostMunkiInfo: fleet.HostMunkiInfo{Version: "1.2.3"},
|
||||
HostsCount: 1,
|
||||
},
|
||||
})
|
||||
status, err = ds.AggregatedMDMStatus(context.Background(), &team1.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, status.HostsCount)
|
||||
assert.Equal(t, 0, status.UnenrolledHostsCount)
|
||||
assert.Equal(t, 1, status.EnrolledManualHostsCount)
|
||||
assert.Equal(t, 0, status.EnrolledAutomatedHostsCount)
|
||||
}
|
||||
|
||||
func testHostsLite(t *testing.T, ds *Datastore) {
|
||||
_, err := ds.HostLite(context.Background(), 1)
|
||||
require.Error(t, err)
|
||||
|
||||
@@ -207,6 +207,10 @@ type Datastore interface {
|
||||
GetMunkiVersion(ctx context.Context, hostID uint) (string, error)
|
||||
GetMDM(ctx context.Context, hostID uint) (enrolled bool, serverURL string, installedFromDep bool, err error)
|
||||
|
||||
AggregatedMunkiVersion(ctx context.Context, teamID *uint) ([]AggregatedMunkiVersion, error)
|
||||
AggregatedMDMStatus(ctx context.Context, teamID *uint) (AggregatedMDMStatus, error)
|
||||
GenerateAggregatedMunkiAndMDM(ctx context.Context) error
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TargetStore
|
||||
|
||||
|
||||
@@ -269,3 +269,20 @@ type MacadminsData struct {
|
||||
Munki *HostMunkiInfo `json:"munki"`
|
||||
MDM *HostMDM `json:"mobile_device_management"`
|
||||
}
|
||||
|
||||
type AggregatedMunkiVersion struct {
|
||||
HostMunkiInfo
|
||||
HostsCount int `json:"hosts_count" db:"hosts_count"`
|
||||
}
|
||||
|
||||
type AggregatedMDMStatus struct {
|
||||
EnrolledManualHostsCount int `json:"enrolled_manual_hosts_count" db:"enrolled_manual_hosts_count"`
|
||||
EnrolledAutomatedHostsCount int `json:"enrolled_automated_hosts_count" db:"enrolled_automated_hosts_count"`
|
||||
UnenrolledHostsCount int `json:"unenrolled_hosts_count" db:"unenrolled_hosts_count"`
|
||||
HostsCount int `json:"hosts_count" db:"hosts_count"`
|
||||
}
|
||||
|
||||
type AggregatedMacadminsData struct {
|
||||
MunkiVersions []AggregatedMunkiVersion `json:"munki_versions"`
|
||||
MDMStatus AggregatedMDMStatus `json:"mobile_device_management_enrollment_status"`
|
||||
}
|
||||
|
||||
@@ -257,6 +257,7 @@ type Service interface {
|
||||
ListHostDeviceMapping(ctx context.Context, id uint) ([]*HostDeviceMapping, error)
|
||||
|
||||
MacadminsData(ctx context.Context, id uint) (*MacadminsData, error)
|
||||
AggregatedMacadminsData(ctx context.Context, teamID *uint) (*AggregatedMacadminsData, error)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AppConfigService provides methods for configuring the Fleet application
|
||||
|
||||
@@ -176,6 +176,12 @@ type GetMunkiVersionFunc func(ctx context.Context, hostID uint) (string, error)
|
||||
|
||||
type GetMDMFunc func(ctx context.Context, hostID uint) (enrolled bool, serverURL string, installedFromDep bool, err error)
|
||||
|
||||
type AggregatedMunkiVersionFunc func(ctx context.Context, teamID *uint) ([]fleet.AggregatedMunkiVersion, error)
|
||||
|
||||
type AggregatedMDMStatusFunc func(ctx context.Context, teamID *uint) (fleet.AggregatedMDMStatus, error)
|
||||
|
||||
type GenerateAggregatedMunkiAndMDMFunc func(ctx context.Context) error
|
||||
|
||||
type CountHostsInTargetsFunc func(ctx context.Context, filter fleet.TeamFilter, targets fleet.HostTargets, now time.Time) (fleet.TargetMetrics, error)
|
||||
|
||||
type HostIDsInTargetsFunc func(ctx context.Context, filter fleet.TeamFilter, targets fleet.HostTargets) ([]uint, error)
|
||||
@@ -609,6 +615,15 @@ type DataStore struct {
|
||||
GetMDMFunc GetMDMFunc
|
||||
GetMDMFuncInvoked bool
|
||||
|
||||
AggregatedMunkiVersionFunc AggregatedMunkiVersionFunc
|
||||
AggregatedMunkiVersionFuncInvoked bool
|
||||
|
||||
AggregatedMDMStatusFunc AggregatedMDMStatusFunc
|
||||
AggregatedMDMStatusFuncInvoked bool
|
||||
|
||||
GenerateAggregatedMunkiAndMDMFunc GenerateAggregatedMunkiAndMDMFunc
|
||||
GenerateAggregatedMunkiAndMDMFuncInvoked bool
|
||||
|
||||
CountHostsInTargetsFunc CountHostsInTargetsFunc
|
||||
CountHostsInTargetsFuncInvoked bool
|
||||
|
||||
@@ -1299,6 +1314,21 @@ func (s *DataStore) GetMDM(ctx context.Context, hostID uint) (enrolled bool, ser
|
||||
return s.GetMDMFunc(ctx, hostID)
|
||||
}
|
||||
|
||||
func (s *DataStore) AggregatedMunkiVersion(ctx context.Context, teamID *uint) ([]fleet.AggregatedMunkiVersion, error) {
|
||||
s.AggregatedMunkiVersionFuncInvoked = true
|
||||
return s.AggregatedMunkiVersionFunc(ctx, teamID)
|
||||
}
|
||||
|
||||
func (s *DataStore) AggregatedMDMStatus(ctx context.Context, teamID *uint) (fleet.AggregatedMDMStatus, error) {
|
||||
s.AggregatedMDMStatusFuncInvoked = true
|
||||
return s.AggregatedMDMStatusFunc(ctx, teamID)
|
||||
}
|
||||
|
||||
func (s *DataStore) GenerateAggregatedMunkiAndMDM(ctx context.Context) error {
|
||||
s.GenerateAggregatedMunkiAndMDMFuncInvoked = true
|
||||
return s.GenerateAggregatedMunkiAndMDMFunc(ctx)
|
||||
}
|
||||
|
||||
func (s *DataStore) CountHostsInTargets(ctx context.Context, filter fleet.TeamFilter, targets fleet.HostTargets, now time.Time) (fleet.TargetMetrics, error) {
|
||||
s.CountHostsInTargetsFuncInvoked = true
|
||||
return s.CountHostsInTargetsFunc(ctx, filter, targets, now)
|
||||
|
||||
@@ -537,6 +537,7 @@ func attachNewStyleFleetAPIRoutes(r *mux.Router, svc fleet.Service, opts []kitht
|
||||
e.GET("/api/_version_/fleet/carves/{id:[0-9]+}/block/{block_id}", getCarveBlockEndpoint, getCarveBlockRequest{})
|
||||
|
||||
e.GET("/api/_version_/fleet/hosts/{id:[0-9]+}/macadmins", getMacadminsDataEndpoint, getMacadminsDataRequest{})
|
||||
e.GET("/api/_version_/fleet/macadmins", getAggregatedMacadminsDataEndpoint, getAggregatedMacadminsDataRequest{})
|
||||
}
|
||||
|
||||
// TODO: this duplicates the one in makeKitHandler
|
||||
|
||||
@@ -750,3 +750,56 @@ func (svc *Service) MacadminsData(ctx context.Context, id uint) (*fleet.Macadmin
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Aggregated Macadmins
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type getAggregatedMacadminsDataRequest struct {
|
||||
TeamID *uint `query:"team_id,optional"`
|
||||
}
|
||||
|
||||
type getAggregatedMacadminsDataResponse struct {
|
||||
Err error `json:"error,omitempty"`
|
||||
Macadmins *fleet.AggregatedMacadminsData `json:"macadmins"`
|
||||
}
|
||||
|
||||
func (r getAggregatedMacadminsDataResponse) error() error { return r.Err }
|
||||
|
||||
func getAggregatedMacadminsDataEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) {
|
||||
req := request.(*getAggregatedMacadminsDataRequest)
|
||||
data, err := svc.AggregatedMacadminsData(ctx, req.TeamID)
|
||||
if err != nil {
|
||||
return getAggregatedMacadminsDataResponse{Err: err}, nil
|
||||
}
|
||||
return getAggregatedMacadminsDataResponse{Macadmins: data}, nil
|
||||
}
|
||||
|
||||
func (svc *Service) AggregatedMacadminsData(ctx context.Context, teamID *uint) (*fleet.AggregatedMacadminsData, error) {
|
||||
if err := svc.authz.Authorize(ctx, &fleet.Host{TeamID: teamID}, fleet.ActionList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if teamID != nil {
|
||||
_, err := svc.ds.Team(ctx, *teamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
agg := &fleet.AggregatedMacadminsData{}
|
||||
|
||||
versions, err := svc.ds.AggregatedMunkiVersion(ctx, teamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
agg.MunkiVersions = versions
|
||||
|
||||
status, err := svc.ds.AggregatedMDMStatus(ctx, teamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
agg.MDMStatus = status
|
||||
|
||||
return agg, nil
|
||||
}
|
||||
|
||||
@@ -1782,6 +1782,43 @@ func (s *integrationTestSuite) TestGetMacadminsData() {
|
||||
require.Nil(t, macadminsData.Macadmins.Munki)
|
||||
assert.Equal(t, "AAA", macadminsData.Macadmins.MDM.ServerURL)
|
||||
assert.Equal(t, "Enrolled (automated)", macadminsData.Macadmins.MDM.EnrollmentStatus)
|
||||
|
||||
// generate aggregated data
|
||||
require.NoError(t, s.ds.GenerateAggregatedMunkiAndMDM(context.Background()))
|
||||
|
||||
agg := getAggregatedMacadminsDataResponse{}
|
||||
s.DoJSON("GET", "/api/v1/fleet/macadmins", nil, http.StatusOK, &agg)
|
||||
require.NotNil(t, agg.Macadmins)
|
||||
assert.Len(t, agg.Macadmins.MunkiVersions, 2)
|
||||
assert.ElementsMatch(t, agg.Macadmins.MunkiVersions, []fleet.AggregatedMunkiVersion{
|
||||
{
|
||||
HostMunkiInfo: fleet.HostMunkiInfo{Version: "1.5.0"},
|
||||
HostsCount: 1,
|
||||
},
|
||||
{
|
||||
HostMunkiInfo: fleet.HostMunkiInfo{Version: "3.2.0"},
|
||||
HostsCount: 1,
|
||||
},
|
||||
})
|
||||
assert.Equal(t, agg.Macadmins.MDMStatus.EnrolledManualHostsCount, 0)
|
||||
assert.Equal(t, agg.Macadmins.MDMStatus.EnrolledAutomatedHostsCount, 1)
|
||||
assert.Equal(t, agg.Macadmins.MDMStatus.UnenrolledHostsCount, 1)
|
||||
assert.Equal(t, agg.Macadmins.MDMStatus.HostsCount, 2)
|
||||
|
||||
team, err := s.ds.NewTeam(context.Background(), &fleet.Team{
|
||||
Name: "team1" + t.Name(),
|
||||
Description: "desc team1",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
agg = getAggregatedMacadminsDataResponse{}
|
||||
s.DoJSON("GET", "/api/v1/fleet/macadmins", nil, http.StatusOK, &agg, "team_id", fmt.Sprint(team.ID))
|
||||
require.NotNil(t, agg.Macadmins)
|
||||
require.Empty(t, agg.Macadmins.MunkiVersions)
|
||||
require.Empty(t, agg.Macadmins.MDMStatus)
|
||||
|
||||
agg = getAggregatedMacadminsDataResponse{}
|
||||
s.DoJSON("GET", "/api/v1/fleet/macadmins", nil, http.StatusNotFound, &agg, "team_id", "9999999")
|
||||
}
|
||||
|
||||
func (s *integrationTestSuite) TestLabels() {
|
||||
|
||||
Reference in New Issue
Block a user