Skip to content

Commit

Permalink
Merge pull request #7588 from HarryMichal/add-toolbox-e2e-tests
Browse files Browse the repository at this point in the history
tests/e2e: Add Toolbox-specific test cases
  • Loading branch information
openshift-merge-robot authored Oct 12, 2020
2 parents e8f48a1 + a1e1a3a commit ce7478b
Show file tree
Hide file tree
Showing 2 changed files with 369 additions and 0 deletions.
1 change: 1 addition & 0 deletions test/e2e/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var (
BB = "docker.io/library/busybox:latest"
healthcheck = "docker.io/libpod/alpine_healthcheck:latest"
ImageCacheDir = "/tmp/podman/imagecachedir"
fedoraToolbox = "registry.fedoraproject.org/f32/fedora-toolbox:latest"

// This image has seccomp profiles that blocks all syscalls.
// The intention behind blocking all syscalls is to prevent
Expand Down
368 changes: 368 additions & 0 deletions test/e2e/toolbox_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,368 @@
package integration

/*
toolbox_test.go is under the care of the Toolbox Team.
The tests are trying to stress parts of Podman that Toolbox[0] needs for
its functionality.
[0] https://github.com/containers/toolbox
Info about test cases:
- some tests rely on a certain configuration of a container that is done by
executing several commands in the entry-point of a container. To make
sure the initialization had enough time to be executed,
WaitContainerReady() after the container is started.
- in several places there's an invocation of 'podman logs' It is there mainly
to ease debugging when a test goes wrong (during the initialization of a
container) but sometimes it is also used in the test case itself.
Maintainers (Toolbox Team):
- Ondřej Míchal <[email protected]>
- Debarshi Ray <[email protected]>
Also available on Freenode IRC on #silverblue or #podman
*/

import (
"fmt"
"os"
"os/exec"
"os/user"
"strconv"
"strings"
"syscall"

. "github.com/containers/podman/v2/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Toolbox-specific testing", 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 --dns=none - allows self-management of /etc/resolv.conf", func() {
var session *PodmanSessionIntegration

session = podmanTest.Podman([]string{"run", "--dns", "none", ALPINE, "sh", "-c",
"rm -f /etc/resolv.conf; touch -d '1970-01-01 00:02:03' /etc/resolv.conf; stat -c %s:%Y /etc/resolv.conf"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("0:123"))
})

It("podman run --no-hosts - allows self-management of /etc/hosts", func() {
var session *PodmanSessionIntegration

session = podmanTest.Podman([]string{"run", "--no-hosts", ALPINE, "sh", "-c",
"rm -f /etc/hosts; touch -d '1970-01-01 00:02:03' /etc/hosts; stat -c %s:%Y /etc/hosts"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("0:123"))
})

It("podman create --ulimit host + podman exec - correctly mirrors hosts ulimits", func() {
if podmanTest.RemoteTest {
Skip("Ulimit check does not work with a remote client")
}
var session *PodmanSessionIntegration
var containerHardLimit int
var rlimit syscall.Rlimit
var err error

err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit)
Expect(err).To(BeNil())
fmt.Printf("Expected value: %d", rlimit.Max)

session = podmanTest.Podman([]string{"create", "--name", "test", "--ulimit", "host", ALPINE,
"sleep", "1000"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

session = podmanTest.Podman([]string{"start", "test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

session = podmanTest.Podman([]string{"exec", "test", "sh", "-c",
"ulimit -H -n"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
containerHardLimit, err = strconv.Atoi(strings.Trim(session.OutputToString(), "\n"))
Expect(err).To(BeNil())
Expect(containerHardLimit).To(BeNumerically(">=", rlimit.Max))
})

It("podman create --ipc=host --pid=host + podman exec - correct shared memory limit size", func() {
// Comparison of the size of /dev/shm on the host being equal to the one in
// a container
if podmanTest.RemoteTest {
Skip("Shm size check does not work with a remote client")
}
var session *PodmanSessionIntegration
var cmd *exec.Cmd
var hostShmSize, containerShmSize int
var err error

// Because Alpine uses busybox, most commands don't offer advanced options
// like "--output" in df. Therefore the value of the field 'Size' (or
// ('1K-blocks') needs to be extracted manually.
cmd = exec.Command("df", "/dev/shm")
res, err := cmd.Output()
Expect(err).To(BeNil())
lines := strings.SplitN(string(res), "\n", 2)
fields := strings.Fields(lines[len(lines)-1])
hostShmSize, err = strconv.Atoi(fields[1])
Expect(err).To(BeNil())

session = podmanTest.Podman([]string{"create", "--name", "test", "--ipc=host", "--pid=host", ALPINE,
"sleep", "1000"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

session = podmanTest.Podman([]string{"start", "test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

session = podmanTest.Podman([]string{"exec", "test",
"df", "/dev/shm"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
lines = session.OutputToStringArray()
fields = strings.Fields(lines[len(lines)-1])
containerShmSize, err = strconv.Atoi(fields[1])
Expect(err).To(BeNil())

// In some cases it may happen that the size of /dev/shm is not exactly
// equal. Therefore it's fine if there's a slight tolerance between the
// compared values.
Expect(hostShmSize).To(BeNumerically("~", containerShmSize, 100))
})

It("podman create --userns=keep-id --user root:root - entrypoint - entrypoint is executed as root", func() {
var session *PodmanSessionIntegration

session = podmanTest.Podman([]string{"run", "--userns=keep-id", "--user", "root:root", ALPINE,
"id"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("uid=0(root) gid=0(root)"))
})

It("podman create --userns=keep-id + podman exec - correct names of user and group", func() {
var session *PodmanSessionIntegration
var err error

currentUser, err := user.Current()
Expect(err).To(BeNil())

currentGroup, err := user.LookupGroupId(currentUser.Gid)
Expect(err).To(BeNil())

session = podmanTest.Podman([]string{"create", "--name", "test", "--userns=keep-id", ALPINE,
"sleep", "1000"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(err).To(BeNil())

session = podmanTest.Podman([]string{"start", "test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

expectedOutput := fmt.Sprintf("uid=%s(%s) gid=%s(%s)",
currentUser.Uid, currentUser.Username,
currentGroup.Gid, currentGroup.Name)

session = podmanTest.Podman([]string{"exec", "test",
"id"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(expectedOutput))
})

It("podman create --userns=keep-id - entrypoint - adding user with useradd and then removing their password", func() {
var session *PodmanSessionIntegration

var username string = "testuser"
var homeDir string = "/home/testuser"
var shell string = "/bin/sh"
var uid string = "1001"
var gid string = "1001"

useradd := fmt.Sprintf("useradd --home-dir %s --shell %s --uid %s %s",
homeDir, shell, uid, username)
passwd := fmt.Sprintf("passwd --delete %s", username)

session = podmanTest.Podman([]string{"create", "--name", "test", "--userns=keep-id", "--user", "root:root", fedoraToolbox, "sh", "-c",
fmt.Sprintf("%s; %s; echo READY; sleep 1000", useradd, passwd)})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

session = podmanTest.Podman([]string{"start", "test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

Expect(WaitContainerReady(podmanTest, "test", "READY", 2, 1)).To(BeTrue())

expectedOutput := fmt.Sprintf("%s:x:%s:%s::%s:%s",
username, uid, gid, homeDir, shell)

session = podmanTest.Podman([]string{"exec", "test", "cat", "/etc/passwd"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(expectedOutput))

expectedOutput = "passwd: Note: deleting a password also unlocks the password."

session = podmanTest.Podman([]string{"logs", "test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(expectedOutput))
})

It("podman create --userns=keep-id + podman exec - adding group with groupadd", func() {
var session *PodmanSessionIntegration

var groupName string = "testgroup"
var gid string = "1001"

groupadd := fmt.Sprintf("groupadd --gid %s %s", gid, groupName)

session = podmanTest.Podman([]string{"create", "--name", "test", "--userns=keep-id", "--user", "root:root", fedoraToolbox, "sh", "-c",
fmt.Sprintf("%s; echo READY; sleep 1000", groupadd)})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

session = podmanTest.Podman([]string{"start", "test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

Expect(WaitContainerReady(podmanTest, "test", "READY", 2, 1)).To(BeTrue())

session = podmanTest.Podman([]string{"exec", "test", "cat", "/etc/group"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(groupName))

session = podmanTest.Podman([]string{"logs", "test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("READY"))
})

It("podman create --userns=keep-id - entrypoint - modifying existing user with usermod - add to new group, change home/shell/uid", func() {
var session *PodmanSessionIntegration
var badHomeDir string = "/home/badtestuser"
var badShell string = "/bin/sh"
var badUID string = "1001"
var username string = "testuser"
var homeDir string = "/home/testuser"
var shell string = "/bin/bash"
var uid string = "2000"
var groupName string = "testgroup"
var gid string = "2000"

// The use of bad* in the name of variables does not imply the invocation
// of useradd should fail The user is supposed to be created successfuly
// but later his information (uid, home, shell,..) is changed via usermod.
useradd := fmt.Sprintf("useradd --home-dir %s --shell %s --uid %s %s",
badHomeDir, badShell, badUID, username)
groupadd := fmt.Sprintf("groupadd --gid %s %s",
gid, groupName)
usermod := fmt.Sprintf("usermod --append --groups wheel --home %s --shell %s --uid %s --gid %s %s",
homeDir, shell, uid, gid, username)

session = podmanTest.Podman([]string{"create", "--name", "test", "--userns=keep-id", "--user", "root:root", fedoraToolbox, "sh", "-c",
fmt.Sprintf("%s; %s; %s; echo READY; sleep 1000", useradd, groupadd, usermod)})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

session = podmanTest.Podman([]string{"start", "test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

Expect(WaitContainerReady(podmanTest, "test", "READY", 2, 1)).To(BeTrue())

expectedUser := fmt.Sprintf("%s:x:%s:%s::%s:%s",
username, uid, gid, homeDir, shell)

session = podmanTest.Podman([]string{"exec", "test", "cat", "/etc/passwd"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(expectedUser))

session = podmanTest.Podman([]string{"logs", "test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("READY"))
})

It("podman run --privileged --userns=keep-id --user root:root - entrypoint - (bind)mounting", func() {
var session *PodmanSessionIntegration

session = podmanTest.Podman([]string{"run", "--privileged", "--userns=keep-id", "--user", "root:root", ALPINE,
"mount", "-t", "tmpfs", "tmpfs", "/tmp"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

session = podmanTest.Podman([]string{"run", "--privileged", "--userns=keep-id", "--user", "root:root", ALPINE,
"mount", "--rbind", "/tmp", "/var/tmp"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
})

It("podman create + start - with all needed switches for create - sleep as entry-point", func() {
var session *PodmanSessionIntegration

// These should be most of the switches that Toolbox uses to create a "toolbox" container
// https://github.com/containers/toolbox/blob/master/src/cmd/create.go
session = podmanTest.Podman([]string{"create",
"--dns", "none",
"--hostname", "toolbox",
"--ipc", "host",
"--label", "com.github.containers.toolbox=true",
"--name", "test",
"--network", "host",
"--no-hosts",
"--pid", "host",
"--privileged",
"--security-opt", "label=disable",
"--ulimit", "host",
"--userns=keep-id",
"--user", "root:root",
fedoraToolbox, "sh", "-c", "echo READY; sleep 1000"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

session = podmanTest.Podman([]string{"start", "test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

Expect(WaitContainerReady(podmanTest, "test", "READY", 2, 1)).To(BeTrue())

session = podmanTest.Podman([]string{"logs", "test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("READY"))
})
})

0 comments on commit ce7478b

Please sign in to comment.