diff --git a/orbit/changes/11777-deprecate-kickstart-softwareupdated b/orbit/changes/11777-deprecate-kickstart-softwareupdated new file mode 100644 index 000000000..4d2dd2732 --- /dev/null +++ b/orbit/changes/11777-deprecate-kickstart-softwareupdated @@ -0,0 +1,2 @@ +* Removed automatic functionality to call `launchctl kickstart -k softwareupdated` periodically, which was causing issues on some macOS devices. + The `--disable-kickstart-softwareupdated` flag is kept for backwards compatibility but it doesn't have any effect. diff --git a/orbit/cmd/orbit/orbit.go b/orbit/cmd/orbit/orbit.go index 1087ac08b..55fa3f198 100644 --- a/orbit/cmd/orbit/orbit.go +++ b/orbit/cmd/orbit/orbit.go @@ -151,9 +151,15 @@ func main() { Usage: "Launch Fleet Desktop application (flag currently only used on darwin)", EnvVars: []string{"ORBIT_FLEET_DESKTOP"}, }, + // Note: this flag doesn't have any effect anymore. I'm keeping + // it just for backwards compatibility since some users were + // using it because softwareupdated was causing problems and I + // don't want to break their setups. + // + // For more context please check out: https://github.com/fleetdm/fleet/issues/11777 &cli.BoolFlag{ Name: "disable-kickstart-softwareupdated", - Usage: "Disable periodic execution of 'launchctl kickstart -k softwareupdated' on macOS", + Usage: "(Deprecated) Disable periodic execution of 'launchctl kickstart -k softwareupdated' on macOS", EnvVars: []string{"ORBIT_FLEET_DISABLE_KICKSTART_SOFTWAREUPDATED"}, Hidden: true, }, @@ -335,13 +341,8 @@ func main() { g.Add(systemChecker.Execute, systemChecker.Interrupt) go osservice.SetupServiceManagement(constant.SystemServiceName, systemChecker.svcInterruptCh, appDoneCh) - // periodically run launchctl kickstart -k softwareupdated on macOS - if runtime.GOOS == "darwin" && !c.Bool("disable-kickstart-softwareupdated") { - const softwareUpdatedKickstartInterval = 12 * time.Hour - updatedRunner := update.NewSoftwareUpdatedRunner(update.SoftwareUpdatedOptions{ - Interval: softwareUpdatedKickstartInterval, - }) - g.Add(updatedRunner.Execute, updatedRunner.Interrupt) + if !c.Bool("disable-kickstart-softwareupdated") { + log.Warn().Msg("fleetd no longer automatically kickstarts softwareupdated. The --disable-kickstart-softwareupdated flag, which was previously used to disable this behavior, has been deprecated and will be removed in a future version") } updateClientCrtPath := filepath.Join(c.String("root-dir"), constant.UpdateTLSClientCertificateFileName) diff --git a/orbit/pkg/update/execcmd_darwin.go b/orbit/pkg/update/execcmd_darwin.go index 66941518e..65cbdf7c2 100644 --- a/orbit/pkg/update/execcmd_darwin.go +++ b/orbit/pkg/update/execcmd_darwin.go @@ -5,7 +5,3 @@ package update func runRenewEnrollmentProfile() error { return runCmdCollectErr("/usr/bin/profiles", "renew", "--type", "enrollment") } - -func runKickstartSoftwareUpdated() error { - return runCmdCollectErr("launchctl", "kickstart", "-k", "system/com.apple.softwareupdated") -} diff --git a/orbit/pkg/update/execcmd_stub.go b/orbit/pkg/update/execcmd_stub.go index a7d9fa1e1..405f7d76c 100644 --- a/orbit/pkg/update/execcmd_stub.go +++ b/orbit/pkg/update/execcmd_stub.go @@ -5,7 +5,3 @@ package update func runRenewEnrollmentProfile() error { return nil } - -func runKickstartSoftwareUpdated() error { - return nil -} diff --git a/orbit/pkg/update/softwareupdated_runner.go b/orbit/pkg/update/softwareupdated_runner.go deleted file mode 100644 index a4830ebf9..000000000 --- a/orbit/pkg/update/softwareupdated_runner.go +++ /dev/null @@ -1,79 +0,0 @@ -package update - -import ( - "time" - - "github.com/rs/zerolog/log" -) - -// SoftwareUpdatedRunner is a specialized runner to periodically kickstart the -// softwareupdated service on macOS, to work around a bug where the service -// hangs from time to time and prevents updates from being downloaded or update -// notifications from being shown. -// -// It is designed with Execute and Interrupt functions to be compatible with -// oklog/run. -type SoftwareUpdatedRunner struct { - opt SoftwareUpdatedOptions - cancel chan struct{} -} - -// SoftwareUpdatedOptions defines the options provided for the softwareupdated -// runner. -type SoftwareUpdatedOptions struct { - // Interval is the interval at which to run the the kickstart softwareupdated - // command. - Interval time.Duration - - // runCmdFn can be set in tests to mock the command executed to kickstart - // softwareupdated. If nil, defaults to runKickstartSoftwareUpdated. - runCmdFn runCmdFunc -} - -// NewSoftwareUpdatedRunner creates a new runner with the provided options. The -// runner must be started with Execute. -func NewSoftwareUpdatedRunner(opt SoftwareUpdatedOptions) *SoftwareUpdatedRunner { - return &SoftwareUpdatedRunner{ - opt: opt, - cancel: make(chan struct{}), - } -} - -// Execute starts the loop to periodically run the kickstart command. -func (r *SoftwareUpdatedRunner) Execute() error { - log.Debug().Msg("starting softwareupdated runner") - - // ensure it runs ~immediately the first time (e.g. on startup) - firstInterval := 10 * time.Second - if r.opt.Interval < firstInterval { - firstInterval = r.opt.Interval - } - ticker := time.NewTicker(firstInterval) - defer ticker.Stop() - - for { - select { - case <-r.cancel: - return nil - - case <-ticker.C: - log.Info().Msg("executing launchctl kickstart -k softwareupdated") - fn := r.opt.runCmdFn - if fn == nil { - fn = runKickstartSoftwareUpdated - } - if err := fn(); err != nil { - log.Info().Err(err).Msg("executing launchctl kickstart -k softwareupdated failed") - } - // run at the defined interval the next time around - ticker.Reset(r.opt.Interval) - } - } -} - -// Interrupt is the oklog/run interrupt method that stops the runner when -// called. -func (r *SoftwareUpdatedRunner) Interrupt(err error) { - close(r.cancel) - log.Debug().Err(err).Msg("interrupt for softwareupdated runner") -} diff --git a/orbit/pkg/update/softwareupdated_runner_test.go b/orbit/pkg/update/softwareupdated_runner_test.go deleted file mode 100644 index 1d54294e7..000000000 --- a/orbit/pkg/update/softwareupdated_runner_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package update - -import ( - "sync/atomic" - "testing" - "time" - - "github.com/oklog/run" - "github.com/stretchr/testify/require" -) - -func TestSoftwareUpdatedRunner(t *testing.T) { - var callCount int32 - runFn := func() error { - atomic.AddInt32(&callCount, 1) - return nil - } - - var g run.Group - // add the "lead" runner, it will return after 1s and cause all runners to stop - g.Add(func() error { time.Sleep(time.Second); return nil }, func(error) {}) - - // add the softwareupdated runner, should run at least 2 times (leave some - // wiggle room in case it is so slow on CI that it is not scheduled more - // often). - r := NewSoftwareUpdatedRunner(SoftwareUpdatedOptions{Interval: 300 * time.Millisecond, runCmdFn: runFn}) - g.Add(r.Execute, r.Interrupt) - - err := g.Run() - require.NoError(t, err) - require.GreaterOrEqual(t, atomic.LoadInt32(&callCount), int32(2)) -}