Files
podman/pkg/machine/e2e/basic_test.go
Jason T. Greene 0b36126e92 Fix relabeling failures with Z/z volumes on Mac
Non-Linux systems, such as BSD kernels, constrain xatter updates
according to file permissions. This is in contrast to Linux selinux
attr writes, which are governed by an selinux policy. By dafault this
policy apllows users to relabel files owned by themselves even if file
perms would otherwise disallow write.

This results in robust container relabeling results on Linux, and
fragile results everywhere else. Therefore, change the mac policy to
force the nfs_t context on all files, and ignore all relabel
events.

As a side-effect, this will disallow any ability to store custom
selinux constants on files. However, this is of limited use in
a machine context, since files in these volumes are externally
managed on systems which do not support SELinux.

Signed-off-by: Jason T. Greene <jason.greene@redhat.com>
2024-04-08 10:06:44 -05:00

197 lines
6.2 KiB
Go

package e2e_test
import (
"fmt"
"io"
"net"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"time"
"github.com/containers/podman/v5/pkg/machine/define"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
)
var _ = Describe("run basic podman commands", func() {
var (
mb *machineTestBuilder
testDir string
)
BeforeEach(func() {
testDir, mb = setup()
})
AfterEach(func() {
teardown(originalHomeDir, testDir, mb)
})
It("Basic ops", func() {
// golangci-lint has trouble with actually skipping tests marked Skip
// so skip it on cirrus envs and where CIRRUS_CI isn't set.
name := randomString()
i := new(initMachine)
session, err := mb.setName(name).setCmd(i.withImage(mb.imagePath).withNow()).run()
Expect(err).ToNot(HaveOccurred())
Expect(session).To(Exit(0))
bm := basicMachine{}
imgs, err := mb.setCmd(bm.withPodmanCommand([]string{"images", "-q"})).run()
Expect(err).ToNot(HaveOccurred())
Expect(imgs).To(Exit(0))
Expect(imgs.outputToStringSlice()).To(BeEmpty())
newImgs, err := mb.setCmd(bm.withPodmanCommand([]string{"pull", "quay.io/libpod/alpine_nginx"})).run()
Expect(err).ToNot(HaveOccurred())
Expect(newImgs).To(Exit(0))
Expect(newImgs.outputToStringSlice()).To(HaveLen(1))
runAlp, err := mb.setCmd(bm.withPodmanCommand([]string{"run", "quay.io/libpod/alpine_nginx", "cat", "/etc/os-release"})).run()
Expect(err).ToNot(HaveOccurred())
Expect(runAlp).To(Exit(0))
Expect(runAlp.outputToString()).To(ContainSubstring("Alpine Linux"))
contextDir := GinkgoT().TempDir()
cfile := filepath.Join(contextDir, "Containerfile")
err = os.WriteFile(cfile, []byte("FROM quay.io/libpod/alpine_nginx\nRUN ip addr\n"), 0o644)
Expect(err).ToNot(HaveOccurred())
build, err := mb.setCmd(bm.withPodmanCommand([]string{"build", contextDir})).run()
Expect(err).ToNot(HaveOccurred())
Expect(build).To(Exit(0))
Expect(build.outputToString()).To(ContainSubstring("COMMIT"))
rmCon, err := mb.setCmd(bm.withPodmanCommand([]string{"rm", "-a"})).run()
Expect(err).ToNot(HaveOccurred())
Expect(rmCon).To(Exit(0))
})
It("Volume ops", func() {
skipIfVmtype(define.HyperVVirt, "FIXME: #21036 - Hyper-V podman run -v fails due to path translation issues")
tDir, err := filepath.Abs(GinkgoT().TempDir())
Expect(err).ToNot(HaveOccurred())
roFile := filepath.Join(tDir, "attr-test-file")
// Create the file as ready-only, since some platforms disallow selinux attr writes
// The subsequent Z mount should still succeed in spite of that
rf, err := os.OpenFile(roFile, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0o444)
Expect(err).ToNot(HaveOccurred())
rf.Close()
name := randomString()
i := new(initMachine).withImage(mb.imagePath).withNow()
// All other platforms have an implicit mount for the temp area
if isVmtype(define.QemuVirt) {
i.withVolume(tDir)
}
session, err := mb.setName(name).setCmd(i).run()
Expect(err).ToNot(HaveOccurred())
Expect(session).To(Exit(0))
bm := basicMachine{}
// Test relabel works on all platforms
runAlp, err := mb.setCmd(bm.withPodmanCommand([]string{"run", "-v", tDir + ":/test:Z", "quay.io/libpod/alpine_nginx", "ls", "/test/attr-test-file"})).run()
Expect(err).ToNot(HaveOccurred())
Expect(runAlp).To(Exit(0))
})
It("Podman ops with port forwarding and gvproxy", func() {
name := randomString()
i := new(initMachine)
session, err := mb.setName(name).setCmd(i.withImage(mb.imagePath).withNow()).run()
Expect(err).ToNot(HaveOccurred())
Expect(session).To(Exit(0))
ctrName := "test"
bm := basicMachine{}
runAlp, err := mb.setCmd(bm.withPodmanCommand([]string{"run", "-dt", "--name", ctrName, "-p", "62544:80", "quay.io/libpod/alpine_nginx"})).run()
Expect(err).ToNot(HaveOccurred())
Expect(runAlp).To(Exit(0))
testHTTPServer("62544", false, "podman rulez")
// Test exec in machine scenario: https://github.com/containers/podman/issues/20821
exec, err := mb.setCmd(bm.withPodmanCommand([]string{"exec", ctrName, "true"})).run()
Expect(err).ToNot(HaveOccurred())
Expect(exec).To(Exit(0))
out, err := pgrep("gvproxy")
Expect(err).ToNot(HaveOccurred())
Expect(out).ToNot(BeEmpty())
rmCon, err := mb.setCmd(bm.withPodmanCommand([]string{"rm", "-af"})).run()
Expect(err).ToNot(HaveOccurred())
Expect(rmCon).To(Exit(0))
testHTTPServer("62544", true, "")
stop := new(stopMachine)
stopSession, err := mb.setCmd(stop).run()
Expect(err).ToNot(HaveOccurred())
Expect(stopSession).To(Exit(0))
// gxproxy should exit after machine is stopped
out, _ = pgrep("gvproxy")
Expect(out).ToNot(ContainSubstring("gvproxy"))
})
It("podman volume on non-standard path", func() {
skipIfWSL("Requires standard volume handling")
dir, err := os.MkdirTemp("", "machine-volume")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(dir)
testString := "abcdefg1234567"
testFile := "testfile"
err = os.WriteFile(filepath.Join(dir, testFile), []byte(testString), 0644)
Expect(err).ToNot(HaveOccurred())
name := randomString()
machinePath := "/does/not/exist"
init := new(initMachine).withVolume(fmt.Sprintf("%s:%s", dir, machinePath)).withImage(mb.imagePath).withNow()
session, err := mb.setName(name).setCmd(init).run()
Expect(err).ToNot(HaveOccurred())
Expect(session).To(Exit(0))
// Must use path.Join to ensure forward slashes are used, even on Windows.
ssh := new(sshMachine).withSSHCommand([]string{"cat", path.Join(machinePath, testFile)})
ls, err := mb.setName(name).setCmd(ssh).run()
Expect(err).ToNot(HaveOccurred())
Expect(ls).To(Exit(0))
Expect(ls.outputToString()).To(ContainSubstring(testString))
})
})
func testHTTPServer(port string, shouldErr bool, expectedResponse string) {
address := url.URL{
Scheme: "http",
Host: net.JoinHostPort("localhost", port),
}
interval := 250 * time.Millisecond
var err error
var resp *http.Response
for i := 0; i < 6; i++ {
resp, err = http.Get(address.String())
if err != nil && shouldErr {
Expect(err.Error()).To(ContainSubstring(expectedResponse))
return
}
if err == nil {
defer resp.Body.Close()
break
}
time.Sleep(interval)
interval *= 2
}
Expect(err).ToNot(HaveOccurred())
body, err := io.ReadAll(resp.Body)
Expect(err).ToNot(HaveOccurred())
Expect(string(body)).Should(Equal(expectedResponse))
}