github.com/cookieai-jar/moby@v17.12.1-ce-rc2+incompatible/integration-cli/utils_test.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "path/filepath" 8 "strings" 9 10 "github.com/docker/docker/internal/testutil" 11 "github.com/go-check/check" 12 "github.com/gotestyourself/gotestyourself/icmd" 13 "github.com/pkg/errors" 14 ) 15 16 func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) { 17 if testEnv.DaemonPlatform() == "windows" { 18 return "c:", `\` 19 } 20 return "", "/" 21 } 22 23 // TODO: update code to call cmd.RunCmd directly, and remove this function 24 // Deprecated: use gotestyourself/gotestyourself/icmd 25 func runCommandWithOutput(execCmd *exec.Cmd) (string, int, error) { 26 result := icmd.RunCmd(transformCmd(execCmd)) 27 return result.Combined(), result.ExitCode, result.Error 28 } 29 30 // Temporary shim for migrating commands to the new function 31 func transformCmd(execCmd *exec.Cmd) icmd.Cmd { 32 return icmd.Cmd{ 33 Command: execCmd.Args, 34 Env: execCmd.Env, 35 Dir: execCmd.Dir, 36 Stdin: execCmd.Stdin, 37 Stdout: execCmd.Stdout, 38 } 39 } 40 41 // ParseCgroupPaths parses 'procCgroupData', which is output of '/proc/<pid>/cgroup', and returns 42 // a map which cgroup name as key and path as value. 43 func ParseCgroupPaths(procCgroupData string) map[string]string { 44 cgroupPaths := map[string]string{} 45 for _, line := range strings.Split(procCgroupData, "\n") { 46 parts := strings.Split(line, ":") 47 if len(parts) != 3 { 48 continue 49 } 50 cgroupPaths[parts[1]] = parts[2] 51 } 52 return cgroupPaths 53 } 54 55 // RandomTmpDirPath provides a temporary path with rand string appended. 56 // does not create or checks if it exists. 57 func RandomTmpDirPath(s string, platform string) string { 58 // TODO: why doesn't this use os.TempDir() ? 59 tmp := "/tmp" 60 if platform == "windows" { 61 tmp = os.Getenv("TEMP") 62 } 63 path := filepath.Join(tmp, fmt.Sprintf("%s.%s", s, testutil.GenerateRandomAlphaOnlyString(10))) 64 if platform == "windows" { 65 return filepath.FromSlash(path) // Using \ 66 } 67 return filepath.ToSlash(path) // Using / 68 } 69 70 // RunCommandPipelineWithOutput runs the array of commands with the output 71 // of each pipelined with the following (like cmd1 | cmd2 | cmd3 would do). 72 // It returns the final output, the exitCode different from 0 and the error 73 // if something bad happened. 74 // Deprecated: use icmd instead 75 func RunCommandPipelineWithOutput(cmds ...*exec.Cmd) (output string, err error) { 76 if len(cmds) < 2 { 77 return "", errors.New("pipeline does not have multiple cmds") 78 } 79 80 // connect stdin of each cmd to stdout pipe of previous cmd 81 for i, cmd := range cmds { 82 if i > 0 { 83 prevCmd := cmds[i-1] 84 cmd.Stdin, err = prevCmd.StdoutPipe() 85 86 if err != nil { 87 return "", fmt.Errorf("cannot set stdout pipe for %s: %v", cmd.Path, err) 88 } 89 } 90 } 91 92 // start all cmds except the last 93 for _, cmd := range cmds[:len(cmds)-1] { 94 if err = cmd.Start(); err != nil { 95 return "", fmt.Errorf("starting %s failed with error: %v", cmd.Path, err) 96 } 97 } 98 99 defer func() { 100 var pipeErrMsgs []string 101 // wait all cmds except the last to release their resources 102 for _, cmd := range cmds[:len(cmds)-1] { 103 if pipeErr := cmd.Wait(); pipeErr != nil { 104 pipeErrMsgs = append(pipeErrMsgs, fmt.Sprintf("command %s failed with error: %v", cmd.Path, pipeErr)) 105 } 106 } 107 if len(pipeErrMsgs) > 0 && err == nil { 108 err = fmt.Errorf("pipelineError from Wait: %v", strings.Join(pipeErrMsgs, ", ")) 109 } 110 }() 111 112 // wait on last cmd 113 out, err := cmds[len(cmds)-1].CombinedOutput() 114 return string(out), err 115 } 116 117 type elementListOptions struct { 118 element, format string 119 } 120 121 func existingElements(c *check.C, opts elementListOptions) []string { 122 args := []string{} 123 switch opts.element { 124 case "container": 125 args = append(args, "ps", "-a") 126 case "image": 127 args = append(args, "images", "-a") 128 case "network": 129 args = append(args, "network", "ls") 130 case "plugin": 131 args = append(args, "plugin", "ls") 132 case "volume": 133 args = append(args, "volume", "ls") 134 } 135 if opts.format != "" { 136 args = append(args, "--format", opts.format) 137 } 138 out, _ := dockerCmd(c, args...) 139 lines := []string{} 140 for _, l := range strings.Split(out, "\n") { 141 if l != "" { 142 lines = append(lines, l) 143 } 144 } 145 return lines 146 } 147 148 // ExistingContainerIDs returns a list of currently existing container IDs. 149 func ExistingContainerIDs(c *check.C) []string { 150 return existingElements(c, elementListOptions{element: "container", format: "{{.ID}}"}) 151 } 152 153 // ExistingContainerNames returns a list of existing container names. 154 func ExistingContainerNames(c *check.C) []string { 155 return existingElements(c, elementListOptions{element: "container", format: "{{.Names}}"}) 156 } 157 158 // RemoveLinesForExistingElements removes existing elements from the output of a 159 // docker command. 160 // This function takes an output []string and returns a []string. 161 func RemoveLinesForExistingElements(output, existing []string) []string { 162 for _, e := range existing { 163 index := -1 164 for i, line := range output { 165 if strings.Contains(line, e) { 166 index = i 167 break 168 } 169 } 170 if index != -1 { 171 output = append(output[:index], output[index+1:]...) 172 } 173 } 174 return output 175 } 176 177 // RemoveOutputForExistingElements removes existing elements from the output of 178 // a docker command. 179 // This function takes an output string and returns a string. 180 func RemoveOutputForExistingElements(output string, existing []string) string { 181 res := RemoveLinesForExistingElements(strings.Split(output, "\n"), existing) 182 return strings.Join(res, "\n") 183 }