github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/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/hanks177/podman/v4/pkg/rootless"
    13  	. "github.com/hanks177/podman/v4/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  	})
    38  
    39  	AfterEach(func() {
    40  		podmanTest.Cleanup()
    41  		f := CurrentGinkgoTestDescription()
    42  		processTestResult(f)
    43  	})
    44  
    45  	// Returns the /proc/self/mountinfo line for a given mount point
    46  	getMountInfo := func(volume string) []string {
    47  		containerDir := strings.SplitN(volume, ":", 3)[1]
    48  		session := podmanTest.Podman([]string{"run", "--rm", "-v", volume, ALPINE, "awk", fmt.Sprintf(`$5 == "%s" { print }`, containerDir), "/proc/self/mountinfo"})
    49  		session.WaitWithDefaultTimeout()
    50  		Expect(session).Should(Exit(0))
    51  		Expect(session.OutputToString()).To(ContainSubstring(containerDir), "mount point not found in /proc/self/mountinfo")
    52  		return strings.Fields(session.OutputToString())
    53  	}
    54  
    55  	It("podman run with volume flag", func() {
    56  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
    57  		err = os.Mkdir(mountPath, 0755)
    58  		Expect(err).ToNot(HaveOccurred())
    59  		vol := mountPath + ":" + dest
    60  
    61  		// [5] is flags
    62  		Expect(getMountInfo(vol)[5]).To(ContainSubstring("rw"))
    63  		Expect(getMountInfo(vol + ":ro")[5]).To(ContainSubstring("ro"))
    64  
    65  		mountinfo := getMountInfo(vol + ":shared")
    66  		Expect(mountinfo[5]).To(ContainSubstring("rw"))
    67  		Expect(mountinfo[6]).To(ContainSubstring("shared"))
    68  
    69  		// Cached is ignored
    70  		mountinfo = getMountInfo(vol + ":cached")
    71  		Expect(mountinfo[5]).To(ContainSubstring("rw"))
    72  		Expect(mountinfo).To(Not(ContainElement(ContainSubstring("cached"))))
    73  
    74  		// Delegated is ignored
    75  		mountinfo = getMountInfo(vol + ":delegated")
    76  		Expect(mountinfo[5]).To(ContainSubstring("rw"))
    77  		Expect(mountinfo).To(Not(ContainElement(ContainSubstring("delegated"))))
    78  	})
    79  
    80  	It("podman run with --mount flag", func() {
    81  		if podmanTest.Host.Arch == "ppc64le" {
    82  			Skip("skip failing test on ppc64le")
    83  		}
    84  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
    85  		err = os.Mkdir(mountPath, 0755)
    86  		Expect(err).ToNot(HaveOccurred())
    87  		mount := "type=bind,src=" + mountPath + ",target=" + dest
    88  
    89  		session := podmanTest.Podman([]string{"run", "--rm", "--mount", mount, ALPINE, "grep", dest, "/proc/self/mountinfo"})
    90  		session.WaitWithDefaultTimeout()
    91  		Expect(session).Should(Exit(0))
    92  		Expect(session.OutputToString()).To(ContainSubstring(dest + " rw"))
    93  
    94  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro", ALPINE, "grep", dest, "/proc/self/mountinfo"})
    95  		session.WaitWithDefaultTimeout()
    96  		Expect(session).Should(Exit(0))
    97  		Expect(session.OutputToString()).To(ContainSubstring(dest + " ro"))
    98  
    99  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",readonly", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   100  		session.WaitWithDefaultTimeout()
   101  		Expect(session).Should(Exit(0))
   102  		Expect(session.OutputToString()).To(ContainSubstring(dest + " ro"))
   103  
   104  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",consistency=delegated,shared", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   105  		session.WaitWithDefaultTimeout()
   106  		Expect(session).Should(Exit(0))
   107  		Expect(session.OutputToString()).To(ContainSubstring("rw"))
   108  		Expect(session.OutputToString()).To(ContainSubstring("shared"))
   109  
   110  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=" + dest, ALPINE, "grep", dest, "/proc/self/mountinfo"})
   111  		session.WaitWithDefaultTimeout()
   112  		Expect(session).Should(Exit(0))
   113  		Expect(session.OutputToString()).To(ContainSubstring(dest + " rw,nosuid,nodev,relatime - tmpfs"))
   114  
   115  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,tmpcopyup", ALPINE, "ls", "/etc/ssl"})
   116  		session.WaitWithDefaultTimeout()
   117  		Expect(session).Should(Exit(0))
   118  		Expect(session.OutputToString()).To(ContainSubstring("certs"))
   119  
   120  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,tmpcopyup,notmpcopyup", ALPINE, "ls", "/etc/ssl"})
   121  		session.WaitWithDefaultTimeout()
   122  		Expect(session).To(ExitWithError())
   123  
   124  		// test csv escaping
   125  		session = podmanTest.Podman([]string{"run", "--rm", "--mount=type=tmpfs,tmpfs-size=512M,\"destination=/test,\"", ALPINE, "ls", "/test,"})
   126  		session.WaitWithDefaultTimeout()
   127  		Expect(session).Should(Exit(0))
   128  
   129  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=bind,src=/tmp,target=/tmp,tmpcopyup", ALPINE, "true"})
   130  		session.WaitWithDefaultTimeout()
   131  		Expect(session).To(ExitWithError())
   132  
   133  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=bind,src=/tmp,target=/tmp,notmpcopyup", ALPINE, "true"})
   134  		session.WaitWithDefaultTimeout()
   135  		Expect(session).To(ExitWithError())
   136  
   137  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,notmpcopyup", ALPINE, "ls", "/etc/ssl"})
   138  		session.WaitWithDefaultTimeout()
   139  		Expect(session).Should(Exit(0))
   140  		Expect(session.OutputToString()).To(Not(ContainSubstring("certs")))
   141  	})
   142  
   143  	It("podman run with conflicting volumes errors", func() {
   144  		mountPath := filepath.Join(podmanTest.TmpDir, "secrets")
   145  		err := os.Mkdir(mountPath, 0755)
   146  		Expect(err).ToNot(HaveOccurred())
   147  		session := podmanTest.Podman([]string{"run", "-v", mountPath + ":" + dest, "-v", "/tmp" + ":" + dest, ALPINE, "ls"})
   148  		session.WaitWithDefaultTimeout()
   149  		Expect(session).Should(Exit(125))
   150  	})
   151  
   152  	It("podman run with conflict between image volume and user mount succeeds", func() {
   153  		err = podmanTest.RestoreArtifact(redis)
   154  		Expect(err).ToNot(HaveOccurred())
   155  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   156  		err := os.Mkdir(mountPath, 0755)
   157  		Expect(err).To(BeNil())
   158  		testFile := filepath.Join(mountPath, "test1")
   159  		f, err := os.Create(testFile)
   160  		Expect(err).To(BeNil(), "os.Create(testfile)")
   161  		f.Close()
   162  		Expect(err).To(BeNil())
   163  		session := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/data", mountPath), redis, "ls", "/data/test1"})
   164  		session.WaitWithDefaultTimeout()
   165  		Expect(session).Should(Exit(0))
   166  	})
   167  
   168  	It("podman run with mount flag and boolean options", func() {
   169  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   170  		err := os.Mkdir(mountPath, 0755)
   171  		Expect(err).ToNot(HaveOccurred())
   172  		mount := "type=bind,src=" + mountPath + ",target=" + dest
   173  
   174  		session := podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro=false", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   175  		session.WaitWithDefaultTimeout()
   176  		Expect(session).Should(Exit(0))
   177  		Expect(session.OutputToString()).To(ContainSubstring(dest + " rw"))
   178  
   179  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro=true", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   180  		session.WaitWithDefaultTimeout()
   181  		Expect(session).Should(Exit(0))
   182  		Expect(session.OutputToString()).To(ContainSubstring(dest + " ro"))
   183  
   184  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro=true,rw=false", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   185  		session.WaitWithDefaultTimeout()
   186  		Expect(session).To(ExitWithError())
   187  	})
   188  
   189  	It("podman run with volume flag and multiple named volumes", func() {
   190  		session := podmanTest.Podman([]string{"run", "--rm", "-v", "testvol1:/testvol1", "-v", "testvol2:/testvol2", ALPINE, "grep", "/testvol", "/proc/self/mountinfo"})
   191  		session.WaitWithDefaultTimeout()
   192  		Expect(session).Should(Exit(0))
   193  		Expect(session.OutputToString()).To(ContainSubstring("/testvol1"))
   194  		Expect(session.OutputToString()).To(ContainSubstring("/testvol2"))
   195  	})
   196  
   197  	It("podman run with volumes and suid/dev/exec options", func() {
   198  		SkipIfRemote("podman-remote does not support --volumes")
   199  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   200  		err := os.Mkdir(mountPath, 0755)
   201  		Expect(err).ToNot(HaveOccurred())
   202  
   203  		session := podmanTest.Podman([]string{"run", "--rm", "-v", mountPath + ":" + dest + ":suid,dev,exec", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   204  		session.WaitWithDefaultTimeout()
   205  		Expect(session).Should(Exit(0))
   206  		output := session.OutputToString()
   207  		Expect(output).To(Not(ContainSubstring("noexec")))
   208  		Expect(output).To(Not(ContainSubstring("nodev")))
   209  		Expect(output).To(Not(ContainSubstring("nosuid")))
   210  
   211  		session = podmanTest.Podman([]string{"run", "--rm", "--tmpfs", dest + ":suid,dev,exec", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   212  		session.WaitWithDefaultTimeout()
   213  		Expect(session).Should(Exit(0))
   214  		output = session.OutputToString()
   215  		Expect(output).To(Not(ContainSubstring("noexec")))
   216  		Expect(output).To(Not(ContainSubstring("nodev")))
   217  		Expect(output).To(Not(ContainSubstring("nosuid")))
   218  	})
   219  
   220  	// Container should start when workdir is overlay volume
   221  	It("podman run with volume mounted as overlay and used as workdir", func() {
   222  		SkipIfRemote("Overlay volumes only work locally")
   223  		if os.Getenv("container") != "" {
   224  			Skip("Overlay mounts not supported when running in a container")
   225  		}
   226  		if rootless.IsRootless() {
   227  			if _, err := exec.LookPath("fuse-overlayfs"); err != nil {
   228  				Skip("Fuse-Overlayfs required for rootless overlay mount test")
   229  			}
   230  		}
   231  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   232  		err := os.Mkdir(mountPath, 0755)
   233  		Expect(err).ToNot(HaveOccurred())
   234  
   235  		// Container should be able to start with custom overlay volume
   236  		session := podmanTest.Podman([]string{"run", "--rm", "-v", mountPath + ":/data:O", "--workdir=/data", ALPINE, "echo", "hello"})
   237  		session.WaitWithDefaultTimeout()
   238  		Expect(session).Should(Exit(0))
   239  	})
   240  
   241  	It("podman support overlay on named volume", func() {
   242  		SkipIfRemote("Overlay volumes only work locally")
   243  		if os.Getenv("container") != "" {
   244  			Skip("Overlay mounts not supported when running in a container")
   245  		}
   246  		if rootless.IsRootless() {
   247  			if _, err := exec.LookPath("fuse-overlayfs"); err != nil {
   248  				Skip("Fuse-Overlayfs required for rootless overlay mount test")
   249  			}
   250  		}
   251  		session := podmanTest.Podman([]string{"volume", "create", "myvolume"})
   252  		session.WaitWithDefaultTimeout()
   253  		volName := session.OutputToString()
   254  		Expect(session).Should(Exit(0))
   255  
   256  		// create file on actual volume
   257  		session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data", ALPINE, "sh", "-c", "echo hello >> " + "/data/test"})
   258  		session.WaitWithDefaultTimeout()
   259  		Expect(session).Should(Exit(0))
   260  
   261  		// create file on overlay volume
   262  		session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data:O", ALPINE, "sh", "-c", "echo hello >> " + "/data/overlay"})
   263  		session.WaitWithDefaultTimeout()
   264  		Expect(session).Should(Exit(0))
   265  
   266  		// volume should contain only `test` not `overlay`
   267  		session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data", ALPINE, "sh", "-c", "ls /data"})
   268  		session.WaitWithDefaultTimeout()
   269  		Expect(session.OutputToString()).To(Not(ContainSubstring("overlay")))
   270  		Expect(session.OutputToString()).To(ContainSubstring("test"))
   271  
   272  	})
   273  
   274  	It("podman support overlay on named volume with custom upperdir and workdir", func() {
   275  		SkipIfRemote("Overlay volumes only work locally")
   276  		if os.Getenv("container") != "" {
   277  			Skip("Overlay mounts not supported when running in a container")
   278  		}
   279  		if rootless.IsRootless() {
   280  			if _, err := exec.LookPath("fuse-overlayfs"); err != nil {
   281  				Skip("Fuse-Overlayfs required for rootless overlay mount test")
   282  			}
   283  		}
   284  
   285  		// create persistent upperdir on host
   286  		upperDir := filepath.Join(tempdir, "upper")
   287  		err := os.Mkdir(upperDir, 0755)
   288  		Expect(err).To(BeNil(), "mkdir "+upperDir)
   289  
   290  		// create persistent workdir on host
   291  		workDir := filepath.Join(tempdir, "work")
   292  		err = os.Mkdir(workDir, 0755)
   293  		Expect(err).To(BeNil(), "mkdir "+workDir)
   294  
   295  		overlayOpts := fmt.Sprintf("upperdir=%s,workdir=%s", upperDir, workDir)
   296  
   297  		session := podmanTest.Podman([]string{"volume", "create", "myvolume"})
   298  		session.WaitWithDefaultTimeout()
   299  		volName := session.OutputToString()
   300  		Expect(session).Should(Exit(0))
   301  
   302  		// create file on actual volume
   303  		session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data", ALPINE, "sh", "-c", "echo hello >> " + "/data/test"})
   304  		session.WaitWithDefaultTimeout()
   305  		Expect(session).Should(Exit(0))
   306  
   307  		// create file on overlay volume
   308  		session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data:O," + overlayOpts, ALPINE, "sh", "-c", "echo hello >> " + "/data/overlay"})
   309  		session.WaitWithDefaultTimeout()
   310  		Expect(session).Should(Exit(0))
   311  
   312  		session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data:O," + overlayOpts, ALPINE, "sh", "-c", "ls /data"})
   313  		session.WaitWithDefaultTimeout()
   314  		// must contain `overlay` file since it should be persistent on specified upper and workdir
   315  		Expect(session.OutputToString()).To(ContainSubstring("overlay"))
   316  		// this should be there since `test` was written on actual volume not on any overlay
   317  		Expect(session.OutputToString()).To(ContainSubstring("test"))
   318  
   319  		session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data:O", ALPINE, "sh", "-c", "ls /data"})
   320  		session.WaitWithDefaultTimeout()
   321  		// must not contain `overlay` file which was on custom upper and workdir since we have not specified any upper or workdir
   322  		Expect(session.OutputToString()).To(Not(ContainSubstring("overlay")))
   323  		// this should be there since `test` was written on actual volume not on any overlay
   324  		Expect(session.OutputToString()).To(ContainSubstring("test"))
   325  
   326  	})
   327  
   328  	It("podman support overlay volume with custom upperdir and workdir", func() {
   329  		SkipIfRemote("Overlay volumes only work locally")
   330  		if os.Getenv("container") != "" {
   331  			Skip("Overlay mounts not supported when running in a container")
   332  		}
   333  		if rootless.IsRootless() {
   334  			if _, err := exec.LookPath("fuse-overlayfs"); err != nil {
   335  				Skip("Fuse-Overlayfs required for rootless overlay mount test")
   336  			}
   337  		}
   338  
   339  		// Use bindsource instead of named volume
   340  		bindSource := filepath.Join(tempdir, "bindsource")
   341  		err := os.Mkdir(bindSource, 0755)
   342  		Expect(err).To(BeNil(), "mkdir "+bindSource)
   343  
   344  		// create persistent upperdir on host
   345  		upperDir := filepath.Join(tempdir, "upper")
   346  		err = os.Mkdir(upperDir, 0755)
   347  		Expect(err).To(BeNil(), "mkdir "+upperDir)
   348  
   349  		// create persistent workdir on host
   350  		workDir := filepath.Join(tempdir, "work")
   351  		err = os.Mkdir(workDir, 0755)
   352  		Expect(err).To(BeNil(), "mkdir "+workDir)
   353  
   354  		overlayOpts := fmt.Sprintf("upperdir=%s,workdir=%s", upperDir, workDir)
   355  
   356  		// create file on overlay volume
   357  		session := podmanTest.Podman([]string{"run", "--volume", bindSource + ":/data:O," + overlayOpts, ALPINE, "sh", "-c", "echo hello >> " + "/data/overlay"})
   358  		session.WaitWithDefaultTimeout()
   359  		Expect(session).Should(Exit(0))
   360  
   361  		session = podmanTest.Podman([]string{"run", "--volume", bindSource + ":/data:O," + overlayOpts, ALPINE, "sh", "-c", "ls /data"})
   362  		session.WaitWithDefaultTimeout()
   363  		// must contain `overlay` file since it should be persistent on specified upper and workdir
   364  		Expect(session.OutputToString()).To(ContainSubstring("overlay"))
   365  
   366  		session = podmanTest.Podman([]string{"run", "--volume", bindSource + ":/data:O", ALPINE, "sh", "-c", "ls /data"})
   367  		session.WaitWithDefaultTimeout()
   368  		// must not contain `overlay` file which was on custom upper and workdir since we have not specified any upper or workdir
   369  		Expect(session.OutputToString()).To(Not(ContainSubstring("overlay")))
   370  
   371  	})
   372  
   373  	It("podman run with noexec can't exec", func() {
   374  		session := podmanTest.Podman([]string{"run", "--rm", "-v", "/bin:/hostbin:noexec", ALPINE, "/hostbin/ls", "/"})
   375  		session.WaitWithDefaultTimeout()
   376  		Expect(session).To(ExitWithError())
   377  	})
   378  
   379  	It("podman run with tmpfs named volume mounts and unmounts", func() {
   380  		SkipIfRootless("rootless podman mount requires you to be in a user namespace")
   381  		SkipIfRemote("podman-remote does not support --volumes. This test could be simplified to be tested on Remote.")
   382  		volName := "testvol"
   383  		mkVolume := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=nodev", "testvol"})
   384  		mkVolume.WaitWithDefaultTimeout()
   385  		Expect(mkVolume).Should(Exit(0))
   386  
   387  		// Volume not mounted on create
   388  		mountCmd1, err := Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
   389  		Expect(err).To(BeNil())
   390  		mountCmd1.Wait(90)
   391  		Expect(mountCmd1).Should(Exit(0))
   392  		os.Stdout.Sync()
   393  		os.Stderr.Sync()
   394  		mountOut1 := strings.Join(strings.Fields(string(mountCmd1.Out.Contents())), " ")
   395  		fmt.Printf("Output: %s", mountOut1)
   396  		Expect(mountOut1).To(Not(ContainSubstring(volName)))
   397  
   398  		ctrName := "testctr"
   399  		podmanSession := podmanTest.Podman([]string{"run", "-d", "--name", ctrName, "-v", fmt.Sprintf("%s:/testvol", volName), ALPINE, "top"})
   400  		podmanSession.WaitWithDefaultTimeout()
   401  		Expect(podmanSession).Should(Exit(0))
   402  
   403  		// Volume now mounted as container is running
   404  		mountCmd2, err := Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
   405  		Expect(err).To(BeNil())
   406  		mountCmd2.Wait(90)
   407  		Expect(mountCmd2).Should(Exit(0))
   408  		os.Stdout.Sync()
   409  		os.Stderr.Sync()
   410  		mountOut2 := strings.Join(strings.Fields(string(mountCmd2.Out.Contents())), " ")
   411  		fmt.Printf("Output: %s", mountOut2)
   412  		Expect(mountOut2).To(ContainSubstring(volName))
   413  
   414  		// Stop the container to unmount
   415  		podmanStopSession := podmanTest.Podman([]string{"stop", "--time", "0", ctrName})
   416  		podmanStopSession.WaitWithDefaultTimeout()
   417  		Expect(podmanStopSession).Should(Exit(0))
   418  
   419  		// We have to force cleanup so the unmount happens
   420  		podmanCleanupSession := podmanTest.Podman([]string{"container", "cleanup", ctrName})
   421  		podmanCleanupSession.WaitWithDefaultTimeout()
   422  		Expect(podmanCleanupSession).Should(Exit(0))
   423  
   424  		// Ensure volume is unmounted
   425  		mountCmd3, err := Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
   426  		Expect(err).To(BeNil())
   427  		mountCmd3.Wait(90)
   428  		Expect(mountCmd3).Should(Exit(0))
   429  		os.Stdout.Sync()
   430  		os.Stderr.Sync()
   431  		mountOut3 := strings.Join(strings.Fields(string(mountCmd3.Out.Contents())), " ")
   432  		fmt.Printf("Output: %s", mountOut3)
   433  		Expect(mountOut3).To(Not(ContainSubstring(volName)))
   434  	})
   435  
   436  	It("podman named volume copyup", func() {
   437  		baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", ALPINE, "ls", "/etc/apk/"})
   438  		baselineSession.WaitWithDefaultTimeout()
   439  		Expect(baselineSession).Should(Exit(0))
   440  		baselineOutput := baselineSession.OutputToString()
   441  
   442  		inlineVolumeSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "-v", "testvol1:/etc/apk", ALPINE, "ls", "/etc/apk/"})
   443  		inlineVolumeSession.WaitWithDefaultTimeout()
   444  		Expect(inlineVolumeSession).Should(Exit(0))
   445  		Expect(inlineVolumeSession.OutputToString()).To(Equal(baselineOutput))
   446  
   447  		makeVolumeSession := podmanTest.Podman([]string{"volume", "create", "testvol2"})
   448  		makeVolumeSession.WaitWithDefaultTimeout()
   449  		Expect(makeVolumeSession).Should(Exit(0))
   450  
   451  		separateVolumeSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "-v", "testvol2:/etc/apk", ALPINE, "ls", "/etc/apk/"})
   452  		separateVolumeSession.WaitWithDefaultTimeout()
   453  		Expect(separateVolumeSession).Should(Exit(0))
   454  		Expect(separateVolumeSession.OutputToString()).To(Equal(baselineOutput))
   455  	})
   456  
   457  	It("podman named volume copyup symlink", func() {
   458  		imgName := "testimg"
   459  		dockerfile := fmt.Sprintf(`FROM %s
   460  RUN touch /testfile
   461  RUN sh -c "cd /etc/apk && ln -s ../../testfile"`, ALPINE)
   462  		podmanTest.BuildImage(dockerfile, imgName, "false")
   463  
   464  		baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", imgName, "ls", "/etc/apk/"})
   465  		baselineSession.WaitWithDefaultTimeout()
   466  		Expect(baselineSession).Should(Exit(0))
   467  		baselineOutput := baselineSession.OutputToString()
   468  
   469  		outputSession := podmanTest.Podman([]string{"run", "-t", "-i", "-v", "/etc/apk/", imgName, "ls", "/etc/apk/"})
   470  		outputSession.WaitWithDefaultTimeout()
   471  		Expect(outputSession).Should(Exit(0))
   472  		Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
   473  	})
   474  
   475  	It("podman named volume copyup empty directory", func() {
   476  		baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", ALPINE, "ls", "/srv"})
   477  		baselineSession.WaitWithDefaultTimeout()
   478  		Expect(baselineSession).Should(Exit(0))
   479  		baselineOutput := baselineSession.OutputToString()
   480  
   481  		outputSession := podmanTest.Podman([]string{"run", "-t", "-i", "-v", "/srv", ALPINE, "ls", "/srv"})
   482  		outputSession.WaitWithDefaultTimeout()
   483  		Expect(outputSession).Should(Exit(0))
   484  		Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
   485  	})
   486  
   487  	It("podman named volume copyup of /var", func() {
   488  		baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", fedoraMinimal, "ls", "/var"})
   489  		baselineSession.WaitWithDefaultTimeout()
   490  		Expect(baselineSession).Should(Exit(0))
   491  		baselineOutput := baselineSession.OutputToString()
   492  
   493  		outputSession := podmanTest.Podman([]string{"run", "-t", "-i", "-v", "/var", fedoraMinimal, "ls", "/var"})
   494  		outputSession.WaitWithDefaultTimeout()
   495  		Expect(outputSession).Should(Exit(0))
   496  		Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
   497  	})
   498  
   499  	It("podman read-only tmpfs conflict with volume", func() {
   500  		session := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "--read-only", "-v", "tmp_volume:" + dest, ALPINE, "touch", dest + "/a"})
   501  		session.WaitWithDefaultTimeout()
   502  		Expect(session).Should(Exit(0))
   503  
   504  		session2 := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "--read-only", "--tmpfs", dest, ALPINE, "touch", dest + "/a"})
   505  		session2.WaitWithDefaultTimeout()
   506  		Expect(session2).Should(Exit(0))
   507  	})
   508  
   509  	It("podman run with anonymous volume", func() {
   510  		list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   511  		list1.WaitWithDefaultTimeout()
   512  		Expect(list1).Should(Exit(0))
   513  		Expect(list1.OutputToString()).To(Equal(""))
   514  
   515  		session := podmanTest.Podman([]string{"create", "-v", "/test", ALPINE, "top"})
   516  		session.WaitWithDefaultTimeout()
   517  		Expect(session).Should(Exit(0))
   518  
   519  		list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   520  		list2.WaitWithDefaultTimeout()
   521  		Expect(list2).Should(Exit(0))
   522  		arr := list2.OutputToStringArray()
   523  		Expect(arr).To(HaveLen(1))
   524  		Expect(arr[0]).To(Not(Equal("")))
   525  	})
   526  
   527  	It("podman rm -v removes anonymous volume", func() {
   528  		list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   529  		list1.WaitWithDefaultTimeout()
   530  		Expect(list1).Should(Exit(0))
   531  		Expect(list1.OutputToString()).To(Equal(""))
   532  
   533  		ctrName := "testctr"
   534  		session := podmanTest.Podman([]string{"create", "--name", ctrName, "-v", "/test", ALPINE, "top"})
   535  		session.WaitWithDefaultTimeout()
   536  		Expect(session).Should(Exit(0))
   537  
   538  		list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   539  		list2.WaitWithDefaultTimeout()
   540  		Expect(list2).Should(Exit(0))
   541  		arr := list2.OutputToStringArray()
   542  		Expect(arr).To(HaveLen(1))
   543  		Expect(arr[0]).To(Not(Equal("")))
   544  
   545  		remove := podmanTest.Podman([]string{"rm", "-v", ctrName})
   546  		remove.WaitWithDefaultTimeout()
   547  		Expect(remove).Should(Exit(0))
   548  
   549  		list3 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   550  		list3.WaitWithDefaultTimeout()
   551  		Expect(list3).Should(Exit(0))
   552  		Expect(list3.OutputToString()).To(Equal(""))
   553  	})
   554  
   555  	It("podman rm -v retains named volume", func() {
   556  		list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   557  		list1.WaitWithDefaultTimeout()
   558  		Expect(list1).Should(Exit(0))
   559  		Expect(list1.OutputToString()).To(Equal(""))
   560  
   561  		ctrName := "testctr"
   562  		volName := "testvol"
   563  		session := podmanTest.Podman([]string{"create", "--name", ctrName, "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "top"})
   564  		session.WaitWithDefaultTimeout()
   565  		Expect(session).Should(Exit(0))
   566  
   567  		list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   568  		list2.WaitWithDefaultTimeout()
   569  		Expect(list2).Should(Exit(0))
   570  		arr := list2.OutputToStringArray()
   571  		Expect(arr).To(HaveLen(1))
   572  		Expect(arr[0]).To(Equal(volName))
   573  
   574  		remove := podmanTest.Podman([]string{"rm", "-v", ctrName})
   575  		remove.WaitWithDefaultTimeout()
   576  		Expect(remove).Should(Exit(0))
   577  
   578  		list3 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   579  		list3.WaitWithDefaultTimeout()
   580  		Expect(list3).Should(Exit(0))
   581  		arr2 := list3.OutputToStringArray()
   582  		Expect(arr2).To(HaveLen(1))
   583  		Expect(arr2[0]).To(Equal(volName))
   584  	})
   585  
   586  	It("podman run image volume is not noexec", func() {
   587  		session := podmanTest.Podman([]string{"run", "--rm", redis, "grep", "/data", "/proc/self/mountinfo"})
   588  		session.WaitWithDefaultTimeout()
   589  		Expect(session).Should(Exit(0))
   590  		Expect(session.OutputToString()).To(Not(ContainSubstring("noexec")))
   591  	})
   592  
   593  	It("podman mount with invalid option fails", func() {
   594  		volName := "testVol"
   595  		volCreate := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=invalid", volName})
   596  		volCreate.WaitWithDefaultTimeout()
   597  		Expect(volCreate).Should(Exit(0))
   598  
   599  		volMount := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/tmp", volName), ALPINE, "ls"})
   600  		volMount.WaitWithDefaultTimeout()
   601  		Expect(volMount).To(ExitWithError())
   602  	})
   603  
   604  	It("Podman fix for CVE-2020-1726", func() {
   605  		volName := "testVol"
   606  		volCreate := podmanTest.Podman([]string{"volume", "create", volName})
   607  		volCreate.WaitWithDefaultTimeout()
   608  		Expect(volCreate).Should(Exit(0))
   609  
   610  		volPath := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{.Mountpoint}}", volName})
   611  		volPath.WaitWithDefaultTimeout()
   612  		Expect(volPath).Should(Exit(0))
   613  		path := volPath.OutputToString()
   614  
   615  		fileName := "thisIsATestFile"
   616  		file, err := os.Create(filepath.Join(path, fileName))
   617  		Expect(err).To(BeNil())
   618  		defer file.Close()
   619  
   620  		runLs := podmanTest.Podman([]string{"run", "-t", "-i", "--rm", "-v", fmt.Sprintf("%v:/etc/ssl", volName), ALPINE, "ls", "-1", "/etc/ssl"})
   621  		runLs.WaitWithDefaultTimeout()
   622  		Expect(runLs).Should(Exit(0))
   623  		outputArr := runLs.OutputToStringArray()
   624  		Expect(outputArr).To(HaveLen(1))
   625  		Expect(outputArr[0]).To(ContainSubstring(fileName))
   626  	})
   627  
   628  	It("Podman mount over image volume with trailing /", func() {
   629  		image := "podman-volume-test:trailing"
   630  		dockerfile := fmt.Sprintf(`FROM %s
   631  VOLUME /test/`, ALPINE)
   632  		podmanTest.BuildImage(dockerfile, image, "false")
   633  
   634  		ctrName := "testCtr"
   635  		create := podmanTest.Podman([]string{"create", "-v", "/tmp:/test", "--name", ctrName, image, "ls"})
   636  		create.WaitWithDefaultTimeout()
   637  		Expect(create).Should(Exit(0))
   638  
   639  		data := podmanTest.InspectContainer(ctrName)
   640  		Expect(data).To(HaveLen(1))
   641  		Expect(data[0].Mounts).To(HaveLen(1))
   642  		Expect(data[0].Mounts[0]).To(HaveField("Source", "/tmp"))
   643  		Expect(data[0].Mounts[0]).To(HaveField("Destination", "/test"))
   644  	})
   645  
   646  	It("podman run with overlay volume flag", func() {
   647  		SkipIfRemote("Overlay volumes only work locally")
   648  		if os.Getenv("container") != "" {
   649  			Skip("Overlay mounts not supported when running in a container")
   650  		}
   651  		if rootless.IsRootless() {
   652  			if _, err := exec.LookPath("fuse-overlayfs"); err != nil {
   653  				Skip("Fuse-Overlayfs required for rootless overlay mount test")
   654  			}
   655  		}
   656  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   657  		err := os.Mkdir(mountPath, 0755)
   658  		Expect(err).ToNot(HaveOccurred())
   659  		testFile := filepath.Join(mountPath, "test1")
   660  		f, err := os.Create(testFile)
   661  		Expect(err).To(BeNil(), "os.Create "+testFile)
   662  		f.Close()
   663  
   664  		// Make sure host directory gets mounted in to container as overlay
   665  		volumeFlag := fmt.Sprintf("%s:/run/test:O", mountPath)
   666  		Expect(getMountInfo(volumeFlag)[7]).To(Equal("overlay"))
   667  
   668  		// Make sure host files show up in the container
   669  		session := podmanTest.Podman([]string{"run", "--rm", "-v", volumeFlag, ALPINE, "ls", "/run/test/test1"})
   670  		session.WaitWithDefaultTimeout()
   671  		Expect(session).Should(Exit(0))
   672  
   673  		// Make sure modifications in container do not show up on host
   674  		session = podmanTest.Podman([]string{"run", "--rm", "-v", volumeFlag, ALPINE, "touch", "/run/test/container"})
   675  		session.WaitWithDefaultTimeout()
   676  		Expect(session).Should(Exit(0))
   677  		_, err = os.Stat(filepath.Join(mountPath, "container"))
   678  		Expect(err).To(Not(BeNil()))
   679  
   680  		// Make sure modifications in container disappear when container is stopped
   681  		session = podmanTest.Podman([]string{"create", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "top"})
   682  		session.WaitWithDefaultTimeout()
   683  		Expect(session).Should(Exit(0))
   684  		session = podmanTest.Podman([]string{"start", "-l"})
   685  		session.WaitWithDefaultTimeout()
   686  		Expect(session).Should(Exit(0))
   687  		session = podmanTest.Podman([]string{"exec", "-l", "touch", "/run/test/container"})
   688  		session.WaitWithDefaultTimeout()
   689  		Expect(session).Should(Exit(0))
   690  		session = podmanTest.Podman([]string{"exec", "-l", "ls", "/run/test/container"})
   691  		session.WaitWithDefaultTimeout()
   692  		Expect(session).Should(Exit(0))
   693  		session = podmanTest.Podman([]string{"stop", "-l"})
   694  		session.WaitWithDefaultTimeout()
   695  		Expect(session).Should(Exit(0))
   696  		session = podmanTest.Podman([]string{"start", "-l"})
   697  		session.WaitWithDefaultTimeout()
   698  		Expect(session).Should(Exit(0))
   699  		session = podmanTest.Podman([]string{"exec", "-l", "ls", "/run/test/container"})
   700  		session.WaitWithDefaultTimeout()
   701  		Expect(session).To(ExitWithError())
   702  	})
   703  
   704  	It("overlay volume conflicts with named volume and mounts", func() {
   705  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   706  		err := os.Mkdir(mountPath, 0755)
   707  		Expect(err).ToNot(HaveOccurred())
   708  		testFile := filepath.Join(mountPath, "test1")
   709  		f, err := os.Create(testFile)
   710  		Expect(err).To(BeNil())
   711  		f.Close()
   712  		mountSrc := filepath.Join(podmanTest.TempDir, "vol-test1")
   713  		err = os.MkdirAll(mountSrc, 0755)
   714  		Expect(err).To(BeNil())
   715  		mountDest := "/run/test"
   716  		volName := "myvol"
   717  
   718  		session := podmanTest.Podman([]string{"volume", "create", volName})
   719  		session.WaitWithDefaultTimeout()
   720  		Expect(session).Should(Exit(0))
   721  
   722  		// overlay and named volume destinations conflict
   723  		session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:%s:O", mountPath, mountDest), "-v", fmt.Sprintf("%s:%s", volName, mountDest), ALPINE})
   724  		session.WaitWithDefaultTimeout()
   725  		Expect(session).To(ExitWithError())
   726  		// overlay and bind mount destinations conflict
   727  		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})
   728  		session.WaitWithDefaultTimeout()
   729  		Expect(session).To(ExitWithError())
   730  		// overlay and tmpfs mount destinations conflict
   731  		session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:%s:O", mountPath, mountDest), "--mount", fmt.Sprintf("type=tmpfs,target=%s", mountDest), ALPINE})
   732  		session.WaitWithDefaultTimeout()
   733  		Expect(session).To(ExitWithError())
   734  	})
   735  
   736  	It("same volume in multiple places does not deadlock", func() {
   737  		volName := "testVol1"
   738  		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"})
   739  		session.WaitWithDefaultTimeout()
   740  		Expect(session).Should(Exit(0))
   741  		Expect(session.OutputToStringArray()).To(HaveLen(2))
   742  	})
   743  
   744  	It("podman run with --volume and U flag", func() {
   745  		SkipIfRemote("Overlay volumes only work locally")
   746  
   747  		u, err := user.Current()
   748  		Expect(err).To(BeNil())
   749  		name := u.Username
   750  		if name == "root" {
   751  			name = "containers"
   752  		}
   753  
   754  		content, err := ioutil.ReadFile("/etc/subuid")
   755  		if err != nil {
   756  			Skip("cannot read /etc/subuid")
   757  		}
   758  		if !strings.Contains(string(content), name) {
   759  			Skip("cannot find mappings for the current user")
   760  		}
   761  
   762  		if os.Getenv("container") != "" {
   763  			Skip("Overlay mounts not supported when running in a container")
   764  		}
   765  		if rootless.IsRootless() {
   766  			if _, err := exec.LookPath("fuse_overlay"); err != nil {
   767  				Skip("Fuse-Overlayfs required for rootless overlay mount test")
   768  			}
   769  		}
   770  
   771  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   772  		err = os.Mkdir(mountPath, 0755)
   773  		Expect(err).ToNot(HaveOccurred())
   774  		vol := mountPath + ":" + dest + ":U"
   775  
   776  		session := podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "-v", vol, ALPINE, "stat", "-c", "%u:%g", dest})
   777  		session.WaitWithDefaultTimeout()
   778  		Expect(session).Should(Exit(0))
   779  		Expect(session.OutputToString()).To(ContainSubstring("888:888"))
   780  
   781  		session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--userns", "auto", "-v", vol, ALPINE, "stat", "-c", "%u:%g", dest})
   782  		session.WaitWithDefaultTimeout()
   783  		Expect(session).Should(Exit(0))
   784  		Expect(session.OutputToString()).To(ContainSubstring("888:888"))
   785  
   786  		vol += ",O"
   787  		session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--userns", "keep-id", "-v", vol, ALPINE, "stat", "-c", "%u:%g", dest})
   788  		session.WaitWithDefaultTimeout()
   789  		Expect(session).Should(Exit(0))
   790  		Expect(session.OutputToString()).To(ContainSubstring("888:888"))
   791  	})
   792  
   793  	It("podman run with --mount and U flag", func() {
   794  		u, err := user.Current()
   795  		Expect(err).To(BeNil())
   796  		name := u.Username
   797  		if name == "root" {
   798  			name = "containers"
   799  		}
   800  
   801  		content, err := ioutil.ReadFile("/etc/subuid")
   802  		if err != nil {
   803  			Skip("cannot read /etc/subuid")
   804  		}
   805  
   806  		if !strings.Contains(string(content), name) {
   807  			Skip("cannot find mappings for the current user")
   808  		}
   809  
   810  		mountPath := filepath.Join(podmanTest.TempDir, "foo")
   811  		err = os.Mkdir(mountPath, 0755)
   812  		Expect(err).ToNot(HaveOccurred())
   813  
   814  		// false bind mount
   815  		vol := "type=bind,src=" + mountPath + ",dst=" + dest + ",U=false"
   816  		session := podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest})
   817  		session.WaitWithDefaultTimeout()
   818  		Expect(session).Should(Exit(0))
   819  		Expect(session.OutputToString()).ShouldNot(Equal("888:888"))
   820  
   821  		// invalid bind mount
   822  		vol = "type=bind,src=" + mountPath + ",dst=" + dest + ",U=invalid"
   823  		session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest})
   824  		session.WaitWithDefaultTimeout()
   825  		Expect(session).To(ExitWithError())
   826  
   827  		// true bind mount
   828  		vol = "type=bind,src=" + mountPath + ",dst=" + dest + ",U=true"
   829  		session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest})
   830  		session.WaitWithDefaultTimeout()
   831  		Expect(session).Should(Exit(0))
   832  		Expect(session.OutputToString()).Should(Equal("888:888"))
   833  
   834  		// tmpfs mount
   835  		vol = "type=tmpfs," + "dst=" + dest + ",chown"
   836  		session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest})
   837  		session.WaitWithDefaultTimeout()
   838  		Expect(session).Should(Exit(0))
   839  		Expect(session.OutputToString()).Should(Equal("888:888"))
   840  
   841  		// anonymous volume mount
   842  		vol = "type=volume," + "dst=" + dest
   843  		session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest})
   844  		session.WaitWithDefaultTimeout()
   845  		Expect(session).Should(Exit(0))
   846  		Expect(session.OutputToString()).Should(Equal("888:888"))
   847  
   848  		// named volume mount
   849  		namedVolume := podmanTest.Podman([]string{"volume", "create", "foo"})
   850  		namedVolume.WaitWithDefaultTimeout()
   851  		Expect(namedVolume).Should(Exit(0))
   852  
   853  		vol = "type=volume,src=foo,dst=" + dest + ",chown=true"
   854  		session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest})
   855  		session.WaitWithDefaultTimeout()
   856  		Expect(session).Should(Exit(0))
   857  		Expect(session.OutputToString()).Should(Equal("888:888"))
   858  	})
   859  
   860  	It("podman run with --mount and named volume with driver-opts", func() {
   861  		// anonymous volume mount with driver opts
   862  		vol := "type=volume,source=test_vol,dst=/test,volume-opt=type=tmpfs,volume-opt=device=tmpfs,volume-opt=o=nodev"
   863  		session := podmanTest.Podman([]string{"run", "--rm", "--mount", vol, ALPINE, "echo", "hello"})
   864  		session.WaitWithDefaultTimeout()
   865  		Expect(session).Should(Exit(0))
   866  
   867  		inspectVol := podmanTest.Podman([]string{"volume", "inspect", "test_vol"})
   868  		inspectVol.WaitWithDefaultTimeout()
   869  		Expect(inspectVol).Should(Exit(0))
   870  		Expect(inspectVol.OutputToString()).To(ContainSubstring("nodev"))
   871  	})
   872  
   873  	It("volume permissions after run", func() {
   874  		imgName := "testimg"
   875  		dockerfile := fmt.Sprintf(`FROM %s
   876  RUN useradd -m testuser -u 1005
   877  USER testuser`, fedoraMinimal)
   878  		podmanTest.BuildImage(dockerfile, imgName, "false")
   879  
   880  		testString := "testuser testuser"
   881  
   882  		test1 := podmanTest.Podman([]string{"run", "-v", "testvol1:/test", imgName, "bash", "-c", "ls -al /test | grep -v root | grep -v total"})
   883  		test1.WaitWithDefaultTimeout()
   884  		Expect(test1).Should(Exit(0))
   885  		Expect(test1.OutputToString()).To(ContainSubstring(testString))
   886  
   887  		volName := "testvol2"
   888  		vol := podmanTest.Podman([]string{"volume", "create", volName})
   889  		vol.WaitWithDefaultTimeout()
   890  		Expect(vol).Should(Exit(0))
   891  
   892  		test2 := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/test", volName), imgName, "bash", "-c", "ls -al /test | grep -v root | grep -v total"})
   893  		test2.WaitWithDefaultTimeout()
   894  		Expect(test2).Should(Exit(0))
   895  		Expect(test2.OutputToString()).To(ContainSubstring(testString))
   896  
   897  	})
   898  
   899  	It("podman run with named volume check if we honor permission of target dir", func() {
   900  		session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "stat", "-c", "%a %Y", "/var/tmp"})
   901  		session.WaitWithDefaultTimeout()
   902  		Expect(session).Should(Exit(0))
   903  		perms := session.OutputToString()
   904  
   905  		session = podmanTest.Podman([]string{"run", "--rm", "-v", "test:/var/tmp", ALPINE, "stat", "-c", "%a %Y", "/var/tmp"})
   906  		session.WaitWithDefaultTimeout()
   907  		Expect(session).Should(Exit(0))
   908  		Expect(session.OutputToString()).To(Equal(perms))
   909  	})
   910  
   911  	It("podman volume with uid and gid works", func() {
   912  		volName := "testVol"
   913  		volCreate := podmanTest.Podman([]string{"volume", "create", "--opt", "o=uid=1000", volName})
   914  		volCreate.WaitWithDefaultTimeout()
   915  		Expect(volCreate).Should(Exit(0))
   916  
   917  		volMount := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "stat", "-c", "%u", "/test"})
   918  		volMount.WaitWithDefaultTimeout()
   919  		Expect(volMount).Should(Exit(0))
   920  		Expect(volMount.OutputToString()).To(Equal("1000"))
   921  
   922  		volName = "testVol2"
   923  		volCreate = podmanTest.Podman([]string{"volume", "create", "--opt", "o=gid=1000", volName})
   924  		volCreate.WaitWithDefaultTimeout()
   925  		Expect(volCreate).Should(Exit(0))
   926  
   927  		volMount = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "stat", "-c", "%g", "/test"})
   928  		volMount.WaitWithDefaultTimeout()
   929  		Expect(volMount).Should(Exit(0))
   930  		Expect(volMount.OutputToString()).To(Equal("1000"))
   931  
   932  		volName = "testVol3"
   933  		volCreate = podmanTest.Podman([]string{"volume", "create", "--opt", "o=uid=1000,gid=1000", volName})
   934  		volCreate.WaitWithDefaultTimeout()
   935  		Expect(volCreate).Should(Exit(0))
   936  
   937  		volMount = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "stat", "-c", "%u:%g", "/test"})
   938  		volMount.WaitWithDefaultTimeout()
   939  		Expect(volMount).Should(Exit(0))
   940  		Expect(volMount.OutputToString()).To(Equal("1000:1000"))
   941  	})
   942  })