cmd/tailscale: add tailnet info to whoami output

Updates #14375

Change-Id: Ia101a4a3005adb9118051b3416f5a64a4a45987d
Signed-off-by: Will Norris <will@tailscale.com>
This commit is contained in:
Will Norris
2024-12-12 10:33:13 -08:00
committed by Will Norris
parent aec6f8bf13
commit cd34d441be
2 changed files with 32 additions and 4 deletions

View File

@@ -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)
}

View File

@@ -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