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 })