From cd34d441be2f277221e81672125f73ec3e8cb16d Mon Sep 17 00:00:00 2001 From: Will Norris Date: Thu, 12 Dec 2024 10:33:13 -0800 Subject: [PATCH] cmd/tailscale: add tailnet info to whoami output Updates #14375 Change-Id: Ia101a4a3005adb9118051b3416f5a64a4a45987d Signed-off-by: Will Norris --- cmd/tailscale/cli/whoami.go | 2 +- cmd/tailscale/cli/whois.go | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/cmd/tailscale/cli/whoami.go b/cmd/tailscale/cli/whoami.go index 495cb0c3d..5c7966216 100644 --- a/cmd/tailscale/cli/whoami.go +++ b/cmd/tailscale/cli/whoami.go @@ -48,5 +48,5 @@ func runWhoami(ctx context.Context, args []string) error { if err != nil { return err } - return printWhoIs(who, whoamiArgs.json) + return printWhoIs(who, st.CurrentTailnet, whoamiArgs.json) } diff --git a/cmd/tailscale/cli/whois.go b/cmd/tailscale/cli/whois.go index 0b8e407d6..c6cae118c 100644 --- a/cmd/tailscale/cli/whois.go +++ b/cmd/tailscale/cli/whois.go @@ -4,6 +4,7 @@ package cli import ( + "cmp" "context" "encoding/json" "errors" @@ -14,6 +15,8 @@ "github.com/peterbourgon/ff/v3/ffcli" "tailscale.com/client/tailscale/apitype" + "tailscale.com/ipn/ipnstate" + "tailscale.com/tailcfg" ) var whoisCmd = &ffcli.Command{ @@ -47,16 +50,27 @@ func runWhoIs(ctx context.Context, args []string) error { if err != nil { return err } - return printWhoIs(who, whoIsArgs.json) + return printWhoIs(who, nil, whoIsArgs.json) +} + +// whoisAndTailnet combines a WhoIsResponse and TailnetStatus for display. +type whoisAndTailnet struct { + *apitype.WhoIsResponse + CurrentTailnet *ipnstate.TailnetStatus `json:",omitzero"` } // printWhoIs prints the WhoIsResponse to Stdout, either as JSON (if asJSON is // true) or in a human-readable form. -func printWhoIs(who *apitype.WhoIsResponse, asJSON bool) error { +// If tailnet is non-nil, tailnet information is included in the output. +func printWhoIs(who *apitype.WhoIsResponse, tailnet *ipnstate.TailnetStatus, asJSON bool) error { + wat := whoisAndTailnet{ + WhoIsResponse: who, + CurrentTailnet: tailnet, + } if asJSON { ec := json.NewEncoder(Stdout) ec.SetIndent("", " ") - ec.Encode(who) + ec.Encode(wat) return nil } @@ -75,6 +89,20 @@ func printWhoIs(who *apitype.WhoIsResponse, asJSON bool) error { fmt.Fprintf(w, " Name:\t%s\n", who.UserProfile.LoginName) fmt.Fprintf(w, " ID:\t%d\n", who.UserProfile.ID) } + if tailnet != nil { + // use the tailnet display name, if present + var displayName string + if who.Node.HasCap(tailcfg.NodeAttrTailnetDisplayName) { + v, err := tailcfg.UnmarshalNodeCapJSON[string](who.Node.CapMap, tailcfg.NodeAttrTailnetDisplayName) + if err == nil && len(v) > 0 { + displayName = v[0] + } + } + fmt.Fprintln(w, "Tailnet:") + // TODO(will@): plumb through StableTailnetID so we can show that here as well + fmt.Fprintf(w, " Name:\t%s\n", cmp.Or(displayName, tailnet.Name)) + fmt.Fprintf(w, " MagicDNS Suffix:\t%s\n", tailnet.MagicDNSSuffix) + } w.Flush() w = nil // avoid accidental use