98a91e8260
Type: test Signed-off-by: Maros Ondrejicka <maros.ondrejicka@pantheon.tech> Change-Id: I1653001461d4dfc52f1fb3a9e0cf458a506b8324
321 lines
6.4 KiB
Go
Executable File
321 lines
6.4 KiB
Go
Executable File
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/edwarnicke/exechelper"
|
|
)
|
|
|
|
// TODO remove `configTemplate` once its usage has been replaced everywhere with VppConfig
|
|
const configTemplate = `unix {
|
|
nodaemon
|
|
log %[1]s/var/log/vpp/vpp.log
|
|
full-coredump
|
|
cli-listen %[1]s/var/run/vpp/cli.sock
|
|
runtime-dir %[1]s/var/run
|
|
gid vpp
|
|
}
|
|
|
|
api-trace {
|
|
on
|
|
}
|
|
|
|
api-segment {
|
|
gid vpp
|
|
}
|
|
|
|
socksvr {
|
|
socket-name %[1]s/var/run/vpp/api.sock
|
|
}
|
|
|
|
statseg {
|
|
socket-name %[1]s/var/run/vpp/stats.sock
|
|
}
|
|
|
|
plugins {
|
|
plugin unittest_plugin.so { enable }
|
|
plugin dpdk_plugin.so { disable }
|
|
plugin crypto_aesni_plugin.so { enable }
|
|
plugin quic_plugin.so { enable }
|
|
plugin crypto_ipsecmb_plugin.so { disable }
|
|
}
|
|
|
|
`
|
|
|
|
const vclTemplate = `vcl {
|
|
app-socket-api %[1]s
|
|
app-scope-global
|
|
app-scope-local
|
|
namespace-id %[2]s
|
|
namespace-secret %[2]s
|
|
use-mq-eventfd
|
|
}
|
|
`
|
|
|
|
const TopologyDir string = "topo/"
|
|
|
|
type Stanza struct {
|
|
content string
|
|
pad int
|
|
}
|
|
|
|
type ActionResult struct {
|
|
Err error
|
|
Desc string
|
|
ErrOutput string
|
|
StdOutput string
|
|
}
|
|
|
|
type JsonResult struct {
|
|
Code int
|
|
Desc string
|
|
ErrOutput string
|
|
StdOutput string
|
|
}
|
|
|
|
func StartServerApp(running chan error, done chan struct{}, env []string) {
|
|
cmd := exec.Command("iperf3", "-4", "-s")
|
|
if env != nil {
|
|
cmd.Env = env
|
|
}
|
|
err := cmd.Start()
|
|
if err != nil {
|
|
msg := fmt.Errorf("failed to start iperf server: %v", err)
|
|
running <- msg
|
|
return
|
|
}
|
|
running <- nil
|
|
<-done
|
|
cmd.Process.Kill()
|
|
}
|
|
|
|
func StartClientApp(env []string, clnCh chan error) {
|
|
defer func() {
|
|
clnCh <- nil
|
|
}()
|
|
|
|
nTries := 0
|
|
|
|
for {
|
|
cmd := exec.Command("iperf3", "-c", "10.10.10.1", "-u", "-l", "1460", "-b", "10g")
|
|
if env != nil {
|
|
cmd.Env = env
|
|
}
|
|
o, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
if nTries > 5 {
|
|
clnCh <- fmt.Errorf("failed to start client app '%s'.\n%s", err, o)
|
|
return
|
|
}
|
|
time.Sleep(1 * time.Second)
|
|
nTries++
|
|
continue
|
|
} else {
|
|
fmt.Printf("Client output: %s", o)
|
|
}
|
|
break
|
|
}
|
|
}
|
|
|
|
// run vpphelper in docker
|
|
func hstExec(args string, instance string) (string, error) {
|
|
syncFile := fmt.Sprintf("/tmp/%s/sync/rc", instance)
|
|
os.Remove(syncFile)
|
|
|
|
c := "docker exec -d " + instance + " /hs-test " + args
|
|
err := exechelper.Run(c)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
res, err := waitForSyncFile(syncFile)
|
|
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to read sync file while executing './hs-test %s': %v", args, err)
|
|
}
|
|
|
|
o := res.StdOutput + res.ErrOutput
|
|
if res.Code != 0 {
|
|
return o, fmt.Errorf("cmd resulted in non-zero value %d: %s", res.Code, res.Desc)
|
|
}
|
|
return o, err
|
|
}
|
|
|
|
func waitForSyncFile(fname string) (*JsonResult, error) {
|
|
var res JsonResult
|
|
|
|
for i := 0; i < 360; i++ {
|
|
f, err := os.Open(fname)
|
|
if err == nil {
|
|
defer f.Close()
|
|
|
|
data, err := ioutil.ReadFile(fname)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read error: %v", err)
|
|
}
|
|
err = json.Unmarshal(data, &res)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("json unmarshal error: %v", err)
|
|
}
|
|
return &res, nil
|
|
}
|
|
time.Sleep(1 * time.Second)
|
|
}
|
|
return nil, fmt.Errorf("no sync file found")
|
|
}
|
|
|
|
func dockerRun(instance, args string) error {
|
|
exechelper.Run(fmt.Sprintf("mkdir -p /tmp/%s/sync", instance))
|
|
syncPath := fmt.Sprintf("-v /tmp/%s/sync:/tmp/sync", instance)
|
|
cmd := "docker run --cap-add=all -d --privileged --network host --rm "
|
|
cmd += syncPath
|
|
cmd += " " + args
|
|
cmd += " --name " + instance + " hs-test/vpp"
|
|
fmt.Println(cmd)
|
|
return exechelper.Run(cmd)
|
|
}
|
|
|
|
func assertFileSize(f1, f2 string) error {
|
|
fi1, err := os.Stat(f1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fi2, err1 := os.Stat(f2)
|
|
if err1 != nil {
|
|
return err1
|
|
}
|
|
|
|
if fi1.Size() != fi2.Size() {
|
|
return fmt.Errorf("file sizes differ (%d vs %d)", fi1.Size(), fi2.Size())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func dockerExec(cmd string, instance string) ([]byte, error) {
|
|
c := "docker exec -d " + instance + " " + cmd
|
|
return exechelper.CombinedOutput(c)
|
|
}
|
|
|
|
func startEnvoy(ctx context.Context, dockerInstance string) <-chan error {
|
|
errCh := make(chan error)
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
errCh <- err
|
|
return errCh
|
|
}
|
|
|
|
c := []string{"docker", "run", "--rm", "--name", "envoy",
|
|
"-v", fmt.Sprintf("%s/envoy/proxy.yaml:/etc/envoy/envoy.yaml", wd),
|
|
"-v", fmt.Sprintf("shared-vol:/tmp/%s", dockerInstance),
|
|
"-v", fmt.Sprintf("%s/envoy:/tmp", wd),
|
|
"-e", "ENVOY_UID=0",
|
|
"-e", "VCL_CONFIG=/tmp/vcl.conf",
|
|
"envoyproxy/envoy-contrib:v1.21-latest"}
|
|
fmt.Println(c)
|
|
|
|
go func(errCh chan error) {
|
|
count := 0
|
|
var cmd *exec.Cmd
|
|
for ; ; count++ {
|
|
cmd = NewCommand(c, "")
|
|
err = cmd.Start()
|
|
if err == nil {
|
|
break
|
|
}
|
|
if count > 5 {
|
|
errCh <- fmt.Errorf("failed to start envoy docker after %d attempts", count)
|
|
return
|
|
}
|
|
}
|
|
|
|
err = cmd.Wait()
|
|
if err != nil {
|
|
errCh <- fmt.Errorf("failed to start docker: %v", err)
|
|
return
|
|
}
|
|
<-ctx.Done()
|
|
}(errCh)
|
|
return errCh
|
|
}
|
|
|
|
func configureVppProxy() error {
|
|
_, err := dockerExec("vppctl test proxy server server-uri tcp://10.0.0.2/555 client-uri tcp://10.0.1.1/666",
|
|
"vpp-proxy")
|
|
if err != nil {
|
|
return fmt.Errorf("error while configuring vpp proxy test: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func startHttpServer(running chan struct{}, done chan struct{}, addressPort, netNs string) {
|
|
cmd := NewCommand([]string{"./http_server", addressPort}, netNs)
|
|
err := cmd.Start()
|
|
if err != nil {
|
|
fmt.Println("Failed to start http server")
|
|
return
|
|
}
|
|
running <- struct{}{}
|
|
<-done
|
|
cmd.Process.Kill()
|
|
}
|
|
|
|
func startWget(finished chan error, server_ip, port string, netNs string) {
|
|
fname := "test_file_10M"
|
|
defer func() {
|
|
finished <- errors.New("wget error")
|
|
}()
|
|
|
|
cmd := NewCommand([]string{"wget", "--tries=5", "-q", "-O", "/dev/null", server_ip + ":" + port + "/" + fname},
|
|
netNs)
|
|
o, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
fmt.Printf("wget error: '%s'.\n%s", err, o)
|
|
return
|
|
}
|
|
fmt.Printf("Client output: %s", o)
|
|
finished <- nil
|
|
}
|
|
|
|
func (c *Stanza) NewStanza(name string) *Stanza {
|
|
c.Append("\n" + name + " {")
|
|
c.pad += 2
|
|
return c
|
|
}
|
|
|
|
func (c *Stanza) Append(name string) *Stanza {
|
|
c.content += strings.Repeat(" ", c.pad)
|
|
c.content += name + "\n"
|
|
return c
|
|
}
|
|
|
|
func (c *Stanza) Close() *Stanza {
|
|
c.content += "}\n"
|
|
c.pad -= 2
|
|
return c
|
|
}
|
|
|
|
func (s *Stanza) ToString() string {
|
|
return s.content
|
|
}
|
|
|
|
func (s *Stanza) SaveToFile(fileName string) error {
|
|
fo, err := os.Create(fileName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer fo.Close()
|
|
|
|
_, err = io.Copy(fo, strings.NewReader(s.content))
|
|
return err
|
|
}
|