health, controlclient, ipn, magicsock: tell health package state of things

Not yet checking anything. Just plumbing states into the health package.

Updates #1505

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2021-02-24 21:29:51 -08:00
parent 770aa71ffb
commit ba8c6d0775
5 changed files with 126 additions and 2 deletions

View File

@@ -8,12 +8,28 @@ package health
import (
"sync"
"time"
"tailscale.com/tailcfg"
)
var (
mu sync.Mutex
// mu guards everything in this var block.
mu sync.Mutex
m = map[string]error{} // error key => err (or nil for no error)
watchers = map[*watchHandle]func(string, error){} // opt func to run if error state changes
inMapPoll bool
inMapPollSince time.Time
lastMapPollEndedAt time.Time
lastStreamedMapResponse time.Time
derpHomeRegion int
derpRegionConnected = map[int]bool{}
derpRegionLastFrame = map[int]time.Time{}
lastMapRequestHeard time.Time // time we got a 200 from control for a MapRequest
ipnState string
ipnWantRunning bool
)
type watchHandle byte
@@ -53,6 +69,7 @@ func set(key string, err error) {
if !ok && err == nil {
// Initial happy path.
m[key] = nil
selfCheckLocked()
return
}
if ok && (old == nil) == (err == nil) {
@@ -65,7 +82,88 @@ func set(key string, err error) {
return
}
m[key] = err
selfCheckLocked()
for _, cb := range watchers {
go cb(key, err)
}
}
// GotStreamedMapResponse notes that we got a tailcfg.MapResponse
// message in streaming mode, even if it's just a keep-alive message.
func GotStreamedMapResponse() {
mu.Lock()
defer mu.Unlock()
lastStreamedMapResponse = time.Now()
selfCheckLocked()
}
// SetInPollNetMap records that we're in
func SetInPollNetMap(v bool) {
mu.Lock()
defer mu.Unlock()
if v == inMapPoll {
return
}
inMapPoll = v
if v {
inMapPollSince = time.Now()
} else {
lastMapPollEndedAt = time.Now()
}
}
// SetMagicSockDERPHome notes what magicsock's view of its home DERP is.
func SetMagicSockDERPHome(region int) {
mu.Lock()
defer mu.Unlock()
derpHomeRegion = region
selfCheckLocked()
}
// NoteMapRequestHeard notes whenever we successfully sent a map request
// to control for which we received a 200 response.
func NoteMapRequestHeard(mr *tailcfg.MapRequest) {
mu.Lock()
defer mu.Unlock()
// TODO: extract mr.HostInfo.NetInfo.PreferredDERP, compare
// against SetMagicSockDERPHome and
// SetDERPRegionConnectedState
lastMapRequestHeard = time.Now()
selfCheckLocked()
}
func SetDERPRegionConnectedState(region int, connected bool) {
mu.Lock()
defer mu.Unlock()
derpRegionConnected[region] = connected
selfCheckLocked()
}
func NoteDERPRegionReceivedFrame(region int) {
mu.Lock()
defer mu.Unlock()
derpRegionLastFrame[region] = time.Now()
selfCheckLocked()
}
// state is an ipn.State.String() value: "Running", "Stopped", "NeedsLogin", etc.
func SetIPNState(state string, wantRunning bool) {
mu.Lock()
defer mu.Unlock()
ipnState = state
ipnWantRunning = wantRunning
selfCheckLocked()
}
func selfCheckLocked() {
// TODO: check states against each other.
// For staticcheck for now:
_ = inMapPollSince
_ = lastMapPollEndedAt
_ = lastStreamedMapResponse
_ = derpHomeRegion
_ = lastMapRequestHeard
_ = ipnState
_ = ipnWantRunning
}