diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 5141c67a388fa..a21a61cea591c 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -877,6 +877,7 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) { ExitNode: p.StableID() != "" && p.StableID() == exitNodeID, SSH_HostKeys: p.Hostinfo().SSH_HostKeys().AsSlice(), Location: p.Hostinfo().Location(), + Capabilities: p.Capabilities().AsSlice(), } peerStatusFromNode(ps, p) diff --git a/ipn/ipnlocal/local_test.go b/ipn/ipnlocal/local_test.go index c2e6f1cbdf68d..9f626891925c5 100644 --- a/ipn/ipnlocal/local_test.go +++ b/ipn/ipnlocal/local_test.go @@ -729,6 +729,55 @@ func TestStatusWithoutPeers(t *testing.T) { } } +func TestStatusPeerCapabilities(t *testing.T) { + b := newTestLocalBackend(t) + + var cc *mockControl + b.SetControlClientGetterForTesting(func(opts controlclient.Options) (controlclient.Client, error) { + cc = newClient(t, opts) + + t.Logf("ccGen: new mockControl.") + cc.called("New") + return cc, nil + }) + b.Start(ipn.Options{}) + b.Login(nil) + cc.send(nil, "", false, &netmap.NetworkMap{ + SelfNode: (&tailcfg.Node{ + MachineAuthorized: true, + Addresses: ipps("100.101.101.101"), + }).View(), + Peers: []tailcfg.NodeView{ + (&tailcfg.Node{ + ID: 1, + StableID: "foo", + IsWireGuardOnly: true, + Hostinfo: (&tailcfg.Hostinfo{}).View(), + Capabilities: []tailcfg.NodeCapability{tailcfg.CapabilitySSH}, + }).View(), + (&tailcfg.Node{ + ID: 2, + StableID: "bar", + Hostinfo: (&tailcfg.Hostinfo{}).View(), + Capabilities: []tailcfg.NodeCapability{tailcfg.CapabilitySSH}, + }).View(), + }, + }) + got := b.Status() + if got.TailscaleIPs == nil { + t.Errorf("got nil, expected TailscaleIPs value to not be nil") + } + if !reflect.DeepEqual(got.TailscaleIPs, got.Self.TailscaleIPs) { + t.Errorf("got %v, expected %v", got.TailscaleIPs, got.Self.TailscaleIPs) + } + + for _, peer := range got.Peer { + if peer.Capabilities == nil { + t.Errorf("expected populated capabilities field") + } + } +} + // legacyBackend was the interface between Tailscale frontends // (e.g. cmd/tailscale, iOS/MacOS/Windows GUIs) and the tailscale // backend (e.g. cmd/tailscaled) running on the same machine.