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