8 "github.com/edwarnicke/exechelper"
16 type Container struct {
21 volumes map[string]Volume
22 envVars map[string]string
25 func 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")
32 var container = new(Container)
33 container.volumes = make(map[string]Volume)
34 container.envVars = make(map[string]string)
35 container.name = containerName
37 if image, ok := yamlInput["image"]; ok {
38 container.image = image.(string)
40 container.image = "hs-test/vpp"
43 if isOptional, ok := yamlInput["is-optional"]; ok {
44 container.isOptional = isOptional.(bool)
46 container.isOptional = false
49 if _, ok := yamlInput["volumes"]; ok {
50 r:= strings.NewReplacer("$HST_DIR", workDir)
51 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)
57 if isDefaultWorkDir, ok := volumeMap["is-default-work-dir"]; ok &&
58 isDefaultWorkDir.(bool) &&
59 len(container.workDir) == 0 {
60 container.workDir = containerDir
66 if _, ok := yamlInput["vars"]; ok {
67 for _, envVar := range yamlInput["vars"].([]interface{}) {
68 container.addEnvVar(envVar)
74 func (c *Container) run() error {
76 return fmt.Errorf("create volume failed: container name is blank")
79 exechelper.Run(fmt.Sprintf("mkdir -p /tmp/%s/sync", c.name))
80 syncPath := fmt.Sprintf(" -v %s:/tmp/sync", c.getSyncPath())
81 cmd := "docker run --cap-add=all -d --privileged --network host --rm"
83 cmd += c.getVolumesAsCliOption()
84 cmd += c.getEnvVarsAsCliOption()
85 cmd += " --name " + c.name + " " + c.image
87 err := exechelper.Run(cmd)
89 return fmt.Errorf("container run failed: %s", err)
95 func (c *Container) addVolume(hostDir string, containerDir string) {
97 volume.hostDir = hostDir
98 volume.containerDir = containerDir
99 c.volumes[hostDir] = volume
102 func (c *Container) getVolumeByHostDir(hostDir string) Volume {
103 return c.volumes[hostDir]
106 func (c *Container) getVolumesAsCliOption() string {
109 if len(c.volumes) > 0 {
110 for _, volume := range c.volumes {
111 cliOption += fmt.Sprintf(" -v %s:%s", volume.hostDir, volume.containerDir)
118 func (c *Container) getWorkDirAsCliOption() string {
119 if len(c.workDir) == 0 {
122 return fmt.Sprintf(" --workdir=\"%s\"", c.workDir)
125 func (c *Container) addEnvVar(envVar interface{}) {
126 envVarMap := envVar.(ContainerConfig)
127 name := envVarMap["name"].(string)
128 value := envVarMap["value"].(string)
129 c.envVars[name] = value
132 func (c *Container) getEnvVarsAsCliOption() string {
134 if len(c.envVars) == 0 {
138 for name, value := range c.envVars {
139 cliOption += fmt.Sprintf(" -e %s=%s", name, value)
144 func (c *Container) getSyncPath() string {
145 return fmt.Sprintf("/tmp/%s/sync", c.name)
148 func (c *Container) exec(command string) (string, error) {
149 cliCommand := "docker exec -d " + c.name + " " + command
150 byteOutput, err := exechelper.CombinedOutput(cliCommand)
151 return string(byteOutput), err
154 func (c *Container) execAction(args string) (string, error) {
155 syncFile := c.getSyncPath() + "/rc"
158 workDir := c.getWorkDirAsCliOption()
159 cmd := fmt.Sprintf("docker exec -d %s %s hs-test %s",
163 err := exechelper.Run(cmd)
167 res, err := waitForSyncFile(syncFile)
169 return "", fmt.Errorf("failed to read sync file while executing 'hs-test %s': %v", args, err)
171 o := res.StdOutput + res.ErrOutput
173 return o, fmt.Errorf("cmd resulted in non-zero value %d: %s", res.Code, res.Desc)
178 func (c *Container) stop() error {
179 return exechelper.Run("docker stop " + c.name)