github.com/emc-advanced-dev/unik@v0.0.0-20190717152701-a58d3e8e33b7/pkg/util/container.go (about)

     1  // +build !container-binary
     2  
     3  package util
     4  
     5  import (
     6  	"encoding/json"
     7  	"fmt"
     8  	"os"
     9  	"os/exec"
    10  	"runtime"
    11  	"strings"
    12  
    13  	"github.com/sirupsen/logrus"
    14  	"github.com/emc-advanced-dev/pkg/errors"
    15  	"github.com/solo-io/unik/containers"
    16  	"github.com/pborman/uuid"
    17  )
    18  
    19  var containerVersions map[string]string
    20  
    21  func InitContainers() error {
    22  	versionData, err := versiondata.Asset("containers/versions.json")
    23  	if err != nil {
    24  		return errors.New("failed to get version data from containers/versions.json", err)
    25  	}
    26  	if err := json.Unmarshal(versionData, &containerVersions); err != nil {
    27  		return errors.New("failed to unmarshall version data "+string(versionData), err)
    28  	}
    29  	logrus.WithField("versions", containerVersions).Info("using container versions")
    30  	return nil
    31  }
    32  
    33  type Container struct {
    34  	env           map[string]string
    35  	privileged    bool
    36  	volumes       map[string]string
    37  	interactive   bool
    38  	network       string
    39  	containerName string
    40  	name          string
    41  	entrypoint    string
    42  }
    43  
    44  func NewContainer(imageName string) *Container {
    45  	c := &Container{}
    46  
    47  	c.name = imageName
    48  	c.env = make(map[string]string)
    49  	c.volumes = make(map[string]string)
    50  
    51  	return c
    52  }
    53  
    54  func (c *Container) WithEntrypoint(entrypoint string) *Container {
    55  	c.entrypoint = entrypoint
    56  	return c
    57  }
    58  
    59  func (c *Container) WithVolume(hostdir, containerdir string) *Container {
    60  	c.volumes[hostdir] = containerdir
    61  	return c
    62  }
    63  
    64  func (c *Container) WithVolumes(vols map[string]string) *Container {
    65  	for k, v := range vols {
    66  		c.WithVolume(k, v)
    67  	}
    68  	return c
    69  }
    70  
    71  func (c *Container) WithEnv(key, value string) *Container {
    72  	c.env[key] = value
    73  	return c
    74  }
    75  
    76  func (c *Container) WithEnvs(vars map[string]string) *Container {
    77  	for k, v := range vars {
    78  		c.WithEnv(k, v)
    79  	}
    80  	return c
    81  }
    82  
    83  func (c *Container) WithNet(net string) *Container {
    84  	c.network = net
    85  	return c
    86  }
    87  
    88  func (c *Container) WithName(name string) *Container {
    89  	c.containerName = name
    90  	return c
    91  }
    92  
    93  func (c *Container) Interactive(i bool) *Container {
    94  	c.interactive = i
    95  	return c
    96  }
    97  
    98  func (c *Container) Privileged(p bool) *Container {
    99  	c.privileged = p
   100  	return c
   101  }
   102  
   103  func (c *Container) Run(arguments ...string) error {
   104  	cmd := c.BuildCmd(arguments...)
   105  
   106  	LogCommand(cmd, true)
   107  
   108  	return cmd.Run()
   109  }
   110  
   111  func (c *Container) Output(arguments ...string) ([]byte, error) {
   112  	return c.BuildCmd(arguments...).Output()
   113  }
   114  
   115  func (c *Container) CombinedOutput(arguments ...string) ([]byte, error) {
   116  	return c.BuildCmd(arguments...).CombinedOutput()
   117  }
   118  
   119  func (c *Container) Stop() error {
   120  	return exec.Command("docker", "stop", c.containerName).Run()
   121  }
   122  
   123  func (c *Container) BuildCmd(arguments ...string) *exec.Cmd {
   124  	if c.containerName == "" {
   125  		c.containerName = uuid.New()
   126  	}
   127  
   128  	args := []string{"run", "--rm"}
   129  	if c.privileged {
   130  		args = append(args, "--privileged")
   131  	}
   132  	if c.interactive {
   133  		args = append(args, "-i")
   134  	}
   135  	if c.network != "" {
   136  		args = append(args, fmt.Sprintf("--net=%s", c.network))
   137  	}
   138  	for key, val := range c.env {
   139  		args = append(args, "-e", fmt.Sprintf("%s=%s", key, val))
   140  	}
   141  	for key, val := range c.volumes {
   142  		if IsDockerToolbox() {
   143  			key = GetToolboxMountPath(key)
   144  		}
   145  		args = append(args, "-v", fmt.Sprintf("%s:%s", key, val))
   146  	}
   147  
   148  	if c.entrypoint != "" {
   149  		args = append(args, "--entrypoint", c.entrypoint)
   150  	}
   151  
   152  	args = append(args, fmt.Sprintf("--name=%s", c.containerName))
   153  
   154  	containerVer, ok := containerVersions[c.name]
   155  	if !ok {
   156  		logrus.Warnf("version for container %s not found, using version 'latest'", c.name)
   157  		containerVer = "latest"
   158  	}
   159  
   160  	finalName := c.name + ":" + containerVer
   161  	if !strings.Contains(finalName, "/") { /*projectunik container*/
   162  		finalName = "projectunik/" + finalName
   163  	}
   164  
   165  	args = append(args, finalName)
   166  	args = append(args, arguments...)
   167  
   168  	logrus.WithField("args", args).Info("Build cmd for container ", finalName)
   169  
   170  	cmd := exec.Command("docker", args...)
   171  
   172  	return cmd
   173  }
   174  
   175  func IsDockerToolbox() bool {
   176  	return runtime.GOOS == "windows" && os.Getenv("DOCKER_TOOLBOX_INSTALL_PATH") != ""
   177  }
   178  
   179  func GetToolboxMountPath(path string) string {
   180  	path = strings.Replace(path, "\\", "/", -1)
   181  	if len(path) >= 2 && path[1] == ':' {
   182  		path = "/" + strings.ToLower(string(path[0])) + path[2:]
   183  	}
   184  	return path
   185  }