mirror of
https://github.com/tailscale/tailscale.git
synced 2025-07-28 23:04:10 +00:00
tstest/integration/testcontrol: include peer CapMaps in MapResponses
Fixes #16560 Signed-off-by: Raj Singh <raj@tailscale.com>
This commit is contained in:
parent
f421907c38
commit
d6d29abbb6
147
tstest/integration/capmap_test.go
Normal file
147
tstest/integration/capmap_test.go
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/tstest"
|
||||
)
|
||||
|
||||
// TestPeerCapMap tests that the node capability map (CapMap) is included in peer information.
|
||||
func TestPeerCapMap(t *testing.T) {
|
||||
tstest.Shard(t)
|
||||
tstest.Parallel(t)
|
||||
env := NewTestEnv(t)
|
||||
|
||||
// Spin up two nodes.
|
||||
n1 := NewTestNode(t, env)
|
||||
d1 := n1.StartDaemon()
|
||||
n1.AwaitListening()
|
||||
n1.MustUp()
|
||||
n1.AwaitRunning()
|
||||
|
||||
n2 := NewTestNode(t, env)
|
||||
d2 := n2.StartDaemon()
|
||||
n2.AwaitListening()
|
||||
n2.MustUp()
|
||||
n2.AwaitRunning()
|
||||
|
||||
n1.AwaitIP4()
|
||||
n2.AwaitIP4()
|
||||
|
||||
// Get the nodes from the control server.
|
||||
nodes := env.Control.AllNodes()
|
||||
if len(nodes) != 2 {
|
||||
t.Fatalf("expected 2 nodes, got %d nodes", len(nodes))
|
||||
}
|
||||
|
||||
// Figure out which node is which by comparing keys.
|
||||
st1 := n1.MustStatus()
|
||||
var tn1, tn2 *tailcfg.Node
|
||||
for _, n := range nodes {
|
||||
if n.Key == st1.Self.PublicKey {
|
||||
tn1 = n
|
||||
} else {
|
||||
tn2 = n
|
||||
}
|
||||
}
|
||||
|
||||
// Set CapMap on both nodes.
|
||||
caps := make(tailcfg.NodeCapMap)
|
||||
caps["example:custom"] = []tailcfg.RawMessage{`"value"`}
|
||||
caps["example:enabled"] = []tailcfg.RawMessage{`true`}
|
||||
|
||||
env.Control.SetNodeCapMap(tn1.Key, caps)
|
||||
env.Control.SetNodeCapMap(tn2.Key, caps)
|
||||
|
||||
// Check that nodes see each other's CapMap.
|
||||
if err := tstest.WaitFor(10*time.Second, func() error {
|
||||
st1 := n1.MustStatus()
|
||||
st2 := n2.MustStatus()
|
||||
|
||||
if len(st1.Peer) == 0 || len(st2.Peer) == 0 {
|
||||
return errors.New("no peers")
|
||||
}
|
||||
|
||||
// Check n1 sees n2's CapMap.
|
||||
p1 := st1.Peer[st1.Peers()[0]]
|
||||
if p1.CapMap == nil {
|
||||
return errors.New("peer CapMap is nil")
|
||||
}
|
||||
if p1.CapMap["example:custom"] == nil || p1.CapMap["example:enabled"] == nil {
|
||||
return errors.New("peer CapMap missing entries")
|
||||
}
|
||||
|
||||
// Check n2 sees n1's CapMap.
|
||||
p2 := st2.Peer[st2.Peers()[0]]
|
||||
if p2.CapMap == nil {
|
||||
return errors.New("peer CapMap is nil")
|
||||
}
|
||||
if p2.CapMap["example:custom"] == nil || p2.CapMap["example:enabled"] == nil {
|
||||
return errors.New("peer CapMap missing entries")
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d1.MustCleanShutdown(t)
|
||||
d2.MustCleanShutdown(t)
|
||||
}
|
||||
|
||||
// TestSetNodeCapMap tests that SetNodeCapMap updates are propagated to peers.
|
||||
func TestSetNodeCapMap(t *testing.T) {
|
||||
tstest.Shard(t)
|
||||
tstest.Parallel(t)
|
||||
env := NewTestEnv(t)
|
||||
|
||||
n1 := NewTestNode(t, env)
|
||||
d1 := n1.StartDaemon()
|
||||
n1.AwaitListening()
|
||||
n1.MustUp()
|
||||
n1.AwaitRunning()
|
||||
|
||||
nodes := env.Control.AllNodes()
|
||||
if len(nodes) != 1 {
|
||||
t.Fatalf("expected 1 node, got %d nodes", len(nodes))
|
||||
}
|
||||
node1 := nodes[0]
|
||||
|
||||
// Set initial CapMap.
|
||||
caps := make(tailcfg.NodeCapMap)
|
||||
caps["test:state"] = []tailcfg.RawMessage{`"initial"`}
|
||||
env.Control.SetNodeCapMap(node1.Key, caps)
|
||||
|
||||
// Start second node and verify it sees the first node's CapMap.
|
||||
n2 := NewTestNode(t, env)
|
||||
d2 := n2.StartDaemon()
|
||||
n2.AwaitListening()
|
||||
n2.MustUp()
|
||||
n2.AwaitRunning()
|
||||
|
||||
if err := tstest.WaitFor(5*time.Second, func() error {
|
||||
st := n2.MustStatus()
|
||||
if len(st.Peer) == 0 {
|
||||
return errors.New("no peers")
|
||||
}
|
||||
p := st.Peer[st.Peers()[0]]
|
||||
if p.CapMap == nil || p.CapMap["test:state"] == nil {
|
||||
return errors.New("peer CapMap not set")
|
||||
}
|
||||
if string(p.CapMap["test:state"][0]) != `"initial"` {
|
||||
return errors.New("wrong CapMap value")
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d1.MustCleanShutdown(t)
|
||||
d2.MustCleanShutdown(t)
|
||||
}
|
@ -1000,7 +1000,11 @@ func (s *Server) MapResponse(req *tailcfg.MapRequest) (res *tailcfg.MapResponse,
|
||||
s.mu.Lock()
|
||||
peerAddress := s.masquerades[p.Key][node.Key]
|
||||
routes := s.nodeSubnetRoutes[p.Key]
|
||||
peerCapMap := maps.Clone(s.nodeCapMaps[p.Key])
|
||||
s.mu.Unlock()
|
||||
if peerCapMap != nil {
|
||||
p.CapMap = peerCapMap
|
||||
}
|
||||
if peerAddress.IsValid() {
|
||||
if peerAddress.Is6() {
|
||||
p.Addresses[1] = netip.PrefixFrom(peerAddress, peerAddress.BitLen())
|
||||
|
Loading…
x
Reference in New Issue
Block a user