diff --git a/changes/17710-apple-host-mdm-timestamps b/changes/17710-apple-host-mdm-timestamps index 6dcf17c776..f83aedb567 100644 --- a/changes/17710-apple-host-mdm-timestamps +++ b/changes/17710-apple-host-mdm-timestamps @@ -1 +1 @@ -Added mdm_last_enrolled_at and mdm_last_seen_at to host detail endpoints to return the last time a host enrolled, or re-enrolled in MDM and the last time a host checked in via MDM, respectively. This data is only returned for macOS, iOS and iPadOS hosts enrolled in Fleet MDM currently, other platforms will return null. +Added last_mdm_enrolled_at and last_mdm_checked_in_at to host detail endpoints to return the last time a host enrolled, or re-enrolled in MDM and the last time a host checked in via MDM, respectively. This data is only returned for macOS, iOS and iPadOS hosts enrolled in Fleet MDM currently, other platforms will return null. diff --git a/cmd/fleetctl/fleetctl/testdata/expectedHostDetailResponseJson.json b/cmd/fleetctl/fleetctl/testdata/expectedHostDetailResponseJson.json index da55fc1c8d..7afa367ad1 100644 --- a/cmd/fleetctl/fleetctl/testdata/expectedHostDetailResponseJson.json +++ b/cmd/fleetctl/fleetctl/testdata/expectedHostDetailResponseJson.json @@ -53,8 +53,8 @@ "server_url": null, "connected_to_fleet": null }, - "mdm_last_seen_at": null, - "mdm_last_enrolled_at": null, + "last_mdm_checked_in_at": null, + "last_mdm_enrolled_at": null, "team_id": null, "pack_stats": null, "team_name": null, diff --git a/cmd/fleetctl/fleetctl/testdata/expectedHostDetailResponseYaml.yml b/cmd/fleetctl/fleetctl/testdata/expectedHostDetailResponseYaml.yml index 07751ede93..71ddab9d40 100644 --- a/cmd/fleetctl/fleetctl/testdata/expectedHostDetailResponseYaml.yml +++ b/cmd/fleetctl/fleetctl/testdata/expectedHostDetailResponseYaml.yml @@ -30,6 +30,8 @@ spec: label_updated_at: "0001-01-01T00:00:00Z" labels: [] last_enrolled_at: "0001-01-01T00:00:00Z" + last_mdm_checked_in_at: null + last_mdm_enrolled_at: null last_restarted_at: "0001-01-01T00:00:00Z" logger_tls_period: 0 mdm: @@ -41,8 +43,6 @@ spec: pending_action: "" server_url: null connected_to_fleet: null - mdm_last_enrolled_at: null - mdm_last_seen_at: null memory: 0 orbit_version: null os_version: "" diff --git a/server/fleet/hosts.go b/server/fleet/hosts.go index 8271cfb3d3..0c30ddee4d 100644 --- a/server/fleet/hosts.go +++ b/server/fleet/hosts.go @@ -775,8 +775,8 @@ type HostDetail struct { MaintenanceWindow *HostMaintenanceWindow `json:"maintenance_window,omitempty"` EndUsers []HostEndUser `json:"end_users,omitempty"` - MDMLastEnrolledAt *time.Time `json:"mdm_last_enrolled_at"` - MDMLastSeenAt *time.Time `json:"mdm_last_seen_at"` + LastMDMEnrolledAt *time.Time `json:"last_mdm_enrolled_at"` + LastMDMCheckedInAt *time.Time `json:"last_mdm_checked_in_at"` } type HostEndUser struct { diff --git a/server/service/hosts.go b/server/service/hosts.go index d7edad3b40..09bf680dc3 100644 --- a/server/service/hosts.go +++ b/server/service/hosts.go @@ -1210,7 +1210,7 @@ func (svc *Service) getHostDetails(ctx context.Context, host *fleet.Host, opts f var profiles []fleet.HostMDMProfile var mdmLastEnrollment *time.Time - var mdmLastSeen *time.Time + var mdmLastCheckedIn *time.Time if ac.MDM.EnabledAndConfigured || ac.MDM.WindowsEnabledAndConfigured { host.MDM.OSSettings = &fleet.HostMDMOSSettings{} switch host.Platform { @@ -1275,7 +1275,7 @@ func (svc *Service) getHostDetails(ctx context.Context, host *fleet.Host, opts f // fetch host last seen at and last enrolled at times, currently only supported for // Apple platforms - mdmLastEnrollment, mdmLastSeen, err = svc.ds.GetNanoMDMEnrollmentTimes(ctx, host.UUID) + mdmLastEnrollment, mdmLastCheckedIn, err = svc.ds.GetNanoMDMEnrollmentTimes(ctx, host.UUID) if err != nil { return nil, ctxerr.Wrap(ctx, err, "get host mdm enrollment times") } @@ -1335,14 +1335,14 @@ func (svc *Service) getHostDetails(ctx context.Context, host *fleet.Host, opts f } return &fleet.HostDetail{ - Host: *host, - Labels: labels, - Packs: packs, - Batteries: &bats, - MaintenanceWindow: nextMw, - EndUsers: endUsers, - MDMLastEnrolledAt: mdmLastEnrollment, - MDMLastSeenAt: mdmLastSeen, + Host: *host, + Labels: labels, + Packs: packs, + Batteries: &bats, + MaintenanceWindow: nextMw, + EndUsers: endUsers, + LastMDMEnrolledAt: mdmLastEnrollment, + LastMDMCheckedInAt: mdmLastCheckedIn, }, nil } diff --git a/server/service/hosts_test.go b/server/service/hosts_test.go index 6fd94a837f..f52210b295 100644 --- a/server/service/hosts_test.go +++ b/server/service/hosts_test.go @@ -462,14 +462,14 @@ func TestHostDetailsMDMTimestamps(t *testing.T) { require.NoError(t, err) if testcase.platformIsApple { assert.True(t, ds.GetNanoMDMEnrollmentTimesFuncInvoked) - require.NotNil(t, hostDetail.MDMLastEnrolledAt) - assert.Equal(t, *hostDetail.MDMLastEnrolledAt, ts1) - require.NotNil(t, hostDetail.MDMLastSeenAt) - assert.Equal(t, *hostDetail.MDMLastSeenAt, ts2) + require.NotNil(t, hostDetail.LastMDMEnrolledAt) + assert.Equal(t, *hostDetail.LastMDMEnrolledAt, ts1) + require.NotNil(t, hostDetail.LastMDMCheckedInAt) + assert.Equal(t, *hostDetail.LastMDMCheckedInAt, ts2) } else { assert.False(t, ds.GetNanoMDMEnrollmentTimesFuncInvoked) - assert.Nil(t, hostDetail.MDMLastEnrolledAt) - assert.Nil(t, hostDetail.MDMLastSeenAt) + assert.Nil(t, hostDetail.LastMDMEnrolledAt) + assert.Nil(t, hostDetail.LastMDMCheckedInAt) } }) } diff --git a/server/service/integration_mdm_test.go b/server/service/integration_mdm_test.go index 88495403df..997a2dd944 100644 --- a/server/service/integration_mdm_test.go +++ b/server/service/integration_mdm_test.go @@ -10839,8 +10839,8 @@ func (s *integrationMDMTestSuite) TestMDMEnrollDoesntClearLastEnrolledAtForMacOS require.NotNil(t, hostResp.Host) lastEnrolledAt := hostResp.Host.LastEnrolledAt - assert.Nil(t, hostResp.Host.MDMLastEnrolledAt) - assert.Nil(t, hostResp.Host.MDMLastSeenAt) + assert.Nil(t, hostResp.Host.LastMDMEnrolledAt) + assert.Nil(t, hostResp.Host.LastMDMCheckedInAt) // Add the following here for debug: time.Sleep(2 * time.Second) @@ -10853,10 +10853,10 @@ func (s *integrationMDMTestSuite) TestMDMEnrollDoesntClearLastEnrolledAtForMacOS s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/hosts/%d", fleetHost.ID), nil, http.StatusOK, &hostResp) require.NotNil(t, hostResp.Host) assert.Equal(t, lastEnrolledAt, hostResp.Host.LastEnrolledAt) - assert.NotNil(t, hostResp.Host.MDMLastEnrolledAt) - assert.GreaterOrEqual(t, *hostResp.Host.MDMLastEnrolledAt, enrollTime) - assert.NotNil(t, hostResp.Host.MDMLastSeenAt) - assert.GreaterOrEqual(t, *hostResp.Host.MDMLastSeenAt, enrollTime) + assert.NotNil(t, hostResp.Host.LastMDMEnrolledAt) + assert.GreaterOrEqual(t, *hostResp.Host.LastMDMEnrolledAt, enrollTime) + assert.NotNil(t, hostResp.Host.LastMDMCheckedInAt) + assert.GreaterOrEqual(t, *hostResp.Host.LastMDMCheckedInAt, enrollTime) } func (s *integrationMDMTestSuite) TestConnectedToFleetWithoutCheckout() { @@ -13408,10 +13408,10 @@ func (s *integrationMDMTestSuite) TestOTAEnrollment() { require.Equal(t, hwModel, hostByIdentifierResp.Host.HardwareModel) require.Equal(t, "darwin", hostByIdentifierResp.Host.Platform) require.Nil(t, hostByIdentifierResp.Host.TeamID) - require.NotNil(t, hostByIdentifierResp.Host.MDMLastEnrolledAt) - assert.GreaterOrEqual(t, *hostByIdentifierResp.Host.MDMLastEnrolledAt, enrollTime) - require.NotNil(t, hostByIdentifierResp.Host.MDMLastSeenAt) - assert.GreaterOrEqual(t, *hostByIdentifierResp.Host.MDMLastSeenAt, enrollTime) + require.NotNil(t, hostByIdentifierResp.Host.LastMDMEnrolledAt) + assert.GreaterOrEqual(t, *hostByIdentifierResp.Host.LastMDMEnrolledAt, enrollTime) + require.NotNil(t, hostByIdentifierResp.Host.LastMDMCheckedInAt) + assert.GreaterOrEqual(t, *hostByIdentifierResp.Host.LastMDMCheckedInAt, enrollTime) // create a team with a different enroll secret var specResp applyTeamSpecsResponse @@ -13436,10 +13436,10 @@ func (s *integrationMDMTestSuite) TestOTAEnrollment() { require.Equal(t, "ipados", hostByIdentifierResp.Host.Platform) require.NotNil(t, hostByIdentifierResp.Host.TeamID) require.Equal(t, specResp.TeamIDsByName["newteam"], *hostByIdentifierResp.Host.TeamID) - require.NotNil(t, hostByIdentifierResp.Host.MDMLastEnrolledAt) - assert.GreaterOrEqual(t, *hostByIdentifierResp.Host.MDMLastEnrolledAt, enrollTime) - require.NotNil(t, hostByIdentifierResp.Host.MDMLastSeenAt) - assert.GreaterOrEqual(t, *hostByIdentifierResp.Host.MDMLastSeenAt, enrollTime) + require.NotNil(t, hostByIdentifierResp.Host.LastMDMEnrolledAt) + assert.GreaterOrEqual(t, *hostByIdentifierResp.Host.LastMDMEnrolledAt, enrollTime) + require.NotNil(t, hostByIdentifierResp.Host.LastMDMCheckedInAt) + assert.GreaterOrEqual(t, *hostByIdentifierResp.Host.LastMDMCheckedInAt, enrollTime) } func (s *integrationMDMTestSuite) TestSCEPProxy() {