tailscale/tstest/integration/vms/vms_steps_test.go

135 lines
3.0 KiB
Go
Raw Normal View History

// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
package vms
import (
"bytes"
"context"
"fmt"
"net"
"net/http"
"strings"
"testing"
"time"
"golang.org/x/crypto/ssh"
"inet.af/netaddr"
)
const timeout = 15 * time.Second
func retry(t *testing.T, fn func() error) {
t.Helper()
const tries = 3
var err error
for i := 0; i < tries; i++ {
err = fn()
if err != nil {
t.Logf("%dth invocation failed, trying again: %v", i, err)
time.Sleep(50 * time.Millisecond)
}
if err == nil {
return
}
}
t.Fatalf("tried %d times, got: %v", tries, err)
}
func (h *Harness) testPing(t *testing.T, ipAddr netaddr.IP, cli *ssh.Client) {
var outp []byte
var err error
retry(t, func() error {
sess := getSession(t, cli)
outp, err = sess.CombinedOutput(fmt.Sprintf("tailscale ping -c 1 %s", ipAddr))
return err
})
if !bytes.Contains(outp, []byte("pong")) {
t.Log(string(outp))
t.Fatal("no pong")
}
retry(t, func() error {
sess := getSession(t, cli)
// NOTE(Xe): the ping command is inconsistent across distros. Joy.
pingCmd := fmt.Sprintf("sh -c 'ping -c 1 %[1]s || ping -6 -c 1 %[1]s || ping6 -c 1 %[1]s\n'", ipAddr)
t.Logf("running %q", pingCmd)
outp, err = sess.CombinedOutput(pingCmd)
return err
})
if !bytes.Contains(outp, []byte("bytes")) {
t.Log(string(outp))
t.Fatalf("wanted output to contain %q, it did not", "bytes")
}
}
func getSession(t *testing.T, cli *ssh.Client) *ssh.Session {
sess, err := cli.NewSession()
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
sess.Close()
})
return sess
}
func (h *Harness) testOutgoingTCP(t *testing.T, ipAddr netaddr.IP, cli *ssh.Client) {
const sendmsg = "this is a message that curl won't print"
ctx, cancel := context.WithCancel(context.Background())
s := &http.Server{
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t.Logf("http connection from %s", r.RemoteAddr)
cancel()
fmt.Fprintln(w, sendmsg)
}),
}
ln, err := net.Listen("tcp", net.JoinHostPort("::", "0"))
if err != nil {
t.Fatalf("can't make HTTP server: %v", err)
}
_, port, _ := net.SplitHostPort(ln.Addr().String())
go s.Serve(ln)
// sess := getSession(t, cli)
// sess.Stderr = logger.FuncWriter(t.Logf)
// sess.Stdout = logger.FuncWriter(t.Logf)
// sess.Run("ip route show table all")
// sess = getSession(t, cli)
// sess.Stderr = logger.FuncWriter(t.Logf)
// sess.Stdout = logger.FuncWriter(t.Logf)
// sess.Run("sysctl -a")
var outp []byte
retry(t, func() error {
var err error
sess := getSession(t, cli)
v6Arg := ""
if ipAddr.Is6() {
v6Arg = "-6 -g"
}
cmd := fmt.Sprintf("curl -v %s -s -f http://%s\n", v6Arg, net.JoinHostPort(ipAddr.String(), port))
t.Logf("running: %s", cmd)
outp, err = sess.CombinedOutput(cmd)
if err != nil {
t.Log(string(outp))
}
return err
})
if msg := string(bytes.TrimSpace(outp)); !strings.Contains(msg, sendmsg) {
t.Fatalf("wanted %q, got: %q", sendmsg, msg)
}
<-ctx.Done()
}