Преглед изворни кода

tsnet: add a test for restarting a tsnet server, fix Windows

Thanks to @qur and @eric for debugging!

Fixes #6973

Change-Id: Ib2cf8f030cf595cc73dd061c72e78ac19f5fae5d
Signed-off-by: Brad Fitzpatrick <[email protected]>
Brad Fitzpatrick пре 2 година
родитељ
комит
246e0ccdca
4 измењених фајлова са 66 додато и 2 уклоњено
  1. 8 0
      control/controlclient/client.go
  2. 5 1
      ipn/ipnlocal/local.go
  3. 1 1
      tsnet/tsnet.go
  4. 52 0
      tsnet/tsnet_test.go

+ 8 - 0
control/controlclient/client.go

@@ -14,12 +14,20 @@ import (
 	"tailscale.com/tailcfg"
 )
 
+// LoginFlags is a bitmask of options to change the behavior of Client.Login
+// and LocalBackend.
 type LoginFlags int
 
 const (
 	LoginDefault     = LoginFlags(0)
 	LoginInteractive = LoginFlags(1 << iota) // force user login and key refresh
 	LoginEphemeral                           // set RegisterRequest.Ephemeral
+
+	// LocalBackendStartKeyOSNeutral instructs NewLocalBackend to start the
+	// LocalBackend without any OS-dependent StateStore StartKey behavior.
+	//
+	// See https://github.com/tailscale/tailscale/issues/6973.
+	LocalBackendStartKeyOSNeutral
 )
 
 // Client represents a client connection to the control server.

+ 5 - 1
ipn/ipnlocal/local.go

@@ -308,7 +308,11 @@ func NewLocalBackend(logf logger.Logf, logID logid.PublicID, sys *tsd.System, lo
 	dialer := sys.Dialer.Get()
 	_ = sys.MagicSock.Get() // or panic
 
-	pm, err := newProfileManager(store, logf)
+	goos := envknob.GOOS()
+	if loginFlags&controlclient.LocalBackendStartKeyOSNeutral != 0 {
+		goos = ""
+	}
+	pm, err := newProfileManagerWithGOOS(store, logf, goos)
 	if err != nil {
 		return nil, err
 	}

+ 1 - 1
tsnet/tsnet.go

@@ -542,7 +542,7 @@ func (s *Server) start() (reterr error) {
 	if s.Ephemeral {
 		loginFlags = controlclient.LoginEphemeral
 	}
-	lb, err := ipnlocal.NewLocalBackend(logf, s.logid, sys, loginFlags)
+	lb, err := ipnlocal.NewLocalBackend(logf, s.logid, sys, loginFlags|controlclient.LocalBackendStartKeyOSNeutral)
 	if err != nil {
 		return fmt.Errorf("NewLocalBackend: %v", err)
 	}

+ 52 - 0
tsnet/tsnet_test.go

@@ -23,6 +23,7 @@ import (
 	"net/netip"
 	"os"
 	"path/filepath"
+	"reflect"
 	"strings"
 	"sync"
 	"testing"
@@ -470,6 +471,57 @@ func TestListenerCleanup(t *testing.T) {
 	}
 }
 
+// tests https://github.com/tailscale/tailscale/issues/6973 -- that we can start a tsnet server,
+// stop it, and restart it, even on Windows.
+func TestStartStopStartGetsSameIP(t *testing.T) {
+	controlURL := startControl(t)
+
+	tmp := t.TempDir()
+	tmps1 := filepath.Join(tmp, "s1")
+	os.MkdirAll(tmps1, 0755)
+
+	newServer := func() *Server {
+		return &Server{
+			Dir:        tmps1,
+			ControlURL: controlURL,
+			Hostname:   "s1",
+			Logf:       logger.TestLogger(t),
+		}
+	}
+	s1 := newServer()
+	defer s1.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+
+	s1status, err := s1.Up(ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	firstIPs := s1status.TailscaleIPs
+	t.Logf("IPs: %v", firstIPs)
+
+	if err := s1.Close(); err != nil {
+		t.Fatalf("Close: %v", err)
+	}
+
+	s2 := newServer()
+	defer s2.Close()
+
+	s2status, err := s2.Up(ctx)
+	if err != nil {
+		t.Fatalf("second Up: %v", err)
+	}
+
+	secondIPs := s2status.TailscaleIPs
+	t.Logf("IPs: %v", secondIPs)
+
+	if !reflect.DeepEqual(firstIPs, secondIPs) {
+		t.Fatalf("got %v but later %v", firstIPs, secondIPs)
+	}
+}
+
 func TestFunnel(t *testing.T) {
 	ctx, dialCancel := context.WithTimeout(context.Background(), 30*time.Second)
 	defer dialCancel()