mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-16 03:31:39 +00:00
ipn/ipnlocal: populate peers' capabilities (#11365)
Populates capabilties field of peers in ipn status. Updates tailscale/corp#17516 Signed-off-by: Claire Wang <claire@tailscale.com>
This commit is contained in:
parent
9eaa56df93
commit
262fa8a01e
@ -894,6 +894,14 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
|
|||||||
ExitNode: p.StableID() != "" && p.StableID() == exitNodeID,
|
ExitNode: p.StableID() != "" && p.StableID() == exitNodeID,
|
||||||
SSH_HostKeys: p.Hostinfo().SSH_HostKeys().AsSlice(),
|
SSH_HostKeys: p.Hostinfo().SSH_HostKeys().AsSlice(),
|
||||||
Location: p.Hostinfo().Location(),
|
Location: p.Hostinfo().Location(),
|
||||||
|
Capabilities: p.Capabilities().AsSlice(),
|
||||||
|
}
|
||||||
|
if cm := p.CapMap(); cm.Len() > 0 {
|
||||||
|
ps.CapMap = make(tailcfg.NodeCapMap, cm.Len())
|
||||||
|
cm.Range(func(k tailcfg.NodeCapability, v views.Slice[tailcfg.RawMessage]) bool {
|
||||||
|
ps.CapMap[k] = v.AsSlice()
|
||||||
|
return true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
peerStatusFromNode(ps, p)
|
peerStatusFromNode(ps, p)
|
||||||
|
|
||||||
|
@ -736,6 +736,100 @@ func TestStatusWithoutPeers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStatusPeerCapabilities(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
peers []tailcfg.NodeView
|
||||||
|
expectedPeerCapabilities map[tailcfg.StableNodeID][]tailcfg.NodeCapability
|
||||||
|
expectedPeerCapMap map[tailcfg.StableNodeID]tailcfg.NodeCapMap
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "peers-with-capabilities",
|
||||||
|
peers: []tailcfg.NodeView{
|
||||||
|
(&tailcfg.Node{
|
||||||
|
ID: 1,
|
||||||
|
StableID: "foo",
|
||||||
|
IsWireGuardOnly: true,
|
||||||
|
Hostinfo: (&tailcfg.Hostinfo{}).View(),
|
||||||
|
Capabilities: []tailcfg.NodeCapability{tailcfg.CapabilitySSH},
|
||||||
|
CapMap: (tailcfg.NodeCapMap)(map[tailcfg.NodeCapability][]tailcfg.RawMessage{
|
||||||
|
tailcfg.CapabilitySSH: nil,
|
||||||
|
}),
|
||||||
|
}).View(),
|
||||||
|
(&tailcfg.Node{
|
||||||
|
ID: 2,
|
||||||
|
StableID: "bar",
|
||||||
|
Hostinfo: (&tailcfg.Hostinfo{}).View(),
|
||||||
|
Capabilities: []tailcfg.NodeCapability{tailcfg.CapabilityAdmin},
|
||||||
|
CapMap: (tailcfg.NodeCapMap)(map[tailcfg.NodeCapability][]tailcfg.RawMessage{
|
||||||
|
tailcfg.CapabilityAdmin: {`{"test": "true}`},
|
||||||
|
}),
|
||||||
|
}).View(),
|
||||||
|
},
|
||||||
|
expectedPeerCapabilities: map[tailcfg.StableNodeID][]tailcfg.NodeCapability{
|
||||||
|
tailcfg.StableNodeID("foo"): {tailcfg.CapabilitySSH},
|
||||||
|
tailcfg.StableNodeID("bar"): {tailcfg.CapabilityAdmin},
|
||||||
|
},
|
||||||
|
expectedPeerCapMap: map[tailcfg.StableNodeID]tailcfg.NodeCapMap{
|
||||||
|
tailcfg.StableNodeID("foo"): (tailcfg.NodeCapMap)(map[tailcfg.NodeCapability][]tailcfg.RawMessage{
|
||||||
|
tailcfg.CapabilitySSH: nil,
|
||||||
|
}),
|
||||||
|
tailcfg.StableNodeID("bar"): (tailcfg.NodeCapMap)(map[tailcfg.NodeCapability][]tailcfg.RawMessage{
|
||||||
|
tailcfg.CapabilityAdmin: {`{"test": "true}`},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "peers-without-capabilities",
|
||||||
|
peers: []tailcfg.NodeView{
|
||||||
|
(&tailcfg.Node{
|
||||||
|
ID: 1,
|
||||||
|
StableID: "foo",
|
||||||
|
IsWireGuardOnly: true,
|
||||||
|
Hostinfo: (&tailcfg.Hostinfo{}).View(),
|
||||||
|
}).View(),
|
||||||
|
(&tailcfg.Node{
|
||||||
|
ID: 2,
|
||||||
|
StableID: "bar",
|
||||||
|
Hostinfo: (&tailcfg.Hostinfo{}).View(),
|
||||||
|
}).View(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
b.setNetMapLocked(&netmap.NetworkMap{
|
||||||
|
SelfNode: (&tailcfg.Node{
|
||||||
|
MachineAuthorized: true,
|
||||||
|
Addresses: ipps("100.101.101.101"),
|
||||||
|
}).View(),
|
||||||
|
Peers: tt.peers,
|
||||||
|
})
|
||||||
|
got := b.Status()
|
||||||
|
for _, peer := range got.Peer {
|
||||||
|
if !reflect.DeepEqual(peer.Capabilities, tt.expectedPeerCapabilities[peer.ID]) {
|
||||||
|
t.Errorf("peer capabilities: expected %v got %v", tt.expectedPeerCapabilities, peer.Capabilities)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(peer.CapMap, tt.expectedPeerCapMap[peer.ID]) {
|
||||||
|
t.Errorf("peer capmap: expected %v got %v", tt.expectedPeerCapMap, peer.CapMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// legacyBackend was the interface between Tailscale frontends
|
// legacyBackend was the interface between Tailscale frontends
|
||||||
// (e.g. cmd/tailscale, iOS/MacOS/Windows GUIs) and the tailscale
|
// (e.g. cmd/tailscale, iOS/MacOS/Windows GUIs) and the tailscale
|
||||||
// backend (e.g. cmd/tailscaled) running on the same machine.
|
// backend (e.g. cmd/tailscaled) running on the same machine.
|
||||||
|
@ -496,6 +496,12 @@ func (sb *StatusBuilder) AddPeer(peer key.NodePublic, st *PeerStatus) {
|
|||||||
if t := st.KeyExpiry; t != nil {
|
if t := st.KeyExpiry; t != nil {
|
||||||
e.KeyExpiry = ptr.To(*t)
|
e.KeyExpiry = ptr.To(*t)
|
||||||
}
|
}
|
||||||
|
if v := st.CapMap; v != nil {
|
||||||
|
e.CapMap = v
|
||||||
|
}
|
||||||
|
if v := st.Capabilities; v != nil {
|
||||||
|
e.Capabilities = v
|
||||||
|
}
|
||||||
e.Location = st.Location
|
e.Location = st.Location
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user