1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/integration-cli/docker_cli_cp_test.go
Josh Hawn 75f6929b44 Fix docker cp Behavior With Symlinks
[pkg/archive] Update archive/copy path handling

  - Remove unused TarOptions.Name field.
  - Add new TarOptions.RebaseNames field.
  - Update some of the logic around path dir/base splitting.
  - Update some of the logic behind archive entry name rebasing.

[api/types] Add LinkTarget field to PathStat

[daemon] Fix stat, archive, extract of symlinks

  These operations *should* resolve symlinks that are in the path but if the
  resource itself is a symlink then it *should not* be resolved. This patch
  puts this logic into a common function `resolvePath` which resolves symlinks
  of the path's dir in scope of the container rootfs but does not resolve the
  final element of the path. Now archive, extract, and stat operations will
  return symlinks if the path is indeed a symlink.

[api/client] Update cp path hanling

[docs/reference/api] Update description of stat

  Add the linkTarget field to the header of the archive endpoint.
  Remove path field.

[integration-cli] Fix/Add cp symlink test cases

  Copying a symlink should do just that: copy the symlink NOT
  copy the target of the symlink. Also, the resulting file from
  the copy should have the name of the symlink NOT the name of
  the target file.

  Copying to a symlink should copy to the symlink target and not
  modify the symlink itself.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
2015-07-30 12:14:28 -07:00

804 lines
22 KiB
Go

