Add tailscale versions, waiters and helpers for scenario

Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
Kristoffer Dalby 2022-10-18 11:59:28 +02:00
parent 3951f39868
commit 0db608a7b7
No known key found for this signature in database
2 changed files with 118 additions and 9 deletions

View File

@ -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)
}

View File

@ -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()