From 052602752f57dd2dc273f65811a0946a6c575bda Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 14 Nov 2025 08:39:32 -0800 Subject: [PATCH] control/controlclient: make Observer optional As a baby step towards eventbus-ifying controlclient, make the Observer optional. This also means callers that don't care (like this network lock test, and some tests in other repos) can omit it, rather than passing in a no-op one. Updates #12639 Change-Id: Ibd776b45b4425c08db19405bc3172b238e87da4e Signed-off-by: Brad Fitzpatrick --- control/controlclient/auto.go | 10 ++++++---- control/controlclient/direct.go | 4 ++++ ipn/ipnlocal/network-lock_test.go | 7 ------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/control/controlclient/auto.go b/control/controlclient/auto.go index 40b02a598..50248a647 100644 --- a/control/controlclient/auto.go +++ b/control/controlclient/auto.go @@ -117,7 +117,7 @@ type Auto struct { logf logger.Logf closed bool updateCh chan struct{} // readable when we should inform the server of a change - observer Observer // called to update Client status; always non-nil + observer Observer // if non-nil, called to update Client status observerQueue execqueue.ExecQueue shutdownFn func() // to be called prior to shutdown or nil @@ -170,9 +170,6 @@ func NewNoStart(opts Options) (_ *Auto, err error) { } }() - if opts.Observer == nil { - return nil, errors.New("missing required Options.Observer") - } if opts.Logf == nil { opts.Logf = func(fmt string, args ...any) {} } @@ -609,6 +606,11 @@ func (c *Auto) sendStatus(who string, err error, url string, nm *netmap.NetworkM Err: err, state: state, } + + if c.observer == nil { + return + } + c.lastStatus.Store(newSt) // Launch a new goroutine to avoid blocking the caller while the observer diff --git a/control/controlclient/direct.go b/control/controlclient/direct.go index 63a12b249..d30db6191 100644 --- a/control/controlclient/direct.go +++ b/control/controlclient/direct.go @@ -115,6 +115,9 @@ type Direct struct { // Observer is implemented by users of the control client (such as LocalBackend) // to get notified of changes in the control client's status. +// +// If an implementation of Observer also implements [NetmapDeltaUpdater], they get +// delta updates as well as full netmap updates. type Observer interface { // SetControlClientStatus is called when the client has a new status to // report. The Client is provided to allow the Observer to track which @@ -145,6 +148,7 @@ type Options struct { // Observer is called when there's a change in status to report // from the control client. + // If nil, no status updates are reported. Observer Observer // SkipIPForwardingCheck declares that the host's IP diff --git a/ipn/ipnlocal/network-lock_test.go b/ipn/ipnlocal/network-lock_test.go index c7c4c905f..17040fef3 100644 --- a/ipn/ipnlocal/network-lock_test.go +++ b/ipn/ipnlocal/network-lock_test.go @@ -41,12 +41,6 @@ import ( "tailscale.com/util/set" ) -type observerFunc func(controlclient.Status) - -func (f observerFunc) SetControlClientStatus(_ controlclient.Client, s controlclient.Status) { - f(s) -} - func fakeControlClient(t *testing.T, c *http.Client) (*controlclient.Auto, *eventbus.Bus) { hi := hostinfo.New() ni := tailcfg.NetInfo{LinkType: "wired"} @@ -64,7 +58,6 @@ func fakeControlClient(t *testing.T, c *http.Client) (*controlclient.Auto, *even }, HTTPTestClient: c, NoiseTestClient: c, - Observer: observerFunc(func(controlclient.Status) {}), Dialer: dialer, Bus: bus, }