aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/create.go11
-rw-r--r--cmd/podman/exec.go29
-rw-r--r--cmd/podman/images.go27
-rw-r--r--cmd/podman/ps.go4
-rw-r--r--libpod/runtime.go9
-rw-r--r--pkg/rootless/rootless_linux.c2
-rw-r--r--pkg/rootless/rootless_linux.go1
-rw-r--r--test/README.md4
-rw-r--r--test/e2e/images_test.go12
-rw-r--r--test/e2e/load_test.go6
-rw-r--r--test/system/TODO.md105
11 files changed, 179 insertions, 31 deletions
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index fa8b9f57b..8a5d0cf73 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -893,7 +893,16 @@ func joinOrCreateRootlessUserNamespace(createConfig *cc.CreateConfig, runtime *l
}
return false, -1, errors.Errorf("dependency container %s is not running", ctr.ID())
}
- return rootless.JoinNS(uint(pid), 0)
+
+ data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
+ if err != nil {
+ return false, -1, errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
+ }
+ conmonPid, err := strconv.Atoi(string(data))
+ if err != nil {
+ return false, -1, errors.Wrapf(err, "cannot parse PID %q", data)
+ }
+ return rootless.JoinDirectUserAndMountNS(uint(conmonPid))
}
}
return rootless.BecomeRootInUserNS()
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go
index c3bcec2ec..e4cea1f5e 100644
--- a/cmd/podman/exec.go
+++ b/cmd/podman/exec.go
@@ -106,16 +106,25 @@ func execCmd(c *cliconfig.ExecValues) error {
}
- pid, err := ctr.PID()
- if err != nil {
- return err
- }
- became, ret, err := rootless.JoinNS(uint(pid), c.PreserveFDs)
- if err != nil {
- return err
- }
- if became {
- os.Exit(ret)
+ if os.Geteuid() != 0 {
+ var became bool
+ var ret int
+
+ data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
+ if err != nil {
+ return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
+ }
+ conmonPid, err := strconv.Atoi(string(data))
+ if err != nil {
+ return errors.Wrapf(err, "cannot parse PID %q", data)
+ }
+ became, ret, err = rootless.JoinDirectUserAndMountNS(uint(conmonPid))
+ if err != nil {
+ return err
+ }
+ if became {
+ os.Exit(ret)
+ }
}
// ENVIRONMENT VARIABLES
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index 78dc87ad5..f92e5d44d 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -2,6 +2,7 @@ package main
import (
"context"
+ "fmt"
"reflect"
"sort"
"strings"
@@ -128,7 +129,7 @@ func init() {
func imagesCmd(c *cliconfig.ImagesValues) error {
var (
filterFuncs []imagefilters.ResultFilter
- newImage *adapter.ContainerImage
+ image string
)
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
@@ -137,23 +138,23 @@ func imagesCmd(c *cliconfig.ImagesValues) error {
}
defer runtime.Shutdown(false)
if len(c.InputArgs) == 1 {
- newImage, err = runtime.NewImageFromLocal(c.InputArgs[0])
- if err != nil {
- return err
- }
+ image = c.InputArgs[0]
}
-
if len(c.InputArgs) > 1 {
return errors.New("'podman images' requires at most 1 argument")
}
-
+ if len(c.Filter) > 0 && image != "" {
+ return errors.New("can not specify an image and a filter")
+ }
ctx := getContext()
- if len(c.Filter) > 0 || newImage != nil {
- filterFuncs, err = CreateFilterFuncs(ctx, runtime, c.Filter, newImage)
- if err != nil {
- return err
- }
+ if len(c.Filter) > 0 {
+ filterFuncs, err = CreateFilterFuncs(ctx, runtime, c.Filter, nil)
+ } else {
+ filterFuncs, err = CreateFilterFuncs(ctx, runtime, []string{fmt.Sprintf("reference=%s", image)}, nil)
+ }
+ if err != nil {
+ return err
}
opts := imagesOptions{
@@ -174,7 +175,7 @@ func imagesCmd(c *cliconfig.ImagesValues) error {
var filteredImages []*adapter.ContainerImage
//filter the images
- if len(c.Filter) > 0 || newImage != nil {
+ if len(c.Filter) > 0 || len(c.InputArgs) == 1 {
filteredImages = imagefilters.FilterImages(images, filterFuncs)
} else {
filteredImages = images
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 9793d67f8..6caac2406 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -419,7 +419,7 @@ func generateContainerFilterFuncs(filter, filterValue string, runtime *libpod.Ru
return false
}, nil
case "status":
- if !util.StringInSlice(filterValue, []string{"created", "restarting", "running", "paused", "exited", "unknown"}) {
+ if !util.StringInSlice(filterValue, []string{"created", "running", "paused", "exited", "unknown"}) {
return nil, errors.Errorf("%s is not a valid status", filterValue)
}
return func(c *libpod.Container) bool {
@@ -430,6 +430,8 @@ func generateContainerFilterFuncs(filter, filterValue string, runtime *libpod.Ru
state := status.String()
if status == libpod.ContainerStateConfigured {
state = "created"
+ } else if status == libpod.ContainerStateStopped {
+ state = "exited"
}
return state == filterValue
}, nil
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 482cd9d73..9667abfe6 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -971,9 +971,12 @@ func (r *Runtime) refreshRootless() error {
// Take advantage of a command that requires a new userns
// so that we are running as the root user and able to use refresh()
cmd := exec.Command(os.Args[0], "info")
- err := cmd.Run()
- if err != nil {
- return errors.Wrapf(err, "Error running %s info while refreshing state", os.Args[0])
+
+ if output, err := cmd.CombinedOutput(); err != nil {
+ if _, ok := err.(*exec.ExitError); !ok {
+ return errors.Wrapf(err, "Error waiting for info while refreshing state: %s", os.Args[0])
+ }
+ return errors.Wrapf(err, "Error running %s info while refreshing state: %s", os.Args[0], output)
}
return nil
}
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 41acd3475..ff39e9e77 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -277,6 +277,8 @@ reexec_in_user_namespace (int ready)
_exit (EXIT_FAILURE);
}
close (ready);
+ if (b != '1')
+ _exit (EXIT_FAILURE);
if (syscall_setresgid (0, 0, 0) < 0)
{
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index 55fba900e..933cfa2c2 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -229,6 +229,7 @@ func BecomeRootInUserNS() (bool, int, error) {
}
defer r.Close()
defer w.Close()
+ defer w.Write([]byte("0"))
pidC := C.reexec_in_user_namespace(C.int(r.Fd()))
pid := int(pidC)
diff --git a/test/README.md b/test/README.md
index ef3bfbcf9..5e5a7da61 100644
--- a/test/README.md
+++ b/test/README.md
@@ -105,3 +105,7 @@ You can run the test with following command:
```
make localsystem
```
+
+## Contributing to system tests
+
+Please see [the TODO list of needed workflows/tests](system/TODO.md).
diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go
index 4cf58e5bf..4018bf355 100644
--- a/test/e2e/images_test.go
+++ b/test/e2e/images_test.go
@@ -112,6 +112,18 @@ var _ = Describe("Podman images", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(len(session.OutputToStringArray())).To(Equal(1))
+
+ session = podmanTest.Podman([]string{"tag", ALPINE, "foo:a"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ session = podmanTest.Podman([]string{"tag", BB, "foo:b"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"images", "-q", "foo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(2))
})
It("podman images filter reference", func() {
diff --git a/test/e2e/load_test.go b/test/e2e/load_test.go
index 571754347..75c8e4850 100644
--- a/test/e2e/load_test.go
+++ b/test/e2e/load_test.go
@@ -190,7 +190,7 @@ var _ = Describe("Podman load", func() {
load.WaitWithDefaultTimeout()
Expect(load.ExitCode()).To(Equal(0))
- result := podmanTest.Podman([]string{"images", "-f", "label", "hello:world"})
+ result := podmanTest.Podman([]string{"images", "hello:world"})
result.WaitWithDefaultTimeout()
Expect(result.LineInOutputContains("docker")).To(Not(BeTrue()))
Expect(result.LineInOutputContains("localhost")).To(BeTrue())
@@ -216,7 +216,7 @@ var _ = Describe("Podman load", func() {
load.WaitWithDefaultTimeout()
Expect(load.ExitCode()).To(Equal(0))
- result := podmanTest.Podman([]string{"images", "-f", "label", "hello:latest"})
+ result := podmanTest.Podman([]string{"images", "hello:latest"})
result.WaitWithDefaultTimeout()
Expect(result.LineInOutputContains("docker")).To(Not(BeTrue()))
Expect(result.LineInOutputContains("localhost")).To(BeTrue())
@@ -241,7 +241,7 @@ var _ = Describe("Podman load", func() {
load.WaitWithDefaultTimeout()
Expect(load.ExitCode()).To(Equal(0))
- result := podmanTest.Podman([]string{"images", "-f", "label", "load:latest"})
+ result := podmanTest.Podman([]string{"images", "load:latest"})
result.WaitWithDefaultTimeout()
Expect(result.LineInOutputContains("docker")).To(Not(BeTrue()))
Expect(result.LineInOutputContains("localhost")).To(BeTrue())
diff --git a/test/system/TODO.md b/test/system/TODO.md
new file mode 100644
index 000000000..f6110d2e9
--- /dev/null
+++ b/test/system/TODO.md
@@ -0,0 +1,105 @@
+![PODMAN logo](../../logo/podman-logo-source.svg)
+
+# Overview
+
+System tests exercise Podman in the context of a complete, composed environment from
+distribution packages. It should match as closely as possible to how an end-user
+would experience a fresh-install. Dependencies on external configuration and resources
+must be kept minimal, and the tests must be generic and vendor-neutral.
+
+The system-tests must execute cleanly on all tested platforms. They may optionally
+be executed during continuous-integration testing of code-changes, after all other
+testing completes successfully. For a list of tested platforms, please see [the
+CI configuration file.](../../.cirrus.yml)
+
+
+# Execution
+
+When working from a clone of [the libpod repository](https://github.com/containers/libpod),
+the main entry-point for humans and automation is `make localsystem`. When operating
+from a packaged version of the system-tests, the entry-point may vary as appropriate.
+Running the packaged system-tests assumes the version of Podman matches the test
+version, and all standard dependencies are installed.
+
+
+# Test Design and overview
+
+System-tests should be high-level and user work-flow oriented. For example, consider
+how multiple Podman invocations would be used together by an end-user. The set of
+related commands should be considered a single test. If one or more intermediate
+commands fail, the test could still pass if the end-result is still achieved.
+
+
+# *TODO*: List of needed System-tests
+
+***Note***: Common operations (like `rm` and `rmi` for cleanup/reset)
+have been omitted as they are verified by repeated implied use.
+
+- [ ] pull, build, run, attach, commit, diff, inspect
+
+ - Pull existing image from registry
+ - Build new image FROM explicitly pulled image
+ - Run built container in detached mode
+ - Attach to running container, execute command to modify storage.
+ - Commit running container to new image w/ changed ENV VAR
+ - Verify attach + commit using diff
+ - verify changed ENV VAR with inspect
+
+- [ ] Implied pull, create, start, exec, log, stop, wait, rm
+
+ - Create non-existing local image
+ - start stopped container
+ - exec simple command in running container
+ - verify exec result with log
+ - wait on running container
+ - stop running container with 2 second timeout
+ - verify wait in 4 seconds or less
+ - verify stopped by rm **without** --force
+
+- [ ] Implied pull, build, export, modify, import, tag, run, kill
+
+ - Build from Dockerfile FROM non-existing local image
+ - Export built container as tarball
+ - Modify tarball contents
+ - Import tarball
+ - Tag imported image
+ - Run imported image to confirm tarball modification, block on non-special signal
+ - Kill can send non-TERM/KILL signal to container to exit
+ - Confirm exit within timeout
+
+- [ ] Container runlabel, exists, checkpoint, exists, restore, stop, prune
+
+ - Using pre-existing remote image, start it with 'podman container runlabel --pull'
+ - Run a named container that exits immediatly
+ - Confirm 'container exists' zero exit (both containers)
+ - Checkpoint the running container
+ - Confirm 'container exists' non-zero exit (runlabel container)
+ - Confirm 'container exists' zero exit (named container)
+ - Run 'container restore'
+ - Confirm 'container exists' zero exit (both containers)
+ - Stop container
+ - Run 'container prune'
+ - Confirm `podman ps -a` lists no containers
+
+
+# TODO: List of commands to be combined into additional workflows above.
+
+- podman-remote (workflow TBD)
+- history
+- image
+- load
+- mount
+- pause
+- pod
+- port
+- login, push, & logout (difficult, save for last)
+- restart
+- save
+- search
+- stats
+- top
+- umount, unmount
+- unpause
+- volume
+- `--namespace`
+- `--storage-driver`