2014-02-25 11:17:48 -05:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2017-08-22 16:08:42 -04:00
|
|
|
"fmt"
|
|
|
|
"os"
|
2016-12-13 15:21:51 -05:00
|
|
|
"os/exec"
|
2017-08-22 16:08:42 -04:00
|
|
|
"path/filepath"
|
2017-08-21 19:03:58 -04:00
|
|
|
"strings"
|
|
|
|
|
2017-08-22 16:08:42 -04:00
|
|
|
"github.com/docker/docker/pkg/stringutils"
|
2017-09-08 11:16:15 -04:00
|
|
|
"github.com/go-check/check"
|
2017-08-23 17:01:29 -04:00
|
|
|
"github.com/gotestyourself/gotestyourself/icmd"
|
2017-08-22 17:07:52 -04:00
|
|
|
"github.com/pkg/errors"
|
2014-02-25 11:17:48 -05:00
|
|
|
)
|
|
|
|
|
2016-02-03 09:16:00 -05:00
|
|
|
func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) {
|
2017-01-13 11:23:28 -05:00
|
|
|
if testEnv.DaemonPlatform() == "windows" {
|
2016-02-03 09:16:00 -05:00
|
|
|
return "c:", `\`
|
|
|
|
}
|
|
|
|
return "", "/"
|
|
|
|
}
|
|
|
|
|
2016-08-04 12:57:34 -04:00
|
|
|
// TODO: update code to call cmd.RunCmd directly, and remove this function
|
2017-08-23 17:01:29 -04:00
|
|
|
// Deprecated: use gotestyourself/gotestyourself/icmd
|
2016-08-04 12:57:34 -04:00
|
|
|
func runCommandWithOutput(execCmd *exec.Cmd) (string, int, error) {
|
2017-08-23 17:01:29 -04:00
|
|
|
result := icmd.RunCmd(transformCmd(execCmd))
|
2016-08-04 12:57:34 -04:00
|
|
|
return result.Combined(), result.ExitCode, result.Error
|
2014-02-25 11:17:48 -05:00
|
|
|
}
|
|
|
|
|
2016-08-04 12:57:34 -04:00
|
|
|
// Temporary shim for migrating commands to the new function
|
2017-08-23 17:01:29 -04:00
|
|
|
func transformCmd(execCmd *exec.Cmd) icmd.Cmd {
|
|
|
|
return icmd.Cmd{
|
2016-08-04 12:57:34 -04:00
|
|
|
Command: execCmd.Args,
|
|
|
|
Env: execCmd.Env,
|
|
|
|
Dir: execCmd.Dir,
|
|
|
|
Stdin: execCmd.Stdin,
|
|
|
|
Stdout: execCmd.Stdout,
|
|
|
|
}
|
2014-02-25 11:17:48 -05:00
|
|
|
}
|
2017-08-21 19:03:58 -04:00
|
|
|
|
|
|
|
// ParseCgroupPaths parses 'procCgroupData', which is output of '/proc/<pid>/cgroup', and returns
|
|
|
|
// a map which cgroup name as key and path as value.
|
|
|
|
func ParseCgroupPaths(procCgroupData string) map[string]string {
|
|
|
|
cgroupPaths := map[string]string{}
|
|
|
|
for _, line := range strings.Split(procCgroupData, "\n") {
|
|
|
|
parts := strings.Split(line, ":")
|
|
|
|
if len(parts) != 3 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
cgroupPaths[parts[1]] = parts[2]
|
|
|
|
}
|
|
|
|
return cgroupPaths
|
|
|
|
}
|
2017-08-22 16:08:42 -04:00
|
|
|
|
|
|
|
// RandomTmpDirPath provides a temporary path with rand string appended.
|
|
|
|
// does not create or checks if it exists.
|
|
|
|
func RandomTmpDirPath(s string, platform string) string {
|
|
|
|
// TODO: why doesn't this use os.TempDir() ?
|
|
|
|
tmp := "/tmp"
|
|
|
|
if platform == "windows" {
|
|
|
|
tmp = os.Getenv("TEMP")
|
|
|
|
}
|
|
|
|
path := filepath.Join(tmp, fmt.Sprintf("%s.%s", s, stringutils.GenerateRandomAlphaOnlyString(10)))
|
|
|
|
if platform == "windows" {
|
|
|
|
return filepath.FromSlash(path) // Using \
|
|
|
|
}
|
|
|
|
return filepath.ToSlash(path) // Using /
|
|
|
|
}
|
2017-08-22 17:07:52 -04:00
|
|
|
|
|
|
|
// RunCommandPipelineWithOutput runs the array of commands with the output
|
|
|
|
// of each pipelined with the following (like cmd1 | cmd2 | cmd3 would do).
|
|
|
|
// It returns the final output, the exitCode different from 0 and the error
|
|
|
|
// if something bad happened.
|
|
|
|
// Deprecated: use icmd instead
|
|
|
|
func RunCommandPipelineWithOutput(cmds ...*exec.Cmd) (output string, err error) {
|
|
|
|
if len(cmds) < 2 {
|
|
|
|
return "", errors.New("pipeline does not have multiple cmds")
|
|
|
|
}
|
|
|
|
|
|
|
|
// connect stdin of each cmd to stdout pipe of previous cmd
|
|
|
|
for i, cmd := range cmds {
|
|
|
|
if i > 0 {
|
|
|
|
prevCmd := cmds[i-1]
|
|
|
|
cmd.Stdin, err = prevCmd.StdoutPipe()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("cannot set stdout pipe for %s: %v", cmd.Path, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// start all cmds except the last
|
|
|
|
for _, cmd := range cmds[:len(cmds)-1] {
|
|
|
|
if err = cmd.Start(); err != nil {
|
|
|
|
return "", fmt.Errorf("starting %s failed with error: %v", cmd.Path, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
var pipeErrMsgs []string
|
|
|
|
// wait all cmds except the last to release their resources
|
|
|
|
for _, cmd := range cmds[:len(cmds)-1] {
|
|
|
|
if pipeErr := cmd.Wait(); pipeErr != nil {
|
|
|
|
pipeErrMsgs = append(pipeErrMsgs, fmt.Sprintf("command %s failed with error: %v", cmd.Path, pipeErr))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(pipeErrMsgs) > 0 && err == nil {
|
|
|
|
err = fmt.Errorf("pipelineError from Wait: %v", strings.Join(pipeErrMsgs, ", "))
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// wait on last cmd
|
|
|
|
out, err := cmds[len(cmds)-1].CombinedOutput()
|
|
|
|
return string(out), err
|
|
|
|
}
|
2017-09-08 11:16:15 -04:00
|
|
|
|
|
|
|
type elementListOptions struct {
|
|
|
|
element, format string
|
|
|
|
}
|
|
|
|
|
|
|
|
func existingElements(c *check.C, opts elementListOptions) []string {
|
|
|
|
args := []string{}
|
|
|
|
switch opts.element {
|
|
|
|
case "container":
|
|
|
|
args = append(args, "ps", "-a")
|
|
|
|
case "image":
|
|
|
|
args = append(args, "images", "-a")
|
|
|
|
case "network":
|
|
|
|
args = append(args, "network", "ls")
|
|
|
|
case "plugin":
|
|
|
|
args = append(args, "plugin", "ls")
|
|
|
|
case "volume":
|
|
|
|
args = append(args, "volume", "ls")
|
|
|
|
}
|
|
|
|
if opts.format != "" {
|
|
|
|
args = append(args, "--format", opts.format)
|
|
|
|
}
|
|
|
|
out, _ := dockerCmd(c, args...)
|
|
|
|
lines := []string{}
|
|
|
|
for _, l := range strings.Split(out, "\n") {
|
|
|
|
if l != "" {
|
|
|
|
lines = append(lines, l)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lines
|
|
|
|
}
|
|
|
|
|
|
|
|
// ExistingContainerIDs returns a list of currently existing container IDs.
|
|
|
|
func ExistingContainerIDs(c *check.C) []string {
|
|
|
|
return existingElements(c, elementListOptions{element: "container", format: "{{.ID}}"})
|
|
|
|
}
|
|
|
|
|
|
|
|
// ExistingContainerNames returns a list of existing container names.
|
|
|
|
func ExistingContainerNames(c *check.C) []string {
|
|
|
|
return existingElements(c, elementListOptions{element: "container", format: "{{.Names}}"})
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveLinesForExistingElements removes existing elements from the output of a
|
|
|
|
// docker command.
|
|
|
|
// This function takes an output []string and returns a []string.
|
|
|
|
func RemoveLinesForExistingElements(output, existing []string) []string {
|
|
|
|
for _, e := range existing {
|
|
|
|
index := -1
|
|
|
|
for i, line := range output {
|
|
|
|
if strings.Contains(line, e) {
|
|
|
|
index = i
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if index != -1 {
|
|
|
|
output = append(output[:index], output[index+1:]...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return output
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveOutputForExistingElements removes existing elements from the output of
|
|
|
|
// a docker command.
|
|
|
|
// This function takes an output string and returns a string.
|
|
|
|
func RemoveOutputForExistingElements(output string, existing []string) string {
|
|
|
|
res := RemoveLinesForExistingElements(strings.Split(output, "\n"), existing)
|
|
|
|
return strings.Join(res, "\n")
|
|
|
|
}
|