mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-01 14:05:39 +00:00
e6b84f2159
Instead of hard-coding the DERP map (except for cmd/tailscale netcheck for now), get it from the control server at runtime. And make the DERP map support multiple nodes per region with clients picking the first one that's available. (The server will balance the order presented to clients for load balancing) This deletes the stunner package, merging it into the netcheck package instead, to minimize all the config hooks that would've been required. Also fix some test flakes & races. Fixes #387 (Don't hard-code the DERP map) Updates #388 (Add DERP region support) Fixes #399 (wgengine: flaky tests) Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
101 lines
2.7 KiB
Go
101 lines
2.7 KiB
Go
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package wgengine
|
|
|
|
import (
|
|
"log"
|
|
"runtime/pprof"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/tailscale/wireguard-go/wgcfg"
|
|
"tailscale.com/ipn/ipnstate"
|
|
"tailscale.com/tailcfg"
|
|
"tailscale.com/wgengine/filter"
|
|
"tailscale.com/wgengine/router"
|
|
)
|
|
|
|
// NewWatchdog wraps an Engine and makes sure that all methods complete
|
|
// within a reasonable amount of time.
|
|
//
|
|
// If they do not, the watchdog crashes the process.
|
|
func NewWatchdog(e Engine) Engine {
|
|
return &watchdogEngine{
|
|
wrap: e,
|
|
logf: log.Printf,
|
|
fatalf: log.Fatalf,
|
|
maxWait: 45 * time.Second,
|
|
}
|
|
}
|
|
|
|
type watchdogEngine struct {
|
|
wrap Engine
|
|
logf func(format string, args ...interface{})
|
|
fatalf func(format string, args ...interface{})
|
|
maxWait time.Duration
|
|
}
|
|
|
|
func (e *watchdogEngine) watchdogErr(name string, fn func() error) error {
|
|
errCh := make(chan error)
|
|
go func() {
|
|
errCh <- fn()
|
|
}()
|
|
t := time.NewTimer(e.maxWait)
|
|
select {
|
|
case err := <-errCh:
|
|
t.Stop()
|
|
return err
|
|
case <-t.C:
|
|
buf := new(strings.Builder)
|
|
pprof.Lookup("goroutine").WriteTo(buf, 1)
|
|
e.logf("wgengine watchdog stacks:\n%s", buf.String())
|
|
e.fatalf("wgengine: watchdog timeout on %s", name)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (e *watchdogEngine) watchdog(name string, fn func()) {
|
|
e.watchdogErr(name, func() error {
|
|
fn()
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (e *watchdogEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config) error {
|
|
return e.watchdogErr("Reconfig", func() error { return e.wrap.Reconfig(cfg, routerCfg) })
|
|
}
|
|
func (e *watchdogEngine) GetFilter() *filter.Filter {
|
|
var x *filter.Filter
|
|
e.watchdog("GetFilter", func() { x = e.wrap.GetFilter() })
|
|
return x
|
|
}
|
|
func (e *watchdogEngine) SetFilter(filt *filter.Filter) {
|
|
e.watchdog("SetFilter", func() { e.wrap.SetFilter(filt) })
|
|
}
|
|
func (e *watchdogEngine) SetStatusCallback(cb StatusCallback) {
|
|
e.watchdog("SetStatusCallback", func() { e.wrap.SetStatusCallback(cb) })
|
|
}
|
|
func (e *watchdogEngine) UpdateStatus(sb *ipnstate.StatusBuilder) {
|
|
e.watchdog("UpdateStatus", func() { e.wrap.UpdateStatus(sb) })
|
|
}
|
|
func (e *watchdogEngine) SetNetInfoCallback(cb NetInfoCallback) {
|
|
e.watchdog("SetNetInfoCallback", func() { e.wrap.SetNetInfoCallback(cb) })
|
|
}
|
|
func (e *watchdogEngine) RequestStatus() {
|
|
e.watchdog("RequestStatus", func() { e.wrap.RequestStatus() })
|
|
}
|
|
func (e *watchdogEngine) LinkChange(isExpensive bool) {
|
|
e.watchdog("LinkChange", func() { e.wrap.LinkChange(isExpensive) })
|
|
}
|
|
func (e *watchdogEngine) SetDERPMap(m *tailcfg.DERPMap) {
|
|
e.watchdog("SetDERPMap", func() { e.wrap.SetDERPMap(m) })
|
|
}
|
|
func (e *watchdogEngine) Close() {
|
|
e.watchdog("Close", e.wrap.Close)
|
|
}
|
|
func (e *watchdogEngine) Wait() {
|
|
e.wrap.Wait()
|
|
}
|