mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-31 13:07:46 +09:00 
			
		
		
		
	Add tailscale versions, waiters and helpers for scenario
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
		| @@ -7,6 +7,7 @@ import ( | ||||
| 	"net/netip" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/juanfont/headscale" | ||||
| 	v1 "github.com/juanfont/headscale/gen/go/headscale/v1" | ||||
| @@ -20,12 +21,32 @@ const scenarioHashLength = 6 | ||||
|  | ||||
| var errNoHeadscaleAvailable = errors.New("no headscale available") | ||||
| var errNoNamespaceAvailable = errors.New("no namespace available") | ||||
| var TailscaleVersions = []string{ | ||||
| 	"head", | ||||
| 	"unstable", | ||||
| 	"1.32.0", | ||||
| 	"1.30.2", | ||||
| 	"1.28.0", | ||||
| 	"1.26.2", | ||||
| 	"1.24.2", | ||||
| 	"1.22.2", | ||||
| 	"1.20.4", | ||||
| 	"1.18.2", | ||||
| 	"1.16.2", | ||||
|  | ||||
| 	// These versions seem to fail when fetching from apt. | ||||
| 	// "1.14.6", | ||||
| 	// "1.12.4", | ||||
| 	// "1.10.2", | ||||
| 	// "1.8.7", | ||||
| } | ||||
|  | ||||
| type Namespace struct { | ||||
| 	Clients map[string]*tsic.TailscaleInContainer | ||||
|  | ||||
| 	createWaitGroup sync.WaitGroup | ||||
| 	joinWaitGroup   sync.WaitGroup | ||||
| 	syncWaitGroup   sync.WaitGroup | ||||
| } | ||||
|  | ||||
| // TODO(kradalby): make control server configurable, test test correctness with | ||||
| @@ -52,6 +73,8 @@ func NewScenario() (*Scenario, error) { | ||||
| 		return nil, fmt.Errorf("could not connect to docker: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	pool.MaxWait = 60 * time.Second | ||||
|  | ||||
| 	networkName := fmt.Sprintf("hs-%s", hash) | ||||
| 	if overrideNetworkName := os.Getenv("HEADSCALE_TEST_NETWORK_NAME"); overrideNetworkName != "" { | ||||
| 		networkName = overrideNetworkName | ||||
| @@ -162,11 +185,16 @@ func (s *Scenario) CreateNamespace(namespace string) error { | ||||
|  | ||||
| func (s *Scenario) CreateTailscaleNodesInNamespace( | ||||
| 	namespace string, | ||||
| 	version string, | ||||
| 	requestedVersion string, | ||||
| 	count int, | ||||
| ) error { | ||||
| 	if ns, ok := s.namespaces[namespace]; ok { | ||||
| 		for i := 0; i < count; i++ { | ||||
| 			version := requestedVersion | ||||
| 			if requestedVersion == "all" { | ||||
| 				version = TailscaleVersions[i%len(TailscaleVersions)] | ||||
| 			} | ||||
|  | ||||
| 			ns.createWaitGroup.Add(1) | ||||
|  | ||||
| 			go func() { | ||||
| @@ -197,12 +225,12 @@ func (s *Scenario) RunTailscaleUp( | ||||
| 		for _, client := range ns.Clients { | ||||
| 			ns.joinWaitGroup.Add(1) | ||||
|  | ||||
| 			go func() { | ||||
| 			go func(c *tsic.TailscaleInContainer) { | ||||
| 				defer ns.joinWaitGroup.Done() | ||||
|  | ||||
| 				// TODO(kradalby): error handle this | ||||
| 				_ = client.Up(loginServer, authKey) | ||||
| 			}() | ||||
| 				_ = c.Up(loginServer, authKey) | ||||
| 			}(client) | ||||
| 		} | ||||
| 		ns.joinWaitGroup.Wait() | ||||
|  | ||||
| @@ -212,6 +240,75 @@ func (s *Scenario) RunTailscaleUp( | ||||
| 	return fmt.Errorf("failed to up tailscale node: %w", errNoNamespaceAvailable) | ||||
| } | ||||
|  | ||||
| func (s *Scenario) CountTailscale() int { | ||||
| 	count := 0 | ||||
|  | ||||
| 	for _, ns := range s.namespaces { | ||||
| 		count += len(ns.Clients) | ||||
| 	} | ||||
|  | ||||
| 	return count | ||||
| } | ||||
|  | ||||
| func (s *Scenario) WaitForTailscaleSync() error { | ||||
| 	tsCount := s.CountTailscale() | ||||
|  | ||||
| 	for _, ns := range s.namespaces { | ||||
| 		for _, client := range ns.Clients { | ||||
| 			ns.syncWaitGroup.Add(1) | ||||
|  | ||||
| 			go func(c *tsic.TailscaleInContainer) { | ||||
| 				defer ns.syncWaitGroup.Done() | ||||
|  | ||||
| 				// TODO(kradalby): error handle this | ||||
| 				_ = c.WaitForPeers(tsCount) | ||||
| 			}(client) | ||||
| 		} | ||||
| 		ns.syncWaitGroup.Wait() | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // CreateHeadscaleEnv is a conventient method returning a set up Headcale | ||||
| // test environment with nodes of all versions, joined to the server with X | ||||
| // namespaces | ||||
| func (s *Scenario) CreateHeadscaleEnv(namespaces map[string]int) error { | ||||
| 	err := s.StartHeadscale() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	err = s.Headscale().WaitForReady() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	for namespaceName, clientCount := range namespaces { | ||||
| 		err = s.CreateNamespace(namespaceName) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		err = s.CreateTailscaleNodesInNamespace(namespaceName, "all", clientCount) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		key, err := s.CreatePreAuthKey(namespaceName) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		err = s.RunTailscaleUp(namespaceName, s.Headscale().GetEndpoint(), key.GetKey()) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (s *Scenario) GetIPs(namespace string) ([]netip.Addr, error) { | ||||
| 	var ips []netip.Addr | ||||
| 	if ns, ok := s.namespaces[namespace]; ok { | ||||
| @@ -228,3 +325,16 @@ func (s *Scenario) GetIPs(namespace string) ([]netip.Addr, error) { | ||||
|  | ||||
| 	return ips, fmt.Errorf("failed to get ips: %w", errNoNamespaceAvailable) | ||||
| } | ||||
|  | ||||
| func (s *Scenario) GetClients(namespace string) ([]*tsic.TailscaleInContainer, error) { | ||||
| 	var clients []*tsic.TailscaleInContainer | ||||
| 	if ns, ok := s.namespaces[namespace]; ok { | ||||
| 		for _, client := range ns.Clients { | ||||
| 			clients = append(clients, client) | ||||
| 		} | ||||
|  | ||||
| 		return clients, nil | ||||
| 	} | ||||
|  | ||||
| 	return clients, fmt.Errorf("failed to get clients: %w", errNoNamespaceAvailable) | ||||
| } | ||||
|   | ||||
| @@ -74,12 +74,9 @@ func TestHeadscale(t *testing.T) { | ||||
| func TestCreateTailscale(t *testing.T) { | ||||
| 	IntegrationSkip(t) | ||||
|  | ||||
| 	var scenario *Scenario | ||||
| 	var err error | ||||
|  | ||||
| 	namespace := "only-create-containers" | ||||
|  | ||||
| 	scenario, err = NewScenario() | ||||
| 	scenario, err := NewScenario() | ||||
| 	if err != nil { | ||||
| 		t.Errorf("failed to create scenario: %s", err) | ||||
| 	} | ||||
| @@ -89,7 +86,7 @@ func TestCreateTailscale(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	t.Run("create-tailscale", func(t *testing.T) { | ||||
| 		err := scenario.CreateTailscaleNodesInNamespace(namespace, "1.32.0", 3) | ||||
| 		err := scenario.CreateTailscaleNodesInNamespace(namespace, "all", 3) | ||||
| 		if err != nil { | ||||
| 			t.Errorf("failed to add tailscale nodes: %s", err) | ||||
| 		} | ||||
| @@ -97,6 +94,8 @@ func TestCreateTailscale(t *testing.T) { | ||||
| 		if clients := len(scenario.namespaces[namespace].Clients); clients != 3 { | ||||
| 			t.Errorf("wrong number of tailscale clients: %d != %d", clients, 3) | ||||
| 		} | ||||
|  | ||||
| 		// TODO(kradalby): Test "all" version logic | ||||
| 	}) | ||||
|  | ||||
| 	err = scenario.Shutdown() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user