github.com/damirazo/docker@v1.9.0/integration-cli/docker_cli_cp_utils.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "strings" 11 12 "github.com/docker/docker/pkg/archive" 13 "github.com/go-check/check" 14 ) 15 16 type fileType uint32 17 18 const ( 19 ftRegular fileType = iota 20 ftDir 21 ftSymlink 22 ) 23 24 type fileData struct { 25 filetype fileType 26 path string 27 contents string 28 } 29 30 func (fd fileData) creationCommand() string { 31 var command string 32 33 switch fd.filetype { 34 case ftRegular: 35 // Don't overwrite the file if it already exists! 36 command = fmt.Sprintf("if [ ! -f %s ]; then echo %q > %s; fi", fd.path, fd.contents, fd.path) 37 case ftDir: 38 command = fmt.Sprintf("mkdir -p %s", fd.path) 39 case ftSymlink: 40 command = fmt.Sprintf("ln -fs %s %s", fd.contents, fd.path) 41 } 42 43 return command 44 } 45 46 func mkFilesCommand(fds []fileData) string { 47 commands := make([]string, len(fds)) 48 49 for i, fd := range fds { 50 commands[i] = fd.creationCommand() 51 } 52 53 return strings.Join(commands, " && ") 54 } 55 56 var defaultFileData = []fileData{ 57 {ftRegular, "file1", "file1"}, 58 {ftRegular, "file2", "file2"}, 59 {ftRegular, "file3", "file3"}, 60 {ftRegular, "file4", "file4"}, 61 {ftRegular, "file5", "file5"}, 62 {ftRegular, "file6", "file6"}, 63 {ftRegular, "file7", "file7"}, 64 {ftDir, "dir1", ""}, 65 {ftRegular, "dir1/file1-1", "file1-1"}, 66 {ftRegular, "dir1/file1-2", "file1-2"}, 67 {ftDir, "dir2", ""}, 68 {ftRegular, "dir2/file2-1", "file2-1"}, 69 {ftRegular, "dir2/file2-2", "file2-2"}, 70 {ftDir, "dir3", ""}, 71 {ftRegular, "dir3/file3-1", "file3-1"}, 72 {ftRegular, "dir3/file3-2", "file3-2"}, 73 {ftDir, "dir4", ""}, 74 {ftRegular, "dir4/file3-1", "file4-1"}, 75 {ftRegular, "dir4/file3-2", "file4-2"}, 76 {ftDir, "dir5", ""}, 77 {ftSymlink, "symlinkToFile1", "file1"}, 78 {ftSymlink, "symlinkToDir1", "dir1"}, 79 {ftSymlink, "brokenSymlinkToFileX", "fileX"}, 80 {ftSymlink, "brokenSymlinkToDirX", "dirX"}, 81 {ftSymlink, "symlinkToAbsDir", "/root"}, 82 } 83 84 func defaultMkContentCommand() string { 85 return mkFilesCommand(defaultFileData) 86 } 87 88 func makeTestContentInDir(c *check.C, dir string) { 89 for _, fd := range defaultFileData { 90 path := filepath.Join(dir, filepath.FromSlash(fd.path)) 91 switch fd.filetype { 92 case ftRegular: 93 if err := ioutil.WriteFile(path, []byte(fd.contents+"\n"), os.FileMode(0666)); err != nil { 94 c.Fatal(err) 95 } 96 case ftDir: 97 if err := os.Mkdir(path, os.FileMode(0777)); err != nil { 98 c.Fatal(err) 99 } 100 case ftSymlink: 101 if err := os.Symlink(fd.contents, path); err != nil { 102 c.Fatal(err) 103 } 104 } 105 } 106 } 107 108 type testContainerOptions struct { 109 addContent bool 110 readOnly bool 111 volumes []string 112 workDir string 113 command string 114 } 115 116 func makeTestContainer(c *check.C, options testContainerOptions) (containerID string) { 117 if options.addContent { 118 mkContentCmd := defaultMkContentCommand() 119 if options.command == "" { 120 options.command = mkContentCmd 121 } else { 122 options.command = fmt.Sprintf("%s && %s", defaultMkContentCommand(), options.command) 123 } 124 } 125 126 if options.command == "" { 127 options.command = "#(nop)" 128 } 129 130 args := []string{"run", "-d"} 131 132 for _, volume := range options.volumes { 133 args = append(args, "-v", volume) 134 } 135 136 if options.workDir != "" { 137 args = append(args, "-w", options.workDir) 138 } 139 140 if options.readOnly { 141 args = append(args, "--read-only") 142 } 143 144 args = append(args, "busybox", "/bin/sh", "-c", options.command) 145 146 out, status := dockerCmd(c, args...) 147 if status != 0 { 148 c.Fatalf("failed to run container, status %d: %s", status, out) 149 } 150 151 containerID = strings.TrimSpace(out) 152 153 out, status = dockerCmd(c, "wait", containerID) 154 if status != 0 { 155 c.Fatalf("failed to wait for test container container, status %d: %s", status, out) 156 } 157 158 if exitCode := strings.TrimSpace(out); exitCode != "0" { 159 logs, status := dockerCmd(c, "logs", containerID) 160 if status != 0 { 161 logs = "UNABLE TO GET LOGS" 162 } 163 c.Fatalf("failed to make test container, exit code (%s): %s", exitCode, logs) 164 } 165 166 return 167 } 168 169 func makeCatFileCommand(path string) string { 170 return fmt.Sprintf("if [ -f %s ]; then cat %s; fi", path, path) 171 } 172 173 func cpPath(pathElements ...string) string { 174 localizedPathElements := make([]string, len(pathElements)) 175 for i, path := range pathElements { 176 localizedPathElements[i] = filepath.FromSlash(path) 177 } 178 return strings.Join(localizedPathElements, string(filepath.Separator)) 179 } 180 181 func cpPathTrailingSep(pathElements ...string) string { 182 return fmt.Sprintf("%s%c", cpPath(pathElements...), filepath.Separator) 183 } 184 185 func containerCpPath(containerID string, pathElements ...string) string { 186 joined := strings.Join(pathElements, "/") 187 return fmt.Sprintf("%s:%s", containerID, joined) 188 } 189 190 func containerCpPathTrailingSep(containerID string, pathElements ...string) string { 191 return fmt.Sprintf("%s/", containerCpPath(containerID, pathElements...)) 192 } 193 194 func runDockerCp(c *check.C, src, dst string) (err error) { 195 c.Logf("running `docker cp %s %s`", src, dst) 196 197 args := []string{"cp", src, dst} 198 199 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, args...)) 200 if err != nil { 201 err = fmt.Errorf("error executing `docker cp` command: %s: %s", err, out) 202 } 203 204 return 205 } 206 207 func startContainerGetOutput(c *check.C, cID string) (out string, err error) { 208 c.Logf("running `docker start -a %s`", cID) 209 210 args := []string{"start", "-a", cID} 211 212 out, _, err = runCommandWithOutput(exec.Command(dockerBinary, args...)) 213 if err != nil { 214 err = fmt.Errorf("error executing `docker start` command: %s: %s", err, out) 215 } 216 217 return 218 } 219 220 func getTestDir(c *check.C, label string) (tmpDir string) { 221 var err error 222 223 if tmpDir, err = ioutil.TempDir("", label); err != nil { 224 c.Fatalf("unable to make temporary directory: %s", err) 225 } 226 227 return 228 } 229 230 func isCpNotExist(err error) bool { 231 return strings.Contains(err.Error(), "no such file or directory") || strings.Contains(err.Error(), "cannot find the file specified") 232 } 233 234 func isCpDirNotExist(err error) bool { 235 return strings.Contains(err.Error(), archive.ErrDirNotExists.Error()) 236 } 237 238 func isCpNotDir(err error) bool { 239 return strings.Contains(err.Error(), archive.ErrNotDirectory.Error()) || strings.Contains(err.Error(), "filename, directory name, or volume label syntax is incorrect") 240 } 241 242 func isCpCannotCopyDir(err error) bool { 243 return strings.Contains(err.Error(), archive.ErrCannotCopyDir.Error()) 244 } 245 246 func isCpCannotCopyReadOnly(err error) bool { 247 return strings.Contains(err.Error(), "marked read-only") 248 } 249 250 func isCannotOverwriteNonDirWithDir(err error) bool { 251 return strings.Contains(err.Error(), "cannot overwrite non-directory") 252 } 253 254 func fileContentEquals(c *check.C, filename, contents string) (err error) { 255 c.Logf("checking that file %q contains %q\n", filename, contents) 256 257 fileBytes, err := ioutil.ReadFile(filename) 258 if err != nil { 259 return 260 } 261 262 expectedBytes, err := ioutil.ReadAll(strings.NewReader(contents)) 263 if err != nil { 264 return 265 } 266 267 if !bytes.Equal(fileBytes, expectedBytes) { 268 err = fmt.Errorf("file content not equal - expected %q, got %q", string(expectedBytes), string(fileBytes)) 269 } 270 271 return 272 } 273 274 func symlinkTargetEquals(c *check.C, symlink, expectedTarget string) (err error) { 275 c.Logf("checking that the symlink %q points to %q\n", symlink, expectedTarget) 276 277 actualTarget, err := os.Readlink(symlink) 278 if err != nil { 279 return err 280 } 281 282 if actualTarget != expectedTarget { 283 return fmt.Errorf("symlink target points to %q not %q", actualTarget, expectedTarget) 284 } 285 286 return nil 287 } 288 289 func containerStartOutputEquals(c *check.C, cID, contents string) (err error) { 290 c.Logf("checking that container %q start output contains %q\n", cID, contents) 291 292 out, err := startContainerGetOutput(c, cID) 293 if err != nil { 294 return err 295 } 296 297 if out != contents { 298 err = fmt.Errorf("output contents not equal - expected %q, got %q", contents, out) 299 } 300 301 return 302 } 303 304 func defaultVolumes(tmpDir string) []string { 305 if SameHostDaemon.Condition() { 306 return []string{ 307 "/vol1", 308 fmt.Sprintf("%s:/vol2", tmpDir), 309 fmt.Sprintf("%s:/vol3", filepath.Join(tmpDir, "vol3")), 310 fmt.Sprintf("%s:/vol_ro:ro", filepath.Join(tmpDir, "vol_ro")), 311 } 312 } 313 314 // Can't bind-mount volumes with separate host daemon. 315 return []string{"/vol1", "/vol2", "/vol3", "/vol_ro:/vol_ro:ro"} 316 }