diff --git a/cmd/launcher/launcher.go b/cmd/launcher/launcher.go index e9f0f7fa1..ca4a3bdfb 100644 --- a/cmd/launcher/launcher.go +++ b/cmd/launcher/launcher.go @@ -30,6 +30,7 @@ import ( "github.com/kolide/launcher/ee/agent/storage" agentbbolt "github.com/kolide/launcher/ee/agent/storage/bbolt" "github.com/kolide/launcher/ee/agent/timemachine" + "github.com/kolide/launcher/ee/control" "github.com/kolide/launcher/ee/control/actionqueue" "github.com/kolide/launcher/ee/control/consumers/acceleratecontrolconsumer" "github.com/kolide/launcher/ee/control/consumers/flareconsumer" @@ -449,6 +450,8 @@ func runLauncher(ctx context.Context, cancel func(), multiSlogger, systemMultiSl actionsQueue.RegisterActor(uninstallconsumer.UninstallSubsystem, uninstallconsumer.New(k)) // register flare consumer actionsQueue.RegisterActor(flareconsumer.FlareSubsystem, flareconsumer.New(k)) + // register force full control data fetch consumer + actionsQueue.RegisterActor(control.ForceFullControlDataFetchAction, controlService) // create notification consumer notificationConsumer, err := notificationconsumer.NewNotifyConsumer( diff --git a/ee/control/control.go b/ee/control/control.go index 8e2d34f0f..218d5a4d7 100644 --- a/ee/control/control.go +++ b/ee/control/control.go @@ -16,6 +16,8 @@ import ( "golang.org/x/exp/slices" ) +const ForceFullControlDataFetchAction = "force_full_control_data_fetch" + // ControlService is the main object that manages the control service. It is responsible for fetching // and caching control data, and updating consumers and subscribers. type ControlService struct { @@ -96,7 +98,7 @@ func (cs *ControlService) Start(ctx context.Context) { startUpMessageSuccess := false for { - fetchErr := cs.Fetch() + fetchErr := cs.Fetch(false) switch { case fetchErr != nil: cs.slogger.Log(ctx, slog.LevelWarn, @@ -208,7 +210,7 @@ func (cs *ControlService) requestIntervalChanged(newInterval time.Duration) { // Perform a fetch now, to retrieve data faster in case this change // was triggered by localserver or the user clicking on the menu bar app // instead of by a control server change. - if err := cs.Fetch(); err != nil { + if err := cs.Fetch(false); err != nil { // if we got an error, log it and move on cs.slogger.Log(context.TODO(), slog.LevelWarn, "failed to fetch data from control server. Not fatal, moving on", @@ -248,7 +250,7 @@ func (cs *ControlService) readRequestInterval() time.Duration { } // Performs a retrieval of the latest control server data, and notifies observers of updates. -func (cs *ControlService) Fetch() error { +func (cs *ControlService) Fetch(fetchFull bool) error { // Do not block in the case where: // 1. `Start` called `Fetch` on an interval // 2. The control service received an updated `ControlRequestInterval` from the server @@ -286,7 +288,7 @@ func (cs *ControlService) Fetch() error { } } - if hash == lastHash && !cs.knapsack.ForceControlSubsystems() { + if hash == lastHash && !cs.knapsack.ForceControlSubsystems() && !fetchFull { // The last fetched update is still fresh // Nothing to do, skip to the next subsystem continue @@ -382,3 +384,12 @@ func (cs *ControlService) update(subsystem string, reader io.Reader) error { return nil } + +// Do handles the force_full_control_data_fetch action. +func (cs *ControlService) Do(data io.Reader) error { + cs.slogger.Log(context.TODO(), slog.LevelDebug, + "received request to perform full fetch of all subsystems", + ) + + return cs.Fetch(true) +} diff --git a/ee/control/control_test.go b/ee/control/control_test.go index a431778ef..8f2467cb1 100644 --- a/ee/control/control_test.go +++ b/ee/control/control_test.go @@ -247,7 +247,7 @@ func TestControlServiceFetch(t *testing.T) { // Repeat fetches to verify no changes for i := 0; i < tt.fetches; i++ { - err = cs.Fetch() + err = cs.Fetch(false) require.NoError(t, err) // Expect consumer to have gotten exactly one update @@ -353,7 +353,7 @@ func TestControlServicePersistLastFetched(t *testing.T) { err := cs.RegisterConsumer(tt.subsystem, tt.c) require.NoError(t, err) - err = cs.Fetch() + err = cs.Fetch(false) require.NoError(t, err) }