Files
podman/test/e2e/run_volume_test.go
Paul Holzinger 666d839157 golangci-lint: make windows linting happy
It qemu cannot be compiled anyway so make sure we do not try to compile
parts where the typechecker complains about on windows.
Also all the e2e test files are only used on linux as well.
pkg/machine/wsl also reports some error but to many for me to fix them
now. One minor problem was fixed in pkg/machine/machine_windows.go.

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
2024-08-19 11:41:29 +02:00

1069 lines
45 KiB
Go

//go:build linux || freebsd
package integration
import (
"fmt"
"os"
"os/exec"
"os/user"
"path/filepath"
"strings"
. "github.com/containers/podman/v5/test/utils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
)
// in-container mount point: using a path that is definitely not present
// on the host system might help to uncover some issues.
const dest = "/unique/path"
var _ = Describe("Podman run with volumes", func() {
// Returns the /proc/self/mountinfo line for a given mount point
getMountInfo := func(volume string) []string {
containerDir := strings.SplitN(volume, ":", 3)[1]
session := podmanTest.Podman([]string{"run", "--rm", "-v", volume, ALPINE, "awk", fmt.Sprintf(`$5 == "%s" { print }`, containerDir), "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring(containerDir), "mount point not found in /proc/self/mountinfo")
return strings.Fields(session.OutputToString())
}
//nolint:unparam
mountVolumeAndCheckDirectory := func(volName, volPath, expectedOwner, imgName string) {
check := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:%s", volName, volPath), imgName, "stat", "-c", "%U:%G", volPath})
check.WaitWithDefaultTimeout()
Expect(check).Should(ExitCleanly())
Expect(check.OutputToString()).Should(ContainSubstring(fmt.Sprintf("%s:%s", expectedOwner, expectedOwner)))
}
It("podman run with volume flag", func() {
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
err = os.Mkdir(mountPath, 0755)
Expect(err).ToNot(HaveOccurred())
vol := mountPath + ":" + dest
// [5] is flags
Expect(getMountInfo(vol)[5]).To(ContainSubstring("rw"))
Expect(getMountInfo(vol + ":ro")[5]).To(ContainSubstring("ro"))
mountinfo := getMountInfo(vol + ":shared")
Expect(mountinfo[5]).To(ContainSubstring("rw"))
Expect(mountinfo[6]).To(ContainSubstring("shared"))
// Cached is ignored
mountinfo = getMountInfo(vol + ":cached")
Expect(mountinfo[5]).To(ContainSubstring("rw"))
Expect(mountinfo).To(Not(ContainElement(ContainSubstring("cached"))))
// Delegated is ignored
mountinfo = getMountInfo(vol + ":delegated")
Expect(mountinfo[5]).To(ContainSubstring("rw"))
Expect(mountinfo).To(Not(ContainElement(ContainSubstring("delegated"))))
})
It("podman run with --mount flag", func() {
if podmanTest.Host.Arch == "ppc64le" {
Skip("skip failing test on ppc64le")
}
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
err = os.Mkdir(mountPath, 0755)
Expect(err).ToNot(HaveOccurred())
mount := "type=bind,src=" + mountPath + ",target=" + dest
session := podmanTest.Podman([]string{"run", "--rm", "--mount", mount, ALPINE, "grep", dest, "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring(dest + " rw"))
session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro", ALPINE, "grep", dest, "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring(dest + " ro"))
session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",readonly", ALPINE, "grep", dest, "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring(dest + " ro"))
session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",consistency=delegated,shared", ALPINE, "grep", dest, "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("rw"))
Expect(session.OutputToString()).To(ContainSubstring("shared"))
session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=" + dest, ALPINE, "grep", dest, "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring(dest + " rw,nosuid,nodev,relatime - tmpfs"))
session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,tmpcopyup", ALPINE, "ls", "/etc/ssl"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("certs"))
session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,tmpcopyup,notmpcopyup", ALPINE, "ls", "/etc/ssl"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError(125, "cannot pass 'tmpcopyup' and 'notmpcopyup' mnt.Options more than once: must provide an argument for option"))
// test csv escaping
session = podmanTest.Podman([]string{"run", "--rm", "--mount=type=tmpfs,tmpfs-size=512M,\"destination=/test,\"", ALPINE, "ls", "/test,"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=bind,src=/tmp,target=/tmp,tmpcopyup", ALPINE, "true"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError(125, `"tmpcopyup" option not supported for "bind" mount types`))
session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=bind,src=/tmp,target=/tmp,notmpcopyup", ALPINE, "true"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError(125, `"notmpcopyup" option not supported for "bind" mount types`))
session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,notmpcopyup", ALPINE, "ls", "/etc/ssl"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Not(ContainSubstring("certs")))
})
It("podman run with conflicting volumes errors", func() {
mountPath := filepath.Join(podmanTest.TmpDir, "secrets")
err := os.Mkdir(mountPath, 0755)
Expect(err).ToNot(HaveOccurred())
session := podmanTest.Podman([]string{"run", "-v", mountPath + ":" + dest, "-v", "/tmp" + ":" + dest, ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitWithError(125, fmt.Sprintf("%s: duplicate mount destination", dest)))
})
It("podman run with conflict between image volume and user mount succeeds", func() {
err = podmanTest.RestoreArtifact(REDIS_IMAGE)
Expect(err).ToNot(HaveOccurred())
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
err := os.Mkdir(mountPath, 0755)
Expect(err).ToNot(HaveOccurred())
testFile := filepath.Join(mountPath, "test1")
f, err := os.Create(testFile)
Expect(err).ToNot(HaveOccurred(), "os.Create(testfile)")
f.Close()
Expect(err).ToNot(HaveOccurred())
session := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/data:Z", mountPath), REDIS_IMAGE, "ls", "/data/test1"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
})
It("podman run with mount flag and boolean options", func() {
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
err := os.Mkdir(mountPath, 0755)
Expect(err).ToNot(HaveOccurred())
mount := "type=bind,src=" + mountPath + ",target=" + dest
session := podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro=false", ALPINE, "grep", dest, "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring(dest + " rw"))
session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro=true", ALPINE, "grep", dest, "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring(dest + " ro"))
session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",ro=true,rw=false", ALPINE, "grep", dest, "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError(125, "cannot pass 'readonly', 'ro', or 'rw' mnt.Options more than once: must provide an argument for option"))
})
It("podman run with volume flag and multiple named volumes", func() {
session := podmanTest.Podman([]string{"run", "--rm", "-v", "testvol1:/testvol1", "-v", "testvol2:/testvol2", ALPINE, "grep", "/testvol", "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("/testvol1"))
Expect(session.OutputToString()).To(ContainSubstring("/testvol2"))
})
It("podman run with volumes and suid/dev/exec options", func() {
if isRootless() {
// We cannot undo nosuid,nodev,noexec when running rootless for obvious reasons.
// Thus we should check first if our source dir contains such options and skip the test int his case
session := SystemExec("findmnt", []string{"-n", "-o", "OPTIONS", "--target", podmanTest.TempDir})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitCleanly())
output := session.OutputToString()
if strings.Contains(output, "noexec") ||
strings.Contains(output, "nodev") ||
strings.Contains(output, "nosuid") {
Skip("test file system is mounted noexec, nodev or nosuid - cannot bind mount without these options as rootless")
}
}
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
err := os.Mkdir(mountPath, 0755)
Expect(err).ToNot(HaveOccurred())
session := podmanTest.Podman([]string{"run", "--rm", "-v", mountPath + ":" + dest + ":suid,dev,exec", ALPINE, "grep", dest, "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
output := session.OutputToString()
Expect(output).To(Not(ContainSubstring("noexec")))
Expect(output).To(Not(ContainSubstring("nodev")))
Expect(output).To(Not(ContainSubstring("nosuid")))
session = podmanTest.Podman([]string{"run", "--rm", "--tmpfs", dest + ":suid,dev,exec", ALPINE, "grep", dest, "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
output = session.OutputToString()
Expect(output).To(Not(ContainSubstring("noexec")))
Expect(output).To(Not(ContainSubstring("nodev")))
Expect(output).To(Not(ContainSubstring("nosuid")))
})
// Container should start when workdir is overlay volume
It("podman run with volume mounted as overlay and used as workdir", func() {
SkipIfRemote("Overlay volumes only work locally")
if os.Getenv("container") != "" {
Skip("Overlay mounts not supported when running in a container")
}
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
err := os.Mkdir(mountPath, 0755)
Expect(err).ToNot(HaveOccurred())
// Container should be able to start with custom overlay volume
session := podmanTest.Podman([]string{"run", "--rm", "-v", mountPath + ":/data:O", "--workdir=/data", ALPINE, "echo", "hello"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
})
It("podman support overlay on named volume", func() {
SkipIfRemote("Overlay volumes only work locally")
if os.Getenv("container") != "" {
Skip("Overlay mounts not supported when running in a container")
}
session := podmanTest.Podman([]string{"volume", "create", "myvolume"})
session.WaitWithDefaultTimeout()
volName := session.OutputToString()
Expect(session).Should(ExitCleanly())
// create file on actual volume
session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data", ALPINE, "sh", "-c", "echo hello >> " + "/data/test"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
// create file on overlay volume
session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data:O", ALPINE, "sh", "-c", "echo hello >> " + "/data/overlay"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
// volume should contain only `test` not `overlay`
session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data", ALPINE, "sh", "-c", "ls /data"})
session.WaitWithDefaultTimeout()
Expect(session.OutputToString()).To(Not(ContainSubstring("overlay")))
Expect(session.OutputToString()).To(ContainSubstring("test"))
})
It("podman support overlay on named volume with custom upperdir and workdir", func() {
SkipIfRemote("Overlay volumes only work locally")
if os.Getenv("container") != "" {
Skip("Overlay mounts not supported when running in a container")
}
// create persistent upperdir on host
upperDir := filepath.Join(tempdir, "upper")
err := os.Mkdir(upperDir, 0755)
Expect(err).ToNot(HaveOccurred(), "mkdir "+upperDir)
// create persistent workdir on host
workDir := filepath.Join(tempdir, "work")
err = os.Mkdir(workDir, 0755)
Expect(err).ToNot(HaveOccurred(), "mkdir "+workDir)
overlayOpts := fmt.Sprintf("upperdir=%s,workdir=%s", upperDir, workDir)
session := podmanTest.Podman([]string{"volume", "create", "myvolume"})
session.WaitWithDefaultTimeout()
volName := session.OutputToString()
Expect(session).Should(ExitCleanly())
// create file on actual volume
session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data", ALPINE, "sh", "-c", "echo hello >> " + "/data/test"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
// create file on overlay volume
session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data:O," + overlayOpts, ALPINE, "sh", "-c", "echo hello >> " + "/data/overlay"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data:O," + overlayOpts, ALPINE, "sh", "-c", "ls /data"})
session.WaitWithDefaultTimeout()
// must contain `overlay` file since it should be persistent on specified upper and workdir
Expect(session.OutputToString()).To(ContainSubstring("overlay"))
// this should be there since `test` was written on actual volume not on any overlay
Expect(session.OutputToString()).To(ContainSubstring("test"))
session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data:O", ALPINE, "sh", "-c", "ls /data"})
session.WaitWithDefaultTimeout()
// must not contain `overlay` file which was on custom upper and workdir since we have not specified any upper or workdir
Expect(session.OutputToString()).To(Not(ContainSubstring("overlay")))
// this should be there since `test` was written on actual volume not on any overlay
Expect(session.OutputToString()).To(ContainSubstring("test"))
})
It("podman support overlay volume with custom upperdir and workdir", func() {
SkipIfRemote("Overlay volumes only work locally")
if os.Getenv("container") != "" {
Skip("Overlay mounts not supported when running in a container")
}
// Use bindsource instead of named volume
bindSource := filepath.Join(tempdir, "bindsource")
err := os.Mkdir(bindSource, 0755)
Expect(err).ToNot(HaveOccurred(), "mkdir "+bindSource)
// create persistent upperdir on host
upperDir := filepath.Join(tempdir, "upper")
err = os.Mkdir(upperDir, 0755)
Expect(err).ToNot(HaveOccurred(), "mkdir "+upperDir)
// create persistent workdir on host
workDir := filepath.Join(tempdir, "work")
err = os.Mkdir(workDir, 0755)
Expect(err).ToNot(HaveOccurred(), "mkdir "+workDir)
overlayOpts := fmt.Sprintf("upperdir=%s,workdir=%s", upperDir, workDir)
// create file on overlay volume
session := podmanTest.Podman([]string{"run", "--volume", bindSource + ":/data:O," + overlayOpts, ALPINE, "sh", "-c", "echo hello >> " + "/data/overlay"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"run", "--volume", bindSource + ":/data:O," + overlayOpts, ALPINE, "sh", "-c", "ls /data"})
session.WaitWithDefaultTimeout()
// must contain `overlay` file since it should be persistent on specified upper and workdir
Expect(session.OutputToString()).To(ContainSubstring("overlay"))
session = podmanTest.Podman([]string{"run", "--volume", bindSource + ":/data:O", ALPINE, "sh", "-c", "ls /data"})
session.WaitWithDefaultTimeout()
// must not contain `overlay` file which was on custom upper and workdir since we have not specified any upper or workdir
Expect(session.OutputToString()).To(Not(ContainSubstring("overlay")))
})
It("podman run with noexec can't exec", func() {
session := podmanTest.Podman([]string{"run", "--rm", "-v", "/bin:/hostbin:noexec", ALPINE, "/hostbin/ls", "/"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError(126, "ermission denied"))
})
It("podman run with tmpfs named volume mounts and unmounts", func() {
SkipIfRootless("rootless podman mount requires you to be in a user namespace")
SkipIfRemote("podman-remote does not support --volumes. This test could be simplified to be tested on Remote.")
volName := "testvol"
mkVolume := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=nodev", "testvol"})
mkVolume.WaitWithDefaultTimeout()
Expect(mkVolume).Should(ExitCleanly())
// Volume not mounted on create
mountCmd1, err := Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred())
mountCmd1.Wait(90)
Expect(mountCmd1).Should(Exit(0))
mountOut1 := strings.Join(strings.Fields(string(mountCmd1.Out.Contents())), " ")
GinkgoWriter.Printf("Output: %s", mountOut1)
Expect(mountOut1).To(Not(ContainSubstring(volName)))
ctrName := "testctr"
podmanSession := podmanTest.Podman([]string{"run", "-d", "--name", ctrName, "-v", fmt.Sprintf("%s:/testvol", volName), ALPINE, "top"})
podmanSession.WaitWithDefaultTimeout()
Expect(podmanSession).Should(ExitCleanly())
// Volume now mounted as container is running
mountCmd2, err := Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred())
mountCmd2.Wait(90)
Expect(mountCmd2).Should(Exit(0))
mountOut2 := strings.Join(strings.Fields(string(mountCmd2.Out.Contents())), " ")
GinkgoWriter.Printf("Output: %s", mountOut2)
Expect(mountOut2).To(ContainSubstring(volName))
// Stop the container to unmount
podmanTest.StopContainer(ctrName)
// We have to force cleanup so the unmount happens
podmanCleanupSession := podmanTest.Podman([]string{"container", "cleanup", ctrName})
podmanCleanupSession.WaitWithDefaultTimeout()
Expect(podmanCleanupSession).Should(ExitCleanly())
// Ensure volume is unmounted
mountCmd3, err := Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred())
mountCmd3.Wait(90)
Expect(mountCmd3).Should(Exit(0))
mountOut3 := strings.Join(strings.Fields(string(mountCmd3.Out.Contents())), " ")
GinkgoWriter.Printf("Output: %s", mountOut3)
Expect(mountOut3).To(Not(ContainSubstring(volName)))
})
It("podman named volume copyup", func() {
baselineSession := podmanTest.Podman([]string{"run", "--rm", ALPINE, "ls", "/etc/apk/"})
baselineSession.WaitWithDefaultTimeout()
Expect(baselineSession).Should(ExitCleanly())
baselineOutput := baselineSession.OutputToString()
inlineVolumeSession := podmanTest.Podman([]string{"run", "--rm", "-v", "testvol1:/etc/apk", ALPINE, "ls", "/etc/apk/"})
inlineVolumeSession.WaitWithDefaultTimeout()
Expect(inlineVolumeSession).Should(ExitCleanly())
Expect(inlineVolumeSession.OutputToString()).To(Equal(baselineOutput))
makeVolumeSession := podmanTest.Podman([]string{"volume", "create", "testvol2"})
makeVolumeSession.WaitWithDefaultTimeout()
Expect(makeVolumeSession).Should(ExitCleanly())
separateVolumeSession := podmanTest.Podman([]string{"run", "--rm", "-v", "testvol2:/etc/apk", ALPINE, "ls", "/etc/apk/"})
separateVolumeSession.WaitWithDefaultTimeout()
Expect(separateVolumeSession).Should(ExitCleanly())
Expect(separateVolumeSession.OutputToString()).To(Equal(baselineOutput))
copySession := podmanTest.Podman([]string{"run", "--rm", "-v", "testvol3:/etc/apk:copy", ALPINE, "stat", "-c", "%h", "/etc/apk/arch"})
copySession.WaitWithDefaultTimeout()
Expect(copySession).Should(ExitCleanly())
noCopySession := podmanTest.Podman([]string{"run", "--rm", "-v", "testvol4:/etc/apk:nocopy", ALPINE, "stat", "-c", "%h", "/etc/apk/arch"})
noCopySession.WaitWithDefaultTimeout()
Expect(noCopySession).Should(ExitWithError(1, "stat: can't stat '/etc/apk/arch': No such file or directory"))
})
It("podman named volume copyup symlink", func() {
imgName := "testimg"
dockerfile := fmt.Sprintf(`FROM %s
RUN touch /testfile
RUN sh -c "cd /etc/apk && ln -s ../../testfile"`, ALPINE)
podmanTest.BuildImage(dockerfile, imgName, "false")
baselineSession := podmanTest.Podman([]string{"run", "--rm", imgName, "ls", "/etc/apk/"})
baselineSession.WaitWithDefaultTimeout()
Expect(baselineSession).Should(ExitCleanly())
baselineOutput := baselineSession.OutputToString()
outputSession := podmanTest.Podman([]string{"run", "-v", "/etc/apk/", imgName, "ls", "/etc/apk/"})
outputSession.WaitWithDefaultTimeout()
Expect(outputSession).Should(ExitCleanly())
Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
})
It("podman named volume copyup empty directory", func() {
baselineSession := podmanTest.Podman([]string{"run", "--rm", ALPINE, "ls", "/srv"})
baselineSession.WaitWithDefaultTimeout()
Expect(baselineSession).Should(ExitCleanly())
baselineOutput := baselineSession.OutputToString()
outputSession := podmanTest.Podman([]string{"run", "-v", "/srv", ALPINE, "ls", "/srv"})
outputSession.WaitWithDefaultTimeout()
Expect(outputSession).Should(ExitCleanly())
Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
})
It("podman named volume copyup of /var", func() {
baselineSession := podmanTest.Podman([]string{"run", "--rm", fedoraMinimal, "ls", "/var"})
baselineSession.WaitWithDefaultTimeout()
Expect(baselineSession).Should(ExitCleanly())
baselineOutput := baselineSession.OutputToString()
outputSession := podmanTest.Podman([]string{"run", "-v", "/var", fedoraMinimal, "ls", "/var"})
outputSession.WaitWithDefaultTimeout()
Expect(outputSession).Should(ExitCleanly())
Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
})
It("podman read-only tmpfs conflict with volume", func() {
session := podmanTest.Podman([]string{"run", "--rm", "--read-only", "-v", "tmp_volume:" + dest, ALPINE, "touch", dest + "/a"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session2 := podmanTest.Podman([]string{"run", "--rm", "--read-only", "--tmpfs", dest, ALPINE, "touch", dest + "/a"})
session2.WaitWithDefaultTimeout()
Expect(session2).Should(ExitCleanly())
})
It("podman run with anonymous volume", func() {
list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
list1.WaitWithDefaultTimeout()
Expect(list1).Should(ExitCleanly())
Expect(list1.OutputToString()).To(Equal(""))
session := podmanTest.Podman([]string{"create", "-v", "/test", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
list2.WaitWithDefaultTimeout()
Expect(list2).Should(ExitCleanly())
arr := list2.OutputToStringArray()
Expect(arr).To(HaveLen(1))
Expect(arr[0]).To(Not(Equal("")))
})
It("podman rm -v removes anonymous volume", func() {
list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
list1.WaitWithDefaultTimeout()
Expect(list1).Should(ExitCleanly())
Expect(list1.OutputToString()).To(Equal(""))
ctrName := "testctr"
session := podmanTest.Podman([]string{"create", "--name", ctrName, "-v", "/test", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
list2.WaitWithDefaultTimeout()
Expect(list2).Should(ExitCleanly())
arr := list2.OutputToStringArray()
Expect(arr).To(HaveLen(1))
Expect(arr[0]).To(Not(Equal("")))
remove := podmanTest.Podman([]string{"rm", "-v", ctrName})
remove.WaitWithDefaultTimeout()
Expect(remove).Should(ExitCleanly())
list3 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
list3.WaitWithDefaultTimeout()
Expect(list3).Should(ExitCleanly())
Expect(list3.OutputToString()).To(Equal(""))
})
It("podman rm -v retains named volume", func() {
list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
list1.WaitWithDefaultTimeout()
Expect(list1).Should(ExitCleanly())
Expect(list1.OutputToString()).To(Equal(""))
ctrName := "testctr"
volName := "testvol"
session := podmanTest.Podman([]string{"create", "--name", ctrName, "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
list2.WaitWithDefaultTimeout()
Expect(list2).Should(ExitCleanly())
arr := list2.OutputToStringArray()
Expect(arr).To(HaveLen(1))
Expect(arr[0]).To(Equal(volName))
remove := podmanTest.Podman([]string{"rm", "-v", ctrName})
remove.WaitWithDefaultTimeout()
Expect(remove).Should(ExitCleanly())
list3 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
list3.WaitWithDefaultTimeout()
Expect(list3).Should(ExitCleanly())
arr2 := list3.OutputToStringArray()
Expect(arr2).To(HaveLen(1))
Expect(arr2[0]).To(Equal(volName))
})
It("podman run image volume is not noexec", func() {
session := podmanTest.Podman([]string{"run", "--rm", REDIS_IMAGE, "grep", "/data", "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Not(ContainSubstring("noexec")))
})
It("podman mount with invalid option fails", func() {
volName := "testVol"
volCreate := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=invalid", volName})
volCreate.WaitWithDefaultTimeout()
Expect(volCreate).Should(ExitCleanly())
volMount := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/tmp", volName), ALPINE, "ls"})
volMount.WaitWithDefaultTimeout()
Expect(volMount).To(ExitWithError(126, "mounting volume testVol for container "))
})
It("Podman fix for CVE-2020-1726", func() {
volName := "testVol"
volCreate := podmanTest.Podman([]string{"volume", "create", volName})
volCreate.WaitWithDefaultTimeout()
Expect(volCreate).Should(ExitCleanly())
volPath := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{.Mountpoint}}", volName})
volPath.WaitWithDefaultTimeout()
Expect(volPath).Should(ExitCleanly())
path := volPath.OutputToString()
fileName := "thisIsATestFile"
file, err := os.Create(filepath.Join(path, fileName))
Expect(err).ToNot(HaveOccurred())
defer file.Close()
runLs := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%v:/etc/ssl", volName), ALPINE, "ls", "-1", "/etc/ssl"})
runLs.WaitWithDefaultTimeout()
Expect(runLs).Should(ExitCleanly())
outputArr := runLs.OutputToStringArray()
Expect(outputArr).To(HaveLen(1))
Expect(outputArr[0]).To(ContainSubstring(fileName))
})
It("Podman mount over image volume with trailing /", func() {
image := "podman-volume-test:trailing"
dockerfile := fmt.Sprintf(`FROM %s
VOLUME /test/`, ALPINE)
podmanTest.BuildImage(dockerfile, image, "false")
ctrName := "testCtr"
create := podmanTest.Podman([]string{"create", "-v", "/tmp:/test", "--name", ctrName, image, "ls"})
create.WaitWithDefaultTimeout()
Expect(create).Should(ExitCleanly())
data := podmanTest.InspectContainer(ctrName)
Expect(data).To(HaveLen(1))
Expect(data[0].Mounts).To(HaveLen(1))
Expect(data[0].Mounts[0]).To(HaveField("Source", "/tmp"))
Expect(data[0].Mounts[0]).To(HaveField("Destination", "/test"))
})
It("podman run with overlay volume flag", func() {
SkipIfRemote("Overlay volumes only work locally")
if os.Getenv("container") != "" {
Skip("Overlay mounts not supported when running in a container")
}
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
err := os.Mkdir(mountPath, 0755)
Expect(err).ToNot(HaveOccurred())
testFile := filepath.Join(mountPath, "test1")
f, err := os.Create(testFile)
Expect(err).ToNot(HaveOccurred(), "os.Create "+testFile)
f.Close()
// Make sure host directory gets mounted in to container as overlay
volumeFlag := fmt.Sprintf("%s:/run/test:O", mountPath)
Expect(getMountInfo(volumeFlag)[7]).To(Equal("overlay"))
// Make sure host files show up in the container
session := podmanTest.Podman([]string{"run", "--rm", "-v", volumeFlag, ALPINE, "ls", "/run/test/test1"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"run", "--rm", "-v", ".:/app:O", ALPINE, "ls", "/app"})
session.WaitWithDefaultTimeout()
Expect(session.OutputToString()).To(ContainSubstring(filepath.Base(CurrentSpecReport().FileName())))
Expect(session).Should(ExitCleanly())
// Make sure modifications in container do not show up on host
session = podmanTest.Podman([]string{"run", "--rm", "-v", volumeFlag, ALPINE, "touch", "/run/test/container"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
_, err = os.Stat(filepath.Join(mountPath, "container"))
Expect(err).To(HaveOccurred())
// Make sure modifications in container disappear when container is stopped
session = podmanTest.Podman([]string{"create", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"start", "-l"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"exec", "-l", "touch", "/run/test/container"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"exec", "-l", "ls", "/run/test/container"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
podmanTest.StopContainer("-l")
session = podmanTest.Podman([]string{"start", "-l"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"exec", "-l", "ls", "/run/test/container"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError(1, "ls: /run/test/container: No such file or directory"))
})
It("overlay volume conflicts with named volume and mounts", func() {
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
err := os.Mkdir(mountPath, 0755)
Expect(err).ToNot(HaveOccurred())
testFile := filepath.Join(mountPath, "test1")
f, err := os.Create(testFile)
Expect(err).ToNot(HaveOccurred())
f.Close()
mountSrc := filepath.Join(podmanTest.TempDir, "vol-test1")
err = os.MkdirAll(mountSrc, 0755)
Expect(err).ToNot(HaveOccurred())
mountDest := "/run/test"
volName := "myvol"
session := podmanTest.Podman([]string{"volume", "create", volName})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
expectErr := fmt.Sprintf("%s: duplicate mount destination", mountDest)
// overlay and named volume destinations conflict
session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:%s:O", mountPath, mountDest), "-v", fmt.Sprintf("%s:%s", volName, mountDest), ALPINE})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError(125, expectErr))
// overlay and bind mount destinations conflict
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})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError(125, expectErr))
// overlay and tmpfs mount destinations conflict
session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:%s:O", mountPath, mountDest), "--mount", fmt.Sprintf("type=tmpfs,target=%s", mountDest), ALPINE})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError(125, expectErr))
})
It("same volume in multiple places does not deadlock", func() {
volName := "testVol1"
session := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/test1", volName), "-v", fmt.Sprintf("%s:/test2", volName), "--rm", ALPINE, "sh", "-c", "mount | grep /test"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToStringArray()).To(HaveLen(2))
})
It("podman run with --volume and U flag", func() {
SkipIfRemote("Overlay volumes only work locally")
u, err := user.Current()
Expect(err).ToNot(HaveOccurred())
name := u.Username
if name == "root" {
name = "containers"
}
content, err := os.ReadFile("/etc/subuid")
if err != nil {
Skip("cannot read /etc/subuid")
}
if !strings.Contains(string(content), name) {
Skip("cannot find mappings for the current user")
}
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
err = os.Mkdir(mountPath, 0755)
Expect(err).ToNot(HaveOccurred())
vol := mountPath + ":" + dest + ":U"
session := podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "-v", vol, ALPINE, "stat", "-c", "%u:%g", dest})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("888:888"))
// test with an existing directory in the image
session = podmanTest.Podman([]string{"run", "--rm", "--user", "881:882", "-v", "NAMED-VOLUME:/mnt:U", ALPINE, "stat", "-c", "%u:%g", "/mnt"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("881:882"))
session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--userns", "auto", "-v", vol, ALPINE, "stat", "-c", "%u:%g", dest})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("888:888"))
vol += ",O"
session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--userns", "keep-id", "-v", vol, ALPINE, "stat", "-c", "%u:%g", dest})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("888:888"))
})
It("podman run with --mount and U flag", func() {
u, err := user.Current()
Expect(err).ToNot(HaveOccurred())
name := u.Username
if name == "root" {
name = "containers"
}
content, err := os.ReadFile("/etc/subuid")
if err != nil {
Skip("cannot read /etc/subuid")
}
if !strings.Contains(string(content), name) {
Skip("cannot find mappings for the current user")
}
mountPath := filepath.Join(podmanTest.TempDir, "foo")
err = os.Mkdir(mountPath, 0755)
Expect(err).ToNot(HaveOccurred())
// false bind mount
vol := "type=bind,src=" + mountPath + ",dst=" + dest + ",U=false"
session := podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).ShouldNot(Equal("888:888"))
// invalid bind mount
vol = "type=bind,src=" + mountPath + ",dst=" + dest + ",U=invalid"
session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError(125, `'U' or 'chown' must be set to true or false, instead received "invalid": must provide an argument for option`))
// true bind mount
vol = "type=bind,src=" + mountPath + ",dst=" + dest + ",U=true"
session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).Should(Equal("888:888"))
// tmpfs mount
vol = "type=tmpfs," + "dst=" + dest + ",chown"
session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).Should(Equal("888:888"))
// anonymous volume mount
vol = "type=volume," + "dst=" + dest
session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).Should(Equal("888:888"))
// named volume mount
namedVolume := podmanTest.Podman([]string{"volume", "create", "foo"})
namedVolume.WaitWithDefaultTimeout()
Expect(namedVolume).Should(ExitCleanly())
vol = "type=volume,src=foo,dst=" + dest + ",chown=true"
session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).Should(Equal("888:888"))
})
It("podman run with --mount and named volume with driver-opts", func() {
// anonymous volume mount with driver opts
vol := "type=volume,source=test_vol,dst=/test,volume-opt=type=tmpfs,volume-opt=device=tmpfs,volume-opt=o=nodev"
session := podmanTest.Podman([]string{"run", "--rm", "--mount", vol, ALPINE, "echo", "hello"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
inspectVol := podmanTest.Podman([]string{"volume", "inspect", "test_vol"})
inspectVol.WaitWithDefaultTimeout()
Expect(inspectVol).Should(ExitCleanly())
Expect(inspectVol.OutputToString()).To(ContainSubstring("nodev"))
})
It("volume permissions after run", func() {
imgName := "testimg"
dockerfile := fmt.Sprintf(`FROM %s
RUN adduser -D -u 1005 testuser
USER testuser`, CITEST_IMAGE)
podmanTest.BuildImage(dockerfile, imgName, "false")
testString := "testuser testuser"
test1 := podmanTest.Podman([]string{"run", "-v", "testvol1:/test", imgName, "sh", "-c", "ls -al /test | grep -v root | grep -v total"})
test1.WaitWithDefaultTimeout()
Expect(test1).Should(ExitCleanly())
Expect(test1.OutputToString()).To(ContainSubstring(testString))
volName := "testvol2"
vol := podmanTest.Podman([]string{"volume", "create", volName})
vol.WaitWithDefaultTimeout()
Expect(vol).Should(ExitCleanly())
test2 := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/test", volName), imgName, "sh", "-c", "ls -al /test | grep -v root | grep -v total"})
test2.WaitWithDefaultTimeout()
Expect(test2).Should(ExitCleanly())
Expect(test2.OutputToString()).To(ContainSubstring(testString))
})
It("podman run with named volume check if we honor permission of target dir", func() {
session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "stat", "-c", "%a %Y", "/var/tmp"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
perms := session.OutputToString()
session = podmanTest.Podman([]string{"run", "--rm", "-v", "test:/var/tmp", ALPINE, "stat", "-c", "%a %Y", "/var/tmp"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal(perms))
})
It("podman run with -v $SRC:/run does not create /run/.containerenv", func() {
mountSrc := filepath.Join(podmanTest.TempDir, "vol-test1")
err := os.MkdirAll(mountSrc, 0755)
Expect(err).ToNot(HaveOccurred())
session := podmanTest.Podman([]string{"run", "-v", mountSrc + ":/run", ALPINE, "true"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
// the file should not have been created
_, err = os.Stat(filepath.Join(mountSrc, ".containerenv"))
Expect(err).To(HaveOccurred())
})
It("podman volume with uid and gid works", func() {
volName := "testVol"
volCreate := podmanTest.Podman([]string{"volume", "create", "--opt", "o=uid=1000", volName})
volCreate.WaitWithDefaultTimeout()
Expect(volCreate).Should(ExitCleanly())
volMount := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "stat", "-c", "%u", "/test"})
volMount.WaitWithDefaultTimeout()
Expect(volMount).Should(ExitCleanly())
Expect(volMount.OutputToString()).To(Equal("1000"))
volName = "testVol2"
volCreate = podmanTest.Podman([]string{"volume", "create", "--opt", "o=gid=1000", volName})
volCreate.WaitWithDefaultTimeout()
Expect(volCreate).Should(ExitCleanly())
volMount = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "stat", "-c", "%g", "/test"})
volMount.WaitWithDefaultTimeout()
Expect(volMount).Should(ExitCleanly())
Expect(volMount.OutputToString()).To(Equal("1000"))
volName = "testVol3"
volCreate = podmanTest.Podman([]string{"volume", "create", "--opt", "o=uid=1000,gid=1000", volName})
volCreate.WaitWithDefaultTimeout()
Expect(volCreate).Should(ExitCleanly())
volMount = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "stat", "-c", "%u:%g", "/test"})
volMount.WaitWithDefaultTimeout()
Expect(volMount).Should(ExitCleanly())
Expect(volMount.OutputToString()).To(Equal("1000:1000"))
})
It("podman run -v with a relative dir", func() {
mountPath := filepath.Join(podmanTest.TempDir, "vol")
err = os.Mkdir(mountPath, 0755)
Expect(err).ToNot(HaveOccurred())
defer func() {
err := os.RemoveAll(mountPath)
Expect(err).ToNot(HaveOccurred())
}()
f, err := os.CreateTemp(mountPath, "podman")
Expect(err).ToNot(HaveOccurred())
cwd, err := os.Getwd()
Expect(err).ToNot(HaveOccurred())
err = os.Chdir(mountPath)
Expect(err).ToNot(HaveOccurred())
defer func() {
err := os.Chdir(cwd)
Expect(err).ToNot(HaveOccurred())
}()
run := podmanTest.Podman([]string{"run", "--security-opt", "label=disable", "-v", "./:" + dest, ALPINE, "ls", dest})
run.WaitWithDefaultTimeout()
Expect(run).Should(ExitCleanly())
Expect(run.OutputToString()).Should(ContainSubstring(strings.TrimLeft("/vol/", f.Name())))
})
It("podman run --mount type=image with subpath", func() {
podmanTest.AddImageToRWStore(ALPINE)
pathToCheck := "/sbin"
pathInCtr := "/mnt"
ctrCommand := []string{"run", "--mount", fmt.Sprintf("type=image,source=%s,dst=%s,subpath=%s", ALPINE, pathInCtr, pathToCheck), ALPINE, "ls"}
run1Cmd := append(ctrCommand, pathToCheck)
run1 := podmanTest.Podman(run1Cmd)
run1.WaitWithDefaultTimeout()
Expect(run1).Should(ExitCleanly())
run2Cmd := append(ctrCommand, pathInCtr)
run2 := podmanTest.Podman(run2Cmd)
run2.WaitWithDefaultTimeout()
Expect(run2).Should(ExitCleanly())
Expect(run1.OutputToString()).Should(Equal(run2.OutputToString()))
})
It("podman run -v chowns multiple times on empty volume", func() {
imgName := "testimg"
dockerfile := fmt.Sprintf(`FROM %s
RUN addgroup -g 1234 test1
RUN addgroup -g 4567 test2
RUN addgroup -g 7890 test3
RUN adduser -D -u 1234 -G test1 test1
RUN adduser -D -u 4567 -G test2 test2
RUN adduser -D -u 7890 -G test3 test3
RUN mkdir /test1 /test2 /test3 /test4
RUN chown test1:test1 /test1
RUN chown test2:test2 /test2
RUN chown test3:test3 /test4
RUN chmod 755 /test1 /test2 /test3 /test4`, ALPINE)
podmanTest.BuildImage(dockerfile, imgName, "false")
volName := "testVol"
volCreate := podmanTest.Podman([]string{"volume", "create", volName})
volCreate.WaitWithDefaultTimeout()
Expect(volCreate).Should(ExitCleanly())
mountVolumeAndCheckDirectory(volName, "/test1", "test1", imgName)
mountVolumeAndCheckDirectory(volName, "/test2", "test2", imgName)
mountVolumeAndCheckDirectory(volName, "/test3", "root", imgName)
mountVolumeAndCheckDirectory(volName, "/test4", "root", imgName)
})
It("podman run -v chowns until copy-up on volume", func() {
imgName := "testimg"
dockerfile := fmt.Sprintf(`FROM %s
RUN addgroup -g 1234 test1
RUN addgroup -g 4567 test2
RUN addgroup -g 7890 test3
RUN adduser -D -u 1234 -G test1 test1
RUN adduser -D -u 4567 -G test2 test2
RUN adduser -D -u 7890 -G test3 test3
RUN mkdir /test1 /test2 /test3
RUN touch /test2/file1
RUN chown test1:test1 /test1
RUN chown -R test2:test2 /test2
RUN chown test3:test3 /test3
RUN chmod 755 /test1 /test2 /test3`, ALPINE)
podmanTest.BuildImage(dockerfile, imgName, "false")
volName := "testVol"
volCreate := podmanTest.Podman([]string{"volume", "create", volName})
volCreate.WaitWithDefaultTimeout()
Expect(volCreate).Should(ExitCleanly())
mountVolumeAndCheckDirectory(volName, "/test1", "test1", imgName)
mountVolumeAndCheckDirectory(volName, "/test2", "test2", imgName)
mountVolumeAndCheckDirectory(volName, "/test3", "test2", imgName)
})
It("podman run -v chowns until volume has contents", func() {
imgName := "testimg"
dockerfile := fmt.Sprintf(`FROM %s
RUN addgroup -g 1234 test1
RUN addgroup -g 4567 test2
RUN addgroup -g 7890 test3
RUN adduser -D -u 1234 -G test1 test1
RUN adduser -D -u 4567 -G test2 test2
RUN adduser -D -u 7890 -G test3 test3
RUN mkdir /test1 /test2 /test3
RUN chown test1:test1 /test1
RUN chown test2:test2 /test2
RUN chown test3:test3 /test3
RUN chmod 755 /test1 /test2 /test3`, ALPINE)
podmanTest.BuildImage(dockerfile, imgName, "false")
volName := "testVol"
volCreate := podmanTest.Podman([]string{"volume", "create", volName})
volCreate.WaitWithDefaultTimeout()
Expect(volCreate).Should(ExitCleanly())
mountVolumeAndCheckDirectory(volName, "/test1", "test1", imgName)
mountVolumeAndCheckDirectory(volName, "/test2", "test2", imgName)
session := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/test2", volName), imgName, "touch", "/test2/file1"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitCleanly())
mountVolumeAndCheckDirectory(volName, "/test3", "test2", imgName)
})
})