Compare commits
1 Commits
knyar/inte
...
awly/hide-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b419eccbb |
@@ -17,6 +17,7 @@ import (
|
||||
"tailscale.com/client/web"
|
||||
"tailscale.com/clientupdate"
|
||||
"tailscale.com/cmd/tailscale/cli/ffcomplete"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/net/netutil"
|
||||
"tailscale.com/net/tsaddr"
|
||||
@@ -62,6 +63,7 @@ type setArgsT struct {
|
||||
snat bool
|
||||
statefulFiltering bool
|
||||
netfilterMode string
|
||||
hideHealthWarnings string
|
||||
}
|
||||
|
||||
func newSetFlagSet(goos string, setArgs *setArgsT) *flag.FlagSet {
|
||||
@@ -82,6 +84,7 @@ func newSetFlagSet(goos string, setArgs *setArgsT) *flag.FlagSet {
|
||||
setf.BoolVar(&setArgs.updateApply, "auto-update", false, "automatically update to the latest available version")
|
||||
setf.BoolVar(&setArgs.postureChecking, "posture-checking", false, hidden+"allow management plane to gather device posture information")
|
||||
setf.BoolVar(&setArgs.runWebClient, "webclient", false, "expose the web interface for managing this node over Tailscale at port 5252")
|
||||
setf.StringVar(&setArgs.hideHealthWarnings, "hide-health-warnings", "", fmt.Sprintf("a comma-separated list of health warnings to hide; known codes: %v", health.RegisteredCodes()))
|
||||
|
||||
ffcomplete.Flag(setf, "exit-node", func(args []string) ([]string, ffcomplete.ShellCompDirective, error) {
|
||||
st, err := localClient.Status(context.Background())
|
||||
@@ -179,7 +182,7 @@ func runSet(ctx context.Context, args []string) (retErr error) {
|
||||
}
|
||||
|
||||
warnOnAdvertiseRouts(ctx, &maskedPrefs.Prefs)
|
||||
var advertiseExitNodeSet, advertiseRoutesSet bool
|
||||
var advertiseExitNodeSet, advertiseRoutesSet, hideHealthWarningsSet bool
|
||||
setFlagSet.Visit(func(f *flag.Flag) {
|
||||
updateMaskedPrefsFromUpOrSetFlag(maskedPrefs, f.Name)
|
||||
switch f.Name {
|
||||
@@ -187,8 +190,17 @@ func runSet(ctx context.Context, args []string) (retErr error) {
|
||||
advertiseExitNodeSet = true
|
||||
case "advertise-routes":
|
||||
advertiseRoutesSet = true
|
||||
case "hide-health-warnings":
|
||||
hideHealthWarningsSet = true
|
||||
}
|
||||
})
|
||||
if hideHealthWarningsSet {
|
||||
var hide []health.WarnableCode
|
||||
for _, w := range strings.Split(setArgs.hideHealthWarnings, ",") {
|
||||
hide = append(hide, health.WarnableCode(strings.TrimSpace(w)))
|
||||
}
|
||||
maskedPrefs.Prefs.HideHealthWarnings = hide
|
||||
}
|
||||
if maskedPrefs.IsEmpty() {
|
||||
return flag.ErrHelp
|
||||
}
|
||||
|
||||
@@ -777,6 +777,7 @@ func init() {
|
||||
addPrefFlagMapping("auto-update", "AutoUpdate.Apply")
|
||||
addPrefFlagMapping("advertise-connector", "AppConnector")
|
||||
addPrefFlagMapping("posture-checking", "PostureChecking")
|
||||
addPrefFlagMapping("hide-health-warnings", "HideHealthWarnings")
|
||||
}
|
||||
|
||||
func addPrefFlagMapping(flagName string, prefNames ...string) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"slices"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -81,6 +82,8 @@ type Tracker struct {
|
||||
// pendingVisibleTimers contains timers for Warnables that are unhealthy, but are
|
||||
// not visible to the user yet, because they haven't been unhealthy for TimeToVisible
|
||||
pendingVisibleTimers map[*Warnable]*time.Timer
|
||||
// hideWarnables is a list of warnables to skip in Tracker output.
|
||||
hideWarnables []WarnableCode
|
||||
|
||||
// sysErr maps subsystems to their current error (or nil if the subsystem is healthy)
|
||||
// Deprecated: using Warnables should be preferred
|
||||
@@ -177,6 +180,11 @@ func Register(w *Warnable) *Warnable {
|
||||
return w
|
||||
}
|
||||
|
||||
// RegisteredCodes returns the list of all registered Warnable codes.
|
||||
func RegisteredCodes() []WarnableCode {
|
||||
return slices.Collect(maps.Keys(registeredWarnables))
|
||||
}
|
||||
|
||||
// unregister removes a Warnable from the health package. It should only be used
|
||||
// for testing purposes.
|
||||
func unregister(w *Warnable) {
|
||||
@@ -377,7 +385,7 @@ func (t *Tracker) setUnhealthyLocked(w *Warnable, args Args) {
|
||||
}
|
||||
prevWs := t.warnableVal[w]
|
||||
mak.Set(&t.warnableVal, w, ws)
|
||||
if !ws.Equal(prevWs) {
|
||||
if !ws.Equal(prevWs) && !slices.Contains(t.hideWarnables, w.Code) {
|
||||
for _, cb := range t.watchers {
|
||||
// If the Warnable has been unhealthy for more than its TimeToVisible, the callback should be
|
||||
// executed immediately. Otherwise, the callback should be enqueued to run once the Warnable
|
||||
@@ -883,6 +891,24 @@ func (t *Tracker) SetAutoUpdatePrefs(check bool, apply opt.Bool) {
|
||||
t.selfCheckLocked()
|
||||
}
|
||||
|
||||
// HideWarnables prevents the provided list of WarnableCodes from notifying
|
||||
// watchers or returning in any Tracker output if they become unhealthy. The
|
||||
// provided codes replace the previous codes.
|
||||
func (t *Tracker) HideWarnables(warnables []WarnableCode) {
|
||||
if t.nil() {
|
||||
return
|
||||
}
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
t.hideWarnables = warnables
|
||||
|
||||
for _, w := range t.warnables {
|
||||
if slices.Contains(t.hideWarnables, w.Code) {
|
||||
t.setHealthyLocked(w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tracker) timerSelfCheck() {
|
||||
if t.nil() {
|
||||
return
|
||||
@@ -936,7 +962,7 @@ func (t *Tracker) Strings() []string {
|
||||
func (t *Tracker) stringsLocked() []string {
|
||||
result := []string{}
|
||||
for w, ws := range t.warnableVal {
|
||||
if !w.IsVisible(ws) {
|
||||
if !w.IsVisible(ws) || slices.Contains(t.hideWarnables, w.Code) {
|
||||
// Do not append invisible warnings.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package health
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -86,7 +87,7 @@ func (t *Tracker) CurrentState() *State {
|
||||
wm := map[WarnableCode]UnhealthyState{}
|
||||
|
||||
for w, ws := range t.warnableVal {
|
||||
if !w.IsVisible(ws) {
|
||||
if !w.IsVisible(ws) || slices.Contains(t.hideWarnables, w.Code) {
|
||||
// Skip invisible Warnables.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"net/netip"
|
||||
|
||||
"tailscale.com/drive"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/opt"
|
||||
"tailscale.com/types/persist"
|
||||
@@ -38,6 +39,7 @@ func (src *Prefs) Clone() *Prefs {
|
||||
}
|
||||
}
|
||||
}
|
||||
dst.HideHealthWarnings = append(src.HideHealthWarnings[:0:0], src.HideHealthWarnings...)
|
||||
dst.Persist = src.Persist.Clone()
|
||||
return dst
|
||||
}
|
||||
@@ -73,6 +75,7 @@ var _PrefsCloneNeedsRegeneration = Prefs(struct {
|
||||
PostureChecking bool
|
||||
NetfilterKind string
|
||||
DriveShares []*drive.Share
|
||||
HideHealthWarnings []health.WarnableCode
|
||||
AllowSingleHosts marshalAsTrueInJSON
|
||||
Persist *persist.Persist
|
||||
}{})
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"net/netip"
|
||||
|
||||
"tailscale.com/drive"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/opt"
|
||||
"tailscale.com/types/persist"
|
||||
@@ -100,6 +101,9 @@ func (v PrefsView) NetfilterKind() string { return v.ж.Netfilte
|
||||
func (v PrefsView) DriveShares() views.SliceView[*drive.Share, drive.ShareView] {
|
||||
return views.SliceOfViews[*drive.Share, drive.ShareView](v.ж.DriveShares)
|
||||
}
|
||||
func (v PrefsView) HideHealthWarnings() views.Slice[health.WarnableCode] {
|
||||
return views.SliceOf(v.ж.HideHealthWarnings)
|
||||
}
|
||||
func (v PrefsView) AllowSingleHosts() marshalAsTrueInJSON { return v.ж.AllowSingleHosts }
|
||||
func (v PrefsView) Persist() persist.PersistView { return v.ж.Persist.View() }
|
||||
|
||||
@@ -134,6 +138,7 @@ var _PrefsViewNeedsRegeneration = Prefs(struct {
|
||||
PostureChecking bool
|
||||
NetfilterKind string
|
||||
DriveShares []*drive.Share
|
||||
HideHealthWarnings []health.WarnableCode
|
||||
AllowSingleHosts marshalAsTrueInJSON
|
||||
Persist *persist.Persist
|
||||
}{})
|
||||
|
||||
@@ -557,6 +557,9 @@ func NewLocalBackend(logf logger.Logf, logID logid.PublicID, sys *tsd.System, lo
|
||||
fs.SetShares(shares)
|
||||
}
|
||||
}
|
||||
if hideWarns := pm.prefs.HideHealthWarnings().AsSlice(); len(hideWarns) != 0 {
|
||||
b.health.HideWarnables(hideWarns)
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
@@ -1716,6 +1719,21 @@ func applySysPolicy(prefs *ipn.Prefs, lastSuggestedExitNode tailcfg.StableNodeID
|
||||
}
|
||||
}
|
||||
}
|
||||
// Gross, but the type mismatch causes these silly conversion copies.
|
||||
hideHealthWarnings := make([]string, 0, len(prefs.HideHealthWarnings))
|
||||
for _, w := range prefs.HideHealthWarnings {
|
||||
hideHealthWarnings = append(hideHealthWarnings, string(w))
|
||||
}
|
||||
if po, err := syspolicy.GetStringArray(syspolicy.HideHealthWarnings, hideHealthWarnings); err == nil {
|
||||
if !slices.Equal(po, hideHealthWarnings) {
|
||||
newVal := make([]health.WarnableCode, 0, len(po))
|
||||
for _, w := range po {
|
||||
newVal = append(newVal, health.WarnableCode(w))
|
||||
}
|
||||
prefs.HideHealthWarnings = newVal
|
||||
anyChange = true
|
||||
}
|
||||
}
|
||||
|
||||
return anyChange
|
||||
}
|
||||
@@ -3999,6 +4017,10 @@ func (b *LocalBackend) setPrefsLockedOnEntry(newp *ipn.Prefs, unlock unlockOnce)
|
||||
b.authReconfig()
|
||||
}
|
||||
|
||||
if !slices.Equal(oldp.HideHealthWarnings().AsSlice(), newp.HideHealthWarnings) {
|
||||
b.health.HideWarnables(newp.HideHealthWarnings)
|
||||
}
|
||||
|
||||
b.send(ipn.Notify{Prefs: &prefs})
|
||||
return prefs
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
"tailscale.com/atomicfile"
|
||||
"tailscale.com/drive"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/net/netaddr"
|
||||
"tailscale.com/net/tsaddr"
|
||||
@@ -245,6 +246,9 @@ type Prefs struct {
|
||||
// by name.
|
||||
DriveShares []*drive.Share
|
||||
|
||||
// HideHealthWarnings is a list of warnable codes to hide from the user.
|
||||
HideHealthWarnings []health.WarnableCode
|
||||
|
||||
// AllowSingleHosts was a legacy field that was always true
|
||||
// for the past 4.5 years. It controlled whether Tailscale
|
||||
// peers got /32 or /127 routes for each other.
|
||||
@@ -336,6 +340,7 @@ type MaskedPrefs struct {
|
||||
PostureCheckingSet bool `json:",omitempty"`
|
||||
NetfilterKindSet bool `json:",omitempty"`
|
||||
DriveSharesSet bool `json:",omitempty"`
|
||||
HideHealthWarningsSet bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
// SetsInternal reports whether mp has any of the Internal*Set field bools set
|
||||
@@ -615,7 +620,8 @@ func (p *Prefs) Equals(p2 *Prefs) bool {
|
||||
p.AppConnector == p2.AppConnector &&
|
||||
p.PostureChecking == p2.PostureChecking &&
|
||||
slices.EqualFunc(p.DriveShares, p2.DriveShares, drive.SharesEqual) &&
|
||||
p.NetfilterKind == p2.NetfilterKind
|
||||
p.NetfilterKind == p2.NetfilterKind &&
|
||||
slices.Equal(p.HideHealthWarnings, p2.HideHealthWarnings)
|
||||
}
|
||||
|
||||
func (au AutoUpdatePrefs) Pretty() string {
|
||||
|
||||
@@ -65,6 +65,7 @@ func TestPrefsEqual(t *testing.T) {
|
||||
"PostureChecking",
|
||||
"NetfilterKind",
|
||||
"DriveShares",
|
||||
"HideHealthWarnings",
|
||||
"AllowSingleHosts",
|
||||
"Persist",
|
||||
}
|
||||
|
||||
@@ -126,6 +126,9 @@ const (
|
||||
// Keys with a string array value.
|
||||
// AllowedSuggestedExitNodes's string array value is a list of exit node IDs that restricts which exit nodes are considered when generating suggestions for exit nodes.
|
||||
AllowedSuggestedExitNodes Key = "AllowedSuggestedExitNodes"
|
||||
// HideHealthWarnings hides the specified health.WarnableCode types from
|
||||
// the user when they become unhealthy.
|
||||
HideHealthWarnings Key = "HideHealthWarnings"
|
||||
)
|
||||
|
||||
// implicitDefinitions is a list of [setting.Definition] that will be registered
|
||||
@@ -170,6 +173,7 @@ var implicitDefinitions = []*setting.Definition{
|
||||
setting.NewDefinition(TestMenuVisibility, setting.UserSetting, setting.VisibilityValue),
|
||||
setting.NewDefinition(UpdateMenuVisibility, setting.UserSetting, setting.VisibilityValue),
|
||||
setting.NewDefinition(OnboardingFlowVisibility, setting.UserSetting, setting.VisibilityValue),
|
||||
setting.NewDefinition(HideHealthWarnings, setting.UserSetting, setting.StringListValue),
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
Reference in New Issue
Block a user