diff options
64 files changed, 426 insertions, 338 deletions
@@ -3,7 +3,7 @@ export GOPROXY=https://proxy.golang.org GO ?= go DESTDIR ?= -EPOCH_TEST_COMMIT ?= dc1f8b62b168e0815ed5e7eb7c61a26ec3a0c88c +EPOCH_TEST_COMMIT ?= 2b0892e757c878cdb087dd22b8986bccef0276ed HEAD ?= HEAD CHANGELOG_BASE ?= HEAD~ CHANGELOG_TARGET ?= HEAD @@ -5,7 +5,7 @@ Libpod provides a library for applications looking to use the Container Pod concept, popularized by Kubernetes. Libpod also contains the Pod Manager tool `(Podman)`. Podman manages pods, containers, container images, and container volumes. -* [Latest Version: 1.6.0](https://github.com/containers/libpod/releases/latest) +* [Latest Version: 1.6.2](https://github.com/containers/libpod/releases/latest) * [Continuous Integration:](contrib/cirrus/README.md) [![Build Status](https://api.cirrus-ci.com/github/containers/libpod.svg)](https://cirrus-ci.com/github/containers/libpod/master) * [GoDoc: ![GoDoc](https://godoc.org/github.com/containers/libpod/libpod?status.svg)](https://godoc.org/github.com/containers/libpod/libpod) * Automated continuous release downloads (including remote-client): diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 0f2e748fa..235871273 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -22,9 +22,11 @@ - Fixed a bug where `podman stats` was broken on systems running CGroups V2 when run rootless ([#4268](https://github.com/containers/libpod/issues/4268)) - Fixed a bug where the `podman start` command would print the short container ID, instead of the full ID - Fixed a bug where containers created with an OCI runtime that is no longer available (uninstalled or removed from the config file) would not appear in `podman ps` and could not be removed via `podman rm` +- Fixed a bug where containers restored via `podman container restore --import` would retain the CGroup path of the original container, even if their container ID changed; thus, multiple containers created from the same checkpoint would all share the same CGroup ### Misc - The default PID limit for containers is now set to 4096. It can be adjusted back to the old default (unlimited) by passing `--pids-limit 0` to `podman create` and `podman run` +- The `podman start --attach` command now automatically attaches `STDIN` if the container was created with `-i` - The `podman network create` command now validates network names using the same regular expression as container and pod names - The `--systemd` flag to `podman run` and `podman create` will now only enable systemd mode when the binary being run inside the container is `/sbin/init`, `/usr/sbin/init`, or ends in `systemd` (previously detected any path ending in `init` or `systemd`) - Updated vendored Buildah to 1.11.3 diff --git a/changelog.txt b/changelog.txt index dd3fcec82..615e2a135 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,11 @@ +- Changelog for v1.6.2 (2019-10-17) + * Finalize release notes for v1.6.2 + * rootless: drop dependency on docker + * Bump gitvalidation epoch + * Bump to v1.6.2-dev + * Refactor tests when checking for error exit codes + * Attach stdin to container at start if it was created with --interactive + - Changelog for v1.6.2-rc1 (2019-10-16) * Add release notes for Podman 1.6.2 * start: print full container ID diff --git a/cmd/podman/run.go b/cmd/podman/run.go index 4836c99dc..7aa4cb3c4 100644 --- a/cmd/podman/run.go +++ b/cmd/podman/run.go @@ -45,7 +45,6 @@ func runCmd(c *cliconfig.RunValues) error { span, _ := opentracing.StartSpanFromContext(Ctx, "runCmd") defer span.Finish() } - if err := createInit(&c.PodmanCommand); err != nil { return err } diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in index bd2cff3f6..d5247f689 100644 --- a/contrib/spec/podman.spec.in +++ b/contrib/spec/podman.spec.in @@ -39,7 +39,7 @@ %global shortcommit_conmon %(c=%{commit_conmon}; echo ${c:0:7}) Name: podman -Version: 1.6.2 +Version: 1.6.3 Release: #COMMITDATE#.git%{shortcommit0}%{?dist} Summary: Manage Pods, Containers and Container Images License: ASL 2.0 diff --git a/libpod/runtime.go b/libpod/runtime.go index a0cf0ad7c..8f145a809 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -14,7 +14,6 @@ import ( "strings" "sync" "syscall" - "time" "github.com/BurntSushi/toml" is "github.com/containers/image/v4/storage" @@ -353,10 +352,6 @@ func defaultRuntimeConfig() (RuntimeConfig, error) { // SetXdgDirs ensures the XDG_RUNTIME_DIR env and XDG_CONFIG_HOME variables are set. // containers/image uses XDG_RUNTIME_DIR to locate the auth file, XDG_CONFIG_HOME is // use for the libpod.conf configuration file. -// SetXdgDirs internally calls EnableLinger() so that the user's processes are not -// killed once the session is terminated. EnableLinger() also attempts to -// get the runtime directory when XDG_RUNTIME_DIR is not specified. -// This function should only be called when running rootless. func SetXdgDirs() error { if !rootless.IsRootless() { return nil @@ -365,21 +360,6 @@ func SetXdgDirs() error { // Setup XDG_RUNTIME_DIR runtimeDir := os.Getenv("XDG_RUNTIME_DIR") - runtimeDirLinger, err := rootless.EnableLinger() - if err != nil { - return errors.Wrapf(err, "error enabling user session") - } - if runtimeDir == "" && runtimeDirLinger != "" { - if _, err := os.Stat(runtimeDirLinger); err != nil && os.IsNotExist(err) { - chWait := make(chan error) - defer close(chWait) - if _, err := WaitForFile(runtimeDirLinger, chWait, time.Second*10); err != nil { - return errors.Wrapf(err, "waiting for directory '%s'", runtimeDirLinger) - } - } - runtimeDir = runtimeDirLinger - } - if runtimeDir == "" { var err error runtimeDir, err = util.GetRuntimeDir() @@ -400,10 +380,11 @@ func SetXdgDirs() error { // Setup XDG_CONFIG_HOME if cfgHomeDir := os.Getenv("XDG_CONFIG_HOME"); cfgHomeDir == "" { - if cfgHomeDir, err = util.GetRootlessConfigHomeDir(); err != nil { + cfgHomeDir, err := util.GetRootlessConfigHomeDir() + if err != nil { return err } - if err = os.Setenv("XDG_CONFIG_HOME", cfgHomeDir); err != nil { + if err := os.Setenv("XDG_CONFIG_HOME", cfgHomeDir); err != nil { return errors.Wrapf(err, "cannot set XDG_CONFIG_HOME") } } @@ -528,6 +509,17 @@ func newRuntimeFromConfig(ctx context.Context, userConfigPath string, options .. return nil, err } + // storage.conf + storageConfFile, err := storage.DefaultConfigFile(rootless.IsRootless()) + if err != nil { + return nil, err + } + + createStorageConfFile := false + if _, err := os.Stat(storageConfFile); os.IsNotExist(err) { + createStorageConfFile = true + } + defRunConf, err := defaultRuntimeConfig() if err != nil { return nil, err @@ -702,27 +694,21 @@ func newRuntimeFromConfig(ctx context.Context, userConfigPath string, options .. } if rootless.IsRootless() && configPath == "" { - configPath, err := getRootlessConfigPath() - if err != nil { - return nil, err - } - - // storage.conf - storageConfFile, err := storage.DefaultConfigFile(rootless.IsRootless()) - if err != nil { - return nil, err - } - if _, err := os.Stat(storageConfFile); os.IsNotExist(err) { + if createStorageConfFile { if err := util.WriteStorageConfigFile(&runtime.config.StorageConfig, storageConfFile); err != nil { return nil, errors.Wrapf(err, "cannot write config file %s", storageConfFile) } } + configPath, err := getRootlessConfigPath() + if err != nil { + return nil, err + } if configPath != "" { - if err := os.MkdirAll(filepath.Dir(configPath), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(configPath), 0711); err != nil { return nil, err } - file, err := os.OpenFile(configPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) + file, err := os.OpenFile(configPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) if err != nil && !os.IsExist(err) { return nil, errors.Wrapf(err, "cannot open file %s", configPath) } diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go index 12fd98486..5c33467a7 100644 --- a/pkg/adapter/containers.go +++ b/pkg/adapter/containers.go @@ -612,7 +612,9 @@ func (r *LocalRuntime) Start(ctx context.Context, c *cliconfig.StartValues, sigP if c.Attach { inputStream := os.Stdin if !c.Interactive { - inputStream = nil + if !ctr.Stdin() { + inputStream = nil + } } // attach to the container and also start it not already running diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go index f7cb28b0c..f4e83a975 100644 --- a/pkg/adapter/containers_remote.go +++ b/pkg/adapter/containers_remote.go @@ -1092,6 +1092,7 @@ func configureVarlinkAttachStdio(reader *bufio.Reader, writer *bufio.Writer, std // These are the special writers that encode input from the client. varlinkStdinWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.ToStdin) varlinkResizeWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.TerminalResize) + varlinkHangupWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.HangUpFromClient) go func() { // Read from the wire and direct to stdout or stderr @@ -1117,7 +1118,6 @@ func configureVarlinkAttachStdio(reader *bufio.Reader, writer *bufio.Writer, std } } }() - if stdin != nil { // Takes stdinput and sends it over the wire after being encoded go func() { @@ -1126,7 +1126,12 @@ func configureVarlinkAttachStdio(reader *bufio.Reader, writer *bufio.Writer, std sendGenericError(ecChan) errChan <- err } - + _, err := varlinkHangupWriter.Write([]byte("EOF")) + if err != nil { + logrus.Errorf("unable to notify server to hangup: %q", err) + } + err = varlinkStdinWriter.Close() + errChan <- err }() } return errChan diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index 99307e8c4..94c42f7d0 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -11,20 +11,16 @@ import ( "os/exec" gosignal "os/signal" "os/user" - "path/filepath" "runtime" "strconv" - "strings" "sync" - "syscall" "unsafe" "github.com/containers/libpod/pkg/errorhandling" "github.com/containers/storage/pkg/idtools" - "github.com/docker/docker/pkg/signal" - "github.com/godbus/dbus" "github.com/pkg/errors" "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" ) /* @@ -130,7 +126,7 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap) func readUserNs(path string) (string, error) { b := make([]byte, 256) - _, err := syscall.Readlink(path, b) + _, err := unix.Readlink(path, b) if err != nil { return "", err } @@ -143,7 +139,7 @@ func readUserNsFd(fd uintptr) (string, error) { func getParentUserNs(fd uintptr) (uintptr, error) { const nsGetParent = 0xb702 - ret, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(nsGetParent), 0) + ret, _, errno := unix.Syscall(unix.SYS_IOCTL, fd, uintptr(nsGetParent), 0) if errno != 0 { return 0, errno } @@ -179,7 +175,7 @@ func getUserNSFirstChild(fd uintptr) (*os.File, error) { for { nextFd, err := getParentUserNs(fd) if err != nil { - if err == syscall.ENOTTY { + if err == unix.ENOTTY { return os.NewFile(fd, "userns child"), nil } return nil, errors.Wrapf(err, "cannot get parent user namespace") @@ -191,14 +187,14 @@ func getUserNSFirstChild(fd uintptr) (*os.File, error) { } if ns == currentNS { - if err := syscall.Close(int(nextFd)); err != nil { + if err := unix.Close(int(nextFd)); err != nil { return nil, err } // Drop O_CLOEXEC for the fd. - _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, fd, syscall.F_SETFD, 0) + _, _, errno := unix.Syscall(unix.SYS_FCNTL, fd, unix.F_SETFD, 0) if errno != 0 { - if err := syscall.Close(int(fd)); err != nil { + if err := unix.Close(int(fd)); err != nil { logrus.Errorf("failed to close file descriptor %d", fd) } return nil, errno @@ -206,99 +202,13 @@ func getUserNSFirstChild(fd uintptr) (*os.File, error) { return os.NewFile(fd, "userns child"), nil } - if err := syscall.Close(int(fd)); err != nil { + if err := unix.Close(int(fd)); err != nil { return nil, err } fd = nextFd } } -// EnableLinger configures the system to not kill the user processes once the session -// terminates -func EnableLinger() (string, error) { - uid := fmt.Sprintf("%d", GetRootlessUID()) - - conn, err := dbus.SystemBus() - if err == nil { - defer func() { - if err := conn.Close(); err != nil { - logrus.Errorf("unable to close dbus connection: %q", err) - } - }() - } - - lingerEnabled := false - - // If we have a D-BUS connection, attempt to read the LINGER property from it. - if conn != nil { - path := dbus.ObjectPath(fmt.Sprintf("/org/freedesktop/login1/user/_%s", uid)) - ret, err := conn.Object("org.freedesktop.login1", path).GetProperty("org.freedesktop.login1.User.Linger") - if err == nil && ret.Value().(bool) { - lingerEnabled = true - } - } - - xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR") - lingerFile := "" - if xdgRuntimeDir != "" && !lingerEnabled { - lingerFile = filepath.Join(xdgRuntimeDir, "libpod/linger") - _, err := os.Stat(lingerFile) - if err == nil { - lingerEnabled = true - } - } - - if !lingerEnabled { - // First attempt with D-BUS, if it fails, then attempt with "loginctl enable-linger" - if conn != nil { - o := conn.Object("org.freedesktop.login1", "/org/freedesktop/login1") - ret := o.Call("org.freedesktop.login1.Manager.SetUserLinger", 0, uint32(GetRootlessUID()), true, true) - if ret.Err == nil { - lingerEnabled = true - } - } - if !lingerEnabled { - err := exec.Command("loginctl", "enable-linger", uid).Run() - if err == nil { - lingerEnabled = true - } else { - logrus.Debugf("cannot run `loginctl enable-linger` for the current user: %v", err) - } - } - if lingerEnabled && lingerFile != "" { - f, err := os.Create(lingerFile) - if err == nil { - if err := f.Close(); err != nil { - logrus.Errorf("failed to close %s", f.Name()) - } - } else { - logrus.Debugf("could not create linger file: %v", err) - } - } - } - - if !lingerEnabled { - return "", nil - } - - // If we have a D-BUS connection, attempt to read the RUNTIME PATH from it. - if conn != nil { - path := dbus.ObjectPath(fmt.Sprintf("/org/freedesktop/login1/user/_%s", uid)) - ret, err := conn.Object("org.freedesktop.login1", path).GetProperty("org.freedesktop.login1.User.RuntimePath") - if err == nil { - return strings.Trim(ret.String(), "\"\n"), nil - } - } - - // If XDG_RUNTIME_DIR is not set and the D-BUS call didn't work, try to get the runtime path with "loginctl" - output, err := exec.Command("loginctl", "-pRuntimePath", "show-user", uid).Output() - if err != nil { - logrus.Debugf("could not get RuntimePath using loginctl: %v", err) - return "", nil - } - return strings.Trim(strings.Replace(string(output), "RuntimePath=", "", -1), "\"\n"), nil -} - // joinUserAndMountNS re-exec podman in a new userNS and join the user and mount // namespace of the specified PID without looking up its parent. Useful to join directly // the conmon process. @@ -394,7 +304,7 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool, runtime.LockOSThread() defer runtime.UnlockOSThread() - fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0) + fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_DGRAM, 0) if err != nil { return false, -1, err } @@ -491,21 +401,21 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool, signals := []os.Signal{} for sig := 0; sig < numSig; sig++ { - if sig == int(syscall.SIGTSTP) { + if sig == int(unix.SIGTSTP) { continue } - signals = append(signals, syscall.Signal(sig)) + signals = append(signals, unix.Signal(sig)) } gosignal.Notify(c, signals...) defer gosignal.Reset() go func() { for s := range c { - if s == signal.SIGCHLD || s == signal.SIGPIPE { + if s == unix.SIGCHLD || s == unix.SIGPIPE { continue } - if err := syscall.Kill(int(pidC), s.(syscall.Signal)); err != nil { + if err := unix.Kill(int(pidC), s.(unix.Signal)); err != nil { logrus.Errorf("failed to kill %d", int(pidC)) } } @@ -560,7 +470,7 @@ func TryJoinFromFilePaths(pausePidPath string, needNewNamespace bool, paths []st lastErr = nil break } else { - fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0) + fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_DGRAM, 0) if err != nil { lastErr = err continue diff --git a/pkg/rootless/rootless_unsupported.go b/pkg/rootless/rootless_unsupported.go index ce488f364..1499b737f 100644 --- a/pkg/rootless/rootless_unsupported.go +++ b/pkg/rootless/rootless_unsupported.go @@ -37,12 +37,6 @@ func GetRootlessGID() int { return -1 } -// EnableLinger configures the system to not kill the user processes once the session -// terminates -func EnableLinger() (string, error) { - return "", nil -} - // TryJoinFromFilePaths attempts to join the namespaces of the pid files in paths. // This is useful when there are already running containers and we // don't have a pause process yet. We can use the paths to the conmon diff --git a/pkg/util/utils.go b/pkg/util/utils.go index 0190b106d..d9a84e4e5 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -318,7 +318,7 @@ func WriteStorageConfigFile(storageOpts *storage.StoreOptions, storageConf strin if err := os.MkdirAll(filepath.Dir(storageConf), 0755); err != nil { return err } - storageFile, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) + storageFile, err := os.OpenFile(storageConf, os.O_RDWR|os.O_TRUNC, 0600) if err != nil { return errors.Wrapf(err, "cannot open %s", storageConf) } diff --git a/pkg/varlinkapi/attach.go b/pkg/varlinkapi/attach.go index f8557ae0c..37adbbf55 100644 --- a/pkg/varlinkapi/attach.go +++ b/pkg/varlinkapi/attach.go @@ -70,7 +70,6 @@ func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys st } reader, writer, _, pw, streams := setupStreams(call) - go func() { if err := virtwriter.Reader(reader, nil, nil, pw, resize, nil); err != nil { errChan <- err diff --git a/pkg/varlinkapi/virtwriter/virtwriter.go b/pkg/varlinkapi/virtwriter/virtwriter.go index 27ecd1f52..dd171943f 100644 --- a/pkg/varlinkapi/virtwriter/virtwriter.go +++ b/pkg/varlinkapi/virtwriter/virtwriter.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "encoding/json" "io" + "time" "github.com/pkg/errors" "k8s.io/client-go/tools/remotecommand" @@ -26,8 +27,14 @@ const ( TerminalResize SocketDest = iota // Quit and detach Quit SocketDest = iota + // Quit from the client + HangUpFromClient SocketDest = iota ) +// ClientHangup signifies that the client wants to drop its +// connection from the server +var ClientHangup = errors.New("client hangup") + // IntToSocketDest returns a socketdest based on integer input func IntToSocketDest(i int) SocketDest { switch i { @@ -41,6 +48,8 @@ func IntToSocketDest(i int) SocketDest { return TerminalResize case Quit.Int(): return Quit + case HangUpFromClient.Int(): + return HangUpFromClient default: return ToStderr } @@ -65,7 +74,7 @@ func NewVirtWriteCloser(w *bufio.Writer, dest SocketDest) VirtWriteCloser { // Close is a required method for a writecloser func (v VirtWriteCloser) Close() error { - return nil + return v.writer.Flush() } // Write prepends a header to the input message. The header is @@ -96,7 +105,6 @@ func Reader(r *bufio.Reader, output, errput, input io.Writer, resize chan remote if r == nil { return errors.Errorf("Reader must not be nil") } - for { n, err := io.ReadFull(r, headerBytes) if err != nil { @@ -107,7 +115,6 @@ func Reader(r *bufio.Reader, output, errput, input io.Writer, resize chan remote } messageSize = int64(binary.BigEndian.Uint32(headerBytes[4:8])) - switch IntToSocketDest(int(headerBytes[0])) { case ToStdout: if output != nil { @@ -161,7 +168,16 @@ func Reader(r *bufio.Reader, output, errput, input io.Writer, resize chan remote execEcChan <- int(ecInt) } return nil - + case HangUpFromClient: + // This sleep allows the pipes to flush themselves before tearing everything down. + // It makes me sick to do it but after a full day I cannot put my finger on the race + // that occurs when closing things up. It would require a significant rewrite of code + // to make the pipes close down properly. Given that we are currently discussing a + // rewrite of all things remote, this hardly seems worth resolving. + // + // reproducer: echo hello | (podman-remote run -i alpine cat) + time.Sleep(1 * time.Second) + return ClientHangup default: // Something really went wrong return errors.New("unknown multiplex destination") diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go index 1caefd299..4b43ceb30 100644 --- a/test/e2e/checkpoint_test.go +++ b/test/e2e/checkpoint_test.go @@ -67,13 +67,13 @@ var _ = Describe("Podman checkpoint", func() { It("podman checkpoint bogus container", func() { session := podmanTest.Podman([]string{"container", "checkpoint", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman restore bogus container", func() { session := podmanTest.Podman([]string{"container", "restore", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman checkpoint a running container by id", func() { diff --git a/test/e2e/cp_test.go b/test/e2e/cp_test.go index 3317683de..8d4c3dee7 100644 --- a/test/e2e/cp_test.go +++ b/test/e2e/cp_test.go @@ -53,7 +53,7 @@ var _ = Describe("Podman cp", func() { session = podmanTest.Podman([]string{"cp", srcPath, name + ":foo/"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) session = podmanTest.Podman([]string{"cp", srcPath, name + ":foo"}) session.WaitWithDefaultTimeout() @@ -205,7 +205,7 @@ var _ = Describe("Podman cp", func() { session = podmanTest.Podman([]string{"cp", "--pause=false", srcPath, name + ":/test1/"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman cp volume", func() { diff --git a/test/e2e/create_staticip_test.go b/test/e2e/create_staticip_test.go index 709e56665..72a0638f9 100644 --- a/test/e2e/create_staticip_test.go +++ b/test/e2e/create_staticip_test.go @@ -40,13 +40,13 @@ var _ = Describe("Podman create with --ip flag", func() { It("Podman create --ip with garbage address", func() { result := podmanTest.Podman([]string{"create", "--name", "test", "--ip", "114232346", ALPINE, "ls"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).ToNot(Equal(0)) + Expect(result).To(ExitWithError()) }) It("Podman create --ip with v6 address", func() { result := podmanTest.Podman([]string{"create", "--name", "test", "--ip", "2001:db8:bad:beef::1", ALPINE, "ls"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).ToNot(Equal(0)) + Expect(result).To(ExitWithError()) }) It("Podman create --ip with non-allocatable IP", func() { @@ -56,7 +56,7 @@ var _ = Describe("Podman create with --ip flag", func() { result = podmanTest.Podman([]string{"start", "test"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).ToNot(Equal(0)) + Expect(result).To(ExitWithError()) }) It("Podman create with specified static IP has correct IP", func() { @@ -88,6 +88,6 @@ var _ = Describe("Podman create with --ip flag", func() { Expect(result.ExitCode()).To(Equal(0)) result = podmanTest.Podman([]string{"start", "test2"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).ToNot(Equal(0)) + Expect(result).To(ExitWithError()) }) }) diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go index 2918cce78..65b747880 100644 --- a/test/e2e/create_test.go +++ b/test/e2e/create_test.go @@ -235,7 +235,7 @@ var _ = Describe("Podman create", func() { It("podman create --pull", func() { session := podmanTest.PodmanNoCache([]string{"create", "--pull", "never", "--name=foo", "nginx"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) session = podmanTest.PodmanNoCache([]string{"create", "--pull", "always", "--name=foo", "nginx"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go index 13fdabb81..1c4a9adb9 100644 --- a/test/e2e/exec_test.go +++ b/test/e2e/exec_test.go @@ -203,11 +203,11 @@ var _ = Describe("Podman exec", func() { session := podmanTest.Podman([]string{"exec", "--workdir", "/missing", "test1", "pwd"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) session = podmanTest.Podman([]string{"exec", "-w", "/missing", "test1", "pwd"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman exec cannot be invoked", func() { diff --git a/test/e2e/export_test.go b/test/e2e/export_test.go index 8406b0e73..1c84c6f4d 100644 --- a/test/e2e/export_test.go +++ b/test/e2e/export_test.go @@ -72,6 +72,6 @@ var _ = Describe("Podman export", func() { outfile := filepath.Join(podmanTest.TempDir, "container:with:colon.tar") result := podmanTest.Podman([]string{"export", "-o", outfile, cid}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).To(Not(Equal(0))) + Expect(result).To(ExitWithError()) }) }) diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index 49d2c12a8..5d3b1238a 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -40,13 +40,13 @@ var _ = Describe("Podman generate kube", func() { It("podman generate pod kube on bogus object", func() { session := podmanTest.Podman([]string{"generate", "kube", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman generate service kube on bogus object", func() { session := podmanTest.Podman([]string{"generate", "kube", "-s", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman generate kube on container", func() { diff --git a/test/e2e/generate_systemd_test.go b/test/e2e/generate_systemd_test.go index 314743a92..91072b023 100644 --- a/test/e2e/generate_systemd_test.go +++ b/test/e2e/generate_systemd_test.go @@ -37,19 +37,19 @@ var _ = Describe("Podman generate systemd", func() { It("podman generate systemd on bogus container/pod", func() { session := podmanTest.Podman([]string{"generate", "systemd", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman generate systemd bad restart policy", func() { session := podmanTest.Podman([]string{"generate", "systemd", "--restart-policy", "never", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman generate systemd bad timeout value", func() { session := podmanTest.Podman([]string{"generate", "systemd", "--timeout", "-1", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman generate systemd good timeout value", func() { diff --git a/test/e2e/healthcheck_run_test.go b/test/e2e/healthcheck_run_test.go index e10aef427..4acea06eb 100644 --- a/test/e2e/healthcheck_run_test.go +++ b/test/e2e/healthcheck_run_test.go @@ -38,7 +38,7 @@ var _ = Describe("Podman healthcheck run", func() { It("podman healthcheck run bogus container", func() { session := podmanTest.Podman([]string{"healthcheck", "run", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman healthcheck on valid container", func() { diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go index ca1e9d384..7d029c52f 100644 --- a/test/e2e/inspect_test.go +++ b/test/e2e/inspect_test.go @@ -46,7 +46,7 @@ var _ = Describe("Podman inspect", func() { SkipIfRemote() session := podmanTest.Podman([]string{"inspect", "foobar4321"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman inspect with GO format", func() { diff --git a/test/e2e/kill_test.go b/test/e2e/kill_test.go index 017fe4a3f..834f86b77 100644 --- a/test/e2e/kill_test.go +++ b/test/e2e/kill_test.go @@ -35,7 +35,7 @@ var _ = Describe("Podman kill", func() { It("podman kill bogus container", func() { session := podmanTest.Podman([]string{"kill", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman container kill a running container by id", func() { diff --git a/test/e2e/load_test.go b/test/e2e/load_test.go index 9209e1770..9ff358d26 100644 --- a/test/e2e/load_test.go +++ b/test/e2e/load_test.go @@ -143,7 +143,7 @@ var _ = Describe("Podman load", func() { It("podman load bogus file", func() { save := podmanTest.PodmanNoCache([]string{"load", "-i", "foobar.tar"}) save.WaitWithDefaultTimeout() - Expect(save.ExitCode()).ToNot(Equal(0)) + Expect(save).To(ExitWithError()) }) It("podman load multiple tags", func() { diff --git a/test/e2e/login_logout_test.go b/test/e2e/login_logout_test.go index 4d476e05f..14cfed5db 100644 --- a/test/e2e/login_logout_test.go +++ b/test/e2e/login_logout_test.go @@ -109,7 +109,7 @@ var _ = Describe("Podman login and logout", func() { session = podmanTest.Podman([]string{"push", ALPINE, testImg}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman login and logout with flag --authfile", func() { @@ -198,7 +198,7 @@ var _ = Describe("Podman login and logout", func() { session = podmanTest.Podman([]string{"push", ALPINE, "localhost:9001/test-alpine"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) session = podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "localhost:9001"}) session.WaitWithDefaultTimeout() @@ -218,7 +218,7 @@ var _ = Describe("Podman login and logout", func() { session = podmanTest.Podman([]string{"push", ALPINE, testImg}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) session = podmanTest.Podman([]string{"push", ALPINE, "localhost:9001/test-alpine"}) session.WaitWithDefaultTimeout() @@ -234,10 +234,10 @@ var _ = Describe("Podman login and logout", func() { session = podmanTest.Podman([]string{"push", ALPINE, testImg}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) session = podmanTest.Podman([]string{"push", ALPINE, "localhost:9001/test-alpine"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) }) diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go index d17f60a5d..f34d85d76 100644 --- a/test/e2e/logs_test.go +++ b/test/e2e/logs_test.go @@ -108,7 +108,7 @@ var _ = Describe("Podman logs", func() { It("podman logs latest and container name should fail", func() { results := podmanTest.Podman([]string{"logs", "-l", "foobar"}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).ToNot(Equal(0)) + Expect(results).To(ExitWithError()) }) It("podman logs two containers and should display short container IDs", func() { diff --git a/test/e2e/negative_test.go b/test/e2e/negative_test.go index 3cb54a20a..957609b7e 100644 --- a/test/e2e/negative_test.go +++ b/test/e2e/negative_test.go @@ -33,6 +33,6 @@ var _ = Describe("Podman negative command-line", func() { It("podman snuffleupagus exits non-zero", func() { session := podmanTest.Podman([]string{"snuffleupagus"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) }) diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index 264219178..b83757cc0 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -182,19 +182,19 @@ var _ = Describe("Podman network create", func() { It("podman network create with invalid subnet", func() { nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/17000", "fail"}) nc.WaitWithDefaultTimeout() - Expect(nc.ExitCode()).ToNot(BeZero()) + Expect(nc).To(ExitWithError()) }) It("podman network create with invalid IP", func() { nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.0/17000", "fail"}) nc.WaitWithDefaultTimeout() - Expect(nc.ExitCode()).ToNot(BeZero()) + Expect(nc).To(ExitWithError()) }) It("podman network create with invalid gateway for subnet", func() { nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", "--gateway", "192.168.1.1", "fail"}) nc.WaitWithDefaultTimeout() - Expect(nc.ExitCode()).ToNot(BeZero()) + Expect(nc).To(ExitWithError()) }) It("podman network create two networks with same name should fail", func() { @@ -205,13 +205,13 @@ var _ = Describe("Podman network create", func() { ncFail := podmanTest.Podman([]string{"network", "create", "samename"}) ncFail.WaitWithDefaultTimeout() - Expect(ncFail.ExitCode()).ToNot(BeZero()) + Expect(ncFail).To(ExitWithError()) }) It("podman network create with invalid network name", func() { nc := podmanTest.Podman([]string{"network", "create", "foo "}) nc.WaitWithDefaultTimeout() - Expect(nc.ExitCode()).ToNot(BeZero()) + Expect(nc).To(ExitWithError()) }) }) diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go index c61131078..39e08e2e8 100644 --- a/test/e2e/pause_test.go +++ b/test/e2e/pause_test.go @@ -52,13 +52,13 @@ var _ = Describe("Podman pause", func() { It("podman pause bogus container", func() { session := podmanTest.Podman([]string{"pause", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman unpause bogus container", func() { session := podmanTest.Podman([]string{"unpause", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman pause a created container by id", func() { @@ -70,7 +70,7 @@ var _ = Describe("Podman pause", func() { result := podmanTest.Podman([]string{"pause", cid}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).To(Not(Equal(0))) + Expect(result).To(ExitWithError()) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.GetContainerStatus()).To(ContainSubstring(createdState)) }) diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 5d59f0eb0..7069e049d 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -23,7 +23,7 @@ metadata: spec: hostname: {{ .Hostname }} containers: -{{ with .Containers }} +{{ with .Ctrs }} {{ range . }} - command: {{ range .Cmd }} @@ -67,47 +67,128 @@ spec: status: {} ` -type Pod struct { - Name string - Hostname string - Containers []Container -} - -type Container struct { - Cmd []string - Image string - Name string - SecurityContext bool - Caps bool - CapAdd []string - CapDrop []string -} +var ( + defaultCtrName = "testCtr" + defaultCtrCmd = []string{"top"} + defaultCtrImage = ALPINE + defaultPodName = "testPod" +) -func generateKubeYaml(name string, hostname string, ctrs []Container, fileName string) error { +func generateKubeYaml(pod *Pod, fileName string) error { f, err := os.Create(fileName) if err != nil { return err } defer f.Close() - testPod := Pod{name, hostname, ctrs} t, err := template.New("pod").Parse(yamlTemplate) if err != nil { return err } - if err := t.Execute(f, testPod); err != nil { + if err := t.Execute(f, pod); err != nil { return err } return nil } +// Pod describes the options a kube yaml can be configured at pod level +type Pod struct { + Name string + Hostname string + Ctrs []*Ctr +} + +// getPod takes a list of podOptions and returns a pod with sane defaults +// and the configured options +// if no containers are added, it will add the default container +func getPod(options ...podOption) *Pod { + p := Pod{defaultPodName, "", make([]*Ctr, 0)} + for _, option := range options { + option(&p) + } + if len(p.Ctrs) == 0 { + p.Ctrs = []*Ctr{getCtr()} + } + return &p +} + +type podOption func(*Pod) + +func withHostname(h string) podOption { + return func(pod *Pod) { + pod.Hostname = h + } +} + +func withCtr(c *Ctr) podOption { + return func(pod *Pod) { + pod.Ctrs = append(pod.Ctrs, c) + } +} + +// Ctr describes the options a kube yaml can be configured at container level +type Ctr struct { + Name string + Image string + Cmd []string + SecurityContext bool + Caps bool + CapAdd []string + CapDrop []string +} + +// getCtr takes a list of ctrOptions and returns a Ctr with sane defaults +// and the configured options +func getCtr(options ...ctrOption) *Ctr { + c := Ctr{defaultCtrName, defaultCtrImage, defaultCtrCmd, true, false, nil, nil} + for _, option := range options { + option(&c) + } + return &c +} + +type ctrOption func(*Ctr) + +func withCmd(cmd []string) ctrOption { + return func(c *Ctr) { + c.Cmd = cmd + } +} + +func withImage(img string) ctrOption { + return func(c *Ctr) { + c.Image = img + } +} + +func withSecurityContext(sc bool) ctrOption { + return func(c *Ctr) { + c.SecurityContext = sc + } +} + +func withCapAdd(caps []string) ctrOption { + return func(c *Ctr) { + c.CapAdd = caps + c.Caps = true + } +} + +func withCapDrop(caps []string) ctrOption { + return func(c *Ctr) { + c.CapDrop = caps + c.Caps = true + } +} + var _ = Describe("Podman generate kube", func() { var ( tempdir string err error podmanTest *PodmanTestIntegration + kubeYaml string ) BeforeEach(func() { @@ -118,6 +199,8 @@ var _ = Describe("Podman generate kube", func() { podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() podmanTest.SeedImages() + + kubeYaml = filepath.Join(podmanTest.TempDir, "kube.yaml") }) AfterEach(func() { @@ -127,123 +210,98 @@ var _ = Describe("Podman generate kube", func() { }) It("podman play kube test correct command", func() { - ctrName := "testCtr" - ctrCmd := []string{"top"} - testContainer := Container{ctrCmd, ALPINE, ctrName, true, false, nil, nil} - tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml") - - err := generateKubeYaml("test", "", []Container{testContainer}, tempFile) + err := generateKubeYaml(getPod(), kubeYaml) Expect(err).To(BeNil()) - kube := podmanTest.Podman([]string{"play", "kube", tempFile}) + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) kube.WaitWithDefaultTimeout() Expect(kube.ExitCode()).To(Equal(0)) - inspect := podmanTest.Podman([]string{"inspect", ctrName}) + inspect := podmanTest.Podman([]string{"inspect", defaultCtrName}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) - Expect(inspect.OutputToString()).To(ContainSubstring(ctrCmd[0])) + Expect(inspect.OutputToString()).To(ContainSubstring(defaultCtrCmd[0])) }) It("podman play kube test correct output", func() { - ctrName := "testCtr" - ctrCmd := []string{"echo", "hello"} - testContainer := Container{ctrCmd, ALPINE, ctrName, true, false, nil, nil} - tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml") + p := getPod(withCtr(getCtr(withCmd([]string{"echo", "hello"})))) - err := generateKubeYaml("test", "", []Container{testContainer}, tempFile) + err := generateKubeYaml(p, kubeYaml) Expect(err).To(BeNil()) - kube := podmanTest.Podman([]string{"play", "kube", tempFile}) + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) kube.WaitWithDefaultTimeout() Expect(kube.ExitCode()).To(Equal(0)) - logs := podmanTest.Podman([]string{"logs", ctrName}) + logs := podmanTest.Podman([]string{"logs", defaultCtrName}) logs.WaitWithDefaultTimeout() Expect(logs.ExitCode()).To(Equal(0)) Expect(logs.OutputToString()).To(ContainSubstring("hello")) - inspect := podmanTest.Podman([]string{"inspect", ctrName, "--format", "'{{ .Config.Cmd }}'"}) + inspect := podmanTest.Podman([]string{"inspect", defaultCtrName, "--format", "'{{ .Config.Cmd }}'"}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) Expect(inspect.OutputToString()).To(ContainSubstring("hello")) }) It("podman play kube test hostname", func() { - podName := "test" - ctrName := "testCtr" - ctrCmd := []string{"top"} - testContainer := Container{ctrCmd, ALPINE, ctrName, true, false, nil, nil} - tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml") - - err := generateKubeYaml(podName, "", []Container{testContainer}, tempFile) + err := generateKubeYaml(getPod(), kubeYaml) Expect(err).To(BeNil()) - kube := podmanTest.Podman([]string{"play", "kube", tempFile}) + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) kube.WaitWithDefaultTimeout() Expect(kube.ExitCode()).To(Equal(0)) - inspect := podmanTest.Podman([]string{"inspect", ctrName, "--format", "{{ .Config.Hostname }}"}) + inspect := podmanTest.Podman([]string{"inspect", defaultCtrName, "--format", "{{ .Config.Hostname }}"}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) - Expect(inspect.OutputToString()).To(Equal(podName)) + Expect(inspect.OutputToString()).To(Equal(defaultPodName)) }) It("podman play kube test with customized hostname", func() { hostname := "myhostname" - ctrName := "testCtr" - ctrCmd := []string{"top"} - testContainer := Container{ctrCmd, ALPINE, ctrName, true, false, nil, nil} - tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml") - - err := generateKubeYaml("test", hostname, []Container{testContainer}, tempFile) + err := generateKubeYaml(getPod(withHostname(hostname)), kubeYaml) Expect(err).To(BeNil()) - kube := podmanTest.Podman([]string{"play", "kube", tempFile}) + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) kube.WaitWithDefaultTimeout() Expect(kube.ExitCode()).To(Equal(0)) - inspect := podmanTest.Podman([]string{"inspect", ctrName, "--format", "{{ .Config.Hostname }}"}) + inspect := podmanTest.Podman([]string{"inspect", defaultCtrName, "--format", "{{ .Config.Hostname }}"}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) Expect(inspect.OutputToString()).To(Equal(hostname)) }) It("podman play kube cap add", func() { - ctrName := "testCtr" - ctrCmd := []string{"cat", "/proc/self/status"} capAdd := "CAP_SYS_ADMIN" - testContainer := Container{ctrCmd, ALPINE, ctrName, true, true, []string{capAdd}, nil} - tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml") + ctr := getCtr(withCapAdd([]string{capAdd}), withCmd([]string{"cat", "/proc/self/status"})) - err := generateKubeYaml("test", "", []Container{testContainer}, tempFile) + err := generateKubeYaml(getPod(withCtr(ctr)), kubeYaml) Expect(err).To(BeNil()) - kube := podmanTest.Podman([]string{"play", "kube", tempFile}) + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) kube.WaitWithDefaultTimeout() Expect(kube.ExitCode()).To(Equal(0)) - inspect := podmanTest.Podman([]string{"inspect", ctrName}) + inspect := podmanTest.Podman([]string{"inspect", defaultCtrName}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) Expect(inspect.OutputToString()).To(ContainSubstring(capAdd)) }) - It("podman play kube cap add", func() { - ctrName := "testCtr" - ctrCmd := []string{"cat", "/proc/self/status"} - capDrop := "CAP_SYS_ADMIN" - testContainer := Container{ctrCmd, ALPINE, ctrName, true, true, []string{capDrop}, nil} - tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml") + It("podman play kube cap drop", func() { + capDrop := "CAP_CHOWN" + ctr := getCtr(withCapDrop([]string{capDrop})) - err := generateKubeYaml("test", "", []Container{testContainer}, tempFile) + err := generateKubeYaml(getPod(withCtr(ctr)), kubeYaml) Expect(err).To(BeNil()) - kube := podmanTest.Podman([]string{"play", "kube", tempFile}) + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) kube.WaitWithDefaultTimeout() Expect(kube.ExitCode()).To(Equal(0)) - inspect := podmanTest.Podman([]string{"inspect", ctrName}) + inspect := podmanTest.Podman([]string{"inspect", defaultCtrName}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) Expect(inspect.OutputToString()).To(ContainSubstring(capDrop)) @@ -251,19 +309,14 @@ var _ = Describe("Podman generate kube", func() { It("podman play kube no security context", func() { // expect play kube to not fail if no security context is specified - ctrName := "testCtr" - ctrCmd := "ls" - testContainer := Container{[]string{ctrCmd}, ALPINE, ctrName, false, false, nil, nil} - tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml") - - err := generateKubeYaml("test", "", []Container{testContainer}, tempFile) + err := generateKubeYaml(getPod(withCtr(getCtr(withSecurityContext(false)))), kubeYaml) Expect(err).To(BeNil()) - kube := podmanTest.Podman([]string{"play", "kube", tempFile}) + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) kube.WaitWithDefaultTimeout() Expect(kube.ExitCode()).To(Equal(0)) - inspect := podmanTest.Podman([]string{"inspect", ctrName}) + inspect := podmanTest.Podman([]string{"inspect", defaultCtrName}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) }) diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go index 3897aa851..c8072f308 100644 --- a/test/e2e/pod_infra_container_test.go +++ b/test/e2e/pod_infra_container_test.go @@ -122,7 +122,7 @@ var _ = Describe("Podman pod create", func() { session = podmanTest.Podman([]string{"run", fedoraMinimal, "curl", "localhost"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman pod correctly sets up IPCNS", func() { @@ -218,7 +218,7 @@ var _ = Describe("Podman pod create", func() { session = podmanTest.Podman([]string{"run", "--pod", podID, "--network", "bridge", nginx, "curl", "localhost"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman pod container can override pod pid NS", func() { @@ -309,7 +309,7 @@ var _ = Describe("Podman pod create", func() { session = podmanTest.Podman([]string{"rm", infraID}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) session = podmanTest.Podman([]string{"pod", "rm", podID}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/pod_inspect_test.go b/test/e2e/pod_inspect_test.go index 488dd1685..49c647528 100644 --- a/test/e2e/pod_inspect_test.go +++ b/test/e2e/pod_inspect_test.go @@ -35,7 +35,7 @@ var _ = Describe("Podman pod inspect", func() { It("podman inspect bogus pod", func() { session := podmanTest.Podman([]string{"pod", "inspect", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).Should(ExitWithError()) }) It("podman inspect a pod", func() { diff --git a/test/e2e/pod_kill_test.go b/test/e2e/pod_kill_test.go index 7cf67bbfc..a3efec46c 100644 --- a/test/e2e/pod_kill_test.go +++ b/test/e2e/pod_kill_test.go @@ -36,7 +36,7 @@ var _ = Describe("Podman pod kill", func() { It("podman pod kill bogus", func() { session := podmanTest.Podman([]string{"pod", "kill", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman pod kill a pod by id", func() { diff --git a/test/e2e/pod_pause_test.go b/test/e2e/pod_pause_test.go index 619ee6f12..73707926d 100644 --- a/test/e2e/pod_pause_test.go +++ b/test/e2e/pod_pause_test.go @@ -38,13 +38,13 @@ var _ = Describe("Podman pod pause", func() { It("podman pod pause bogus pod", func() { session := podmanTest.Podman([]string{"pod", "pause", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman unpause bogus pod", func() { session := podmanTest.Podman([]string{"pod", "unpause", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman pod pause a created pod by id", func() { diff --git a/test/e2e/pod_ps_test.go b/test/e2e/pod_ps_test.go index 6d5873caa..aa07be55c 100644 --- a/test/e2e/pod_ps_test.go +++ b/test/e2e/pod_ps_test.go @@ -107,7 +107,7 @@ var _ = Describe("Podman ps", func() { It("podman pod ps mutually exclusive flags", func() { session := podmanTest.Podman([]string{"pod", "ps", "-q", "--format", "{{.ID}}"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go index f0689f152..de68e885a 100644 --- a/test/e2e/pod_rm_test.go +++ b/test/e2e/pod_rm_test.go @@ -135,7 +135,7 @@ var _ = Describe("Podman pod rm", func() { fmt.Printf("Removing all empty pods\n") result := podmanTest.Podman([]string{"pod", "rm", "-a"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).To(Not(Equal(0))) + Expect(result).To(ExitWithError()) foundExpectedError, _ := result.ErrorGrepString("contains containers and cannot be removed") Expect(foundExpectedError).To(Equal(true)) diff --git a/test/e2e/pod_stats_test.go b/test/e2e/pod_stats_test.go index 01176f97c..4d573a2c7 100644 --- a/test/e2e/pod_stats_test.go +++ b/test/e2e/pod_stats_test.go @@ -169,7 +169,7 @@ var _ = Describe("Podman pod stats", func() { Expect(session.ExitCode()).To(Equal(0)) stats := podmanTest.Podman([]string{"pod", "stats", "-a", "--no-reset", "--no-stream", "--format", "\"table {{.ID}} \""}) stats.WaitWithDefaultTimeout() - Expect(stats.ExitCode()).ToNot(Equal(0)) + Expect(stats).To(ExitWithError()) }) }) diff --git a/test/e2e/port_test.go b/test/e2e/port_test.go index 53fc33a01..5bb86d558 100644 --- a/test/e2e/port_test.go +++ b/test/e2e/port_test.go @@ -39,13 +39,13 @@ var _ = Describe("Podman port", func() { It("podman port all and latest", func() { result := podmanTest.Podman([]string{"port", "-a", "-l"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).ToNot(Equal(0)) + Expect(result).To(ExitWithError()) }) It("podman port all and extra", func() { result := podmanTest.Podman([]string{"port", "-a", "foobar"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).ToNot(Equal(0)) + Expect(result).To(ExitWithError()) }) It("podman port -l nginx", func() { diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go index 4130f409e..a436d4f09 100644 --- a/test/e2e/ps_test.go +++ b/test/e2e/ps_test.go @@ -230,11 +230,11 @@ var _ = Describe("Podman ps", func() { It("podman ps mutually exclusive flags", func() { session := podmanTest.Podman([]string{"ps", "-aqs"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) session = podmanTest.Podman([]string{"ps", "-a", "--ns", "-s"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman --sort by size", func() { diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go index 68fcaf133..537084220 100644 --- a/test/e2e/pull_test.go +++ b/test/e2e/pull_test.go @@ -40,7 +40,7 @@ var _ = Describe("Podman pull", func() { It("podman pull from docker a not existing image", func() { session := podmanTest.PodmanNoCache([]string{"pull", "ibetthisdoesntexistthere:foo"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman pull from docker with tag", func() { @@ -96,7 +96,7 @@ var _ = Describe("Podman pull", func() { It("podman pull bogus image", func() { session := podmanTest.PodmanNoCache([]string{"pull", "umohnani/get-started"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman pull from docker-archive", func() { diff --git a/test/e2e/push_test.go b/test/e2e/push_test.go index 4360eeece..50f0ca6d9 100644 --- a/test/e2e/push_test.go +++ b/test/e2e/push_test.go @@ -140,7 +140,7 @@ var _ = Describe("Podman push", func() { push := podmanTest.PodmanNoCache([]string{"push", "--creds=podmantest:test", ALPINE, "localhost:5000/tlstest"}) push.WaitWithDefaultTimeout() - Expect(push.ExitCode()).To(Not(Equal(0))) + Expect(push).To(ExitWithError()) push = podmanTest.PodmanNoCache([]string{"push", "--creds=podmantest:test", "--tls-verify=false", ALPINE, "localhost:5000/tlstest"}) push.WaitWithDefaultTimeout() @@ -151,11 +151,11 @@ var _ = Describe("Podman push", func() { push = podmanTest.PodmanNoCache([]string{"push", "--creds=podmantest:wrongpasswd", ALPINE, "localhost:5000/credstest"}) push.WaitWithDefaultTimeout() - Expect(push.ExitCode()).To(Not(Equal(0))) + Expect(push).To(ExitWithError()) push = podmanTest.PodmanNoCache([]string{"push", "--creds=podmantest:test", "--cert-dir=fakedir", ALPINE, "localhost:5000/certdirtest"}) push.WaitWithDefaultTimeout() - Expect(push.ExitCode()).To(Not(Equal(0))) + Expect(push).To(ExitWithError()) push = podmanTest.PodmanNoCache([]string{"push", "--creds=podmantest:test", ALPINE, "localhost:5000/defaultflags"}) push.WaitWithDefaultTimeout() diff --git a/test/e2e/rmi_test.go b/test/e2e/rmi_test.go index 506adee7e..80e877de1 100644 --- a/test/e2e/rmi_test.go +++ b/test/e2e/rmi_test.go @@ -102,7 +102,7 @@ var _ = Describe("Podman rmi", func() { // Trying without --force should fail result := podmanTest.PodmanNoCache([]string{"rmi", alpineId}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).ToNot(Equal(0)) + Expect(result).To(ExitWithError()) // With --force it should work resultForce := podmanTest.PodmanNoCache([]string{"rmi", "-f", alpineId}) diff --git a/test/e2e/run_cpu_test.go b/test/e2e/run_cpu_test.go index 42f17985c..29ceb4e67 100644 --- a/test/e2e/run_cpu_test.go +++ b/test/e2e/run_cpu_test.go @@ -164,12 +164,12 @@ var _ = Describe("Podman run cpu", func() { It("podman run cpus and cpu-period", func() { result := podmanTest.Podman([]string{"run", "--rm", "--cpu-period=5000", "--cpus=0.5", ALPINE, "ls"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).To(Not(Equal(0))) + Expect(result).To(ExitWithError()) }) It("podman run cpus and cpu-quota", func() { result := podmanTest.Podman([]string{"run", "--rm", "--cpu-quota=5000", "--cpus=0.5", ALPINE, "ls"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).To(Not(Equal(0))) + Expect(result).To(ExitWithError()) }) }) diff --git a/test/e2e/run_device_test.go b/test/e2e/run_device_test.go index d3b4b0e32..eae3f574c 100644 --- a/test/e2e/run_device_test.go +++ b/test/e2e/run_device_test.go @@ -37,7 +37,7 @@ var _ = Describe("Podman run device", func() { It("podman run bad device test", func() { session := podmanTest.Podman([]string{"run", "-q", "--device", "/dev/baddevice", ALPINE, "true"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman run device test", func() { @@ -70,7 +70,7 @@ var _ = Describe("Podman run device", func() { It("podman run device rename and bad permission test", func() { session := podmanTest.Podman([]string{"run", "-q", "--security-opt", "label=disable", "--device", "/dev/kmsg:/dev/kmsg1:rd", ALPINE, "ls", "--color=never", "/dev/kmsg1"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman run device host device and container device parameter are directories", func() { diff --git a/test/e2e/run_dns_test.go b/test/e2e/run_dns_test.go index dc0f4a8fb..02b9ff8d1 100644 --- a/test/e2e/run_dns_test.go +++ b/test/e2e/run_dns_test.go @@ -51,7 +51,7 @@ var _ = Describe("Podman run dns", func() { It("podman run add bad dns server", func() { session := podmanTest.Podman([]string{"run", "--dns=foobar", ALPINE, "ls"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman run add dns server", func() { @@ -71,7 +71,7 @@ var _ = Describe("Podman run dns", func() { It("podman run add bad host", func() { session := podmanTest.Podman([]string{"run", "--add-host=foo:1.2", ALPINE, "ls"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman run add host", func() { @@ -105,15 +105,15 @@ var _ = Describe("Podman run dns", func() { It("podman run mutually excludes --dns* and --network", func() { session := podmanTest.Podman([]string{"run", "--dns=1.2.3.4", "--network", "container:ALPINE", ALPINE}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) session = podmanTest.Podman([]string{"run", "--dns-opt=1.2.3.4", "--network", "container:ALPINE", ALPINE}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) session = podmanTest.Podman([]string{"run", "--dns-search=foobar.com", "--network", "none", ALPINE}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) session = podmanTest.Podman([]string{"run", "--dns=1.2.3.4", "--network", "host", ALPINE}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 31291d373..ec12f709a 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -74,7 +74,7 @@ var _ = Describe("Podman run networking", func() { Expect(results.OutputToString()).To(ContainSubstring("8000")) ncBusy := SystemExec("nc", []string{"-l", "-p", "80"}) - Expect(ncBusy.ExitCode()).ToNot(Equal(0)) + Expect(ncBusy).To(ExitWithError()) }) It("podman run network expose ports in image metadata", func() { @@ -229,7 +229,7 @@ var _ = Describe("Podman run networking", func() { It("podman run network in bogus user created network namespace", func() { session := podmanTest.Podman([]string{"run", "-dt", "--net", "ns:/run/netns/xxy", ALPINE, "wget", "www.podman.io"}) session.Wait(90) - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) Expect(session.ErrorToString()).To(ContainSubstring("stat /run/netns/xxy: no such file or directory")) }) }) diff --git a/test/e2e/run_ns_test.go b/test/e2e/run_ns_test.go index e3e86fc66..c8ba68efc 100644 --- a/test/e2e/run_ns_test.go +++ b/test/e2e/run_ns_test.go @@ -48,7 +48,7 @@ var _ = Describe("Podman run ns", func() { session = podmanTest.Podman([]string{"run", "--pid=badpid", fedoraMinimal, "bash", "-c", "echo $$"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman run --cgroup private test", func() { @@ -102,6 +102,6 @@ var _ = Describe("Podman run ns", func() { It("podman run bad ipc pid test", func() { session := podmanTest.Podman([]string{"run", "--ipc=badpid", fedoraMinimal, "bash", "-c", "echo $$"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).ToNot(Equal(0)) + Expect(session).To(ExitWithError()) }) }) diff --git a/test/e2e/run_staticip_test.go b/test/e2e/run_staticip_test.go index 7a877ebdc..5b4842fea 100644 --- a/test/e2e/run_staticip_test.go +++ b/test/e2e/run_staticip_test.go @@ -40,19 +40,19 @@ var _ = Describe("Podman run with --ip flag", func() { It("Podman run --ip with garbage address", func() { result := podmanTest.Podman([]string{"run", "-ti", "--ip", "114232346", ALPINE, "ls"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).ToNot(Equal(0)) + Expect(result).To(ExitWithError()) }) It("Podman run --ip with v6 address", func() { result := podmanTest.Podman([]string{"run", "-ti", "--ip", "2001:db8:bad:beef::1", ALPINE, "ls"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).ToNot(Equal(0)) + Expect(result).To(ExitWithError()) }) It("Podman run --ip with non-allocatable IP", func() { result := podmanTest.Podman([]string{"run", "-ti", "--ip", "203.0.113.124", ALPINE, "ls"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).ToNot(Equal(0)) + Expect(result).To(ExitWithError()) }) It("Podman run with specified static IP has correct IP", func() { @@ -70,6 +70,6 @@ var _ = Describe("Podman run with --ip flag", func() { Expect(result.ExitCode()).To(Equal(0)) result = podmanTest.Podman([]string{"run", "-ti", "--ip", ip, ALPINE, "ip", "addr"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).ToNot(Equal(0)) + Expect(result).To(ExitWithError()) }) }) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 1e6f1d97d..874aa498e 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -170,7 +170,7 @@ var _ = Describe("Podman run", func() { session := podmanTest.Podman([]string{"run", "-it", "--security-opt", strings.Join([]string{"seccomp=", jsonFile}, ""), ALPINE, "pwd"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) match, _ := session.GrepString("Operation not permitted") Expect(match).Should(BeTrue()) }) @@ -730,11 +730,11 @@ USER mail` session := podmanTest.Podman([]string{"run", "--volume", ":/myvol1:z", ALPINE, "touch", "/myvol2/foo.txt"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).ToNot(Equal(0)) + Expect(session).To(ExitWithError()) Expect(session.ErrorToString()).To(ContainSubstring("directory cannot be empty")) session = podmanTest.Podman([]string{"run", "--volume", vol1 + ":", ALPINE, "touch", "/myvol2/foo.txt"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).ToNot(Equal(0)) + Expect(session).To(ExitWithError()) Expect(session.ErrorToString()).To(ContainSubstring("directory cannot be empty")) }) @@ -815,7 +815,7 @@ USER mail` It("podman run --rm failed container should delete itself", func() { session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "foo"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) numContainers := podmanTest.NumberOfContainers() Expect(numContainers).To(Equal(0)) @@ -824,7 +824,7 @@ USER mail` It("podman run failed container should NOT delete itself", func() { session := podmanTest.Podman([]string{"run", ALPINE, "foo"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) numContainers := podmanTest.NumberOfContainers() Expect(numContainers).To(Equal(1)) @@ -840,28 +840,28 @@ USER mail` It("podman run with bad healthcheck retries", func() { session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "[\"foo\"]", "--health-retries", "0", ALPINE, "top"}) session.Wait() - Expect(session.ExitCode()).ToNot(Equal(0)) + Expect(session).To(ExitWithError()) Expect(session.ErrorToString()).To(ContainSubstring("healthcheck-retries must be greater than 0")) }) It("podman run with bad healthcheck timeout", func() { session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "[\"foo\"]", "--health-timeout", "0s", ALPINE, "top"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).ToNot(Equal(0)) + Expect(session).To(ExitWithError()) Expect(session.ErrorToString()).To(ContainSubstring("healthcheck-timeout must be at least 1 second")) }) It("podman run with bad healthcheck start-period", func() { session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "[\"foo\"]", "--health-start-period", "-1s", ALPINE, "top"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).ToNot(Equal(0)) + Expect(session).To(ExitWithError()) Expect(session.ErrorToString()).To(ContainSubstring("healthcheck-start-period must be 0 seconds or greater")) }) It("podman run with --add-host and --no-hosts fails", func() { session := podmanTest.Podman([]string{"run", "-dt", "--add-host", "test1:127.0.0.1", "--no-hosts", ALPINE, "top"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).ToNot(Equal(0)) + Expect(session).To(ExitWithError()) }) It("podman run --http-proxy test", func() { @@ -990,6 +990,6 @@ USER mail` It("podman run with cgroups=garbage errors", func() { session := podmanTest.Podman([]string{"run", "-d", "--cgroups=garbage", ALPINE, "top"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) }) diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index bc3a14b66..94bfebab7 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -155,7 +155,7 @@ var _ = Describe("Podman run with volumes", func() { session = podmanTest.Podman([]string{"run", "--rm", "--mount", fmt.Sprintf("type=bind,src=%s,target=/run/test,ro=true,rw=false", mountPath), ALPINE, "grep", "/run/test", "/proc/self/mountinfo"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman run with volume flag and multiple named volumes", func() { @@ -191,7 +191,7 @@ var _ = Describe("Podman run with volumes", func() { 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.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) It("podman run with tmpfs named volume mounts and unmounts", func() { diff --git a/test/e2e/runlabel_test.go b/test/e2e/runlabel_test.go index 4e2cb501e..52a011efb 100644 --- a/test/e2e/runlabel_test.go +++ b/test/e2e/runlabel_test.go @@ -75,12 +75,12 @@ var _ = Describe("podman container runlabel", func() { It("podman container runlabel bogus label should result in non-zero exit code", func() { result := podmanTest.Podman([]string{"container", "runlabel", "RUN", ALPINE}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).ToNot(Equal(0)) + Expect(result).To(ExitWithError()) }) It("podman container runlabel bogus label in remote image should result in non-zero exit", func() { result := podmanTest.Podman([]string{"container", "runlabel", "RUN", "docker.io/library/ubuntu:latest"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).ToNot(Equal(0)) + Expect(result).To(ExitWithError()) }) diff --git a/test/e2e/save_test.go b/test/e2e/save_test.go index be1ede962..52dab923b 100644 --- a/test/e2e/save_test.go +++ b/test/e2e/save_test.go @@ -72,7 +72,7 @@ var _ = Describe("Podman save", func() { save := podmanTest.PodmanNoCache([]string{"save", "-o", outfile, "FOOBAR"}) save.WaitWithDefaultTimeout() - Expect(save.ExitCode()).To(Not(Equal(0))) + Expect(save).To(ExitWithError()) }) It("podman save to directory with oci format", func() { @@ -113,7 +113,7 @@ var _ = Describe("Podman save", func() { save := podmanTest.PodmanNoCache([]string{"save", "--compress", "--format", "docker-dir", "-o", outdir, ALPINE}) save.WaitWithDefaultTimeout() - Expect(save.ExitCode()).To(Not(Equal(0))) + Expect(save).To(ExitWithError()) }) }) diff --git a/test/e2e/start_test.go b/test/e2e/start_test.go index 13f14183b..da581f158 100644 --- a/test/e2e/start_test.go +++ b/test/e2e/start_test.go @@ -108,7 +108,7 @@ var _ = Describe("Podman start", func() { start := podmanTest.Podman([]string{"start", "-l"}) start.WaitWithDefaultTimeout() - Expect(start.ExitCode()).Should(BeNumerically(">", 0)) + Expect(start).To(ExitWithError()) Eventually(podmanTest.NumberOfContainers(), defaultWaitTimeout, 3.0).Should(BeZero()) }) @@ -120,7 +120,7 @@ var _ = Describe("Podman start", func() { start := podmanTest.Podman([]string{"start", "-l"}) start.WaitWithDefaultTimeout() - Expect(start.ExitCode()).Should(BeNumerically(">", 0)) + Expect(start).To(ExitWithError()) Eventually(podmanTest.NumberOfContainers(), defaultWaitTimeout, 3.0).Should(Equal(1)) }) diff --git a/test/e2e/volume_create_test.go b/test/e2e/volume_create_test.go index 77e8abbd4..41107b5ba 100644 --- a/test/e2e/volume_create_test.go +++ b/test/e2e/volume_create_test.go @@ -61,6 +61,6 @@ var _ = Describe("Podman volume create", func() { It("podman create volume with bad volume option", func() { session := podmanTest.Podman([]string{"volume", "create", "--opt", "badOpt=bad"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) }) diff --git a/test/e2e/volume_rm_test.go b/test/e2e/volume_rm_test.go index 61cf9b893..6f2020828 100644 --- a/test/e2e/volume_rm_test.go +++ b/test/e2e/volume_rm_test.go @@ -56,7 +56,7 @@ var _ = Describe("Podman volume rm", func() { session = podmanTest.Podman([]string{"volume", "rm", "myvol"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) Expect(session.ErrorToString()).To(ContainSubstring(cid)) session = podmanTest.Podman([]string{"volume", "rm", "-f", "myvol"}) @@ -116,7 +116,7 @@ var _ = Describe("Podman volume rm", func() { session = podmanTest.Podman([]string{"volume", "rm", "myv"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) session = podmanTest.Podman([]string{"volume", "ls"}) session.WaitWithDefaultTimeout() diff --git a/test/system/075-exec.bats b/test/system/075-exec.bats index 11cb98269..472fdd1ab 100644 --- a/test/system/075-exec.bats +++ b/test/system/075-exec.bats @@ -29,4 +29,24 @@ load helpers run_podman rm $cid } +@test "podman exec - leak check" { + skip_if_remote + + # Start a container in the background then run exec command + # three times and make sure no any exec pid hash file leak + run_podman run -td $IMAGE /bin/sh + cid="$output" + + is "$(check_exec_pid)" "" "exec pid hash file indeed doesn't exist" + + for i in {1..3}; do + run_podman exec $cid /bin/true + done + + is "$(check_exec_pid)" "" "there isn't any exec pid hash file leak" + + run_podman stop --time 1 $cid + run_podman rm -f $cid +} + # vim: filetype=sh diff --git a/test/system/helpers.bash b/test/system/helpers.bash index 3d607f4bd..8c061d2c9 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -373,5 +373,19 @@ function random_string() { head /dev/urandom | tr -dc a-zA-Z0-9 | head -c$length } + +######################### +# find_exec_pid_files # Returns nothing or exec_pid hash files +######################### +# +# Return exec_pid hash files if exists, otherwise, return nothing +# +function find_exec_pid_files() { + run_podman info --format '{{.store.RunRoot}}' + local storage_path="$output" + if [ -d $storage_path ]; then + find $storage_path -type f -iname 'exec_pid_*' + fi +} # END miscellaneous tools ############################################################################### diff --git a/test/utils/matchers.go b/test/utils/matchers.go new file mode 100644 index 000000000..07c1232e7 --- /dev/null +++ b/test/utils/matchers.go @@ -0,0 +1,61 @@ +package utils + +import ( + "fmt" + + "github.com/onsi/gomega/format" + "github.com/onsi/gomega/gexec" +) + +// ExitWithError matches when assertion is > argument. Default 0 +// Modeled after the gomega Exit() matcher +func ExitWithError(optionalExitCode ...int) *exitMatcher { + exitCode := 0 + if len(optionalExitCode) > 0 { + exitCode = optionalExitCode[0] + } + return &exitMatcher{exitCode: exitCode} +} + +type exitMatcher struct { + exitCode int + actualExitCode int +} + +func (m *exitMatcher) Match(actual interface{}) (success bool, err error) { + exiter, ok := actual.(gexec.Exiter) + if !ok { + return false, fmt.Errorf("ExitWithError must be passed a gexec.Exiter (Missing method ExitCode() int) Got:\n#{format.Object(actual, 1)}") + } + + m.actualExitCode = exiter.ExitCode() + if m.actualExitCode == -1 { + return false, nil + } + return m.actualExitCode > m.exitCode, nil +} + +func (m *exitMatcher) FailureMessage(actual interface{}) (message string) { + if m.actualExitCode == -1 { + return "Expected process to exit. It did not." + } + return format.Message(m.actualExitCode, "to be greater than exit code:", m.exitCode) +} + +func (m *exitMatcher) NegatedFailureMessage(actual interface{}) (message string) { + if m.actualExitCode == -1 { + return "you really shouldn't be able to see this!" + } else { + if m.exitCode == -1 { + return "Expected process not to exit. It did." + } + return format.Message(m.actualExitCode, "is less than or equal to exit code:", m.exitCode) + } +} +func (m *exitMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { + session, ok := actual.(*gexec.Session) + if ok { + return session.ExitCode() == -1 + } + return true +} diff --git a/test/utils/utils.go b/test/utils/utils.go index 7d373bd56..ad78d9792 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -268,7 +268,7 @@ func (s *PodmanSession) ErrorGrepString(term string) (bool, []string) { return matches, greps } -//LineInOutputStartsWith returns true if a line in a +// LineInOutputStartsWith returns true if a line in a // session output starts with the supplied string func (s *PodmanSession) LineInOuputStartsWith(term string) bool { for _, i := range s.OutputToStringArray() { @@ -279,7 +279,7 @@ func (s *PodmanSession) LineInOuputStartsWith(term string) bool { return false } -//LineInOutputContains returns true if a line in a +// LineInOutputContains returns true if a line in a // session output contains the supplied string func (s *PodmanSession) LineInOutputContains(term string) bool { for _, i := range s.OutputToStringArray() { @@ -290,7 +290,7 @@ func (s *PodmanSession) LineInOutputContains(term string) bool { return false } -//LineInOutputContainsTag returns true if a line in the +// LineInOutputContainsTag returns true if a line in the // session's output contains the repo-tag pair as returned // by podman-images(1). func (s *PodmanSession) LineInOutputContainsTag(repo, tag string) bool { @@ -348,7 +348,7 @@ func StringInSlice(s string, sl []string) bool { return false } -//tagOutPutToMap parses each string in imagesOutput and returns +// tagOutPutToMap parses each string in imagesOutput and returns // a map of repo:tag pairs. Notice, the first array item will // be skipped as it's considered to be the header. func tagOutputToMap(imagesOutput []string) map[string]string { @@ -371,7 +371,7 @@ func tagOutputToMap(imagesOutput []string) map[string]string { return m } -//GetHostDistributionInfo returns a struct with its distribution name and version +// GetHostDistributionInfo returns a struct with its distribution name and version func GetHostDistributionInfo() HostOS { f, err := os.Open(OSReleasePath) defer f.Close() @@ -415,7 +415,7 @@ func IsKernelNewerThan(version string) (bool, error) { } -//IsCommandAvaible check if command exist +// IsCommandAvaible check if command exist func IsCommandAvailable(command string) bool { check := exec.Command("bash", "-c", strings.Join([]string{"command -v", command}, " ")) err := check.Run() diff --git a/troubleshooting.md b/troubleshooting.md index 6fed719f7..c4e577645 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -410,3 +410,22 @@ You'll need to either: * configure the host to use cgroups v1 * update the image to use an updated version of systemd. + +### 17) rootless containers exit once the user session exits + + +You need to set lingering mode through loginctl to prevent user processes to be killed once +the user session completed. + +#### Symptom + +Once the user logs out all the containers exit. + +#### Solution +You'll need to either: + +* loginctl enable-linger $UID + +or as root if your user has not enough privileges. + +* sudo loginctl enable-linger $UID diff --git a/vendor/modules.txt b/vendor/modules.txt index 712bfb69a..65a99869e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -346,12 +346,12 @@ github.com/onsi/ginkgo/internal/specrunner # github.com/onsi/gomega v1.7.0 github.com/onsi/gomega github.com/onsi/gomega/gexec +github.com/onsi/gomega/format github.com/onsi/gomega/internal/assertion github.com/onsi/gomega/internal/asyncassertion github.com/onsi/gomega/internal/testingtsupport github.com/onsi/gomega/matchers github.com/onsi/gomega/types -github.com/onsi/gomega/format github.com/onsi/gomega/gbytes github.com/onsi/gomega/internal/oraclematcher github.com/onsi/gomega/matchers/support/goraph/bipartitegraph diff --git a/version/version.go b/version/version.go index 2c4d69b78..c0dbeadfe 100644 --- a/version/version.go +++ b/version/version.go @@ -4,7 +4,7 @@ package version // NOTE: remember to bump the version at the top // of the top-level README.md file when this is // bumped. -const Version = "1.6.2-dev" +const Version = "1.6.3-dev" // RemoteAPIVersion is the version for the remote // client API. It is used to determine compatibility |