summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@tailscale.com>2021-05-12 14:43:43 -0700
committerBrad Fitzpatrick <bradfitz@tailscale.com>2021-05-12 14:43:43 -0700
commit5a7c6f16780736c8564b30b5fd57f8db8a327b5f (patch)
treedd6df6b74f5c9f593915d3280882186097dbbe30
parentd32667011dbb9ad4025982944313533eb9a7c16f (diff)
downloadtailscale-5a7c6f16780736c8564b30b5fd57f8db8a327b5f.tar.xz
tailscale-5a7c6f16780736c8564b30b5fd57f8db8a327b5f.zip
tstest/integration{,/testcontrol}: add node update support, two node test
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
-rw-r--r--tstest/integration/integration_test.go59
-rw-r--r--tstest/integration/testcontrol/testcontrol.go40
2 files changed, 90 insertions, 9 deletions
diff --git a/tstest/integration/integration_test.go b/tstest/integration/integration_test.go
index bc296782f..154e0120b 100644
--- a/tstest/integration/integration_test.go
+++ b/tstest/integration/integration_test.go
@@ -10,6 +10,7 @@ import (
crand "crypto/rand"
"crypto/tls"
"encoding/json"
+ "errors"
"flag"
"fmt"
"io"
@@ -89,10 +90,7 @@ func TestOneNodeUp_NoAuth(t *testing.T) {
t.Error(err)
}
- t.Logf("Running up --login-server=%s ...", env.ControlServer.URL)
- if err := n1.Tailscale("up", "--login-server="+env.ControlServer.URL).Run(); err != nil {
- t.Fatalf("up: %v", err)
- }
+ n1.MustUp()
if d, _ := time.ParseDuration(os.Getenv("TS_POST_UP_SLEEP")); d > 0 {
t.Logf("Sleeping for %v to give 'up' time to misbehave (https://github.com/tailscale/tailscale/issues/1840) ...", d)
@@ -116,7 +114,6 @@ func TestOneNodeUp_Auth(t *testing.T) {
env.Control.RequireAuth = true
n1 := newTestNode(t, env)
-
d1 := n1.StartDaemon(t)
defer d1.Kill()
@@ -155,6 +152,50 @@ func TestOneNodeUp_Auth(t *testing.T) {
}
+func TestTwoNodes(t *testing.T) {
+ t.Parallel()
+ bins := buildTestBinaries(t)
+
+ env := newTestEnv(t, bins)
+ defer env.Close()
+
+ // Create two nodes:
+ n1 := newTestNode(t, env)
+ d1 := n1.StartDaemon(t)
+ defer d1.Kill()
+
+ n2 := newTestNode(t, env)
+ d2 := n2.StartDaemon(t)
+ defer d2.Kill()
+
+ n1.AwaitListening(t)
+ n2.AwaitListening(t)
+ n1.MustUp()
+ n2.MustUp()
+ n1.AwaitRunning(t)
+ n2.AwaitRunning(t)
+
+ if err := tstest.WaitFor(2*time.Second, func() error {
+ st := n1.MustStatus(t)
+ if len(st.Peer) == 0 {
+ return errors.New("no peers")
+ }
+ if len(st.Peer) > 1 {
+ return fmt.Errorf("got %d peers; want 1", len(st.Peer))
+ }
+ peer := st.Peer[st.Peers()[0]]
+ if peer.ID == st.Self.ID {
+ return errors.New("peer is self")
+ }
+ return nil
+ }); err != nil {
+ t.Error(err)
+ }
+
+ d1.MustCleanShutdown(t)
+ d2.MustCleanShutdown(t)
+}
+
// testBinaries are the paths to a tailscaled and tailscale binary.
// These can be shared by multiple nodes.
type testBinaries struct {
@@ -298,6 +339,14 @@ func (n *testNode) StartDaemon(t testing.TB) *Daemon {
}
}
+func (n *testNode) MustUp() {
+ t := n.env.t
+ t.Logf("Running up --login-server=%s ...", n.env.ControlServer.URL)
+ if err := n.Tailscale("up", "--login-server="+n.env.ControlServer.URL).Run(); err != nil {
+ t.Fatalf("up: %v", err)
+ }
+}
+
// AwaitListening waits for the tailscaled to be serving local clients
// over its localhost IPC mechanism. (Unix socket, etc)
func (n *testNode) AwaitListening(t testing.TB) {
diff --git a/tstest/integration/testcontrol/testcontrol.go b/tstest/integration/testcontrol/testcontrol.go
index cd1051c58..1771bf65a 100644
--- a/tstest/integration/testcontrol/testcontrol.go
+++ b/tstest/integration/testcontrol/testcontrol.go
@@ -18,6 +18,7 @@ import (
"math/rand"
"net/http"
"net/url"
+ "sort"
"strings"
"sync"
"time"
@@ -167,6 +168,18 @@ func (s *Server) Node(nodeKey tailcfg.NodeKey) *tailcfg.Node {
return s.nodes[nodeKey].Clone()
}
+func (s *Server) AllNodes() (nodes []*tailcfg.Node) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ for _, n := range s.nodes {
+ nodes = append(nodes, n.Clone())
+ }
+ sort.Slice(nodes, func(i, j int) bool {
+ return nodes[i].StableID < nodes[j].StableID
+ })
+ return nodes
+}
+
func (s *Server) getUser(nodeKey tailcfg.NodeKey) (*tailcfg.User, *tailcfg.Login) {
s.mu.Lock()
defer s.mu.Unlock()
@@ -366,6 +379,21 @@ func sendUpdate(dst chan<- updateType, updateType updateType) {
}
}
+func (s *Server) UpdateNode(n *tailcfg.Node) (peersToUpdate []tailcfg.NodeID) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if n.Key.IsZero() {
+ panic("zero nodekey")
+ }
+ s.nodes[n.Key] = n.Clone()
+ for _, n2 := range s.nodes {
+ if n.ID != n2.ID {
+ peersToUpdate = append(peersToUpdate, n2.ID)
+ }
+ }
+ return peersToUpdate
+}
+
func (s *Server) serveMap(w http.ResponseWriter, r *http.Request, mkey tailcfg.MachineKey) {
ctx := r.Context()
@@ -391,10 +419,8 @@ func (s *Server) serveMap(w http.ResponseWriter, r *http.Request, mkey tailcfg.M
if !req.ReadOnly {
endpoints := filterInvalidIPv6Endpoints(req.Endpoints)
node.Endpoints = endpoints
- // TODO: more
- // TODO: register node,
- //s.UpdateEndpoint(mkey, req.NodeKey,
- // XXX
+ node.DiscoKey = req.DiscoKey
+ peersToUpdate = s.UpdateNode(node)
}
nodeID := node.ID
@@ -501,6 +527,12 @@ func (s *Server) MapResponse(req *tailcfg.MapRequest) (res *tailcfg.MapResponse,
CollectServices: "true",
PacketFilter: tailcfg.FilterAllowAll,
}
+ for _, p := range s.AllNodes() {
+ if p.StableID != node.StableID {
+ res.Peers = append(res.Peers, p)
+ }
+ }
+
res.Node.Addresses = []netaddr.IPPrefix{
netaddr.MustParseIPPrefix(fmt.Sprintf("100.64.%d.%d/32", uint8(node.ID>>8), uint8(node.ID))),
}