cmd/tailscale: make "up", "status" warn if routes and --accept-routes off

Example output:

    # Health check:
    #     - Some peers are advertising routes but --accept-routes is false

Also, move "tailscale status" health checks to the bottom, where they
won't be lost in large netmaps.

Updates #2053
Updates #6266

Change-Id: I5ae76a0cd69a452ce70063875cd7d974bfeb8f1a
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2022-11-11 09:43:49 -08:00
committed by Brad Fitzpatrick
parent 66b4a363bd
commit 08e110ebc5
8 changed files with 108 additions and 30 deletions
+13
View File
@@ -16,6 +16,7 @@ import (
qt "github.com/frankban/quicktest"
"github.com/google/go-cmp/cmp"
"tailscale.com/health/healthmsg"
"tailscale.com/ipn"
"tailscale.com/ipn/ipnstate"
"tailscale.com/tstest"
@@ -1143,3 +1144,15 @@ func TestCleanUpArgs(t *testing.T) {
c.Assert(got, qt.DeepEquals, tt.want)
}
}
func TestUpWorthWarning(t *testing.T) {
if !upWorthyWarning(healthmsg.WarnAcceptRoutesOff) {
t.Errorf("WarnAcceptRoutesOff of %q should be worth warning", healthmsg.WarnAcceptRoutesOff)
}
if !upWorthyWarning(healthmsg.TailscaleSSHOnBut + "some problem") {
t.Errorf("want true for SSH problems")
}
if upWorthyWarning("not in map poll") {
t.Errorf("want false for other misc errors")
}
}
+11 -4
View File
@@ -128,18 +128,21 @@ func runStatus(ctx context.Context, args []string) error {
return err
}
// print health check information prior to checking LocalBackend state as
// it may provide an explanation to the user if we choose to exit early
if len(st.Health) > 0 {
printHealth := func() {
printf("# Health check:\n")
for _, m := range st.Health {
printf("# - %s\n", m)
}
outln()
}
description, ok := isRunningOrStarting(st)
if !ok {
// print health check information if we're in a weird state, as it might
// provide context about why we're in that weird state.
if len(st.Health) > 0 && (st.BackendState == ipn.Starting.String() || st.BackendState == ipn.NoState.String()) {
printHealth()
outln()
}
outln(description)
os.Exit(1)
}
@@ -214,6 +217,10 @@ func runStatus(ctx context.Context, args []string) error {
}
}
Stdout.Write(buf.Bytes())
if len(st.Health) > 0 {
outln()
printHealth()
}
return nil
}
+39 -12
View File
@@ -25,6 +25,7 @@ import (
shellquote "github.com/kballard/go-shellquote"
"github.com/peterbourgon/ff/v3/ffcli"
qrcode "github.com/skip2/go-qrcode"
"tailscale.com/health/healthmsg"
"tailscale.com/ipn"
"tailscale.com/ipn/ipnstate"
"tailscale.com/net/tsaddr"
@@ -495,7 +496,7 @@ func runUp(ctx context.Context, args []string) (retErr error) {
defer func() {
if retErr == nil {
checkSSHUpWarnings(ctx)
checkUpWarnings(ctx)
}
}()
@@ -678,25 +679,39 @@ func runUp(ctx context.Context, args []string) (retErr error) {
}
}
func checkSSHUpWarnings(ctx context.Context) {
if !upArgs.runSSH {
return
}
st, err := localClient.Status(ctx)
// upWorthWarning reports whether the health check message s is worth warning
// about during "tailscale up". Many of the health checks are noisy or confusing
// or very ephemeral and happen especially briefly at startup.
//
// TODO(bradfitz): change the server to send typed warnings with metadata about
// the health check, rather than just a string.
func upWorthyWarning(s string) bool {
return strings.Contains(s, healthmsg.TailscaleSSHOnBut) ||
strings.Contains(s, healthmsg.WarnAcceptRoutesOff)
}
func checkUpWarnings(ctx context.Context) {
st, err := localClient.StatusWithoutPeers(ctx)
if err != nil {
// Ignore. Don't spam more.
return
}
if len(st.Health) == 0 {
var warn []string
for _, w := range st.Health {
if upWorthyWarning(w) {
warn = append(warn, w)
}
}
if len(warn) == 0 {
return
}
if len(st.Health) == 1 && strings.Contains(st.Health[0], "SSH") {
printf("%s\n", st.Health[0])
if len(warn) == 1 {
printf("%s\n", warn[0])
return
}
printf("# Health check:\n")
for _, m := range st.Health {
printf(" - %s\n", m)
printf("# Health check warnings:\n")
for _, m := range warn {
printf("# - %s\n", m)
}
}
@@ -1040,3 +1055,15 @@ func exitNodeIP(p *ipn.Prefs, st *ipnstate.Status) (ip netip.Addr) {
}
return
}
func anyPeerAdvertisingRoutes(st *ipnstate.Status) bool {
for _, ps := range st.Peer {
if ps.PrimaryRoutes == nil {
continue
}
if ps.PrimaryRoutes.Len() > 0 {
return true
}
}
return false
}
+1
View File
@@ -51,6 +51,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
tailscale.com/derp/derphttp from tailscale.com/net/netcheck
tailscale.com/disco from tailscale.com/derp
tailscale.com/envknob from tailscale.com/cmd/tailscale/cli+
tailscale.com/health/healthmsg from tailscale.com/cmd/tailscale/cli
tailscale.com/hostinfo from tailscale.com/net/interfaces+
tailscale.com/ipn from tailscale.com/cmd/tailscale/cli+
tailscale.com/ipn/ipnstate from tailscale.com/cmd/tailscale/cli+
+1
View File
@@ -194,6 +194,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/doctor/routetable from tailscale.com/ipn/ipnlocal
tailscale.com/envknob from tailscale.com/control/controlclient+
tailscale.com/health from tailscale.com/control/controlclient+
tailscale.com/health/healthmsg from tailscale.com/ipn/ipnlocal
tailscale.com/hostinfo from tailscale.com/control/controlclient+
tailscale.com/ipn from tailscale.com/ipn/ipnlocal+
tailscale.com/ipn/ipnlocal from tailscale.com/ssh/tailssh+