mirror of
https://github.com/tailscale/tailscale.git
synced 2025-10-04 20:12:16 +02:00
health: make it omittable
Saves 86 KB. And stop depending on expvar and usermetrics when disabled, in prep to removing all the expvar/metrics/tsweb stuff. Updates #12614 Change-Id: I35d2479ddd1d39b615bab32b1fa940ae8cbf9b11 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
9c3aec58ba
commit
447cbdd1d0
@ -741,7 +741,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/
|
||||
tailscale.com/logpolicy from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/logtail from tailscale.com/control/controlclient+
|
||||
tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+
|
||||
tailscale.com/metrics from tailscale.com/health+
|
||||
tailscale.com/metrics from tailscale.com/net/tstun+
|
||||
tailscale.com/net/ace from tailscale.com/control/controlhttp
|
||||
tailscale.com/net/bakedroots from tailscale.com/net/tlsdial+
|
||||
💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock
|
||||
|
@ -112,7 +112,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
||||
tailscale.com/ipn/ipnstate from tailscale.com/client/local+
|
||||
tailscale.com/kube/kubetypes from tailscale.com/envknob
|
||||
tailscale.com/licenses from tailscale.com/client/web+
|
||||
tailscale.com/metrics from tailscale.com/health+
|
||||
tailscale.com/metrics from tailscale.com/tsweb+
|
||||
tailscale.com/net/ace from tailscale.com/cmd/tailscale/cli+
|
||||
tailscale.com/net/bakedroots from tailscale.com/net/tlsdial
|
||||
tailscale.com/net/captivedetection from tailscale.com/net/netcheck
|
||||
|
@ -76,7 +76,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/logpolicy from tailscale.com/cmd/tailscaled+
|
||||
tailscale.com/logtail from tailscale.com/cmd/tailscaled+
|
||||
tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+
|
||||
tailscale.com/metrics from tailscale.com/health+
|
||||
tailscale.com/metrics from tailscale.com/net/tstun+
|
||||
tailscale.com/net/ace from tailscale.com/control/controlhttp
|
||||
tailscale.com/net/bakedroots from tailscale.com/net/tlsdial
|
||||
💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock
|
||||
@ -179,7 +179,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/util/syspolicy/policyclient from tailscale.com/cmd/tailscaled+
|
||||
tailscale.com/util/syspolicy/ptype from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/util/testenv from tailscale.com/control/controlclient+
|
||||
tailscale.com/util/usermetric from tailscale.com/health+
|
||||
tailscale.com/util/usermetric from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/util/vizerror from tailscale.com/tailcfg+
|
||||
tailscale.com/util/winutil from tailscale.com/ipn/ipnauth
|
||||
tailscale.com/util/zstdframe from tailscale.com/control/controlclient
|
||||
@ -324,7 +324,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
encoding/json from expvar+
|
||||
encoding/pem from crypto/tls+
|
||||
errors from bufio+
|
||||
expvar from tailscale.com/health+
|
||||
expvar from tailscale.com/metrics+
|
||||
flag from tailscale.com/cmd/tailscaled+
|
||||
fmt from compress/flate+
|
||||
hash from crypto+
|
||||
|
@ -99,7 +99,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/logpolicy from tailscale.com/cmd/tailscaled+
|
||||
tailscale.com/logtail from tailscale.com/cmd/tailscaled+
|
||||
tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+
|
||||
tailscale.com/metrics from tailscale.com/health+
|
||||
tailscale.com/metrics from tailscale.com/net/tstun+
|
||||
tailscale.com/net/ace from tailscale.com/control/controlhttp+
|
||||
tailscale.com/net/bakedroots from tailscale.com/net/tlsdial
|
||||
💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock
|
||||
@ -206,7 +206,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/util/syspolicy/policyclient from tailscale.com/cmd/tailscaled+
|
||||
tailscale.com/util/syspolicy/ptype from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/util/testenv from tailscale.com/control/controlclient+
|
||||
tailscale.com/util/usermetric from tailscale.com/health+
|
||||
tailscale.com/util/usermetric from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/util/vizerror from tailscale.com/tailcfg+
|
||||
tailscale.com/util/winutil from tailscale.com/ipn/ipnauth
|
||||
tailscale.com/util/zstdframe from tailscale.com/control/controlclient
|
||||
@ -353,7 +353,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
encoding/json from expvar+
|
||||
encoding/pem from crypto/tls+
|
||||
errors from bufio+
|
||||
expvar from tailscale.com/health+
|
||||
expvar from tailscale.com/metrics+
|
||||
flag from tailscale.com/cmd/tailscaled+
|
||||
fmt from compress/flate+
|
||||
hash from crypto+
|
||||
|
@ -321,7 +321,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/logpolicy from tailscale.com/cmd/tailscaled+
|
||||
tailscale.com/logtail from tailscale.com/cmd/tailscaled+
|
||||
tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+
|
||||
tailscale.com/metrics from tailscale.com/health+
|
||||
tailscale.com/metrics from tailscale.com/net/tstun+
|
||||
tailscale.com/net/ace from tailscale.com/control/controlhttp
|
||||
tailscale.com/net/bakedroots from tailscale.com/net/tlsdial+
|
||||
💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock+
|
||||
|
@ -169,7 +169,7 @@ tailscale.com/cmd/tsidp dependencies: (generated by github.com/tailscale/depawar
|
||||
tailscale.com/logpolicy from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/logtail from tailscale.com/control/controlclient+
|
||||
tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+
|
||||
tailscale.com/metrics from tailscale.com/health+
|
||||
tailscale.com/metrics from tailscale.com/net/tstun+
|
||||
tailscale.com/net/ace from tailscale.com/control/controlhttp
|
||||
tailscale.com/net/bakedroots from tailscale.com/ipn/ipnlocal+
|
||||
💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock
|
||||
|
13
feature/buildfeatures/feature_health_disabled.go
Normal file
13
feature/buildfeatures/feature_health_disabled.go
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Code generated by gen.go; DO NOT EDIT.
|
||||
|
||||
//go:build ts_omit_health
|
||||
|
||||
package buildfeatures
|
||||
|
||||
// HasHealth is whether the binary was built with support for modular feature "Health checking support".
|
||||
// Specifically, it's whether the binary was NOT built with the "ts_omit_health" build tag.
|
||||
// It's a const so it can be used for dead code elimination.
|
||||
const HasHealth = false
|
13
feature/buildfeatures/feature_health_enabled.go
Normal file
13
feature/buildfeatures/feature_health_enabled.go
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Code generated by gen.go; DO NOT EDIT.
|
||||
|
||||
//go:build !ts_omit_health
|
||||
|
||||
package buildfeatures
|
||||
|
||||
// HasHealth is whether the binary was built with support for modular feature "Health checking support".
|
||||
// Specifically, it's whether the binary was NOT built with the "ts_omit_health" build tag.
|
||||
// It's a const so it can be used for dead code elimination.
|
||||
const HasHealth = true
|
@ -150,6 +150,7 @@ var Features = map[FeatureTag]FeatureMeta{
|
||||
Desc: "Generic Receive Offload support (performance)",
|
||||
Deps: []FeatureTag{"netstack"},
|
||||
},
|
||||
"health": {Sym: "Health", Desc: "Health checking support"},
|
||||
"hujsonconf": {Sym: "HuJSONConf", Desc: "HuJSON config file support"},
|
||||
"iptables": {Sym: "IPTables", Desc: "Linux iptables support"},
|
||||
"kube": {Sym: "Kube", Desc: "Kubernetes integration"},
|
||||
|
@ -8,7 +8,6 @@ package health
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"expvar"
|
||||
"fmt"
|
||||
"maps"
|
||||
"net/http"
|
||||
@ -20,14 +19,13 @@ import (
|
||||
"time"
|
||||
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/metrics"
|
||||
"tailscale.com/feature/buildfeatures"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/tstime"
|
||||
"tailscale.com/types/opt"
|
||||
"tailscale.com/util/cibuild"
|
||||
"tailscale.com/util/eventbus"
|
||||
"tailscale.com/util/mak"
|
||||
"tailscale.com/util/usermetric"
|
||||
"tailscale.com/version"
|
||||
)
|
||||
|
||||
@ -132,12 +130,15 @@ type Tracker struct {
|
||||
lastLoginErr error
|
||||
localLogConfigErr error
|
||||
tlsConnectionErrors map[string]error // map[ServerName]error
|
||||
metricHealthMessage *metrics.MultiLabelMap[metricHealthMessageLabel]
|
||||
metricHealthMessage any // nil or *metrics.MultiLabelMap[metricHealthMessageLabel]
|
||||
}
|
||||
|
||||
// NewTracker contructs a new [Tracker] and attaches the given eventbus.
|
||||
// NewTracker will panic is no eventbus is given.
|
||||
func NewTracker(bus *eventbus.Bus) *Tracker {
|
||||
if !buildfeatures.HasHealth {
|
||||
return &Tracker{}
|
||||
}
|
||||
if bus == nil {
|
||||
panic("no eventbus set")
|
||||
}
|
||||
@ -221,6 +222,9 @@ const legacyErrorArgKey = "LegacyError"
|
||||
// temporarily (2024-06-14) while we migrate the old health infrastructure based
|
||||
// on Subsystems to the new Warnables architecture.
|
||||
func (s Subsystem) Warnable() *Warnable {
|
||||
if !buildfeatures.HasHealth {
|
||||
return &noopWarnable
|
||||
}
|
||||
w, ok := subsystemsWarnables[s]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("health: no Warnable for Subsystem %q", s))
|
||||
@ -230,10 +234,15 @@ func (s Subsystem) Warnable() *Warnable {
|
||||
|
||||
var registeredWarnables = map[WarnableCode]*Warnable{}
|
||||
|
||||
var noopWarnable Warnable
|
||||
|
||||
// Register registers a new Warnable with the health package and returns it.
|
||||
// Register panics if the Warnable was already registered, because Warnables
|
||||
// should be unique across the program.
|
||||
func Register(w *Warnable) *Warnable {
|
||||
if !buildfeatures.HasHealth {
|
||||
return &noopWarnable
|
||||
}
|
||||
if registeredWarnables[w.Code] != nil {
|
||||
panic(fmt.Sprintf("health: a Warnable with code %q was already registered", w.Code))
|
||||
}
|
||||
@ -245,6 +254,9 @@ func Register(w *Warnable) *Warnable {
|
||||
// unregister removes a Warnable from the health package. It should only be used
|
||||
// for testing purposes.
|
||||
func unregister(w *Warnable) {
|
||||
if !buildfeatures.HasHealth {
|
||||
return
|
||||
}
|
||||
if registeredWarnables[w.Code] == nil {
|
||||
panic(fmt.Sprintf("health: attempting to unregister Warnable %q that was not registered", w.Code))
|
||||
}
|
||||
@ -317,6 +329,9 @@ func StaticMessage(s string) func(Args) string {
|
||||
// some lost Tracker plumbing, we want to capture stack trace
|
||||
// samples when it occurs.
|
||||
func (t *Tracker) nil() bool {
|
||||
if !buildfeatures.HasHealth {
|
||||
return true
|
||||
}
|
||||
if t != nil {
|
||||
return false
|
||||
}
|
||||
@ -385,37 +400,10 @@ func (w *Warnable) IsVisible(ws *warningState, clockNow func() time.Time) bool {
|
||||
return clockNow().Sub(ws.BrokenSince) >= w.TimeToVisible
|
||||
}
|
||||
|
||||
// SetMetricsRegistry sets up the metrics for the Tracker. It takes
|
||||
// a usermetric.Registry and registers the metrics there.
|
||||
func (t *Tracker) SetMetricsRegistry(reg *usermetric.Registry) {
|
||||
if reg == nil || t.metricHealthMessage != nil {
|
||||
return
|
||||
}
|
||||
|
||||
t.metricHealthMessage = usermetric.NewMultiLabelMapWithRegistry[metricHealthMessageLabel](
|
||||
reg,
|
||||
"tailscaled_health_messages",
|
||||
"gauge",
|
||||
"Number of health messages broken down by type.",
|
||||
)
|
||||
|
||||
t.metricHealthMessage.Set(metricHealthMessageLabel{
|
||||
Type: MetricLabelWarning,
|
||||
}, expvar.Func(func() any {
|
||||
if t.nil() {
|
||||
return 0
|
||||
}
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
t.updateBuiltinWarnablesLocked()
|
||||
return int64(len(t.stringsLocked()))
|
||||
}))
|
||||
}
|
||||
|
||||
// IsUnhealthy reports whether the current state is unhealthy because the given
|
||||
// warnable is set.
|
||||
func (t *Tracker) IsUnhealthy(w *Warnable) bool {
|
||||
if t.nil() {
|
||||
if !buildfeatures.HasHealth || t.nil() {
|
||||
return false
|
||||
}
|
||||
t.mu.Lock()
|
||||
@ -429,7 +417,7 @@ func (t *Tracker) IsUnhealthy(w *Warnable) bool {
|
||||
// SetUnhealthy takes ownership of args. The args can be nil if no additional information is
|
||||
// needed for the unhealthy state.
|
||||
func (t *Tracker) SetUnhealthy(w *Warnable, args Args) {
|
||||
if t.nil() {
|
||||
if !buildfeatures.HasHealth || t.nil() {
|
||||
return
|
||||
}
|
||||
t.mu.Lock()
|
||||
@ -438,7 +426,7 @@ func (t *Tracker) SetUnhealthy(w *Warnable, args Args) {
|
||||
}
|
||||
|
||||
func (t *Tracker) setUnhealthyLocked(w *Warnable, args Args) {
|
||||
if w == nil {
|
||||
if !buildfeatures.HasHealth || w == nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -489,7 +477,7 @@ func (t *Tracker) setUnhealthyLocked(w *Warnable, args Args) {
|
||||
|
||||
// SetHealthy removes any warningState for the given Warnable.
|
||||
func (t *Tracker) SetHealthy(w *Warnable) {
|
||||
if t.nil() {
|
||||
if !buildfeatures.HasHealth || t.nil() {
|
||||
return
|
||||
}
|
||||
t.mu.Lock()
|
||||
@ -498,7 +486,7 @@ func (t *Tracker) SetHealthy(w *Warnable) {
|
||||
}
|
||||
|
||||
func (t *Tracker) setHealthyLocked(w *Warnable) {
|
||||
if t.warnableVal[w] == nil {
|
||||
if !buildfeatures.HasHealth || t.warnableVal[w] == nil {
|
||||
// Nothing to remove
|
||||
return
|
||||
}
|
||||
@ -1009,7 +997,7 @@ func (t *Tracker) OverallError() error {
|
||||
// each Warning to show a localized version of them instead. This function is
|
||||
// here for legacy compatibility purposes and is deprecated.
|
||||
func (t *Tracker) Strings() []string {
|
||||
if t.nil() {
|
||||
if !buildfeatures.HasHealth || t.nil() {
|
||||
return nil
|
||||
}
|
||||
t.mu.Lock()
|
||||
@ -1018,6 +1006,9 @@ func (t *Tracker) Strings() []string {
|
||||
}
|
||||
|
||||
func (t *Tracker) stringsLocked() []string {
|
||||
if !buildfeatures.HasHealth {
|
||||
return nil
|
||||
}
|
||||
result := []string{}
|
||||
for w, ws := range t.warnableVal {
|
||||
if !w.IsVisible(ws, t.now) {
|
||||
@ -1078,6 +1069,9 @@ var fakeErrForTesting = envknob.RegisterString("TS_DEBUG_FAKE_HEALTH_ERROR")
|
||||
// updateBuiltinWarnablesLocked performs a number of checks on the state of the backend,
|
||||
// and adds/removes Warnings from the Tracker as needed.
|
||||
func (t *Tracker) updateBuiltinWarnablesLocked() {
|
||||
if !buildfeatures.HasHealth {
|
||||
return
|
||||
}
|
||||
t.updateWarmingUpWarnableLocked()
|
||||
|
||||
if w, show := t.showUpdateWarnable(); show {
|
||||
@ -1316,11 +1310,17 @@ func (s *ReceiveFuncStats) Name() string {
|
||||
}
|
||||
|
||||
func (s *ReceiveFuncStats) Enter() {
|
||||
if !buildfeatures.HasHealth {
|
||||
return
|
||||
}
|
||||
s.numCalls.Add(1)
|
||||
s.inCall.Store(true)
|
||||
}
|
||||
|
||||
func (s *ReceiveFuncStats) Exit() {
|
||||
if !buildfeatures.HasHealth {
|
||||
return
|
||||
}
|
||||
s.inCall.Store(false)
|
||||
}
|
||||
|
||||
@ -1329,7 +1329,7 @@ func (s *ReceiveFuncStats) Exit() {
|
||||
//
|
||||
// If t is nil, it returns nil.
|
||||
func (t *Tracker) ReceiveFuncStats(which ReceiveFunc) *ReceiveFuncStats {
|
||||
if t == nil {
|
||||
if !buildfeatures.HasHealth || t == nil {
|
||||
return nil
|
||||
}
|
||||
t.initOnce.Do(t.doOnceInit)
|
||||
@ -1337,6 +1337,9 @@ func (t *Tracker) ReceiveFuncStats(which ReceiveFunc) *ReceiveFuncStats {
|
||||
}
|
||||
|
||||
func (t *Tracker) doOnceInit() {
|
||||
if !buildfeatures.HasHealth {
|
||||
return
|
||||
}
|
||||
for i := range t.MagicSockReceiveFuncs {
|
||||
f := &t.MagicSockReceiveFuncs[i]
|
||||
f.name = (ReceiveFunc(i)).String()
|
||||
@ -1385,10 +1388,3 @@ func (t *Tracker) LastNoiseDialWasRecent() bool {
|
||||
t.lastNoiseDial = now
|
||||
return dur < 2*time.Minute
|
||||
}
|
||||
|
||||
const MetricLabelWarning = "warning"
|
||||
|
||||
type metricHealthMessageLabel struct {
|
||||
// TODO: break down by warnable.severity as well?
|
||||
Type string
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"tailscale.com/metrics"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/tstest"
|
||||
"tailscale.com/tstime"
|
||||
@ -497,7 +498,11 @@ func TestHealthMetric(t *testing.T) {
|
||||
tr.applyUpdates = tt.apply
|
||||
tr.latestVersion = tt.cv
|
||||
tr.SetMetricsRegistry(&usermetric.Registry{})
|
||||
if val := tr.metricHealthMessage.Get(metricHealthMessageLabel{Type: MetricLabelWarning}).String(); val != strconv.Itoa(tt.wantMetricCount) {
|
||||
m, ok := tr.metricHealthMessage.(*metrics.MultiLabelMap[metricHealthMessageLabel])
|
||||
if !ok {
|
||||
t.Fatal("metricHealthMessage has wrong type or is nil")
|
||||
}
|
||||
if val := m.Get(metricHealthMessageLabel{Type: MetricLabelWarning}).String(); val != strconv.Itoa(tt.wantMetricCount) {
|
||||
t.Fatalf("metric value: %q, want: %q", val, strconv.Itoa(tt.wantMetricCount))
|
||||
}
|
||||
for _, w := range tr.CurrentState().Warnings {
|
||||
@ -634,7 +639,11 @@ func TestControlHealth(t *testing.T) {
|
||||
var r usermetric.Registry
|
||||
ht.SetMetricsRegistry(&r)
|
||||
|
||||
got := ht.metricHealthMessage.Get(metricHealthMessageLabel{
|
||||
m, ok := ht.metricHealthMessage.(*metrics.MultiLabelMap[metricHealthMessageLabel])
|
||||
if !ok {
|
||||
t.Fatal("metricHealthMessage has wrong type or is nil")
|
||||
}
|
||||
got := m.Get(metricHealthMessageLabel{
|
||||
Type: MetricLabelWarning,
|
||||
}).String()
|
||||
want := strconv.Itoa(
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"tailscale.com/feature/buildfeatures"
|
||||
"tailscale.com/tailcfg"
|
||||
)
|
||||
|
||||
@ -120,7 +121,7 @@ func (w *Warnable) unhealthyState(ws *warningState) *UnhealthyState {
|
||||
// The returned State is a snapshot of shared memory, and the caller should not
|
||||
// mutate the returned value.
|
||||
func (t *Tracker) CurrentState() *State {
|
||||
if t.nil() {
|
||||
if !buildfeatures.HasHealth || t.nil() {
|
||||
return &State{}
|
||||
}
|
||||
|
||||
|
52
health/usermetrics.go
Normal file
52
health/usermetrics.go
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !ts_omit_health && !ts_omit_usermetrics
|
||||
|
||||
package health
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
|
||||
"tailscale.com/feature/buildfeatures"
|
||||
"tailscale.com/util/usermetric"
|
||||
)
|
||||
|
||||
const MetricLabelWarning = "warning"
|
||||
|
||||
type metricHealthMessageLabel struct {
|
||||
// TODO: break down by warnable.severity as well?
|
||||
Type string
|
||||
}
|
||||
|
||||
// SetMetricsRegistry sets up the metrics for the Tracker. It takes
|
||||
// a usermetric.Registry and registers the metrics there.
|
||||
func (t *Tracker) SetMetricsRegistry(reg *usermetric.Registry) {
|
||||
if !buildfeatures.HasHealth {
|
||||
return
|
||||
}
|
||||
|
||||
if reg == nil || t.metricHealthMessage != nil {
|
||||
return
|
||||
}
|
||||
|
||||
m := usermetric.NewMultiLabelMapWithRegistry[metricHealthMessageLabel](
|
||||
reg,
|
||||
"tailscaled_health_messages",
|
||||
"gauge",
|
||||
"Number of health messages broken down by type.",
|
||||
)
|
||||
|
||||
m.Set(metricHealthMessageLabel{
|
||||
Type: MetricLabelWarning,
|
||||
}, expvar.Func(func() any {
|
||||
if t.nil() {
|
||||
return 0
|
||||
}
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
t.updateBuiltinWarnablesLocked()
|
||||
return int64(len(t.stringsLocked()))
|
||||
}))
|
||||
t.metricHealthMessage = m
|
||||
}
|
8
health/usermetrics_omit.go
Normal file
8
health/usermetrics_omit.go
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build ts_omit_health || ts_omit_usermetrics
|
||||
|
||||
package health
|
||||
|
||||
func (t *Tracker) SetMetricsRegistry(any) {}
|
@ -8,234 +8,278 @@ import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"tailscale.com/feature/buildfeatures"
|
||||
"tailscale.com/version"
|
||||
)
|
||||
|
||||
func condRegister(f func() *Warnable) *Warnable {
|
||||
if !buildfeatures.HasHealth {
|
||||
return nil
|
||||
}
|
||||
return f()
|
||||
}
|
||||
|
||||
/**
|
||||
This file contains definitions for the Warnables maintained within this `health` package.
|
||||
*/
|
||||
|
||||
// updateAvailableWarnable is a Warnable that warns the user that an update is available.
|
||||
var updateAvailableWarnable = Register(&Warnable{
|
||||
Code: "update-available",
|
||||
Title: "Update available",
|
||||
Severity: SeverityLow,
|
||||
Text: func(args Args) string {
|
||||
if version.IsMacAppStore() || version.IsAppleTV() || version.IsMacSys() || version.IsWindowsGUI() || runtime.GOOS == "android" {
|
||||
return fmt.Sprintf("An update from version %s to %s is available.", args[ArgCurrentVersion], args[ArgAvailableVersion])
|
||||
} else {
|
||||
return fmt.Sprintf("An update from version %s to %s is available. Run `tailscale update` or `tailscale set --auto-update` to update now.", args[ArgCurrentVersion], args[ArgAvailableVersion])
|
||||
}
|
||||
},
|
||||
var updateAvailableWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "update-available",
|
||||
Title: "Update available",
|
||||
Severity: SeverityLow,
|
||||
Text: func(args Args) string {
|
||||
if version.IsMacAppStore() || version.IsAppleTV() || version.IsMacSys() || version.IsWindowsGUI() || runtime.GOOS == "android" {
|
||||
return fmt.Sprintf("An update from version %s to %s is available.", args[ArgCurrentVersion], args[ArgAvailableVersion])
|
||||
} else {
|
||||
return fmt.Sprintf("An update from version %s to %s is available. Run `tailscale update` or `tailscale set --auto-update` to update now.", args[ArgCurrentVersion], args[ArgAvailableVersion])
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// securityUpdateAvailableWarnable is a Warnable that warns the user that an important security update is available.
|
||||
var securityUpdateAvailableWarnable = Register(&Warnable{
|
||||
Code: "security-update-available",
|
||||
Title: "Security update available",
|
||||
Severity: SeverityMedium,
|
||||
Text: func(args Args) string {
|
||||
if version.IsMacAppStore() || version.IsAppleTV() || version.IsMacSys() || version.IsWindowsGUI() || runtime.GOOS == "android" {
|
||||
return fmt.Sprintf("A security update from version %s to %s is available.", args[ArgCurrentVersion], args[ArgAvailableVersion])
|
||||
} else {
|
||||
return fmt.Sprintf("A security update from version %s to %s is available. Run `tailscale update` or `tailscale set --auto-update` to update now.", args[ArgCurrentVersion], args[ArgAvailableVersion])
|
||||
}
|
||||
},
|
||||
var securityUpdateAvailableWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "security-update-available",
|
||||
Title: "Security update available",
|
||||
Severity: SeverityMedium,
|
||||
Text: func(args Args) string {
|
||||
if version.IsMacAppStore() || version.IsAppleTV() || version.IsMacSys() || version.IsWindowsGUI() || runtime.GOOS == "android" {
|
||||
return fmt.Sprintf("A security update from version %s to %s is available.", args[ArgCurrentVersion], args[ArgAvailableVersion])
|
||||
} else {
|
||||
return fmt.Sprintf("A security update from version %s to %s is available. Run `tailscale update` or `tailscale set --auto-update` to update now.", args[ArgCurrentVersion], args[ArgAvailableVersion])
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// unstableWarnable is a Warnable that warns the user that they are using an unstable version of Tailscale
|
||||
// so they won't be surprised by all the issues that may arise.
|
||||
var unstableWarnable = Register(&Warnable{
|
||||
Code: "is-using-unstable-version",
|
||||
Title: "Using an unstable version",
|
||||
Severity: SeverityLow,
|
||||
Text: StaticMessage("This is an unstable version of Tailscale meant for testing and development purposes. Please report any issues to Tailscale."),
|
||||
var unstableWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "is-using-unstable-version",
|
||||
Title: "Using an unstable version",
|
||||
Severity: SeverityLow,
|
||||
Text: StaticMessage("This is an unstable version of Tailscale meant for testing and development purposes. Please report any issues to Tailscale."),
|
||||
}
|
||||
})
|
||||
|
||||
// NetworkStatusWarnable is a Warnable that warns the user that the network is down.
|
||||
var NetworkStatusWarnable = Register(&Warnable{
|
||||
Code: "network-status",
|
||||
Title: "Network down",
|
||||
Severity: SeverityMedium,
|
||||
Text: StaticMessage("Tailscale cannot connect because the network is down. Check your Internet connection."),
|
||||
ImpactsConnectivity: true,
|
||||
TimeToVisible: 5 * time.Second,
|
||||
var NetworkStatusWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "network-status",
|
||||
Title: "Network down",
|
||||
Severity: SeverityMedium,
|
||||
Text: StaticMessage("Tailscale cannot connect because the network is down. Check your Internet connection."),
|
||||
ImpactsConnectivity: true,
|
||||
TimeToVisible: 5 * time.Second,
|
||||
}
|
||||
})
|
||||
|
||||
// IPNStateWarnable is a Warnable that warns the user that Tailscale is stopped.
|
||||
var IPNStateWarnable = Register(&Warnable{
|
||||
Code: "wantrunning-false",
|
||||
Title: "Tailscale off",
|
||||
Severity: SeverityLow,
|
||||
Text: StaticMessage("Tailscale is stopped."),
|
||||
var IPNStateWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "wantrunning-false",
|
||||
Title: "Tailscale off",
|
||||
Severity: SeverityLow,
|
||||
Text: StaticMessage("Tailscale is stopped."),
|
||||
}
|
||||
})
|
||||
|
||||
// localLogWarnable is a Warnable that warns the user that the local log is misconfigured.
|
||||
var localLogWarnable = Register(&Warnable{
|
||||
Code: "local-log-config-error",
|
||||
Title: "Local log misconfiguration",
|
||||
Severity: SeverityLow,
|
||||
Text: func(args Args) string {
|
||||
return fmt.Sprintf("The local log is misconfigured: %v", args[ArgError])
|
||||
},
|
||||
var localLogWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "local-log-config-error",
|
||||
Title: "Local log misconfiguration",
|
||||
Severity: SeverityLow,
|
||||
Text: func(args Args) string {
|
||||
return fmt.Sprintf("The local log is misconfigured: %v", args[ArgError])
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// LoginStateWarnable is a Warnable that warns the user that they are logged out,
|
||||
// and provides the last login error if available.
|
||||
var LoginStateWarnable = Register(&Warnable{
|
||||
Code: "login-state",
|
||||
Title: "Logged out",
|
||||
Severity: SeverityMedium,
|
||||
Text: func(args Args) string {
|
||||
if args[ArgError] != "" {
|
||||
return fmt.Sprintf("You are logged out. The last login error was: %v", args[ArgError])
|
||||
} else {
|
||||
return "You are logged out."
|
||||
}
|
||||
},
|
||||
DependsOn: []*Warnable{IPNStateWarnable},
|
||||
var LoginStateWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "login-state",
|
||||
Title: "Logged out",
|
||||
Severity: SeverityMedium,
|
||||
Text: func(args Args) string {
|
||||
if args[ArgError] != "" {
|
||||
return fmt.Sprintf("You are logged out. The last login error was: %v", args[ArgError])
|
||||
} else {
|
||||
return "You are logged out."
|
||||
}
|
||||
},
|
||||
DependsOn: []*Warnable{IPNStateWarnable},
|
||||
}
|
||||
})
|
||||
|
||||
// notInMapPollWarnable is a Warnable that warns the user that we are using a stale network map.
|
||||
var notInMapPollWarnable = Register(&Warnable{
|
||||
Code: "not-in-map-poll",
|
||||
Title: "Out of sync",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{NetworkStatusWarnable, IPNStateWarnable},
|
||||
Text: StaticMessage("Unable to connect to the Tailscale coordination server to synchronize the state of your tailnet. Peer reachability might degrade over time."),
|
||||
// 8 minutes reflects a maximum maintenance window for the coordination server.
|
||||
TimeToVisible: 8 * time.Minute,
|
||||
var notInMapPollWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "not-in-map-poll",
|
||||
Title: "Out of sync",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{NetworkStatusWarnable, IPNStateWarnable},
|
||||
Text: StaticMessage("Unable to connect to the Tailscale coordination server to synchronize the state of your tailnet. Peer reachability might degrade over time."),
|
||||
// 8 minutes reflects a maximum maintenance window for the coordination server.
|
||||
TimeToVisible: 8 * time.Minute,
|
||||
}
|
||||
})
|
||||
|
||||
// noDERPHomeWarnable is a Warnable that warns the user that Tailscale doesn't have a home DERP.
|
||||
var noDERPHomeWarnable = Register(&Warnable{
|
||||
Code: "no-derp-home",
|
||||
Title: "No home relay server",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{NetworkStatusWarnable},
|
||||
Text: StaticMessage("Tailscale could not connect to any relay server. Check your Internet connection."),
|
||||
ImpactsConnectivity: true,
|
||||
TimeToVisible: 10 * time.Second,
|
||||
var noDERPHomeWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "no-derp-home",
|
||||
Title: "No home relay server",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{NetworkStatusWarnable},
|
||||
Text: StaticMessage("Tailscale could not connect to any relay server. Check your Internet connection."),
|
||||
ImpactsConnectivity: true,
|
||||
TimeToVisible: 10 * time.Second,
|
||||
}
|
||||
})
|
||||
|
||||
// noDERPConnectionWarnable is a Warnable that warns the user that Tailscale couldn't connect to a specific DERP server.
|
||||
var noDERPConnectionWarnable = Register(&Warnable{
|
||||
Code: "no-derp-connection",
|
||||
Title: "Relay server unavailable",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{
|
||||
NetworkStatusWarnable,
|
||||
var noDERPConnectionWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "no-derp-connection",
|
||||
Title: "Relay server unavailable",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{
|
||||
NetworkStatusWarnable,
|
||||
|
||||
// Technically noDERPConnectionWarnable could be used to warn about
|
||||
// failure to connect to a specific DERP server (e.g. your home is derp1
|
||||
// but you're trying to connect to a peer's derp4 and are unable) but as
|
||||
// of 2024-09-25 we only use this for connecting to your home DERP, so
|
||||
// we depend on noDERPHomeWarnable which is the ability to figure out
|
||||
// what your DERP home even is.
|
||||
noDERPHomeWarnable,
|
||||
},
|
||||
Text: func(args Args) string {
|
||||
if n := args[ArgDERPRegionName]; n != "" {
|
||||
return fmt.Sprintf("Tailscale could not connect to the '%s' relay server. Your Internet connection might be down, or the server might be temporarily unavailable.", n)
|
||||
} else {
|
||||
return fmt.Sprintf("Tailscale could not connect to the relay server with ID '%s'. Your Internet connection might be down, or the server might be temporarily unavailable.", args[ArgDERPRegionID])
|
||||
}
|
||||
},
|
||||
ImpactsConnectivity: true,
|
||||
TimeToVisible: 10 * time.Second,
|
||||
// Technically noDERPConnectionWarnable could be used to warn about
|
||||
// failure to connect to a specific DERP server (e.g. your home is derp1
|
||||
// but you're trying to connect to a peer's derp4 and are unable) but as
|
||||
// of 2024-09-25 we only use this for connecting to your home DERP, so
|
||||
// we depend on noDERPHomeWarnable which is the ability to figure out
|
||||
// what your DERP home even is.
|
||||
noDERPHomeWarnable,
|
||||
},
|
||||
Text: func(args Args) string {
|
||||
if n := args[ArgDERPRegionName]; n != "" {
|
||||
return fmt.Sprintf("Tailscale could not connect to the '%s' relay server. Your Internet connection might be down, or the server might be temporarily unavailable.", n)
|
||||
} else {
|
||||
return fmt.Sprintf("Tailscale could not connect to the relay server with ID '%s'. Your Internet connection might be down, or the server might be temporarily unavailable.", args[ArgDERPRegionID])
|
||||
}
|
||||
},
|
||||
ImpactsConnectivity: true,
|
||||
TimeToVisible: 10 * time.Second,
|
||||
}
|
||||
})
|
||||
|
||||
// derpTimeoutWarnable is a Warnable that warns the user that Tailscale hasn't
|
||||
// heard from the home DERP region for a while.
|
||||
var derpTimeoutWarnable = Register(&Warnable{
|
||||
Code: "derp-timed-out",
|
||||
Title: "Relay server timed out",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{
|
||||
NetworkStatusWarnable,
|
||||
noDERPConnectionWarnable, // don't warn about it being stalled if we're not connected
|
||||
noDERPHomeWarnable, // same reason as noDERPConnectionWarnable's dependency
|
||||
},
|
||||
Text: func(args Args) string {
|
||||
if n := args[ArgDERPRegionName]; n != "" {
|
||||
return fmt.Sprintf("Tailscale hasn't heard from the '%s' relay server in %v. The server might be temporarily unavailable, or your Internet connection might be down.", n, args[ArgDuration])
|
||||
} else {
|
||||
return fmt.Sprintf("Tailscale hasn't heard from the home relay server (region ID '%v') in %v. The server might be temporarily unavailable, or your Internet connection might be down.", args[ArgDERPRegionID], args[ArgDuration])
|
||||
}
|
||||
},
|
||||
var derpTimeoutWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "derp-timed-out",
|
||||
Title: "Relay server timed out",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{
|
||||
NetworkStatusWarnable,
|
||||
noDERPConnectionWarnable, // don't warn about it being stalled if we're not connected
|
||||
noDERPHomeWarnable, // same reason as noDERPConnectionWarnable's dependency
|
||||
},
|
||||
Text: func(args Args) string {
|
||||
if n := args[ArgDERPRegionName]; n != "" {
|
||||
return fmt.Sprintf("Tailscale hasn't heard from the '%s' relay server in %v. The server might be temporarily unavailable, or your Internet connection might be down.", n, args[ArgDuration])
|
||||
} else {
|
||||
return fmt.Sprintf("Tailscale hasn't heard from the home relay server (region ID '%v') in %v. The server might be temporarily unavailable, or your Internet connection might be down.", args[ArgDERPRegionID], args[ArgDuration])
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// derpRegionErrorWarnable is a Warnable that warns the user that a DERP region is reporting an issue.
|
||||
var derpRegionErrorWarnable = Register(&Warnable{
|
||||
Code: "derp-region-error",
|
||||
Title: "Relay server error",
|
||||
Severity: SeverityLow,
|
||||
DependsOn: []*Warnable{NetworkStatusWarnable},
|
||||
Text: func(args Args) string {
|
||||
return fmt.Sprintf("The relay server #%v is reporting an issue: %v", args[ArgDERPRegionID], args[ArgError])
|
||||
},
|
||||
var derpRegionErrorWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "derp-region-error",
|
||||
Title: "Relay server error",
|
||||
Severity: SeverityLow,
|
||||
DependsOn: []*Warnable{NetworkStatusWarnable},
|
||||
Text: func(args Args) string {
|
||||
return fmt.Sprintf("The relay server #%v is reporting an issue: %v", args[ArgDERPRegionID], args[ArgError])
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// noUDP4BindWarnable is a Warnable that warns the user that Tailscale couldn't listen for incoming UDP connections.
|
||||
var noUDP4BindWarnable = Register(&Warnable{
|
||||
Code: "no-udp4-bind",
|
||||
Title: "NAT traversal setup failure",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{NetworkStatusWarnable, IPNStateWarnable},
|
||||
Text: StaticMessage("Tailscale couldn't listen for incoming UDP connections."),
|
||||
ImpactsConnectivity: true,
|
||||
var noUDP4BindWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "no-udp4-bind",
|
||||
Title: "NAT traversal setup failure",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{NetworkStatusWarnable, IPNStateWarnable},
|
||||
Text: StaticMessage("Tailscale couldn't listen for incoming UDP connections."),
|
||||
ImpactsConnectivity: true,
|
||||
}
|
||||
})
|
||||
|
||||
// mapResponseTimeoutWarnable is a Warnable that warns the user that Tailscale hasn't received a network map from the coordination server in a while.
|
||||
var mapResponseTimeoutWarnable = Register(&Warnable{
|
||||
Code: "mapresponse-timeout",
|
||||
Title: "Network map response timeout",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{NetworkStatusWarnable, IPNStateWarnable},
|
||||
Text: func(args Args) string {
|
||||
return fmt.Sprintf("Tailscale hasn't received a network map from the coordination server in %s.", args[ArgDuration])
|
||||
},
|
||||
var mapResponseTimeoutWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "mapresponse-timeout",
|
||||
Title: "Network map response timeout",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{NetworkStatusWarnable, IPNStateWarnable},
|
||||
Text: func(args Args) string {
|
||||
return fmt.Sprintf("Tailscale hasn't received a network map from the coordination server in %s.", args[ArgDuration])
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// tlsConnectionFailedWarnable is a Warnable that warns the user that Tailscale could not establish an encrypted connection with a server.
|
||||
var tlsConnectionFailedWarnable = Register(&Warnable{
|
||||
Code: "tls-connection-failed",
|
||||
Title: "Encrypted connection failed",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{NetworkStatusWarnable},
|
||||
Text: func(args Args) string {
|
||||
return fmt.Sprintf("Tailscale could not establish an encrypted connection with '%q': %v", args[ArgServerName], args[ArgError])
|
||||
},
|
||||
var tlsConnectionFailedWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "tls-connection-failed",
|
||||
Title: "Encrypted connection failed",
|
||||
Severity: SeverityMedium,
|
||||
DependsOn: []*Warnable{NetworkStatusWarnable},
|
||||
Text: func(args Args) string {
|
||||
return fmt.Sprintf("Tailscale could not establish an encrypted connection with '%q': %v", args[ArgServerName], args[ArgError])
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// magicsockReceiveFuncWarnable is a Warnable that warns the user that one of the Magicsock functions is not running.
|
||||
var magicsockReceiveFuncWarnable = Register(&Warnable{
|
||||
Code: "magicsock-receive-func-error",
|
||||
Title: "MagicSock function not running",
|
||||
Severity: SeverityMedium,
|
||||
Text: func(args Args) string {
|
||||
return fmt.Sprintf("The MagicSock function %s is not running. You might experience connectivity issues.", args[ArgMagicsockFunctionName])
|
||||
},
|
||||
var magicsockReceiveFuncWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "magicsock-receive-func-error",
|
||||
Title: "MagicSock function not running",
|
||||
Severity: SeverityMedium,
|
||||
Text: func(args Args) string {
|
||||
return fmt.Sprintf("The MagicSock function %s is not running. You might experience connectivity issues.", args[ArgMagicsockFunctionName])
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// testWarnable is a Warnable that is used within this package for testing purposes only.
|
||||
var testWarnable = Register(&Warnable{
|
||||
Code: "test-warnable",
|
||||
Title: "Test warnable",
|
||||
Severity: SeverityLow,
|
||||
Text: func(args Args) string {
|
||||
return args[ArgError]
|
||||
},
|
||||
var testWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "test-warnable",
|
||||
Title: "Test warnable",
|
||||
Severity: SeverityLow,
|
||||
Text: func(args Args) string {
|
||||
return args[ArgError]
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// applyDiskConfigWarnable is a Warnable that warns the user that there was an error applying the envknob config stored on disk.
|
||||
var applyDiskConfigWarnable = Register(&Warnable{
|
||||
Code: "apply-disk-config",
|
||||
Title: "Could not apply configuration",
|
||||
Severity: SeverityMedium,
|
||||
Text: func(args Args) string {
|
||||
return fmt.Sprintf("An error occurred applying the Tailscale envknob configuration stored on disk: %v", args[ArgError])
|
||||
},
|
||||
var applyDiskConfigWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "apply-disk-config",
|
||||
Title: "Could not apply configuration",
|
||||
Severity: SeverityMedium,
|
||||
Text: func(args Args) string {
|
||||
return fmt.Sprintf("An error occurred applying the Tailscale envknob configuration stored on disk: %v", args[ArgError])
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// warmingUpWarnableDuration is the duration for which the warmingUpWarnable is reported by the backend after the user
|
||||
@ -245,9 +289,11 @@ const warmingUpWarnableDuration = 5 * time.Second
|
||||
// warmingUpWarnable is a Warnable that is reported by the backend when it is starting up, for a maximum time of
|
||||
// warmingUpWarnableDuration. The GUIs use the presence of this Warnable to prevent showing any other warnings until
|
||||
// the backend is fully started.
|
||||
var warmingUpWarnable = Register(&Warnable{
|
||||
Code: "warming-up",
|
||||
Title: "Tailscale is starting",
|
||||
Severity: SeverityLow,
|
||||
Text: StaticMessage("Tailscale is starting. Please wait."),
|
||||
var warmingUpWarnable = condRegister(func() *Warnable {
|
||||
return &Warnable{
|
||||
Code: "warming-up",
|
||||
Title: "Tailscale is starting",
|
||||
Severity: SeverityLow,
|
||||
Text: StaticMessage("Tailscale is starting. Please wait."),
|
||||
}
|
||||
})
|
||||
|
@ -165,7 +165,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware)
|
||||
tailscale.com/logpolicy from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/logtail from tailscale.com/control/controlclient+
|
||||
tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+
|
||||
tailscale.com/metrics from tailscale.com/health+
|
||||
tailscale.com/metrics from tailscale.com/net/tstun+
|
||||
tailscale.com/net/ace from tailscale.com/control/controlhttp
|
||||
tailscale.com/net/bakedroots from tailscale.com/ipn/ipnlocal+
|
||||
💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock
|
||||
|
@ -1710,7 +1710,7 @@ func (c *Conn) mkReceiveFunc(ruc *RebindingUDPConn, healthItem *health.ReceiveFu
|
||||
var epCache epAddrEndpointCache
|
||||
|
||||
return func(buffs [][]byte, sizes []int, eps []conn.Endpoint) (_ int, retErr error) {
|
||||
if healthItem != nil {
|
||||
if buildfeatures.HasHealth && healthItem != nil {
|
||||
healthItem.Enter()
|
||||
defer healthItem.Exit()
|
||||
defer func() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user