1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
// Copyright (c) Tailscale Inc & contributors
// 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)
}
|