tsnet: reset serve config only once
Prior to this change, we were resetting the tsnet's serve config every time tsnet.Server.Up was run. This is important to do on startup, to prevent messy interactions with stale configuration when the code has changed. However, Up is frequently run as a just-in-case step (for example, by Server.ListenTLS/ListenFunnel and possibly by consumers of tsnet). When the serve config is reset on each of these calls to Up, this creates situations in which the serve config disappears unexpectedly. The solution is to reset the serve config only on the first call to Up. Fixes #8800 Updates tailscale/corp#27200 Signed-off-by: Harry Harpham <harry@tailscale.com>
This commit is contained in:
+31
-26
@@ -160,25 +160,26 @@ type Server struct {
|
|||||||
|
|
||||||
getCertForTesting func(*tls.ClientHelloInfo) (*tls.Certificate, error)
|
getCertForTesting func(*tls.ClientHelloInfo) (*tls.Certificate, error)
|
||||||
|
|
||||||
initOnce sync.Once
|
initOnce sync.Once
|
||||||
initErr error
|
initErr error
|
||||||
lb *ipnlocal.LocalBackend
|
lb *ipnlocal.LocalBackend
|
||||||
sys *tsd.System
|
sys *tsd.System
|
||||||
netstack *netstack.Impl
|
netstack *netstack.Impl
|
||||||
netMon *netmon.Monitor
|
netMon *netmon.Monitor
|
||||||
rootPath string // the state directory
|
rootPath string // the state directory
|
||||||
hostname string
|
hostname string
|
||||||
shutdownCtx context.Context
|
shutdownCtx context.Context
|
||||||
shutdownCancel context.CancelFunc
|
shutdownCancel context.CancelFunc
|
||||||
proxyCred string // SOCKS5 proxy auth for loopbackListener
|
proxyCred string // SOCKS5 proxy auth for loopbackListener
|
||||||
localAPICred string // basic auth password for loopbackListener
|
localAPICred string // basic auth password for loopbackListener
|
||||||
loopbackListener net.Listener // optional loopback for localapi and proxies
|
loopbackListener net.Listener // optional loopback for localapi and proxies
|
||||||
localAPIListener net.Listener // in-memory, used by localClient
|
localAPIListener net.Listener // in-memory, used by localClient
|
||||||
localClient *local.Client // in-memory
|
localClient *local.Client // in-memory
|
||||||
localAPIServer *http.Server
|
localAPIServer *http.Server
|
||||||
logbuffer *filch.Filch
|
resetServeConfigOnce sync.Once
|
||||||
logtail *logtail.Logger
|
logbuffer *filch.Filch
|
||||||
logid logid.PublicID
|
logtail *logtail.Logger
|
||||||
|
logid logid.PublicID
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
listeners map[listenKey]*listener
|
listeners map[listenKey]*listener
|
||||||
@@ -388,8 +389,8 @@ func (s *Server) Up(ctx context.Context) (*ipnstate.Status, error) {
|
|||||||
if n.ErrMessage != nil {
|
if n.ErrMessage != nil {
|
||||||
return nil, fmt.Errorf("tsnet.Up: backend: %s", *n.ErrMessage)
|
return nil, fmt.Errorf("tsnet.Up: backend: %s", *n.ErrMessage)
|
||||||
}
|
}
|
||||||
if s := n.State; s != nil {
|
if st := n.State; st != nil {
|
||||||
if *s == ipn.Running {
|
if *st == ipn.Running {
|
||||||
status, err := lc.Status(ctx)
|
status, err := lc.Status(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("tsnet.Up: %w", err)
|
return nil, fmt.Errorf("tsnet.Up: %w", err)
|
||||||
@@ -398,11 +399,15 @@ func (s *Server) Up(ctx context.Context) (*ipnstate.Status, error) {
|
|||||||
return nil, errors.New("tsnet.Up: running, but no ip")
|
return nil, errors.New("tsnet.Up: running, but no ip")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the persisted serve config state to prevent stale configuration
|
// The first time Up is run, clear the persisted serve config.
|
||||||
// from code changes. This is a temporary workaround until we have a better
|
// We do this to prevent messy interactions with stale config in
|
||||||
// way to handle this. (2023-03-11)
|
// the face of code changes.
|
||||||
if err := lc.SetServeConfig(ctx, new(ipn.ServeConfig)); err != nil {
|
var srvResetErr error
|
||||||
return nil, fmt.Errorf("tsnet.Up: %w", err)
|
s.resetServeConfigOnce.Do(func() {
|
||||||
|
srvResetErr = lc.SetServeConfig(ctx, new(ipn.ServeConfig))
|
||||||
|
})
|
||||||
|
if srvResetErr != nil {
|
||||||
|
return nil, fmt.Errorf("tsnet.Up: clearing serve config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return status, nil
|
return status, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user