Add events to resync UI to actual config

This also provide fixup for UI no aligning to changed config when coming from cli up with config flags.
This commit is contained in:
riccardom
2026-06-08 18:06:02 +02:00
parent 029e69279c
commit 1100cea6a4
3 changed files with 49 additions and 9 deletions
+36 -9
View File
@@ -60,20 +60,46 @@ func (s *Server) onMDMPolicyChange(_, curr *mdm.Policy) {
return return
} }
// Notify any active gRPC SubscribeEvents subscriber (typically the UI // publishConfigChangedEvent has already fired inside
// tray) that the daemon's effective configuration has changed. // restartEngineForMDM with source="mdm". Here we additionally emit an
// Reusing the SYSTEM category keeps the proto enum stable for // MDM-specific user-visible toast so the operator knows their IT
// backwards-compat; metadata["source"]="mdm" + ["type"]="policy_changed" // policy was applied (UserMessage != "" triggers the GUI notifier).
// disambiguates the trigger for handler routing on the client side. _ = curr
managed := curr.ManagedKeys()
s.statusRecorder.PublishEvent( s.statusRecorder.PublishEvent(
proto.SystemEvent_INFO, proto.SystemEvent_INFO,
proto.SystemEvent_SYSTEM, proto.SystemEvent_SYSTEM,
fmt.Sprintf("MDM policy applied; engine restarted with %d managed key(s)", len(managed)), "MDM policy applied",
"NetBird configuration was updated by your IT policy.", "NetBird configuration was updated by your IT policy.",
map[string]string{"source": "mdm", "type": "policy_applied"},
)
}
// publishConfigChangedEvent broadcasts a SystemEvent informing any active
// SubscribeEvents subscriber (typically the GUI tray) that the daemon's
// effective Config has been replaced and any cached client-side view
// should be refreshed. Callers pass a stable `source` label so the GUI
// can distinguish a startup spawn from a user-triggered Up or an
// MDM-driven restart. Reusing the SYSTEM category keeps the proto enum
// stable; metadata.type="config_changed" routes to the GUI's refresh
// handler. UserMessage is left empty so the system tray does not toast
// for every internal restart; the MDM path emits a separate
// "policy_applied" event (with UserMessage) for that purpose.
func (s *Server) publishConfigChangedEvent(source string) {
if s.statusRecorder == nil {
return
}
var managed []string
if s.config != nil {
managed = s.config.Policy().ManagedKeys()
}
s.statusRecorder.PublishEvent(
proto.SystemEvent_INFO,
proto.SystemEvent_SYSTEM,
fmt.Sprintf("daemon config changed (source=%s)", source),
"",
map[string]string{ map[string]string{
"source": "mdm", "source": source,
"type": "policy_changed", "type": "config_changed",
"managed_fields": strings.Join(managed, ","), "managed_fields": strings.Join(managed, ","),
}, },
) )
@@ -122,6 +148,7 @@ func (s *Server) restartEngineForMDM() error {
s.clientGiveUpChan = make(chan struct{}) s.clientGiveUpChan = make(chan struct{})
log.Info("MDM restart: spawning connectWithRetryRuns with re-resolved config") log.Info("MDM restart: spawning connectWithRetryRuns with re-resolved config")
go s.connectWithRetryRuns(ctx, config, s.statusRecorder, s.clientRunningChan, s.clientGiveUpChan) go s.connectWithRetryRuns(ctx, config, s.statusRecorder, s.clientRunningChan, s.clientGiveUpChan)
s.publishConfigChangedEvent("mdm")
return nil return nil
} }
+2
View File
@@ -230,6 +230,7 @@ func (s *Server) Start() error {
s.clientRunningChan = make(chan struct{}) s.clientRunningChan = make(chan struct{})
s.clientGiveUpChan = make(chan struct{}) s.clientGiveUpChan = make(chan struct{})
go s.connectWithRetryRuns(ctx, config, s.statusRecorder, s.clientRunningChan, s.clientGiveUpChan) go s.connectWithRetryRuns(ctx, config, s.statusRecorder, s.clientRunningChan, s.clientGiveUpChan)
s.publishConfigChangedEvent("startup")
return nil return nil
} }
@@ -768,6 +769,7 @@ func (s *Server) Up(callerCtx context.Context, msg *proto.UpRequest) (*proto.UpR
s.clientGiveUpChan = make(chan struct{}) s.clientGiveUpChan = make(chan struct{})
go s.connectWithRetryRuns(ctx, s.config, s.statusRecorder, s.clientRunningChan, s.clientGiveUpChan) go s.connectWithRetryRuns(ctx, s.config, s.statusRecorder, s.clientRunningChan, s.clientGiveUpChan)
s.publishConfigChangedEvent("up_rpc")
s.mutex.Unlock() s.mutex.Unlock()
return s.waitForUp(callerCtx) return s.waitForUp(callerCtx)
+11
View File
@@ -1150,6 +1150,17 @@ func (s *serviceClient) onTrayReady() {
s.onUpdateAvailable(newVersion, enforced) s.onUpdateAvailable(newVersion, enforced)
} }
}) })
s.eventManager.AddHandler(func(event *proto.SystemEvent) {
// Daemon emits a config_changed event after every engine spawn
// (Server.Start, Server.Up, MDM ticker restart). Re-sync the
// tray submenu checkboxes from the fresh daemon-side config so
// the user does not have to restart the tray to see CLI- or
// MDM-driven changes.
if event.Category == proto.SystemEvent_SYSTEM && event.Metadata["type"] == "config_changed" {
log.Infof("config_changed event received (source=%s); refreshing settings", event.Metadata["source"])
s.loadSettings()
}
})
go s.eventManager.Start(s.ctx) go s.eventManager.Start(s.ctx)
go s.eventHandler.listen(s.ctx) go s.eventHandler.listen(s.ctx)