Skip to content

Commit

Permalink
Update MDM migration flow with offline dialog (#21274)
Browse files Browse the repository at this point in the history
  • Loading branch information
gillespi314 authored Aug 13, 2024
1 parent 6664822 commit 73658dd
Show file tree
Hide file tree
Showing 7 changed files with 343 additions and 44 deletions.
90 changes: 57 additions & 33 deletions orbit/cmd/desktop/desktop.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
_ "embed"
"errors"
"fmt"
Expand Down Expand Up @@ -60,6 +61,10 @@ func setupRunners() {
}

func main() {
// FIXME: we need to do a better job of graceful shutdown, releasing resources, stopping
// tickers, etc. (https://github.com/fleetdm/fleet/issues/21256)
ctx, cancel := context.WithCancel(context.Background())

// Orbits uses --version to get the fleet-desktop version. Logs do not need to be set up when running this.
if len(os.Args) > 1 && os.Args[1] == "--version" {
// Must work with update.GetVersion
Expand Down Expand Up @@ -106,6 +111,9 @@ func main() {
go setupRunners()

var mdmMigrator useraction.MDMMigrator
// swiftDialogCh is a channel shared by the migrator and the offline watcher to
// coordinate the display of the dialog and ensure only one dialog is shown at a time.
var swiftDialogCh chan struct{}

// This ticker is used for fetching the desktop summary. It is initialized here because it is
// stopped in `OnExit.`
Expand Down Expand Up @@ -163,6 +171,7 @@ func main() {
if err != nil {
log.Fatal().Err(err).Msg("unable to initialize request client")
}

client.WithInvalidTokenRetry(func() string {
log.Debug().Msg("refetching token from disk for API retry")
newToken, err := tokenReader.Read()
Expand All @@ -174,13 +183,6 @@ func main() {
return newToken
})

refetchToken := func() {
if _, err := tokenReader.Read(); err != nil {
log.Error().Err(err).Msg("refetch token")
}
log.Debug().Msg("successfully refetched the token from disk")
}

disableTray := func() {
log.Debug().Msg("disabling tray items")
myDeviceItem.SetTitle("Connecting...")
Expand All @@ -192,6 +194,46 @@ func main() {
migrateMDMItem.Hide()
}

// TODO: we can probably extract this into a function that sets up both the migrator and the
// offline watcher
if runtime.GOOS == "darwin" {
dir, err := migration.Dir()
if err != nil {
log.Fatal().Err(err).Msg("getting directory for MDM migration file")
}

mrw := migration.NewReadWriter(dir, constant.MigrationFileName)

// we use channel buffer size of 1 to allow one dialog at a time with non-blocking sends.
swiftDialogCh = make(chan struct{}, 1)

_, swiftDialogPath, _ := update.LocalTargetPaths(
tufUpdateRoot,
"swiftDialog",
update.SwiftDialogMacOSTarget,
)
mdmMigrator = useraction.NewMDMMigrator(
swiftDialogPath,
15*time.Minute,
&mdmMigrationHandler{
client: client,
tokenReader: &tokenReader,
},
mrw,
fleetURL,
swiftDialogCh,
)

useraction.StartMDMMigrationOfflineWatcher(ctx, client, swiftDialogPath, swiftDialogCh, migration.FileWatcher(mrw))
}

refetchToken := func() {
if _, err := tokenReader.Read(); err != nil {
log.Error().Err(err).Msg("refetch token")
}
log.Debug().Msg("successfully refetched the token from disk")
}

// checkToken performs API test calls to enable the "My device" item as
// soon as the device auth token is registered by Fleet.
checkToken := func() <-chan interface{} {
Expand Down Expand Up @@ -252,30 +294,6 @@ func main() {
}
}()

if runtime.GOOS == "darwin" {
dir, err := migration.Dir()
if err != nil {
log.Fatal().Err(err).Msg("getting directory for MDM migration file")
}

mrw := migration.NewReadWriter(dir, constant.MigrationFileName)
_, swiftDialogPath, _ := update.LocalTargetPaths(
tufUpdateRoot,
"swiftDialog",
update.SwiftDialogMacOSTarget,
)
mdmMigrator = useraction.NewMDMMigrator(
swiftDialogPath,
15*time.Minute,
&mdmMigrationHandler{
client: client,
tokenReader: &tokenReader,
},
mrw,
fleetURL,
)
}

reportError := func(err error, info map[string]any) {
if !client.GetServerCapabilities().Has(fleet.CapabilityErrorReporting) {
log.Info().Msg("skipped reporting error to the server as it doesn't have the capability enabled")
Expand Down Expand Up @@ -425,13 +443,19 @@ func main() {
}
}()
}

// FIXME: it doesn't look like this is actually triggering, at least when desktop gets
// killed (https://github.com/fleetdm/fleet/issues/21256)
onExit := func() {
log.Info().Msg("exit")
if mdmMigrator != nil {
mdmMigrator.Exit()
}
if swiftDialogCh != nil {
close(swiftDialogCh)
}
summaryTicker.Stop()

log.Info().Msg("exit")
cancel()
}

systray.Run(onReady, onExit)
Expand Down
3 changes: 3 additions & 0 deletions orbit/pkg/constant/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,7 @@ const (
MDMMigrationTypeManual = "manual"
// MDMMigrationTypeADE indicates that the MDM migration is for an ADE enrolled host.
MDMMigrationTypeADE = "ade"
// MDMMigrationOfflineWatcherInterval is the interval at which the offline watcher checks for
// the presence of the migration file.
MDMMigrationOfflineWatcherInterval = 3 * time.Minute
)
28 changes: 27 additions & 1 deletion orbit/pkg/migration/readwriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (rw *ReadWriter) RemoveFile() error {
}

func (rw *ReadWriter) GetMigrationType() (string, error) {
data, err := rw.read()
data, err := rw.read() // TODO: confirm error handling with jahziel, what about other errors?
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return "", nil
Expand Down Expand Up @@ -108,6 +108,32 @@ func (rw *ReadWriter) setChmod() error {
return os.Chmod(rw.FileName, constant.DefaultWorldReadableFileMode)
}

func (rw *ReadWriter) NewFileWatcher() FileWatcher {
return &fileWatcher{rw: rw}
}

type FileWatcher interface {
GetMigrationType() (string, error)
FileExists() (bool, error)
DirExists() (bool, error)
}

type fileWatcher struct {
rw *ReadWriter
}

func (r *fileWatcher) GetMigrationType() (string, error) {
return r.rw.GetMigrationType()
}

func (r *fileWatcher) FileExists() (bool, error) {
return r.rw.FileExists()
}

func (r *fileWatcher) DirExists() (bool, error) {
return r.rw.DirExists()
}

func Dir() (string, error) {
homedir, err := os.UserHomeDir()
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions orbit/pkg/update/swift_dialog.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ func (s *SwiftDialogDownloader) Run(cfg *fleet.OrbitConfig) error {
return nil
}

// TODO: we probably want to ensure that swiftDialog is always installed if we're going to be
// using it offline.
if !cfg.Notifications.NeedsMDMMigration && !cfg.Notifications.RenewEnrollmentProfile {
log.Debug().Msg("got false needs migration and false renew enrollment")
return nil
Expand Down
2 changes: 2 additions & 0 deletions orbit/pkg/useraction/mdm_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ type MDMMigrator interface {
type MDMMigratorProps struct {
OrgInfo fleet.DesktopOrgInfo
IsUnmanaged bool
// DisableTakeover is used to disable the blur and always on top features of the dialog.
DisableTakeover bool
}

// MDMMigratorHandler handles remote actions/callbacks that the migrator calls.
Expand Down
Loading

0 comments on commit 73658dd

Please sign in to comment.