Skip to content

Commit

Permalink
Added DERP integration tests
Browse files Browse the repository at this point in the history
Linting fixes

Set listen addr to :8443
  • Loading branch information
juanfont committed Apr 24, 2023
1 parent 549f5a1 commit eacd687
Show file tree
Hide file tree
Showing 4 changed files with 259 additions and 16 deletions.
247 changes: 247 additions & 0 deletions integration/embedded_derp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
package integration

import (
"fmt"
"log"
"net/url"
"testing"

"github.com/juanfont/headscale"
"github.com/juanfont/headscale/integration/dockertestutil"
"github.com/juanfont/headscale/integration/hsic"
"github.com/juanfont/headscale/integration/tsic"
"github.com/ory/dockertest/v3"
)

type EmbeddedDERPServerScenario struct {
*Scenario

tsicNetworks map[string]*dockertest.Network
}

func TestDERPServerScenario(t *testing.T) {
IntegrationSkip(t)
// t.Parallel()

baseScenario, err := NewScenario()
if err != nil {
t.Errorf("failed to create scenario: %s", err)
}

scenario := EmbeddedDERPServerScenario{
Scenario: baseScenario,
tsicNetworks: map[string]*dockertest.Network{},
}

spec := map[string]int{
"user1": len(TailscaleVersions),
}

headscaleConfig := hsic.DefaultConfigEnv()
headscaleConfig["HEADSCALE_LISTEN_ADDR"] = "0.0.0.0:8443"
headscaleConfig["HEADSCALE_DERP_URLS"] = ""
headscaleConfig["HEADSCALE_DERP_SERVER_ENABLED"] = "true"
headscaleConfig["HEADSCALE_DERP_SERVER_REGION_ID"] = "999"
headscaleConfig["HEADSCALE_DERP_SERVER_REGION_CODE"] = "headscale"
headscaleConfig["HEADSCALE_DERP_SERVER_REGION_NAME"] = "Headscale Embedded DERP"
headscaleConfig["HEADSCALE_DERP_SERVER_STUN_LISTEN_ADDR"] = "0.0.0.0:3478"

err = scenario.CreateHeadscaleEnv(
spec,
hsic.WithConfigEnv(headscaleConfig),
hsic.WithPort(8443),
hsic.WithTestName("derpserver"),
hsic.WithHostPortBindings(
map[string][]string{
"8443/tcp": {"8443"},
"3478/udp": {"3478"},
},
),
hsic.WithExtraPorts([]string{"3478/udp"}),
hsic.WithTLS(),
hsic.WithHostnameAsServerURL(),
)

if err != nil {
t.Errorf("failed to create headscale environment: %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)
}

err = scenario.WaitForTailscaleSync()
if err != nil {
t.Errorf("failed wait for tailscale clients to be in sync: %s", err)
}

allHostnames, err := scenario.ListTailscaleClientsFQDNs()
if err != nil {
t.Errorf("failed to get FQDNs: %s", err)
}

success := pingDerpAllHelper(t, allClients, allHostnames)

t.Logf("%d successful pings out of %d", success, len(allClients)*len(allIps))

err = scenario.Shutdown()
if err != nil {
t.Errorf("failed to tear down scenario: %s", err)
}
}

func (s *EmbeddedDERPServerScenario) CreateHeadscaleEnv(
users map[string]int,
opts ...hsic.Option,
) error {
hsServer, err := s.Headscale(opts...)
if err != nil {
return err
}

headscaleEndpoint := hsServer.GetEndpoint()
headscaleURL, err := url.Parse(headscaleEndpoint)
if err != nil {
return err
}

headscaleURL.Host = fmt.Sprintf("%s:%s", hsServer.GetHostname(), headscaleURL.Port())

extraHosts := []string{
"host.docker.internal:host-gateway",
fmt.Sprintf("%s:host-gateway", hsServer.GetHostname()),
}

err = hsServer.WaitForReady()
if err != nil {
return err
}

hash, err := headscale.GenerateRandomStringDNSSafe(scenarioHashLength)
if err != nil {
return err
}

for userName, clientCount := range users {
err = s.CreateUser(userName)
if err != nil {
return err
}

err = s.CreateTailscaleIsolatedNodesInUser(
hash,
userName,
"all",
clientCount,
tsic.WithExtraHosts(extraHosts),
)
if err != nil {
return err
}

key, err := s.CreatePreAuthKey(userName, true, false)
if err != nil {
return err
}

err = s.RunTailscaleUp(userName, headscaleURL.String(), key.GetKey())
if err != nil {
return err
}
}

return nil
}

func (s *EmbeddedDERPServerScenario) CreateTailscaleIsolatedNodesInUser(
hash string,
userStr string,
requestedVersion string,
count int,
opts ...tsic.Option,
) error {
if user, ok := s.users[userStr]; ok {
for clientN := 0; clientN < count; clientN++ {
networkName := fmt.Sprintf("tsnet-%s-%s-%d",
hash,
userStr,
clientN,
)
network, err := dockertestutil.GetFirstOrCreateNetwork(
s.pool,
networkName,
)
if err != nil {
return fmt.Errorf("failed to create or get %s network: %w", networkName, err)
}

s.tsicNetworks[networkName] = network

version := requestedVersion
if requestedVersion == "all" {
version = TailscaleVersions[clientN%len(TailscaleVersions)]
}

headscale, err := s.Headscale()
if err != nil {
return fmt.Errorf("failed to create tailscale node: %w", err)
}

cert := headscale.GetCert()
hostname := headscale.GetHostname()

user.createWaitGroup.Add(1)

opts = append(opts,
tsic.WithHeadscaleTLS(cert),
tsic.WithHeadscaleName(hostname),
)

go func() {
defer user.createWaitGroup.Done()

// TODO(kradalby): error handle this
tsClient, err := tsic.New(
s.pool,
version,
network,
opts...,
)
if err != nil {
// return fmt.Errorf("failed to add tailscale node: %w", err)
log.Printf("failed to create tailscale node: %s", err)
}

err = tsClient.WaitForReady()
if err != nil {
// return fmt.Errorf("failed to add tailscale node: %w", err)
log.Printf("failed to wait for tailscaled: %s", err)
}

user.Clients[tsClient.Hostname()] = tsClient
}()
}
user.createWaitGroup.Wait()

return nil
}

return fmt.Errorf("failed to add tailscale node: %w", errNoUserAvailable)
}

func (s *EmbeddedDERPServerScenario) Shutdown() error {
for _, network := range s.tsicNetworks {
err := s.pool.RemoveNetwork(network)
if err != nil {
return err
}
}

return s.Scenario.Shutdown()
}
8 changes: 4 additions & 4 deletions integration/hsic/hsic.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func WithPort(port int) Option {
}
}

