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