Merge pull request #884 from kradalby/integration-v2-ping-by-hostname

This commit is contained in:
Kristoffer Dalby 2022-10-23 14:12:06 +02:00 committed by GitHub
commit ae189c03ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 157 additions and 40 deletions

View file

@ -1,6 +1,8 @@
package integration
import v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
import (
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
)
type ControlServer interface {
Shutdown() error
@ -9,5 +11,5 @@ type ControlServer interface {
WaitForReady() error
CreateNamespace(namespace string) error
CreateAuthKey(namespace string) (*v1.PreAuthKey, error)
ListNodes(namespace string) ([]*v1.Machine, error)
ListMachinesInNamespace(namespace string) ([]*v1.Machine, error)
}

View file

@ -1,11 +1,10 @@
package integration
import (
"net/netip"
"testing"
)
func TestPingAll(t *testing.T) {
func TestPingAllByIP(t *testing.T) {
IntegrationSkip(t)
scenario, err := NewScenario()
@ -23,30 +22,14 @@ func TestPingAll(t *testing.T) {
t.Errorf("failed to create headscale environment: %s", err)
}
var allIps []netip.Addr
var allClients []TailscaleClient
allClients, err := scenario.ListTailscaleClients()
if err != nil {
t.Errorf("failed to get clients: %s", err)
}
for namespace, count := range spec {
ips, err := scenario.GetIPs(namespace)
if err != nil {
t.Errorf("failed to get tailscale ips: %s", err)
}
if len(ips) != count*2 {
t.Errorf(
"got the wrong amount of tailscale ips, %d != %d",
len(ips),
count*2,
)
}
clients, err := scenario.GetClients(namespace)
if err != nil {
t.Errorf("failed to get tailscale clients: %s", err)
}
allIps = append(allIps, ips...)
allClients = append(allClients, clients...)
allIps, err := scenario.ListTailscaleClientsIPs()
if err != nil {
t.Errorf("failed to get clients: %s", err)
}
err = scenario.WaitForTailscaleSync()
@ -58,7 +41,7 @@ func TestPingAll(t *testing.T) {
for _, client := range allClients {
for _, ip := range allIps {
err := client.Ping(ip)
err := client.Ping(ip.String())
if err != nil {
t.Errorf("failed to ping %s from %s: %s", ip, client.Hostname(), err)
} else {
@ -69,8 +52,63 @@ func TestPingAll(t *testing.T) {
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)
// }
err = scenario.Shutdown()
if err != nil {
t.Errorf("failed to tear down scenario: %s", err)
}
}
func TestPingAllByHostname(t *testing.T) {
IntegrationSkip(t)
scenario, err := NewScenario()
if err != nil {
t.Errorf("failed to create scenario: %s", err)
}
spec := map[string]int{
// Omit 1.16.2 (-1) because it does not have the FQDN field
"namespace3": len(TailscaleVersions) - 1,
"namespace4": len(TailscaleVersions) - 1,
}
err = scenario.CreateHeadscaleEnv(spec)
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)
}
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 := 0
for _, client := range allClients {
for _, hostname := range allHostnames {
err := client.Ping(hostname)
if err != nil {
t.Errorf("failed to ping %s from %s: %s", hostname, client.Hostname(), err)
} else {
success++
}
}
}
t.Logf("%d successful pings out of %d", success, len(allClients)*len(allClients))
err = scenario.Shutdown()
if err != nil {
t.Errorf("failed to tear down scenario: %s", err)
}
}

View file

@ -199,7 +199,7 @@ func (t *HeadscaleInContainer) CreateAuthKey(
return &preAuthKey, nil
}
func (t *HeadscaleInContainer) ListNodes(
func (t *HeadscaleInContainer) ListMachinesInNamespace(
namespace string,
) ([]*v1.Machine, error) {
command := []string{"headscale", "--namespace", namespace, "nodes", "list", "--output", "json"}

View file

@ -29,7 +29,7 @@ var (
TailscaleVersions = []string{
"head",
"unstable",
"1.32.0",
"1.32.1",
"1.30.2",
"1.28.0",
"1.26.2",
@ -138,6 +138,15 @@ func (s *Scenario) Shutdown() error {
return nil
}
func (s *Scenario) Namespaces() []string {
namespaces := make([]string, 0)
for namespace := range s.namespaces {
namespaces = append(namespaces, namespace)
}
return namespaces
}
/// Headscale related stuff
// Note: These functions assume that there is a _single_ headscale instance for now
@ -345,3 +354,61 @@ func (s *Scenario) GetClients(namespace string) ([]TailscaleClient, error) {
return clients, fmt.Errorf("failed to get clients: %w", errNoNamespaceAvailable)
}
func (s *Scenario) ListTailscaleClients(namespaces ...string) ([]TailscaleClient, error) {
var allClients []TailscaleClient
if len(namespaces) == 0 {
namespaces = s.Namespaces()
}
for _, namespace := range namespaces {
clients, err := s.GetClients(namespace)
if err != nil {
return nil, err
}
allClients = append(allClients, clients...)
}
return allClients, nil
}
func (s *Scenario) ListTailscaleClientsIPs(namespaces ...string) ([]netip.Addr, error) {
var allIps []netip.Addr
if len(namespaces) == 0 {
namespaces = s.Namespaces()
}
for _, namespace := range namespaces {
ips, err := s.GetIPs(namespace)
if err != nil {
return nil, err
}
allIps = append(allIps, ips...)
}
return allIps, nil
}
func (s *Scenario) ListTailscaleClientsFQDNs(namespaces ...string) ([]string, error) {
allFQDNs := make([]string, 0)
clients, err := s.ListTailscaleClients(namespaces...)
if err != nil {
return nil, err
}
for _, client := range clients {
fqdn, err := client.FQDN()
if err != nil {
return nil, err
}
allFQDNs = append(allFQDNs, fqdn)
}
return allFQDNs, nil
}

View file

@ -12,7 +12,8 @@ type TailscaleClient interface {
Version() string
Up(loginServer, authKey string) error
IPs() ([]netip.Addr, error)
FQDN() (string, error)
Status() (*ipnstate.Status, error)
WaitForPeers(expected int) error
Ping(ip netip.Addr) error
Ping(hostnameOrIP string) error
}

View file

@ -46,7 +46,7 @@ func New(
return nil, err
}
hostname := fmt.Sprintf("ts-%s-%s", version, hash)
hostname := fmt.Sprintf("ts-%s-%s", strings.ReplaceAll(version, ".", "-"), hash)
// TODO(kradalby): figure out why we need to "refresh" the network here.
// network, err = dockertestutil.GetFirstOrCreateNetwork(pool, network.Network.Name)
@ -204,6 +204,15 @@ func (t *TailscaleInContainer) Status() (*ipnstate.Status, error) {
return &status, err
}
func (t *TailscaleInContainer) FQDN() (string, error) {
status, err := t.Status()
if err != nil {
return "", fmt.Errorf("failed to get FQDN: %w", err)
}
return status.Self.DNSName, nil
}
func (t *TailscaleInContainer) WaitForPeers(expected int) error {
return t.pool.Retry(func() error {
status, err := t.Status()
@ -220,14 +229,14 @@ func (t *TailscaleInContainer) WaitForPeers(expected int) error {
}
// TODO(kradalby): Make multiping, go routine magic.
func (t *TailscaleInContainer) Ping(ip netip.Addr) error {
func (t *TailscaleInContainer) Ping(hostnameOrIP string) error {
return t.pool.Retry(func() error {
command := []string{
"tailscale", "ping",
"--timeout=1s",
"--c=10",
"--until-direct=true",
ip.String(),
hostnameOrIP,
}
result, _, err := dockertestutil.ExecuteCommand(
@ -238,8 +247,8 @@ func (t *TailscaleInContainer) Ping(ip netip.Addr) error {
if err != nil {
log.Printf(
"failed to run ping command from %s to %s, err: %s",
t.hostname,
ip.String(),
t.Hostname(),
hostnameOrIP,
err,
)