// WithExtraPorts exposes additional ports on the container (e.g. 3478/udp for STUN)
// WithExtraPorts exposes additional ports on the container (e.g. 3478/udp for STUN).
func WithExtraPorts(ports []string) Option {
return func(hsic *HeadscaleInContainer) {
hsic.extraPorts = ports
Expand Down Expand Up @@ -190,14 +190,14 @@ func New(

portProto := fmt.Sprintf("%d/tcp", hsic.port)

serverUrl, err := url.Parse(hsic.env["HEADSCALE_SERVER_URL"])
serverURL, err := url.Parse(hsic.env["HEADSCALE_SERVER_URL"])
if err != nil {
return nil, err
}

if len(hsic.tlsCert) != 0 && len(hsic.tlsKey) != 0 {
serverUrl.Scheme = "https"
hsic.env["HEADSCALE_SERVER_URL"] = serverUrl.String()
serverURL.Scheme = "https"
hsic.env["HEADSCALE_SERVER_URL"] = serverURL.String()
}

headscaleBuildOptions := &dockertest.BuildOptions{
Expand Down
11 changes: 1 addition & 10 deletions integration/tsic/tsic.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,15 +499,6 @@ type (
}
)

type (
DERPPingOption = func(args *derpPingArgs)

derpPingArgs struct {
timeout time.Duration
count int
}
)

// WithPingTimeout sets the timeout for the ping command.
func WithPingTimeout(timeout time.Duration) PingOption {
return func(args *pingArgs) {
Expand Down Expand Up @@ -605,7 +596,7 @@ func (t *TailscaleInContainer) PingViaDERP(hostnameOrIP string, opts ...PingOpti
),
)
if err != nil {
fmt.Printf(
log.Printf(
"failed to run ping command from %s to %s, err: %s",
t.Hostname(),
hostnameOrIP,
Expand Down
9 changes: 7 additions & 2 deletions integration/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import (
"github.com/juanfont/headscale/integration/tsic"
)

const (
derpPingTimeout = 2 * time.Second
derpPingCount = 10
)

func pingAllHelper(t *testing.T, clients []TailscaleClient, addrs []string) int {
t.Helper()
success := 0
Expand Down Expand Up @@ -37,8 +42,8 @@ func pingDerpAllHelper(t *testing.T, clients []TailscaleClient, addrs []string)

err := client.PingViaDERP(
addr,
tsic.WithPingTimeout(2*time.Second),
tsic.WithPingCount(10),
tsic.WithPingTimeout(derpPingTimeout),
tsic.WithPingCount(derpPingCount),
)
if err != nil {
t.Errorf("failed to ping %s from %s: %s", addr, client.Hostname(), err)
Expand Down

0 comments on commit eacd687

Please sign in to comment.