From 685d4226c800a79555fc5b36bcd3d6fa1f5961d4 Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Mon, 7 Jul 2025 10:35:15 -0400 Subject: [PATCH] 21277: Keep fleet desktop running when host is offline (#30493) For #21277 Show offline message on Fleet Desktop if host is offline. --- orbit/changes/21277-offline-indicator | 1 + orbit/cmd/desktop/desktop.go | 27 ++++++++++++++++++++- orbit/cmd/orbit/orbit.go | 34 +++++++++++++++++---------- 3 files changed, 48 insertions(+), 14 deletions(-) create mode 100644 orbit/changes/21277-offline-indicator diff --git a/orbit/changes/21277-offline-indicator b/orbit/changes/21277-offline-indicator new file mode 100644 index 0000000000..51b73f8841 --- /dev/null +++ b/orbit/changes/21277-offline-indicator @@ -0,0 +1 @@ +* Added feature for showing an informational message on fleet desktop if host becomes offline. \ No newline at end of file diff --git a/orbit/cmd/desktop/desktop.go b/orbit/cmd/desktop/desktop.go index 14abb59e19..9113eb4211 100644 --- a/orbit/cmd/desktop/desktop.go +++ b/orbit/cmd/desktop/desktop.go @@ -175,6 +175,14 @@ func main() { myDeviceItem := systray.AddMenuItem("Connecting...", "") myDeviceItem.Disable() + myDeviceItem.Hide() + + hostOfflineItem := systray.AddMenuItem( + `🛜🚫 Your computer is offline. + +It might take up to 5 minutes to reconnect to Fleet.`, + "") + hostOfflineItem.Disable() selfServiceItem := systray.AddMenuItem("Self-service", "") selfServiceItem.Disable() @@ -220,12 +228,17 @@ func main() { disableTray := func() { log.Debug().Msg("disabling tray items") myDeviceItem.SetTitle("Connecting...") + myDeviceItem.Show() myDeviceItem.Disable() + transparencyItem.Disable() selfServiceItem.Disable() selfServiceItem.Hide() + migrateMDMItem.Disable() migrateMDMItem.Hide() + + hostOfflineItem.Hide() } reportError := func(err error, info map[string]any) { @@ -283,8 +296,13 @@ func main() { if err == nil || errors.Is(err, service.ErrMissingLicense) { log.Debug().Msg("enabling tray items") myDeviceItem.SetTitle("My device") + myDeviceItem.Show() myDeviceItem.Enable() + transparencyItem.Enable() + transparencyItem.Show() + + hostOfflineItem.Hide() // Hide Self-Service for Free tier if errors.Is(err, service.ErrMissingLicense) || (summary.SelfService != nil && !*summary.SelfService) { @@ -345,21 +363,28 @@ func main() { sum, err := client.DesktopSummary(tokenReader.GetCached()) switch { case err == nil: - // OK + hostOfflineItem.Hide() case errors.Is(err, service.ErrMissingLicense): myDeviceItem.SetTitle("My device") + myDeviceItem.Show() + hostOfflineItem.Hide() continue case errors.Is(err, service.ErrUnauthenticated): disableTray() + hostOfflineItem.Hide() <-checkToken() continue default: + myDeviceItem.Hide() + transparencyItem.Disable() + hostOfflineItem.Show() log.Error().Err(err).Msg("get desktop summary") continue } refreshMenuItems(sum.DesktopSummary, selfServiceItem, myDeviceItem) myDeviceItem.Enable() + myDeviceItem.Show() // Check our file to see if we should migrate var migrationType string diff --git a/orbit/cmd/orbit/orbit.go b/orbit/cmd/orbit/orbit.go index c3d97816e6..5aba888849 100644 --- a/orbit/cmd/orbit/orbit.go +++ b/orbit/cmd/orbit/orbit.go @@ -955,6 +955,10 @@ func main() { return fmt.Errorf("error new orbit client: %w", err) } + // If the server can't be reached, we want to fail quickly on any blocking network calls + // so that desktop can be launched as soon as possible. + serverIsReachable := orbitClient.Ping() == nil + // create the notifications middleware that wraps the orbit client // (must be shared by all runners that use a ConfigFetcher). const ( @@ -1043,18 +1047,20 @@ func main() { orbitClient.RegisterConfigReceiver(extRunner) } - // Run a early check of fleetd configuration to check if orbit needs to - // restart before proceeding to start the sub-systems. + // Run an early check of fleetd configuration (iff server can be reached) + // to check if orbit needs to restart before proceeding to start the sub-systems. // // E.g. the administrator has updated the following agent options for this device: // - `update_channels` // - `extensions` were removed/unset // - `command_line_flags` (osquery startup flags) - if err := orbitClient.RunConfigReceivers(); err != nil { - log.Error().Msgf("failed initial config fetch: %s", err) - } else if orbitClient.RestartTriggered() { - log.Info().Msg("exiting after early config fetch") - return nil + if serverIsReachable { + if err := orbitClient.RunConfigReceivers(); err != nil { + log.Error().Msgf("failed initial config fetch: %s", err) + } else if orbitClient.RestartTriggered() { + log.Info().Msg("exiting after early config fetch") + return nil + } } addSubsystem(&g, "config receivers", &wrapSubsystem{ @@ -1094,12 +1100,14 @@ func main() { return fmt.Errorf("initializing client: %w", err) } - // Check if token is not expired and still good. - // If not, rotate the token. - expired, _ := trw.HasExpired() - if expired || deviceClient.CheckToken(trw.GetCached()) != nil { - if err := trw.Rotate(); err != nil { - return fmt.Errorf("rotating token: %w", err) + // Check if the token is not expired and still good. + // If not, rotate the token iff the server is reachable. + if serverIsReachable { + expired, _ := trw.HasExpired() + if expired || deviceClient.CheckToken(trw.GetCached()) != nil { + if err := trw.Rotate(); err != nil { + return fmt.Errorf("rotating token: %w", err) + } } }