package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"github.com/go-check/check"
)
const (
cpTestPathParent = "/some"
cpTestPath = "/some/path"
cpTestName = "test"
cpFullPath = "/some/path/test"
cpContainerContents = "holla, i am the container"
cpHostContents = "hello, i am the host"
)
// Ensure that an all-local path case returns an error.
func (s *DockerSuite) TestCpLocalOnly(c *check.C) {
err := runDockerCp(c, "foo", "bar")
if err == nil {
c.Fatal("expected failure, got success")
}
if !strings.Contains(err.Error(), "must specify at least one container source") {
c.Fatalf("unexpected output: %s", err.Error())
}
}
// Test for #5656
// Check that garbage paths don't escape the container's rootfs
func (s *DockerSuite) TestCpGarbagePath(c *check.C) {
out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
if exitCode != 0 {
c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
out, _ = dockerCmd(c, "wait", cleanedContainerID)
if strings.TrimSpace(out) != "0" {
c.Fatal("failed to set up container", out)
}
if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
c.Fatal(err)
}
hostFile, err := os.Create(cpFullPath)
if err != nil {
c.Fatal(err)
}
defer hostFile.Close()
defer os.RemoveAll(cpTestPathParent)
fmt.Fprintf(hostFile, "%s", cpHostContents)
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
c.Fatal(err)
}
tmpname := filepath.Join(tmpdir, cpTestName)
defer os.RemoveAll(tmpdir)
path := path.Join("../../../../../../../../../../../../", cpFullPath)
dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir)
file, _ := os.Open(tmpname)
defer file.Close()
test, err := ioutil.ReadAll(file)
if err != nil {
c.Fatal(err)
}
if string(test) == cpHostContents {
c.Errorf("output matched host file -- garbage path can escape container rootfs")
}
if string(test) != cpContainerContents {
c.Errorf("output doesn't match the input for garbage path")
}
}
// Check that relative paths are relative to the container's rootfs
func (s *DockerSuite) TestCpRelativePath(c *check.C) {
out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
if exitCode != 0 {
c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
out, _ = dockerCmd(c, "wait", cleanedContainerID)
if strings.TrimSpace(out) != "0" {
c.Fatal("failed to set up container", out)
}
if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
c.Fatal(err)
}
hostFile, err := os.Create(cpFullPath)
if err != nil {
c.Fatal(err)
}
defer hostFile.Close()
defer os.RemoveAll(cpTestPathParent)
fmt.Fprintf(hostFile, "%s", cpHostContents)
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
c.Fatal(err)
}
tmpname := filepath.Join(tmpdir, cpTestName)
defer os.RemoveAll(tmpdir)
var relPath string
if path.IsAbs(cpFullPath) {
// normally this is `filepath.Rel("/", cpFullPath)` but we cannot
// get this unix-path manipulation on windows with filepath.
relPath = cpFullPath[1:]
} else {
c.Fatalf("path %s was assumed to be an absolute path", cpFullPath)
}
dockerCmd(c, "cp", cleanedContainerID+":"+relPath, tmpdir)
file, _ := os.Open(tmpname)
defer file.Close()
test, err := ioutil.ReadAll(file)
if err != nil {
c.Fatal(err)
}
if string(test) == cpHostContents {
c.Errorf("output matched host file -- relative path can escape container rootfs")
}
if string(test) != cpContainerContents {
c.Errorf("output doesn't match the input for relative path")
}
}
// Check that absolute paths are relative to the container's rootfs
func (s *DockerSuite) TestCpAbsolutePath(c *check.C) {
out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
if exitCode != 0 {
c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
out, _ = dockerCmd(c, "wait", cleanedContainerID)
if strings.TrimSpace(out) != "0" {
c.Fatal("failed to set up container", out)
}
if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
c.Fatal(err)
}
hostFile, err := os.Create(cpFullPath)
if err != nil {
c.Fatal(err)
}
defer hostFile.Close()
defer os.RemoveAll(cpTestPathParent)
fmt.Fprintf(hostFile, "%s", cpHostContents)
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
c.Fatal(err)
}
tmpname := filepath.Join(tmpdir, cpTestName)
defer os.RemoveAll(tmpdir)
path := cpFullPath
dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir)
file, _ := os.Open(tmpname)
defer file.Close()
test, err := ioutil.ReadAll(file)
if err != nil {
c.Fatal(err)
}
if string(test) == cpHostContents {
c.Errorf("output matched host file -- absolute path can escape container rootfs")
}
if string(test) != cpContainerContents {
c.Errorf("output doesn't match the input for absolute path")
}
}
// Test for #5619
// Check that absolute symlinks are still relative to the container's rootfs
func (s *DockerSuite) TestCpAbsoluteSymlink(c *check.C) {
out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpFullPath+" container_path")
if exitCode != 0 {
c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
out, _ = dockerCmd(c, "wait", cleanedContainerID)
if strings.TrimSpace(out) != "0" {
c.Fatal("failed to set up container", out)
}
if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
c.Fatal(err)
}
hostFile, err := os.Create(cpFullPath)
if err != nil {
c.Fatal(err)
}
defer hostFile.Close()
defer os.RemoveAll(cpTestPathParent)
fmt.Fprintf(hostFile, "%s", cpHostContents)
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
c.Fatal(err)
}
tmpname := filepath.Join(tmpdir, "container_path")
defer os.RemoveAll(tmpdir)
path := path.Join("/", "container_path")
dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir)
// We should have copied a symlink *NOT* the file itself!
linkTarget, err := os.Readlink(tmpname)
if err != nil {
c.Fatal(err)
}
if linkTarget != filepath.FromSlash(cpFullPath) {
c.Errorf("symlink target was %q, but expected: %q", linkTarget, cpFullPath)
}
}
// Check that symlinks to a directory behave as expected when copying one from
// a container.
func (s *DockerSuite) TestCpFromSymlinkToDirectory(c *check.C) {
out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpTestPathParent+" /dir_link")
if exitCode != 0 {
c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
out, _ = dockerCmd(c, "wait", cleanedContainerID)
if strings.TrimSpace(out) != "0" {
c.Fatal("failed to set up container", out)
}
testDir, err := ioutil.TempDir("", "test-cp-from-symlink-to-dir-")
if err != nil {
c.Fatal(err)
}
defer os.RemoveAll(testDir)
// This copy command should copy the symlink, not the target, into the
// temporary directory.
dockerCmd(c, "cp", cleanedContainerID+":"+"/dir_link", testDir)
expectedPath := filepath.Join(testDir, "dir_link")
linkTarget, err := os.Readlink(expectedPath)
if err != nil {
c.Fatalf("unable to read symlink at %q: %v", expectedPath, err)
}
if linkTarget != filepath.FromSlash(cpTestPathParent) {
c.Errorf("symlink target was %q, but expected: %q", linkTarget, cpTestPathParent)
}
os.Remove(expectedPath)
// This copy command should resolve the symlink (note the trailing
// seperator), copying the target into the temporary directory.
dockerCmd(c, "cp", cleanedContainerID+":"+"/dir_link/", testDir)
// It *should not* have copied the directory using the target's name, but
// used the given name instead.
unexpectedPath := filepath.Join(testDir, cpTestPathParent)
if stat, err := os.Lstat(unexpectedPath); err == nil {
c.Fatalf("target name was copied: %q - %q", stat.Mode(), stat.Name())
}
// It *should* have copied the directory using the asked name "dir_link".
stat, err := os.Lstat(expectedPath)
if err != nil {
c.Fatalf("unable to stat resource at %q: %v", expectedPath, err)
}
if !stat.IsDir() {
c.Errorf("should have copied a directory but got %q instead", stat.Mode())
}
}
// Check that symlinks to a directory behave as expected when copying one to a
// container.
func (s *DockerSuite) TestCpToSymlinkToDirectory(c *check.C) {
testRequires(c, SameHostDaemon) // Requires local volume mount bind.
testVol, err := ioutil.TempDir("", "test-cp-to-symlink-to-dir-")
if err != nil {
c.Fatal(err)
}
defer os.RemoveAll(testVol)
// Create a test container with a local volume. We will test by copying
// to the volume path in the container which we can then verify locally.
out, exitCode := dockerCmd(c, "create", "-v", testVol+":/testVol", "busybox")
if exitCode != 0 {
c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
// Create a temp directory to hold a test file nested in a direcotry.
testDir, err := ioutil.TempDir("", "test-cp-to-symlink-to-dir-")
if err != nil {
c.Fatal(err)
}
defer os.RemoveAll(testDir)
// This file will be at "/testDir/some/path/test" and will be copied into
// the test volume later.
hostTestFilename := filepath.Join(testDir, cpFullPath)
if err := os.MkdirAll(filepath.Dir(hostTestFilename), os.FileMode(0700)); err != nil {
c.Fatal(err)
}
if err := ioutil.WriteFile(hostTestFilename, []byte(cpHostContents), os.FileMode(0600)); err != nil {
c.Fatal(err)
}
// Now create another temp directory to hold a symlink to the
// "/testDir/some" directory.
linkDir, err := ioutil.TempDir("", "test-cp-to-symlink-to-dir-")
if err != nil {
c.Fatal(err)
}
defer os.RemoveAll(linkDir)
// Then symlink "/linkDir/dir_link" to "/testdir/some".
linkTarget := filepath.Join(testDir, cpTestPathParent)
localLink := filepath.Join(linkDir, "dir_link")
if err := os.Symlink(linkTarget, localLink); err != nil {
c.Fatal(err)
}
// Now copy that symlink into the test volume in the container.
dockerCmd(c, "cp", localLink, cleanedContainerID+":/testVol")
// This copy command should have copied the symlink *not* the target.
expectedPath := filepath.Join(testVol, "dir_link")
actualLinkTarget, err := os.Readlink(expectedPath)
if err != nil {
c.Fatalf("unable to read symlink at %q: %v", expectedPath, err)
}
if actualLinkTarget != linkTarget {
c.Errorf("symlink target was %q, but expected: %q", actualLinkTarget, linkTarget)
}
// Good, now remove that copied link for the next test.
os.Remove(expectedPath)
// This copy command should resolve the symlink (note the trailing
// seperator), copying the target into the test volume directory in the
// container.
dockerCmd(c, "cp", localLink+"/", cleanedContainerID+":/testVol")
// It *should not* have copied the directory using the target's name, but
// used the given name instead.
unexpectedPath := filepath.Join(testVol, cpTestPathParent)
if stat, err := os.Lstat(unexpectedPath); err == nil {
c.Fatalf("target name was copied: %q - %q", stat.Mode(), stat.Name())
}
// It *should* have copied the directory using the asked name "dir_link".
stat, err := os.Lstat(expectedPath)
if err != nil {
c.Fatalf("unable to stat resource at %q: %v", expectedPath, err)
}
if !stat.IsDir() {
c.Errorf("should have copied a directory but got %q instead", stat.Mode())
}
// And this directory should contain the file copied from the host at the
// expected location: "/testVol/dir_link/path/test"
expectedFilepath := filepath.Join(testVol, "dir_link/path/test")
fileContents, err := ioutil.ReadFile(expectedFilepath)
if err != nil {
c.Fatal(err)
}
if string(fileContents) != cpHostContents {
c.Fatalf("file contains %q but expected %q", string(fileContents), cpHostContents)
}
}
// Test for #5619
// Check that symlinks which are part of the resource path are still relative to the container's rootfs
func (s *DockerSuite) TestCpSymlinkComponent(c *check.C) {
out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpTestPath+" container_path")
if exitCode != 0 {
c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
out, _ = dockerCmd(c, "wait", cleanedContainerID)
if strings.TrimSpace(out) != "0" {
c.Fatal("failed to set up container", out)
}
if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
c.Fatal(err)
}
hostFile, err := os.Create(cpFullPath)
if err != nil {
c.Fatal(err)
}
defer hostFile.Close()
defer os.RemoveAll(cpTestPathParent)
fmt.Fprintf(hostFile, "%s", cpHostContents)
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
c.Fatal(err)
}
tmpname := filepath.Join(tmpdir, cpTestName)
defer os.RemoveAll(tmpdir)
path := path.Join("/", "container_path", cpTestName)
dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir)
file, _ := os.Open(tmpname)
defer file.Close()
test, err := ioutil.ReadAll(file)
if err != nil {
c.Fatal(err)
}
if string(test) == cpHostContents {
c.Errorf("output matched host file -- symlink path component can escape container rootfs")
}
if string(test) != cpContainerContents {
c.Errorf("output doesn't match the input for symlink path component")
}
}
// Check that cp with unprivileged user doesn't return any error
func (s *DockerSuite) TestCpUnprivilegedUser(c *check.C) {
testRequires(c, UnixCli) // uses chmod/su: not available on windows
out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "touch "+cpTestName)
if exitCode != 0 {
c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
out, _ = dockerCmd(c, "wait", cleanedContainerID)
if strings.TrimSpace(out) != "0" {
c.Fatal("failed to set up container", out)
}
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
c.Fatal(err)
}
defer os.RemoveAll(tmpdir)
if err = os.Chmod(tmpdir, 0777); err != nil {
c.Fatal(err)
}
path := cpTestName
_, _, err = runCommandWithOutput(exec.Command("su", "unprivilegeduser", "-c", dockerBinary+" cp "+cleanedContainerID+":"+path+" "+tmpdir))
if err != nil {
c.Fatalf("couldn't copy with unprivileged user: %s:%s %s", cleanedContainerID, path, err)
}
}
func (s *DockerSuite) TestCpSpecialFiles(c *check.C) {
testRequires(c, SameHostDaemon)
outDir, err := ioutil.TempDir("", "cp-test-special-files")
if err != nil {
c.Fatal(err)
}
defer os.RemoveAll(outDir)
out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "touch /foo")
if exitCode != 0 {
c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
out, _ = dockerCmd(c, "wait", cleanedContainerID)
if strings.TrimSpace(out) != "0" {
c.Fatal("failed to set up container", out)
}
// Copy actual /etc/resolv.conf
dockerCmd(c, "cp", cleanedContainerID+":/etc/resolv.conf", outDir)
expected, err := ioutil.ReadFile("/var/lib/docker/containers/" + cleanedContainerID + "/resolv.conf")
actual, err := ioutil.ReadFile(outDir + "/resolv.conf")
if !bytes.Equal(actual, expected) {
c.Fatalf("Expected copied file to be duplicate of the container resolvconf")
}
// Copy actual /etc/hosts
dockerCmd(c, "cp", cleanedContainerID+":/etc/hosts", outDir)
expected, err = ioutil.ReadFile("/var/lib/docker/containers/" + cleanedContainerID + "/hosts")
actual, err = ioutil.ReadFile(outDir + "/hosts")
if !bytes.Equal(actual, expected) {
c.Fatalf("Expected copied file to be duplicate of the container hosts")
}
// Copy actual /etc/resolv.conf
dockerCmd(c, "cp", cleanedContainerID+":/etc/hostname", outDir)
expected, err = ioutil.ReadFile("/var/lib/docker/containers/" + cleanedContainerID + "/hostname")
actual, err = ioutil.ReadFile(outDir + "/hostname")
if !bytes.Equal(actual, expected) {
c.Fatalf("Expected copied file to be duplicate of the container resolvconf")
}
}
func (s *DockerSuite) TestCpVolumePath(c *check.C) {
testRequires(c, SameHostDaemon)
tmpDir, err := ioutil.TempDir("", "cp-test-volumepath")
if err != nil {
c.Fatal(err)
}
defer os.RemoveAll(tmpDir)
outDir, err := ioutil.TempDir("", "cp-test-volumepath-out")
if err != nil {
c.Fatal(err)
}
defer os.RemoveAll(outDir)
_, err = os.Create(tmpDir + "/test")
if err != nil {
c.Fatal(err)
}
out, exitCode := dockerCmd(c, "run", "-d", "-v", "/foo", "-v", tmpDir+"/test:/test", "-v", tmpDir+":/baz", "busybox", "/bin/sh", "-c", "touch /foo/bar")
if exitCode != 0 {
c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
out, _ = dockerCmd(c, "wait", cleanedContainerID)
if strings.TrimSpace(out) != "0" {
c.Fatal("failed to set up container", out)
}
// Copy actual volume path
dockerCmd(c, "cp", cleanedContainerID+":/foo", outDir)
stat, err := os.Stat(outDir + "/foo")
if err != nil {
c.Fatal(err)
}
if !stat.IsDir() {
c.Fatal("expected copied content to be dir")
}
stat, err = os.Stat(outDir + "/foo/bar")
if err != nil {
c.Fatal(err)
}
if stat.IsDir() {
c.Fatal("Expected file `bar` to be a file")
}
// Copy file nested in volume
dockerCmd(c, "cp", cleanedContainerID+":/foo/bar", outDir)
stat, err = os.Stat(outDir + "/bar")
if err != nil {
c.Fatal(err)
}
if stat.IsDir() {
c.Fatal("Expected file `bar` to be a file")
}
// Copy Bind-mounted dir
dockerCmd(c, "cp", cleanedContainerID+":/baz", outDir)
stat, err = os.Stat(outDir + "/baz")
if err != nil {
c.Fatal(err)
}
if !stat.IsDir() {
c.Fatal("Expected `baz` to be a dir")
}
// Copy file nested in bind-mounted dir
dockerCmd(c, "cp", cleanedContainerID+":/baz/test", outDir)
fb, err := ioutil.ReadFile(outDir + "/baz/test")
if err != nil {
c.Fatal(err)
}
fb2, err := ioutil.ReadFile(tmpDir + "/test")
if err != nil {
c.Fatal(err)
}
if !bytes.Equal(fb, fb2) {
c.Fatalf("Expected copied file to be duplicate of bind-mounted file")
}
// Copy bind-mounted file
dockerCmd(c, "cp", cleanedContainerID+":/test", outDir)
fb, err = ioutil.ReadFile(outDir + "/test")
if err != nil {
c.Fatal(err)
}
fb2, err = ioutil.ReadFile(tmpDir + "/test")
if err != nil {
c.Fatal(err)
}
if !bytes.Equal(fb, fb2) {
c.Fatalf("Expected copied file to be duplicate of bind-mounted file")
}
}
func (s *DockerSuite) TestCpToDot(c *check.C) {
out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test")
if exitCode != 0 {
c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
out, _ = dockerCmd(c, "wait", cleanedContainerID)
if strings.TrimSpace(out) != "0" {
c.Fatal("failed to set up container", out)
}
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
c.Fatal(err)
}
defer os.RemoveAll(tmpdir)
cwd, err := os.Getwd()
if err != nil {
c.Fatal(err)
}
defer os.Chdir(cwd)
if err := os.Chdir(tmpdir); err != nil {
c.Fatal(err)
}
dockerCmd(c, "cp", cleanedContainerID+":/test", ".")
content, err := ioutil.ReadFile("./test")
if string(content) != "lololol\n" {
c.Fatalf("Wrong content in copied file %q, should be %q", content, "lololol\n")
}
}
func (s *DockerSuite) TestCpToStdout(c *check.C) {
out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test")
if exitCode != 0 {
c.Fatalf("failed to create a container:%s\n", out)
}
cID := strings.TrimSpace(out)
out, _ = dockerCmd(c, "wait", cID)
if strings.TrimSpace(out) != "0" {
c.Fatalf("failed to set up container:%s\n", out)
}
out, _, err := runCommandPipelineWithOutput(
exec.Command(dockerBinary, "cp", cID+":/test", "-"),
exec.Command("tar", "-vtf", "-"))
if err != nil {
c.Fatalf("Failed to run commands: %s", err)
}
if !strings.Contains(out, "test") || !strings.Contains(out, "-rw") {
c.Fatalf("Missing file from tar TOC:\n%s", out)
}
}
func (s *DockerSuite) TestCpNameHasColon(c *check.C) {
testRequires(c, SameHostDaemon)
out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /te:s:t")
if exitCode != 0 {
c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
out, _ = dockerCmd(c, "wait", cleanedContainerID)
if strings.TrimSpace(out) != "0" {
c.Fatal("failed to set up container", out)
}
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
c.Fatal(err)
}
defer os.RemoveAll(tmpdir)
dockerCmd(c, "cp", cleanedContainerID+":/te:s:t", tmpdir)
content, err := ioutil.ReadFile(tmpdir + "/te:s:t")
if string(content) != "lololol\n" {
c.Fatalf("Wrong content in copied file %q, should be %q", content, "lololol\n")
}
}
func (s *DockerSuite) TestCopyAndRestart(c *check.C) {
expectedMsg := "hello"
out, _ := dockerCmd(c, "run", "-d", "busybox", "echo", expectedMsg)
id := strings.TrimSpace(string(out))
out, _ = dockerCmd(c, "wait", id)
status := strings.TrimSpace(out)
if status != "0" {
c.Fatalf("container exited with status %s", status)
}
tmpDir, err := ioutil.TempDir("", "test-docker-restart-after-copy-")
if err != nil {
c.Fatalf("unable to make temporary directory: %s", err)
}
defer os.RemoveAll(tmpDir)
dockerCmd(c, "cp", fmt.Sprintf("%s:/etc/issue", id), tmpDir)
out, _ = dockerCmd(c, "start", "-a", id)
msg := strings.TrimSpace(out)
if msg != expectedMsg {
c.Fatalf("expected %q but got %q", expectedMsg, msg)
}
}
func (s *DockerSuite) TestCopyCreatedContainer(c *check.C) {
dockerCmd(c, "create", "--name", "test_cp", "-v", "/test", "busybox")
tmpDir, err := ioutil.TempDir("", "test")
if err != nil {
c.Fatalf("unable to make temporary directory: %s", err)
}
defer os.RemoveAll(tmpDir)
dockerCmd(c, "cp", "test_cp:/bin/sh", tmpDir)
}