From 55a388561439c32aea806079cec11bffbe9050b6 Mon Sep 17 00:00:00 2001 From: Juan Font Date: Tue, 27 Dec 2022 19:05:21 +0000 Subject: [PATCH] Added integration tests for ephemeral nodes Fetch the machines from headscale --- integration/control.go | 2 +- integration/general_test.go | 105 ++++++++++++++++++++++++++++++++++- integration/hsic/hsic.go | 11 +++- integration/scenario.go | 6 +- integration/scenario_test.go | 4 +- 5 files changed, 120 insertions(+), 8 deletions(-) diff --git a/integration/control.go b/integration/control.go index d05f5305..a0f76e11 100644 --- a/integration/control.go +++ b/integration/control.go @@ -11,7 +11,7 @@ type ControlServer interface { GetEndpoint() string WaitForReady() error CreateNamespace(namespace string) error - CreateAuthKey(namespace string) (*v1.PreAuthKey, error) + CreateAuthKey(namespace string, reusable bool, ephemeral bool) (*v1.PreAuthKey, error) ListMachinesInNamespace(namespace string) ([]*v1.Machine, error) GetCert() []byte GetHostname() string diff --git a/integration/general_test.go b/integration/general_test.go index 9c5b0742..5a4ed95f 100644 --- a/integration/general_test.go +++ b/integration/general_test.go @@ -122,7 +122,7 @@ func TestAuthKeyLogoutAndRelogin(t *testing.T) { } for namespaceName := range spec { - key, err := scenario.CreatePreAuthKey(namespaceName) + key, err := scenario.CreatePreAuthKey(namespaceName, true, false) if err != nil { t.Errorf("failed to create pre-auth key for namespace %s: %s", namespaceName, err) } @@ -197,6 +197,109 @@ func TestAuthKeyLogoutAndRelogin(t *testing.T) { } } +func TestEphemeral(t *testing.T) { + IntegrationSkip(t) + t.Parallel() + + scenario, err := NewScenario() + if err != nil { + t.Errorf("failed to create scenario: %s", err) + } + + spec := map[string]int{ + "namespace1": len(TailscaleVersions), + "namespace2": len(TailscaleVersions), + } + + headscale, err := scenario.Headscale(hsic.WithTestName("ephemeral")) + if err != nil { + t.Errorf("failed to create headscale environment: %s", err) + } + + for namespaceName, clientCount := range spec { + err = scenario.CreateNamespace(namespaceName) + if err != nil { + t.Errorf("failed to create namespace %s: %s", namespaceName, err) + } + + err = scenario.CreateTailscaleNodesInNamespace(namespaceName, "all", clientCount, []tsic.Option{}...) + if err != nil { + t.Errorf("failed to create tailscale nodes in namespace %s: %s", namespaceName, err) + } + + key, err := scenario.CreatePreAuthKey(namespaceName, true, true) + if err != nil { + t.Errorf("failed to create pre-auth key for namespace %s: %s", namespaceName, err) + } + + err = scenario.RunTailscaleUp(namespaceName, headscale.GetEndpoint(), key.GetKey()) + if err != nil { + t.Errorf("failed to run tailscale up for namespace %s: %s", namespaceName, err) + } + } + + err = scenario.WaitForTailscaleSync() + if err != nil { + t.Errorf("failed wait for tailscale clients to be in sync: %s", err) + } + + allClients, err := scenario.ListTailscaleClients() + if err != nil { + t.Errorf("failed to get clients: %s", err) + } + + allIps, err := scenario.ListTailscaleClientsIPs() + if err != nil { + t.Errorf("failed to get clients: %s", err) + } + + success := 0 + for _, client := range allClients { + for _, ip := range allIps { + err := client.Ping(ip.String()) + if err != nil { + t.Errorf("failed to ping %s from %s: %s", ip, client.Hostname(), err) + } else { + success++ + } + } + } + + t.Logf("%d successful pings out of %d", success, len(allClients)*len(allIps)) + + for _, client := range allClients { + err := client.Logout() + if err != nil { + t.Errorf("failed to logout client %s: %s", client.Hostname(), err) + } + } + + scenario.WaitForTailscaleLogout() + + t.Logf("all clients logged out") + + for namespaceName := range spec { + machines, err := headscale.ListMachinesInNamespace(namespaceName) + if err != nil { + log.Error(). + Err(err). + Str("namespace", namespaceName). + Msg("Error listing machines in namespace") + + return + } + + if len(machines) != 0 { + t.Errorf("expected no machines, got %d in namespace %s", len(machines), namespaceName) + } + } + + err = scenario.Shutdown() + if err != nil { + t.Errorf("failed to tear down scenario: %s", err) + } +} + func TestPingAllByHostname(t *testing.T) { IntegrationSkip(t) t.Parallel() diff --git a/integration/hsic/hsic.go b/integration/hsic/hsic.go index 9766c882..9f74bb2f 100644 --- a/integration/hsic/hsic.go +++ b/integration/hsic/hsic.go @@ -316,6 +316,8 @@ func (t *HeadscaleInContainer) CreateNamespace( func (t *HeadscaleInContainer) CreateAuthKey( namespace string, + reusable bool, + ephemeral bool, ) (*v1.PreAuthKey, error) { command := []string{ "headscale", @@ -323,13 +325,20 @@ func (t *HeadscaleInContainer) CreateAuthKey( namespace, "preauthkeys", "create", - "--reusable", "--expiration", "24h", "--output", "json", } + if reusable { + command = append(command, "--reusable") + } + + if ephemeral { + command = append(command, "--ephemeral") + } + result, _, err := dockertestutil.ExecuteCommand( t.container, command, diff --git a/integration/scenario.go b/integration/scenario.go index e4489b26..6679f101 100644 --- a/integration/scenario.go +++ b/integration/scenario.go @@ -194,9 +194,9 @@ func (s *Scenario) Headscale(opts ...hsic.Option) (ControlServer, error) { return headscale, nil } -func (s *Scenario) CreatePreAuthKey(namespace string) (*v1.PreAuthKey, error) { +func (s *Scenario) CreatePreAuthKey(namespace string, reusable bool, ephemeral bool) (*v1.PreAuthKey, error) { if headscale, err := s.Headscale(); err == nil { - key, err := headscale.CreateAuthKey(namespace) + key, err := headscale.CreateAuthKey(namespace, reusable, ephemeral) if err != nil { return nil, fmt.Errorf("failed to create namespace: %w", err) } @@ -368,7 +368,7 @@ func (s *Scenario) CreateHeadscaleEnv( return err } - key, err := s.CreatePreAuthKey(namespaceName) + key, err := s.CreatePreAuthKey(namespaceName, true, false) if err != nil { return err } diff --git a/integration/scenario_test.go b/integration/scenario_test.go index 480409ff..97005e55 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -62,7 +62,7 @@ func TestHeadscale(t *testing.T) { }) t.Run("create-auth-key", func(t *testing.T) { - _, err := scenario.CreatePreAuthKey(namespace) + _, err := scenario.CreatePreAuthKey(namespace, true, false) if err != nil { t.Errorf("failed to create preauthkey: %s", err) } @@ -166,7 +166,7 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) { }) t.Run("join-headscale", func(t *testing.T) { - key, err := scenario.CreatePreAuthKey(namespace) + key, err := scenario.CreatePreAuthKey(namespace, true, false) if err != nil { t.Errorf("failed to create preauthkey: %s", err) }