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 <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2025-11-14 08:39:32 -08:00
parent 124301fbb6
commit 378a21ecfa
3 changed files with 10 additions and 11 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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,
}