Browse Source

cmd/tailscale/cli,ipn: mention available update in "tailscale status" (#9205)

Cache the last `ClientVersion` value that was received from coordination
server and pass it in the localapi `/status` response.
When running `tailscale status`, print a message if `RunningAsLatest` is
`false`.

Updates #6907

Signed-off-by: Andrew Lytvynov <[email protected]>
Andrew Lytvynov 2 years ago
parent
commit
d23b8ffb13
4 changed files with 16 additions and 1 deletions
  1. 3 0
      cmd/tailscale/cli/status.go
  2. 9 0
      ipn/ipnlocal/local.go
  3. 2 0
      ipn/ipnstate/ipnstate.go
  4. 2 1
      tailcfg/tailcfg.go

+ 3 - 0
cmd/tailscale/cli/status.go

@@ -236,6 +236,9 @@ func runStatus(ctx context.Context, args []string) error {
 		printHealth()
 	}
 	printFunnelStatus(ctx)
+	if cv := st.ClientVersion; cv != nil && !cv.RunningLatest && cv.LatestVersion != "" {
+		printf("# New Tailscale version is available: %q, run `tailscale update` to update.\n", cv.LatestVersion)
+	}
 	return nil
 }
 

+ 9 - 0
ipn/ipnlocal/local.go

@@ -268,6 +268,9 @@ type LocalBackend struct {
 	// at the moment that tkaSyncLock is taken).
 	tkaSyncLock sync.Mutex
 	clock       tstime.Clock
+
+	// Last ClientVersion received in MapResponse, guarded by mu.
+	lastClientVersion *tailcfg.ClientVersion
 }
 
 type updateStatus struct {
@@ -671,6 +674,9 @@ func (b *LocalBackend) updateStatus(sb *ipnstate.StatusBuilder, extraLocked func
 		s.TUN = !b.sys.IsNetstack()
 		s.BackendState = b.state.String()
 		s.AuthURL = b.authURLSticky
+		if prefs := b.pm.CurrentPrefs(); prefs.Valid() && prefs.AutoUpdate().Check {
+			s.ClientVersion = b.lastClientVersion
+		}
 		if err := health.OverallError(); err != nil {
 			switch e := err.(type) {
 			case multierr.Error:
@@ -2181,6 +2187,9 @@ func (b *LocalBackend) tellClientToBrowseToURL(url string) {
 // onClientVersion is called on MapResponse updates when a MapResponse contains
 // a non-nil ClientVersion message.
 func (b *LocalBackend) onClientVersion(v *tailcfg.ClientVersion) {
+	b.mu.Lock()
+	b.lastClientVersion = v
+	b.mu.Unlock()
 	switch runtime.GOOS {
 	case "darwin", "ios":
 		// These auto-update well enough, and we haven't converted the

+ 2 - 0
ipn/ipnstate/ipnstate.go

@@ -71,6 +71,8 @@ type Status struct {
 
 	Peer map[key.NodePublic]*PeerStatus
 	User map[tailcfg.UserID]tailcfg.UserProfile
+
+	ClientVersion *tailcfg.ClientVersion
 }
 
 // TKAKey describes a key trusted by network lock.

+ 2 - 1
tailcfg/tailcfg.go

@@ -110,7 +110,8 @@ type CapabilityVersion int
 //   - 70: 2023-08-16: removed most Debug fields; added NodeAttrDisable*, NodeAttrDebug* instead
 //   - 71: 2023-08-17: added NodeAttrOneCGNATEnable, NodeAttrOneCGNATDisable
 //   - 72: 2023-08-23: TS-2023-006 UPnP issue fixed; UPnP can now be used again
-const CurrentCapabilityVersion CapabilityVersion = 72
+//   - 73: 2023-09-01: Non-Windows clients expect to receive ClientVersion
+const CurrentCapabilityVersion CapabilityVersion = 73
 
 type StableID string