mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 00:49:03 +00:00
**Related issue:** Fixes #33807 Adds missing host platform key to mdm enrolled and mdm unenrolled activity details api response data. This allows the UI to display the activities properly - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually
102 lines
3.4 KiB
Go
102 lines
3.4 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
kitlog "github.com/go-kit/log"
|
|
"github.com/go-kit/log/level"
|
|
"google.golang.org/api/googleapi"
|
|
)
|
|
|
|
// ReconcileAndroidDevices polls AMAPI for devices that Fleet still considers enrolled
|
|
// and flips them to unenrolled if Google reports them missing (404).
|
|
// This complements (does not replace) Pub/Sub DELETED handling.
|
|
func ReconcileAndroidDevices(ctx context.Context, ds fleet.Datastore, logger kitlog.Logger, licenseKey string) error {
|
|
appConfig, err := ds.AppConfig(ctx)
|
|
if err != nil {
|
|
return ctxerr.Wrap(ctx, err, "get app config")
|
|
}
|
|
if !appConfig.MDM.AndroidEnabledAndConfigured {
|
|
return nil
|
|
}
|
|
|
|
// Ensure an enterprise exists, otherwise nothing to do, and keep its ID to build device resource names.
|
|
enterprise, err := ds.GetEnterprise(ctx)
|
|
if err != nil {
|
|
return ctxerr.Wrap(ctx, err, "get android enterprise")
|
|
}
|
|
|
|
client := newAMAPIClient(ctx, logger, licenseKey)
|
|
|
|
// Best-effort set authentication secret for proxy client usage (no-op for Google client).
|
|
if assets, err := ds.GetAllMDMConfigAssetsByName(ctx, []fleet.MDMAssetName{fleet.MDMAssetAndroidFleetServerSecret}, nil); err == nil {
|
|
if asset, ok := assets[fleet.MDMAssetAndroidFleetServerSecret]; ok && len(asset.Value) > 0 {
|
|
_ = client.SetAuthenticationSecret(string(asset.Value))
|
|
}
|
|
}
|
|
|
|
devices, err := ds.ListAndroidEnrolledDevicesForReconcile(ctx)
|
|
if err != nil {
|
|
return ctxerr.Wrap(ctx, err, "list enrolled android devices for reconcile")
|
|
}
|
|
if len(devices) == 0 {
|
|
return nil
|
|
}
|
|
|
|
checked := 0
|
|
unenrolled := 0
|
|
for _, dev := range devices {
|
|
if dev == nil || dev.DeviceID == "" {
|
|
continue
|
|
}
|
|
checked++
|
|
deviceName := fmt.Sprintf("%s/devices/%s", enterprise.Name(), dev.DeviceID)
|
|
_, err := client.EnterprisesDevicesGet(ctx, deviceName)
|
|
switch {
|
|
case err == nil:
|
|
// Device exists, no-op.
|
|
continue
|
|
case isNotFound(err):
|
|
if derr := ds.SetAndroidHostUnenrolled(ctx, dev.HostID); derr != nil {
|
|
level.Error(logger).Log("msg", "failed to mark android host unenrolled during reconcile", "host_id", dev.HostID, "err", derr)
|
|
continue
|
|
}
|
|
// Emit system activity to mirror Pub/Sub DELETED handling.
|
|
var displayName, serial, platform string
|
|
if hosts, herr := ds.ListHostsLiteByIDs(ctx, []uint{dev.HostID}); herr == nil && len(hosts) == 1 && hosts[0] != nil {
|
|
displayName = hosts[0].DisplayName()
|
|
serial = hosts[0].HardwareSerial
|
|
platform = hosts[0].Platform
|
|
}
|
|
if aerr := ds.NewActivity(ctx, nil, fleet.ActivityTypeMDMUnenrolled{
|
|
HostSerial: serial,
|
|
HostDisplayName: displayName,
|
|
InstalledFromDEP: false,
|
|
Platform: platform,
|
|
}, nil, time.Now()); aerr != nil {
|
|
level.Debug(logger).Log("msg", "failed to create mdm_unenrolled activity during android reconcile", "host_id", dev.HostID, "err", aerr)
|
|
}
|
|
unenrolled++
|
|
level.Debug(logger).Log("msg", "android device missing in Google; marked unenrolled", "host_id", dev.HostID, "device", deviceName)
|
|
default:
|
|
level.Debug(logger).Log("msg", "error reconciling android device", "device", deviceName, "err", err)
|
|
}
|
|
}
|
|
|
|
level.Debug(logger).Log("msg", "android reconcile complete", "checked", checked, "unenrolled", unenrolled)
|
|
return nil
|
|
}
|
|
|
|
func isNotFound(err error) bool {
|
|
var ge *googleapi.Error
|
|
if errors.As(err, &ge) {
|
|
return ge.Code == http.StatusNotFound
|
|
}
|
|
return false
|
|
}
|