mirror of
https://github.com/containers/podman.git
synced 2025-12-08 06:39:05 +08:00
e2e test failures are rife with messages like:
Expected 1 to equal 0
These make me cry. They're anti-helpful, requiring the reader
to dive into the source code to figure out what those numbers
mean.
Solution: Go tests have a '.Should(Exit(NNN))' mechanism. I
don't know if it spits out a better diagnostic (I have no way
to run e2e tests on my laptop), but I have to fantasize that
it will, and given the state of our flakes I assume that at
least one test will fail and give me the opportunity to see
what the error message looks like.
THIS IS NOT REVIEWABLE CODE. There is no way for a human
to review it. Don't bother. Maybe look at a few random
ones for sanity. If you want to really review, here is
a reproducer of what I did:
cd test/e2e
! positive assertions. The second is the same as the first,
! with the addition of (unnecessary) parentheses because
! some invocations were written that way. The third is BeZero().
perl -pi -e 's/Expect\((\S+)\.ExitCode\(\)\)\.To\(Equal\((\d+)\)\)/Expect($1).Should(Exit($2))/' *_test.go
perl -pi -e 's/Expect\((\S+)\.ExitCode\(\)\)\.To\(\(Equal\((\d+)\)\)\)/Expect($1).Should(Exit($2))/' *_test.go
perl -pi -e 's/Expect\((\S+)\.ExitCode\(\)\)\.To\(BeZero\(\)\)/Expect($1).Should(Exit(0))/' *_test.go
! Same as above, but handles three non-numeric exit codes
! in run_exit_test.go
perl -pi -e 's/Expect\((\S+)\.ExitCode\(\)\)\.To\(Equal\((\S+)\)\)/Expect($1).Should(Exit($2))/' *_test.go
! negative assertions. Difference is the spelling of 'To(Not)',
! 'ToNot', and 'NotTo'. I assume those are all the same.
perl -pi -e 's/Expect\((\S+)\.ExitCode\(\)\)\.To\(Not\(Equal\((0)\)\)\)/Expect($1).To(ExitWithError())/' *_test.go
perl -pi -e 's/Expect\((\S+)\.ExitCode\(\)\)\.ToNot\(Equal\((0)\)\)/Expect($1).To(ExitWithError())/' *_test.go
perl -pi -e 's/Expect\((\S+)\.ExitCode\(\)\)\.NotTo\(Equal\((0)\)\)/Expect($1).To(ExitWithError())/' *_test.go
! negative, old use of BeZero()
perl -pi -e 's/Expect\((\S+)\.ExitCode\(\)\)\.ToNot\(BeZero\(\)\)/Expect($1).Should(ExitWithError())/' *_test.go
Run those on a clean copy of main branch (at the same branch
point as my PR, of course), then diff against a checked-out
copy of my PR. There should be no differences. Then all you
have to review is that my replacements above are sane.
UPDATE: nope, that's not enough, you also need to add gomega/gexec
to the files that don't have it:
perl -pi -e '$_ .= "$1/gexec\"\n" if m!^(.*/onsi/gomega)"!' $(grep -L gomega/gexec $(git log -1 --stat | awk '$1 ~ /test\/e2e\// { print $1}'))
UPDATE 2: hand-edit run_volume_test.go
UPDATE 3: sigh, add WaitWithDefaultTimeout() to a couple of places
UPDATE 4: skip a test due to bug #10935 (race condition)
Signed-off-by: Ed Santiago <santiago@redhat.com>
706 lines
28 KiB
Go
706 lines
28 KiB
Go
package integration
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"os/user"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/containers/podman/v3/pkg/rootless"
|
|
. "github.com/containers/podman/v3/test/utils"
|
|
. "github.com/onsi/ginkgo"
|
|
. "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() {
|
|
var (
|
|
tempdir string
|
|
err error
|
|
podmanTest *PodmanTestIntegration
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
tempdir, err = CreateTempDirInTempDir()
|
|
if err != nil {
|
|
os.Exit(1)
|
|
}
|
|
podmanTest = PodmanTestCreate(tempdir)
|
|
podmanTest.Setup()
|
|
podmanTest.SeedImages()
|
|
})
|
|
|
|
AfterEach(func() {
|
|
podmanTest.Cleanup()
|
|
f := CurrentGinkgoTestDescription()
|
|
processTestResult(f)
|
|
})
|
|
|
|
It("podman run with volume flag", func() {
|
|
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
|
|
os.Mkdir(mountPath, 0755)
|
|
vol := mountPath + ":" + dest
|
|
|
|
session := podmanTest.Podman([]string{"run", "--rm", "-v", vol, ALPINE, "grep", dest, "/proc/self/mountinfo"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
found, matches := session.GrepString(dest)
|
|
Expect(found).Should(BeTrue())
|
|
Expect(matches[0]).To(ContainSubstring("rw"))
|
|
|
|
session = podmanTest.Podman([]string{"run", "--rm", "-v", vol + ":ro", ALPINE, "grep", dest, "/proc/self/mountinfo"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
found, matches = session.GrepString(dest)
|
|
Expect(found).Should(BeTrue())
|
|
Expect(matches[0]).To(ContainSubstring("ro"))
|
|
|
|
session = podmanTest.Podman([]string{"run", "--rm", "-v", vol + ":shared", ALPINE, "grep", dest, "/proc/self/mountinfo"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
found, matches = session.GrepString(dest)
|
|
Expect(found).Should(BeTrue())
|
|
Expect(matches[0]).To(ContainSubstring("rw"))
|
|
Expect(matches[0]).To(ContainSubstring("shared"))
|
|
|
|
// Cached is ignored
|
|
session = podmanTest.Podman([]string{"run", "--rm", "-v", vol + ":cached", ALPINE, "grep", dest, "/proc/self/mountinfo"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
found, matches = session.GrepString(dest)
|
|
Expect(found).Should(BeTrue())
|
|
Expect(matches[0]).To(ContainSubstring("rw"))
|
|
Expect(matches[0]).To(Not(ContainSubstring("cached")))
|
|
|
|
// Delegated is ignored
|
|
session = podmanTest.Podman([]string{"run", "--rm", "-v", vol + ":delegated", ALPINE, "grep", dest, "/proc/self/mountinfo"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
found, matches = session.GrepString(dest)
|
|
Expect(found).Should(BeTrue())
|
|
Expect(matches[0]).To(ContainSubstring("rw"))
|
|
Expect(matches[0]).To(Not(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")
|
|
os.Mkdir(mountPath, 0755)
|
|
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(Exit(0))
|
|
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(Exit(0))
|
|
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(Exit(0))
|
|
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(Exit(0))
|
|
found, matches := session.GrepString(dest)
|
|
Expect(found).Should(BeTrue())
|
|
Expect(matches[0]).To(ContainSubstring("rw"))
|
|
Expect(matches[0]).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(Exit(0))
|
|
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(Exit(0))
|
|
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())
|
|
|
|
session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=bind,src=/tmp,target=/tmp,tmpcopyup", ALPINE, "true"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).To(ExitWithError())
|
|
|
|
session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=bind,src=/tmp,target=/tmp,notmpcopyup", ALPINE, "true"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).To(ExitWithError())
|
|
|
|
session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,notmpcopyup", ALPINE, "ls", "/etc/ssl"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
Expect(session.OutputToString()).To(Not(ContainSubstring("certs")))
|
|
})
|
|
|
|
It("podman run with conflicting volumes errors", func() {
|
|
mountPath := filepath.Join(podmanTest.TmpDir, "secrets")
|
|
os.Mkdir(mountPath, 0755)
|
|
session := podmanTest.Podman([]string{"run", "-v", mountPath + ":" + dest, "-v", "/tmp" + ":" + dest, ALPINE, "ls"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(125))
|
|
})
|
|
|
|
It("podman run with conflict between image volume and user mount succeeds", func() {
|
|
podmanTest.RestoreArtifact(redis)
|
|
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
|
|
err := os.Mkdir(mountPath, 0755)
|
|
Expect(err).To(BeNil())
|
|
testFile := filepath.Join(mountPath, "test1")
|
|
f, err := os.Create(testFile)
|
|
f.Close()
|
|
Expect(err).To(BeNil())
|
|
session := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/data", mountPath), redis, "ls", "/data/test1"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
})
|
|
|
|
It("podman run with mount flag and boolean options", func() {
|
|
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
|
|
os.Mkdir(mountPath, 0755)
|
|
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(Exit(0))
|
|
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(Exit(0))
|
|
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())
|
|
})
|
|
|
|
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(Exit(0))
|
|
Expect(session.OutputToString()).To(ContainSubstring("/testvol1"))
|
|
Expect(session.OutputToString()).To(ContainSubstring("/testvol2"))
|
|
})
|
|
|
|
It("podman run with volumes and suid/dev/exec options", func() {
|
|
SkipIfRemote("podman-remote does not support --volumes")
|
|
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
|
|
os.Mkdir(mountPath, 0755)
|
|
|
|
session := podmanTest.Podman([]string{"run", "--rm", "-v", mountPath + ":" + dest + ":suid,dev,exec", ALPINE, "grep", dest, "/proc/self/mountinfo"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
found, matches := session.GrepString(dest)
|
|
Expect(found).Should(BeTrue())
|
|
Expect(matches[0]).To(Not(ContainSubstring("noexec")))
|
|
Expect(matches[0]).To(Not(ContainSubstring("nodev")))
|
|
Expect(matches[0]).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(Exit(0))
|
|
found, matches = session.GrepString(dest)
|
|
Expect(found).Should(BeTrue())
|
|
Expect(matches[0]).To(Not(ContainSubstring("noexec")))
|
|
Expect(matches[0]).To(Not(ContainSubstring("nodev")))
|
|
Expect(matches[0]).To(Not(ContainSubstring("nosuid")))
|
|
})
|
|
|
|
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())
|
|
})
|
|
|
|
It("podman run with tmpfs named volume mounts and unmounts", func() {
|
|
SkipIfRootless("FIXME: 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(Exit(0))
|
|
|
|
// Volume not mounted on create
|
|
mountCmd1, err := Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
|
|
Expect(err).To(BeNil())
|
|
mountCmd1.Wait(90)
|
|
Expect(mountCmd1).Should(Exit(0))
|
|
os.Stdout.Sync()
|
|
os.Stderr.Sync()
|
|
mountOut1 := strings.Join(strings.Fields(string(mountCmd1.Out.Contents())), " ")
|
|
fmt.Printf("Output: %s", mountOut1)
|
|
Expect(strings.Contains(mountOut1, volName)).To(BeFalse())
|
|
|
|
ctrName := "testctr"
|
|
podmanSession := podmanTest.Podman([]string{"run", "-d", "--name", ctrName, "-v", fmt.Sprintf("%s:/testvol", volName), ALPINE, "top"})
|
|
podmanSession.WaitWithDefaultTimeout()
|
|
Expect(podmanSession).Should(Exit(0))
|
|
|
|
// Volume now mounted as container is running
|
|
mountCmd2, err := Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
|
|
Expect(err).To(BeNil())
|
|
mountCmd2.Wait(90)
|
|
Expect(mountCmd2).Should(Exit(0))
|
|
os.Stdout.Sync()
|
|
os.Stderr.Sync()
|
|
mountOut2 := strings.Join(strings.Fields(string(mountCmd2.Out.Contents())), " ")
|
|
fmt.Printf("Output: %s", mountOut2)
|
|
Expect(strings.Contains(mountOut2, volName)).To(BeTrue())
|
|
|
|
// Stop the container to unmount
|
|
podmanStopSession := podmanTest.Podman([]string{"stop", "--time", "0", ctrName})
|
|
podmanStopSession.WaitWithDefaultTimeout()
|
|
Expect(podmanStopSession).Should(Exit(0))
|
|
|
|
// We have to force cleanup so the unmount happens
|
|
podmanCleanupSession := podmanTest.Podman([]string{"container", "cleanup", ctrName})
|
|
podmanCleanupSession.WaitWithDefaultTimeout()
|
|
Expect(podmanCleanupSession).Should(Exit(0))
|
|
|
|
// Ensure volume is unmounted
|
|
mountCmd3, err := Start(exec.Command("mount"), GinkgoWriter, GinkgoWriter)
|
|
Expect(err).To(BeNil())
|
|
mountCmd3.Wait(90)
|
|
Expect(mountCmd3).Should(Exit(0))
|
|
os.Stdout.Sync()
|
|
os.Stderr.Sync()
|
|
mountOut3 := strings.Join(strings.Fields(string(mountCmd3.Out.Contents())), " ")
|
|
fmt.Printf("Output: %s", mountOut3)
|
|
Expect(strings.Contains(mountOut3, volName)).To(BeFalse())
|
|
})
|
|
|
|
It("podman named volume copyup", func() {
|
|
baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", ALPINE, "ls", "/etc/apk/"})
|
|
baselineSession.WaitWithDefaultTimeout()
|
|
Expect(baselineSession).Should(Exit(0))
|
|
baselineOutput := baselineSession.OutputToString()
|
|
|
|
inlineVolumeSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "-v", "testvol1:/etc/apk", ALPINE, "ls", "/etc/apk/"})
|
|
inlineVolumeSession.WaitWithDefaultTimeout()
|
|
Expect(inlineVolumeSession).Should(Exit(0))
|
|
Expect(inlineVolumeSession.OutputToString()).To(Equal(baselineOutput))
|
|
|
|
makeVolumeSession := podmanTest.Podman([]string{"volume", "create", "testvol2"})
|
|
makeVolumeSession.WaitWithDefaultTimeout()
|
|
Expect(makeVolumeSession).Should(Exit(0))
|
|
|
|
separateVolumeSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "-v", "testvol2:/etc/apk", ALPINE, "ls", "/etc/apk/"})
|
|
separateVolumeSession.WaitWithDefaultTimeout()
|
|
Expect(separateVolumeSession).Should(Exit(0))
|
|
Expect(separateVolumeSession.OutputToString()).To(Equal(baselineOutput))
|
|
})
|
|
|
|
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", "-t", "-i", imgName, "ls", "/etc/apk/"})
|
|
baselineSession.WaitWithDefaultTimeout()
|
|
Expect(baselineSession).Should(Exit(0))
|
|
baselineOutput := baselineSession.OutputToString()
|
|
|
|
outputSession := podmanTest.Podman([]string{"run", "-t", "-i", "-v", "/etc/apk/", imgName, "ls", "/etc/apk/"})
|
|
outputSession.WaitWithDefaultTimeout()
|
|
Expect(outputSession).Should(Exit(0))
|
|
Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
|
|
})
|
|
|
|
It("podman named volume copyup empty directory", func() {
|
|
baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", ALPINE, "ls", "/srv"})
|
|
baselineSession.WaitWithDefaultTimeout()
|
|
Expect(baselineSession).Should(Exit(0))
|
|
baselineOutput := baselineSession.OutputToString()
|
|
|
|
outputSession := podmanTest.Podman([]string{"run", "-t", "-i", "-v", "/srv", ALPINE, "ls", "/srv"})
|
|
outputSession.WaitWithDefaultTimeout()
|
|
Expect(outputSession).Should(Exit(0))
|
|
Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
|
|
})
|
|
|
|
It("podman named volume copyup of /var", func() {
|
|
baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", fedoraMinimal, "ls", "/var"})
|
|
baselineSession.WaitWithDefaultTimeout()
|
|
Expect(baselineSession).Should(Exit(0))
|
|
baselineOutput := baselineSession.OutputToString()
|
|
|
|
outputSession := podmanTest.Podman([]string{"run", "-t", "-i", "-v", "/var", fedoraMinimal, "ls", "/var"})
|
|
outputSession.WaitWithDefaultTimeout()
|
|
Expect(outputSession).Should(Exit(0))
|
|
Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
|
|
})
|
|
|
|
It("podman read-only tmpfs conflict with volume", func() {
|
|
session := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "--read-only", "-v", "tmp_volume:" + dest, ALPINE, "touch", dest + "/a"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
|
|
session2 := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "--read-only", "--tmpfs", dest, ALPINE, "touch", dest + "/a"})
|
|
session2.WaitWithDefaultTimeout()
|
|
Expect(session2).Should(Exit(0))
|
|
})
|
|
|
|
It("podman run with anonymous volume", func() {
|
|
list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
|
|
list1.WaitWithDefaultTimeout()
|
|
Expect(list1).Should(Exit(0))
|
|
Expect(list1.OutputToString()).To(Equal(""))
|
|
|
|
session := podmanTest.Podman([]string{"create", "-v", "/test", ALPINE, "top"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
|
|
list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
|
|
list2.WaitWithDefaultTimeout()
|
|
Expect(list2).Should(Exit(0))
|
|
arr := list2.OutputToStringArray()
|
|
Expect(len(arr)).To(Equal(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(Exit(0))
|
|
Expect(list1.OutputToString()).To(Equal(""))
|
|
|
|
ctrName := "testctr"
|
|
session := podmanTest.Podman([]string{"create", "--name", ctrName, "-v", "/test", ALPINE, "top"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
|
|
list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
|
|
list2.WaitWithDefaultTimeout()
|
|
Expect(list2).Should(Exit(0))
|
|
arr := list2.OutputToStringArray()
|
|
Expect(len(arr)).To(Equal(1))
|
|
Expect(arr[0]).To(Not(Equal("")))
|
|
|
|
remove := podmanTest.Podman([]string{"rm", "-v", ctrName})
|
|
remove.WaitWithDefaultTimeout()
|
|
Expect(remove).Should(Exit(0))
|
|
|
|
list3 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
|
|
list3.WaitWithDefaultTimeout()
|
|
Expect(list3).Should(Exit(0))
|
|
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(Exit(0))
|
|
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(Exit(0))
|
|
|
|
list2 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
|
|
list2.WaitWithDefaultTimeout()
|
|
Expect(list2).Should(Exit(0))
|
|
arr := list2.OutputToStringArray()
|
|
Expect(len(arr)).To(Equal(1))
|
|
Expect(arr[0]).To(Equal(volName))
|
|
|
|
remove := podmanTest.Podman([]string{"rm", "-v", ctrName})
|
|
remove.WaitWithDefaultTimeout()
|
|
Expect(remove).Should(Exit(0))
|
|
|
|
list3 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
|
|
list3.WaitWithDefaultTimeout()
|
|
Expect(list3).Should(Exit(0))
|
|
arr2 := list3.OutputToStringArray()
|
|
Expect(len(arr2)).To(Equal(1))
|
|
Expect(arr2[0]).To(Equal(volName))
|
|
})
|
|
|
|
It("podman run image volume is not noexec", func() {
|
|
session := podmanTest.Podman([]string{"run", "--rm", redis, "grep", "/data", "/proc/self/mountinfo"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
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(Exit(0))
|
|
|
|
volMount := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/tmp", volName), ALPINE, "ls"})
|
|
volMount.WaitWithDefaultTimeout()
|
|
Expect(volMount).To(ExitWithError())
|
|
})
|
|
|
|
It("Podman fix for CVE-2020-1726", func() {
|
|
volName := "testVol"
|
|
volCreate := podmanTest.Podman([]string{"volume", "create", volName})
|
|
volCreate.WaitWithDefaultTimeout()
|
|
Expect(volCreate).Should(Exit(0))
|
|
|
|
volPath := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{.Mountpoint}}", volName})
|
|
volPath.WaitWithDefaultTimeout()
|
|
Expect(volPath).Should(Exit(0))
|
|
path := volPath.OutputToString()
|
|
|
|
fileName := "thisIsATestFile"
|
|
file, err := os.Create(filepath.Join(path, fileName))
|
|
Expect(err).To(BeNil())
|
|
defer file.Close()
|
|
|
|
runLs := podmanTest.Podman([]string{"run", "-t", "-i", "--rm", "-v", fmt.Sprintf("%v:/etc/ssl", volName), ALPINE, "ls", "-1", "/etc/ssl"})
|
|
runLs.WaitWithDefaultTimeout()
|
|
Expect(runLs).Should(Exit(0))
|
|
outputArr := runLs.OutputToStringArray()
|
|
Expect(len(outputArr)).To(Equal(1))
|
|
Expect(strings.Contains(outputArr[0], fileName)).To(BeTrue())
|
|
})
|
|
|
|
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(Exit(0))
|
|
|
|
data := podmanTest.InspectContainer(ctrName)
|
|
Expect(len(data)).To(Equal(1))
|
|
Expect(len(data[0].Mounts)).To(Equal(1))
|
|
Expect(data[0].Mounts[0].Source).To(Equal("/tmp"))
|
|
Expect(data[0].Mounts[0].Destination).To(Equal("/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")
|
|
}
|
|
if rootless.IsRootless() {
|
|
if _, err := exec.LookPath("fuse_overlay"); err != nil {
|
|
Skip("Fuse-Overlayfs required for rootless overlay mount test")
|
|
}
|
|
}
|
|
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
|
|
os.Mkdir(mountPath, 0755)
|
|
testFile := filepath.Join(mountPath, "test1")
|
|
f, err := os.Create(testFile)
|
|
f.Close()
|
|
|
|
// Make sure host directory gets mounted in to container as overlay
|
|
session := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "grep", "/run/test", "/proc/self/mountinfo"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
found, matches := session.GrepString("/run/test")
|
|
Expect(found).Should(BeTrue())
|
|
Expect(matches[0]).To(ContainSubstring("overlay"))
|
|
|
|
// Make sure host files show up in the container
|
|
session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "ls", "/run/test/test1"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
|
|
// Make sure modifications in container do not show up on host
|
|
session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "touch", "/run/test/container"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
_, err = os.Stat(filepath.Join(mountPath, "container"))
|
|
Expect(err).To(Not(BeNil()))
|
|
|
|
// 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(Exit(0))
|
|
session = podmanTest.Podman([]string{"start", "-l"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
session = podmanTest.Podman([]string{"exec", "-l", "touch", "/run/test/container"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
session = podmanTest.Podman([]string{"exec", "-l", "ls", "/run/test/container"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
session = podmanTest.Podman([]string{"stop", "-l"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
session = podmanTest.Podman([]string{"start", "-l"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
session = podmanTest.Podman([]string{"exec", "-l", "ls", "/run/test/container"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).To(ExitWithError())
|
|
})
|
|
|
|
It("overlay volume conflicts with named volume and mounts", func() {
|
|
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
|
|
os.Mkdir(mountPath, 0755)
|
|
testFile := filepath.Join(mountPath, "test1")
|
|
f, err := os.Create(testFile)
|
|
Expect(err).To(BeNil())
|
|
f.Close()
|
|
mountSrc := filepath.Join(podmanTest.TempDir, "vol-test1")
|
|
err = os.MkdirAll(mountSrc, 0755)
|
|
Expect(err).To(BeNil())
|
|
mountDest := "/run/test"
|
|
volName := "myvol"
|
|
|
|
session := podmanTest.Podman([]string{"volume", "create", volName})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
|
|
// 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())
|
|
// 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())
|
|
// 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())
|
|
})
|
|
|
|
It("same volume in multiple places does not deadlock", func() {
|
|
volName := "testVol1"
|
|
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"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
Expect(len(session.OutputToStringArray())).To(Equal(2))
|
|
})
|
|
|
|
It("podman run with U volume flag", func() {
|
|
SkipIfRemote("Overlay volumes only work locally")
|
|
|
|
u, err := user.Current()
|
|
Expect(err).To(BeNil())
|
|
name := u.Username
|
|
if name == "root" {
|
|
name = "containers"
|
|
}
|
|
|
|
content, err := ioutil.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")
|
|
}
|
|
|
|
if os.Getenv("container") != "" {
|
|
Skip("Overlay mounts not supported when running in a container")
|
|
}
|
|
if rootless.IsRootless() {
|
|
if _, err := exec.LookPath("fuse_overlay"); err != nil {
|
|
Skip("Fuse-Overlayfs required for rootless overlay mount test")
|
|
}
|
|
}
|
|
|
|
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
|
|
os.Mkdir(mountPath, 0755)
|
|
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(Exit(0))
|
|
found, _ := session.GrepString("888:888")
|
|
Expect(found).Should(BeTrue())
|
|
|
|
session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--userns", "auto", "-v", vol, ALPINE, "stat", "-c", "%u:%g", dest})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).Should(Exit(0))
|
|
found, _ = session.GrepString("888:888")
|
|
Expect(found).Should(BeTrue())
|
|
|
|
vol = 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(Exit(0))
|
|
found, _ = session.GrepString("888:888")
|
|
Expect(found).Should(BeTrue())
|
|
})
|
|
|
|
It("volume permissions after run", func() {
|
|
imgName := "testimg"
|
|
dockerfile := fmt.Sprintf(`FROM %s
|
|
RUN useradd -m testuser -u 1005
|
|
USER testuser`, fedoraMinimal)
|
|
podmanTest.BuildImage(dockerfile, imgName, "false")
|
|
|
|
testString := "testuser testuser"
|
|
|
|
test1 := podmanTest.Podman([]string{"run", "-v", "testvol1:/test", imgName, "bash", "-c", "ls -al /test | grep -v root | grep -v total"})
|
|
test1.WaitWithDefaultTimeout()
|
|
Expect(test1).Should(Exit(0))
|
|
Expect(strings.Contains(test1.OutputToString(), testString)).To(BeTrue())
|
|
|
|
volName := "testvol2"
|
|
vol := podmanTest.Podman([]string{"volume", "create", volName})
|
|
vol.WaitWithDefaultTimeout()
|
|
Expect(vol).Should(Exit(0))
|
|
|
|
test2 := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/test", volName), imgName, "bash", "-c", "ls -al /test | grep -v root | grep -v total"})
|
|
test2.WaitWithDefaultTimeout()
|
|
Expect(test2).Should(Exit(0))
|
|
Expect(strings.Contains(test2.OutputToString(), testString)).To(BeTrue())
|
|
|
|
})
|
|
|
|
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(Exit(0))
|
|
|
|
volMount := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "stat", "-c", "%u", "/test"})
|
|
volMount.WaitWithDefaultTimeout()
|
|
Expect(volMount).Should(Exit(0))
|
|
Expect(volMount.OutputToString()).To(Equal("1000"))
|
|
|
|
volName = "testVol2"
|
|
volCreate = podmanTest.Podman([]string{"volume", "create", "--opt", "o=gid=1000", volName})
|
|
volCreate.WaitWithDefaultTimeout()
|
|
Expect(volCreate).Should(Exit(0))
|
|
|
|
volMount = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "stat", "-c", "%g", "/test"})
|
|
volMount.WaitWithDefaultTimeout()
|
|
Expect(volMount).Should(Exit(0))
|
|
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(Exit(0))
|
|
|
|
volMount = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "stat", "-c", "%u:%g", "/test"})
|
|
volMount.WaitWithDefaultTimeout()
|
|
Expect(volMount).Should(Exit(0))
|
|
Expect(volMount.OutputToString()).To(Equal("1000:1000"))
|
|
})
|
|
})
|