blob: 4ad454848fa8f15a3ca9d02a90f220c4ed8538fc [file] [log] [blame]
Maros Ondrejicka11a03e92022-12-01 09:56:37 +01001package main
2
3import (
4 "fmt"
Maros Ondrejickadb823ed2022-12-14 16:30:04 +01005 "os"
6 "strings"
Maros Ondrejicka11a03e92022-12-01 09:56:37 +01007
8 "github.com/edwarnicke/exechelper"
9)
10
Maros Ondrejicka0e79abb2022-12-06 19:46:24 +010011type Volume struct {
Maros Ondrejickadb823ed2022-12-14 16:30:04 +010012 hostDir string
13 containerDir string
Maros Ondrejicka0e79abb2022-12-06 19:46:24 +010014}
15
16type Container struct {
Maros Ondrejickadb823ed2022-12-14 16:30:04 +010017 isOptional bool
18 name string
19 image string
20 workDir string
21 volumes map[string]Volume
22 envVars map[string]string
23}
24
25func NewContainer(yamlInput ContainerConfig) (*Container, error) {
26 containerName := yamlInput["name"].(string)
27 if len(containerName) == 0 {
28 err := fmt.Errorf("container name must not be blank")
29 return nil, err
30 }
31
32 var container = new(Container)
33 container.volumes = make(map[string]Volume)
34 container.envVars = make(map[string]string)
35 container.name = containerName
36
37 if image, ok := yamlInput["image"]; ok {
38 container.image = image.(string)
39 } else {
40 container.image = "hs-test/vpp"
41 }
42
43 if isOptional, ok := yamlInput["is-optional"]; ok {
44 container.isOptional = isOptional.(bool)
45 } else {
46 container.isOptional = false
47 }
48
49 if _, ok := yamlInput["volumes"]; ok {
Filip Tehlarf3ee2b62023-01-09 12:07:09 +010050 r := strings.NewReplacer("$HST_DIR", workDir)
Maros Ondrejickadb823ed2022-12-14 16:30:04 +010051 for _, volu := range yamlInput["volumes"].([]interface{}) {
52 volumeMap := volu.(ContainerConfig)
53 hostDir := r.Replace(volumeMap["host-dir"].(string))
54 containerDir := volumeMap["container-dir"].(string)
55 container.addVolume(hostDir, containerDir)
56
57 if isDefaultWorkDir, ok := volumeMap["is-default-work-dir"]; ok &&
Filip Tehlarf3ee2b62023-01-09 12:07:09 +010058 isDefaultWorkDir.(bool) &&
59 len(container.workDir) == 0 {
Maros Ondrejickadb823ed2022-12-14 16:30:04 +010060 container.workDir = containerDir
61 }
62
63 }
64 }
65
66 if _, ok := yamlInput["vars"]; ok {
67 for _, envVar := range yamlInput["vars"].([]interface{}) {
68 container.addEnvVar(envVar)
69 }
70 }
71 return container, nil
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010072}
73
Maros Ondrejicka87531802022-12-19 20:35:27 +010074func (c *Container) getRunCommand() string {
Maros Ondrejickadb823ed2022-12-14 16:30:04 +010075 syncPath := fmt.Sprintf(" -v %s:/tmp/sync", c.getSyncPath())
76 cmd := "docker run --cap-add=all -d --privileged --network host --rm"
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010077 cmd += syncPath
Maros Ondrejickadb823ed2022-12-14 16:30:04 +010078 cmd += c.getVolumesAsCliOption()
79 cmd += c.getEnvVarsAsCliOption()
80 cmd += " --name " + c.name + " " + c.image
Maros Ondrejicka87531802022-12-19 20:35:27 +010081 return cmd
82}
83
84func (c *Container) run() error {
85 if c.name == "" {
86 return fmt.Errorf("run container failed: name is blank")
87 }
88
89 exechelper.Run(fmt.Sprintf("mkdir -p /tmp/%s/sync", c.name))
90 cmd := c.getRunCommand()
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010091 err := exechelper.Run(cmd)
92 if err != nil {
Maros Ondrejickadb823ed2022-12-14 16:30:04 +010093 return fmt.Errorf("container run failed: %s", err)
Maros Ondrejicka11a03e92022-12-01 09:56:37 +010094 }
95
96 return nil
97}
98
Maros Ondrejickadb823ed2022-12-14 16:30:04 +010099func (c *Container) addVolume(hostDir string, containerDir string) {
100 var volume Volume
101 volume.hostDir = hostDir
102 volume.containerDir = containerDir
103 c.volumes[hostDir] = volume
Maros Ondrejicka0e79abb2022-12-06 19:46:24 +0100104}
105
Maros Ondrejickadb823ed2022-12-14 16:30:04 +0100106func (c *Container) getVolumeByHostDir(hostDir string) Volume {
107 return c.volumes[hostDir]
108}
109
110func (c *Container) getVolumesAsCliOption() string {
111 cliOption := ""
Maros Ondrejicka0e79abb2022-12-06 19:46:24 +0100112
113 if len(c.volumes) > 0 {
114 for _, volume := range c.volumes {
Maros Ondrejickadb823ed2022-12-14 16:30:04 +0100115 cliOption += fmt.Sprintf(" -v %s:%s", volume.hostDir, volume.containerDir)
Maros Ondrejicka0e79abb2022-12-06 19:46:24 +0100116 }
117 }
118
Maros Ondrejickadb823ed2022-12-14 16:30:04 +0100119 return cliOption
120}
121
122func (c *Container) getWorkDirAsCliOption() string {
123 if len(c.workDir) == 0 {
124 return ""
125 }
126 return fmt.Sprintf(" --workdir=\"%s\"", c.workDir)
127}
128
129func (c *Container) addEnvVar(envVar interface{}) {
130 envVarMap := envVar.(ContainerConfig)
131 name := envVarMap["name"].(string)
132 value := envVarMap["value"].(string)
133 c.envVars[name] = value
134}
135
136func (c *Container) getEnvVarsAsCliOption() string {
137 cliOption := ""
138 if len(c.envVars) == 0 {
139 return cliOption
140 }
141
142 for name, value := range c.envVars {
143 cliOption += fmt.Sprintf(" -e %s=%s", name, value)
144 }
145 return cliOption
146}
147
148func (c *Container) getSyncPath() string {
149 return fmt.Sprintf("/tmp/%s/sync", c.name)
150}
151
152func (c *Container) exec(command string) (string, error) {
153 cliCommand := "docker exec -d " + c.name + " " + command
154 byteOutput, err := exechelper.CombinedOutput(cliCommand)
155 return string(byteOutput), err
156}
157
158func (c *Container) execAction(args string) (string, error) {
159 syncFile := c.getSyncPath() + "/rc"
160 os.Remove(syncFile)
161
162 workDir := c.getWorkDirAsCliOption()
163 cmd := fmt.Sprintf("docker exec -d %s %s hs-test %s",
164 workDir,
165 c.name,
166 args)
167 err := exechelper.Run(cmd)
168 if err != nil {
169 return "", err
170 }
171 res, err := waitForSyncFile(syncFile)
172 if err != nil {
173 return "", fmt.Errorf("failed to read sync file while executing 'hs-test %s': %v", args, err)
174 }
175 o := res.StdOutput + res.ErrOutput
176 if res.Code != 0 {
177 return o, fmt.Errorf("cmd resulted in non-zero value %d: %s", res.Code, res.Desc)
178 }
179 return o, err
Maros Ondrejicka0e79abb2022-12-06 19:46:24 +0100180}
181
182func (c *Container) stop() error {
183 return exechelper.Run("docker stop " + c.name)
184}