summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xAPI.md9
-rw-r--r--CONTRIBUTING.md14
-rw-r--r--Makefile2
-rw-r--r--RELEASE_NOTES.md31
-rw-r--r--changelog.txt43
-rw-r--r--cmd/podman/build.go2
-rw-r--r--cmd/podman/cliconfig/config.go1
-rw-r--r--cmd/podman/commands.go5
-rw-r--r--cmd/podman/common.go13
-rw-r--r--cmd/podman/container.go51
-rw-r--r--cmd/podman/containers_prune.go1
-rw-r--r--cmd/podman/cp.go15
-rw-r--r--cmd/podman/errors.go5
-rw-r--r--cmd/podman/errors_remote.go43
-rw-r--r--cmd/podman/exec.go10
-rw-r--r--cmd/podman/image.go41
-rw-r--r--cmd/podman/images.go30
-rw-r--r--cmd/podman/images_prune.go1
-rw-r--r--cmd/podman/info.go1
-rw-r--r--cmd/podman/main.go3
-rw-r--r--cmd/podman/play_kube.go11
-rw-r--r--cmd/podman/pod_create.go4
-rw-r--r--cmd/podman/pod_ps.go5
-rw-r--r--cmd/podman/pod_start.go2
-rw-r--r--cmd/podman/port.go6
-rw-r--r--cmd/podman/ps.go45
-rw-r--r--cmd/podman/refresh.go6
-rw-r--r--cmd/podman/rmi.go16
-rw-r--r--cmd/podman/runlabel.go7
-rw-r--r--cmd/podman/stop.go67
-rw-r--r--cmd/podman/system_prune.go1
-rw-r--r--cmd/podman/system_renumber.go1
-rw-r--r--cmd/podman/varlink.go3
-rw-r--r--cmd/podman/varlink/io.podman.varlink5
-rw-r--r--cmd/podman/version.go1
-rw-r--r--cmd/podman/volume_ls.go5
-rw-r--r--cmd/podman/volume_prune.go1
-rw-r--r--completions/bash/podman2
-rw-r--r--docs/podman-container-refresh.1.md25
-rw-r--r--docs/podman-container-runlabel.1.md6
-rw-r--r--docs/podman-container.1.md12
-rw-r--r--docs/podman-image.1.md7
-rw-r--r--docs/podman-system.1.md2
-rw-r--r--docs/podman.1.md2
-rwxr-xr-xhack/podman-commands.sh122
-rw-r--r--libpod/container_api.go5
-rw-r--r--libpod/container_internal_linux.go19
-rw-r--r--libpod/oci.go29
-rw-r--r--libpod/runtime.go6
-rw-r--r--pkg/adapter/containers.go72
-rw-r--r--pkg/adapter/containers_remote.go109
-rw-r--r--pkg/adapter/runtime.go9
-rw-r--r--pkg/adapter/runtime_remote.go76
-rw-r--r--pkg/adapter/shortcuts/shortcuts.go27
-rw-r--r--pkg/rootless/rootless_linux.go3
-rw-r--r--pkg/varlinkapi/containers.go16
-rw-r--r--test/e2e/attach_test.go10
-rw-r--r--test/e2e/checkpoint_test.go18
-rw-r--r--test/e2e/commit_test.go15
-rw-r--r--test/e2e/create_test.go7
-rw-r--r--test/e2e/diff_test.go7
-rw-r--r--test/e2e/exec_test.go10
-rw-r--r--test/e2e/export_test.go16
-rw-r--r--test/e2e/images_test.go41
-rw-r--r--test/e2e/kill_test.go13
-rw-r--r--test/e2e/load_test.go4
-rw-r--r--test/e2e/mount_test.go15
-rw-r--r--test/e2e/pause_test.go17
-rw-r--r--test/e2e/pod_create_test.go2
-rw-r--r--test/e2e/port_test.go13
-rw-r--r--test/e2e/ps_test.go15
-rw-r--r--test/e2e/pull_test.go36
-rw-r--r--test/e2e/push_test.go70
-rw-r--r--test/e2e/restart_test.go15
-rw-r--r--test/e2e/rm_test.go11
-rw-r--r--test/e2e/rmi_test.go9
-rw-r--r--test/e2e/run_cleanup_test.go6
-rw-r--r--test/e2e/run_networking_test.go33
-rw-r--r--test/e2e/run_ns_test.go3
-rw-r--r--test/e2e/run_privileged_test.go3
-rw-r--r--test/e2e/run_test.go15
-rw-r--r--test/e2e/start_test.go10
-rw-r--r--test/e2e/stop_test.go9
-rw-r--r--test/e2e/systemd_test.go22
-rw-r--r--test/e2e/top_test.go11
-rw-r--r--test/e2e/wait_test.go7
-rwxr-xr-xtest/test_podman_baseline.sh2
-rw-r--r--test/utils/utils.go1
88 files changed, 1084 insertions, 438 deletions
diff --git a/API.md b/API.md
index c4f23c9bd..d255037c1 100755
--- a/API.md
+++ b/API.md
@@ -43,6 +43,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func GetContainerStats(name: string) ContainerStats](#GetContainerStats)
+[func GetContainersByContext(all: bool, latest: bool, args: []string) []string](#GetContainersByContext)
+
[func GetImage(id: string) Image](#GetImage)
[func GetInfo() PodmanInfo](#GetInfo)
@@ -460,6 +462,13 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.GetContainerStats '{"name
}
}
~~~
+### <a name="GetContainersByContext"></a>func GetContainersByContext
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method GetContainersByContext(all: [bool](https://godoc.org/builtin#bool), latest: [bool](https://godoc.org/builtin#bool), args: [[]string](#[]string)) [[]string](#[]string)</div>
+GetContainersByContext allows you to get a list of container ids depending on all, latest, or a list of
+container names. The definition of latest container means the latest by creation date. In a multi-
+user environment, results might differ from what you expect.
### <a name="GetImage"></a>func GetImage
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b1b166fef..3778d6d7d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -329,10 +329,16 @@ author hold special privileges on the github repository. Others can be used by
unintentionally. Instead, just write ``LGTM``, or
spell it out.
-* ``[skip ci]``: Within the HEAD commit will cause Cirrus CI to ***NOT*** execute
- tests on the PR. This is useful in basically two cases: 1) You're still working
- and don't want to waste resources. 2) You haven't modified any code that would
- be exercised by the tests. For example, documentation updates (outside of code).
+* ``/hold`` and ``/unhold``: Override the automatic handling of a request. Either
+ put it on hold (no handling) or remove the hold (normal handling).
+
+* ``[ci skip]``: [Adding `[ci skip]` within the HEAD commit](https://cirrus-ci.org/guide/writing-tasks/#conditional-task-execution)
+ will cause Cirrus CI to ***NOT*** execute tests for the PR or after merge. This
+ is useful in only one instance: Your changes are absolutely not exercised by
+ any test. For example, documentation changes. ***IMPORTANT NOTE*** **Other
+ automation may interpret the lack of test results as "PASSED" and unintentionall
+ merge a PR. Consider also using `/hold` in a comment, to add additional
+ protection.**
[The complete list may be found on the command-help page.](https://prow.k8s.io/command-help)
However, not all commands are implemented for this repository. If in doubt, ask a maintainer.
diff --git a/Makefile b/Makefile
index 7e2c98b8a..60fb3eda7 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
GO ?= go
DESTDIR ?= /
-EPOCH_TEST_COMMIT ?= 174e8997aa0d8fc648564a9ac2a79ab786e87362
+EPOCH_TEST_COMMIT ?= cabfc9b6fb16c5b55d70140182496bbe129f6a4b
HEAD ?= HEAD
CHANGELOG_BASE ?= HEAD~
CHANGELOG_TARGET ?= HEAD
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 0bacad0d7..67975730e 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,34 @@
# Release Notes
+## 1.1.1
+### Bugfixes
+- Fixed a bug where `podman container restore` was erroneously available as `podman restore` ([#2191](https://github.com/containers/libpod/issues/2191))
+- Fixed a bug where the `volume_path` option in `libpod.conf` was not being respected
+- Fixed a bug where Podman failed to build when the `varlink` tag was not present ([#2459](https://github.com/containers/libpod/issues/2459))
+- Fixed a bug where the `podman image load` command was listed twice in help text
+- Fixed a bug where the `podman image sign` command was also listed as `podman sign`
+- Fixed a bug where the `podman image list` command incorrectly had an `image` alias
+- Fixed a bug where the `podman images` command incorrectly had `ls` and `list` aliases
+- Fixed a bug where the `podman image rm` command was being displayed as `podman image rmi`
+- Fixed a bug where the `podman create` command would attempt to parse arguments meant for the container
+- Fixed a bug where the combination of FIPS mode and user namespaces resulted in permissions errors
+- Fixed a bug where the `--time` alias for `--timeout` for the `podman restart` and `podman stop` commands did not function
+- Fixed a bug where the default stop timeout for newly-created containers was being set to 0 seconds (resulting in an immediate SIGKILL on running `podman stop`)
+- Fixed a bug where the output format of `podman port` was incorrect, printing full container ID instead of truncated ID
+- Fixed a bug where the `podman container list` command did not exist
+- Fixed a bug where `podman build` could not build a container from images tagged locally that did not exist in a registry ([#2469](https://github.com/containers/libpod/issues/2469))
+- Fixed a bug where some Podman commands that accept no arguments would not error when provided arguments
+- Fixed a bug where `podman play kube` could not handle cases where a pod and a container shared a name
+
+### Misc
+- Usage text for many commands was greatly improved
+- Major cleanups were made to Podman manpages, ensuring that command lists are accurate
+- Greatly improved debugging output when the `newuidmap` and `newgidmap` binaries fail when using rootless Podman
+- The `-s` alias for the global `--storage-driver` option has been removed
+- The `podman container refresh` command has been deprecated, as its intended use case is no longer relevant. The command has been hidden and manpages deleted. It will be removed in a future release
+- The `podman container runlabel` command will now pull images not available locally even without the `--pull` option. The `--pull` option has been deprecated
+- The `podman container checkpoint` and `podman container restore` commands are now only available on OCI runtimes where they are supported (e.g. `runc`)
+
## 1.1.0
### Features
- Added `--latest` and `--all` flags to `podman mount` and `podman umount`
@@ -59,7 +88,7 @@
- Updated Buildah to v1.7, picking up a number of bugfixes
- Updated containers/image library to v1.5, picking up a number of bugfixes and performance improvements to pushing images
- Updated containers/storage library to v1.10, picking up a number of bugfixes
-- Work on the remote Podman client for interacting with Podman remotely over Varlink is progressing steadily, and many image and pod commands are supported
+- Work on the remote Podman client for interacting with Podman remotely over Varlink is progressing steadily, and many image and pod commands are supported - please see the [Readme](https://github.com/containers/libpod/blob/master/remote_client.md) for details
- Added path masking to mounts with the `:z` and `:Z` options, preventing users from accidentally performing an SELinux relabel of their entire home directory
- The `podman container runlabel` command will not pull an image if it does not contain the requested label
- Many commands' usage information now includes examples
diff --git a/changelog.txt b/changelog.txt
index 803aad796..9dd0ae2d1 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,46 @@
+- Changelog for v1.1.1 (2019-03-01)
+ * Update release notes for v1.1.1
+ * Pull image for runlabel if not local
+ * Fix SystemExec completion race
+ * Fix link inconsistencies in man pages
+ * Verify that used OCI runtime supports checkpoint
+ * Should be defaulting to pull not pull-always
+ * podman-commands script: refactor
+ * Move Alias lines to descriptions of commands
+ * Fix usage messages for podman image list, rm
+ * Fix -s to --storage-driver in baseline test
+ * No podman container ps command exists
+ * Allow Exec API user to override streams
+ * fix up a number of misplace commands
+ * rootless, new[ug]idmap: on failure add output
+ * [ci skip] Critical note about merge bot
+ * podman port fix output
+ * Fix ignored --time argument to podman restart
+ * secrets: fix fips-mode with user namespaces
+ * Fix four errors tagged by Cobra macro debugging
+ * Clean up man pages to match commands
+ * Add debugging for errors to Cobra compatibility macros
+ * Command-line input validation: reject unused args
+ * Fix ignored --stop-timeout flag to 'podman create'
+ * fixup! Incorporate review feedback
+ * fixup! missed some more:
+ * fixup! Correction to 'checkpoint'
+ * Followup to #2456: update examples, add trust
+ * podman create: disable interspersed opts
+ * fix up a number of misplace commands
+ * Add a task to Cirrus gating to build w/o Varlink
+ * Skip checkpoint/restore tests on Fedora for now
+ * Fix build for non-Varlink-tagged Podman
+ * Remove restore as podman subcommand
+ * Better usage synopses for subcommands
+ * Bump gitvalidation epoch
+ * Bump to v1.2.0-dev
+ * Centralize setting default volume path
+ * Ensure volume path is set appropriately by default
+ * Move all storage configuration defaults into libpod
+ * rename pod when we have a name collision with a container
+ * podman remote-client readme
+
- Changelog for v1.1.0 (2019-02-26)
* Vendor in latest buildah 1.7.1
* volume: do not create a volume if there is a bind
diff --git a/cmd/podman/build.go b/cmd/podman/build.go
index 8ea9e6957..cfeabfb4e 100644
--- a/cmd/podman/build.go
+++ b/cmd/podman/build.go
@@ -53,7 +53,7 @@ func init() {
flags.SetInterspersed(false)
budFlags := buildahcli.GetBudFlags(&budFlagsValues)
- flag := budFlags.Lookup("pull-always")
+ flag := budFlags.Lookup("pull")
flag.Value.Set("true")
flag.DefValue = "true"
layerFlags := buildahcli.GetLayerFlags(&layerValues)
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index a9032202f..702e20040 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -409,7 +409,6 @@ type RunlabelValues struct {
Opt2 string
Opt3 string
Quiet bool
- Pull bool
SignaturePolicy string
TlsVerify bool
}
diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go
index fd36e77d5..c261e54e2 100644
--- a/cmd/podman/commands.go
+++ b/cmd/podman/commands.go
@@ -18,7 +18,7 @@ func getMainCommands() []*cobra.Command {
_execCommand,
_generateCommand,
_playCommand,
- _psCommand,
+ &_psCommand,
_loginCommand,
_logoutCommand,
_logsCommand,
@@ -32,7 +32,6 @@ func getMainCommands() []*cobra.Command {
_searchCommand,
_startCommand,
_statsCommand,
- _stopCommand,
_topCommand,
_umountCommand,
_unpauseCommand,
@@ -54,6 +53,7 @@ func getImageSubCommands() []*cobra.Command {
// Commands that the local client implements
func getContainerSubCommands() []*cobra.Command {
+
return []*cobra.Command{
_attachCommand,
_checkpointCommand,
@@ -65,7 +65,6 @@ func getContainerSubCommands() []*cobra.Command {
_exportCommand,
_killCommand,
_logsCommand,
- _psCommand,
_mountCommand,
_pauseCommand,
_portCommand,
diff --git a/cmd/podman/common.go b/cmd/podman/common.go
index f9dfa3759..c9e937825 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -59,6 +59,14 @@ func checkAllAndLatest(c *cobra.Command, args []string, ignoreArgLen bool) error
return nil
}
+// noSubArgs checks that there are no further positional parameters
+func noSubArgs(c *cobra.Command, args []string) error {
+ if len(args) > 0 {
+ return errors.Errorf("`%s` takes no arguments", c.CommandPath())
+ }
+ return nil
+}
+
// getAllOrLatestContainers tries to return the correct list of containers
// depending if --all, --latest or <container-id> is used.
// It requires the Context (c) and the Runtime (runtime). As different
@@ -303,8 +311,8 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"kernel-memory", "",
"Kernel memory limit (format: `<number>[<unit>]`, where unit = b, k, m or g)",
)
- createFlags.StringSlice(
- "label", []string{},
+ createFlags.StringSliceP(
+ "label", "l", []string{},
"Set metadata on container (default [])",
)
createFlags.StringSlice(
@@ -519,7 +527,6 @@ func scrubServer(server string) string {
func UsageTemplate() string {
return `Usage:{{if .Runnable}}
{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
-
{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
Aliases:
diff --git a/cmd/podman/container.go b/cmd/podman/container.go
index d2450fdd3..0bcdf533a 100644
--- a/cmd/podman/container.go
+++ b/cmd/podman/container.go
@@ -1,28 +1,53 @@
package main
import (
+ "strings"
+
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/spf13/cobra"
)
-var containerDescription = "Manage containers"
-var containerCommand = cliconfig.PodmanCommand{
- Command: &cobra.Command{
- Use: "container",
- Short: "Manage Containers",
- Long: containerDescription,
- TraverseChildren: true,
- },
-}
+var (
+ containerDescription = "Manage containers"
+ containerCommand = cliconfig.PodmanCommand{
+ Command: &cobra.Command{
+ Use: "container",
+ Short: "Manage Containers",
+ Long: containerDescription,
+ TraverseChildren: true,
+ },
+ }
-// Commands that are universally implemented.
-var containerCommands = []*cobra.Command{
- _containerExistsCommand,
-}
+ listSubCommand cliconfig.PsValues
+ _listSubCommand = &cobra.Command{
+ Use: strings.Replace(_psCommand.Use, "ps", "list", 1),
+ Args: noSubArgs,
+ Short: _psCommand.Short,
+ Long: _psCommand.Long,
+ Aliases: []string{"ls"},
+ RunE: func(cmd *cobra.Command, args []string) error {
+ listSubCommand.InputArgs = args
+ listSubCommand.GlobalFlags = MainGlobalOpts
+ return psCmd(&listSubCommand)
+ },
+ Example: strings.Replace(_psCommand.Example, "podman ps", "podman container list", -1),
+ }
+
+ // Commands that are universally implemented.
+ containerCommands = []*cobra.Command{
+ _containerExistsCommand,
+ _inspectCommand,
+ _listSubCommand,
+ }
+)
func init() {
+ listSubCommand.Command = _listSubCommand
+ psInit(&listSubCommand)
+
containerCommand.AddCommand(containerCommands...)
containerCommand.AddCommand(getContainerSubCommands()...)
containerCommand.SetUsageTemplate(UsageTemplate())
+
rootCmd.AddCommand(containerCommand.Command)
}
diff --git a/cmd/podman/containers_prune.go b/cmd/podman/containers_prune.go
index 6e4960429..0d0e75332 100644
--- a/cmd/podman/containers_prune.go
+++ b/cmd/podman/containers_prune.go
@@ -21,6 +21,7 @@ var (
`
_pruneContainersCommand = &cobra.Command{
Use: "prune",
+ Args: noSubArgs,
Short: "Remove all stopped containers",
Long: pruneContainersDescription,
RunE: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go
index 30b6d75d2..5958370b6 100644
--- a/cmd/podman/cp.go
+++ b/cmd/podman/cp.go
@@ -240,7 +240,6 @@ func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, ch
// return functions for copying items
copyFileWithTar := chrootarchive.CopyFileWithTarAndChown(chownOpts, digest.Canonical.Digester().Hash(), idMappingOpts.UIDMap, idMappingOpts.GIDMap)
copyWithTar := chrootarchive.CopyWithTarAndChown(chownOpts, digest.Canonical.Digester().Hash(), idMappingOpts.UIDMap, idMappingOpts.GIDMap)
- untarPath := chrootarchive.UntarPathAndChown(chownOpts, digest.Canonical.Digester().Hash(), idMappingOpts.UIDMap, idMappingOpts.GIDMap)
if srcfi.IsDir() {
@@ -263,17 +262,11 @@ func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, ch
if destfi != nil && destfi.IsDir() {
destPath = filepath.Join(destPath, filepath.Base(srcPath))
}
- // Copy the file, preserving attributes.
- logrus.Debugf("copying %q to %q", srcPath, destPath)
- if err = copyFileWithTar(srcPath, destPath); err != nil {
- return errors.Wrapf(err, "error copying %q to %q", srcPath, destPath)
- }
- return nil
}
- // We're extracting an archive into the destination directory.
- logrus.Debugf("extracting contents of %q into %q", srcPath, destPath)
- if err = untarPath(srcPath, destPath); err != nil {
- return errors.Wrapf(err, "error extracting %q into %q", srcPath, destPath)
+ // Copy the file, preserving attributes.
+ logrus.Debugf("copying %q to %q", srcPath, destPath)
+ if err = copyFileWithTar(srcPath, destPath); err != nil {
+ return errors.Wrapf(err, "error copying %q to %q", srcPath, destPath)
}
return nil
}
diff --git a/cmd/podman/errors.go b/cmd/podman/errors.go
index 2572b8779..9731037f4 100644
--- a/cmd/podman/errors.go
+++ b/cmd/podman/errors.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package main
import (
@@ -13,7 +15,8 @@ func outputError(err error) {
if MainGlobalOpts.LogLevel == "debug" {
logrus.Errorf(err.Error())
} else {
- if ee, ok := err.(*exec.ExitError); ok {
+ ee, ok := err.(*exec.ExitError)
+ if ok {
if status, ok := ee.Sys().(syscall.WaitStatus); ok {
exitCode = status.ExitStatus()
}
diff --git a/cmd/podman/errors_remote.go b/cmd/podman/errors_remote.go
new file mode 100644
index 000000000..ab255ea56
--- /dev/null
+++ b/cmd/podman/errors_remote.go
@@ -0,0 +1,43 @@
+// +build remoteclient
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "syscall"
+
+ "github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+func outputError(err error) {
+ if MainGlobalOpts.LogLevel == "debug" {
+ logrus.Errorf(err.Error())
+ } else {
+ if ee, ok := err.(*exec.ExitError); ok {
+ if status, ok := ee.Sys().(syscall.WaitStatus); ok {
+ exitCode = status.ExitStatus()
+ }
+ }
+ var ne error
+ switch e := err.(type) {
+ // For some reason golang wont let me list them with commas so listing them all.
+ case *iopodman.ImageNotFound:
+ ne = errors.New(e.Reason)
+ case *iopodman.ContainerNotFound:
+ ne = errors.New(e.Reason)
+ case *iopodman.PodNotFound:
+ ne = errors.New(e.Reason)
+ case *iopodman.VolumeNotFound:
+ ne = errors.New(e.Reason)
+ case *iopodman.ErrorOccurred:
+ ne = errors.New(e.Reason)
+ default:
+ ne = err
+ }
+ fmt.Fprintln(os.Stderr, "Error:", ne.Error())
+ }
+}
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go
index 032262497..4917fb606 100644
--- a/cmd/podman/exec.go
+++ b/cmd/podman/exec.go
@@ -105,5 +105,13 @@ func execCmd(c *cliconfig.ExecValues) error {
envs = append(envs, fmt.Sprintf("%s=%s", k, v))
}
- return ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir)
+ streams := new(libpod.AttachStreams)
+ streams.OutputStream = os.Stdout
+ streams.ErrorStream = os.Stderr
+ streams.InputStream = os.Stdin
+ streams.AttachOutput = true
+ streams.AttachError = true
+ streams.AttachInput = true
+
+ return ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir, streams)
}
diff --git a/cmd/podman/image.go b/cmd/podman/image.go
index aaa1866c4..57be7fe14 100644
--- a/cmd/podman/image.go
+++ b/cmd/podman/image.go
@@ -1,6 +1,8 @@
package main
import (
+ "strings"
+
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/spf13/cobra"
)
@@ -14,13 +16,39 @@ var (
Long: imageDescription,
},
}
- _imagesSubCommand = _imagesCommand
+ imagesSubCommand cliconfig.ImagesValues
+ _imagesSubCommand = &cobra.Command{
+ Use: strings.Replace(_imagesCommand.Use, "images", "list", 1),
+ Short: _imagesCommand.Short,
+ Long: _imagesCommand.Long,
+ Aliases: []string{"ls"},
+ RunE: func(cmd *cobra.Command, args []string) error {
+ imagesSubCommand.InputArgs = args
+ imagesSubCommand.GlobalFlags = MainGlobalOpts
+ return imagesCmd(&imagesSubCommand)
+ },
+ Example: strings.Replace(_imagesCommand.Example, "podman images", "podman image list", -1),
+ }
+
+ rmSubCommand cliconfig.RmiValues
+ _rmSubCommand = &cobra.Command{
+ Use: strings.Replace(_rmiCommand.Use, "rmi", "rm", 1),
+ Short: _rmiCommand.Short,
+ Long: _rmiCommand.Long,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ rmSubCommand.InputArgs = args
+ rmSubCommand.GlobalFlags = MainGlobalOpts
+ return rmiCmd(&rmSubCommand)
+ },
+ Example: strings.Replace(_rmiCommand.Example, "podman rmi", "podman image rm", -1),
+ }
)
//imageSubCommands are implemented both in local and remote clients
var imageSubCommands = []*cobra.Command{
_buildCommand,
_historyCommand,
+ _imagesSubCommand,
_imageExistsCommand,
_importCommand,
_inspectCommand,
@@ -28,17 +56,20 @@ var imageSubCommands = []*cobra.Command{
_pruneImagesCommand,
_pullCommand,
_pushCommand,
- _rmiCommand,
+ _rmSubCommand,
_saveCommand,
_tagCommand,
}
func init() {
+ rmSubCommand.Command = _rmSubCommand
+ rmiInit(&rmSubCommand)
+
+ imagesSubCommand.Command = _imagesSubCommand
+ imagesInit(&imagesSubCommand)
+
imageCommand.SetUsageTemplate(UsageTemplate())
imageCommand.AddCommand(imageSubCommands...)
imageCommand.AddCommand(getImageSubCommands()...)
- _imagesSubCommand.Aliases = []string{"ls", "list"}
- imageCommand.AddCommand(&_imagesSubCommand)
-
}
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index e6f4d9a60..26e51bef7 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -102,22 +102,26 @@ var (
}
)
-func init() {
- imagesCommand.Command = &_imagesCommand
- imagesCommand.SetUsageTemplate(UsageTemplate())
-
- flags := imagesCommand.Flags()
- flags.BoolVarP(&imagesCommand.All, "all", "a", false, "Show all images (default hides intermediate images)")
- flags.BoolVar(&imagesCommand.Digests, "digests", false, "Show digests")
- flags.StringSliceVarP(&imagesCommand.Filter, "filter", "f", []string{}, "Filter output based on conditions provided (default [])")
- flags.StringVar(&imagesCommand.Format, "format", "", "Change the output format to JSON or a Go template")
- flags.BoolVarP(&imagesCommand.Noheading, "noheading", "n", false, "Do not print column headings")
+func imagesInit(command *cliconfig.ImagesValues) {
+ command.SetUsageTemplate(UsageTemplate())
+
+ flags := command.Flags()
+ flags.BoolVarP(&command.All, "all", "a", false, "Show all images (default hides intermediate images)")
+ flags.BoolVar(&command.Digests, "digests", false, "Show digests")
+ flags.StringSliceVarP(&command.Filter, "filter", "f", []string{}, "Filter output based on conditions provided (default [])")
+ flags.StringVar(&command.Format, "format", "", "Change the output format to JSON or a Go template")
+ flags.BoolVarP(&command.Noheading, "noheading", "n", false, "Do not print column headings")
// TODO Need to learn how to deal with second name being a string instead of a char.
// This needs to be "no-trunc, notruncate"
- flags.BoolVar(&imagesCommand.NoTrunc, "no-trunc", false, "Do not truncate output")
- flags.BoolVarP(&imagesCommand.Quiet, "quiet", "q", false, "Display only image IDs")
- flags.StringVar(&imagesCommand.Sort, "sort", "created", "Sort by created, id, repository, size, or tag")
+ flags.BoolVar(&command.NoTrunc, "no-trunc", false, "Do not truncate output")
+ flags.BoolVarP(&command.Quiet, "quiet", "q", false, "Display only image IDs")
+ flags.StringVar(&command.Sort, "sort", "created", "Sort by created, id, repository, size, or tag")
+
+}
+func init() {
+ imagesCommand.Command = &_imagesCommand
+ imagesInit(&imagesCommand)
}
func imagesCmd(c *cliconfig.ImagesValues) error {
diff --git a/cmd/podman/images_prune.go b/cmd/podman/images_prune.go
index 79dcd097c..427374f68 100644
--- a/cmd/podman/images_prune.go
+++ b/cmd/podman/images_prune.go
@@ -18,6 +18,7 @@ var (
`
_pruneImagesCommand = &cobra.Command{
Use: "prune",
+ Args: noSubArgs,
Short: "Remove unused images",
Long: pruneImagesDescription,
RunE: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/info.go b/cmd/podman/info.go
index a1473dac9..e87f4e151 100644
--- a/cmd/podman/info.go
+++ b/cmd/podman/info.go
@@ -19,6 +19,7 @@ var (
infoDescription = "Display podman system information"
_infoCommand = &cobra.Command{
Use: "info",
+ Args: noSubArgs,
Long: infoDescription,
Short: `Display information pertaining to the host, current storage stats, and build of podman. Useful for the user and when reporting issues.`,
RunE: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index d36270853..b3faf05c0 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -47,8 +47,9 @@ var mainCommands = []*cobra.Command{
podCommand.Command,
_pullCommand,
_pushCommand,
- _rmiCommand,
+ &_rmiCommand,
_saveCommand,
+ _stopCommand,
_tagCommand,
_versionCommand,
imageCommand.Command,
diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go
index 6f23e340e..ac46ad5c6 100644
--- a/cmd/podman/play_kube.go
+++ b/cmd/podman/play_kube.go
@@ -90,8 +90,17 @@ func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error {
return errors.Wrapf(err, "unable to read %s as YAML", args[0])
}
+ // check for name collision between pod and container
+ podName := podYAML.ObjectMeta.Name
+ for _, n := range podYAML.Spec.Containers {
+ if n.Name == podName {
+ fmt.Printf("a container exists with the same name (%s) as the pod in your YAML file; changing pod name to %s_pod\n", podName, podName)
+ podName = fmt.Sprintf("%s_pod", podName)
+ }
+ }
+
podOptions = append(podOptions, libpod.WithInfraContainer())
- podOptions = append(podOptions, libpod.WithPodName(podYAML.ObjectMeta.Name))
+ podOptions = append(podOptions, libpod.WithPodName(podName))
// TODO for now we just used the default kernel namespaces; we need to add/subtract this from yaml
nsOptions, err := shared.GetNamespaceOptions(strings.Split(DefaultKernelNamespaces, ","))
diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go
index f1bbecb84..43c211b2c 100644
--- a/cmd/podman/pod_create.go
+++ b/cmd/podman/pod_create.go
@@ -24,6 +24,7 @@ var (
_podCreateCommand = &cobra.Command{
Use: "create",
+ Args: noSubArgs,
Short: "Create a new empty pod",
Long: podCreateDescription,
RunE: func(cmd *cobra.Command, args []string) error {
@@ -59,9 +60,6 @@ func podCreateCmd(c *cliconfig.PodCreateValues) error {
podIdFile *os.File
)
- if len(c.InputArgs) > 0 {
- return errors.New("podman pod create does not accept any arguments")
- }
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
diff --git a/cmd/podman/pod_ps.go b/cmd/podman/pod_ps.go
index 70e077651..8e48740e6 100644
--- a/cmd/podman/pod_ps.go
+++ b/cmd/podman/pod_ps.go
@@ -121,6 +121,7 @@ var (
_podPsCommand = &cobra.Command{
Use: "ps",
Aliases: []string{"ls", "list"},
+ Args: noSubArgs,
Short: "List pods",
Long: podPsDescription,
RunE: func(cmd *cobra.Command, args []string) error {
@@ -160,10 +161,6 @@ func podPsCmd(c *cliconfig.PodPsValues) error {
}
defer runtime.Shutdown(false)
- if len(c.InputArgs) > 0 {
- return errors.Errorf("too many arguments, ps takes no arguments")
- }
-
opts := podPsOptions{
NoTrunc: c.NoTrunc,
Quiet: c.Quiet,
diff --git a/cmd/podman/pod_start.go b/cmd/podman/pod_start.go
index eef9d2a71..ca8ad08cf 100644
--- a/cmd/podman/pod_start.go
+++ b/cmd/podman/pod_start.go
@@ -18,7 +18,7 @@ var (
Starts one or more pods. The pod name or ID can be used.
`
_podStartCommand = &cobra.Command{
- Use: "start POD [POD...]",
+ Use: "start [flags] POD [POD...]",
Short: "Start one or more pods",
Long: podStartDescription,
RunE: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/port.go b/cmd/podman/port.go
index 1c3086536..ffb5749fb 100644
--- a/cmd/podman/port.go
+++ b/cmd/podman/port.go
@@ -128,9 +128,6 @@ func portCmd(c *cliconfig.PortValues) error {
if state, _ := con.State(); state != libpod.ContainerStateRunning {
continue
}
- if c.All {
- fmt.Println(con.ID())
- }
portmappings, err := con.PortMappings()
if err != nil {
@@ -143,6 +140,9 @@ func portCmd(c *cliconfig.PortValues) error {
if hostIP == "" {
hostIP = "0.0.0.0"
}
+ if c.All {
+ fmt.Printf("%s\t", con.ID()[:12])
+ }
// If not searching by port or port/proto, then dump what we see
if port == "" {
fmt.Printf("%d/%s -> %s:%d\n", v.ContainerPort, v.Protocol, hostIP, v.HostPort)
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 3bc4f0b08..0dedd850d 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -157,8 +157,9 @@ func (a psSortedSize) Less(i, j int) bool {
var (
psCommand cliconfig.PsValues
psDescription = "Prints out information about the containers"
- _psCommand = &cobra.Command{
+ _psCommand = cobra.Command{
Use: "ps",
+ Args: noSubArgs,
Short: "List containers",
Long: psDescription,
RunE: func(cmd *cobra.Command, args []string) error {
@@ -172,27 +173,31 @@ var (
}
)
-func init() {
- psCommand.Command = _psCommand
- psCommand.SetUsageTemplate(UsageTemplate())
- flags := psCommand.Flags()
- flags.BoolVarP(&psCommand.All, "all", "a", false, "Show all the containers, default is only running containers")
- flags.StringSliceVarP(&psCommand.Filter, "filter", "f", []string{}, "Filter output based on conditions given")
- flags.StringVar(&psCommand.Format, "format", "", "Pretty-print containers to JSON or using a Go template")
- flags.IntVarP(&psCommand.Last, "last", "n", -1, "Print the n last created containers (all states)")
- flags.BoolVarP(&psCommand.Latest, "latest", "l", false, "Show the latest container created (all states)")
- flags.BoolVar(&psCommand.Namespace, "namespace", false, "Display namespace information")
- flags.BoolVar(&psCommand.Namespace, "ns", false, "Display namespace information")
- flags.BoolVar(&psCommand.NoTrunct, "no-trunc", false, "Display the extended information")
- flags.BoolVarP(&psCommand.Pod, "pod", "p", false, "Print the ID and name of the pod the containers are associated with")
- flags.BoolVarP(&psCommand.Quiet, "quiet", "q", false, "Print the numeric IDs of the containers only")
- flags.BoolVarP(&psCommand.Size, "size", "s", false, "Display the total file sizes")
- flags.StringVar(&psCommand.Sort, "sort", "created", "Sort output by command, created, id, image, names, runningfor, size, or status")
- flags.BoolVar(&psCommand.Sync, "sync", false, "Sync container state with OCI runtime")
+func psInit(command *cliconfig.PsValues) {
+ command.SetUsageTemplate(UsageTemplate())
+ flags := command.Flags()
+ flags.BoolVarP(&command.All, "all", "a", false, "Show all the containers, default is only running containers")
+ flags.StringSliceVarP(&command.Filter, "filter", "f", []string{}, "Filter output based on conditions given")
+ flags.StringVar(&command.Format, "format", "", "Pretty-print containers to JSON or using a Go template")
+ flags.IntVarP(&command.Last, "last", "n", -1, "Print the n last created containers (all states)")
+ flags.BoolVarP(&command.Latest, "latest", "l", false, "Show the latest container created (all states)")
+ flags.BoolVar(&command.Namespace, "namespace", false, "Display namespace information")
+ flags.BoolVar(&command.Namespace, "ns", false, "Display namespace information")
+ flags.BoolVar(&command.NoTrunct, "no-trunc", false, "Display the extended information")
+ flags.BoolVarP(&command.Pod, "pod", "p", false, "Print the ID and name of the pod the containers are associated with")
+ flags.BoolVarP(&command.Quiet, "quiet", "q", false, "Print the numeric IDs of the containers only")
+ flags.BoolVarP(&command.Size, "size", "s", false, "Display the total file sizes")
+ flags.StringVar(&command.Sort, "sort", "created", "Sort output by command, created, id, image, names, runningfor, size, or status")
+ flags.BoolVar(&command.Sync, "sync", false, "Sync container state with OCI runtime")
markFlagHiddenForRemoteClient("latest", flags)
}
+func init() {
+ psCommand.Command = &_psCommand
+ psInit(&psCommand)
+}
+
func psCmd(c *cliconfig.PsValues) error {
if c.Bool("trace") {
span, _ := opentracing.StartSpanFromContext(Ctx, "psCmd")
@@ -215,10 +220,6 @@ func psCmd(c *cliconfig.PsValues) error {
defer runtime.Shutdown(false)
- if len(c.InputArgs) > 0 {
- return errors.Errorf("too many arguments, ps takes no arguments")
- }
-
opts := shared.PsOptions{
All: c.All,
Format: c.Format,
diff --git a/cmd/podman/refresh.go b/cmd/podman/refresh.go
index 641748452..1e4a31a52 100644
--- a/cmd/podman/refresh.go
+++ b/cmd/podman/refresh.go
@@ -15,6 +15,7 @@ var (
refreshDescription = "The refresh command resets the state of all containers to handle database changes after a Podman upgrade. All running containers will be restarted."
_refreshCommand = &cobra.Command{
Use: "refresh",
+ Args: noSubArgs,
Short: "Refresh container state",
Long: refreshDescription,
RunE: func(cmd *cobra.Command, args []string) error {
@@ -26,15 +27,12 @@ var (
)
func init() {
+ _refreshCommand.Hidden = true
refreshCommand.Command = _refreshCommand
refreshCommand.SetUsageTemplate(UsageTemplate())
}
func refreshCmd(c *cliconfig.RefreshValues) error {
- if len(c.InputArgs) > 0 {
- return errors.Errorf("refresh does not accept any arguments")
- }
-
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go
index e5bb9b486..511668df7 100644
--- a/cmd/podman/rmi.go
+++ b/cmd/podman/rmi.go
@@ -14,7 +14,7 @@ import (
var (
rmiCommand cliconfig.RmiValues
rmiDescription = "Removes one or more locally stored images."
- _rmiCommand = &cobra.Command{
+ _rmiCommand = cobra.Command{
Use: "rmi [flags] IMAGE [IMAGE...]",
Short: "Removes one or more images from local storage",
Long: rmiDescription,
@@ -29,12 +29,16 @@ var (
}
)
+func rmiInit(command *cliconfig.RmiValues) {
+ command.SetUsageTemplate(UsageTemplate())
+ flags := command.Flags()
+ flags.BoolVarP(&command.All, "all", "a", false, "Remove all images")
+ flags.BoolVarP(&command.Force, "force", "f", false, "Force Removal of the image")
+}
+
func init() {
- rmiCommand.Command = _rmiCommand
- rmiCommand.SetUsageTemplate(UsageTemplate())
- flags := rmiCommand.Flags()
- flags.BoolVarP(&rmiCommand.All, "all", "a", false, "Remove all images")
- flags.BoolVarP(&rmiCommand.Force, "force", "f", false, "Force Removal of the image")
+ rmiCommand.Command = &_rmiCommand
+ rmiInit(&rmiCommand)
}
func rmiCmd(c *cliconfig.RmiValues) error {
diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go
index bc4e650f9..f91ffed0d 100644
--- a/cmd/podman/runlabel.go
+++ b/cmd/podman/runlabel.go
@@ -53,10 +53,12 @@ func init() {
flags.MarkHidden("opt2")
flags.MarkHidden("opt3")
- flags.BoolVarP(&runlabelCommand.Pull, "pull", "p", false, "Pull the image if it does not exist locally prior to executing the label contents")
+ flags.BoolP("pull", "p", false, "Pull the image if it does not exist locally prior to executing the label contents")
flags.BoolVarP(&runlabelCommand.Quiet, "quiet", "q", false, "Suppress output information when installing images")
flags.StringVar(&runlabelCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
flags.BoolVar(&runlabelCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
+
+ flags.MarkDeprecated("pull", "podman will pull if not found in local storage")
}
// installCmd gets the data from the command line and calls installImage
@@ -95,7 +97,6 @@ func runlabelCmd(c *cliconfig.RunlabelValues) error {
if len(args) > 2 {
extraArgs = args[2:]
}
- pull := c.Pull
label := args[0]
runlabelImage := args[1]
@@ -131,7 +132,7 @@ func runlabelCmd(c *cliconfig.RunlabelValues) error {
}
authfile := getAuthFile(c.Authfile)
- runLabel, imageName, err := shared.GetRunlabel(label, runlabelImage, ctx, runtime, pull, c.Creds, dockerRegistryOptions, authfile, c.SignaturePolicy, stdOut)
+ runLabel, imageName, err := shared.GetRunlabel(label, runlabelImage, ctx, runtime, true, c.Creds, dockerRegistryOptions, authfile, c.SignaturePolicy, stdOut)
if err != nil {
return err
}
diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go
index ab9a2cf38..7bd160494 100644
--- a/cmd/podman/stop.go
+++ b/cmd/podman/stop.go
@@ -2,15 +2,14 @@ package main
import (
"fmt"
+ "reflect"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
- "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/rootless"
- opentracing "github.com/opentracing/opentracing-go"
+ "github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -52,63 +51,43 @@ func init() {
markFlagHiddenForRemoteClient("latest", flags)
}
+// stopCmd stops a container or containers
func stopCmd(c *cliconfig.StopValues) error {
+ if c.Flag("timeout").Changed && c.Flag("time").Changed {
+ return errors.New("the --timeout and --time flags are mutually exclusive")
+ }
+
if c.Bool("trace") {
span, _ := opentracing.StartSpanFromContext(Ctx, "stopCmd")
defer span.Finish()
}
rootless.SetSkipStorageSetup(true)
- runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
+ runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)
- containers, err := getAllOrLatestContainers(&c.PodmanCommand, runtime, libpod.ContainerStateRunning, "running")
+ ok, failures, err := runtime.StopContainers(getContext(), c)
if err != nil {
- if len(containers) == 0 {
- return err
- }
- fmt.Println(err.Error())
+ return err
}
- if c.Flag("timeout").Changed && c.Flag("time").Changed {
- return errors.New("the --timeout and --time flags are mutually exclusive")
+ for _, id := range ok {
+ fmt.Println(id)
}
- var stopFuncs []shared.ParallelWorkerInput
- for _, ctr := range containers {
- con := ctr
- var stopTimeout uint
- if c.Flag("timeout").Changed || c.Flag("time").Changed {
- stopTimeout = c.Timeout
- } else {
- stopTimeout = ctr.StopTimeout()
- logrus.Debugf("Set timeout to container %s default (%d)", ctr.ID(), stopTimeout)
- }
- f := func() error {
- if err := con.StopWithTimeout(stopTimeout); err != nil {
- if errors.Cause(err) == libpod.ErrCtrStopped {
- logrus.Debugf("Container %s already stopped", con.ID())
- return nil
- }
- return err
- }
- return nil
- }
- stopFuncs = append(stopFuncs, shared.ParallelWorkerInput{
- ContainerID: con.ID(),
- ParallelFunc: f,
- })
- }
+ if len(failures) > 0 {
+ keys := reflect.ValueOf(failures).MapKeys()
+ lastKey := keys[len(keys)-1].String()
+ lastErr := failures[lastKey]
+ delete(failures, lastKey)
- maxWorkers := shared.Parallelize("stop")
- if c.GlobalIsSet("max-workers") {
- maxWorkers = c.GlobalFlags.MaxWorks
+ for _, err := range failures {
+ outputError(err)
+ }
+ return lastErr
}
- logrus.Debugf("Setting maximum workers to %d", maxWorkers)
-
- stopErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, stopFuncs)
- return printParallelOutput(stopErrors, errCount)
+ return nil
}
diff --git a/cmd/podman/system_prune.go b/cmd/podman/system_prune.go
index a823dcad1..f566387fa 100644
--- a/cmd/podman/system_prune.go
+++ b/cmd/podman/system_prune.go
@@ -23,6 +23,7 @@ var (
`
_pruneSystemCommand = &cobra.Command{
Use: "prune",
+ Args: noSubArgs,
Short: "Remove unused data",
Long: pruneSystemDescription,
RunE: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/system_renumber.go b/cmd/podman/system_renumber.go
index c8ce628b1..31137b9f6 100644
--- a/cmd/podman/system_renumber.go
+++ b/cmd/podman/system_renumber.go
@@ -18,6 +18,7 @@ var (
_renumberCommand = &cobra.Command{
Use: "renumber",
+ Args: noSubArgs,
Short: "Migrate lock numbers",
Long: renumberDescription,
RunE: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go
index f19d03885..5cc79ef96 100644
--- a/cmd/podman/varlink.go
+++ b/cmd/podman/varlink.go
@@ -49,6 +49,9 @@ func varlinkCmd(c *cliconfig.VarlinkValues) error {
if len(args) < 1 {
return errors.Errorf("you must provide a varlink URI")
}
+ if len(args) > 1 {
+ return errors.Errorf("too many arguments. Requires exactly 1")
+ }
timeout := time.Duration(c.Timeout) * time.Millisecond
// Create a single runtime for varlink
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index 618af3481..73e6c15f9 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -459,6 +459,11 @@ method ListContainers() -> (containers: []Container)
# [InspectContainer](#InspectContainer).
method GetContainer(id: string) -> (container: Container)
+# GetContainersByContext allows you to get a list of container ids depending on all, latest, or a list of
+# container names. The definition of latest container means the latest by creation date. In a multi-
+# user environment, results might differ from what you expect.
+method GetContainersByContext(all: bool, latest: bool, args: []string) -> (containers: []string)
+
# CreateContainer creates a new container from an image. It uses a [Create](#Create) type for input. The minimum
# input required for CreateContainer is an image name. If the image name is not found, an [ImageNotFound](#ImageNotFound)
# error will be returned. Otherwise, the ID of the newly created container will be returned.
diff --git a/cmd/podman/version.go b/cmd/podman/version.go
index c65ba94f9..b3615ce23 100644
--- a/cmd/podman/version.go
+++ b/cmd/podman/version.go
@@ -17,6 +17,7 @@ var (
versionCommand cliconfig.VersionValues
_versionCommand = &cobra.Command{
Use: "version",
+ Args: noSubArgs,
Short: "Display the Podman Version Information",
RunE: func(cmd *cobra.Command, args []string) error {
versionCommand.InputArgs = args
diff --git a/cmd/podman/volume_ls.go b/cmd/podman/volume_ls.go
index 5adfc1e91..6855f38e0 100644
--- a/cmd/podman/volume_ls.go
+++ b/cmd/podman/volume_ls.go
@@ -49,6 +49,7 @@ and the output format can be changed to JSON or a user specified Go template.
_volumeLsCommand = &cobra.Command{
Use: "ls",
Aliases: []string{"list"},
+ Args: noSubArgs,
Short: "List volumes",
Long: volumeLsDescription,
RunE: func(cmd *cobra.Command, args []string) error {
@@ -76,10 +77,6 @@ func volumeLsCmd(c *cliconfig.VolumeLsValues) error {
}
defer runtime.Shutdown(false)
- if len(c.InputArgs) > 0 {
- return errors.Errorf("too many arguments, ls takes no arguments")
- }
-
opts := volumeLsOptions{
Quiet: c.Quiet,
}
diff --git a/cmd/podman/volume_prune.go b/cmd/podman/volume_prune.go
index 1f7931aa4..370f072eb 100644
--- a/cmd/podman/volume_prune.go
+++ b/cmd/podman/volume_prune.go
@@ -24,6 +24,7 @@ using force.
`
_volumePruneCommand = &cobra.Command{
Use: "prune",
+ Args: noSubArgs,
Short: "Remove all unused volumes",
Long: volumePruneDescription,
RunE: func(cmd *cobra.Command, args []string) error {
diff --git a/completions/bash/podman b/completions/bash/podman
index 36ac27d52..74e3a49d2 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -2401,8 +2401,6 @@ _podman_container_runlabel() {
--display
--help
-h
- -p
- --pull
-q
--quiet
--tls-verify
diff --git a/docs/podman-container-refresh.1.md b/docs/podman-container-refresh.1.md
deleted file mode 100644
index 26552faa6..000000000
--- a/docs/podman-container-refresh.1.md
+++ /dev/null
@@ -1,25 +0,0 @@
-% podman-container-refresh(1)
-
-## NAME
-podman\-container\-refresh - Refresh all containers
-
-## SYNOPSIS
-**podman container refresh**
-
-## DESCRIPTION
-The refresh command refreshes the state of all containers to pick up database
-schema or general configuration changes. It is not necessary during normal
-operation, and will typically be invoked by package managers after finishing an
-upgrade of the Podman package.
-
-As part of refresh, all running containers will be restarted.
-
-## EXAMPLES ##
-
-```
-$ podman container refresh
-[root@localhost /]#
-```
-
-## SEE ALSO
-podman(1), podman-run(1)
diff --git a/docs/podman-container-runlabel.1.md b/docs/podman-container-runlabel.1.md
index c5d7a278f..7547f7187 100644
--- a/docs/podman-container-runlabel.1.md
+++ b/docs/podman-container-runlabel.1.md
@@ -9,7 +9,6 @@ podman-container-runlabel - Execute Image Label Method
[**-h**|**--help**]
[**--display**]
[**-n**][**--name**[=*NAME*]]
-[**-p**][[**--pull**]]
[**--rootfs**=*ROOTFS*]
[**--set**=*NAME*=*VALUE*]
[**--storage**]
@@ -27,7 +26,7 @@ If the container image has a LABEL INSTALL instruction like the following:
`podman container runlabel` will set the following environment variables for use in the command:
If the container image does not have the desired label, an error message will be displayed along with a non-zero
-return code.
+return code. If the image is not found in local storage, Podman will attempt to pull it first.
Note: Podman will always ensure that `podman` is the first argument of the command being executed.
@@ -82,9 +81,6 @@ Print usage statement
**-n** **--name**=""
Use this name for creating content for the container. NAME will default to the IMAGENAME if it is not specified.
-**p** **--pull**
- Pull the image if it cannot be found in local storage.
-
**--quiet, -q**
Suppress output information when pulling images
diff --git a/docs/podman-container.1.md b/docs/podman-container.1.md
index 86ffd32c4..1ba957480 100644
--- a/docs/podman-container.1.md
+++ b/docs/podman-container.1.md
@@ -14,25 +14,22 @@ The container command allows you to manage containers
| Command | Man Page | Description |
| --------- | --------------------------------------------------- | ---------------------------------------------------------------------------- |
| attach | [podman-attach(1)](podman-attach.1.md) | Attach to a running container. |
-| checkpoint | [podman-container-checkpoint(1)](podman-container-checkpoint.1.md) | Checkpoints one or more containers. |
+| checkpoint | [podman-container-checkpoint(1)](podman-container-checkpoint.1.md) | Checkpoints one or more containers. |
| cleanup | [podman-container-cleanup(1)](podman-container-cleanup.1.md) | Cleanup containers network and mountpoints. |
| commit | [podman-commit(1)](podman-commit.1.md) | Create new image based on the changed container. |
| create | [podman-create(1)](podman-create.1.md) | Create a new container. |
| diff | [podman-diff(1)](podman-diff.1.md) | Inspect changes on a container or image's filesystem. |
| exec | [podman-exec(1)](podman-exec.1.md) | Execute a command in a running container. |
-| exists | [podman-exists(1)](podman-container-exists.1.md) | Check if a container exists in local storage |
+| exists | [podman-container-exists(1)](podman-container-exists.1.md) | Check if a container exists in local storage |
| export | [podman-export(1)](podman-export.1.md) | Export a container's filesystem contents as a tar archive. |
| inspect | [podman-inspect(1)](podman-inspect.1.md) | Display a container or image's configuration. |
| kill | [podman-kill(1)](podman-kill.1.md) | Kill the main process in one or more containers. |
-| list | [podman-ps(1)](podman-ps.1.md) | List the containers on the system. |
+| list | [podman-ps(1)](podman-ps.1.md) | List the containers on the system.(alias ls) |
| logs | [podman-logs(1)](podman-logs.1.md) | Display the logs of a container. |
-| ls | [podman-ps(1)](podman-ps.1.md) | List the containers on the system. |
| mount | [podman-mount(1)](podman-mount.1.md) | Mount a working container's root filesystem. |
| pause | [podman-pause(1)](podman-pause.1.md) | Pause one or more containers. |
| port | [podman-port(1)](podman-port.1.md) | List port mappings for the container. |
| prune | [podman-container-prune(1)](podman-container-prune.1.md)| Remove all stopped containers from local storage. |
-| ps | [podman-ps(1)](podman-ps.1.md) | List the containers on the system. |
-| refresh | [podman-refresh(1)](podman-container-refresh.1.md) | Refresh the state of all containers |
| restart | [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. |
| restore | [podman-container-restore(1)](podman-container-restore.1.md) | Restores one or more containers from a checkpoint. |
| rm | [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. |
@@ -42,8 +39,7 @@ The container command allows you to manage containers
| stats | [podman-stats(1)](podman-stats.1.md) | Display a live stream of one or more container's resource usage statistics. |
| stop | [podman-stop(1)](podman-stop.1.md) | Stop one or more running containers. |
| top | [podman-top(1)](podman-top.1.md) | Display the running processes of a container. |
-| umount | [podman-umount(1)](podman-umount.1.md) | Unmount a working container's root filesystem. |
-| unmount | [podman-umount(1)](podman-umount.1.md) | Unmount a working container's root filesystem. |
+| umount | [podman-umount(1)](podman-umount.1.md) | Unmount a working container's root filesystem.(Alias unmount) |
| unpause | [podman-unpause(1)](podman-unpause.1.md) | Unpause one or more containers. |
| wait | [podman-wait(1)](podman-wait.1.md) | Wait on one or more containers to stop and print their exit codes. |
diff --git a/docs/podman-image.1.md b/docs/podman-image.1.md
index 95e8b7e48..b4ae752f6 100644
--- a/docs/podman-image.1.md
+++ b/docs/podman-image.1.md
@@ -14,17 +14,16 @@ The image command allows you to manage images
| Command | Man Page | Description |
| -------- | ----------------------------------------------- | --------------------------------------------------------------------------- |
| build | [podman-build(1)](podman-build.1.md) | Build a container using a Dockerfile. |
-| exists | [podman-exists(1)](podman-image-exists.1.md) | Check if a image exists in local storage. |
+| exists | [podman-image-exists(1)](podman-image-exists.1.md) | Check if a image exists in local storage. |
| history | [podman-history(1)](podman-history.1.md) | Show the history of an image. |
| import | [podman-import(1)](podman-import.1.md) | Import a tarball and save it as a filesystem image. |
| inspect | [podman-inspect(1)](podman-inspect.1.md) | Display a image or image's configuration. |
-| list | [podman-images(1)](podman-images.1.md) | List the container images on the system. |
+| list | [podman-images(1)](podman-images.1.md) | List the container images on the system.(alias ls) |
| load | [podman-load(1)](podman-load.1.md) | Load an image from the docker archive. |
-| ls | [podman-images(1)](podman-images.1.md) | List the container images on the system. |
| prune | [podman-image-prune(1)](podman-image-prune.1.md)| Removed all unused images from the local store. |
| pull | [podman-pull(1)](podman-pull.1.md) | Pull an image from a registry. |
| push | [podman-push(1)](podman-push.1.md) | Push an image from local storage to elsewhere. |
-| rm | [podman-rm(1)](podman-rmi.1.md) | Removes one or more locally stored images. |
+| rm | [podman-rmi(1)](podman-rmi.1.md) | Removes one or more locally stored images. |
| save | [podman-save(1)](podman-save.1.md) | Save an image to docker-archive or oci. |
| sign | [podman-image-sign(1)](podman-image-sign.1.md) | Sign an image. |
| tag | [podman-tag(1)](podman-tag.1.md) | Add an additional name to a local image. |
diff --git a/docs/podman-system.1.md b/docs/podman-system.1.md
index d088d4d9a..6d87648e8 100644
--- a/docs/podman-system.1.md
+++ b/docs/podman-system.1.md
@@ -13,7 +13,7 @@ The system command allows you to manage the podman systems
| Command | Man Page | Description |
| ------- | --------------------------------------------------- | ---------------------------------------------------------------------------- |
-| info | [podman-system-info(1)](podman-info.1.md) | Displays Podman related system information. |
+| info | [podman-info(1)](podman-info.1.md) | Displays Podman related system information. |
| prune | [podman-system-prune(1)](podman-system-prune.1.md) | Remove all unused data |
| renumber | [podman-system-renumber(1)](podman-system-renumber.1.md)| Migrate lock numbers to handle a change in maximum number of locks. |
diff --git a/docs/podman.1.md b/docs/podman.1.md
index 43f288fd7..bc03d3c5a 100644
--- a/docs/podman.1.md
+++ b/docs/podman.1.md
@@ -137,7 +137,6 @@ the exit codes follow the `chroot` standard, see below:
| [podman-exec(1)](podman-exec.1.md) | Execute a command in a running container. |
| [podman-export(1)](podman-export.1.md) | Export a container's filesystem contents as a tar archive. |
| [podman-generate(1)](podman-generate.1.md)| Generate structured data based for a containers and pods. |
-| [podman-help(1)](podman-history.1.md) | Show help information on podman. |
| [podman-history(1)](podman-history.1.md) | Show the history of an image. |
| [podman-image(1)](podman-image.1.md) | Manage Images. |
| [podman-images(1)](podman-images.1.md) | List images in local storage. |
@@ -157,7 +156,6 @@ the exit codes follow the `chroot` standard, see below:
| [podman-ps(1)](podman-ps.1.md) | Prints out information about containers. |
| [podman-pull(1)](podman-pull.1.md) | Pull an image from a registry. |
| [podman-push(1)](podman-push.1.md) | Push an image from local storage to elsewhere. |
-| [podman-refresh(1)](podman-refresh.1.md) | Refresh state of all containers to handle database changes. |
| [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. |
| [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. |
| [podman-rmi(1)](podman-rmi.1.md) | Removes one or more locally stored images. |
diff --git a/hack/podman-commands.sh b/hack/podman-commands.sh
index e4c63ab59..754f2923d 100755
--- a/hack/podman-commands.sh
+++ b/hack/podman-commands.sh
@@ -1,40 +1,82 @@
-#!/bin/sh
-./bin/podman --help | sed -n -Ee '0,/Available Commands/d' -e '/^Flags/q;p' | sed '/^$/d' | awk '{ print $1 }' > /tmp/podman.cmd
-man ./docs/podman.1 | sed -n -e '0,/COMMANDS/d' -e '/^FILES/q;p' | grep podman | cut -f2 -d- | cut -f1 -d\( > /tmp/podman.man
-echo diff -B -u /tmp/podman.cmd /tmp/podman.man
-diff -B -u /tmp/podman.cmd /tmp/podman.man
-
-./bin/podman image --help | sed -n -e '0,/Available Commands/d' -e '/^Flags/q;p' | sed '/^$/d' | awk '{ print $1 }' > /tmp/podman-image.cmd
-man ./docs/podman-image.1 | sed -n -Ee '0,/COMMANDS/d' -e 's/^[[:space:]]*//' -e '/^SEE ALSO/q;p' | grep podman | cut -f1 -d' ' | sed 's/^.//' > /tmp/podman-image.man
-echo diff -B -u /tmp/podman-image.cmd /tmp/podman-image.man
-diff -B -u /tmp/podman-image.cmd /tmp/podman-image.man
-
-./bin/podman container --help | sed -n -e '0,/Available Commands/d' -e '/^Flags/q;p' | sed '/^$/d' | awk '{ print $1 }' > /tmp/podman-container.cmd
-man docs/podman-container.1 | sed -n -Ee '0,/COMMANDS/d' -e 's/^[[:space:]]*//' -e '/^SEE ALSO/q;p' | grep podman | cut -f1 -d' ' | sed 's/^.//' > /tmp/podman-container.man
-echo diff -B -u /tmp/podman-container.cmd /tmp/podman-container.man
-diff -B -u /tmp/podman-container.cmd /tmp/podman-container.man
-
-./bin/podman system --help | sed -n -e '0,/Available Commands/d' -e '/^Flags/q;p' | sed '/^$/d' | awk '{ print $1 }' > /tmp/podman-system.cmd
-man docs/podman-system.1 | sed -n -Ee '0,/COMMANDS/d' -e 's/^[[:space:]]*//' -e '/^SEE ALSO/q;p' | grep podman | cut -f1 -d' ' | sed 's/^.//' > /tmp/podman-system.man
-echo diff -B -u /tmp/podman-system.cmd /tmp/podman-system.man
-diff -B -u /tmp/podman-system.cmd /tmp/podman-system.man
-
-./bin/podman play --help | sed -n -e '0,/Available Commands/d' -e '/^Flags/q;p' | sed '/^$/d' | awk '{ print $1 }' > /tmp/podman-play.cmd
-man docs/podman-play.1 | sed -n -Ee '0,/COMMANDS/d' -e 's/^[[:space:]]*//' -e '/^SEE ALSO/q;p' | grep podman | cut -f1 -d' ' | sed 's/^.//' > /tmp/podman-play.man
-echo diff -B -u /tmp/podman-play.cmd /tmp/podman-play.man
-diff -B -u /tmp/podman-play.cmd /tmp/podman-play.man
-
-./bin/podman generate --help | sed -n -e '0,/Available Commands/d' -e '/^Flags/q;p' | sed '/^$/d' | awk '{ print $1 }' > /tmp/podman-generate.cmd
-man docs/podman-generate.1 | sed -n -Ee '0,/COMMANDS/d' -e 's/^[[:space:]]*//' -e '/^SEE ALSO/q;p' | grep podman | cut -f1 -d' ' | sed 's/^.//' > /tmp/podman-generate.man
-echo diff -B -u /tmp/podman-generate.cmd /tmp/podman-generate.man
-diff -B -u /tmp/podman-generate.cmd /tmp/podman-generate.man
-
-./bin/podman pod --help | sed -n -e '0,/Available Commands/d' -e '/^Flags/q;p' | sed '/^$/d' | awk '{ print $1 }' > /tmp/podman-pod.cmd
-man docs/podman-pod.1 | sed -n -Ee '0,/COMMANDS/d' -e 's/^[[:space:]]*//' -e '/^SEE ALSO/q;p' | grep podman | cut -f1 -d' ' | sed 's/^.//' > /tmp/podman-pod.man
-echo diff -B -u /tmp/podman-pod.cmd /tmp/podman-pod.man
-diff -B -u /tmp/podman-pod.cmd /tmp/podman-pod.man
-
-./bin/podman volume --help | sed -n -e '0,/Available Commands/d' -e '/^Flags/q;p' | sed '/^$/d' | awk '{ print $1 }' > /tmp/podman-volume.cmd
-man docs/podman-volume.1 | sed -n -Ee '0,/COMMANDS/d' -e 's/^[[:space:]]*//' -e '/^SEE ALSO/q;p' | grep podman | cut -f1 -d' ' | sed 's/^.//' > /tmp/podman-volume.man
-echo diff -B -u /tmp/podman-volume.cmd /tmp/podman-volume.man
-diff -B -u /tmp/podman-volume.cmd /tmp/podman-volume.man
+#!/bin/bash
+#
+# Compare commands listed by 'podman help' against those in 'man podman'.
+# Recurse into subcommands as well.
+#
+# Because we read metadoc files in the `docs` directory, this script
+# must run from the top level of a git checkout. FIXME: if necessary,
+# it could instead run 'man podman-XX'; my thinking is that this
+# script should run early in CI.
+#
+
+# override with, e.g., PODMAN=./bin/podman-remote
+PODMAN=${PODMAN:-./bin/podman}
+
+function die() {
+ echo "FATAL: $*" >&2
+ exit 1
+}
+
+
+# Run 'podman help' (possibly against a subcommand, e.g. 'podman help image')
+# and return a list of each first word under 'Available Commands', that is,
+# the command name but not its description.
+function podman_commands() {
+ $PODMAN help "$@" |\
+ awk '/^Available Commands:/{ok=1;next}/^Flags:/{ok=0}ok { print $1 }' |\
+ grep .
+}
+
+# Read a list of subcommands from a command's metadoc
+function podman_man() {
+ if [ "$@" = "podman" ]; then
+ # podman itself.
+ # This md file has a table of the form:
+ # | [podman-cmd(1)\[(podman-cmd.1.md) | Description ... |
+ # For all such, print the 'cmd' portion (the one in brackets).
+ sed -ne 's/^|\s\+\[podman-\([a-z]\+\)(1.*/\1/p' <docs/$1.1.md
+ elif [ "$@" = "podman-image-trust" ]; then
+ # Special case: set and show aren't actually in a table in the man page
+ echo set
+ echo show
+ else
+ # podman subcommand.
+ # Each md file has a table of the form:
+ # | cmd | [podman-cmd(1)](podman-cmd.1.md) | Description ... |
+ # For all such we find, with 'podman- in the second column, print the
+ # first column (with whitespace trimmed)
+ awk -F\| '$3 ~ /podman-/ { gsub(" ","",$2); print $2 }' < docs/$1.1.md
+ fi
+}
+
+# The main thing. Compares help and man page; if we find subcommands, recurse.
+rc=0
+function compare_help_and_man() {
+ echo
+ echo "checking: podman $@"
+
+ # e.g. podman, podman-image, podman-volume
+ local basename=$(echo podman "$@" | sed -e 's/ /-/g')
+
+ podman_commands "$@" | sort > /tmp/${basename}_help.txt
+ podman_man $basename | sort > /tmp/${basename}_man.txt
+
+ diff -u /tmp/${basename}_help.txt /tmp/${basename}_man.txt || rc=1
+
+ # Now look for subcommands, e.g. container, image
+ for cmd in $(< /tmp/${basename}_help.txt); do
+ usage=$($PODMAN "$@" $cmd --help | grep -A1 '^Usage:' | tail -1)
+
+ # if string ends in '[command]', recurse into its subcommands
+ if expr "$usage" : '.*\[command\]$' >/dev/null; then
+ compare_help_and_man "$@" $cmd
+ fi
+ done
+
+ rm -f /tmp/${basename}_{help,man}.txt
+}
+
+
+compare_help_and_man
+
+exit $rc
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 09d7f220d..6bef3c47d 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -203,9 +203,8 @@ func (c *Container) Kill(signal uint) error {
}
// Exec starts a new process inside the container
-// TODO allow specifying streams to attach to
// TODO investigate allowing exec without attaching
-func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir string) error {
+func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir string, streams *AttachStreams) error {
var capList []string
locked := false
@@ -267,7 +266,7 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir
logrus.Debugf("Creating new exec session in container %s with session id %s", c.ID(), sessionID)
- execCmd, err := c.runtime.ociRuntime.execContainer(c, cmd, capList, env, tty, workDir, hostUser, sessionID)
+ execCmd, err := c.runtime.ociRuntime.execContainer(c, cmd, capList, env, tty, workDir, hostUser, sessionID, streams)
if err != nil {
return errors.Wrapf(err, "error exec %s", c.ID())
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index b074efa3a..0e9a5124e 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -472,10 +472,19 @@ func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr
return nil
}
-func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointOptions) (err error) {
-
+func (c *Container) checkpointRestoreSupported() (err error) {
if !criu.CheckForCriu() {
- return errors.Errorf("checkpointing a container requires at least CRIU %d", criu.MinCriuVersion)
+ return errors.Errorf("Checkpoint/Restore requires at least CRIU %d", criu.MinCriuVersion)
+ }
+ if !c.runtime.ociRuntime.featureCheckCheckpointing() {
+ return errors.Errorf("Configured runtime does not support checkpoint/restore")
+ }
+ return nil
+}
+
+func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointOptions) (err error) {
+ if err := c.checkpointRestoreSupported(); err != nil {
+ return err
}
if c.state.State != ContainerStateRunning {
@@ -532,8 +541,8 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
func (c *Container) restore(ctx context.Context, options ContainerCheckpointOptions) (err error) {
- if !criu.CheckForCriu() {
- return errors.Errorf("restoring a container requires at least CRIU %d", criu.MinCriuVersion)
+ if err := c.checkpointRestoreSupported(); err != nil {
+ return err
}
if (c.state.State != ContainerStateConfigured) && (c.state.State != ContainerStateExited) {
diff --git a/libpod/oci.go b/libpod/oci.go
index 26d2c6ef1..2b3cc5db5 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -733,7 +733,7 @@ func (r *OCIRuntime) unpauseContainer(ctr *Container) error {
// TODO: Add --detach support
// TODO: Convert to use conmon
// TODO: add --pid-file and use that to generate exec session tracking
-func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty bool, cwd, user, sessionID string) (*exec.Cmd, error) {
+func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty bool, cwd, user, sessionID string, streams *AttachStreams) (*exec.Cmd, error) {
if len(cmd) == 0 {
return nil, errors.Wrapf(ErrInvalidArg, "must provide a command to execute")
}
@@ -789,9 +789,17 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty
logrus.Debugf("Starting runtime %s with following arguments: %v", r.path, args)
execCmd := exec.Command(r.path, args...)
- execCmd.Stdout = os.Stdout
- execCmd.Stderr = os.Stderr
- execCmd.Stdin = os.Stdin
+
+ if streams.AttachOutput {
+ execCmd.Stdout = streams.OutputStream
+ }
+ if streams.AttachInput {
+ execCmd.Stdin = streams.InputStream
+ }
+ if streams.AttachError {
+ execCmd.Stderr = streams.ErrorStream
+ }
+
execCmd.Env = append(execCmd.Env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir))
if err := execCmd.Start(); err != nil {
@@ -890,3 +898,16 @@ func (r *OCIRuntime) checkpointContainer(ctr *Container, options ContainerCheckp
args = append(args, ctr.ID())
return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, args...)
}
+
+func (r *OCIRuntime) featureCheckCheckpointing() bool {
+ // Check if the runtime implements checkpointing. Currently only
+ // runc's checkpoint/restore implementation is supported.
+ cmd := exec.Command(r.path, "checkpoint", "-h")
+ if err := cmd.Start(); err != nil {
+ return false
+ }
+ if err := cmd.Wait(); err == nil {
+ return true
+ }
+ return false
+}
diff --git a/libpod/runtime.go b/libpod/runtime.go
index f53cdd8b8..112b6820a 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -477,6 +477,12 @@ func NewRuntimeFromConfig(configPath string, options ...RuntimeOption) (runtime
runtime.config.OCIRuntime = defaultRuntimeConfig.OCIRuntime
runtime.config.StorageConfig = storage.StoreOptions{}
+ tmpDir, err := getDefaultTmpDir()
+ if err != nil {
+ return nil, err
+ }
+ runtime.config.TmpDir = tmpDir
+
// Check to see if the given configuration file exists
if _, err := os.Stat(configPath); err != nil {
return nil, errors.Wrapf(err, "error checking existence of configuration file %s", configPath)
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
new file mode 100644
index 000000000..b0c75cf49
--- /dev/null
+++ b/pkg/adapter/containers.go
@@ -0,0 +1,72 @@
+// +build !remoteclient
+
+package adapter
+
+import (
+ "context"
+
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/adapter/shortcuts"
+ "github.com/pkg/errors"
+)
+
+// GetLatestContainer gets the latest Container and wraps it in an adapter Container
+func (r *LocalRuntime) GetLatestContainer() (*Container, error) {
+ Container := Container{}
+ c, err := r.Runtime.GetLatestContainer()
+ Container.Container = c
+ return &Container, err
+}
+
+// GetAllContainers gets all Containers and wraps each one in an adapter Container
+func (r *LocalRuntime) GetAllContainers() ([]*Container, error) {
+ var containers []*Container
+ allContainers, err := r.Runtime.GetAllContainers()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, c := range allContainers {
+ containers = append(containers, &Container{c})
+ }
+ return containers, nil
+}
+
+// LookupContainer gets a Container by name or id and wraps it in an adapter Container
+func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
+ ctr, err := r.Runtime.LookupContainer(idOrName)
+ if err != nil {
+ return nil, err
+ }
+ return &Container{ctr}, nil
+}
+
+// StopContainers stops container(s) based on CLI inputs.
+// Returns list of successful id(s), map of failed id(s) + error, or error not from container
+func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopValues) ([]string, map[string]error, error) {
+ timeout := uint(0)
+ if cli.Flags().Changed("timeout") {
+ timeout = uint(cli.Timeout)
+ }
+
+ var (
+ ok = []string{}
+ failures = map[string]error{}
+ )
+
+ ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
+ if err != nil {
+ return ok, failures, err
+ }
+
+ for _, c := range ctrs {
+ err := c.StopWithTimeout(timeout)
+ if err != nil && errors.Cause(err) != libpod.ErrCtrStopped {
+ failures[c.ID()] = err
+ } else {
+ ok = append(ok, c.ID())
+ }
+ }
+ return ok, failures, nil
+}
diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go
index 3f43a6905..df40c8efd 100644
--- a/pkg/adapter/containers_remote.go
+++ b/pkg/adapter/containers_remote.go
@@ -3,8 +3,13 @@
package adapter
import (
+ "context"
"encoding/json"
+ "errors"
+
+ "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
+ "github.com/sirupsen/logrus"
iopodman "github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
@@ -29,6 +34,70 @@ func (c *Container) ID() string {
return c.config.ID
}
+// Config returns a container config
+func (r *LocalRuntime) Config(name string) *libpod.ContainerConfig {
+ // TODO the Spec being returned is not populated. Matt and I could not figure out why. Will defer
+ // further looking into it for after devconf.
+ // The libpod function for this has no errors so we are kind of in a tough
+ // spot here. Logging the errors for now.
+ reply, err := iopodman.ContainerConfig().Call(r.Conn, name)
+ if err != nil {
+ logrus.Error("call to container.config failed")
+ }
+ data := libpod.ContainerConfig{}
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ logrus.Error("failed to unmarshal container inspect data")
+ }
+ return &data
+
+}
+
+// ContainerState returns the "state" of the container.
+func (r *LocalRuntime) ContainerState(name string) (*libpod.ContainerState, error) { // no-lint
+ reply, err := iopodman.ContainerStateData().Call(r.Conn, name)
+ if err != nil {
+ return nil, err
+ }
+ data := libpod.ContainerState{}
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ return nil, err
+ }
+ return &data, err
+
+}
+
+// LookupContainer gets basic information about container over a varlink
+// connection and then translates it to a *Container
+func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
+ state, err := r.ContainerState(idOrName)
+ if err != nil {
+ return nil, err
+ }
+ config := r.Config(idOrName)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Container{
+ remoteContainer{
+ r,
+ config,
+ state,
+ },
+ }, nil
+}
+
+func (r *LocalRuntime) GetLatestContainer() (*Container, error) {
+ reply, err := iopodman.GetContainersByContext().Call(r.Conn, false, true, nil)
+ if err != nil {
+ return nil, err
+ }
+ if len(reply) > 0 {
+ return r.LookupContainer(reply[0])
+ }
+ return nil, errors.New("no containers exist")
+}
+
// GetArtifact returns a container's artifacts
func (c *Container) GetArtifact(name string) ([]byte, error) {
var data []byte
@@ -55,18 +124,42 @@ func (c *Container) Name() string {
return c.config.Name
}
+// StopContainers stops requested containers using CLI inputs.
+// Returns the list of stopped container ids, map of failed to stop container ids + errors, or any non-container error
+func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopValues) ([]string, map[string]error, error) {
+ var (
+ ok = []string{}
+ failures = map[string]error{}
+ )
+
+ ids, err := iopodman.GetContainersByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
+ if err != nil {
+ return ok, failures, err
+ }
+
+ for _, id := range ids {
+ stopped, err := iopodman.StopContainer().Call(r.Conn, id, int64(cli.Timeout))
+ if err != nil {
+ failures[id] = err
+ } else {
+ ok = append(ok, stopped)
+ }
+ }
+ return ok, failures, nil
+}
+
// BatchContainerOp is wrapper func to mimic shared's function with a similar name meant for libpod
func BatchContainerOp(ctr *Container, opts shared.PsOptions) (shared.BatchContainerStruct, error) {
// TODO If pod ps ever shows container's sizes, re-enable this code; otherwise it isn't needed
// and would be a perf hit
- //data, err := ctr.Inspect(true)
- //if err != nil {
- // return shared.BatchContainerStruct{}, err
- //}
+ // data, err := ctr.Inspect(true)
+ // if err != nil {
+ // return shared.BatchContainerStruct{}, err
+ // }
//
- //size := new(shared.ContainerSize)
- //size.RootFsSize = data.SizeRootFs
- //size.RwSize = data.SizeRw
+ // size := new(shared.ContainerSize)
+ // size.RootFsSize = data.SizeRootFs
+ // size.RwSize = data.SizeRw
bcs := shared.BatchContainerStruct{
ConConfig: ctr.config,
@@ -75,7 +168,7 @@ func BatchContainerOp(ctr *Container, opts shared.PsOptions) (shared.BatchContai
Pid: ctr.state.PID,
StartedTime: ctr.state.StartedTime,
ExitedTime: ctr.state.FinishedTime,
- //Size: size,
+ // Size: size,
}
return bcs, nil
}
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index 8624981b1..5be2ca150 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -108,15 +108,6 @@ func (r *LocalRuntime) RemoveImage(ctx context.Context, img *ContainerImage, for
return r.Runtime.RemoveImage(ctx, img.Image, force)
}
-// LookupContainer ...
-func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
- ctr, err := r.Runtime.LookupContainer(idOrName)
- if err != nil {
- return nil, err
- }
- return &Container{ctr}, nil
-}
-
// PruneImages is wrapper into PruneImages within the image pkg
func (r *LocalRuntime) PruneImages(all bool) ([]string, error) {
return r.ImageRuntime().PruneImages(all)
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index 29b43e9b0..14cda7bff 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -5,7 +5,6 @@ package adapter
import (
"bufio"
"context"
- "encoding/json"
"fmt"
"io"
"io/ioutil"
@@ -49,14 +48,13 @@ func GetRuntime(c *cliconfig.PodmanCommand) (*LocalRuntime, error) {
if err != nil {
return nil, err
}
- rr := RemoteRuntime{
- Conn: conn,
- Remote: true,
- }
- foo := LocalRuntime{
- &rr,
- }
- return &foo, nil
+
+ return &LocalRuntime{
+ &RemoteRuntime{
+ Conn: conn,
+ Remote: true,
+ },
+ }, nil
}
// Shutdown is a bogus wrapper for compat with the libpod runtime
@@ -315,66 +313,6 @@ func (ci *ContainerImage) History(ctx context.Context) ([]*image.History, error)
return imageHistories, nil
}
-// LookupContainer gets basic information about container over a varlink
-// connection and then translates it to a *Container
-func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
- state, err := r.ContainerState(idOrName)
- if err != nil {
- return nil, err
- }
- config := r.Config(idOrName)
- if err != nil {
- return nil, err
- }
-
- rc := remoteContainer{
- r,
- config,
- state,
- }
-
- c := Container{
- rc,
- }
- return &c, nil
-}
-
-func (r *LocalRuntime) GetLatestContainer() (*Container, error) {
- return nil, libpod.ErrNotImplemented
-}
-
-// ContainerState returns the "state" of the container.
-func (r *LocalRuntime) ContainerState(name string) (*libpod.ContainerState, error) { //no-lint
- reply, err := iopodman.ContainerStateData().Call(r.Conn, name)
- if err != nil {
- return nil, err
- }
- data := libpod.ContainerState{}
- if err := json.Unmarshal([]byte(reply), &data); err != nil {
- return nil, err
- }
- return &data, err
-
-}
-
-// Config returns a container config
-func (r *LocalRuntime) Config(name string) *libpod.ContainerConfig {
- // TODO the Spec being returned is not populated. Matt and I could not figure out why. Will defer
- // further looking into it for after devconf.
- // The libpod function for this has no errors so we are kind of in a tough
- // spot here. Logging the errors for now.
- reply, err := iopodman.ContainerConfig().Call(r.Conn, name)
- if err != nil {
- logrus.Error("call to container.config failed")
- }
- data := libpod.ContainerConfig{}
- if err := json.Unmarshal([]byte(reply), &data); err != nil {
- logrus.Error("failed to unmarshal container inspect data")
- }
- return &data
-
-}
-
// PruneImages is the wrapper call for a remote-client to prune images
func (r *LocalRuntime) PruneImages(all bool) ([]string, error) {
return iopodman.ImagesPrune().Call(r.Conn, all)
diff --git a/pkg/adapter/shortcuts/shortcuts.go b/pkg/adapter/shortcuts/shortcuts.go
index 0633399ae..677d88457 100644
--- a/pkg/adapter/shortcuts/shortcuts.go
+++ b/pkg/adapter/shortcuts/shortcuts.go
@@ -25,3 +25,30 @@ func GetPodsByContext(all, latest bool, pods []string, runtime *libpod.Runtime)
}
return outpods, nil
}
+
+// GetContainersByContext gets pods whether all, latest, or a slice of names/ids
+func GetContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) ([]*libpod.Container, error) {
+ var ctrs = []*libpod.Container{}
+
+ if all {
+ return runtime.GetAllContainers()
+ }
+
+ if latest {
+ c, err := runtime.GetLatestContainer()
+ if err != nil {
+ return nil, err
+ }
+ ctrs = append(ctrs, c)
+ return ctrs, nil
+ }
+
+ for _, c := range names {
+ ctr, err := runtime.LookupContainer(c)
+ if err != nil {
+ return nil, err
+ }
+ ctrs = append(ctrs, ctr)
+ }
+ return ctrs, nil
+}
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index 9a192c0fa..98692707f 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -93,7 +93,8 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap)
Args: args,
}
- if err := cmd.Run(); err != nil {
+ if output, err := cmd.CombinedOutput(); err != nil {
+ logrus.Debugf("error from %s: %s", tool, output)
return errors.Wrapf(err, "cannot setup namespace using %s", tool)
}
return nil
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
index ad9f107a7..27b8d15d2 100644
--- a/pkg/varlinkapi/containers.go
+++ b/pkg/varlinkapi/containers.go
@@ -13,6 +13,7 @@ import (
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/adapter/shortcuts"
cc "github.com/containers/libpod/pkg/spec"
"github.com/containers/storage/pkg/archive"
"github.com/pkg/errors"
@@ -60,6 +61,21 @@ func (i *LibpodAPI) GetContainer(call iopodman.VarlinkCall, id string) error {
return call.ReplyGetContainer(makeListContainer(ctr.ID(), batchInfo))
}
+// GetContainersByContext returns a slice of container ids based on all, latest, or a list
+func (i *LibpodAPI) GetContainersByContext(call iopodman.VarlinkCall, all, latest bool, input []string) error {
+ var ids []string
+
+ ctrs, err := shortcuts.GetContainersByContext(all, latest, input, i.Runtime)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ for _, c := range ctrs {
+ ids = append(ids, c.ID())
+ }
+ return call.ReplyGetContainersByContext(ids)
+}
+
// InspectContainer ...
func (i *LibpodAPI) InspectContainer(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
diff --git a/test/e2e/attach_test.go b/test/e2e/attach_test.go
index 42866d5a1..9c013e459 100644
--- a/test/e2e/attach_test.go
+++ b/test/e2e/attach_test.go
@@ -51,6 +51,16 @@ var _ = Describe("Podman attach", func() {
Expect(results.ExitCode()).To(Equal(125))
})
+ It("podman container attach to non-running container", func() {
+ session := podmanTest.Podman([]string{"container", "create", "--name", "test1", "-d", "-i", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ results := podmanTest.Podman([]string{"container", "attach", "test1"})
+ results.WaitWithDefaultTimeout()
+ Expect(results.ExitCode()).To(Equal(125))
+ })
+
It("podman attach to multiple containers", func() {
session := podmanTest.RunTopContainer("test1")
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go
index fda6eb085..583432df1 100644
--- a/test/e2e/checkpoint_test.go
+++ b/test/e2e/checkpoint_test.go
@@ -6,6 +6,7 @@ import (
"fmt"
"net"
"os"
+ "os/exec"
"github.com/containers/libpod/pkg/criu"
. "github.com/containers/libpod/test/utils"
@@ -27,9 +28,26 @@ var _ = Describe("Podman checkpoint", func() {
}
podmanTest = PodmanTestCreate(tempdir)
podmanTest.RestoreAllArtifacts()
+ // Check if the runtime implements checkpointing. Currently only
+ // runc's checkpoint/restore implementation is supported.
+ cmd := exec.Command(podmanTest.OCIRuntime, "checkpoint", "-h")
+ if err := cmd.Start(); err != nil {
+ Skip("OCI runtime does not support checkpoint/restore")
+ }
+ if err := cmd.Wait(); err != nil {
+ Skip("OCI runtime does not support checkpoint/restore")
+ }
+
if !criu.CheckForCriu() {
Skip("CRIU is missing or too old.")
}
+ // TODO: Remove the skip when the current CRIU SELinux problem is solved.
+ // See: https://github.com/containers/libpod/issues/2334
+ hostInfo := podmanTest.Host
+ if hostInfo.Distribution == "fedora" {
+ Skip("Checkpointing containers on Fedora currently broken.")
+ }
+
})
AfterEach(func() {
diff --git a/test/e2e/commit_test.go b/test/e2e/commit_test.go
index 34b218621..6b65d9b75 100644
--- a/test/e2e/commit_test.go
+++ b/test/e2e/commit_test.go
@@ -50,6 +50,21 @@ var _ = Describe("Podman commit", func() {
Expect(StringInSlice("foobar.com/test1-image:latest", data[0].RepoTags)).To(BeTrue())
})
+ It("podman container commit container", func() {
+ _, ec, _ := podmanTest.RunLsContainer("test1")
+ Expect(ec).To(Equal(0))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(1))
+
+ session := podmanTest.Podman([]string{"container", "commit", "test1", "foobar.com/test1-image:latest"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"container", "inspect", "foobar.com/test1-image:latest"})
+ check.WaitWithDefaultTimeout()
+ data := check.InspectImageJSON()
+ Expect(StringInSlice("foobar.com/test1-image:latest", data[0].RepoTags)).To(BeTrue())
+ })
+
It("podman commit container with message", func() {
_, ec, _ := podmanTest.RunLsContainer("test1")
Expect(ec).To(Equal(0))
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index 9a526b778..12e4f3508 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -56,6 +56,13 @@ var _ = Describe("Podman create", func() {
Expect(podmanTest.NumberOfContainers()).To(Equal(1))
})
+ It("podman container create container based on a remote image", func() {
+ session := podmanTest.Podman([]string{"container", "create", BB_GLIBC, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(1))
+ })
+
It("podman create using short options", func() {
session := podmanTest.Podman([]string{"create", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/diff_test.go b/test/e2e/diff_test.go
index 94e150467..82ced7cfa 100644
--- a/test/e2e/diff_test.go
+++ b/test/e2e/diff_test.go
@@ -43,6 +43,13 @@ var _ = Describe("Podman diff", func() {
Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 0))
})
+ It("podman container diff of image", func() {
+ session := podmanTest.Podman([]string{"container", "diff", ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 0))
+ })
+
It("podman diff bogus image", func() {
session := podmanTest.Podman([]string{"diff", "1234"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go
index 5839b364d..667a81d07 100644
--- a/test/e2e/exec_test.go
+++ b/test/e2e/exec_test.go
@@ -57,6 +57,16 @@ var _ = Describe("Podman exec", func() {
Expect(session.ExitCode()).To(Equal(0))
})
+ It("podman container exec simple command", func() {
+ setup := podmanTest.RunTopContainer("test1")
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"container", "exec", "test1", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+
It("podman exec simple command using latest", func() {
setup := podmanTest.RunTopContainer("test1")
setup.WaitWithDefaultTimeout()
diff --git a/test/e2e/export_test.go b/test/e2e/export_test.go
index dba0a2255..114c28a3d 100644
--- a/test/e2e/export_test.go
+++ b/test/e2e/export_test.go
@@ -50,6 +50,22 @@ var _ = Describe("Podman export", func() {
Expect(err).To(BeNil())
})
+ It("podman container export output flag", func() {
+ SkipIfRemote()
+ _, ec, cid := podmanTest.RunLsContainer("")
+ Expect(ec).To(Equal(0))
+
+ outfile := filepath.Join(podmanTest.TempDir, "container.tar")
+ result := podmanTest.Podman([]string{"container", "export", "-o", outfile, cid})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ _, err := os.Stat(outfile)
+ Expect(err).To(BeNil())
+
+ err = os.Remove(outfile)
+ Expect(err).To(BeNil())
+ })
+
It("podman export bad filename", func() {
_, ec, cid := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go
index 595084403..e26f4affd 100644
--- a/test/e2e/images_test.go
+++ b/test/e2e/images_test.go
@@ -43,6 +43,15 @@ var _ = Describe("Podman images", func() {
Expect(session.LineInOuputStartsWith("docker.io/library/busybox")).To(BeTrue())
})
+ It("podman image List", func() {
+ session := podmanTest.Podman([]string{"image", "list"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 2))
+ Expect(session.LineInOuputStartsWith("docker.io/library/alpine")).To(BeTrue())
+ Expect(session.LineInOuputStartsWith("docker.io/library/busybox")).To(BeTrue())
+ })
+
It("podman images with multiple tags", func() {
// tag "docker.io/library/alpine:latest" to "foo:{a,b,c}"
session := podmanTest.Podman([]string{"tag", ALPINE, "foo:a", "foo:b", "foo:c"})
@@ -135,6 +144,23 @@ var _ = Describe("Podman images", func() {
Expect(len(result.OutputToStringArray())).To(Equal(1))
})
+ It("podman image list filter after image", func() {
+ if podmanTest.RemoteTest {
+ Skip("Does not work on remote client")
+ }
+ rmi := podmanTest.Podman([]string{"image", "rm", "busybox"})
+ rmi.WaitWithDefaultTimeout()
+ Expect(rmi.ExitCode()).To(Equal(0))
+
+ dockerfile := `FROM docker.io/library/alpine:latest
+`
+ podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
+ result := podmanTest.Podman([]string{"image", "list", "-q", "-f", "after=docker.io/library/alpine:latest"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(len(result.OutputToStringArray())).To(Equal(1))
+ })
+
It("podman images filter dangling", func() {
if podmanTest.RemoteTest {
Skip("Does not work on remote client")
@@ -164,6 +190,21 @@ var _ = Describe("Podman images", func() {
Expect(result.ExitCode()).To(Equal(0))
})
+ It("podman check for image with sha256: prefix", func() {
+ if podmanTest.RemoteTest {
+ Skip("Does not work on remote client")
+ }
+ session := podmanTest.Podman([]string{"image", "inspect", "--format=json", ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.IsJSONOutputValid()).To(BeTrue())
+ imageData := session.InspectImageJSON()
+
+ result := podmanTest.Podman([]string{"image", "ls", fmt.Sprintf("sha256:%s", imageData[0].ID)})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ })
+
It("podman images sort by tag", func() {
session := podmanTest.Podman([]string{"images", "--sort", "tag", "--format={{.Tag}}"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/kill_test.go b/test/e2e/kill_test.go
index 5f1f5f4c1..cde8729c8 100644
--- a/test/e2e/kill_test.go
+++ b/test/e2e/kill_test.go
@@ -41,6 +41,19 @@ var _ = Describe("Podman kill", func() {
Expect(session.ExitCode()).To(Not(Equal(0)))
})
+ It("podman container kill a running container by id", func() {
+ session := podmanTest.RunTopContainer("")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ cid := session.OutputToString()
+
+ result := podmanTest.Podman([]string{"container", "kill", cid})
+ result.WaitWithDefaultTimeout()
+
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
+ })
+
It("podman kill a running container by id", func() {
session := podmanTest.RunTopContainer("")
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/load_test.go b/test/e2e/load_test.go
index c85810454..571754347 100644
--- a/test/e2e/load_test.go
+++ b/test/e2e/load_test.go
@@ -59,7 +59,7 @@ var _ = Describe("Podman load", func() {
Expect(save.ExitCode()).To(Equal(0))
compress := SystemExec("gzip", []string{outfile})
- compress.WaitWithDefaultTimeout()
+ Expect(compress.ExitCode()).To(Equal(0))
outfile = outfile + ".gz"
rmi := podmanTest.Podman([]string{"rmi", ALPINE})
@@ -174,7 +174,6 @@ var _ = Describe("Podman load", func() {
It("podman load localhost registry from scratch", func() {
outfile := filepath.Join(podmanTest.TempDir, "load_test.tar.gz")
-
setup := podmanTest.Podman([]string{"tag", ALPINE, "hello:world"})
setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0))
@@ -255,7 +254,6 @@ var _ = Describe("Podman load", func() {
save.WaitWithDefaultTimeout()
Expect(save.ExitCode()).To(Equal(0))
session := SystemExec("xz", []string{outfile})
- session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
rmi := podmanTest.Podman([]string{"rmi", BB})
diff --git a/test/e2e/mount_test.go b/test/e2e/mount_test.go
index 94218e6a9..bf0442de2 100644
--- a/test/e2e/mount_test.go
+++ b/test/e2e/mount_test.go
@@ -49,6 +49,21 @@ var _ = Describe("Podman mount", func() {
Expect(umount.ExitCode()).To(Equal(0))
})
+ It("podman container mount", func() {
+ setup := podmanTest.Podman([]string{"container", "create", ALPINE, "ls"})
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+ cid := setup.OutputToString()
+
+ mount := podmanTest.Podman([]string{"container", "mount", cid})
+ mount.WaitWithDefaultTimeout()
+ Expect(mount.ExitCode()).To(Equal(0))
+
+ umount := podmanTest.Podman([]string{"container", "umount", cid})
+ umount.WaitWithDefaultTimeout()
+ Expect(umount.ExitCode()).To(Equal(0))
+ })
+
It("podman mount with json format", func() {
setup := podmanTest.Podman([]string{"create", ALPINE, "ls"})
setup.WaitWithDefaultTimeout()
diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go
index f1ea17ead..7530ca85c 100644
--- a/test/e2e/pause_test.go
+++ b/test/e2e/pause_test.go
@@ -80,6 +80,23 @@ var _ = Describe("Podman pause", func() {
result.WaitWithDefaultTimeout()
})
+ It("podman container pause a running container by id", func() {
+ session := podmanTest.RunTopContainer("")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ cid := session.OutputToString()
+
+ result := podmanTest.Podman([]string{"container", "pause", cid})
+ result.WaitWithDefaultTimeout()
+
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
+ Expect(podmanTest.GetContainerStatus()).To(ContainSubstring(pausedState))
+
+ result = podmanTest.Podman([]string{"container", "unpause", cid})
+ result.WaitWithDefaultTimeout()
+ })
+
It("podman unpause a running container by id", func() {
session := podmanTest.RunTopContainer("")
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index cb2b0e7b0..4717267a1 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -95,7 +95,6 @@ var _ = Describe("Podman pod create", func() {
Expect(webserver.ExitCode()).To(Equal(0))
check := SystemExec("nc", []string{"-z", "localhost", "80"})
- check.WaitWithDefaultTimeout()
Expect(check.ExitCode()).To(Equal(1))
})
@@ -111,7 +110,6 @@ var _ = Describe("Podman pod create", func() {
Expect(webserver.ExitCode()).To(Equal(0))
check := SystemExec("nc", []string{"-z", "localhost", "80"})
- check.WaitWithDefaultTimeout()
Expect(check.ExitCode()).To(Equal(0))
})
diff --git a/test/e2e/port_test.go b/test/e2e/port_test.go
index fa633c379..6ddc5d34f 100644
--- a/test/e2e/port_test.go
+++ b/test/e2e/port_test.go
@@ -60,6 +60,19 @@ var _ = Describe("Podman port", func() {
Expect(result.LineInOuputStartsWith(fmt.Sprintf("80/tcp -> 0.0.0.0:%s", port))).To(BeTrue())
})
+ It("podman container port -l nginx", func() {
+ podmanTest.RestoreArtifact(nginx)
+ session := podmanTest.Podman([]string{"container", "run", "-dt", "-P", nginx})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ result := podmanTest.Podman([]string{"container", "port", "-l"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ port := strings.Split(result.OutputToStringArray()[0], ":")[1]
+ Expect(result.LineInOuputStartsWith(fmt.Sprintf("80/tcp -> 0.0.0.0:%s", port))).To(BeTrue())
+ })
+
It("podman port -l port nginx", func() {
podmanTest.RestoreArtifact(nginx)
session := podmanTest.Podman([]string{"run", "-dt", "-P", nginx})
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 9b1c55bb4..a31fc3f09 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -65,6 +65,21 @@ var _ = Describe("Podman ps", func() {
Expect(len(result.OutputToStringArray())).Should(BeNumerically(">", 0))
})
+ It("podman container list all", func() {
+ _, ec, _ := podmanTest.RunLsContainer("")
+ Expect(ec).To(Equal(0))
+
+ result := podmanTest.Podman([]string{"container", "list", "-a"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(len(result.OutputToStringArray())).Should(BeNumerically(">", 0))
+
+ result = podmanTest.Podman([]string{"container", "ls", "-a"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(len(result.OutputToStringArray())).Should(BeNumerically(">", 0))
+ })
+
It("podman ps size flag", func() {
_, ec, _ := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go
index faad8202e..d9b9c7213 100644
--- a/test/e2e/pull_test.go
+++ b/test/e2e/pull_test.go
@@ -6,10 +6,12 @@ import (
"os"
"fmt"
+ "path/filepath"
+ "strings"
+
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
- "strings"
)
var _ = Describe("Podman pull", func() {
@@ -92,58 +94,56 @@ var _ = Describe("Podman pull", func() {
})
It("podman pull from docker-archive", func() {
- session := podmanTest.Podman([]string{"save", "-o", "/tmp/alp.tar", "alpine"})
+ tarfn := filepath.Join(podmanTest.TempDir, "alp.tar")
+ session := podmanTest.Podman([]string{"save", "-o", tarfn, "alpine"})
session.WaitWithDefaultTimeout()
+
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"rmi", "alpine"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pull", "docker-archive:/tmp/alp.tar"})
+ session = podmanTest.Podman([]string{"pull", fmt.Sprintf("docker-archive:%s", tarfn)})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"rmi", "alpine"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- clean := SystemExec("rm", []string{"/tmp/alp.tar"})
- clean.WaitWithDefaultTimeout()
- Expect(clean.ExitCode()).To(Equal(0))
})
It("podman pull from oci-archive", func() {
- session := podmanTest.Podman([]string{"save", "--format", "oci-archive", "-o", "/tmp/oci-alp.tar", "alpine"})
+ tarfn := filepath.Join(podmanTest.TempDir, "oci-alp.tar")
+ session := podmanTest.Podman([]string{"save", "--format", "oci-archive", "-o", tarfn, "alpine"})
session.WaitWithDefaultTimeout()
+
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"rmi", "alpine"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pull", "oci-archive:/tmp/oci-alp.tar"})
+ session = podmanTest.Podman([]string{"pull", fmt.Sprintf("oci-archive:%s", tarfn)})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"rmi", "alpine"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- clean := SystemExec("rm", []string{"/tmp/oci-alp.tar"})
- clean.WaitWithDefaultTimeout()
})
It("podman pull from local directory", func() {
- setup := SystemExec("mkdir", []string{"-p", "/tmp/podmantestdir"})
- setup.WaitWithDefaultTimeout()
- session := podmanTest.Podman([]string{"push", "alpine", "dir:/tmp/podmantestdir"})
+ dirpath := filepath.Join(podmanTest.TempDir, "alpine")
+ os.MkdirAll(dirpath, os.ModePerm)
+ imgPath := fmt.Sprintf("dir:%s", dirpath)
+
+ session := podmanTest.Podman([]string{"push", "alpine", imgPath})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"rmi", "alpine"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pull", "dir:/tmp/podmantestdir"})
+ session = podmanTest.Podman([]string{"pull", imgPath})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"rmi", "podmantestdir"})
+ session = podmanTest.Podman([]string{"rmi", "alpine"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
-
- clean := SystemExec("rm", []string{"-fr", "/tmp/podmantestdir"})
- clean.WaitWithDefaultTimeout()
})
It("podman pull check quiet", func() {
diff --git a/test/e2e/push_test.go b/test/e2e/push_test.go
index 42aefd1f7..fee117783 100644
--- a/test/e2e/push_test.go
+++ b/test/e2e/push_test.go
@@ -51,13 +51,11 @@ var _ = Describe("Podman push", func() {
})
It("podman push to dir", func() {
- session := podmanTest.Podman([]string{"push", "--remove-signatures", ALPINE, "dir:/tmp/busybox"})
+ bbdir := filepath.Join(podmanTest.TempDir, "busybox")
+ session := podmanTest.Podman([]string{"push", "--remove-signatures", ALPINE,
+ fmt.Sprintf("dir:%s", bbdir)})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
-
- clean := SystemExec("rm", []string{"-fr", "/tmp/busybox"})
- clean.WaitWithDefaultTimeout()
- Expect(clean.ExitCode()).To(Equal(0))
})
It("podman push to local registry", func() {
@@ -85,20 +83,21 @@ var _ = Describe("Podman push", func() {
authPath := filepath.Join(podmanTest.TempDir, "auth")
os.Mkdir(authPath, os.ModePerm)
os.MkdirAll("/etc/containers/certs.d/localhost:5000", os.ModePerm)
- debug := SystemExec("ls", []string{"-l", podmanTest.TempDir})
- debug.WaitWithDefaultTimeout()
+ defer os.RemoveAll("/etc/containers/certs.d/localhost:5000")
cwd, _ := os.Getwd()
certPath := filepath.Join(cwd, "../", "certs")
if IsCommandAvailable("getenforce") {
ge := SystemExec("getenforce", []string{})
- ge.WaitWithDefaultTimeout()
+ Expect(ge.ExitCode()).To(Equal(0))
if ge.OutputToString() == "Enforcing" {
se := SystemExec("setenforce", []string{"0"})
- se.WaitWithDefaultTimeout()
-
- defer SystemExec("setenforce", []string{"1"})
+ Expect(se.ExitCode()).To(Equal(0))
+ defer func() {
+ se2 := SystemExec("setenforce", []string{"1"})
+ Expect(se2.ExitCode()).To(Equal(0))
+ }()
}
}
podmanTest.RestoreArtifact(registry)
@@ -111,8 +110,6 @@ var _ = Describe("Podman push", func() {
f.WriteString(session.OutputToString())
f.Sync()
- debug = SystemExec("cat", []string{filepath.Join(authPath, "htpasswd")})
- debug.WaitWithDefaultTimeout()
session = podmanTest.Podman([]string{"run", "-d", "-p", "5000:5000", "--name", "registry", "-v",
strings.Join([]string{authPath, "/auth"}, ":"), "-e", "REGISTRY_AUTH=htpasswd", "-e",
@@ -138,8 +135,7 @@ var _ = Describe("Podman push", func() {
Expect(push.ExitCode()).To(Equal(0))
setup := SystemExec("cp", []string{filepath.Join(certPath, "domain.crt"), "/etc/containers/certs.d/localhost:5000/ca.crt"})
- setup.WaitWithDefaultTimeout()
- defer os.RemoveAll("/etc/containers/certs.d/localhost:5000")
+ Expect(setup.ExitCode()).To(Equal(0))
push = podmanTest.Podman([]string{"push", "--creds=podmantest:wrongpasswd", ALPINE, "localhost:5000/credstest"})
push.WaitWithDefaultTimeout()
@@ -155,23 +151,22 @@ var _ = Describe("Podman push", func() {
})
It("podman push to docker-archive", func() {
- session := podmanTest.Podman([]string{"push", ALPINE, "docker-archive:/tmp/alp:latest"})
+ tarfn := filepath.Join(podmanTest.TempDir, "alp.tar")
+ session := podmanTest.Podman([]string{"push", ALPINE,
+ fmt.Sprintf("docker-archive:%s:latest", tarfn)})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- clean := SystemExec("rm", []string{"/tmp/alp"})
- clean.WaitWithDefaultTimeout()
- Expect(clean.ExitCode()).To(Equal(0))
})
It("podman push to docker daemon", func() {
setup := SystemExec("bash", []string{"-c", "systemctl status docker 2>&1"})
- setup.WaitWithDefaultTimeout()
if setup.LineInOutputContains("Active: inactive") {
setup = SystemExec("systemctl", []string{"start", "docker"})
- setup.WaitWithDefaultTimeout()
-
- defer SystemExec("systemctl", []string{"stop", "docker"})
+ defer func() {
+ stop := SystemExec("systemctl", []string{"stop", "docker"})
+ Expect(stop.ExitCode()).To(Equal(0))
+ }()
} else if setup.ExitCode() != 0 {
Skip("Docker is not available")
}
@@ -181,22 +176,19 @@ var _ = Describe("Podman push", func() {
Expect(session.ExitCode()).To(Equal(0))
check := SystemExec("docker", []string{"images", "--format", "{{.Repository}}:{{.Tag}}"})
- check.WaitWithDefaultTimeout()
Expect(check.ExitCode()).To(Equal(0))
Expect(check.OutputToString()).To(ContainSubstring("alpine:podmantest"))
clean := SystemExec("docker", []string{"rmi", "alpine:podmantest"})
- clean.WaitWithDefaultTimeout()
Expect(clean.ExitCode()).To(Equal(0))
})
It("podman push to oci-archive", func() {
- session := podmanTest.Podman([]string{"push", ALPINE, "oci-archive:/tmp/alp.tar:latest"})
+ tarfn := filepath.Join(podmanTest.TempDir, "alp.tar")
+ session := podmanTest.Podman([]string{"push", ALPINE,
+ fmt.Sprintf("oci-archive:%s:latest", tarfn)})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- clean := SystemExec("rm", []string{"/tmp/alp.tar"})
- clean.WaitWithDefaultTimeout()
- Expect(clean.ExitCode()).To(Equal(0))
})
It("podman push to local ostree", func() {
@@ -208,33 +200,29 @@ var _ = Describe("Podman push", func() {
os.MkdirAll(ostreePath, os.ModePerm)
setup := SystemExec("ostree", []string{strings.Join([]string{"--repo=", ostreePath}, ""), "init"})
- setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
session := podmanTest.Podman([]string{"push", ALPINE, strings.Join([]string{"ostree:alp@", ostreePath}, "")})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- clean := SystemExec("rm", []string{"-rf", ostreePath})
- clean.WaitWithDefaultTimeout()
- Expect(clean.ExitCode()).To(Equal(0))
})
It("podman push to docker-archive no reference", func() {
- session := podmanTest.Podman([]string{"push", ALPINE, "docker-archive:/tmp/alp"})
+ tarfn := filepath.Join(podmanTest.TempDir, "alp.tar")
+ session := podmanTest.Podman([]string{"push", ALPINE,
+ fmt.Sprintf("docker-archive:%s", tarfn)})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- clean := SystemExec("rm", []string{"/tmp/alp"})
- clean.WaitWithDefaultTimeout()
- Expect(clean.ExitCode()).To(Equal(0))
})
It("podman push to oci-archive no reference", func() {
- session := podmanTest.Podman([]string{"push", ALPINE, "oci-archive:/tmp/alp-oci"})
+ ociarc := filepath.Join(podmanTest.TempDir, "alp-oci")
+ session := podmanTest.Podman([]string{"push", ALPINE,
+ fmt.Sprintf("oci-archive:%s", ociarc)})
+
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- clean := SystemExec("rm", []string{"/tmp/alp-oci"})
- clean.WaitWithDefaultTimeout()
- Expect(clean.ExitCode()).To(Equal(0))
})
})
diff --git a/test/e2e/restart_test.go b/test/e2e/restart_test.go
index 5c914a367..a101219d4 100644
--- a/test/e2e/restart_test.go
+++ b/test/e2e/restart_test.go
@@ -90,6 +90,21 @@ var _ = Describe("Podman restart", func() {
Expect(restartTime.OutputToString()).To(Not(Equal(startTime.OutputToString())))
})
+ It("Podman container restart running container", func() {
+ _ = podmanTest.RunTopContainer("test1")
+ ok := WaitForContainer(podmanTest)
+ Expect(ok).To(BeTrue())
+ startTime := podmanTest.Podman([]string{"container", "inspect", "--format='{{.State.StartedAt}}'", "test1"})
+ startTime.WaitWithDefaultTimeout()
+
+ session := podmanTest.Podman([]string{"container", "restart", "test1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ restartTime := podmanTest.Podman([]string{"container", "inspect", "--format='{{.State.StartedAt}}'", "test1"})
+ restartTime.WaitWithDefaultTimeout()
+ Expect(restartTime.OutputToString()).To(Not(Equal(startTime.OutputToString())))
+ })
+
It("Podman restart multiple containers", func() {
_, exitCode, _ := podmanTest.RunLsContainer("test1")
Expect(exitCode).To(Equal(0))
diff --git a/test/e2e/rm_test.go b/test/e2e/rm_test.go
index 71dacfa80..db08dda8b 100644
--- a/test/e2e/rm_test.go
+++ b/test/e2e/rm_test.go
@@ -65,6 +65,17 @@ var _ = Describe("Podman rm", func() {
Expect(result.ExitCode()).To(Equal(0))
})
+ It("podman container rm created container", func() {
+ session := podmanTest.Podman([]string{"container", "create", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ cid := session.OutputToString()
+
+ result := podmanTest.Podman([]string{"container", "rm", cid})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ })
+
It("podman rm running container with -f", func() {
session := podmanTest.RunTopContainer("")
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/rmi_test.go b/test/e2e/rmi_test.go
index dcbda2df4..26cc925ef 100644
--- a/test/e2e/rmi_test.go
+++ b/test/e2e/rmi_test.go
@@ -275,4 +275,13 @@ RUN find $LOCAL
Expect(images.ExitCode()).To(Equal(0))
Expect(len(images.OutputToStringArray())).To(Equal(0))
})
+
+ // Don't rerun all tests; just assume that if we get that diagnostic,
+ // we're getting rmi
+ It("podman image rm is the same as rmi", func() {
+ session := podmanTest.Podman([]string{"image", "rm"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(125))
+ Expect(session.LineInOutputContains("image name or ID must be specified"))
+ })
})
diff --git a/test/e2e/run_cleanup_test.go b/test/e2e/run_cleanup_test.go
index aa823b4e6..1f2a4085d 100644
--- a/test/e2e/run_cleanup_test.go
+++ b/test/e2e/run_cleanup_test.go
@@ -36,14 +36,16 @@ var _ = Describe("Podman run exit", func() {
It("podman run -d mount cleanup test", func() {
mount := SystemExec("mount", nil)
- mount.WaitWithDefaultTimeout()
+ Expect(mount.ExitCode()).To(Equal(0))
+
out1 := mount.OutputToString()
result := podmanTest.Podman([]string{"create", "-dt", ALPINE, "echo", "hello"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
mount = SystemExec("mount", nil)
- mount.WaitWithDefaultTimeout()
+ Expect(mount.ExitCode()).To(Equal(0))
+
out2 := mount.OutputToString()
Expect(out1).To(Equal(out2))
})
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index a07e4d047..c89a4f487 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -58,7 +58,6 @@ var _ = Describe("Podman run networking", func() {
session.Wait(30)
Expect(session.ExitCode()).To(Equal(0))
results := SystemExec("iptables", []string{"-t", "nat", "-L"})
- results.Wait(30)
Expect(results.ExitCode()).To(Equal(0))
Expect(results.OutputToString()).To(ContainSubstring("222"))
Expect(results.OutputToString()).To(ContainSubstring("223"))
@@ -69,12 +68,10 @@ var _ = Describe("Podman run networking", func() {
session.Wait(30)
Expect(session.ExitCode()).To(Equal(0))
results := SystemExec("iptables", []string{"-t", "nat", "-L"})
- results.Wait(30)
Expect(results.ExitCode()).To(Equal(0))
Expect(results.OutputToString()).To(ContainSubstring("8000"))
ncBusy := SystemExec("nc", []string{"-l", "-p", "80"})
- ncBusy.Wait(10)
Expect(ncBusy.ExitCode()).ToNot(Equal(0))
})
@@ -183,26 +180,40 @@ var _ = Describe("Podman run networking", func() {
if Containerized() {
Skip("Can not be run within a container.")
}
- SystemExec("ip", []string{"netns", "add", "xxx"})
+ addXXX := SystemExec("ip", []string{"netns", "add", "xxx"})
+ Expect(addXXX.ExitCode()).To(Equal(0))
+ defer func() {
+ delXXX := SystemExec("ip", []string{"netns", "delete", "xxx"})
+ Expect(delXXX.ExitCode()).To(Equal(0))
+ }()
+
session := podmanTest.Podman([]string{"run", "-dt", "--net", "ns:/run/netns/xxx", ALPINE, "wget", "www.podman.io"})
session.Wait(90)
Expect(session.ExitCode()).To(Equal(0))
- SystemExec("ip", []string{"netns", "delete", "xxx"})
})
It("podman run n user created network namespace with resolv.conf", func() {
if Containerized() {
Skip("Can not be run within a container.")
}
- SystemExec("ip", []string{"netns", "add", "xxx"})
- SystemExec("mkdir", []string{"-p", "/etc/netns/xxx"})
- SystemExec("bash", []string{"-c", "echo nameserver 11.11.11.11 > /etc/netns/xxx/resolv.conf"})
- session := podmanTest.Podman([]string{"run", "--net", "ns:/run/netns/xxx", ALPINE, "cat", "/etc/resolv.conf"})
+ addXXX2 := SystemExec("ip", []string{"netns", "add", "xxx2"})
+ Expect(addXXX2.ExitCode()).To(Equal(0))
+ defer func() {
+ delXXX2 := SystemExec("ip", []string{"netns", "delete", "xxx2"})
+ Expect(delXXX2.ExitCode()).To(Equal(0))
+ }()
+
+ mdXXX2 := SystemExec("mkdir", []string{"-p", "/etc/netns/xxx2"})
+ Expect(mdXXX2.ExitCode()).To(Equal(0))
+ defer os.RemoveAll("/etc/netns/xxx2")
+
+ nsXXX2 := SystemExec("bash", []string{"-c", "echo nameserver 11.11.11.11 > /etc/netns/xxx2/resolv.conf"})
+ Expect(nsXXX2.ExitCode()).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"run", "--net", "ns:/run/netns/xxx2", ALPINE, "cat", "/etc/resolv.conf"})
session.Wait(90)
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("11.11.11.11"))
- SystemExec("ip", []string{"netns", "delete", "xxx"})
- SystemExec("rm", []string{"-rf", "/etc/netns/xxx"})
})
It("podman run network in bogus user created network namespace", func() {
diff --git a/test/e2e/run_ns_test.go b/test/e2e/run_ns_test.go
index 9962185f2..3d95c3a0b 100644
--- a/test/e2e/run_ns_test.go
+++ b/test/e2e/run_ns_test.go
@@ -53,7 +53,6 @@ var _ = Describe("Podman run ns", func() {
It("podman run ipcns test", func() {
setup := SystemExec("ls", []string{"--inode", "-d", "/dev/shm"})
- setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0))
hostShm := setup.OutputToString()
@@ -65,7 +64,6 @@ var _ = Describe("Podman run ns", func() {
It("podman run ipcns ipcmk host test", func() {
setup := SystemExec("ipcmk", []string{"-M", "1024"})
- setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0))
output := strings.Split(setup.OutputToString(), " ")
ipc := output[len(output)-1]
@@ -74,7 +72,6 @@ var _ = Describe("Podman run ns", func() {
Expect(session.ExitCode()).To(Equal(0))
setup = SystemExec("ipcrm", []string{"-m", ipc})
- setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0))
})
diff --git a/test/e2e/run_privileged_test.go b/test/e2e/run_privileged_test.go
index 0c0de30c5..ee6e8e950 100644
--- a/test/e2e/run_privileged_test.go
+++ b/test/e2e/run_privileged_test.go
@@ -46,7 +46,6 @@ var _ = Describe("Podman privileged container tests", func() {
It("podman privileged CapEff", func() {
cap := SystemExec("grep", []string{"CapEff", "/proc/self/status"})
- cap.WaitWithDefaultTimeout()
Expect(cap.ExitCode()).To(Equal(0))
session := podmanTest.Podman([]string{"run", "--privileged", "busybox", "grep", "CapEff", "/proc/self/status"})
@@ -57,7 +56,6 @@ var _ = Describe("Podman privileged container tests", func() {
It("podman cap-add CapEff", func() {
cap := SystemExec("grep", []string{"CapEff", "/proc/self/status"})
- cap.WaitWithDefaultTimeout()
Expect(cap.ExitCode()).To(Equal(0))
session := podmanTest.Podman([]string{"run", "--cap-add", "all", "busybox", "grep", "CapEff", "/proc/self/status"})
@@ -97,7 +95,6 @@ var _ = Describe("Podman privileged container tests", func() {
}
cap := SystemExec("grep", []string{"NoNewPrivs", "/proc/self/status"})
- cap.WaitWithDefaultTimeout()
if cap.ExitCode() != 0 {
Skip("Can't determine NoNewPrivs")
}
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 6bd49de33..4ba32a94a 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -68,6 +68,20 @@ var _ = Describe("Podman run", func() {
Expect(session.ExitCode()).To(Equal(0))
})
+ It("podman container run a container based on on a short name with localhost", func() {
+ podmanTest.RestoreArtifact(nginx)
+ tag := podmanTest.Podman([]string{"image", "tag", nginx, "localhost/libpod/alpine_nginx:latest"})
+ tag.WaitWithDefaultTimeout()
+
+ rmi := podmanTest.Podman([]string{"image", "rm", nginx})
+ rmi.WaitWithDefaultTimeout()
+
+ session := podmanTest.Podman([]string{"container", "run", "libpod/alpine_nginx:latest", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ErrorToString()).ToNot(ContainSubstring("Trying to pull"))
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+
It("podman run a container based on local image with short options", func() {
session := podmanTest.Podman([]string{"run", "-dt", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
@@ -387,7 +401,6 @@ var _ = Describe("Podman run", func() {
err = ioutil.WriteFile(keyFile, []byte(mountString), 0755)
Expect(err).To(BeNil())
execSession := SystemExec("ln", []string{"-s", targetDir, filepath.Join(secretsDir, "mysymlink")})
- execSession.WaitWithDefaultTimeout()
Expect(execSession.ExitCode()).To(Equal(0))
session := podmanTest.Podman([]string{"--default-mounts-file=" + mountsFile, "run", "--rm", ALPINE, "cat", "/run/secrets/test.txt"})
diff --git a/test/e2e/start_test.go b/test/e2e/start_test.go
index c4ed6f545..51fece3f1 100644
--- a/test/e2e/start_test.go
+++ b/test/e2e/start_test.go
@@ -50,6 +50,16 @@ var _ = Describe("Podman start", func() {
Expect(session.ExitCode()).To(Equal(0))
})
+ It("podman container start single container by id", func() {
+ session := podmanTest.Podman([]string{"container", "create", "-d", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ cid := session.OutputToString()
+ session = podmanTest.Podman([]string{"container", "start", cid})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+
It("podman start single container by name", func() {
session := podmanTest.Podman([]string{"create", "-d", "--name", "foobar99", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/stop_test.go b/test/e2e/stop_test.go
index 8fffedbb9..eb680d2a1 100644
--- a/test/e2e/stop_test.go
+++ b/test/e2e/stop_test.go
@@ -59,6 +59,15 @@ var _ = Describe("Podman stop", func() {
Expect(session.ExitCode()).To(Equal(0))
})
+ It("podman stop container by name", func() {
+ session := podmanTest.RunTopContainer("test1")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ session = podmanTest.Podman([]string{"container", "stop", "test1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+
It("podman stop stopped container", func() {
session := podmanTest.RunTopContainer("test1")
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go
index a7e7a1500..252361288 100644
--- a/test/e2e/systemd_test.go
+++ b/test/e2e/systemd_test.go
@@ -53,31 +53,27 @@ WantedBy=multi-user.target
sys_file := ioutil.WriteFile("/etc/systemd/system/redis.service", []byte(systemd_unit_file), 0644)
Expect(sys_file).To(BeNil())
+ defer func() {
+ stop := SystemExec("bash", []string{"-c", "systemctl stop redis"})
+ os.Remove("/etc/systemd/system/redis.service")
+ SystemExec("bash", []string{"-c", "systemctl daemon-reload"})
+ Expect(stop.ExitCode()).To(Equal(0))
+ }()
create := podmanTest.Podman([]string{"create", "-d", "--name", "redis", "redis"})
create.WaitWithDefaultTimeout()
Expect(create.ExitCode()).To(Equal(0))
- enable := SystemExec("bash", []string{"-c", "systemctl daemon-reload && systemctl enable --now redis"})
- enable.WaitWithDefaultTimeout()
+ enable := SystemExec("bash", []string{"-c", "systemctl daemon-reload"})
Expect(enable.ExitCode()).To(Equal(0))
start := SystemExec("bash", []string{"-c", "systemctl start redis"})
- start.WaitWithDefaultTimeout()
+ Expect(start.ExitCode()).To(Equal(0))
logs := SystemExec("bash", []string{"-c", "journalctl -n 20 -u redis"})
- logs.WaitWithDefaultTimeout()
+ Expect(logs.ExitCode()).To(Equal(0))
status := SystemExec("bash", []string{"-c", "systemctl status redis"})
- status.WaitWithDefaultTimeout()
Expect(status.OutputToString()).To(ContainSubstring("active (running)"))
-
- cleanup := SystemExec("bash", []string{"-c", "systemctl stop redis && systemctl disable redis"})
- cleanup.WaitWithDefaultTimeout()
- Expect(cleanup.ExitCode()).To(Equal(0))
- os.Remove("/etc/systemd/system/redis.service")
- sys_clean := SystemExec("bash", []string{"-c", "systemctl daemon-reload"})
- sys_clean.WaitWithDefaultTimeout()
- Expect(sys_clean.ExitCode()).To(Equal(0))
})
})
diff --git a/test/e2e/top_test.go b/test/e2e/top_test.go
index 067358468..156c37035 100644
--- a/test/e2e/top_test.go
+++ b/test/e2e/top_test.go
@@ -65,6 +65,17 @@ var _ = Describe("Podman top", func() {
Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1))
})
+ It("podman container top on container", func() {
+ session := podmanTest.Podman([]string{"container", "run", "-d", ALPINE, "top", "-d", "2"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ result := podmanTest.Podman([]string{"container", "top", "-l"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1))
+ })
+
It("podman top with options", func() {
session := podmanTest.Podman([]string{"run", "-d", ALPINE, "top", "-d", "2"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/wait_test.go b/test/e2e/wait_test.go
index 08da97aa0..69e64774c 100644
--- a/test/e2e/wait_test.go
+++ b/test/e2e/wait_test.go
@@ -66,4 +66,11 @@ var _ = Describe("Podman wait", func() {
session = podmanTest.Podman([]string{"wait", "-l"})
session.Wait(20)
})
+ It("podman container wait on latest container", func() {
+ session := podmanTest.Podman([]string{"container", "run", "-d", ALPINE, "sleep", "1"})
+ session.Wait(20)
+ Expect(session.ExitCode()).To(Equal(0))
+ session = podmanTest.Podman([]string{"container", "wait", "-l"})
+ session.Wait(20)
+ })
})
diff --git a/test/test_podman_baseline.sh b/test/test_podman_baseline.sh
index 8a878b4e7..664fd2b03 100755
--- a/test/test_podman_baseline.sh
+++ b/test/test_podman_baseline.sh
@@ -195,7 +195,7 @@ podman rmi --all
########
# 1.004608 MB is 1,004,608 bytes. The container overhead is 4608 bytes (or 9 512 byte pages), so this allocates 1 MB of usable storage
-PODMANBASE="-s overlay --storage-opt overlay.size=1.004608M --root /tmp/podman_test/crio"
+PODMANBASE="--storage-driver overlay --storage-opt overlay.size=1.004608M --root /tmp/podman_test/crio"
TMPDIR=/tmp/podman_test
mkdir $TMPDIR
dd if=/dev/zero of=$TMPDIR/virtfs bs=1024 count=30720
diff --git a/test/utils/utils.go b/test/utils/utils.go
index 098779321..499466f5a 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -326,6 +326,7 @@ func SystemExec(command string, args []string) *PodmanSession {
if err != nil {
Fail(fmt.Sprintf("unable to run command: %s %s", command, strings.Join(args, " ")))
}
+ session.Wait(defaultWaitTimeout)
return &PodmanSession{session}
}