hs-test: restrict concurrency on envoy
[vpp.git] / extras / hs-test / container.go
index 3128a8e..874ce3d 100644 (file)
@@ -2,30 +2,190 @@ package main
 
 import (
        "fmt"
+       "os"
+       "strings"
 
        "github.com/edwarnicke/exechelper"
 )
 
+type Volume struct {
+       hostDir      string
+       containerDir string
+}
+
 type Container struct {
-       name string
+       isOptional       bool
+       name             string
+       image            string
+       workDir          string
+       extraRunningArgs string
+       volumes          map[string]Volume
+       envVars          map[string]string
+}
+
+func NewContainer(yamlInput ContainerConfig) (*Container, error) {
+       containerName := yamlInput["name"].(string)
+       if len(containerName) == 0 {
+               err := fmt.Errorf("container name must not be blank")
+               return nil, err
+       }
+
+       var container = new(Container)
+       container.volumes = make(map[string]Volume)
+       container.envVars = make(map[string]string)
+       container.name = containerName
+
+       if image, ok := yamlInput["image"]; ok {
+               container.image = image.(string)
+       } else {
+               container.image = "hs-test/vpp"
+       }
+
+       if args, ok := yamlInput["extra-args"]; ok {
+               container.extraRunningArgs = args.(string)
+       } else {
+               container.extraRunningArgs = ""
+       }
+
+       if isOptional, ok := yamlInput["is-optional"]; ok {
+               container.isOptional = isOptional.(bool)
+       } else {
+               container.isOptional = false
+       }
+
+       if _, ok := yamlInput["volumes"]; ok {
+               r := strings.NewReplacer("$HST_DIR", workDir)
+               for _, volu := range yamlInput["volumes"].([]interface{}) {
+                       volumeMap := volu.(ContainerConfig)
+                       hostDir := r.Replace(volumeMap["host-dir"].(string))
+                       containerDir := volumeMap["container-dir"].(string)
+                       container.addVolume(hostDir, containerDir)
+
+                       if isDefaultWorkDir, ok := volumeMap["is-default-work-dir"]; ok &&
+                               isDefaultWorkDir.(bool) &&
+                               len(container.workDir) == 0 {
+                               container.workDir = containerDir
+                       }
+
+               }
+       }
+
+       if _, ok := yamlInput["vars"]; ok {
+               for _, envVar := range yamlInput["vars"].([]interface{}) {
+                       container.addEnvVar(envVar)
+               }
+       }
+       return container, nil
+}
+
+func (c *Container) getRunCommand() string {
+       syncPath := fmt.Sprintf(" -v %s:/tmp/sync", c.getSyncPath())
+       cmd := "docker run --cap-add=all -d --privileged --network host --rm"
+       cmd += syncPath
+       cmd += c.getVolumesAsCliOption()
+       cmd += c.getEnvVarsAsCliOption()
+       cmd += " --name " + c.name + " " + c.image + " " + c.extraRunningArgs
+       return cmd
 }
 
 func (c *Container) run() error {
        if c.name == "" {
-               return fmt.Errorf("create volume failed: container name is blank")
+               return fmt.Errorf("run container failed: name is blank")
        }
 
        exechelper.Run(fmt.Sprintf("mkdir -p /tmp/%s/sync", c.name))
-       syncPath := fmt.Sprintf("-v /tmp/%s/sync:/tmp/sync", c.name)
-       cmd := "docker run --cap-add=all -d --privileged --network host --rm "
-       cmd += syncPath
-       cmd += " --name " + c.name + " hs-test/vpp"
-       fmt.Println(cmd)
+       cmd := c.getRunCommand()
        err := exechelper.Run(cmd)
        if err != nil {
-               return fmt.Errorf("create volume failed: %s", err)
+               return fmt.Errorf("container run failed: %s", err)
        }
 
        return nil
 }
 
+func (c *Container) addVolume(hostDir string, containerDir string) {
+       var volume Volume
+       volume.hostDir = hostDir
+       volume.containerDir = containerDir
+       c.volumes[hostDir] = volume
+}
+
+func (c *Container) getVolumeByHostDir(hostDir string) Volume {
+       return c.volumes[hostDir]
+}
+
+func (c *Container) getVolumesAsCliOption() string {
+       cliOption := ""
+
+       if len(c.volumes) > 0 {
+               for _, volume := range c.volumes {
+                       cliOption += fmt.Sprintf(" -v %s:%s", volume.hostDir, volume.containerDir)
+               }
+       }
+
+       return cliOption
+}
+
+func (c *Container) getWorkDirAsCliOption() string {
+       if len(c.workDir) == 0 {
+               return ""
+       }
+       return fmt.Sprintf(" --workdir=\"%s\"", c.workDir)
+}
+
+func (c *Container) addEnvVar(envVar interface{}) {
+       envVarMap := envVar.(ContainerConfig)
+       name := envVarMap["name"].(string)
+       value := envVarMap["value"].(string)
+       c.envVars[name] = value
+}
+
+func (c *Container) getEnvVarsAsCliOption() string {
+       cliOption := ""
+       if len(c.envVars) == 0 {
+               return cliOption
+       }
+
+       for name, value := range c.envVars {
+               cliOption += fmt.Sprintf(" -e %s=%s", name, value)
+       }
+       return cliOption
+}
+
+func (c *Container) getSyncPath() string {
+       return fmt.Sprintf("/tmp/%s/sync", c.name)
+}
+
+func (c *Container) exec(command string) (string, error) {
+       cliCommand := "docker exec -d " + c.name + " " + command
+       byteOutput, err := exechelper.CombinedOutput(cliCommand)
+       return string(byteOutput), err
+}
+
+func (c *Container) execAction(args string) (string, error) {
+       syncFile := c.getSyncPath() + "/rc"
+       os.Remove(syncFile)
+
+       workDir := c.getWorkDirAsCliOption()
+       cmd := fmt.Sprintf("docker exec -d %s %s hs-test %s",
+               workDir,
+               c.name,
+               args)
+       err := exechelper.Run(cmd)
+       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 (c *Container) stop() error {
+       return exechelper.Run("docker stop " + c.name)
+}