github.com/containers/podman/v5@v5.1.0-rc1/test/e2e/cp_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"os"
     5  	"os/exec"
     6  	"os/user"
     7  	"path/filepath"
     8  
     9  	. "github.com/containers/podman/v5/test/utils"
    10  	. "github.com/onsi/ginkgo/v2"
    11  	. "github.com/onsi/gomega"
    12  )
    13  
    14  // NOTE: Only smoke tests.  The system tests (i.e., "./test/system/*") take
    15  // care of function and regression tests.  Please consider adding system tests
    16  // rather than e2e tests.  System tests are used in RHEL gating.
    17  
    18  var _ = Describe("Podman cp", func() {
    19  
    20  	// Copy a file to the container, then back to the host and make sure
    21  	// that the contents match.
    22  	It("podman cp file", func() {
    23  		srcFile, err := os.CreateTemp("", "")
    24  		Expect(err).ToNot(HaveOccurred())
    25  		defer srcFile.Close()
    26  		defer os.Remove(srcFile.Name())
    27  
    28  		originalContent := []byte("podman cp file test")
    29  		err = os.WriteFile(srcFile.Name(), originalContent, 0644)
    30  		Expect(err).ToNot(HaveOccurred())
    31  
    32  		// Create a container. NOTE that container mustn't be running for copying.
    33  		session := podmanTest.Podman([]string{"create", ALPINE})
    34  		session.WaitWithDefaultTimeout()
    35  		Expect(session).Should(ExitCleanly())
    36  		name := session.OutputToString()
    37  
    38  		// Copy TO the container.
    39  
    40  		// Cannot copy to a nonexistent path (note the trailing "/").
    41  		session = podmanTest.Podman([]string{"cp", srcFile.Name(), name + ":foo/"})
    42  		session.WaitWithDefaultTimeout()
    43  		Expect(session).To(ExitWithError(125, `"foo/" could not be found on container`))
    44  
    45  		// The file will now be created (and written to).
    46  		session = podmanTest.Podman([]string{"cp", srcFile.Name(), name + ":foo"})
    47  		session.WaitWithDefaultTimeout()
    48  		Expect(session).Should(ExitCleanly())
    49  
    50  		// Copy FROM the container.
    51  
    52  		destFile, err := os.CreateTemp("", "")
    53  		Expect(err).ToNot(HaveOccurred())
    54  		defer destFile.Close()
    55  		defer os.Remove(destFile.Name())
    56  
    57  		session = podmanTest.Podman([]string{"cp", name + ":foo", destFile.Name()})
    58  		session.WaitWithDefaultTimeout()
    59  		Expect(session).Should(ExitCleanly())
    60  
    61  		session = podmanTest.Podman([]string{"start", name})
    62  		session.WaitWithDefaultTimeout()
    63  		Expect(session).Should(ExitCleanly())
    64  
    65  		// Now make sure the content matches.
    66  		roundtripContent, err := os.ReadFile(destFile.Name())
    67  		Expect(err).ToNot(HaveOccurred())
    68  		Expect(roundtripContent).To(Equal(originalContent))
    69  	})
    70  
    71  	// Copy a file to the container, then back to the host in --pid=host
    72  	It("podman cp --pid=host file", func() {
    73  		SkipIfRootlessCgroupsV1("Not supported for rootless + CgroupsV1")
    74  		srcFile, err := os.CreateTemp("", "")
    75  		Expect(err).ToNot(HaveOccurred())
    76  		defer srcFile.Close()
    77  		defer os.Remove(srcFile.Name())
    78  
    79  		originalContent := []byte("podman cp file test")
    80  		err = os.WriteFile(srcFile.Name(), originalContent, 0644)
    81  		Expect(err).ToNot(HaveOccurred())
    82  
    83  		// Create a container. NOTE that container mustn't be running for copying.
    84  		session := podmanTest.Podman([]string{"create", "--pid=host", ALPINE, "top"})
    85  		session.WaitWithDefaultTimeout()
    86  		Expect(session).Should(ExitCleanly())
    87  		name := session.OutputToString()
    88  
    89  		session = podmanTest.Podman([]string{"start", name})
    90  		session.WaitWithDefaultTimeout()
    91  		Expect(session).Should(ExitCleanly())
    92  
    93  		// The file will now be created (and written to).
    94  		session = podmanTest.Podman([]string{"cp", srcFile.Name(), name + ":foo"})
    95  		session.WaitWithDefaultTimeout()
    96  		Expect(session).Should(ExitCleanly())
    97  
    98  		// Copy FROM the container.
    99  
   100  		destFile, err := os.CreateTemp("", "")
   101  		Expect(err).ToNot(HaveOccurred())
   102  		defer destFile.Close()
   103  		defer os.Remove(destFile.Name())
   104  
   105  		session = podmanTest.Podman([]string{"cp", name + ":foo", destFile.Name()})
   106  		session.WaitWithDefaultTimeout()
   107  		Expect(session).Should(ExitCleanly())
   108  
   109  		// Now make sure the content matches.
   110  		roundtripContent, err := os.ReadFile(destFile.Name())
   111  		Expect(err).ToNot(HaveOccurred())
   112  		Expect(roundtripContent).To(Equal(originalContent))
   113  	})
   114  
   115  	// Create a symlink in the container, use it as a copy destination and
   116  	// make sure that the link and the resolved path are accessible and
   117  	// give the right content.
   118  	It("podman cp symlink", func() {
   119  		srcFile, err := os.CreateTemp("", "")
   120  		Expect(err).ToNot(HaveOccurred())
   121  		defer srcFile.Close()
   122  		defer os.Remove(srcFile.Name())
   123  
   124  		originalContent := []byte("podman cp symlink test")
   125  		err = os.WriteFile(srcFile.Name(), originalContent, 0644)
   126  		Expect(err).ToNot(HaveOccurred())
   127  
   128  		session := podmanTest.Podman([]string{"run", "-d", ALPINE, "top"})
   129  		session.WaitWithDefaultTimeout()
   130  		Expect(session).Should(ExitCleanly())
   131  		name := session.OutputToString()
   132  
   133  		session = podmanTest.Podman([]string{"exec", name, "ln", "-s", "/tmp", "/test"})
   134  		session.WaitWithDefaultTimeout()
   135  		Expect(session).Should(ExitCleanly())
   136  
   137  		session = podmanTest.Podman([]string{"cp", "--pause=false", srcFile.Name(), name + ":/test"})
   138  		session.WaitWithDefaultTimeout()
   139  		Expect(session).Should(ExitCleanly())
   140  
   141  		session = podmanTest.Podman([]string{"exec", name, "cat", "/tmp/" + filepath.Base(srcFile.Name())})
   142  		session.WaitWithDefaultTimeout()
   143  		Expect(session).Should(ExitCleanly())
   144  		Expect(session.OutputToString()).To(ContainSubstring(string(originalContent)))
   145  
   146  		session = podmanTest.Podman([]string{"exec", name, "cat", "/test/" + filepath.Base(srcFile.Name())})
   147  		session.WaitWithDefaultTimeout()
   148  		Expect(session).Should(ExitCleanly())
   149  		Expect(session.OutputToString()).To(ContainSubstring(string(originalContent)))
   150  	})
   151  
   152  	// Copy a file to a volume in the container.  The tricky part is that
   153  	// containers mustn't be running for copying, so Podman has to do some
   154  	// intense Yoga and 1) detect volume paths on the container, 2) resolve
   155  	// the path to the volume's mount point on the host, and 3) copy the
   156  	// data to the volume and not the container.
   157  	It("podman cp volume", func() {
   158  		srcFile, err := os.CreateTemp("", "")
   159  		Expect(err).ToNot(HaveOccurred())
   160  		defer srcFile.Close()
   161  		defer os.Remove(srcFile.Name())
   162  
   163  		originalContent := []byte("podman cp volume")
   164  		err = os.WriteFile(srcFile.Name(), originalContent, 0644)
   165  		Expect(err).ToNot(HaveOccurred())
   166  		session := podmanTest.Podman([]string{"volume", "create", "data"})
   167  		session.WaitWithDefaultTimeout()
   168  		Expect(session).Should(ExitCleanly())
   169  
   170  		session = podmanTest.Podman([]string{"create", "-v", "data:/data", "--name", "container1", ALPINE})
   171  		session.WaitWithDefaultTimeout()
   172  		Expect(session).Should(ExitCleanly())
   173  
   174  		session = podmanTest.Podman([]string{"cp", srcFile.Name(), "container1" + ":/data/file.txt"})
   175  		session.WaitWithDefaultTimeout()
   176  		Expect(session).Should(ExitCleanly())
   177  
   178  		// Now get the volume's mount point, read the file and make
   179  		// sure the contents match.
   180  		session = podmanTest.Podman([]string{"volume", "inspect", "data", "--format", "{{.Mountpoint}}"})
   181  		session.WaitWithDefaultTimeout()
   182  		Expect(session).Should(ExitCleanly())
   183  
   184  		volumeMountPoint := session.OutputToString()
   185  		copiedContent, err := os.ReadFile(filepath.Join(volumeMountPoint, "file.txt"))
   186  		Expect(err).ToNot(HaveOccurred())
   187  		Expect(copiedContent).To(Equal(originalContent))
   188  	})
   189  
   190  	// Create another user in the container, let them create a file, copy
   191  	// it to the host and back to the container and make sure that we can
   192  	// access it, and (roughly) the right users own it.
   193  	It("podman cp from ctr chown ", func() {
   194  		srcFile, err := os.CreateTemp("", "")
   195  		Expect(err).ToNot(HaveOccurred())
   196  		defer srcFile.Close()
   197  		defer os.Remove(srcFile.Name())
   198  
   199  		setup := podmanTest.RunTopContainer("testctr")
   200  		setup.WaitWithDefaultTimeout()
   201  		Expect(setup).Should(ExitCleanly())
   202  
   203  		session := podmanTest.Podman([]string{"exec", "testctr", "adduser", "-S", "testuser"})
   204  		session.WaitWithDefaultTimeout()
   205  		Expect(session).Should(ExitCleanly())
   206  
   207  		session = podmanTest.Podman([]string{"exec", "-u", "testuser", "testctr", "touch", "/tmp/testfile"})
   208  		session.WaitWithDefaultTimeout()
   209  		Expect(session).Should(ExitCleanly())
   210  
   211  		session = podmanTest.Podman([]string{"cp", "--pause=false", "testctr:/tmp/testfile", srcFile.Name()})
   212  		session.WaitWithDefaultTimeout()
   213  		Expect(session).Should(ExitCleanly())
   214  
   215  		// owner of the file copied to local machine is not testuser
   216  		u, err := user.Current()
   217  		Expect(err).ToNot(HaveOccurred())
   218  		cmd := exec.Command("ls", "-l", srcFile.Name())
   219  		cmdRet, err := cmd.Output()
   220  		Expect(err).ToNot(HaveOccurred())
   221  		Expect(string(cmdRet)).To(ContainSubstring(u.Username))
   222  
   223  		session = podmanTest.Podman([]string{"cp", "--pause=false", srcFile.Name(), "testctr:testfile2"})
   224  		session.WaitWithDefaultTimeout()
   225  		Expect(session).Should(ExitCleanly())
   226  
   227  		// owner of the file copied to a container is the root user
   228  		session = podmanTest.Podman([]string{"exec", "testctr", "ls", "-l", "testfile2"})
   229  		session.WaitWithDefaultTimeout()
   230  		Expect(session).Should(ExitCleanly())
   231  		Expect(session.OutputToString()).To(ContainSubstring("root"))
   232  	})
   233  
   234  	// Copy the root dir "/" of a container to the host.
   235  	It("podman cp the root directory from the ctr to an existing directory on the host ", func() {
   236  		container := "copyroottohost"
   237  		session := podmanTest.RunTopContainer(container)
   238  		session.WaitWithDefaultTimeout()
   239  		Expect(session).Should(ExitCleanly())
   240  
   241  		session = podmanTest.Podman([]string{"exec", container, "touch", "/dummy.txt"})
   242  		session.WaitWithDefaultTimeout()
   243  		Expect(session).Should(ExitCleanly())
   244  
   245  		tmpDir := GinkgoT().TempDir()
   246  
   247  		session = podmanTest.Podman([]string{"cp", container + ":/", tmpDir})
   248  		session.WaitWithDefaultTimeout()
   249  		Expect(session).Should(ExitCleanly())
   250  
   251  		cmd := exec.Command("ls", "-la", tmpDir)
   252  		output, err := cmd.Output()
   253  		lsOutput := string(output)
   254  		Expect(err).ToNot(HaveOccurred())
   255  		Expect(lsOutput).To(ContainSubstring("dummy.txt"))
   256  		Expect(lsOutput).To(ContainSubstring("tmp"))
   257  		Expect(lsOutput).To(ContainSubstring("etc"))
   258  		Expect(lsOutput).To(ContainSubstring("var"))
   259  		Expect(lsOutput).To(ContainSubstring("bin"))
   260  		Expect(lsOutput).To(ContainSubstring("usr"))
   261  	})
   262  })