github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/test/e2e/run_volume_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/containers/podman/v2/pkg/rootless"
    11  	. "github.com/containers/podman/v2/test/utils"
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  	"github.com/onsi/gomega/gexec"
    15  )
    16  
    17  // in-container mount point: using a path that is definitely not present
    18  // on the host system might help to uncover some issues.
    19  const dest = "/unique/path"
    20  
    21  var _ = Describe("Podman run with volumes", func() {
    22  	var (
    23  		tempdir    string
    24  		err        error
    25  		podmanTest *PodmanTestIntegration
    26  	)
    27  
    28  	BeforeEach(func() {
    29  		tempdir, err = CreateTempDirInTempDir()
    30  		if err != nil {
    31  			os.Exit(1)
    32  		}
    33  		podmanTest = PodmanTestCreate(tempdir)
    34  		podmanTest.Setup()
    35  		podmanTest.SeedImages()
    36  	})
    37  
    38  	AfterEach(func() {
    39  		podmanTest.Cleanup()
    40  		f := CurrentGinkgoTestDescription()
    41  		processTestResult(f)
    42  	})
    43  
    44  	It("podman run with volume flag", func() {
    45  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
    46  		os.Mkdir(mountPath, 0755)
    47  		vol := mountPath + ":" + dest
    48  
    49  		session := podmanTest.Podman([]string{"run", "--rm", "-v", vol, ALPINE, "grep", dest, "/proc/self/mountinfo"})
    50  		session.WaitWithDefaultTimeout()
    51  		Expect(session.ExitCode()).To(Equal(0))
    52  		found, matches := session.GrepString(dest)
    53  		Expect(found).Should(BeTrue())
    54  		Expect(matches[0]).To(ContainSubstring("rw"))
    55  
    56  		session = podmanTest.Podman([]string{"run", "--rm", "-v", vol + ":ro", ALPINE, "grep", dest, "/proc/self/mountinfo"})
    57  		session.WaitWithDefaultTimeout()
    58  		Expect(session.ExitCode()).To(Equal(0))
    59  		found, matches = session.GrepString(dest)
    60  		Expect(found).Should(BeTrue())
    61  		Expect(matches[0]).To(ContainSubstring("ro"))
    62  
    63  		session = podmanTest.Podman([]string{"run", "--rm", "-v", vol + ":shared", ALPINE, "grep", dest, "/proc/self/mountinfo"})
    64  		session.WaitWithDefaultTimeout()
    65  		Expect(session.ExitCode()).To(Equal(0))
    66  		found, matches = session.GrepString(dest)
    67  		Expect(found).Should(BeTrue())
    68  		Expect(matches[0]).To(ContainSubstring("rw"))
    69  		Expect(matches[0]).To(ContainSubstring("shared"))
    70  
    71  		// Cached is ignored
    72  		session = podmanTest.Podman([]string{"run", "--rm", "-v", vol + ":cached", ALPINE, "grep", dest, "/proc/self/mountinfo"})
    73  		session.WaitWithDefaultTimeout()
    74  		Expect(session.ExitCode()).To(Equal(0))
    75  		found, matches = session.GrepString(dest)
    76  		Expect(found).Should(BeTrue())
    77  		Expect(matches[0]).To(ContainSubstring("rw"))
    78  		Expect(matches[0]).To(Not(ContainSubstring("cached")))
    79  
    80  		// Delegated is ignored
    81  		session = podmanTest.Podman([]string{"run", "--rm", "-v", vol + ":delegated", ALPINE, "grep", dest, "/proc/self/mountinfo"})
    82  		session.WaitWithDefaultTimeout()
    83  		Expect(session.ExitCode()).To(Equal(0))
    84  		found, matches = session.GrepString(dest)
    85  		Expect(found).Should(BeTrue())
    86  		Expect(matches[0]).To(ContainSubstring("rw"))
    87  		Expect(matches[0]).To(Not(ContainSubstring("delegated")))
    88  	})
    89  
    90  	It("podman run with --mount flag", func() {
    91  		if podmanTest.Host.Arch == "ppc64le" {
    92  			Skip("skip failing test on ppc64le")
    93  		}
    94  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
    95  		os.Mkdir(mountPath, 0755)
    96  		mount := "type=bind,src=" + mountPath + ",target=" + dest
    97  
    98  		session := podmanTest.Podman([]string{"run", "--rm", "--mount", mount, ALPINE, "grep", dest, "/proc/self/mountinfo"})
    99  		session.WaitWithDefaultTimeout()
   100  		Expect(session.ExitCode()).To(Equal(0))
   101  		Expect(session.OutputToString()).To(ContainSubstring(dest + " rw"))
   102  
   103  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   104  		session.WaitWithDefaultTimeout()
   105  		Expect(session.ExitCode()).To(Equal(0))
   106  		Expect(session.OutputToString()).To(ContainSubstring(dest + " ro"))
   107  
   108  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",readonly", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   109  		session.WaitWithDefaultTimeout()
   110  		Expect(session.ExitCode()).To(Equal(0))
   111  		Expect(session.OutputToString()).To(ContainSubstring(dest + " ro"))
   112  
   113  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",shared", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   114  		session.WaitWithDefaultTimeout()
   115  		Expect(session.ExitCode()).To(Equal(0))
   116  		found, matches := session.GrepString(dest)
   117  		Expect(found).Should(BeTrue())
   118  		Expect(matches[0]).To(ContainSubstring("rw"))
   119  		Expect(matches[0]).To(ContainSubstring("shared"))
   120  
   121  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=" + dest, ALPINE, "grep", dest, "/proc/self/mountinfo"})
   122  		session.WaitWithDefaultTimeout()
   123  		Expect(session.ExitCode()).To(Equal(0))
   124  		Expect(session.OutputToString()).To(ContainSubstring(dest + " rw,nosuid,nodev,relatime - tmpfs"))
   125  
   126  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,tmpcopyup", ALPINE, "ls", "/etc/ssl"})
   127  		session.WaitWithDefaultTimeout()
   128  		Expect(session.ExitCode()).To(Equal(0))
   129  		Expect(session.OutputToString()).To(ContainSubstring("certs"))
   130  
   131  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,tmpcopyup,notmpcopyup", ALPINE, "ls", "/etc/ssl"})
   132  		session.WaitWithDefaultTimeout()
   133  		Expect(session.ExitCode()).To(Not(Equal(0)))
   134  
   135  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=bind,src=/tmp,target=/tmp,tmpcopyup", ALPINE, "true"})
   136  		session.WaitWithDefaultTimeout()
   137  		Expect(session.ExitCode()).To(Not(Equal(0)))
   138  
   139  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=bind,src=/tmp,target=/tmp,notmpcopyup", ALPINE, "true"})
   140  		session.WaitWithDefaultTimeout()
   141  		Expect(session.ExitCode()).To(Not(Equal(0)))
   142  
   143  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,notmpcopyup", ALPINE, "ls", "/etc/ssl"})
   144  		session.WaitWithDefaultTimeout()
   145  		Expect(session.ExitCode()).To(Equal(0))
   146  		Expect(session.OutputToString()).To(Not(ContainSubstring("certs")))
   147  	})
   148  
   149  	It("podman run with conflicting volumes errors", func() {
   150  		mountPath := filepath.Join(podmanTest.TmpDir, "secrets")
   151  		os.Mkdir(mountPath, 0755)
   152  		session := podmanTest.Podman([]string{"run", "-v", mountPath + ":" + dest, "-v", "/tmp" + ":" + dest, ALPINE, "ls"})
   153  		session.WaitWithDefaultTimeout()
   154  		Expect(session.ExitCode()).To(Equal(125))
   155  	})
   156  
   157  	It("podman run with conflict between image volume and user mount succeeds", func() {
   158  		podmanTest.RestoreArtifact(redis)
   159  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   160  		err := os.Mkdir(mountPath, 0755)
   161  		Expect(err).To(BeNil())
   162  		testFile := filepath.Join(mountPath, "test1")
   163  		f, err := os.Create(testFile)
   164  		f.Close()
   165  		Expect(err).To(BeNil())
   166  		session := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/data", mountPath), redis, "ls", "/data/test1"})
   167  		session.WaitWithDefaultTimeout()
   168  		Expect(session.ExitCode()).To(Equal(0))
   169  	})
   170  
   171  	It("podman run with mount flag and boolean options", func() {
   172  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   173  		os.Mkdir(mountPath, 0755)
   174  		mount := "type=bind,src=" + mountPath + ",target=" + dest
   175  
   176  		session := podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro=false", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   177  		session.WaitWithDefaultTimeout()
   178  		Expect(session.ExitCode()).To(Equal(0))
   179  		Expect(session.OutputToString()).To(ContainSubstring(dest + " rw"))
   180  
   181  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro=true", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   182  		session.WaitWithDefaultTimeout()
   183  		Expect(session.ExitCode()).To(Equal(0))
   184  		Expect(session.OutputToString()).To(ContainSubstring(dest + " ro"))
   185  
   186  		session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro=true,rw=false", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   187  		session.WaitWithDefaultTimeout()
   188  		Expect(session).To(ExitWithError())
   189  	})
   190  
   191  	It("podman run with volume flag and multiple named volumes", func() {
   192  		session := podmanTest.Podman([]string{"run", "--rm", "-v", "testvol1:/testvol1", "-v", "testvol2:/testvol2", ALPINE, "grep", "/testvol", "/proc/self/mountinfo"})
   193  		session.WaitWithDefaultTimeout()
   194  		Expect(session.ExitCode()).To(Equal(0))
   195  		Expect(session.OutputToString()).To(ContainSubstring("/testvol1"))
   196  		Expect(session.OutputToString()).To(ContainSubstring("/testvol2"))
   197  	})
   198  
   199  	It("podman run with volumes and suid/dev/exec options", func() {
   200  		SkipIfRemote("podman-remote does not support --volumes")
   201  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   202  		os.Mkdir(mountPath, 0755)
   203  
   204  		session := podmanTest.Podman([]string{"run", "--rm", "-v", mountPath + ":" + dest + ":suid,dev,exec", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   205  		session.WaitWithDefaultTimeout()
   206  		Expect(session.ExitCode()).To(Equal(0))
   207  		found, matches := session.GrepString(dest)
   208  		Expect(found).Should(BeTrue())
   209  		Expect(matches[0]).To(Not(ContainSubstring("noexec")))
   210  		Expect(matches[0]).To(Not(ContainSubstring("nodev")))
   211  		Expect(matches[0]).To(Not(ContainSubstring("nosuid")))
   212  
   213  		session = podmanTest.Podman([]string{"run", "--rm", "--tmpfs", dest + ":suid,dev,exec", ALPINE, "grep", dest, "/proc/self/mountinfo"})
   214  		session.WaitWithDefaultTimeout()
   215  		Expect(session.ExitCode()).To(Equal(0))
   216  		found, matches = session.GrepString(dest)
   217  		Expect(found).Should(BeTrue())
   218  		Expect(matches[0]).To(Not(ContainSubstring("noexec")))
   219  		Expect(matches[0]).To(Not(ContainSubstring("nodev")))
   220  		Expect(matches[0]).To(Not(ContainSubstring("nosuid")))
   221  	})
   222  
   223  	It("podman run with noexec can't exec", func() {
   224  		session := podmanTest.Podman([]string{"run", "--rm", "-v", "/bin:/hostbin:noexec", ALPINE, "/hostbin/ls", "/"})
   225  		session.WaitWithDefaultTimeout()
   226  		Expect(session).To(ExitWithError())
   227  	})
   228  
   229  	It("podman run with tmpfs named volume mounts and unmounts", func() {
   230  		SkipIfRootless("FIXME:  rootless podman mount requires you to be in a user namespace")
   231  		SkipIfRemote("podman-remote does not support --volumes this test could be simplified to be tested on Remote.")
   232  		volName := "testvol"
   233  		mkVolume := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=nodev", "testvol"})
   234  		mkVolume.WaitWithDefaultTimeout()
   235  		Expect(mkVolume.ExitCode()).To(Equal(0))
   236  
   237  		// Volume not mounted on create
   238  		mountCmd1, err := gexec.Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
   239  		Expect(err).To(BeNil())
   240  		mountCmd1.Wait(90)
   241  		Expect(mountCmd1.ExitCode()).To(Equal(0))
   242  		os.Stdout.Sync()
   243  		os.Stderr.Sync()
   244  		mountOut1 := strings.Join(strings.Fields(string(mountCmd1.Out.Contents())), " ")
   245  		fmt.Printf("Output: %s", mountOut1)
   246  		Expect(strings.Contains(mountOut1, volName)).To(BeFalse())
   247  
   248  		ctrName := "testctr"
   249  		podmanSession := podmanTest.Podman([]string{"run", "-d", "--name", ctrName, "-v", fmt.Sprintf("%s:/testvol", volName), ALPINE, "top"})
   250  		podmanSession.WaitWithDefaultTimeout()
   251  		Expect(podmanSession.ExitCode()).To(Equal(0))
   252  
   253  		// Volume now mounted as container is running
   254  		mountCmd2, err := gexec.Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
   255  		Expect(err).To(BeNil())
   256  		mountCmd2.Wait(90)
   257  		Expect(mountCmd2.ExitCode()).To(Equal(0))
   258  		os.Stdout.Sync()
   259  		os.Stderr.Sync()
   260  		mountOut2 := strings.Join(strings.Fields(string(mountCmd2.Out.Contents())), " ")
   261  		fmt.Printf("Output: %s", mountOut2)
   262  		Expect(strings.Contains(mountOut2, volName)).To(BeTrue())
   263  
   264  		// Stop the container to unmount
   265  		podmanStopSession := podmanTest.Podman([]string{"stop", "--time", "0", ctrName})
   266  		podmanStopSession.WaitWithDefaultTimeout()
   267  		Expect(podmanStopSession.ExitCode()).To(Equal(0))
   268  
   269  		// We have to force cleanup so the unmount happens
   270  		podmanCleanupSession := podmanTest.Podman([]string{"container", "cleanup", ctrName})
   271  		podmanCleanupSession.WaitWithDefaultTimeout()
   272  		Expect(podmanCleanupSession.ExitCode()).To(Equal(0))
   273  
   274  		// Ensure volume is unmounted
   275  		mountCmd3, err := gexec.Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
   276  		Expect(err).To(BeNil())
   277  		mountCmd3.Wait(90)
   278  		Expect(mountCmd3.ExitCode()).To(Equal(0))
   279  		os.Stdout.Sync()
   280  		os.Stderr.Sync()
   281  		mountOut3 := strings.Join(strings.Fields(string(mountCmd3.Out.Contents())), " ")
   282  		fmt.Printf("Output: %s", mountOut3)
   283  		Expect(strings.Contains(mountOut3, volName)).To(BeFalse())
   284  	})
   285  
   286  	It("podman named volume copyup", func() {
   287  		baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", ALPINE, "ls", "/etc/apk/"})
   288  		baselineSession.WaitWithDefaultTimeout()
   289  		Expect(baselineSession.ExitCode()).To(Equal(0))
   290  		baselineOutput := baselineSession.OutputToString()
   291  
   292  		inlineVolumeSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "-v", "testvol1:/etc/apk", ALPINE, "ls", "/etc/apk/"})
   293  		inlineVolumeSession.WaitWithDefaultTimeout()
   294  		Expect(inlineVolumeSession.ExitCode()).To(Equal(0))
   295  		Expect(inlineVolumeSession.OutputToString()).To(Equal(baselineOutput))
   296  
   297  		makeVolumeSession := podmanTest.Podman([]string{"volume", "create", "testvol2"})
   298  		makeVolumeSession.WaitWithDefaultTimeout()
   299  		Expect(makeVolumeSession.ExitCode()).To(Equal(0))
   300  
   301  		separateVolumeSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "-v", "testvol2:/etc/apk", ALPINE, "ls", "/etc/apk/"})
   302  		separateVolumeSession.WaitWithDefaultTimeout()
   303  		Expect(separateVolumeSession.ExitCode()).To(Equal(0))
   304  		Expect(separateVolumeSession.OutputToString()).To(Equal(baselineOutput))
   305  	})
   306  
   307  	It("podman read-only tmpfs conflict with volume", func() {
   308  		session := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "--read-only", "-v", "tmp_volume:" + dest, ALPINE, "touch", dest + "/a"})
   309  		session.WaitWithDefaultTimeout()
   310  		Expect(session.ExitCode()).To(Equal(0))
   311  
   312  		session2 := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "--read-only", "--tmpfs", dest, ALPINE, "touch", dest + "/a"})
   313  		session2.WaitWithDefaultTimeout()
   314  		Expect(session2.ExitCode()).To(Equal(0))
   315  	})
   316  
   317  	It("podman run with anonymous volume", func() {
   318  		list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   319  		list1.WaitWithDefaultTimeout()
   320  		Expect(list1.ExitCode()).To(Equal(0))
   321  		Expect(list1.OutputToString()).To(Equal(""))
   322  
   323  		session := podmanTest.Podman([]string{"create", "-v", "/test", ALPINE, "top"})
   324  		session.WaitWithDefaultTimeout()
   325  		Expect(session.ExitCode()).To(Equal(0))
   326  
   327  		list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   328  		list2.WaitWithDefaultTimeout()
   329  		Expect(list2.ExitCode()).To(Equal(0))
   330  		arr := list2.OutputToStringArray()
   331  		Expect(len(arr)).To(Equal(1))
   332  		Expect(arr[0]).To(Not(Equal("")))
   333  	})
   334  
   335  	It("podman rm -v removes anonymous volume", func() {
   336  		list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   337  		list1.WaitWithDefaultTimeout()
   338  		Expect(list1.ExitCode()).To(Equal(0))
   339  		Expect(list1.OutputToString()).To(Equal(""))
   340  
   341  		ctrName := "testctr"
   342  		session := podmanTest.Podman([]string{"create", "--name", ctrName, "-v", "/test", ALPINE, "top"})
   343  		session.WaitWithDefaultTimeout()
   344  		Expect(session.ExitCode()).To(Equal(0))
   345  
   346  		list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   347  		list2.WaitWithDefaultTimeout()
   348  		Expect(list2.ExitCode()).To(Equal(0))
   349  		arr := list2.OutputToStringArray()
   350  		Expect(len(arr)).To(Equal(1))
   351  		Expect(arr[0]).To(Not(Equal("")))
   352  
   353  		remove := podmanTest.Podman([]string{"rm", "-v", ctrName})
   354  		remove.WaitWithDefaultTimeout()
   355  		Expect(remove.ExitCode()).To(Equal(0))
   356  
   357  		list3 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   358  		list3.WaitWithDefaultTimeout()
   359  		Expect(list3.ExitCode()).To(Equal(0))
   360  		Expect(list3.OutputToString()).To(Equal(""))
   361  	})
   362  
   363  	It("podman rm -v retains named volume", func() {
   364  		list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   365  		list1.WaitWithDefaultTimeout()
   366  		Expect(list1.ExitCode()).To(Equal(0))
   367  		Expect(list1.OutputToString()).To(Equal(""))
   368  
   369  		ctrName := "testctr"
   370  		volName := "testvol"
   371  		session := podmanTest.Podman([]string{"create", "--name", ctrName, "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "top"})
   372  		session.WaitWithDefaultTimeout()
   373  		Expect(session.ExitCode()).To(Equal(0))
   374  
   375  		list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   376  		list2.WaitWithDefaultTimeout()
   377  		Expect(list2.ExitCode()).To(Equal(0))
   378  		arr := list2.OutputToStringArray()
   379  		Expect(len(arr)).To(Equal(1))
   380  		Expect(arr[0]).To(Equal(volName))
   381  
   382  		remove := podmanTest.Podman([]string{"rm", "-v", ctrName})
   383  		remove.WaitWithDefaultTimeout()
   384  		Expect(remove.ExitCode()).To(Equal(0))
   385  
   386  		list3 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
   387  		list3.WaitWithDefaultTimeout()
   388  		Expect(list3.ExitCode()).To(Equal(0))
   389  		arr2 := list3.OutputToStringArray()
   390  		Expect(len(arr2)).To(Equal(1))
   391  		Expect(arr2[0]).To(Equal(volName))
   392  	})
   393  
   394  	It("podman run image volume is not noexec", func() {
   395  		session := podmanTest.Podman([]string{"run", "--rm", redis, "grep", "/data", "/proc/self/mountinfo"})
   396  		session.WaitWithDefaultTimeout()
   397  		Expect(session.ExitCode()).To(Equal(0))
   398  		Expect(session.OutputToString()).To(Not(ContainSubstring("noexec")))
   399  	})
   400  
   401  	It("podman mount with invalid option fails", func() {
   402  		volName := "testVol"
   403  		volCreate := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=invalid", volName})
   404  		volCreate.WaitWithDefaultTimeout()
   405  		Expect(volCreate.ExitCode()).To(Equal(0))
   406  
   407  		volMount := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/tmp", volName), ALPINE, "ls"})
   408  		volMount.WaitWithDefaultTimeout()
   409  		Expect(volMount.ExitCode()).To(Not(Equal(0)))
   410  	})
   411  
   412  	It("Podman fix for CVE-2020-1726", func() {
   413  		volName := "testVol"
   414  		volCreate := podmanTest.Podman([]string{"volume", "create", volName})
   415  		volCreate.WaitWithDefaultTimeout()
   416  		Expect(volCreate.ExitCode()).To(Equal(0))
   417  
   418  		volPath := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{.Mountpoint}}", volName})
   419  		volPath.WaitWithDefaultTimeout()
   420  		Expect(volPath.ExitCode()).To(Equal(0))
   421  		path := volPath.OutputToString()
   422  
   423  		fileName := "thisIsATestFile"
   424  		file, err := os.Create(filepath.Join(path, fileName))
   425  		Expect(err).To(BeNil())
   426  		defer file.Close()
   427  
   428  		runLs := podmanTest.Podman([]string{"run", "-t", "-i", "--rm", "-v", fmt.Sprintf("%v:/etc/ssl", volName), ALPINE, "ls", "-1", "/etc/ssl"})
   429  		runLs.WaitWithDefaultTimeout()
   430  		Expect(runLs.ExitCode()).To(Equal(0))
   431  		outputArr := runLs.OutputToStringArray()
   432  		Expect(len(outputArr)).To(Equal(1))
   433  		Expect(strings.Contains(outputArr[0], fileName)).To(BeTrue())
   434  	})
   435  
   436  	It("Podman mount over image volume with trailing /", func() {
   437  		image := "podman-volume-test:trailing"
   438  		dockerfile := `
   439  FROM alpine:latest
   440  VOLUME /test/`
   441  		podmanTest.BuildImage(dockerfile, image, "false")
   442  
   443  		ctrName := "testCtr"
   444  		create := podmanTest.Podman([]string{"create", "-v", "/tmp:/test", "--name", ctrName, image, "ls"})
   445  		create.WaitWithDefaultTimeout()
   446  		Expect(create.ExitCode()).To(Equal(0))
   447  
   448  		data := podmanTest.InspectContainer(ctrName)
   449  		Expect(len(data)).To(Equal(1))
   450  		Expect(len(data[0].Mounts)).To(Equal(1))
   451  		Expect(data[0].Mounts[0].Source).To(Equal("/tmp"))
   452  		Expect(data[0].Mounts[0].Destination).To(Equal("/test"))
   453  	})
   454  
   455  	It("podman run with overlay volume flag", func() {
   456  		SkipIfRemote("Overlay volumes only work locally")
   457  		if os.Getenv("container") != "" {
   458  			Skip("Overlay mounts not supported when running in a container")
   459  		}
   460  		if rootless.IsRootless() {
   461  			if _, err := exec.LookPath("fuse_overlay"); err != nil {
   462  				Skip("Fuse-Overlayfs required for rootless overlay mount test")
   463  			}
   464  		}
   465  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   466  		os.Mkdir(mountPath, 0755)
   467  		testFile := filepath.Join(mountPath, "test1")
   468  		f, err := os.Create(testFile)
   469  		f.Close()
   470  
   471  		// Make sure host directory gets mounted in to container as overlay
   472  		session := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "grep", "/run/test", "/proc/self/mountinfo"})
   473  		session.WaitWithDefaultTimeout()
   474  		Expect(session.ExitCode()).To(Equal(0))
   475  		found, matches := session.GrepString("/run/test")
   476  		Expect(found).Should(BeTrue())
   477  		Expect(matches[0]).To(ContainSubstring("overlay"))
   478  
   479  		// Make sure host files show up in the container
   480  		session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "ls", "/run/test/test1"})
   481  		session.WaitWithDefaultTimeout()
   482  		Expect(session.ExitCode()).To(Equal(0))
   483  
   484  		// Make sure modifications in container do not show up on host
   485  		session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "touch", "/run/test/container"})
   486  		session.WaitWithDefaultTimeout()
   487  		Expect(session.ExitCode()).To(Equal(0))
   488  		_, err = os.Stat(filepath.Join(mountPath, "container"))
   489  		Expect(err).To(Not(BeNil()))
   490  
   491  		// Make sure modifications in container disappear when container is stopped
   492  		session = podmanTest.Podman([]string{"create", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "top"})
   493  		session.WaitWithDefaultTimeout()
   494  		Expect(session.ExitCode()).To(Equal(0))
   495  		session = podmanTest.Podman([]string{"start", "-l"})
   496  		session.WaitWithDefaultTimeout()
   497  		Expect(session.ExitCode()).To(Equal(0))
   498  		session = podmanTest.Podman([]string{"exec", "-l", "touch", "/run/test/container"})
   499  		session.WaitWithDefaultTimeout()
   500  		Expect(session.ExitCode()).To(Equal(0))
   501  		session = podmanTest.Podman([]string{"exec", "-l", "ls", "/run/test/container"})
   502  		session.WaitWithDefaultTimeout()
   503  		Expect(session.ExitCode()).To(Equal(0))
   504  		session = podmanTest.Podman([]string{"stop", "-l"})
   505  		session.WaitWithDefaultTimeout()
   506  		Expect(session.ExitCode()).To(Equal(0))
   507  		session = podmanTest.Podman([]string{"start", "-l"})
   508  		session.WaitWithDefaultTimeout()
   509  		Expect(session.ExitCode()).To(Equal(0))
   510  		session = podmanTest.Podman([]string{"exec", "-l", "ls", "/run/test/container"})
   511  		session.WaitWithDefaultTimeout()
   512  		Expect(session.ExitCode()).To(Not(Equal(0)))
   513  	})
   514  
   515  	It("overlay volume conflicts with named volume and mounts", func() {
   516  		mountPath := filepath.Join(podmanTest.TempDir, "secrets")
   517  		os.Mkdir(mountPath, 0755)
   518  		testFile := filepath.Join(mountPath, "test1")
   519  		f, err := os.Create(testFile)
   520  		Expect(err).To(BeNil())
   521  		f.Close()
   522  		mountSrc := filepath.Join(podmanTest.TempDir, "vol-test1")
   523  		err = os.MkdirAll(mountSrc, 0755)
   524  		Expect(err).To(BeNil())
   525  		mountDest := "/run/test"
   526  		volName := "myvol"
   527  
   528  		session := podmanTest.Podman([]string{"volume", "create", volName})
   529  		session.WaitWithDefaultTimeout()
   530  		Expect(session.ExitCode()).To(Equal(0))
   531  
   532  		// overlay and named volume destinations conflict
   533  		session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:%s:O", mountPath, mountDest), "-v", fmt.Sprintf("%s:%s", volName, mountDest), ALPINE})
   534  		session.WaitWithDefaultTimeout()
   535  		Expect(session.ExitCode()).To(Not(Equal(0)))
   536  		// overlay and bind mount destinations conflict
   537  		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})
   538  		Expect(session.ExitCode()).To(Not(Equal(0)))
   539  		// overlay and tmpfs mount destinations conflict
   540  		session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:%s:O", mountPath, mountDest), "--mount", fmt.Sprintf("type=tmpfs,target=%s", mountDest), ALPINE})
   541  		Expect(session.ExitCode()).To(Not(Equal(0)))
   542  	})
   543  
   544  	It("same volume in multiple places does not deadlock", func() {
   545  		volName := "testVol1"
   546  		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"})
   547  		session.WaitWithDefaultTimeout()
   548  		Expect(session.ExitCode()).To(Equal(0))
   549  		Expect(len(session.OutputToStringArray())).To(Equal(2))
   550  	})
   551  })