github.com/AbhinandanKurakure/podman/v3@v3.4.10/test/e2e/run_volume_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"os/exec"
     8  	"os/user"
     9  	"path/filepath"
    10  	"strings"
    11  
    12  	"github.com/containers/podman/v3/pkg/rootless"
    13  	. "github.com/containers/podman/v3/test/utils"
    14  	. "github.com/onsi/ginkgo"
    15  	. "github.com/onsi/gomega"
    16  	. "github.com/onsi/gomega/gexec"
    17  )
    18  
    19  // in-container mount point: using a path that is definitely not present
    20  // on the host system might help to uncover some issues.
    21  const dest = "/unique/path"
    22  
    23  var _ = Describe("Podman run with volumes", func() {
    24  	var (
    25  		tempdir    string
    26  		err        error
    27  		podmanTest *PodmanTestIntegration
    28  	)
    29  
    30  	BeforeEach(func() {
    31  		tempdir, err = CreateTempDirInTempDir()
    32  		if err != nil {
    33  			os.Exit(1)
    34  		}
    35  		podmanTest = PodmanTestCreate(tempdir)
    36  		podmanTest.Setup()
    37  		podmanTest.SeedImages()
    38  	})
    39  
    40  	AfterEach(func() {
    41  		podmanTest.Cleanup()
    42  		f := CurrentGinkgoTestDescription()
    43  		processTestResult(f)
    44  	})
    45  
    46  	It("podman run with volume flag", func() {
    47  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
    48  		os.Mkdir(mountPath, 0755)
    49  		vol := mountPath + ":" + dest
    50  
    51  		session := podmanTest.Podman([]string{"run", "--rm", "-v", vol, ALPINE, "grep", dest, "/proc/self/mountinfo"})
    52  		session.WaitWithDefaultTimeout()
    53  		Expect(session).Should(Exit(0))
    54  		found, matches := session.GrepString(dest)
    55  		Expect(found).Should(BeTrue())
    56  		Expect(matches[0]).To(ContainSubstring("rw"))
    57  
    58  		session = podmanTest.Podman([]string{"run", "--rm", "-v", vol + ":ro", ALPINE, "grep", dest, "/proc/self/mountinfo"})
    59  		session.WaitWithDefaultTimeout()
    60  		Expect(session).Should(Exit(0))
    61  		found, matches = session.GrepString(dest)
    62  		Expect(found).Should(BeTrue())
    63  		Expect(matches[0]).To(ContainSubstring("ro"))
    64  
    65  		session = podmanTest.Podman([]string{"run", "--rm", "-v", vol + ":shared", ALPINE, "grep", dest, "/proc/self/mountinfo"})
    66  		session.WaitWithDefaultTimeout()
    67  		Expect(session).Should(Exit(0))
    68  		found, matches = session.GrepString(dest)
    69  		Expect(found).Should(BeTrue())
    70  		Expect(matches[0]).To(ContainSubstring("rw"))
    71  		Expect(matches[0]).To(ContainSubstring("shared"))
    72  
    73  		// Cached is ignored
    74  		session = podmanTest.Podman([]string{"run", "--rm", "-v", vol + ":cached", ALPINE, "grep", dest, "/proc/self/mountinfo"})
    75  		session.WaitWithDefaultTimeout()
    76  		Expect(session).Should(Exit(0))
    77  		found, matches = session.GrepString(dest)
    78  		Expect(found).Should(BeTrue())
    79  		Expect(matches[0]).To(ContainSubstring("rw"))
    80  		Expect(matches[0]).To(Not(ContainSubstring("cached")))
    81  
    82  		// Delegated is ignored
    83  		session = podmanTest.Podman([]string{"run", "--rm", "-v", vol + ":delegated", ALPINE, "grep", dest, "/proc/self/mountinfo"})
    84  		session.WaitWithDefaultTimeout()
    85  		Expect(session).Should(Exit(0))
    86  		found, matches = session.GrepString(dest)
    87  		Expect(found).Should(BeTrue())
    88  		Expect(matches[0]).To(ContainSubstring("rw"))
    89  		Expect(matches[0]).To(Not(ContainSubstring("delegated")))
    90  	})
    91  
    92  	It("podman run with --mount flag", func() {
    93  		if podmanTest.Host.Arch == "ppc64le" {
    94  			Skip("skip failing test on ppc64le")
    95  		}
    96  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
    97  		os.Mkdir(mountPath, 0755)
    98  		mount := "type=bind,src=" + mountPath + ",target=" + dest
    99  
   100  		session := podmanTest.Podman([]string{"run", "--rm", "--mount", mount, ALPINE, "grep", dest, "/proc/self/mountinfo"})
   101  		session.WaitWithDefaultTimeout()
   102  		Expect(session).Should(Exit(0))
   103  		Expect(session.OutputToString()).To(ContainSubstring(dest + " rw"))
   104  
   105  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   106  		session.WaitWithDefaultTimeout()
   107  		Expect(session).Should(Exit(0))
   108  		Expect(session.OutputToString()).To(ContainSubstring(dest + " ro"))
   109  
   110  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",readonly", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   111  		session.WaitWithDefaultTimeout()
   112  		Expect(session).Should(Exit(0))
   113  		Expect(session.OutputToString()).To(ContainSubstring(dest + " ro"))
   114  
   115  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",consistency=delegated,shared", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   116  		session.WaitWithDefaultTimeout()
   117  		Expect(session).Should(Exit(0))
   118  		found, matches := session.GrepString(dest)
   119  		Expect(found).Should(BeTrue())
   120  		Expect(matches[0]).To(ContainSubstring("rw"))
   121  		Expect(matches[0]).To(ContainSubstring("shared"))
   122  
   123  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=" + dest, ALPINE, "grep", dest, "/proc/self/mountinfo"})
   124  		session.WaitWithDefaultTimeout()
   125  		Expect(session).Should(Exit(0))
   126  		Expect(session.OutputToString()).To(ContainSubstring(dest + " rw,nosuid,nodev,relatime - tmpfs"))
   127  
   128  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,tmpcopyup", ALPINE, "ls", "/etc/ssl"})
   129  		session.WaitWithDefaultTimeout()
   130  		Expect(session).Should(Exit(0))
   131  		Expect(session.OutputToString()).To(ContainSubstring("certs"))
   132  
   133  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,tmpcopyup,notmpcopyup", ALPINE, "ls", "/etc/ssl"})
   134  		session.WaitWithDefaultTimeout()
   135  		Expect(session).To(ExitWithError())
   136  
   137  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=bind,src=/tmp,target=/tmp,tmpcopyup", ALPINE, "true"})
   138  		session.WaitWithDefaultTimeout()
   139  		Expect(session).To(ExitWithError())
   140  
   141  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=bind,src=/tmp,target=/tmp,notmpcopyup", ALPINE, "true"})
   142  		session.WaitWithDefaultTimeout()
   143  		Expect(session).To(ExitWithError())
   144  
   145  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,notmpcopyup", ALPINE, "ls", "/etc/ssl"})
   146  		session.WaitWithDefaultTimeout()
   147  		Expect(session).Should(Exit(0))
   148  		Expect(session.OutputToString()).To(Not(ContainSubstring("certs")))
   149  	})
   150  
   151  	It("podman run with conflicting volumes errors", func() {
   152  		mountPath := filepath.Join(podmanTest.TmpDir, "secrets")
   153  		os.Mkdir(mountPath, 0755)
   154  		session := podmanTest.Podman([]string{"run", "-v", mountPath + ":" + dest, "-v", "/tmp" + ":" + dest, ALPINE, "ls"})
   155  		session.WaitWithDefaultTimeout()
   156  		Expect(session).Should(Exit(125))
   157  	})
   158  
   159  	It("podman run with conflict between image volume and user mount succeeds", func() {
   160  		podmanTest.RestoreArtifact(redis)
   161  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   162  		err := os.Mkdir(mountPath, 0755)
   163  		Expect(err).To(BeNil())
   164  		testFile := filepath.Join(mountPath, "test1")
   165  		f, err := os.Create(testFile)
   166  		f.Close()
   167  		Expect(err).To(BeNil())
   168  		session := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/data", mountPath), redis, "ls", "/data/test1"})
   169  		session.WaitWithDefaultTimeout()
   170  		Expect(session).Should(Exit(0))
   171  	})
   172  
   173  	It("podman run with mount flag and boolean options", func() {
   174  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   175  		os.Mkdir(mountPath, 0755)
   176  		mount := "type=bind,src=" + mountPath + ",target=" + dest
   177  
   178  		session := podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro=false", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   179  		session.WaitWithDefaultTimeout()
   180  		Expect(session).Should(Exit(0))
   181  		Expect(session.OutputToString()).To(ContainSubstring(dest + " rw"))
   182  
   183  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro=true", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   184  		session.WaitWithDefaultTimeout()
   185  		Expect(session).Should(Exit(0))
   186  		Expect(session.OutputToString()).To(ContainSubstring(dest + " ro"))
   187  
   188  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro=true,rw=false", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   189  		session.WaitWithDefaultTimeout()
   190  		Expect(session).To(ExitWithError())
   191  	})
   192  
   193  	It("podman run with volume flag and multiple named volumes", func() {
   194  		session := podmanTest.Podman([]string{"run", "--rm", "-v", "testvol1:/testvol1", "-v", "testvol2:/testvol2", ALPINE, "grep", "/testvol", "/proc/self/mountinfo"})
   195  		session.WaitWithDefaultTimeout()
   196  		Expect(session).Should(Exit(0))
   197  		Expect(session.OutputToString()).To(ContainSubstring("/testvol1"))
   198  		Expect(session.OutputToString()).To(ContainSubstring("/testvol2"))
   199  	})
   200  
   201  	It("podman run with volumes and suid/dev/exec options", func() {
   202  		SkipIfRemote("podman-remote does not support --volumes")
   203  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   204  		os.Mkdir(mountPath, 0755)
   205  
   206  		session := podmanTest.Podman([]string{"run", "--rm", "-v", mountPath + ":" + dest + ":suid,dev,exec", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   207  		session.WaitWithDefaultTimeout()
   208  		Expect(session).Should(Exit(0))
   209  		found, matches := session.GrepString(dest)
   210  		Expect(found).Should(BeTrue())
   211  		Expect(matches[0]).To(Not(ContainSubstring("noexec")))
   212  		Expect(matches[0]).To(Not(ContainSubstring("nodev")))
   213  		Expect(matches[0]).To(Not(ContainSubstring("nosuid")))
   214  
   215  		session = podmanTest.Podman([]string{"run", "--rm", "--tmpfs", dest + ":suid,dev,exec", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   216  		session.WaitWithDefaultTimeout()
   217  		Expect(session).Should(Exit(0))
   218  		found, matches = session.GrepString(dest)
   219  		Expect(found).Should(BeTrue())
   220  		Expect(matches[0]).To(Not(ContainSubstring("noexec")))
   221  		Expect(matches[0]).To(Not(ContainSubstring("nodev")))
   222  		Expect(matches[0]).To(Not(ContainSubstring("nosuid")))
   223  	})
   224  
   225  	// Container should start when workdir is overlayed volume
   226  	It("podman run with volume mounted as overlay and used as workdir", func() {
   227  		SkipIfRemote("Overlay volumes only work locally")
   228  		if os.Getenv("container") != "" {
   229  			Skip("Overlay mounts not supported when running in a container")
   230  		}
   231  		if rootless.IsRootless() {
   232  			if _, err := exec.LookPath("fuse-overlayfs"); err != nil {
   233  				Skip("Fuse-Overlayfs required for rootless overlay mount test")
   234  			}
   235  		}
   236  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   237  		os.Mkdir(mountPath, 0755)
   238  
   239  		//Container should be able to start with custom overlayed volume
   240  		session := podmanTest.Podman([]string{"run", "--rm", "-v", mountPath + ":/data:O", "--workdir=/data", ALPINE, "echo", "hello"})
   241  		session.WaitWithDefaultTimeout()
   242  		Expect(session).Should(Exit(0))
   243  	})
   244  
   245  	It("podman run with noexec can't exec", func() {
   246  		session := podmanTest.Podman([]string{"run", "--rm", "-v", "/bin:/hostbin:noexec", ALPINE, "/hostbin/ls", "/"})
   247  		session.WaitWithDefaultTimeout()
   248  		Expect(session).To(ExitWithError())
   249  	})
   250  
   251  	It("podman run with tmpfs named volume mounts and unmounts", func() {
   252  		SkipIfRootless("FIXME:  rootless podman mount requires you to be in a user namespace")
   253  		SkipIfRemote("podman-remote does not support --volumes this test could be simplified to be tested on Remote.")
   254  		volName := "testvol"
   255  		mkVolume := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=nodev", "testvol"})
   256  		mkVolume.WaitWithDefaultTimeout()
   257  		Expect(mkVolume).Should(Exit(0))
   258  
   259  		// Volume not mounted on create
   260  		mountCmd1, err := Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
   261  		Expect(err).To(BeNil())
   262  		mountCmd1.Wait(90)
   263  		Expect(mountCmd1).Should(Exit(0))
   264  		os.Stdout.Sync()
   265  		os.Stderr.Sync()
   266  		mountOut1 := strings.Join(strings.Fields(string(mountCmd1.Out.Contents())), " ")
   267  		fmt.Printf("Output: %s", mountOut1)
   268  		Expect(strings.Contains(mountOut1, volName)).To(BeFalse())
   269  
   270  		ctrName := "testctr"
   271  		podmanSession := podmanTest.Podman([]string{"run", "-d", "--name", ctrName, "-v", fmt.Sprintf("%s:/testvol", volName), ALPINE, "top"})
   272  		podmanSession.WaitWithDefaultTimeout()
   273  		Expect(podmanSession).Should(Exit(0))
   274  
   275  		// Volume now mounted as container is running
   276  		mountCmd2, err := Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
   277  		Expect(err).To(BeNil())
   278  		mountCmd2.Wait(90)
   279  		Expect(mountCmd2).Should(Exit(0))
   280  		os.Stdout.Sync()
   281  		os.Stderr.Sync()
   282  		mountOut2 := strings.Join(strings.Fields(string(mountCmd2.Out.Contents())), " ")
   283  		fmt.Printf("Output: %s", mountOut2)
   284  		Expect(strings.Contains(mountOut2, volName)).To(BeTrue())
   285  
   286  		// Stop the container to unmount
   287  		podmanStopSession := podmanTest.Podman([]string{"stop", "--time", "0", ctrName})
   288  		podmanStopSession.WaitWithDefaultTimeout()
   289  		Expect(podmanStopSession).Should(Exit(0))
   290  
   291  		// We have to force cleanup so the unmount happens
   292  		podmanCleanupSession := podmanTest.Podman([]string{"container", "cleanup", ctrName})
   293  		podmanCleanupSession.WaitWithDefaultTimeout()
   294  		Expect(podmanCleanupSession).Should(Exit(0))
   295  
   296  		// Ensure volume is unmounted
   297  		mountCmd3, err := Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
   298  		Expect(err).To(BeNil())
   299  		mountCmd3.Wait(90)
   300  		Expect(mountCmd3).Should(Exit(0))
   301  		os.Stdout.Sync()
   302  		os.Stderr.Sync()
   303  		mountOut3 := strings.Join(strings.Fields(string(mountCmd3.Out.Contents())), " ")
   304  		fmt.Printf("Output: %s", mountOut3)
   305  		Expect(strings.Contains(mountOut3, volName)).To(BeFalse())
   306  	})
   307  
   308  	It("podman named volume copyup", func() {
   309  		baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", ALPINE, "ls", "/etc/apk/"})
   310  		baselineSession.WaitWithDefaultTimeout()
   311  		Expect(baselineSession).Should(Exit(0))
   312  		baselineOutput := baselineSession.OutputToString()
   313  
   314  		inlineVolumeSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "-v", "testvol1:/etc/apk", ALPINE, "ls", "/etc/apk/"})
   315  		inlineVolumeSession.WaitWithDefaultTimeout()
   316  		Expect(inlineVolumeSession).Should(Exit(0))
   317  		Expect(inlineVolumeSession.OutputToString()).To(Equal(baselineOutput))
   318  
   319  		makeVolumeSession := podmanTest.Podman([]string{"volume", "create", "testvol2"})
   320  		makeVolumeSession.WaitWithDefaultTimeout()
   321  		Expect(makeVolumeSession).Should(Exit(0))
   322  
   323  		separateVolumeSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "-v", "testvol2:/etc/apk", ALPINE, "ls", "/etc/apk/"})
   324  		separateVolumeSession.WaitWithDefaultTimeout()
   325  		Expect(separateVolumeSession).Should(Exit(0))
   326  		Expect(separateVolumeSession.OutputToString()).To(Equal(baselineOutput))
   327  	})
   328  
   329  	It("podman named volume copyup symlink", func() {
   330  		imgName := "testimg"
   331  		dockerfile := fmt.Sprintf(`FROM %s
   332  RUN touch /testfile
   333  RUN sh -c "cd /etc/apk && ln -s ../../testfile"`, ALPINE)
   334  		podmanTest.BuildImage(dockerfile, imgName, "false")
   335  
   336  		baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", imgName, "ls", "/etc/apk/"})
   337  		baselineSession.WaitWithDefaultTimeout()
   338  		Expect(baselineSession).Should(Exit(0))
   339  		baselineOutput := baselineSession.OutputToString()
   340  
   341  		outputSession := podmanTest.Podman([]string{"run", "-t", "-i", "-v", "/etc/apk/", imgName, "ls", "/etc/apk/"})
   342  		outputSession.WaitWithDefaultTimeout()
   343  		Expect(outputSession).Should(Exit(0))
   344  		Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
   345  	})
   346  
   347  	It("podman named volume copyup empty directory", func() {
   348  		baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", ALPINE, "ls", "/srv"})
   349  		baselineSession.WaitWithDefaultTimeout()
   350  		Expect(baselineSession).Should(Exit(0))
   351  		baselineOutput := baselineSession.OutputToString()
   352  
   353  		outputSession := podmanTest.Podman([]string{"run", "-t", "-i", "-v", "/srv", ALPINE, "ls", "/srv"})
   354  		outputSession.WaitWithDefaultTimeout()
   355  		Expect(outputSession).Should(Exit(0))
   356  		Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
   357  	})
   358  
   359  	It("podman named volume copyup of /var", func() {
   360  		baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", fedoraMinimal, "ls", "/var"})
   361  		baselineSession.WaitWithDefaultTimeout()
   362  		Expect(baselineSession).Should(Exit(0))
   363  		baselineOutput := baselineSession.OutputToString()
   364  
   365  		outputSession := podmanTest.Podman([]string{"run", "-t", "-i", "-v", "/var", fedoraMinimal, "ls", "/var"})
   366  		outputSession.WaitWithDefaultTimeout()
   367  		Expect(outputSession).Should(Exit(0))
   368  		Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
   369  	})
   370  
   371  	It("podman read-only tmpfs conflict with volume", func() {
   372  		session := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "--read-only", "-v", "tmp_volume:" + dest, ALPINE, "touch", dest + "/a"})
   373  		session.WaitWithDefaultTimeout()
   374  		Expect(session).Should(Exit(0))
   375  
   376  		session2 := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "--read-only", "--tmpfs", dest, ALPINE, "touch", dest + "/a"})
   377  		session2.WaitWithDefaultTimeout()
   378  		Expect(session2).Should(Exit(0))
   379  	})
   380  
   381  	It("podman run with anonymous volume", func() {
   382  		list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   383  		list1.WaitWithDefaultTimeout()
   384  		Expect(list1).Should(Exit(0))
   385  		Expect(list1.OutputToString()).To(Equal(""))
   386  
   387  		session := podmanTest.Podman([]string{"create", "-v", "/test", ALPINE, "top"})
   388  		session.WaitWithDefaultTimeout()
   389  		Expect(session).Should(Exit(0))
   390  
   391  		list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   392  		list2.WaitWithDefaultTimeout()
   393  		Expect(list2).Should(Exit(0))
   394  		arr := list2.OutputToStringArray()
   395  		Expect(len(arr)).To(Equal(1))
   396  		Expect(arr[0]).To(Not(Equal("")))
   397  	})
   398  
   399  	It("podman rm -v removes anonymous volume", func() {
   400  		list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   401  		list1.WaitWithDefaultTimeout()
   402  		Expect(list1).Should(Exit(0))
   403  		Expect(list1.OutputToString()).To(Equal(""))
   404  
   405  		ctrName := "testctr"
   406  		session := podmanTest.Podman([]string{"create", "--name", ctrName, "-v", "/test", ALPINE, "top"})
   407  		session.WaitWithDefaultTimeout()
   408  		Expect(session).Should(Exit(0))
   409  
   410  		list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   411  		list2.WaitWithDefaultTimeout()
   412  		Expect(list2).Should(Exit(0))
   413  		arr := list2.OutputToStringArray()
   414  		Expect(len(arr)).To(Equal(1))
   415  		Expect(arr[0]).To(Not(Equal("")))
   416  
   417  		remove := podmanTest.Podman([]string{"rm", "-v", ctrName})
   418  		remove.WaitWithDefaultTimeout()
   419  		Expect(remove).Should(Exit(0))
   420  
   421  		list3 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   422  		list3.WaitWithDefaultTimeout()
   423  		Expect(list3).Should(Exit(0))
   424  		Expect(list3.OutputToString()).To(Equal(""))
   425  	})
   426  
   427  	It("podman rm -v retains named volume", func() {
   428  		list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   429  		list1.WaitWithDefaultTimeout()
   430  		Expect(list1).Should(Exit(0))
   431  		Expect(list1.OutputToString()).To(Equal(""))
   432  
   433  		ctrName := "testctr"
   434  		volName := "testvol"
   435  		session := podmanTest.Podman([]string{"create", "--name", ctrName, "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "top"})
   436  		session.WaitWithDefaultTimeout()
   437  		Expect(session).Should(Exit(0))
   438  
   439  		list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   440  		list2.WaitWithDefaultTimeout()
   441  		Expect(list2).Should(Exit(0))
   442  		arr := list2.OutputToStringArray()
   443  		Expect(len(arr)).To(Equal(1))
   444  		Expect(arr[0]).To(Equal(volName))
   445  
   446  		remove := podmanTest.Podman([]string{"rm", "-v", ctrName})
   447  		remove.WaitWithDefaultTimeout()
   448  		Expect(remove).Should(Exit(0))
   449  
   450  		list3 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   451  		list3.WaitWithDefaultTimeout()
   452  		Expect(list3).Should(Exit(0))
   453  		arr2 := list3.OutputToStringArray()
   454  		Expect(len(arr2)).To(Equal(1))
   455  		Expect(arr2[0]).To(Equal(volName))
   456  	})
   457  
   458  	It("podman run image volume is not noexec", func() {
   459  		session := podmanTest.Podman([]string{"run", "--rm", redis, "grep", "/data", "/proc/self/mountinfo"})
   460  		session.WaitWithDefaultTimeout()
   461  		Expect(session).Should(Exit(0))
   462  		Expect(session.OutputToString()).To(Not(ContainSubstring("noexec")))
   463  	})
   464  
   465  	It("podman mount with invalid option fails", func() {
   466  		volName := "testVol"
   467  		volCreate := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=invalid", volName})
   468  		volCreate.WaitWithDefaultTimeout()
   469  		Expect(volCreate).Should(Exit(0))
   470  
   471  		volMount := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/tmp", volName), ALPINE, "ls"})
   472  		volMount.WaitWithDefaultTimeout()
   473  		Expect(volMount).To(ExitWithError())
   474  	})
   475  
   476  	It("Podman fix for CVE-2020-1726", func() {
   477  		volName := "testVol"
   478  		volCreate := podmanTest.Podman([]string{"volume", "create", volName})
   479  		volCreate.WaitWithDefaultTimeout()
   480  		Expect(volCreate).Should(Exit(0))
   481  
   482  		volPath := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{.Mountpoint}}", volName})
   483  		volPath.WaitWithDefaultTimeout()
   484  		Expect(volPath).Should(Exit(0))
   485  		path := volPath.OutputToString()
   486  
   487  		fileName := "thisIsATestFile"
   488  		file, err := os.Create(filepath.Join(path, fileName))
   489  		Expect(err).To(BeNil())
   490  		defer file.Close()
   491  
   492  		runLs := podmanTest.Podman([]string{"run", "-t", "-i", "--rm", "-v", fmt.Sprintf("%v:/etc/ssl", volName), ALPINE, "ls", "-1", "/etc/ssl"})
   493  		runLs.WaitWithDefaultTimeout()
   494  		Expect(runLs).Should(Exit(0))
   495  		outputArr := runLs.OutputToStringArray()
   496  		Expect(len(outputArr)).To(Equal(1))
   497  		Expect(strings.Contains(outputArr[0], fileName)).To(BeTrue())
   498  	})
   499  
   500  	It("Podman mount over image volume with trailing /", func() {
   501  		image := "podman-volume-test:trailing"
   502  		dockerfile := fmt.Sprintf(`FROM %s
   503  VOLUME /test/`, ALPINE)
   504  		podmanTest.BuildImage(dockerfile, image, "false")
   505  
   506  		ctrName := "testCtr"
   507  		create := podmanTest.Podman([]string{"create", "-v", "/tmp:/test", "--name", ctrName, image, "ls"})
   508  		create.WaitWithDefaultTimeout()
   509  		Expect(create).Should(Exit(0))
   510  
   511  		data := podmanTest.InspectContainer(ctrName)
   512  		Expect(len(data)).To(Equal(1))
   513  		Expect(len(data[0].Mounts)).To(Equal(1))
   514  		Expect(data[0].Mounts[0].Source).To(Equal("/tmp"))
   515  		Expect(data[0].Mounts[0].Destination).To(Equal("/test"))
   516  	})
   517  
   518  	It("podman run with overlay volume flag", func() {
   519  		SkipIfRemote("Overlay volumes only work locally")
   520  		if os.Getenv("container") != "" {
   521  			Skip("Overlay mounts not supported when running in a container")
   522  		}
   523  		if rootless.IsRootless() {
   524  			if _, err := exec.LookPath("fuse_overlay"); err != nil {
   525  				Skip("Fuse-Overlayfs required for rootless overlay mount test")
   526  			}
   527  		}
   528  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   529  		os.Mkdir(mountPath, 0755)
   530  		testFile := filepath.Join(mountPath, "test1")
   531  		f, err := os.Create(testFile)
   532  		f.Close()
   533  
   534  		// Make sure host directory gets mounted in to container as overlay
   535  		session := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "grep", "/run/test", "/proc/self/mountinfo"})
   536  		session.WaitWithDefaultTimeout()
   537  		Expect(session).Should(Exit(0))
   538  		found, matches := session.GrepString("/run/test")
   539  		Expect(found).Should(BeTrue())
   540  		Expect(matches[0]).To(ContainSubstring("overlay"))
   541  
   542  		// Make sure host files show up in the container
   543  		session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "ls", "/run/test/test1"})
   544  		session.WaitWithDefaultTimeout()
   545  		Expect(session).Should(Exit(0))
   546  
   547  		// Make sure modifications in container do not show up on host
   548  		session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "touch", "/run/test/container"})
   549  		session.WaitWithDefaultTimeout()
   550  		Expect(session).Should(Exit(0))
   551  		_, err = os.Stat(filepath.Join(mountPath, "container"))
   552  		Expect(err).To(Not(BeNil()))
   553  
   554  		// Make sure modifications in container disappear when container is stopped
   555  		session = podmanTest.Podman([]string{"create", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "top"})
   556  		session.WaitWithDefaultTimeout()
   557  		Expect(session).Should(Exit(0))
   558  		session = podmanTest.Podman([]string{"start", "-l"})
   559  		session.WaitWithDefaultTimeout()
   560  		Expect(session).Should(Exit(0))
   561  		session = podmanTest.Podman([]string{"exec", "-l", "touch", "/run/test/container"})
   562  		session.WaitWithDefaultTimeout()
   563  		Expect(session).Should(Exit(0))
   564  		session = podmanTest.Podman([]string{"exec", "-l", "ls", "/run/test/container"})
   565  		session.WaitWithDefaultTimeout()
   566  		Expect(session).Should(Exit(0))
   567  		session = podmanTest.Podman([]string{"stop", "-l"})
   568  		session.WaitWithDefaultTimeout()
   569  		Expect(session).Should(Exit(0))
   570  		session = podmanTest.Podman([]string{"start", "-l"})
   571  		session.WaitWithDefaultTimeout()
   572  		Expect(session).Should(Exit(0))
   573  		session = podmanTest.Podman([]string{"exec", "-l", "ls", "/run/test/container"})
   574  		session.WaitWithDefaultTimeout()
   575  		Expect(session).To(ExitWithError())
   576  	})
   577  
   578  	It("overlay volume conflicts with named volume and mounts", func() {
   579  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   580  		os.Mkdir(mountPath, 0755)
   581  		testFile := filepath.Join(mountPath, "test1")
   582  		f, err := os.Create(testFile)
   583  		Expect(err).To(BeNil())
   584  		f.Close()
   585  		mountSrc := filepath.Join(podmanTest.TempDir, "vol-test1")
   586  		err = os.MkdirAll(mountSrc, 0755)
   587  		Expect(err).To(BeNil())
   588  		mountDest := "/run/test"
   589  		volName := "myvol"
   590  
   591  		session := podmanTest.Podman([]string{"volume", "create", volName})
   592  		session.WaitWithDefaultTimeout()
   593  		Expect(session).Should(Exit(0))
   594  
   595  		// overlay and named volume destinations conflict
   596  		session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:%s:O", mountPath, mountDest), "-v", fmt.Sprintf("%s:%s", volName, mountDest), ALPINE})
   597  		session.WaitWithDefaultTimeout()
   598  		Expect(session).To(ExitWithError())
   599  		// overlay and bind mount destinations conflict
   600  		session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:%s:O", mountPath, mountDest), "--mount", fmt.Sprintf("type=bind,src=%s,target=%s", mountSrc, mountDest), ALPINE})
   601  		session.WaitWithDefaultTimeout()
   602  		Expect(session).To(ExitWithError())
   603  		// overlay and tmpfs mount destinations conflict
   604  		session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:%s:O", mountPath, mountDest), "--mount", fmt.Sprintf("type=tmpfs,target=%s", mountDest), ALPINE})
   605  		session.WaitWithDefaultTimeout()
   606  		Expect(session).To(ExitWithError())
   607  	})
   608  
   609  	It("same volume in multiple places does not deadlock", func() {
   610  		volName := "testVol1"
   611  		session := podmanTest.Podman([]string{"run", "-t", "-i", "-v", fmt.Sprintf("%s:/test1", volName), "-v", fmt.Sprintf("%s:/test2", volName), "--rm", ALPINE, "sh", "-c", "mount | grep /test"})
   612  		session.WaitWithDefaultTimeout()
   613  		Expect(session).Should(Exit(0))
   614  		Expect(len(session.OutputToStringArray())).To(Equal(2))
   615  	})
   616  
   617  	It("podman run with U volume flag", func() {
   618  		SkipIfRemote("Overlay volumes only work locally")
   619  
   620  		u, err := user.Current()
   621  		Expect(err).To(BeNil())
   622  		name := u.Username
   623  		if name == "root" {
   624  			name = "containers"
   625  		}
   626  
   627  		content, err := ioutil.ReadFile("/etc/subuid")
   628  		if err != nil {
   629  			Skip("cannot read /etc/subuid")
   630  		}
   631  		if !strings.Contains(string(content), name) {
   632  			Skip("cannot find mappings for the current user")
   633  		}
   634  
   635  		if os.Getenv("container") != "" {
   636  			Skip("Overlay mounts not supported when running in a container")
   637  		}
   638  		if rootless.IsRootless() {
   639  			if _, err := exec.LookPath("fuse_overlay"); err != nil {
   640  				Skip("Fuse-Overlayfs required for rootless overlay mount test")
   641  			}
   642  		}
   643  
   644  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   645  		os.Mkdir(mountPath, 0755)
   646  		vol := mountPath + ":" + dest + ":U"
   647  
   648  		session := podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "-v", vol, ALPINE, "stat", "-c", "%u:%g", dest})
   649  		session.WaitWithDefaultTimeout()
   650  		Expect(session).Should(Exit(0))
   651  		found, _ := session.GrepString("888:888")
   652  		Expect(found).Should(BeTrue())
   653  
   654  		session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--userns", "auto", "-v", vol, ALPINE, "stat", "-c", "%u:%g", dest})
   655  		session.WaitWithDefaultTimeout()
   656  		Expect(session).Should(Exit(0))
   657  		found, _ = session.GrepString("888:888")
   658  		Expect(found).Should(BeTrue())
   659  
   660  		vol = vol + ",O"
   661  		session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--userns", "keep-id", "-v", vol, ALPINE, "stat", "-c", "%u:%g", dest})
   662  		session.WaitWithDefaultTimeout()
   663  		Expect(session).Should(Exit(0))
   664  		found, _ = session.GrepString("888:888")
   665  		Expect(found).Should(BeTrue())
   666  	})
   667  
   668  	It("volume permissions after run", func() {
   669  		imgName := "testimg"
   670  		dockerfile := fmt.Sprintf(`FROM %s
   671  RUN useradd -m testuser -u 1005
   672  USER testuser`, fedoraMinimal)
   673  		podmanTest.BuildImage(dockerfile, imgName, "false")
   674  
   675  		testString := "testuser testuser"
   676  
   677  		test1 := podmanTest.Podman([]string{"run", "-v", "testvol1:/test", imgName, "bash", "-c", "ls -al /test | grep -v root | grep -v total"})
   678  		test1.WaitWithDefaultTimeout()
   679  		Expect(test1).Should(Exit(0))
   680  		Expect(strings.Contains(test1.OutputToString(), testString)).To(BeTrue())
   681  
   682  		volName := "testvol2"
   683  		vol := podmanTest.Podman([]string{"volume", "create", volName})
   684  		vol.WaitWithDefaultTimeout()
   685  		Expect(vol).Should(Exit(0))
   686  
   687  		test2 := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/test", volName), imgName, "bash", "-c", "ls -al /test | grep -v root | grep -v total"})
   688  		test2.WaitWithDefaultTimeout()
   689  		Expect(test2).Should(Exit(0))
   690  		Expect(strings.Contains(test2.OutputToString(), testString)).To(BeTrue())
   691  
   692  	})
   693  
   694  	It("podman run with named volume check if we honor permission of target dir", func() {
   695  		session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "stat", "-c", "%a %Y", "/var/tmp"})
   696  		session.WaitWithDefaultTimeout()
   697  		Expect(session).Should(Exit(0))
   698  		perms := session.OutputToString()
   699  
   700  		session = podmanTest.Podman([]string{"run", "--rm", "-v", "test:/var/tmp", ALPINE, "stat", "-c", "%a %Y", "/var/tmp"})
   701  		session.WaitWithDefaultTimeout()
   702  		Expect(session).Should(Exit(0))
   703  		Expect(session.OutputToString()).To(Equal(perms))
   704  	})
   705  
   706  	It("podman volume with uid and gid works", func() {
   707  		volName := "testVol"
   708  		volCreate := podmanTest.Podman([]string{"volume", "create", "--opt", "o=uid=1000", volName})
   709  		volCreate.WaitWithDefaultTimeout()
   710  		Expect(volCreate).Should(Exit(0))
   711  
   712  		volMount := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "stat", "-c", "%u", "/test"})
   713  		volMount.WaitWithDefaultTimeout()
   714  		Expect(volMount).Should(Exit(0))
   715  		Expect(volMount.OutputToString()).To(Equal("1000"))
   716  
   717  		volName = "testVol2"
   718  		volCreate = podmanTest.Podman([]string{"volume", "create", "--opt", "o=gid=1000", volName})
   719  		volCreate.WaitWithDefaultTimeout()
   720  		Expect(volCreate).Should(Exit(0))
   721  
   722  		volMount = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "stat", "-c", "%g", "/test"})
   723  		volMount.WaitWithDefaultTimeout()
   724  		Expect(volMount).Should(Exit(0))
   725  		Expect(volMount.OutputToString()).To(Equal("1000"))
   726  
   727  		volName = "testVol3"
   728  		volCreate = podmanTest.Podman([]string{"volume", "create", "--opt", "o=uid=1000,gid=1000", volName})
   729  		volCreate.WaitWithDefaultTimeout()
   730  		Expect(volCreate).Should(Exit(0))
   731  
   732  		volMount = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "stat", "-c", "%u:%g", "/test"})
   733  		volMount.WaitWithDefaultTimeout()
   734  		Expect(volMount).Should(Exit(0))
   735  		Expect(volMount.OutputToString()).To(Equal("1000:1000"))
   736  	})
   737  })