From d8ba5e6f6bd5bad62fc7dfb9694611d775c207d3 Mon Sep 17 00:00:00 2001 From: riccardom Date: Thu, 11 Jun 2026 12:58:33 +0200 Subject: [PATCH] Moves callback into Run method arg --- client/mdm/ticker.go | 31 +++++++++++++------------------ client/mdm/ticker_test.go | 38 ++++++++++++++++++++++---------------- client/server/server.go | 4 ++-- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/client/mdm/ticker.go b/client/mdm/ticker.go index 88356ad74..fb7982e1e 100644 --- a/client/mdm/ticker.go +++ b/client/mdm/ticker.go @@ -22,35 +22,33 @@ const DefaultReloadInterval = 1 * time.Minute var policyLoader = LoadPolicy // Ticker periodically re-reads the OS-native MDM policy via LoadPolicy and -// invokes onChange whenever the observed Policy diverges from the last -// observation (added / removed / changed keys). Launch with Run from a -// goroutine; cancel the supplied context to stop. +// invokes the onChange callback (supplied to Run) whenever the observed +// Policy diverges from the last observation (added / removed / changed +// keys). Launch with Run from a goroutine; cancel the supplied context +// to stop. type Ticker struct { interval time.Duration - onChange func(prev, curr *Policy) error prev *Policy } -// NewTicker constructs a Ticker that re-reads the OS-native policy -// every reloadInterval and invokes onChange on any diff. -// onChange may be nil for a log-only ticker. +// NewTicker constructs a Ticker that will re-read the OS-native policy +// every reloadInterval once Run is called. // The initial snapshot is populated by calling policyLoader at // construction time so the first tick only fires // onChange when the policy actually changed since boot — without // this baseline the first tick would report every currently-managed // key as "added" and trigger a spurious engine restart. -func NewTicker(reloadInterval time.Duration, onChange func(prev, curr *Policy) error) *Ticker { +func NewTicker(reloadInterval time.Duration) *Ticker { return &Ticker{ interval: reloadInterval, - onChange: onChange, prev: policyLoader(), } } // Run blocks until ctx is cancelled, polling the OS-native policy store at // the configured cadence and emitting log lines + onChange callback on -// every observed diff. -func (t *Ticker) Run(ctx context.Context) { +// every observed diff. onChange must be non-nil. +func (t *Ticker) Run(ctx context.Context, onChange func(prev, curr *Policy) error) { tk := time.NewTicker(t.interval) defer tk.Stop() log.Infof("MDM policy reload ticker started (interval=%s)", t.interval) @@ -68,14 +66,11 @@ func (t *Ticker) Run(ctx context.Context) { log.Infof("MDM policy changed: added=%v removed=%v changed=%v", added, removed, changed) prev := t.prev - - if t.onChange != nil { - if err := t.onChange(prev, curr); err != nil { - log.Errorf("MDM policy change handler failed (retrying in 1 minute): %v", err) - continue - } - t.prev = curr + if err := onChange(prev, curr); err != nil { + log.Errorf("MDM policy change handler failed (retrying in 1 minute): %v", err) + continue } + t.prev = curr } } } diff --git a/client/mdm/ticker_test.go b/client/mdm/ticker_test.go index 098688e44..17f3cfc2f 100644 --- a/client/mdm/ticker_test.go +++ b/client/mdm/ticker_test.go @@ -34,18 +34,21 @@ func TestTicker_FiresOnChangeWithDelta(t *testing.T) { type change struct{ prev, curr *Policy } changes := make(chan change, 1) - tk := NewTicker(testReloadInterval, func(prev, curr *Policy) error { - select { - case changes <- change{prev, curr}: - default: - } - return nil - }) + tk := NewTicker(testReloadInterval) require.Equal(t, testReloadInterval, tk.interval) ctx, cancel := context.WithCancel(context.Background()) done := make(chan struct{}) - go func() { tk.Run(ctx); close(done) }() + go func() { + tk.Run(ctx, func(prev, curr *Policy) error { + select { + case changes <- change{prev, curr}: + default: + } + return nil + }) + close(done) + }() // Stop Run and wait for it to exit before returning, so the policyLoader // restore in t.Cleanup can't race the ticker goroutine still reading it. defer func() { cancel(); <-done }() @@ -71,17 +74,20 @@ func TestTicker_NoCallbackWhenPolicyUnchanged(t *testing.T) { }) fired := make(chan struct{}, 1) - tk := NewTicker(testReloadInterval, func(_, _ *Policy) error { - select { - case fired <- struct{}{}: - default: - } - return nil - }) + tk := NewTicker(testReloadInterval) ctx, cancel := context.WithCancel(context.Background()) done := make(chan struct{}) - go func() { tk.Run(ctx); close(done) }() + go func() { + tk.Run(ctx, func(_, _ *Policy) error { + select { + case fired <- struct{}{}: + default: + } + return nil + }) + close(done) + }() defer func() { cancel(); <-done }() // Over ~2 ticks at the 1s test cadence the policy never changes, so the diff --git a/client/server/server.go b/client/server/server.go index 821439c68..32daf7718 100644 --- a/client/server/server.go +++ b/client/server/server.go @@ -174,8 +174,8 @@ func (s *Server) Start() error { // applies the freshly-read MDM policy as the last layer) and brings // the engine back with the new values. if s.mdmTicker == nil { - s.mdmTicker = mdm.NewTicker(mdm.DefaultReloadInterval, s.onMDMPolicyChange) - go s.mdmTicker.Run(s.rootCtx) + s.mdmTicker = mdm.NewTicker(mdm.DefaultReloadInterval) + go s.mdmTicker.Run(s.rootCtx, s.onMDMPolicyChange) } // if current state contains any error, return it