blob: 581b8461082cafd7bc8e44bdbc56e7d2bfa13f7b [file] [log] [blame]
Filip Tehlar229f5fc2022-08-09 14:44:47 +00001package main
2
3import (
4 "context"
5 "encoding/json"
6 "errors"
7 "fmt"
8 "io"
9 "io/ioutil"
10 "os"
11 "os/exec"
12 "strings"
Filip Tehlar229f5fc2022-08-09 14:44:47 +000013 "time"
14
15 "github.com/edwarnicke/exechelper"
16)
17
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010018// TODO remove `configTemplate` once its usage has been replaced everywhere with VppConfig
Filip Tehlar229f5fc2022-08-09 14:44:47 +000019const configTemplate = `unix {
20 nodaemon
21 log %[1]s/var/log/vpp/vpp.log
22 full-coredump
23 cli-listen %[1]s/var/run/vpp/cli.sock
24 runtime-dir %[1]s/var/run
25 gid vpp
26}
27
28api-trace {
29 on
30}
31
32api-segment {
33 gid vpp
34}
35
36socksvr {
37 socket-name %[1]s/var/run/vpp/api.sock
38}
39
40statseg {
41 socket-name %[1]s/var/run/vpp/stats.sock
42}
43
44plugins {
45 plugin unittest_plugin.so { enable }
46 plugin dpdk_plugin.so { disable }
47 plugin crypto_aesni_plugin.so { enable }
48 plugin quic_plugin.so { enable }
Filip Tehlarb15a0002022-11-10 12:34:17 +010049 plugin crypto_ipsecmb_plugin.so { disable }
Filip Tehlar229f5fc2022-08-09 14:44:47 +000050}
51
52`
53
Maros Ondrejicka0db15752022-10-12 22:58:01 +020054const vclTemplate = `vcl {
55 app-socket-api %[1]s
56 app-scope-global
57 app-scope-local
58 namespace-id %[2]s
59 namespace-secret %[2]s
60 use-mq-eventfd
61}
62`
63
Filip Tehlar229f5fc2022-08-09 14:44:47 +000064const TopologyDir string = "topo/"
65
66type Stanza struct {
67 content string
68 pad int
69}
70
71type ActionResult struct {
72 Err error
73 Desc string
74 ErrOutput string
75 StdOutput string
76}
77
78type JsonResult struct {
79 Code int
80 Desc string
81 ErrOutput string
82 StdOutput string
83}
84
85func StartServerApp(running chan error, done chan struct{}, env []string) {
86 cmd := exec.Command("iperf3", "-4", "-s")
87 if env != nil {
88 cmd.Env = env
89 }
90 err := cmd.Start()
91 if err != nil {
92 msg := fmt.Errorf("failed to start iperf server: %v", err)
93 running <- msg
94 return
95 }
96 running <- nil
97 <-done
98 cmd.Process.Kill()
99}
100
101func StartClientApp(env []string, clnCh chan error) {
102 defer func() {
103 clnCh <- nil
104 }()
105
106 nTries := 0
107
108 for {
109 cmd := exec.Command("iperf3", "-c", "10.10.10.1", "-u", "-l", "1460", "-b", "10g")
110 if env != nil {
111 cmd.Env = env
112 }
113 o, err := cmd.CombinedOutput()
114 if err != nil {
115 if nTries > 5 {
116 clnCh <- fmt.Errorf("failed to start client app '%s'.\n%s", err, o)
117 return
118 }
119 time.Sleep(1 * time.Second)
120 nTries++
121 continue
122 } else {
123 fmt.Printf("Client output: %s", o)
124 }
125 break
126 }
127}
128
129// run vpphelper in docker
130func hstExec(args string, instance string) (string, error) {
131 syncFile := fmt.Sprintf("/tmp/%s/sync/rc", instance)
132 os.Remove(syncFile)
133
134 c := "docker exec -d " + instance + " /hs-test " + args
135 err := exechelper.Run(c)
136 if err != nil {
137 return "", err
138 }
139
140 res, err := waitForSyncFile(syncFile)
141
142 if err != nil {
143 return "", fmt.Errorf("failed to read sync file while executing './hs-test %s': %v", args, err)
144 }
145
146 o := res.StdOutput + res.ErrOutput
147 if res.Code != 0 {
148 return o, fmt.Errorf("cmd resulted in non-zero value %d: %s", res.Code, res.Desc)
149 }
150 return o, err
151}
152
153func waitForSyncFile(fname string) (*JsonResult, error) {
154 var res JsonResult
155
Maros Ondrejicka0db15752022-10-12 22:58:01 +0200156 for i := 0; i < 360; i++ {
Filip Tehlar229f5fc2022-08-09 14:44:47 +0000157 f, err := os.Open(fname)
158 if err == nil {
159 defer f.Close()
160
161 data, err := ioutil.ReadFile(fname)
162 if err != nil {
163 return nil, fmt.Errorf("read error: %v", err)
164 }
165 err = json.Unmarshal(data, &res)
166 if err != nil {
167 return nil, fmt.Errorf("json unmarshal error: %v", err)
168 }
169 return &res, nil
170 }
171 time.Sleep(1 * time.Second)
172 }
173 return nil, fmt.Errorf("no sync file found")
174}
175
176func dockerRun(instance, args string) error {
177 exechelper.Run(fmt.Sprintf("mkdir -p /tmp/%s/sync", instance))
178 syncPath := fmt.Sprintf("-v /tmp/%s/sync:/tmp/sync", instance)
179 cmd := "docker run --cap-add=all -d --privileged --network host --rm "
180 cmd += syncPath
181 cmd += " " + args
182 cmd += " --name " + instance + " hs-test/vpp"
183 fmt.Println(cmd)
184 return exechelper.Run(cmd)
185}
186
187func assertFileSize(f1, f2 string) error {
188 fi1, err := os.Stat(f1)
189 if err != nil {
190 return err
191 }
192
193 fi2, err1 := os.Stat(f2)
194 if err1 != nil {
195 return err1
196 }
197
198 if fi1.Size() != fi2.Size() {
199 return fmt.Errorf("file sizes differ (%d vs %d)", fi1.Size(), fi2.Size())
200 }
201 return nil
202}
203
204func dockerExec(cmd string, instance string) ([]byte, error) {
205 c := "docker exec -d " + instance + " " + cmd
206 return exechelper.CombinedOutput(c)
207}
208
209func startEnvoy(ctx context.Context, dockerInstance string) <-chan error {
210 errCh := make(chan error)
211 wd, err := os.Getwd()
212 if err != nil {
213 errCh <- err
214 return errCh
215 }
216
217 c := []string{"docker", "run", "--rm", "--name", "envoy",
218 "-v", fmt.Sprintf("%s/envoy/proxy.yaml:/etc/envoy/envoy.yaml", wd),
219 "-v", fmt.Sprintf("shared-vol:/tmp/%s", dockerInstance),
220 "-v", fmt.Sprintf("%s/envoy:/tmp", wd),
Maros Ondrejickaeeaf6c82022-10-13 15:38:17 +0200221 "-e", "ENVOY_UID=0",
Filip Tehlar229f5fc2022-08-09 14:44:47 +0000222 "-e", "VCL_CONFIG=/tmp/vcl.conf",
223 "envoyproxy/envoy-contrib:v1.21-latest"}
224 fmt.Println(c)
225
226 go func(errCh chan error) {
227 count := 0
228 var cmd *exec.Cmd
229 for ; ; count++ {
230 cmd = NewCommand(c, "")
231 err = cmd.Start()
232 if err == nil {
233 break
234 }
235 if count > 5 {
Maros Ondrejickaeeaf6c82022-10-13 15:38:17 +0200236 errCh <- fmt.Errorf("failed to start envoy docker after %d attempts", count)
Filip Tehlar229f5fc2022-08-09 14:44:47 +0000237 return
238 }
239 }
240
241 err = cmd.Wait()
242 if err != nil {
243 errCh <- fmt.Errorf("failed to start docker: %v", err)
244 return
245 }
246 <-ctx.Done()
247 }(errCh)
248 return errCh
249}
250
Filip Tehlar229f5fc2022-08-09 14:44:47 +0000251func configureVppProxy() error {
252 _, err := dockerExec("vppctl test proxy server server-uri tcp://10.0.0.2/555 client-uri tcp://10.0.1.1/666",
253 "vpp-proxy")
254 if err != nil {
255 return fmt.Errorf("error while configuring vpp proxy test: %v", err)
256 }
257 return nil
258}
259
260func startHttpServer(running chan struct{}, done chan struct{}, addressPort, netNs string) {
261 cmd := NewCommand([]string{"./http_server", addressPort}, netNs)
262 err := cmd.Start()
263 if err != nil {
264 fmt.Println("Failed to start http server")
265 return
266 }
267 running <- struct{}{}
268 <-done
269 cmd.Process.Kill()
270}
271
272func startWget(finished chan error, server_ip, port string, netNs string) {
273 fname := "test_file_10M"
274 defer func() {
275 finished <- errors.New("wget error")
276 }()
277
278 cmd := NewCommand([]string{"wget", "--tries=5", "-q", "-O", "/dev/null", server_ip + ":" + port + "/" + fname},
279 netNs)
280 o, err := cmd.CombinedOutput()
281 if err != nil {
282 fmt.Printf("wget error: '%s'.\n%s", err, o)
283 return
284 }
285 fmt.Printf("Client output: %s", o)
286 finished <- nil
287}
288
289func (c *Stanza) NewStanza(name string) *Stanza {
290 c.Append("\n" + name + " {")
291 c.pad += 2
292 return c
293}
294
295func (c *Stanza) Append(name string) *Stanza {
296 c.content += strings.Repeat(" ", c.pad)
297 c.content += name + "\n"
298 return c
299}
300
301func (c *Stanza) Close() *Stanza {
302 c.content += "}\n"
303 c.pad -= 2
304 return c
305}
306
307func (s *Stanza) ToString() string {
308 return s.content
309}
310
311func (s *Stanza) SaveToFile(fileName string) error {
312 fo, err := os.Create(fileName)
313 if err != nil {
314 return err
315 }
316 defer fo.Close()
317
318 _, err = io.Copy(fo, strings.NewReader(s.content))
319 return err
320}