summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml33
-rw-r--r--cmd/podman/attach.go1
-rw-r--r--cmd/podman/build.go4
-rw-r--r--cmd/podman/checkpoint.go1
-rw-r--r--cmd/podman/cleanup.go1
-rw-r--r--cmd/podman/commit.go6
-rw-r--r--cmd/podman/common.go28
-rw-r--r--cmd/podman/container.go1
-rw-r--r--cmd/podman/containers_prune.go1
-rw-r--r--cmd/podman/cp.go9
-rw-r--r--cmd/podman/create.go22
-rw-r--r--cmd/podman/diff.go4
-rw-r--r--cmd/podman/exec.go35
-rw-r--r--cmd/podman/exists.go18
-rw-r--r--cmd/podman/export.go1
-rw-r--r--cmd/podman/generate.go1
-rw-r--r--cmd/podman/generate_kube.go9
-rw-r--r--cmd/podman/healthcheck.go1
-rw-r--r--cmd/podman/healthcheck_run.go2
-rw-r--r--cmd/podman/history.go6
-rw-r--r--cmd/podman/image.go1
-rw-r--r--cmd/podman/images.go3
-rw-r--r--cmd/podman/images_prune.go7
-rw-r--r--cmd/podman/import.go7
-rw-r--r--cmd/podman/info.go10
-rw-r--r--cmd/podman/inspect.go7
-rw-r--r--cmd/podman/kill.go1
-rw-r--r--cmd/podman/load.go1
-rw-r--r--cmd/podman/login.go1
-rw-r--r--cmd/podman/logout.go1
-rw-r--r--cmd/podman/logs.go7
-rw-r--r--cmd/podman/main.go4
-rw-r--r--cmd/podman/mount.go10
-rw-r--r--cmd/podman/pause.go9
-rw-r--r--cmd/podman/play.go2
-rw-r--r--cmd/podman/play_kube.go7
-rw-r--r--cmd/podman/pod.go6
-rw-r--r--cmd/podman/pod_create.go8
-rw-r--r--cmd/podman/pod_inspect.go8
-rw-r--r--cmd/podman/pod_kill.go7
-rw-r--r--cmd/podman/pod_pause.go7
-rw-r--r--cmd/podman/pod_ps.go1
-rw-r--r--cmd/podman/pod_restart.go7
-rw-r--r--cmd/podman/pod_rm.go9
-rw-r--r--cmd/podman/pod_start.go7
-rw-r--r--cmd/podman/pod_stats.go8
-rw-r--r--cmd/podman/pod_stop.go7
-rw-r--r--cmd/podman/pod_top.go11
-rw-r--r--cmd/podman/pod_unpause.go7
-rw-r--r--cmd/podman/port.go6
-rw-r--r--cmd/podman/ps.go5
-rw-r--r--cmd/podman/pull.go9
-rw-r--r--cmd/podman/push.go8
-rw-r--r--cmd/podman/refresh.go8
-rw-r--r--cmd/podman/restart.go7
-rw-r--r--cmd/podman/restore.go1
-rw-r--r--cmd/podman/rm.go9
-rw-r--r--cmd/podman/rmi.go3
-rw-r--r--cmd/podman/run.go1
-rw-r--r--cmd/podman/runlabel.go1
-rw-r--r--cmd/podman/save.go5
-rw-r--r--cmd/podman/search.go7
-rw-r--r--cmd/podman/sign.go3
-rw-r--r--cmd/podman/start.go6
-rw-r--r--cmd/podman/stats.go5
-rw-r--r--cmd/podman/stop.go9
-rw-r--r--cmd/podman/system.go1
-rw-r--r--cmd/podman/system_prune.go1
-rw-r--r--cmd/podman/system_renumber.go1
-rw-r--r--cmd/podman/tag.go3
-rw-r--r--cmd/podman/top.go17
-rw-r--r--cmd/podman/trust.go7
-rw-r--r--cmd/podman/trust_set_show.go2
-rw-r--r--cmd/podman/umount.go12
-rw-r--r--cmd/podman/unpause.go9
-rw-r--r--cmd/podman/varlink.go6
-rw-r--r--cmd/podman/volume.go5
-rw-r--r--cmd/podman/volume_create.go7
-rw-r--r--cmd/podman/volume_inspect.go8
-rw-r--r--cmd/podman/volume_ls.go4
-rw-r--r--cmd/podman/volume_prune.go9
-rw-r--r--cmd/podman/volume_rm.go9
-rw-r--r--cmd/podman/wait.go6
-rw-r--r--contrib/cirrus/README.md11
-rwxr-xr-xcontrib/cirrus/test/test_dot_cirrus_yaml.py78
-rw-r--r--contrib/gate/Dockerfile1
-rw-r--r--docs/podman.1.md1
-rwxr-xr-xhack/podman-commands.sh3
-rw-r--r--libpod/boltdb_state.go167
-rw-r--r--libpod/container_internal.go20
-rw-r--r--libpod/container_internal_test.go48
-rw-r--r--libpod/oci.go6
-rw-r--r--test/README.md4
-rw-r--r--test/system/000-TEMPLATE114
-rw-r--r--test/system/001-basic.bats50
-rw-r--r--test/system/005-info.bats54
-rw-r--r--test/system/010-images.bats46
-rw-r--r--test/system/015-help.bats76
-rw-r--r--test/system/030-run.bats34
-rw-r--r--test/system/035-logs.bats24
-rw-r--r--test/system/040-ps.bats38
-rw-r--r--test/system/050-stop.bats67
-rw-r--r--test/system/060-mount.bats37
-rw-r--r--test/system/070-build.bats28
-rw-r--r--test/system/110-history.bats49
-rw-r--r--test/system/200-pod-top.bats37
-rw-r--r--test/system/README.md82
-rw-r--r--test/system/TODO.md105
-rw-r--r--test/system/helpers.bash349
-rwxr-xr-xtest/system/helpers.t145
-rw-r--r--test/system/libpod_suite_test.go217
-rw-r--r--test/system/version_test.go51
-rwxr-xr-xtest/test_podman_baseline.sh95
113 files changed, 2033 insertions, 559 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index b473980ea..328b2e676 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -27,11 +27,17 @@ env:
####
#### Cache-image names to test with
###
+ ACTIVE_CACHE_IMAGE_NAMES: >-
+ fedora-29-libpod-d6d53e40
+ fedora-28-libpod-d6d53e40
+ ubuntu-18-libpod-d6d53e40
+ rhel-7-libpod-7f4cd1f7
+ image-builder-image-1541772081
FEDORA_CACHE_IMAGE_NAME: "fedora-29-libpod-d6d53e40"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-28-libpod-d6d53e40"
UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-d6d53e40"
+ PRIOR_RHEL_CACHE_IMAGE_NAME: "rhel-7-libpod-7f4cd1f7"
# RHEL_CACHE_IMAGE_NAME: "rhel-8-notready"
- PRIOR_RHEL_CACHE_IMAGE_NAME: "rhel-7-libpod-d6d53e40"
# CENTOS_CACHE_IMAGE_NAME: "centos-7-notready"
####
@@ -108,6 +114,7 @@ gating_task:
gate_script:
- '/usr/local/bin/entrypoint.sh validate'
- '/usr/local/bin/entrypoint.sh lint'
+ - '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/test/test_dot_cirrus_yaml.py'
# This task runs `make vendor` followed by ./hack/tree_status.sh to check
# whether the git tree is clean. The reasoning for that is to make sure
@@ -149,6 +156,30 @@ build_each_commit_task:
- env GOPATH=/var/tmp/go/ make build-all-new-commits GIT_BASE_BRANCH=origin/$CIRRUS_BASE_BRANCH
+# Update metadata on VM images referenced by this repository state
+meta_task:
+
+ depends_on:
+ - "gating"
+
+ container:
+ image: "quay.io/libpod/imgts:latest" # see contrib/imgts
+ cpu: 1
+ memory: 1
+
+ env:
+ # Space-separated list of images used by this repository state
+ IMGNAMES: "${ACTIVE_CACHE_IMAGE_NAMES}"
+ BUILDID: "${CIRRUS_BUILD_ID}"
+ REPOREF: "${CIRRUS_CHANGE_IN_REPO}"
+ GCPJSON: ENCRYPTED[950d9c64ad78f7b1f0c7e499b42dc058d2b23aa67e38b315e68f557f2aba0bf83068d4734f7b1e1bdd22deabe99629df]
+ GCPNAME: ENCRYPTED[b05d469a0dba8cb479cb00cc7c1f6747c91d17622fba260a986b976aa6c817d4077eacffd4613d6d5f23afc4084fab1d]
+ GCPPROJECT: ENCRYPTED[7c80e728e046b1c76147afd156a32c1c57d4a1ac1eab93b7e68e718c61ca8564fc61fef815952b8ae0a64e7034b8fe4f]
+ CIRRUS_CLONE_DEPTH: 1 # source not used
+
+ script: /usr/local/bin/entrypoint.sh
+
+
# This task does the unit and integration testing for every platform
testing_task:
diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go
index a22aa92a1..08976cdaa 100644
--- a/cmd/podman/attach.go
+++ b/cmd/podman/attach.go
@@ -30,6 +30,7 @@ var (
func init() {
attachCommand.Command = _attachCommand
+ attachCommand.SetHelpTemplate(HelpTemplate())
attachCommand.SetUsageTemplate(UsageTemplate())
flags := attachCommand.Flags()
flags.StringVar(&attachCommand.DetachKeys, "detach-keys", "", "Override the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _")
diff --git a/cmd/podman/build.go b/cmd/podman/build.go
index cfeabfb4e..5fcf03b93 100644
--- a/cmd/podman/build.go
+++ b/cmd/podman/build.go
@@ -18,8 +18,7 @@ import (
var (
buildCommand cliconfig.BuildValues
- buildDescription = "Builds an OCI or Docker image using instructions from one\n" +
- "or more Dockerfiles and a specified build context directory."
+ buildDescription = "Builds an OCI or Docker image using instructions from one or more Dockerfiles and a specified build context directory."
layerValues buildahcli.LayerResults
budFlagsValues buildahcli.BudResults
fromAndBudValues buildahcli.FromAndBudResults
@@ -48,6 +47,7 @@ var (
func init() {
buildCommand.Command = _buildCommand
+ buildCommand.SetHelpTemplate(HelpTemplate())
buildCommand.SetUsageTemplate(UsageTemplate())
flags := buildCommand.Flags()
flags.SetInterspersed(false)
diff --git a/cmd/podman/checkpoint.go b/cmd/podman/checkpoint.go
index 367065766..dbf72c2cd 100644
--- a/cmd/podman/checkpoint.go
+++ b/cmd/podman/checkpoint.go
@@ -40,6 +40,7 @@ var (
func init() {
checkpointCommand.Command = _checkpointCommand
+ checkpointCommand.SetHelpTemplate(HelpTemplate())
checkpointCommand.SetUsageTemplate(UsageTemplate())
flags := checkpointCommand.Flags()
diff --git a/cmd/podman/cleanup.go b/cmd/podman/cleanup.go
index fbbd337a7..17e637da1 100644
--- a/cmd/podman/cleanup.go
+++ b/cmd/podman/cleanup.go
@@ -37,6 +37,7 @@ var (
func init() {
cleanupCommand.Command = _cleanupCommand
+ cleanupCommand.SetHelpTemplate(HelpTemplate())
cleanupCommand.SetUsageTemplate(UsageTemplate())
flags := cleanupCommand.Flags()
diff --git a/cmd/podman/commit.go b/cmd/podman/commit.go
index 43c54c320..584ab6880 100644
--- a/cmd/podman/commit.go
+++ b/cmd/podman/commit.go
@@ -19,10 +19,7 @@ import (
var (
commitCommand cliconfig.CommitValues
- commitDescription = `Create an image from a container's changes.
- Optionally tag the image created, set the author with the --author flag,
- set the commit message with the --message flag,
- and make changes to the instructions with the --change flag.`
+ commitDescription = `Create an image from a container's changes. Optionally tag the image created, set the author with the --author flag, set the commit message with the --message flag, and make changes to the instructions with the --change flag.`
_commitCommand = &cobra.Command{
Use: "commit [flags] CONTAINER IMAGE",
@@ -41,6 +38,7 @@ var (
func init() {
commitCommand.Command = _commitCommand
+ commitCommand.SetHelpTemplate(HelpTemplate())
commitCommand.SetUsageTemplate(UsageTemplate())
flags := commitCommand.Flags()
flags.StringSliceVarP(&commitCommand.Change, "change", "c", []string{}, fmt.Sprintf("Apply the following possible instructions to the created image (default []): %s", strings.Join(libpod.ChangeCmds, " | ")))
diff --git a/cmd/podman/common.go b/cmd/podman/common.go
index c9e937825..30eaa95d8 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -3,7 +3,6 @@ package main
import (
"context"
"fmt"
- "github.com/spf13/cobra"
"os"
"strings"
@@ -14,6 +13,7 @@ import (
"github.com/containers/storage"
"github.com/fatih/camelcase"
"github.com/pkg/errors"
+ "github.com/spf13/cobra"
)
var (
@@ -67,6 +67,16 @@ func noSubArgs(c *cobra.Command, args []string) error {
return nil
}
+func commandRunE() func(*cobra.Command, []string) error {
+ return func(cmd *cobra.Command, args []string) error {
+ if len(args) > 0 {
+ return errors.Errorf("unrecognized command `%s %s`\nTry '%s --help' for more information.", cmd.CommandPath(), args[0], cmd.CommandPath())
+ } else {
+ return errors.Errorf("missing command '%s COMMAND'\nTry '%s --help' for more information.", cmd.CommandPath(), cmd.CommandPath())
+ }
+ }
+}
+
// 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
@@ -311,7 +321,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"kernel-memory", "",
"Kernel memory limit (format: `<number>[<unit>]`, where unit = b, k, m or g)",
)
- createFlags.StringSliceP(
+ createFlags.StringArrayP(
"label", "l", []string{},
"Set metadata on container (default [])",
)
@@ -521,11 +531,23 @@ func scrubServer(server string) string {
return strings.TrimPrefix(server, "http://")
}
+// HelpTemplate returns the help template for podman commands
+// This uses the short and long options.
+// command should not use this.
+func HelpTemplate() string {
+ return `{{.Short}}
+
+Description:
+ {{.Long}}
+
+{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
+}
+
// UsageTemplate returns the usage template for podman commands
// This blocks the desplaying of the global options. The main podman
// command should not use this.
func UsageTemplate() string {
- return `Usage:{{if .Runnable}}
+ return `Usage:{{if (and .Runnable (not .HasAvailableSubCommands))}}
{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
diff --git a/cmd/podman/container.go b/cmd/podman/container.go
index 0bcdf533a..8ad8d7a44 100644
--- a/cmd/podman/container.go
+++ b/cmd/podman/container.go
@@ -15,6 +15,7 @@ var (
Short: "Manage Containers",
Long: containerDescription,
TraverseChildren: true,
+ RunE: commandRunE(),
},
}
diff --git a/cmd/podman/containers_prune.go b/cmd/podman/containers_prune.go
index 0d0e75332..39be70c5b 100644
--- a/cmd/podman/containers_prune.go
+++ b/cmd/podman/containers_prune.go
@@ -34,6 +34,7 @@ var (
func init() {
pruneContainersCommand.Command = _pruneContainersCommand
+ pruneContainersCommand.SetHelpTemplate(HelpTemplate())
pruneContainersCommand.SetUsageTemplate(UsageTemplate())
flags := pruneContainersCommand.Flags()
flags.BoolVarP(&pruneContainersCommand.Force, "force", "f", false, "Force removal of a running container. The default is false")
diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go
index a3411b158..6223676ac 100644
--- a/cmd/podman/cp.go
+++ b/cmd/podman/cp.go
@@ -27,8 +27,11 @@ import (
var (
cpCommand cliconfig.CpValues
- cpDescription = "Copy files/folders between a container and the local filesystem"
- _cpCommand = &cobra.Command{
+ cpDescription = `Command copies the contents of SRC_PATH to the DEST_PATH.
+
+ You can copy from the container's file system to the local machine or the reverse, from the local filesystem to the container. If "-" is specified for either the SRC_PATH or DEST_PATH, you can also stream a tar archive from STDIN or to STDOUT. The CONTAINER can be a running or stopped container. The SRC_PATH or DEST_PATH can be a file or directory.
+`
+ _cpCommand = &cobra.Command{
Use: "cp [flags] SRC_PATH DEST_PATH",
Short: "Copy files/folders between a container and the local filesystem",
Long: cpDescription,
@@ -45,6 +48,8 @@ func init() {
cpCommand.Command = _cpCommand
flags := cpCommand.Flags()
flags.BoolVar(&cpCommand.Extract, "extract", false, "Extract the tar file into the destination directory.")
+ cpCommand.SetHelpTemplate(HelpTemplate())
+ cpCommand.SetUsageTemplate(UsageTemplate())
rootCmd.AddCommand(cpCommand.Command)
}
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index a7b9bbf31..8a5d0cf73 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -37,11 +37,9 @@ import (
var (
createCommand cliconfig.CreateValues
- createDescription = "Creates a new container from the given image or" +
- " storage and prepares it for running the specified command. The" +
- " container ID is then printed to stdout. You can then start it at" +
- " any time with the podman start <container_id> command. The container" +
- " will be created with the initial state 'created'."
+ createDescription = `Creates a new container from the given image or storage and prepares it for running the specified command.
+
+ The container ID is then printed to stdout. You can then start it at any time with the podman start <container_id> command. The container will be created with the initial state 'created'.`
_createCommand = &cobra.Command{
Use: "create [flags] IMAGE [COMMAND [ARG...]]",
Short: "Create but do not start a container",
@@ -64,6 +62,7 @@ var (
func init() {
createCommand.PodmanCommand.Command = _createCommand
+ createCommand.SetHelpTemplate(HelpTemplate())
createCommand.SetUsageTemplate(UsageTemplate())
getCreateFlags(&createCommand.PodmanCommand)
@@ -593,7 +592,7 @@ func parseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l
}
// LABEL VARIABLES
- labels, err := getAllLabels(c.StringSlice("label-file"), c.StringSlice("label"))
+ labels, err := getAllLabels(c.StringSlice("label-file"), c.StringArray("label"))
if err != nil {
return nil, errors.Wrapf(err, "unable to process labels")
}
@@ -894,7 +893,16 @@ func joinOrCreateRootlessUserNamespace(createConfig *cc.CreateConfig, runtime *l
}
return false, -1, errors.Errorf("dependency container %s is not running", ctr.ID())
}
- return rootless.JoinNS(uint(pid), 0)
+
+ data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
+ if err != nil {
+ return false, -1, errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
+ }
+ conmonPid, err := strconv.Atoi(string(data))
+ if err != nil {
+ return false, -1, errors.Wrapf(err, "cannot parse PID %q", data)
+ }
+ return rootless.JoinDirectUserAndMountNS(uint(conmonPid))
}
}
return rootless.BecomeRootInUserNS()
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index e232d7e66..bd3a985b7 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -34,8 +34,7 @@ func (so stdoutStruct) Out() error {
var (
diffCommand cliconfig.DiffValues
- diffDescription = fmt.Sprint(`Displays changes on a container or image's filesystem. The
- container or image will be compared to its parent layer`)
+ diffDescription = fmt.Sprint(`Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer.`)
_diffCommand = &cobra.Command{
Use: "diff [flags] CONTAINER | IMAGE",
@@ -54,6 +53,7 @@ var (
func init() {
diffCommand.Command = _diffCommand
+ diffCommand.SetHelpTemplate(HelpTemplate())
diffCommand.SetUsageTemplate(UsageTemplate())
flags := diffCommand.Flags()
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go
index 32a6e4bb5..e4cea1f5e 100644
--- a/cmd/podman/exec.go
+++ b/cmd/podman/exec.go
@@ -17,10 +17,7 @@ import (
var (
execCommand cliconfig.ExecValues
- execDescription = `
- podman exec
-
- Run a command in a running container
+ execDescription = `Execute the specified command inside a running container.
`
_execCommand = &cobra.Command{
Use: "exec [flags] CONTAINER [COMMAND [ARG...]]",
@@ -39,6 +36,7 @@ var (
func init() {
execCommand.Command = _execCommand
+ execCommand.SetHelpTemplate(HelpTemplate())
execCommand.SetUsageTemplate(UsageTemplate())
flags := execCommand.Flags()
flags.SetInterspersed(false)
@@ -108,16 +106,25 @@ func execCmd(c *cliconfig.ExecValues) error {
}
- pid, err := ctr.PID()
- if err != nil {
- return err
- }
- became, ret, err := rootless.JoinNS(uint(pid), c.PreserveFDs)
- if err != nil {
- return err
- }
- if became {
- os.Exit(ret)
+ if os.Geteuid() != 0 {
+ var became bool
+ var ret int
+
+ data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
+ if err != nil {
+ return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
+ }
+ conmonPid, err := strconv.Atoi(string(data))
+ if err != nil {
+ return errors.Wrapf(err, "cannot parse PID %q", data)
+ }
+ became, ret, err = rootless.JoinDirectUserAndMountNS(uint(conmonPid))
+ if err != nil {
+ return err
+ }
+ if became {
+ os.Exit(ret)
+ }
}
// ENVIRONMENT VARIABLES
diff --git a/cmd/podman/exists.go b/cmd/podman/exists.go
index 109831e74..8a2f78c88 100644
--- a/cmd/podman/exists.go
+++ b/cmd/podman/exists.go
@@ -16,21 +16,12 @@ var (
containerExistsCommand cliconfig.ContainerExistsValues
podExistsCommand cliconfig.PodExistsValues
- imageExistsDescription = `
- podman image exists
+ imageExistsDescription = `If the named image exists in local storage, podman image exists exits with 0, otherwise the exit code will be 1.`
- Check if an image exists in local storage
-`
- containerExistsDescription = `
- podman container exists
+ containerExistsDescription = `If the named container exists in local storage, podman container exists exits with 0, otherwise the exit code will be 1.`
- Check if a container exists in local storage
-`
- podExistsDescription = `
- podman pod exists
+ podExistsDescription = `If the named pod exists in local storage, podman pod exists exits with 0, otherwise the exit code will be 1.`
- Check if a pod exists in local storage
-`
_imageExistsCommand = &cobra.Command{
Use: "exists IMAGE",
Short: "Check if an image exists in local storage",
@@ -75,12 +66,15 @@ var (
func init() {
imageExistsCommand.Command = _imageExistsCommand
imageExistsCommand.DisableFlagsInUseLine = true
+ imageExistsCommand.SetHelpTemplate(HelpTemplate())
imageExistsCommand.SetUsageTemplate(UsageTemplate())
containerExistsCommand.Command = _containerExistsCommand
containerExistsCommand.DisableFlagsInUseLine = true
+ containerExistsCommand.SetHelpTemplate(HelpTemplate())
containerExistsCommand.SetUsageTemplate(UsageTemplate())
podExistsCommand.Command = _podExistsCommand
podExistsCommand.DisableFlagsInUseLine = true
+ podExistsCommand.SetHelpTemplate(HelpTemplate())
podExistsCommand.SetUsageTemplate(UsageTemplate())
}
diff --git a/cmd/podman/export.go b/cmd/podman/export.go
index d40c05019..4be2a3c86 100644
--- a/cmd/podman/export.go
+++ b/cmd/podman/export.go
@@ -32,6 +32,7 @@ var (
func init() {
exportCommand.Command = _exportCommand
+ exportCommand.SetHelpTemplate(HelpTemplate())
exportCommand.SetUsageTemplate(UsageTemplate())
flags := exportCommand.Flags()
flags.StringVarP(&exportCommand.Output, "output", "o", "/dev/stdout", "Write to a file, default is STDOUT")
diff --git a/cmd/podman/generate.go b/cmd/podman/generate.go
index 773d625ee..197fd26a6 100644
--- a/cmd/podman/generate.go
+++ b/cmd/podman/generate.go
@@ -12,6 +12,7 @@ var (
Use: "generate",
Short: "Generated structured data",
Long: generateDescription,
+ RunE: commandRunE(),
}
)
diff --git a/cmd/podman/generate_kube.go b/cmd/podman/generate_kube.go
index fa2872b77..e3db14af3 100644
--- a/cmd/podman/generate_kube.go
+++ b/cmd/podman/generate_kube.go
@@ -15,10 +15,12 @@ import (
var (
containerKubeCommand cliconfig.GenerateKubeValues
- containerKubeDescription = "Generate Kubernetes Pod YAML"
- _containerKubeCommand = &cobra.Command{
+ containerKubeDescription = `Command generates Kubernetes Pod YAML (v1 specification) from a podman container or pod.
+
+ Whether the input is for a container or pod, Podman will always generate the specification as a Pod. The input may be in the form of a pod or container name or ID.`
+ _containerKubeCommand = &cobra.Command{
Use: "kube [flags] CONTAINER | POD",
- Short: "Generate Kubernetes pod YAML for a container or pod",
+ Short: "Generate Kubernetes pod YAML from a container or pod",
Long: containerKubeDescription,
RunE: func(cmd *cobra.Command, args []string) error {
containerKubeCommand.InputArgs = args
@@ -33,6 +35,7 @@ var (
func init() {
containerKubeCommand.Command = _containerKubeCommand
+ containerKubeCommand.SetHelpTemplate(HelpTemplate())
containerKubeCommand.SetUsageTemplate(UsageTemplate())
flags := containerKubeCommand.Flags()
flags.BoolVarP(&containerKubeCommand.Service, "service", "s", false, "Generate YAML for kubernetes service object")
diff --git a/cmd/podman/healthcheck.go b/cmd/podman/healthcheck.go
index e7cc125cc..48d6b6bbf 100644
--- a/cmd/podman/healthcheck.go
+++ b/cmd/podman/healthcheck.go
@@ -11,6 +11,7 @@ var healthcheckCommand = cliconfig.PodmanCommand{
Use: "healthcheck",
Short: "Manage Healthcheck",
Long: healthcheckDescription,
+ RunE: commandRunE(),
},
}
diff --git a/cmd/podman/healthcheck_run.go b/cmd/podman/healthcheck_run.go
index a91f87146..d92b2ac01 100644
--- a/cmd/podman/healthcheck_run.go
+++ b/cmd/podman/healthcheck_run.go
@@ -13,7 +13,7 @@ var (
healthcheckRunCommand cliconfig.HealthCheckValues
healthcheckRunDescription = "run the health check of a container"
_healthcheckrunCommand = &cobra.Command{
- Use: "run CONTAINER",
+ Use: "run [flags] CONTAINER",
Short: "run the health check of a container",
Long: healthcheckRunDescription,
Example: `podman healthcheck run mywebapp`,
diff --git a/cmd/podman/history.go b/cmd/podman/history.go
index 533ee91cb..f6cfe91b6 100644
--- a/cmd/podman/history.go
+++ b/cmd/podman/history.go
@@ -37,8 +37,9 @@ type historyOptions struct {
var (
historyCommand cliconfig.HistoryValues
- historyDescription = "Displays the history of an image. The information can be printed out in an easy to read, " +
- "or user specified format, and can be truncated."
+ historyDescription = `Displays the history of an image.
+
+ The information can be printed out in an easy to read, or user specified format, and can be truncated.`
_historyCommand = &cobra.Command{
Use: "history [flags] IMAGE",
Short: "Show history of a specified image",
@@ -53,6 +54,7 @@ var (
func init() {
historyCommand.Command = _historyCommand
+ historyCommand.SetHelpTemplate(HelpTemplate())
historyCommand.SetUsageTemplate(UsageTemplate())
flags := historyCommand.Flags()
flags.StringVar(&historyCommand.Format, "format", "", "Change the output to JSON or a Go template")
diff --git a/cmd/podman/image.go b/cmd/podman/image.go
index 57be7fe14..52bac6ecb 100644
--- a/cmd/podman/image.go
+++ b/cmd/podman/image.go
@@ -14,6 +14,7 @@ var (
Use: "image",
Short: "Manage images",
Long: imageDescription,
+ RunE: commandRunE(),
},
}
imagesSubCommand cliconfig.ImagesValues
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index 80b12b0eb..f92e5d44d 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -86,7 +86,7 @@ func (a imagesSortedSize) Less(i, j int) bool {
var (
imagesCommand cliconfig.ImagesValues
- imagesDescription = "lists locally stored images."
+ imagesDescription = "Lists images previously pulled to the system or created on the system."
_imagesCommand = cobra.Command{
Use: "images [flags] [IMAGE]",
@@ -104,6 +104,7 @@ var (
)
func imagesInit(command *cliconfig.ImagesValues) {
+ command.SetHelpTemplate(HelpTemplate())
command.SetUsageTemplate(UsageTemplate())
flags := command.Flags()
diff --git a/cmd/podman/images_prune.go b/cmd/podman/images_prune.go
index 427374f68..b6f335fb3 100644
--- a/cmd/podman/images_prune.go
+++ b/cmd/podman/images_prune.go
@@ -11,11 +11,9 @@ import (
var (
pruneImagesCommand cliconfig.PruneImagesValues
- pruneImagesDescription = `
- podman image prune
+ pruneImagesDescription = `Removes all unnamed images from local storage.
- Removes all unnamed images from local storage
-`
+ If an image is not being used by a container, it will be removed from the system.`
_pruneImagesCommand = &cobra.Command{
Use: "prune",
Args: noSubArgs,
@@ -31,6 +29,7 @@ var (
func init() {
pruneImagesCommand.Command = _pruneImagesCommand
+ pruneImagesCommand.SetHelpTemplate(HelpTemplate())
pruneImagesCommand.SetUsageTemplate(UsageTemplate())
flags := pruneImagesCommand.Flags()
flags.BoolVarP(&pruneImagesCommand.All, "all", "a", false, "Remove all unused images, not just dangling ones")
diff --git a/cmd/podman/import.go b/cmd/podman/import.go
index ddf1bd802..c3351ab1b 100644
--- a/cmd/podman/import.go
+++ b/cmd/podman/import.go
@@ -13,9 +13,9 @@ var (
importCommand cliconfig.ImportValues
importDescription = `Create a container image from the contents of the specified tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz).
- Note remote tar balls can be specified, via web address.
- Optionally tag the image. You can specify the instructions using the --change option.
- `
+
+ Note remote tar balls can be specified, via web address.
+ Optionally tag the image. You can specify the instructions using the --change option.`
_importCommand = &cobra.Command{
Use: "import [flags] PATH [REFERENCE]",
Short: "Import a tarball to create a filesystem image",
@@ -33,6 +33,7 @@ var (
func init() {
importCommand.Command = _importCommand
+ importCommand.SetHelpTemplate(HelpTemplate())
importCommand.SetUsageTemplate(UsageTemplate())
flags := importCommand.Flags()
flags.StringSliceVarP(&importCommand.Change, "change", "c", []string{}, "Apply the following possible instructions to the created image (default []): CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR")
diff --git a/cmd/podman/info.go b/cmd/podman/info.go
index e87f4e151..de20eb009 100644
--- a/cmd/podman/info.go
+++ b/cmd/podman/info.go
@@ -16,12 +16,15 @@ import (
var (
infoCommand cliconfig.InfoValues
- infoDescription = "Display podman system information"
- _infoCommand = &cobra.Command{
+ infoDescription = `Display information pertaining to the host, current storage stats, and build of podman.
+
+ Useful for the user and when reporting issues.
+`
+ _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.`,
+ Short: "Display podman system information",
RunE: func(cmd *cobra.Command, args []string) error {
infoCommand.InputArgs = args
infoCommand.GlobalFlags = MainGlobalOpts
@@ -33,6 +36,7 @@ var (
func init() {
infoCommand.Command = _infoCommand
+ infoCommand.SetHelpTemplate(HelpTemplate())
infoCommand.SetUsageTemplate(UsageTemplate())
flags := infoCommand.Flags()
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index 1c93a03e1..0af96088f 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -24,8 +24,10 @@ const (
var (
inspectCommand cliconfig.InspectValues
- inspectDescription = "This displays the low-level information on containers and images identified by name or ID. By default, this will render all results in a JSON array. If the container and image have the same name, this will return container JSON for unspecified type."
- _inspectCommand = &cobra.Command{
+ inspectDescription = `This displays the low-level information on containers and images identified by name or ID.
+
+ If given a name that matches both a container and an image, this command inspects the container. By default, this will render all results in a JSON array.`
+ _inspectCommand = &cobra.Command{
Use: "inspect [flags] CONTAINER | IMAGE",
Short: "Display the configuration of a container or image",
Long: inspectDescription,
@@ -42,6 +44,7 @@ var (
func init() {
inspectCommand.Command = _inspectCommand
+ inspectCommand.SetHelpTemplate(HelpTemplate())
inspectCommand.SetUsageTemplate(UsageTemplate())
flags := inspectCommand.Flags()
flags.StringVarP(&inspectCommand.TypeObject, "type", "t", inspectAll, "Return JSON for specified type, (e.g image, container or task)")
diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go
index 82a257e23..2c1e13eaf 100644
--- a/cmd/podman/kill.go
+++ b/cmd/podman/kill.go
@@ -38,6 +38,7 @@ var (
func init() {
killCommand.Command = _killCommand
+ killCommand.SetHelpTemplate(HelpTemplate())
killCommand.SetUsageTemplate(UsageTemplate())
flags := killCommand.Flags()
diff --git a/cmd/podman/load.go b/cmd/podman/load.go
index 5a0742aba..3c71e2f61 100644
--- a/cmd/podman/load.go
+++ b/cmd/podman/load.go
@@ -30,6 +30,7 @@ var (
func init() {
loadCommand.Command = _loadCommand
+ loadCommand.SetHelpTemplate(HelpTemplate())
loadCommand.SetUsageTemplate(UsageTemplate())
flags := loadCommand.Flags()
flags.StringVarP(&loadCommand.Input, "input", "i", "/dev/stdin", "Read from archive file, default is STDIN")
diff --git a/cmd/podman/login.go b/cmd/podman/login.go
index 48d4eefbc..43a7d246e 100644
--- a/cmd/podman/login.go
+++ b/cmd/podman/login.go
@@ -37,6 +37,7 @@ var (
func init() {
loginCommand.Command = _loginCommand
+ loginCommand.SetHelpTemplate(HelpTemplate())
loginCommand.SetUsageTemplate(UsageTemplate())
flags := loginCommand.Flags()
diff --git a/cmd/podman/logout.go b/cmd/podman/logout.go
index 2a540ceba..268e6b44c 100644
--- a/cmd/podman/logout.go
+++ b/cmd/podman/logout.go
@@ -30,6 +30,7 @@ var (
func init() {
logoutCommand.Command = _logoutCommand
+ logoutCommand.SetHelpTemplate(HelpTemplate())
logoutCommand.SetUsageTemplate(UsageTemplate())
flags := logoutCommand.Flags()
flags.BoolVarP(&logoutCommand.All, "all", "a", false, "Remove the cached credentials for all registries in the auth file")
diff --git a/cmd/podman/logs.go b/cmd/podman/logs.go
index a02010eda..9df7281fc 100644
--- a/cmd/podman/logs.go
+++ b/cmd/podman/logs.go
@@ -15,8 +15,10 @@ import (
var (
logsCommand cliconfig.LogsValues
- logsDescription = "The podman logs command batch-retrieves whatever logs are present for a container at the time of execution. This does not guarantee execution" +
- "order when combined with podman run (i.e. your run may not have generated any logs at the time you execute podman logs"
+ logsDescription = `Retrieves logs for a container.
+
+ This does not guarantee execution order when combined with podman run (i.e. your run may not have generated any logs at the time you execute podman logs.
+`
_logsCommand = &cobra.Command{
Use: "logs [flags] CONTAINER",
Short: "Fetch the logs of a container",
@@ -34,6 +36,7 @@ var (
func init() {
logsCommand.Command = _logsCommand
+ logsCommand.SetHelpTemplate(HelpTemplate())
logsCommand.SetUsageTemplate(UsageTemplate())
flags := logsCommand.Flags()
flags.BoolVar(&logsCommand.Details, "details", false, "Show extra details provided to the logs")
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 97ffa8930..7d4b650a9 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -82,9 +82,7 @@ var cmdsNotRequiringRootless = map[*cobra.Command]bool{
var rootCmd = &cobra.Command{
Use: "podman",
Long: "manage pods and images",
- RunE: func(cmd *cobra.Command, args []string) error {
- return cmd.Help()
- },
+ RunE: commandRunE(),
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return before(cmd, args)
},
diff --git a/cmd/podman/mount.go b/cmd/podman/mount.go
index 3a3432194..c5b7e2404 100644
--- a/cmd/podman/mount.go
+++ b/cmd/podman/mount.go
@@ -17,12 +17,11 @@ import (
var (
mountCommand cliconfig.MountValues
- mountDescription = `
- podman mount
- Lists all mounted containers mount points
+ mountDescription = `podman mount
+ Lists all mounted containers mount points if no container is specified
- podman mount CONTAINER-NAME-OR-ID
- Mounts the specified container and outputs the mountpoint
+ podman mount CONTAINER-NAME-OR-ID
+ Mounts the specified container and outputs the mountpoint
`
_mountCommand = &cobra.Command{
@@ -42,6 +41,7 @@ var (
func init() {
mountCommand.Command = _mountCommand
+ mountCommand.SetHelpTemplate(HelpTemplate())
mountCommand.SetUsageTemplate(UsageTemplate())
flags := mountCommand.Flags()
flags.BoolVarP(&mountCommand.All, "all", "a", false, "Mount all containers")
diff --git a/cmd/podman/pause.go b/cmd/podman/pause.go
index 3a5b80359..fa4648128 100644
--- a/cmd/podman/pause.go
+++ b/cmd/podman/pause.go
@@ -14,12 +14,8 @@ import (
var (
pauseCommand cliconfig.PauseValues
- pauseDescription = `
- podman pause
-
- Pauses one or more running containers. The container name or ID can be used.
-`
- _pauseCommand = &cobra.Command{
+ pauseDescription = `Pauses one or more running containers. The container name or ID can be used.`
+ _pauseCommand = &cobra.Command{
Use: "pause [flags] CONTAINER [CONTAINER...]",
Short: "Pause all the processes in one or more containers",
Long: pauseDescription,
@@ -36,6 +32,7 @@ var (
func init() {
pauseCommand.Command = _pauseCommand
+ pauseCommand.SetHelpTemplate(HelpTemplate())
pauseCommand.SetUsageTemplate(UsageTemplate())
flags := pauseCommand.Flags()
flags.BoolVarP(&pauseCommand.All, "all", "a", false, "Pause all running containers")
diff --git a/cmd/podman/play.go b/cmd/podman/play.go
index 495a1f170..95eae653e 100644
--- a/cmd/podman/play.go
+++ b/cmd/podman/play.go
@@ -12,11 +12,13 @@ var (
Use: "play",
Short: "Play a pod",
Long: playDescription,
+ RunE: commandRunE(),
}
)
func init() {
playCommand.Command = _playCommand
+ playCommand.SetHelpTemplate(HelpTemplate())
playCommand.SetUsageTemplate(UsageTemplate())
playCommand.AddCommand(getPlaySubCommands()...)
}
diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go
index 1910b68b5..980f3a09c 100644
--- a/cmd/podman/play_kube.go
+++ b/cmd/podman/play_kube.go
@@ -32,8 +32,10 @@ const (
var (
playKubeCommand cliconfig.KubePlayValues
- playKubeDescription = "Play a Pod and its containers based on a Kubrernetes YAML"
- _playKubeCommand = &cobra.Command{
+ playKubeDescription = `Command reads in a structured file of Kubernetes YAML.
+
+ It creates the pod and containers described in the YAML. The containers within the pod are then started and the ID of the new Pod is output.`
+ _playKubeCommand = &cobra.Command{
Use: "kube [flags] KUBEFILE",
Short: "Play a pod based on Kubernetes YAML",
Long: playKubeDescription,
@@ -49,6 +51,7 @@ var (
func init() {
playKubeCommand.Command = _playKubeCommand
+ playKubeCommand.SetHelpTemplate(HelpTemplate())
playKubeCommand.SetUsageTemplate(UsageTemplate())
flags := playKubeCommand.Flags()
flags.StringVar(&playKubeCommand.Authfile, "authfile", "", "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override")
diff --git a/cmd/podman/pod.go b/cmd/podman/pod.go
index 7067f2429..2d9bca21d 100644
--- a/cmd/podman/pod.go
+++ b/cmd/podman/pod.go
@@ -6,15 +6,14 @@ import (
)
var (
- podDescription = `Manage container pods.
-
-Pods are a group of one or more containers sharing the same network, pid and ipc namespaces.`
+ podDescription = `Pods are a group of one or more containers sharing the same network, pid and ipc namespaces.`
)
var podCommand = cliconfig.PodmanCommand{
Command: &cobra.Command{
Use: "pod",
Short: "Manage pods",
Long: podDescription,
+ RunE: commandRunE(),
},
}
@@ -37,5 +36,6 @@ var podSubCommands = []*cobra.Command{
func init() {
podCommand.AddCommand(podSubCommands...)
+ podCommand.SetHelpTemplate(HelpTemplate())
podCommand.SetUsageTemplate(UsageTemplate())
}
diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go
index 43c211b2c..d2b7da597 100644
--- a/cmd/podman/pod_create.go
+++ b/cmd/podman/pod_create.go
@@ -17,10 +17,9 @@ var (
DefaultKernelNamespaces = "cgroup,ipc,net,uts"
podCreateCommand cliconfig.PodCreateValues
- podCreateDescription = "Creates a new empty pod. The pod ID is then" +
- " printed to stdout. You can then start it at any time with the" +
- " podman pod start <pod_id> command. The pod will be created with the" +
- " initial state 'created'."
+ podCreateDescription = `After creating the pod, the pod ID is printed to stdout.
+
+ You can then start it at any time with the podman pod start <pod_id> command. The pod will be created with the initial state 'created'.`
_podCreateCommand = &cobra.Command{
Use: "create",
@@ -37,6 +36,7 @@ var (
func init() {
podCreateCommand.Command = _podCreateCommand
+ podCreateCommand.SetHelpTemplate(HelpTemplate())
podCreateCommand.SetUsageTemplate(UsageTemplate())
flags := podCreateCommand.Flags()
flags.SetInterspersed(false)
diff --git a/cmd/podman/pod_inspect.go b/cmd/podman/pod_inspect.go
index 8b2747af0..79ffe2e6f 100644
--- a/cmd/podman/pod_inspect.go
+++ b/cmd/podman/pod_inspect.go
@@ -12,8 +12,11 @@ import (
var (
podInspectCommand cliconfig.PodInspectValues
- podInspectDescription = "Display the configuration for a pod by name or id"
- _podInspectCommand = &cobra.Command{
+ podInspectDescription = `Display the configuration for a pod by name or id
+
+ By default, this will render all results in a JSON array. If the container and image have the same name, this command returns the container JSON.`
+
+ _podInspectCommand = &cobra.Command{
Use: "inspect [flags] POD",
Short: "Displays a pod configuration",
Long: podInspectDescription,
@@ -28,6 +31,7 @@ var (
func init() {
podInspectCommand.Command = _podInspectCommand
+ podInspectCommand.SetHelpTemplate(HelpTemplate())
podInspectCommand.SetUsageTemplate(UsageTemplate())
flags := podInspectCommand.Flags()
flags.BoolVarP(&podInspectCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
diff --git a/cmd/podman/pod_kill.go b/cmd/podman/pod_kill.go
index 70d86d186..ebd7db762 100644
--- a/cmd/podman/pod_kill.go
+++ b/cmd/podman/pod_kill.go
@@ -14,8 +14,10 @@ import (
var (
podKillCommand cliconfig.PodKillValues
- podKillDescription = "The main process of each container inside the specified pod will be sent SIGKILL, or any signal specified with option --signal."
- _podKillCommand = &cobra.Command{
+ podKillDescription = `Signals are sent to the main process of each container inside the specified pod.
+
+ The default signal is SIGKILL, or any signal specified with option --signal.`
+ _podKillCommand = &cobra.Command{
Use: "kill [flags] POD [POD...]",
Short: "Send the specified signal or SIGKILL to containers in pod",
Long: podKillDescription,
@@ -35,6 +37,7 @@ var (
func init() {
podKillCommand.Command = _podKillCommand
+ podKillCommand.SetHelpTemplate(HelpTemplate())
podKillCommand.SetUsageTemplate(UsageTemplate())
flags := podKillCommand.Flags()
flags.BoolVarP(&podKillCommand.All, "all", "a", false, "Kill all containers in all pods")
diff --git a/cmd/podman/pod_pause.go b/cmd/podman/pod_pause.go
index f7c90dbbe..ff29e0e1d 100644
--- a/cmd/podman/pod_pause.go
+++ b/cmd/podman/pod_pause.go
@@ -11,8 +11,10 @@ import (
var (
podPauseCommand cliconfig.PodPauseValues
- podPauseDescription = `Pauses one or more pods. The pod name or ID can be used.`
- _podPauseCommand = &cobra.Command{
+ podPauseDescription = `The pod name or ID can be used.
+
+ All running containers within each specified pod will then be paused.`
+ _podPauseCommand = &cobra.Command{
Use: "pause [flags] POD [POD...]",
Short: "Pause one or more pods",
Long: podPauseDescription,
@@ -32,6 +34,7 @@ var (
func init() {
podPauseCommand.Command = _podPauseCommand
+ podPauseCommand.SetHelpTemplate(HelpTemplate())
podPauseCommand.SetUsageTemplate(UsageTemplate())
flags := podPauseCommand.Flags()
flags.BoolVarP(&podPauseCommand.All, "all", "a", false, "Pause all running pods")
diff --git a/cmd/podman/pod_ps.go b/cmd/podman/pod_ps.go
index 8e48740e6..e30a03005 100644
--- a/cmd/podman/pod_ps.go
+++ b/cmd/podman/pod_ps.go
@@ -134,6 +134,7 @@ var (
func init() {
podPsCommand.Command = _podPsCommand
+ podPsCommand.SetHelpTemplate(HelpTemplate())
podPsCommand.SetUsageTemplate(UsageTemplate())
flags := podPsCommand.Flags()
flags.BoolVar(&podPsCommand.CtrNames, "ctr-names", false, "Display the container names")
diff --git a/cmd/podman/pod_restart.go b/cmd/podman/pod_restart.go
index ba77e1409..0765b98db 100644
--- a/cmd/podman/pod_restart.go
+++ b/cmd/podman/pod_restart.go
@@ -12,8 +12,10 @@ import (
var (
podRestartCommand cliconfig.PodRestartValues
- podRestartDescription = `Restarts one or more pods. The pod ID or name can be used.`
- _podRestartCommand = &cobra.Command{
+ podRestartDescription = `The pod ID or name can be used.
+
+ All of the containers within each of the specified pods will be restarted. If a container in a pod is not currently running it will be started.`
+ _podRestartCommand = &cobra.Command{
Use: "restart [flags] POD [POD...]",
Short: "Restart one or more pods",
Long: podRestartDescription,
@@ -33,6 +35,7 @@ var (
func init() {
podRestartCommand.Command = _podRestartCommand
+ podRestartCommand.SetHelpTemplate(HelpTemplate())
podRestartCommand.SetUsageTemplate(UsageTemplate())
flags := podRestartCommand.Flags()
flags.BoolVarP(&podRestartCommand.All, "all", "a", false, "Restart all running pods")
diff --git a/cmd/podman/pod_rm.go b/cmd/podman/pod_rm.go
index fa452b061..a40992818 100644
--- a/cmd/podman/pod_rm.go
+++ b/cmd/podman/pod_rm.go
@@ -12,11 +12,9 @@ import (
var (
podRmCommand cliconfig.PodRmValues
- podRmDescription = fmt.Sprintf(`
-podman rm will remove one or more pods from the host. The pod name or ID can
-be used. A pod with containers will not be removed without --force.
-If --force is specified, all containers will be stopped, then removed.
-`)
+ podRmDescription = fmt.Sprintf(`podman rm will remove one or more pods from the host.
+
+ The pod name or ID can be used. A pod with containers will not be removed without --force. If --force is specified, all containers will be stopped, then removed.`)
_podRmCommand = &cobra.Command{
Use: "rm [flags] POD [POD...]",
Short: "Remove one or more pods",
@@ -37,6 +35,7 @@ If --force is specified, all containers will be stopped, then removed.
func init() {
podRmCommand.Command = _podRmCommand
+ podRmCommand.SetHelpTemplate(HelpTemplate())
podRmCommand.SetUsageTemplate(UsageTemplate())
flags := podRmCommand.Flags()
flags.BoolVarP(&podRmCommand.All, "all", "a", false, "Remove all running pods")
diff --git a/cmd/podman/pod_start.go b/cmd/podman/pod_start.go
index ca8ad08cf..949af80d8 100644
--- a/cmd/podman/pod_start.go
+++ b/cmd/podman/pod_start.go
@@ -12,11 +12,9 @@ import (
var (
podStartCommand cliconfig.PodStartValues
- podStartDescription = `
- podman pod start
+ podStartDescription = `The pod name or ID can be used.
- Starts one or more pods. The pod name or ID can be used.
-`
+ All containers defined in the pod will be started.`
_podStartCommand = &cobra.Command{
Use: "start [flags] POD [POD...]",
Short: "Start one or more pods",
@@ -37,6 +35,7 @@ var (
func init() {
podStartCommand.Command = _podStartCommand
+ podStartCommand.SetHelpTemplate(HelpTemplate())
podStartCommand.SetUsageTemplate(UsageTemplate())
flags := podStartCommand.Flags()
flags.BoolVarP(&podStartCommand.All, "all", "a", false, "Start all pods")
diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go
index 2761ce9cc..7dbd84525 100644
--- a/cmd/podman/pod_stats.go
+++ b/cmd/podman/pod_stats.go
@@ -22,10 +22,11 @@ import (
var (
podStatsCommand cliconfig.PodStatsValues
- podStatsDescription = "Display a live stream of resource usage statistics for the containers in or more pods"
- _podStatsCommand = &cobra.Command{
+ podStatsDescription = `For each specified pod this command will display percentage of CPU, memory, network I/O, block I/O and PIDs for containers in one the pods.`
+
+ _podStatsCommand = &cobra.Command{
Use: "stats [flags] POD [POD...]",
- Short: "Display percentage of CPU, memory, network I/O, block I/O and PIDs for containers in one or more pods",
+ Short: "Display a live stream of resource usage statistics for the containers in one or more pods",
Long: podStatsDescription,
RunE: func(cmd *cobra.Command, args []string) error {
podStatsCommand.InputArgs = args
@@ -40,6 +41,7 @@ var (
func init() {
podStatsCommand.Command = _podStatsCommand
+ podStatsCommand.SetHelpTemplate(HelpTemplate())
podStatsCommand.SetUsageTemplate(UsageTemplate())
flags := podStatsCommand.Flags()
flags.BoolVarP(&podStatsCommand.All, "all", "a", false, "Provide stats for all running pods")
diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go
index 951cf082a..f1b0ac51f 100644
--- a/cmd/podman/pod_stop.go
+++ b/cmd/podman/pod_stop.go
@@ -12,11 +12,9 @@ import (
var (
podStopCommand cliconfig.PodStopValues
- podStopDescription = `
- podman pod stop
+ podStopDescription = `The pod name or ID can be used.
- Stops one or more running pods. The pod name or ID can be used.
-`
+ This command will stop all running containers in each of the specified pods.`
_podStopCommand = &cobra.Command{
Use: "stop [flags] POD [POD...]",
@@ -38,6 +36,7 @@ var (
func init() {
podStopCommand.Command = _podStopCommand
+ podStopCommand.SetHelpTemplate(HelpTemplate())
podStopCommand.SetUsageTemplate(UsageTemplate())
flags := podStopCommand.Flags()
flags.BoolVarP(&podStopCommand.All, "all", "a", false, "Stop all running pods")
diff --git a/cmd/podman/pod_top.go b/cmd/podman/pod_top.go
index c5383d376..c9a6d8822 100644
--- a/cmd/podman/pod_top.go
+++ b/cmd/podman/pod_top.go
@@ -16,12 +16,10 @@ import (
var (
podTopCommand cliconfig.PodTopValues
- podTopDescription = fmt.Sprintf(`Display the running processes containers in a pod. Specify format descriptors
-to alter the output. You may run "podman pod top -l pid pcpu seccomp" to print
-the process ID, the CPU percentage and the seccomp mode of each process of
-the latest pod.
-%s
-`, getDescriptorString())
+ podTopDescription = fmt.Sprintf(`Specify format descriptors to alter the output.
+
+ You may run "podman pod top -l pid pcpu seccomp" to print the process ID, the CPU percentage and the seccomp mode of each process of the latest pod.
+%s`, getDescriptorString())
_podTopCommand = &cobra.Command{
Use: "top [flags] CONTAINER [FORMAT-DESCRIPTORS]",
@@ -40,6 +38,7 @@ the latest pod.
func init() {
podTopCommand.Command = _podTopCommand
+ podTopCommand.SetHelpTemplate(HelpTemplate())
podTopCommand.SetUsageTemplate(UsageTemplate())
flags := podTopCommand.Flags()
flags.BoolVarP(&podTopCommand.Latest, "latest,", "l", false, "Act on the latest pod podman is aware of")
diff --git a/cmd/podman/pod_unpause.go b/cmd/podman/pod_unpause.go
index 6b142d573..0623c6abb 100644
--- a/cmd/podman/pod_unpause.go
+++ b/cmd/podman/pod_unpause.go
@@ -12,8 +12,10 @@ import (
var (
podUnpauseCommand cliconfig.PodUnpauseValues
- podUnpauseDescription = `Unpauses one or more pods. The pod name or ID can be used.`
- _podUnpauseCommand = &cobra.Command{
+ podUnpauseDescription = `The podman unpause command will unpause all "paused" containers assigned to the pod.
+
+ The pod name or ID can be used.`
+ _podUnpauseCommand = &cobra.Command{
Use: "unpause [flags] POD [POD...]",
Short: "Unpause one or more pods",
Long: podUnpauseDescription,
@@ -33,6 +35,7 @@ var (
func init() {
podUnpauseCommand.Command = _podUnpauseCommand
+ podUnpauseCommand.SetHelpTemplate(HelpTemplate())
podUnpauseCommand.SetUsageTemplate(UsageTemplate())
flags := podUnpauseCommand.Flags()
flags.BoolVarP(&podUnpauseCommand.All, "all", "a", false, "Unpause all running pods")
diff --git a/cmd/podman/port.go b/cmd/podman/port.go
index ffb5749fb..b5a4d3eec 100644
--- a/cmd/podman/port.go
+++ b/cmd/podman/port.go
@@ -14,10 +14,7 @@ import (
var (
portCommand cliconfig.PortValues
- portDescription = `
- podman port
-
- List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT
+ portDescription = `List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT
`
_portCommand = &cobra.Command{
Use: "port [flags] CONTAINER",
@@ -39,6 +36,7 @@ var (
func init() {
portCommand.Command = _portCommand
+ portCommand.SetHelpTemplate(HelpTemplate())
portCommand.SetUsageTemplate(UsageTemplate())
flags := portCommand.Flags()
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 0dedd850d..6caac2406 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -174,6 +174,7 @@ var (
)
func psInit(command *cliconfig.PsValues) {
+ command.SetHelpTemplate(HelpTemplate())
command.SetUsageTemplate(UsageTemplate())
flags := command.Flags()
flags.BoolVarP(&command.All, "all", "a", false, "Show all the containers, default is only running containers")
@@ -418,7 +419,7 @@ func generateContainerFilterFuncs(filter, filterValue string, runtime *libpod.Ru
return false
}, nil
case "status":
- if !util.StringInSlice(filterValue, []string{"created", "restarting", "running", "paused", "exited", "unknown"}) {
+ if !util.StringInSlice(filterValue, []string{"created", "running", "paused", "exited", "unknown"}) {
return nil, errors.Errorf("%s is not a valid status", filterValue)
}
return func(c *libpod.Container) bool {
@@ -429,6 +430,8 @@ func generateContainerFilterFuncs(filter, filterValue string, runtime *libpod.Ru
state := status.String()
if status == libpod.ContainerStateConfigured {
state = "created"
+ } else if status == libpod.ContainerStateStopped {
+ state = "exited"
}
return state == filterValue
}, nil
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go
index 5f4658fe1..7986d5530 100644
--- a/cmd/podman/pull.go
+++ b/cmd/podman/pull.go
@@ -23,11 +23,9 @@ import (
var (
pullCommand cliconfig.PullValues
- pullDescription = `
-Pulls an image from a registry and stores it locally.
-An image can be pulled using its tag or digest. If a tag is not
-specified, the image with the 'latest' tag (if it exists) is pulled
-`
+ pullDescription = `Pulls an image from a registry and stores it locally.
+
+ An image can be pulled using its tag or digest. If a tag is not specified, the image with the 'latest' tag (if it exists) is pulled.`
_pullCommand = &cobra.Command{
Use: "pull [flags] IMAGE-PATH",
Short: "Pull an image from a registry",
@@ -45,6 +43,7 @@ specified, the image with the 'latest' tag (if it exists) is pulled
func init() {
pullCommand.Command = _pullCommand
+ pullCommand.SetHelpTemplate(HelpTemplate())
pullCommand.SetUsageTemplate(UsageTemplate())
flags := pullCommand.Flags()
flags.BoolVar(&pullCommand.AllTags, "all-tags", false, "All tagged images inthe repository will be pulled")
diff --git a/cmd/podman/push.go b/cmd/podman/push.go
index bc909cb5e..afc385527 100644
--- a/cmd/podman/push.go
+++ b/cmd/podman/push.go
@@ -20,10 +20,9 @@ import (
var (
pushCommand cliconfig.PushValues
- pushDescription = fmt.Sprintf(`
- Pushes an image to a specified location.
- The Image "DESTINATION" uses a "transport":"details" format.
- See podman-push(1) section "DESTINATION" for the expected format`)
+ pushDescription = fmt.Sprintf(`Pushes an image to a specified location.
+
+ The Image "DESTINATION" uses a "transport":"details" format. See podman-push(1) section "DESTINATION" for the expected format.`)
_pushCommand = &cobra.Command{
Use: "push [flags] IMAGE REGISTRY",
@@ -42,6 +41,7 @@ var (
func init() {
pushCommand.Command = _pushCommand
+ pushCommand.SetHelpTemplate(HelpTemplate())
pushCommand.SetUsageTemplate(UsageTemplate())
flags := pushCommand.Flags()
flags.MarkHidden("signature-policy")
diff --git a/cmd/podman/refresh.go b/cmd/podman/refresh.go
index 1e4a31a52..ed2e173ab 100644
--- a/cmd/podman/refresh.go
+++ b/cmd/podman/refresh.go
@@ -12,8 +12,11 @@ import (
var (
refreshCommand cliconfig.RefreshValues
- 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{
+ refreshDescription = `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",
@@ -29,6 +32,7 @@ var (
func init() {
_refreshCommand.Hidden = true
refreshCommand.Command = _refreshCommand
+ refreshCommand.SetHelpTemplate(HelpTemplate())
refreshCommand.SetUsageTemplate(UsageTemplate())
}
diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go
index 5aa12070e..341cbf978 100644
--- a/cmd/podman/restart.go
+++ b/cmd/podman/restart.go
@@ -16,8 +16,10 @@ import (
var (
restartCommand cliconfig.RestartValues
- restartDescription = `Restarts one or more running containers. The container ID or name can be used. A timeout before forcibly stopping can be set, but defaults to 10 seconds`
- _restartCommand = &cobra.Command{
+ restartDescription = `Restarts one or more running containers. The container ID or name can be used.
+
+ A timeout before forcibly stopping can be set, but defaults to 10 seconds.`
+ _restartCommand = &cobra.Command{
Use: "restart [flags] CONTAINER [CONTAINER...]",
Short: "Restart one or more containers",
Long: restartDescription,
@@ -37,6 +39,7 @@ var (
func init() {
restartCommand.Command = _restartCommand
+ restartCommand.SetHelpTemplate(HelpTemplate())
restartCommand.SetUsageTemplate(UsageTemplate())
flags := restartCommand.Flags()
flags.BoolVarP(&restartCommand.All, "all", "a", false, "Restart all non-running containers")
diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go
index 73d355734..0f6828432 100644
--- a/cmd/podman/restore.go
+++ b/cmd/podman/restore.go
@@ -40,6 +40,7 @@ var (
func init() {
restoreCommand.Command = _restoreCommand
+ restoreCommand.SetHelpTemplate(HelpTemplate())
restoreCommand.SetUsageTemplate(UsageTemplate())
flags := restoreCommand.Flags()
flags.BoolVarP(&restoreCommand.All, "all", "a", false, "Restore all checkpointed containers")
diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go
index d23f8228c..4230bb396 100644
--- a/cmd/podman/rm.go
+++ b/cmd/podman/rm.go
@@ -15,11 +15,9 @@ import (
var (
rmCommand cliconfig.RmValues
- rmDescription = fmt.Sprintf(`
-Podman rm will remove one or more containers from the host.
-The container name or ID can be used. This does not remove images.
-Running containers will not be removed without the -f option.
-`)
+ rmDescription = fmt.Sprintf(`Removes one or more containers from the host. The container name or ID can be used.
+
+ Command does not remove images. Running containers will not be removed without the -f option.`)
_rmCommand = &cobra.Command{
Use: "rm [flags] CONTAINER [CONTAINER...]",
Short: "Remove one or more containers",
@@ -40,6 +38,7 @@ Running containers will not be removed without the -f option.
func init() {
rmCommand.Command = _rmCommand
+ rmCommand.SetHelpTemplate(HelpTemplate())
rmCommand.SetUsageTemplate(UsageTemplate())
flags := rmCommand.Flags()
flags.BoolVarP(&rmCommand.All, "all", "a", false, "Remove all containers")
diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go
index 511668df7..149cd8d82 100644
--- a/cmd/podman/rmi.go
+++ b/cmd/podman/rmi.go
@@ -13,7 +13,7 @@ import (
var (
rmiCommand cliconfig.RmiValues
- rmiDescription = "Removes one or more locally stored images."
+ rmiDescription = "Removes one or more previously pulled or locally created images."
_rmiCommand = cobra.Command{
Use: "rmi [flags] IMAGE [IMAGE...]",
Short: "Removes one or more images from local storage",
@@ -30,6 +30,7 @@ var (
)
func rmiInit(command *cliconfig.RmiValues) {
+ command.SetHelpTemplate(HelpTemplate())
command.SetUsageTemplate(UsageTemplate())
flags := command.Flags()
flags.BoolVarP(&command.All, "all", "a", false, "Remove all images")
diff --git a/cmd/podman/run.go b/cmd/podman/run.go
index f66b939d3..ff09e670d 100644
--- a/cmd/podman/run.go
+++ b/cmd/podman/run.go
@@ -39,6 +39,7 @@ var (
func init() {
runCommand.Command = _runCommand
+ runCommand.SetHelpTemplate(HelpTemplate())
runCommand.SetUsageTemplate(UsageTemplate())
flags := runCommand.Flags()
flags.SetInterspersed(false)
diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go
index f91ffed0d..68621e095 100644
--- a/cmd/podman/runlabel.go
+++ b/cmd/podman/runlabel.go
@@ -38,6 +38,7 @@ Executes a command as described by a container image label.
func init() {
runlabelCommand.Command = _runlabelCommand
+ runlabelCommand.SetHelpTemplate(HelpTemplate())
runlabelCommand.SetUsageTemplate(UsageTemplate())
flags := runlabelCommand.Flags()
flags.StringVar(&runlabelCommand.Authfile, "authfile", "", "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override")
diff --git a/cmd/podman/save.go b/cmd/podman/save.go
index 3bc283772..494496a3d 100644
--- a/cmd/podman/save.go
+++ b/cmd/podman/save.go
@@ -23,9 +23,7 @@ var validFormats = []string{ociManifestDir, ociArchive, v2s2ManifestDir, v2s2Arc
var (
saveCommand cliconfig.SaveValues
- saveDescription = `
- Save an image to docker-archive or oci-archive on the local machine.
- Default is docker-archive`
+ saveDescription = `Save an image to docker-archive or oci-archive on the local machine. Default is docker-archive.`
_saveCommand = &cobra.Command{
Use: "save [flags] IMAGE",
@@ -54,6 +52,7 @@ var (
func init() {
saveCommand.Command = _saveCommand
+ saveCommand.SetHelpTemplate(HelpTemplate())
saveCommand.SetUsageTemplate(UsageTemplate())
flags := saveCommand.Flags()
flags.BoolVar(&saveCommand.Compress, "compress", false, "Compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)")
diff --git a/cmd/podman/search.go b/cmd/podman/search.go
index 5c14f1ff1..e508c2bcf 100644
--- a/cmd/podman/search.go
+++ b/cmd/podman/search.go
@@ -18,9 +18,9 @@ const (
var (
searchCommand cliconfig.SearchValues
- searchDescription = `
- Search registries for a given image. Can search all the default registries or a specific registry.
- Can limit the number of results, and filter the output based on certain conditions.`
+ searchDescription = `Search registries for a given image. Can search all the default registries or a specific registry.
+
+ Users can limit the number of results, and filter the output based on certain conditions.`
_searchCommand = &cobra.Command{
Use: "search [flags] TERM",
Short: "Search registry for image",
@@ -38,6 +38,7 @@ var (
func init() {
searchCommand.Command = _searchCommand
+ searchCommand.SetHelpTemplate(HelpTemplate())
searchCommand.SetUsageTemplate(UsageTemplate())
flags := searchCommand.Flags()
flags.StringVar(&searchCommand.Authfile, "authfile", "", "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override")
diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go
index 2cf228d01..06418e4a5 100644
--- a/cmd/podman/sign.go
+++ b/cmd/podman/sign.go
@@ -22,7 +22,7 @@ import (
var (
signCommand cliconfig.SignValues
- signDescription = "Create a signature file that can be used later to verify the image"
+ signDescription = "Create a signature file that can be used later to verify the image."
_signCommand = &cobra.Command{
Use: "sign [flags] IMAGE [IMAGE...]",
Short: "Sign an image",
@@ -39,6 +39,7 @@ var (
func init() {
signCommand.Command = _signCommand
+ signCommand.SetHelpTemplate(HelpTemplate())
signCommand.SetUsageTemplate(UsageTemplate())
flags := signCommand.Flags()
flags.StringVarP(&signCommand.Directory, "directory", "d", "", "Define an alternate directory to store signatures")
diff --git a/cmd/podman/start.go b/cmd/podman/start.go
index 3ce04ea79..e942c1ccd 100644
--- a/cmd/podman/start.go
+++ b/cmd/podman/start.go
@@ -15,11 +15,8 @@ import (
var (
startCommand cliconfig.StartValues
- startDescription = `
- podman start
+ startDescription = `Starts one or more containers. The container name or ID can be used.`
- Starts one or more containers. The container name or ID can be used.
-`
_startCommand = &cobra.Command{
Use: "start [flags] CONTAINER [CONTAINER...]",
Short: "Start one or more containers",
@@ -37,6 +34,7 @@ var (
func init() {
startCommand.Command = _startCommand
+ startCommand.SetHelpTemplate(HelpTemplate())
startCommand.SetUsageTemplate(UsageTemplate())
flags := startCommand.Flags()
flags.BoolVarP(&startCommand.Attach, "attach", "a", false, "Attach container's STDOUT and STDERR")
diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go
index dcb274471..3e2e114a9 100644
--- a/cmd/podman/stats.go
+++ b/cmd/podman/stats.go
@@ -31,10 +31,10 @@ type statsOutputParams struct {
var (
statsCommand cliconfig.StatsValues
- statsDescription = "display a live stream of one or more containers' resource usage statistics"
+ statsDescription = "Display percentage of CPU, memory, network I/O, block I/O and PIDs for one or more containers."
_statsCommand = &cobra.Command{
Use: "stats [flags] CONTAINER [CONTAINER...]",
- Short: "Display percentage of CPU, memory, network I/O, block I/O and PIDs for one or more containers",
+ Short: "Display a live stream of container resource usage statistics",
Long: statsDescription,
RunE: func(cmd *cobra.Command, args []string) error {
statsCommand.InputArgs = args
@@ -52,6 +52,7 @@ var (
func init() {
statsCommand.Command = _statsCommand
+ statsCommand.SetHelpTemplate(HelpTemplate())
statsCommand.SetUsageTemplate(UsageTemplate())
flags := statsCommand.Flags()
flags.BoolVarP(&statsCommand.All, "all", "a", false, "Show all containers. Only running containers are shown by default. The default is false")
diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go
index 7bd160494..2a1470ad0 100644
--- a/cmd/podman/stop.go
+++ b/cmd/podman/stop.go
@@ -15,13 +15,9 @@ import (
var (
stopCommand cliconfig.StopValues
- stopDescription = `
- podman stop
+ stopDescription = `Stops one or more running containers. The container name or ID can be used.
- Stops one or more running containers. The container name or ID can be used.
- A timeout to forcibly stop the container can also be set but defaults to 10
- seconds otherwise.
-`
+ A timeout to forcibly stop the container can also be set but defaults to 10 seconds otherwise.`
_stopCommand = &cobra.Command{
Use: "stop [flags] CONTAINER [CONTAINER...]",
Short: "Stop one or more containers",
@@ -42,6 +38,7 @@ var (
func init() {
stopCommand.Command = _stopCommand
+ stopCommand.SetHelpTemplate(HelpTemplate())
stopCommand.SetUsageTemplate(UsageTemplate())
flags := stopCommand.Flags()
flags.BoolVarP(&stopCommand.All, "all", "a", false, "Stop all running containers")
diff --git a/cmd/podman/system.go b/cmd/podman/system.go
index 741b79da5..528a594de 100644
--- a/cmd/podman/system.go
+++ b/cmd/podman/system.go
@@ -13,6 +13,7 @@ var (
Use: "system",
Short: "Manage podman",
Long: systemDescription,
+ RunE: commandRunE(),
},
}
)
diff --git a/cmd/podman/system_prune.go b/cmd/podman/system_prune.go
index f566387fa..624f24acb 100644
--- a/cmd/podman/system_prune.go
+++ b/cmd/podman/system_prune.go
@@ -36,6 +36,7 @@ var (
func init() {
pruneSystemCommand.Command = _pruneSystemCommand
+ pruneSystemCommand.SetHelpTemplate(HelpTemplate())
pruneSystemCommand.SetUsageTemplate(UsageTemplate())
flags := pruneSystemCommand.Flags()
flags.BoolVarP(&pruneSystemCommand.All, "all", "a", false, "Remove all unused data")
diff --git a/cmd/podman/system_renumber.go b/cmd/podman/system_renumber.go
index 31137b9f6..ed0b28a3c 100644
--- a/cmd/podman/system_renumber.go
+++ b/cmd/podman/system_renumber.go
@@ -31,6 +31,7 @@ var (
func init() {
renumberCommand.Command = _renumberCommand
+ renumberCommand.SetHelpTemplate(HelpTemplate())
renumberCommand.SetUsageTemplate(UsageTemplate())
}
diff --git a/cmd/podman/tag.go b/cmd/podman/tag.go
index 98c6e3449..98d9a6856 100644
--- a/cmd/podman/tag.go
+++ b/cmd/podman/tag.go
@@ -10,7 +10,7 @@ import (
var (
tagCommand cliconfig.TagValues
- tagDescription = "Adds one or more additional names to locally-stored image"
+ tagDescription = "Adds one or more additional names to locally-stored image."
_tagCommand = &cobra.Command{
Use: "tag [flags] IMAGE TAG [TAG...]",
Short: "Add an additional name to a local image",
@@ -28,6 +28,7 @@ var (
func init() {
tagCommand.Command = _tagCommand
+ tagCommand.SetHelpTemplate(HelpTemplate())
tagCommand.SetUsageTemplate(UsageTemplate())
}
diff --git a/cmd/podman/top.go b/cmd/podman/top.go
index d96402f1a..c2156050c 100644
--- a/cmd/podman/top.go
+++ b/cmd/podman/top.go
@@ -18,20 +18,20 @@ func getDescriptorString() string {
descriptors, err := libpod.GetContainerPidInformationDescriptors()
if err == nil {
return fmt.Sprintf(`
-Format Descriptors:
-%s`, strings.Join(descriptors, ","))
+ Format Descriptors:
+ %s`, strings.Join(descriptors, ","))
}
return ""
}
var (
topCommand cliconfig.TopValues
- topDescription = fmt.Sprintf(`Display the running processes of the container. Specify format descriptors
-to alter the output. You may run "podman top -l pid pcpu seccomp" to print
-the process ID, the CPU percentage and the seccomp mode of each process of
-the latest container.
-%s
-`, getDescriptorString())
+ topDescription = fmt.Sprintf(`Similar to system "top" command.
+
+ Specify format descriptors to alter the output.
+
+ Running "podman top -l pid pcpu seccomp" will print the process ID, the CPU percentage and the seccomp mode of each process of the latest container.
+%s`, getDescriptorString())
_topCommand = &cobra.Command{
Use: "top [flags] CONTAINER [FORMAT-DESCRIPTIOS]",
@@ -50,6 +50,7 @@ the latest container.
func init() {
topCommand.Command = _topCommand
+ topCommand.SetHelpTemplate(HelpTemplate())
topCommand.SetUsageTemplate(UsageTemplate())
flags := topCommand.Flags()
flags.BoolVar(&topCommand.ListDescriptors, "list-descriptors", false, "")
diff --git a/cmd/podman/trust.go b/cmd/podman/trust.go
index 8b02dcdc6..0a79e1570 100644
--- a/cmd/podman/trust.go
+++ b/cmd/podman/trust.go
@@ -6,16 +6,21 @@ import (
)
var (
+ trustDescription = `Manages which registries you trust as a source of container images based on its location.
+
+ The location is determined by the transport and the registry host of the image. Using this container image docker://docker.io/library/busybox as an example, docker is the transport and docker.io is the registry host.`
trustCommand = cliconfig.PodmanCommand{
Command: &cobra.Command{
Use: "trust",
Short: "Manage container image trust policy",
- Long: "podman image trust command",
+ Long: trustDescription,
+ RunE: commandRunE(),
},
}
)
func init() {
+ trustCommand.SetHelpTemplate(HelpTemplate())
trustCommand.SetUsageTemplate(UsageTemplate())
trustCommand.AddCommand(getTrustSubCommands()...)
imageCommand.AddCommand(trustCommand.Command)
diff --git a/cmd/podman/trust_set_show.go b/cmd/podman/trust_set_show.go
index 746854249..5a70c21cc 100644
--- a/cmd/podman/trust_set_show.go
+++ b/cmd/podman/trust_set_show.go
@@ -50,8 +50,10 @@ var (
func init() {
setTrustCommand.Command = _setTrustCommand
+ setTrustCommand.SetHelpTemplate(HelpTemplate())
setTrustCommand.SetUsageTemplate(UsageTemplate())
showTrustCommand.Command = _showTrustCommand
+ showTrustCommand.SetHelpTemplate(HelpTemplate())
showTrustCommand.SetUsageTemplate(UsageTemplate())
setFlags := setTrustCommand.Flags()
setFlags.StringVar(&setTrustCommand.PolicyPath, "policypath", "", "")
diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go
index 48c97fa31..c57d5794c 100644
--- a/cmd/podman/umount.go
+++ b/cmd/podman/umount.go
@@ -14,12 +14,11 @@ import (
var (
umountCommand cliconfig.UmountValues
- description = `
-Container storage increments a mount counter each time a container is mounted.
-When a container is unmounted, the mount counter is decremented and the
-container's root filesystem is physically unmounted only when the mount
-counter reaches zero indicating no other processes are using the mount.
-An unmount can be forced with the --force flag.
+ description = `Container storage increments a mount counter each time a container is mounted.
+
+ When a container is unmounted, the mount counter is decremented. The container's root filesystem is physically unmounted only when the mount counter reaches zero indicating no other processes are using the mount.
+
+ An unmount can be forced with the --force flag.
`
_umountCommand = &cobra.Command{
Use: "umount [flags] CONTAINER [CONTAINER...]",
@@ -42,6 +41,7 @@ An unmount can be forced with the --force flag.
func init() {
umountCommand.Command = _umountCommand
+ umountCommand.SetHelpTemplate(HelpTemplate())
umountCommand.SetUsageTemplate(UsageTemplate())
flags := umountCommand.Flags()
flags.BoolVarP(&umountCommand.All, "all", "a", false, "Umount all of the currently mounted containers")
diff --git a/cmd/podman/unpause.go b/cmd/podman/unpause.go
index 58fd19fe1..0c52a2443 100644
--- a/cmd/podman/unpause.go
+++ b/cmd/podman/unpause.go
@@ -15,12 +15,8 @@ import (
var (
unpauseCommand cliconfig.UnpauseValues
- unpauseDescription = `
- podman unpause
-
- Unpauses one or more running containers. The container name or ID can be used.
-`
- _unpauseCommand = &cobra.Command{
+ unpauseDescription = `Unpauses one or more previously paused containers. The container name or ID can be used.`
+ _unpauseCommand = &cobra.Command{
Use: "unpause [flags] CONTAINER [CONTAINER...]",
Short: "Unpause the processes in one or more containers",
Long: unpauseDescription,
@@ -36,6 +32,7 @@ var (
func init() {
unpauseCommand.Command = _unpauseCommand
+ unpauseCommand.SetHelpTemplate(HelpTemplate())
unpauseCommand.SetUsageTemplate(UsageTemplate())
flags := unpauseCommand.Flags()
flags.BoolVarP(&unpauseCommand.All, "all", "a", false, "Unpause all paused containers")
diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go
index 5cc79ef96..787ad01cd 100644
--- a/cmd/podman/varlink.go
+++ b/cmd/podman/varlink.go
@@ -18,10 +18,9 @@ import (
var (
varlinkCommand cliconfig.VarlinkValues
- varlinkDescription = `
- podman varlink
+ varlinkDescription = `Run varlink interface. Podman varlink listens on the specified unix domain socket for incoming connects.
- run varlink interface
+ Tools speaking varlink protocol can remotely manage pods, containers and images.
`
_varlinkCommand = &cobra.Command{
Use: "varlink [flags] URI",
@@ -39,6 +38,7 @@ var (
func init() {
varlinkCommand.Command = _varlinkCommand
+ varlinkCommand.SetHelpTemplate(HelpTemplate())
varlinkCommand.SetUsageTemplate(UsageTemplate())
flags := varlinkCommand.Flags()
flags.Int64VarP(&varlinkCommand.Timeout, "timeout", "t", 1000, "Time until the varlink session expires in milliseconds. Use 0 to disable the timeout")
diff --git a/cmd/podman/volume.go b/cmd/podman/volume.go
index 8a8664151..2a071d0c7 100644
--- a/cmd/podman/volume.go
+++ b/cmd/podman/volume.go
@@ -5,15 +5,14 @@ import (
"github.com/spf13/cobra"
)
-var volumeDescription = `Manage volumes.
-
-Volumes are created in and can be shared between containers.`
+var volumeDescription = `Volumes are created in and can be shared between containers.`
var volumeCommand = cliconfig.PodmanCommand{
Command: &cobra.Command{
Use: "volume",
Short: "Manage volumes",
Long: volumeDescription,
+ RunE: commandRunE(),
},
}
var volumeSubcommands = []*cobra.Command{
diff --git a/cmd/podman/volume_create.go b/cmd/podman/volume_create.go
index 96b2ed8c7..d873f9806 100644
--- a/cmd/podman/volume_create.go
+++ b/cmd/podman/volume_create.go
@@ -11,11 +11,7 @@ import (
var (
volumeCreateCommand cliconfig.VolumeCreateValues
- volumeCreateDescription = `
-podman volume create
-
-Creates a new volume. If using the default driver, "local", the volume will
-be created at.`
+ volumeCreateDescription = `If using the default driver, "local", the volume will be created on the host in the volumes directory under container storage.`
_volumeCreateCommand = &cobra.Command{
Use: "create [flags] [NAME]",
@@ -34,6 +30,7 @@ be created at.`
func init() {
volumeCreateCommand.Command = _volumeCreateCommand
+ volumeCommand.SetHelpTemplate(HelpTemplate())
volumeCreateCommand.SetUsageTemplate(UsageTemplate())
flags := volumeCreateCommand.Flags()
flags.StringVar(&volumeCreateCommand.Driver, "driver", "", "Specify volume driver name (default local)")
diff --git a/cmd/podman/volume_inspect.go b/cmd/podman/volume_inspect.go
index 8add7a375..fdd8b5b0b 100644
--- a/cmd/podman/volume_inspect.go
+++ b/cmd/podman/volume_inspect.go
@@ -9,12 +9,9 @@ import (
var (
volumeInspectCommand cliconfig.VolumeInspectValues
- volumeInspectDescription = `
-podman volume inspect
+ volumeInspectDescription = `Display detailed information on one or more volumes.
-Display detailed information on one or more volumes. Can change the format
-from JSON to a Go template.
-`
+ Use a Go template to change the format from JSON.`
_volumeInspectCommand = &cobra.Command{
Use: "inspect [flags] VOLUME [VOLUME...]",
Short: "Display detailed information on one or more volumes",
@@ -32,6 +29,7 @@ from JSON to a Go template.
func init() {
volumeInspectCommand.Command = _volumeInspectCommand
+ volumeInspectCommand.SetHelpTemplate(HelpTemplate())
volumeInspectCommand.SetUsageTemplate(UsageTemplate())
flags := volumeInspectCommand.Flags()
flags.BoolVarP(&volumeInspectCommand.All, "all", "a", false, "Inspect all volumes")
diff --git a/cmd/podman/volume_ls.go b/cmd/podman/volume_ls.go
index 6855f38e0..5a36f4f7d 100644
--- a/cmd/podman/volume_ls.go
+++ b/cmd/podman/volume_ls.go
@@ -44,8 +44,7 @@ var (
podman volume ls
List all available volumes. The output of the volumes can be filtered
-and the output format can be changed to JSON or a user specified Go template.
-`
+and the output format can be changed to JSON or a user specified Go template.`
_volumeLsCommand = &cobra.Command{
Use: "ls",
Aliases: []string{"list"},
@@ -62,6 +61,7 @@ and the output format can be changed to JSON or a user specified Go template.
func init() {
volumeLsCommand.Command = _volumeLsCommand
+ volumeLsCommand.SetHelpTemplate(HelpTemplate())
volumeLsCommand.SetUsageTemplate(UsageTemplate())
flags := volumeLsCommand.Flags()
diff --git a/cmd/podman/volume_prune.go b/cmd/podman/volume_prune.go
index 370f072eb..70ba506e7 100644
--- a/cmd/podman/volume_prune.go
+++ b/cmd/podman/volume_prune.go
@@ -16,12 +16,10 @@ import (
var (
volumePruneCommand cliconfig.VolumePruneValues
- volumePruneDescription = `
-podman volume prune
+ volumePruneDescription = `Volumes that are not currently owned by a container will be removed.
-Remove all unused volumes. Will prompt for confirmation if not
-using force.
-`
+ The command prompts for confirmation which can be overridden with the --force flag.
+ Note all data will be destroyed.`
_volumePruneCommand = &cobra.Command{
Use: "prune",
Args: noSubArgs,
@@ -37,6 +35,7 @@ using force.
func init() {
volumePruneCommand.Command = _volumePruneCommand
+ volumePruneCommand.SetHelpTemplate(HelpTemplate())
volumePruneCommand.SetUsageTemplate(UsageTemplate())
flags := volumePruneCommand.Flags()
diff --git a/cmd/podman/volume_rm.go b/cmd/podman/volume_rm.go
index 73b1a6668..8c6d5e97a 100644
--- a/cmd/podman/volume_rm.go
+++ b/cmd/podman/volume_rm.go
@@ -11,13 +11,9 @@ import (
var (
volumeRmCommand cliconfig.VolumeRmValues
- volumeRmDescription = `
-podman volume rm
+ volumeRmDescription = `Remove one or more existing volumes.
-Remove one or more existing volumes. Will only remove volumes that are
-not being used by any containers. To remove the volumes anyways, use the
---force flag.
-`
+ By default only volumes that are not being used by any containers will be removed. To remove the volumes anyways, use the --force flag.`
_volumeRmCommand = &cobra.Command{
Use: "rm [flags] VOLUME [VOLUME...]",
Aliases: []string{"remove"},
@@ -36,6 +32,7 @@ not being used by any containers. To remove the volumes anyways, use the
func init() {
volumeRmCommand.Command = _volumeRmCommand
+ volumeRmCommand.SetHelpTemplate(HelpTemplate())
volumeRmCommand.SetUsageTemplate(UsageTemplate())
flags := volumeRmCommand.Flags()
flags.BoolVarP(&volumeRmCommand.All, "all", "a", false, "Remove all volumes")
diff --git a/cmd/podman/wait.go b/cmd/podman/wait.go
index 6c2a8c9ff..4449898a0 100644
--- a/cmd/podman/wait.go
+++ b/cmd/podman/wait.go
@@ -14,10 +14,7 @@ import (
var (
waitCommand cliconfig.WaitValues
- waitDescription = `
- podman wait
-
- Block until one or more containers stop and then print their exit codes
+ waitDescription = `Block until one or more containers stop and then print their exit codes.
`
_waitCommand = &cobra.Command{
Use: "wait [flags] CONTAINER [CONTAINER...]",
@@ -36,6 +33,7 @@ var (
func init() {
waitCommand.Command = _waitCommand
+ waitCommand.SetHelpTemplate(HelpTemplate())
waitCommand.SetUsageTemplate(UsageTemplate())
flags := waitCommand.Flags()
flags.UintVarP(&waitCommand.Interval, "interval", "i", 250, "Milliseconds to wait before polling for completion")
diff --git a/contrib/cirrus/README.md b/contrib/cirrus/README.md
index 0d91301c6..e3b3182ec 100644
--- a/contrib/cirrus/README.md
+++ b/contrib/cirrus/README.md
@@ -33,6 +33,17 @@ task (pass or fail) is set based on the exit status of the last script to execut
the vendor.conf, the code and the vendored packages in ./vendor are in sync
at all times.
+### ``meta`` Task
+
+***N/B: Steps below are performed by automation***
+
+1. Launch a container built from definition in ``./contrib/imgts``.
+
+2. Update VM Image metadata to help track usage across all automation.
+
+4. Always exits successfully unless there's a major problem.
+
+
### ``testing`` Task
***N/B: Steps below are performed by automation***
diff --git a/contrib/cirrus/test/test_dot_cirrus_yaml.py b/contrib/cirrus/test/test_dot_cirrus_yaml.py
new file mode 100755
index 000000000..2894bc45e
--- /dev/null
+++ b/contrib/cirrus/test/test_dot_cirrus_yaml.py
@@ -0,0 +1,78 @@
+#!/bin/env python3
+
+import sys
+import os
+import os.path
+import unittest
+import warnings
+import yaml
+
+class TestCaseBase(unittest.TestCase):
+
+ SCRIPT_PATH = os.path.realpath((os.path.dirname(sys.argv[0])))
+ CIRRUS_WORKING_DIR = os.environ.get('CIRRUS_WORKING_DIR',
+ '{0}/../../../'.format(SCRIPT_PATH))
+
+ def setUp(self):
+ os.chdir(self.CIRRUS_WORKING_DIR)
+
+
+class TestCirrusYAML(TestCaseBase):
+
+ IMAGE_NAME_SUFFIX = '_CACHE_IMAGE_NAME'
+ ACTIVE_IMAGES_NAME = 'ACTIVE_CACHE_IMAGE_NAMES'
+
+ def setUp(self):
+ TestCirrusYAML._cirrus = None
+ super().setUp()
+
+ @property
+ def cirrus(self):
+ if TestCirrusYAML._cirrus is None:
+ with warnings.catch_warnings():
+ warnings.filterwarnings("ignore",category=DeprecationWarning)
+ with open('.cirrus.yml', "r") as dot_cirrus_dot_yaml:
+ TestCirrusYAML._cirrus = yaml.load(dot_cirrus_dot_yaml)
+ return TestCirrusYAML._cirrus
+
+ def _assert_get_cache_image_names(self, env):
+ inames = set([key for key in env.keys()
+ if key.endswith(self.IMAGE_NAME_SUFFIX)])
+ self.assertNotEqual(inames, set())
+
+ ivalues = set([value for key, value in env.items()
+ if key in inames])
+ self.assertNotEqual(ivalues, set())
+ return ivalues
+
+ def _assert_get_subdct(self, key, dct):
+ self.assertIn(key, dct)
+ return dct[key]
+
+ def test_parse_yaml(self):
+ self.assertIsInstance(self.cirrus, dict)
+
+ def test_active_cache_image_names(self):
+ env = self._assert_get_subdct('env', self.cirrus)
+ acin = self._assert_get_subdct(self.ACTIVE_IMAGES_NAME, env)
+
+ for ivalue in self._assert_get_cache_image_names(env):
+ self.assertIn(ivalue, acin,
+ "The '{}' sub-key of 'env' should contain this among"
+ " its space-separated values."
+ "".format(self.ACTIVE_IMAGES_NAME))
+
+
+ def test_cache_image_names_active(self):
+ env = self._assert_get_subdct('env', self.cirrus)
+ ivalues = self._assert_get_cache_image_names(env)
+
+ for avalue in set(self._assert_get_subdct(self.ACTIVE_IMAGES_NAME, env).split()):
+ self.assertIn(avalue, ivalues,
+ "All space-separated values in the '{}' sub-key"
+ " of 'env' must also be used in a key with a '{}' suffix."
+ "".format(self.ACTIVE_IMAGES_NAME, self.IMAGE_NAME_SUFFIX))
+
+
+if __name__ == '__main__':
+ unittest.main(failfast=True, catchbreak=True, verbosity=0)
diff --git a/contrib/gate/Dockerfile b/contrib/gate/Dockerfile
index 4d88ae9a6..16d5eda67 100644
--- a/contrib/gate/Dockerfile
+++ b/contrib/gate/Dockerfile
@@ -29,6 +29,7 @@ RUN dnf -y install \
python3-dateutil \
python3-psutil \
python3-pytoml \
+ python3-pyyaml \
python3-varlink \
skopeo-containers \
slirp4netns \
diff --git a/docs/podman.1.md b/docs/podman.1.md
index bc03d3c5a..5c930995c 100644
--- a/docs/podman.1.md
+++ b/docs/podman.1.md
@@ -137,6 +137,7 @@ 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-healthcheck(1)](podman-healthcheck.1.md)| Manage healthchecks for containers |
| [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. |
diff --git a/hack/podman-commands.sh b/hack/podman-commands.sh
index 754f2923d..eb599763c 100755
--- a/hack/podman-commands.sh
+++ b/hack/podman-commands.sh
@@ -35,6 +35,9 @@ function podman_man() {
# | [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
+
+ # Special case: there is no podman-help man page, nor need for such.
+ echo "help"
elif [ "$@" = "podman-image-trust" ]; then
# Special case: set and show aren't actually in a table in the man page
echo set
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index c226a0617..92a7b1538 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -382,6 +382,11 @@ func (s *BoltState) LookupContainer(idOrName string) (*Container, error) {
return err
}
+ namesBucket, err := getNamesBucket(tx)
+ if err != nil {
+ return err
+ }
+
nsBucket, err := getNSBucket(tx)
if err != nil {
return err
@@ -395,41 +400,59 @@ func (s *BoltState) LookupContainer(idOrName string) (*Container, error) {
// It might not be in our namespace, but
// getContainerFromDB() will handle that case.
id = []byte(idOrName)
- } else {
- // They did not give us a full container ID.
- // Search for partial ID or full name matches
- // Use else-if in case the name is set to a partial ID
- exists := false
- err = idBucket.ForEach(func(checkID, checkName []byte) error {
- // If the container isn't in our namespace, we
- // can't match it
- if s.namespaceBytes != nil {
- ns := nsBucket.Get(checkID)
- if !bytes.Equal(ns, s.namespaceBytes) {
- return nil
- }
+ return s.getContainerFromDB(id, ctr, ctrBucket)
+ }
+
+ // Next, check if the full name was given
+ isPod := false
+ fullID := namesBucket.Get([]byte(idOrName))
+ if fullID != nil {
+ // The name exists and maps to an ID.
+ // However, we are not yet certain the ID is a
+ // container.
+ ctrExists = ctrBucket.Bucket(fullID)
+ if ctrExists != nil {
+ // A container bucket matching the full ID was
+ // found.
+ return s.getContainerFromDB(fullID, ctr, ctrBucket)
+ }
+ // Don't error if we have a name match but it's not a
+ // container - there's a chance we have a container with
+ // an ID starting with those characters.
+ // However, so we can return a good error, note whether
+ // this is a pod.
+ isPod = true
+ }
+
+ // We were not given a full container ID or name.
+ // Search for partial ID matches.
+ exists := false
+ err = idBucket.ForEach(func(checkID, checkName []byte) error {
+ // If the container isn't in our namespace, we
+ // can't match it
+ if s.namespaceBytes != nil {
+ ns := nsBucket.Get(checkID)
+ if !bytes.Equal(ns, s.namespaceBytes) {
+ return nil
}
- if string(checkName) == idOrName {
- if exists {
- return errors.Wrapf(ErrCtrExists, "more than one result for ID or name %s", idOrName)
- }
- id = checkID
- exists = true
- } else if strings.HasPrefix(string(checkID), idOrName) {
- if exists {
- return errors.Wrapf(ErrCtrExists, "more than one result for ID or name %s", idOrName)
- }
- id = checkID
- exists = true
+ }
+ if strings.HasPrefix(string(checkID), idOrName) {
+ if exists {
+ return errors.Wrapf(ErrCtrExists, "more than one result for container ID %s", idOrName)
}
+ id = checkID
+ exists = true
+ }
- return nil
- })
- if err != nil {
- return err
- } else if !exists {
- return errors.Wrapf(ErrNoSuchCtr, "no container with name or ID %s found", idOrName)
+ return nil
+ })
+ if err != nil {
+ return err
+ } else if !exists {
+ if isPod {
+ return errors.Wrapf(ErrNoSuchCtr, "%s is a pod, not a container", idOrName)
}
+ return errors.Wrapf(ErrNoSuchCtr, "no container with name or ID %s found", idOrName)
}
return s.getContainerFromDB(id, ctr, ctrBucket)
@@ -941,6 +964,11 @@ func (s *BoltState) LookupPod(idOrName string) (*Pod, error) {
return err
}
+ namesBkt, err := getNamesBucket(tx)
+ if err != nil {
+ return err
+ }
+
nsBkt, err := getNSBucket(tx)
if err != nil {
return err
@@ -954,41 +982,56 @@ func (s *BoltState) LookupPod(idOrName string) (*Pod, error) {
// It might not be in our namespace, but getPodFromDB()
// will handle that case.
id = []byte(idOrName)
- } else {
- // They did not give us a full pod ID.
- // Search for partial ID or full name matches
- // Use else-if in case the name is set to a partial ID
- exists := false
- err = idBucket.ForEach(func(checkID, checkName []byte) error {
- // If the pod isn't in our namespace, we
- // can't match it
- if s.namespaceBytes != nil {
- ns := nsBkt.Get(checkID)
- if !bytes.Equal(ns, s.namespaceBytes) {
- return nil
- }
+ return s.getPodFromDB(id, pod, podBkt)
+ }
+
+ // Next, check if the full name was given
+ isCtr := false
+ fullID := namesBkt.Get([]byte(idOrName))
+ if fullID != nil {
+ // The name exists and maps to an ID.
+ // However, we aren't yet sure if the ID is a pod.
+ podExists = podBkt.Bucket(fullID)
+ if podExists != nil {
+ // A pod bucket matching the full ID was found.
+ return s.getPodFromDB(fullID, pod, podBkt)
+ }
+ // Don't error if we have a name match but it's not a
+ // pod - there's a chance we have a pod with an ID
+ // starting with those characters.
+ // However, so we can return a good error, note whether
+ // this is a container.
+ isCtr = true
+ }
+ // They did not give us a full pod name or ID.
+ // Search for partial ID matches.
+ exists := false
+ err = idBucket.ForEach(func(checkID, checkName []byte) error {
+ // If the pod isn't in our namespace, we
+ // can't match it
+ if s.namespaceBytes != nil {
+ ns := nsBkt.Get(checkID)
+ if !bytes.Equal(ns, s.namespaceBytes) {
+ return nil
}
- if string(checkName) == idOrName {
- if exists {
- return errors.Wrapf(ErrPodExists, "more than one result for ID or name %s", idOrName)
- }
- id = checkID
- exists = true
- } else if strings.HasPrefix(string(checkID), idOrName) {
- if exists {
- return errors.Wrapf(ErrPodExists, "more than one result for ID or name %s", idOrName)
- }
- id = checkID
- exists = true
+ }
+ if strings.HasPrefix(string(checkID), idOrName) {
+ if exists {
+ return errors.Wrapf(ErrPodExists, "more than one result for ID or name %s", idOrName)
}
+ id = checkID
+ exists = true
+ }
- return nil
- })
- if err != nil {
- return err
- } else if !exists {
- return errors.Wrapf(ErrNoSuchPod, "no pod with name or ID %s found", idOrName)
+ return nil
+ })
+ if err != nil {
+ return err
+ } else if !exists {
+ if isCtr {
+ return errors.Wrapf(ErrNoSuchPod, "%s is a container, not a pod", idOrName)
}
+ return errors.Wrapf(ErrNoSuchPod, "no pod with name or ID %s found", idOrName)
}
// We might have found a container ID, but it's OK
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 08945c410..d86062e38 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -34,8 +34,8 @@ const (
)
var (
- // localeToLanguage maps from locale values to language tags.
- localeToLanguage = map[string]string{
+ // localeToLanguageMap maps from locale values to language tags.
+ localeToLanguageMap = map[string]string{
"": "und-u-va-posix",
"c": "und-u-va-posix",
"posix": "und-u-va-posix",
@@ -1281,6 +1281,16 @@ func (c *Container) saveSpec(spec *spec.Spec) error {
return nil
}
+// localeToLanguage translates POSIX locale strings to BCP 47 language tags.
+func localeToLanguage(locale string) string {
+ locale = strings.Replace(strings.SplitN(locale, ".", 2)[0], "_", "-", 1)
+ langString, ok := localeToLanguageMap[strings.ToLower(locale)]
+ if !ok {
+ langString = locale
+ }
+ return langString
+}
+
// Warning: precreate hooks may alter 'config' in place.
func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (extensionStageHooks map[string][]spec.Hook, err error) {
var locale string
@@ -1296,11 +1306,7 @@ func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (exten
}
}
- langString, ok := localeToLanguage[strings.ToLower(locale)]
- if !ok {
- langString = locale
- }
-
+ langString := localeToLanguage(locale)
lang, err := language.Parse(langString)
if err != nil {
logrus.Warnf("failed to parse language %q: %s", langString, err)
diff --git a/libpod/container_internal_test.go b/libpod/container_internal_test.go
index f1e2b70a7..1654af929 100644
--- a/libpod/container_internal_test.go
+++ b/libpod/container_internal_test.go
@@ -17,6 +17,54 @@ import (
// hookPath is the path to an example hook executable.
var hookPath string
+func TestLocaleToLanguage(t *testing.T) {
+ for _, testCase := range []struct {
+ locale string
+ language string
+ }{
+ {
+ locale: "",
+ language: "und-u-va-posix",
+ },
+ {
+ locale: "C",
+ language: "und-u-va-posix",
+ },
+ {
+ locale: "POSIX",
+ language: "und-u-va-posix",
+ },
+ {
+ locale: "c",
+ language: "und-u-va-posix",
+ },
+ {
+ locale: "en",
+ language: "en",
+ },
+ {
+ locale: "en_US",
+ language: "en-US",
+ },
+ {
+ locale: "en.UTF-8",
+ language: "en",
+ },
+ {
+ locale: "en_US.UTF-8",
+ language: "en-US",
+ },
+ {
+ locale: "does-not-exist",
+ language: "does-not-exist",
+ },
+ } {
+ t.Run(testCase.locale, func(t *testing.T) {
+ assert.Equal(t, testCase.language, localeToLanguage(testCase.locale))
+ })
+ }
+}
+
func TestPostDeleteHooks(t *testing.T) {
ctx := context.Background()
dir, err := ioutil.TempDir("", "libpod_test_")
diff --git a/libpod/oci.go b/libpod/oci.go
index 2cbf25699..c3b5f9af2 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -805,6 +805,12 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty
execCmd.Env = append(execCmd.Env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir))
+ if preserveFDs > 0 {
+ for fd := 3; fd < 3+preserveFDs; fd++ {
+ execCmd.ExtraFiles = append(execCmd.ExtraFiles, os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)))
+ }
+ }
+
if err := execCmd.Start(); err != nil {
return nil, errors.Wrapf(err, "cannot start container %s", c.ID())
}
diff --git a/test/README.md b/test/README.md
index ef3bfbcf9..5e5a7da61 100644
--- a/test/README.md
+++ b/test/README.md
@@ -105,3 +105,7 @@ You can run the test with following command:
```
make localsystem
```
+
+## Contributing to system tests
+
+Please see [the TODO list of needed workflows/tests](system/TODO.md).
diff --git a/test/system/000-TEMPLATE b/test/system/000-TEMPLATE
new file mode 100644
index 000000000..296ed4d58
--- /dev/null
+++ b/test/system/000-TEMPLATE
@@ -0,0 +1,114 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# FIXME: short description of the purpose of this module
+#
+# FIXME: copy this file to 'NNN-yourtestname.bats' and edit as needed.
+#
+
+load helpers
+
+@test "podman subcmd - description of this particular test" {
+ args="some sort of argument list"
+ run_podman subcmd $args
+ is "$output" "what we expect" "output from 'podman subcmd $args'"
+}
+
+# vim: filetype=sh
+
+###############################################################################
+#
+# FIXME FIXME FIXME: Most of the time you can cut from here on down.
+# FIXME FIXME FIXME: The above template is probably enough for many tests.
+# FIXME FIXME FIXME:
+# FIXME FIXME FIXME: If you need anything more complicated, read on.
+#
+# FIXME: This is a bloated test template. It provides mostly stuff for you
+# FIXME: to remove, plus stuff for you to base your tests on.
+# FIXME:
+# FIXME: copy this file to 'NNN-yourtestname.bats' and edit as needed.
+# FIXME: Read all FIXMEs, act on them as needed, then remove them.
+# FIXME: test w/ $ PODMAN=./bin/podman bats test/system/NNN-yourtestname.bats
+#
+
+load helpers
+
+# FIXME: DELETE THESE LINES UNLESS YOU ABSOLUTELY NEED THEM.
+# FIXME: Most tests will not need a custom setup/teardown: they are
+# FIXME: provided by helpers.bash.
+# FIXME: But if you have to do anything special, these give you the
+# FIXME: names of the standard setup/teardown so you can call them
+# FIXME: before or after your own additions.
+function setup() {
+ basic_setup
+ # FIXME: you almost certainly want to do your own setup _after_ basic.
+}
+function teardown() {
+ # FIXME: you almost certainly want to do your own teardown _before_ basic.
+ basic_teardown
+}
+
+
+# FIXME: very basic one-pass example
+@test "podman FOO - description of test" {
+ # FIXME: please try to remove this line; that is, try to write tests
+ # that will pass as both root and rootless.
+ skip_if_rootless
+
+ # FIXME: template for run commands. Always use 'run_podman'!
+ # FIXME: The '?' means 'ignore exit status'; use a number if you
+ # FIXME: expect a precise nonzero code, or omit for 0 (usual case).
+ # FIXME: NEVER EVER RUN 'podman' DIRECTLY. See helpers.bash for why.
+ run_podman '?' run -d $IMAGE sh -c 'prep..; echo READY'
+ cid="$output"
+ wait_for_ready $cid
+
+ run_podman logs $cid
+ # FIXME: example of dprint. This will trigger if PODMAN_TEST_DEBUG=FOO
+ # FIXME: ...or anything that matches the name assigned in the @test line.
+ dprint "podman logs $cid -> '$output'"
+ is "$output" "what are we expecting?" "description of this check"
+
+ # Clean up
+ run_podman rm $cid
+}
+
+
+# FIXME: another example, this time with a test table loop
+@test "podman FOO - json - template for playing with json output" {
+ # FIXME: Define a multiline string in tabular form, using '|' as separator.
+ # FIXME: Each row defines one test. Each column (there may be as many as
+ # FIXME: you want) is one field. In the case below we have two, a
+ # FIXME: json field descriptor and an expected value.
+ tests="
+id | [0-9a-f]\\\{64\\\}
+created | [0-9-]\\\+T[0-9:]\\\+\\\.[0-9]\\\+Z
+size | -\\\?[0-9]\\\+
+"
+
+ # FIXME: Run a basic podman command. We'll check $output multiple times
+ # FIXME: in the while loop below.
+ run_podman history --format json $IMAGE
+
+ # FIXME: parse_table is what does all the work, giving us test cases.
+ parse_table "$tests" | while read field expect; do
+ # FIXME: this shows a drawback of BATS and bash: we can't include '|'
+ # FIXME: in the table, but we need to because some images don't
+ # FIXME: have a CID. So, yeah, this is ugly -- but rare.
+ if [ "$field" = "id" ]; then expect="$expect\|<missing>";fi
+
+ # output is an array of dicts; check each one
+ count=$(echo "$output" | jq '. | length')
+ i=0
+ while [ $i -lt $count ]; do
+ actual=$(echo "$output" | jq -r ".[$i].$field")
+ # FIXME: please be sure to note the third field!
+ # FIXME: that's the test name. Make it something useful! Include
+ # FIXME: loop variables whenever possible. Don't just say "my test"
+ is "$actual" "$expect\$" "jq .[$i].$field"
+ i=$(expr $i + 1)
+ done
+ done
+}
+
+
+# vim: filetype=sh
diff --git a/test/system/001-basic.bats b/test/system/001-basic.bats
new file mode 100644
index 000000000..85b9bc1ca
--- /dev/null
+++ b/test/system/001-basic.bats
@@ -0,0 +1,50 @@
+#!/usr/bin/env bats
+#
+# Simplest set of podman tests. If any of these fail, we have serious problems.
+#
+
+load helpers
+
+# Override standard setup! We don't yet trust podman-images or podman-rm
+function setup() {
+ :
+}
+
+@test "podman version emits reasonable output" {
+ run_podman version
+
+ is "${lines[0]}" "Version:[ ]\+[1-9][0-9.]\+" "Version line 1"
+ is "$output" ".*Go Version: \+" "'Go Version' in output"
+ is "$output" ".*RemoteAPI Version: \+" "API version in output"
+}
+
+
+@test "podman can pull an image" {
+ run_podman pull $IMAGE
+}
+
+# This is for development only; it's intended to make sure our timeout
+# in run_podman continues to work. This test should never run in production
+# because it will, by definition, fail.
+@test "timeout" {
+ if [ -z "$PODMAN_RUN_TIMEOUT_TEST" ]; then
+ skip "define \$PODMAN_RUN_TIMEOUT_TEST to enable this test"
+ fi
+ PODMAN_TIMEOUT=10 run_podman run $IMAGE sleep 90
+ echo "*** SHOULD NEVER GET HERE"
+}
+
+
+# Too many tests rely on jq for parsing JSON.
+#
+# If absolutely necessary, one could establish a convention such as
+# defining PODMAN_TEST_SKIP_JQ=1 and adding a skip_if_no_jq() helper.
+# For now, let's assume this is not absolutely necessary.
+@test "jq is installed and produces reasonable output" {
+ type -path jq >/dev/null || die "FATAL: 'jq' tool not found."
+
+ run jq -r .a.b < <(echo '{ "a": { "b" : "you found me" } }')
+ is "$output" "you found me" "sample invocation of 'jq'"
+}
+
+# vim: filetype=sh
diff --git a/test/system/005-info.bats b/test/system/005-info.bats
new file mode 100644
index 000000000..7dcc78838
--- /dev/null
+++ b/test/system/005-info.bats
@@ -0,0 +1,54 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "podman info - basic test" {
+ run_podman info
+
+ expected_keys="
+BuildahVersion: *[0-9.]\\\+
+Conmon:\\\s\\\+package:
+Distribution:
+OCIRuntime:\\\s\\\+package:
+os:
+rootless:
+insecure registries:
+store:
+GraphDriverName:
+GraphRoot:
+GraphStatus:
+ImageStore:\\\s\\\+number: 1
+RunRoot:
+"
+ while read expect; do
+ is "$output" ".*$expect" "output includes '$expect'"
+ done < <(parse_table "$expected_keys")
+}
+
+@test "podman info - json" {
+ run_podman info --format=json
+
+ expr_nvr="[a-z0-9-]\\\+-[a-z0-9.]\\\+-[a-z0-9]\\\+\."
+ expr_path="/[a-z0-9\\\/.]\\\+\\\$"
+
+ tests="
+host.BuildahVersion | [0-9.]
+host.Conmon.package | $expr_nvr
+host.Conmon.path | $expr_path
+host.OCIRuntime.package | $expr_nvr
+host.OCIRuntime.path | $expr_path
+store.ConfigFile | $expr_path
+store.GraphDriverName | [a-z0-9]\\\+\\\$
+store.GraphRoot | $expr_path
+store.ImageStore.number | 1
+"
+
+ parse_table "$tests" | while read field expect; do
+ actual=$(echo "$output" | jq -r ".$field")
+ dprint "# actual=<$actual> expect=<$expect>"
+ is "$actual" "$expect" "jq .$field"
+ done
+
+}
+
+# vim: filetype=sh
diff --git a/test/system/010-images.bats b/test/system/010-images.bats
new file mode 100644
index 000000000..1c9577e34
--- /dev/null
+++ b/test/system/010-images.bats
@@ -0,0 +1,46 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "podman images - basic output" {
+ run_podman images -a
+
+ is "${lines[0]}" "REPOSITORY *TAG *IMAGE ID *CREATED *SIZE" "header line"
+ is "${lines[1]}" "$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME *$PODMAN_TEST_IMAGE_TAG *[0-9a-f]\+" "podman images output"
+}
+
+@test "podman images - custom formats" {
+ tests="
+--format {{.ID}} | [0-9a-f]\\\{12\\\}
+--format {{.ID}} --no-trunc | sha256:[0-9a-f]\\\{64\\\}
+--format {{.Repository}}:{{.Tag}} | $PODMAN_TEST_IMAGE_FQN
+"
+
+ parse_table "$tests" | while read fmt expect; do
+ run_podman images $fmt
+ is "$output" "$expect\$" "podman images $fmt"
+ done
+
+}
+
+
+@test "podman images - json" {
+ tests="
+names[0] | $PODMAN_TEST_IMAGE_FQN
+id | [0-9a-f]\\\{64\\\}
+digest | sha256:[0-9a-f]\\\{64\\\}
+created | [0-9-]\\\+T[0-9:]\\\+\\\.[0-9]\\\+Z
+size | [0-9]\\\+
+"
+
+ run_podman images -a --format json
+
+ parse_table "$tests" | while read field expect; do
+ actual=$(echo "$output" | jq -r ".[0].$field")
+ dprint "# actual=<$actual> expect=<$expect}>"
+ is "$actual" "$expect" "jq .$field"
+ done
+
+}
+
+# vim: filetype=sh
diff --git a/test/system/015-help.bats b/test/system/015-help.bats
new file mode 100644
index 000000000..b648599f7
--- /dev/null
+++ b/test/system/015-help.bats
@@ -0,0 +1,76 @@
+#!/usr/bin/env bats
+#
+# Tests based on 'podman help'
+#
+# Find all commands listed by 'podman --help'. Run each one, make sure it
+# provides its own --help output. If the usage message ends in '[command]',
+# treat it as a subcommand, and recurse into its own list of sub-subcommands.
+#
+# Any usage message that ends in '[flags]' is interpreted as a command
+# that takes no further arguments; we confirm by running with 'invalid-arg'
+# and confirming that it exits with error status and message.
+#
+load helpers
+
+# run 'podman help', parse the output looking for 'Available Commands';
+# return that list.
+function podman_commands() {
+ dprint "$@"
+ run_podman help "$@" |\
+ awk '/^Available Commands:/{ok=1;next}/^Flags:/{ok=0}ok { print $1 }' |\
+ grep .
+ "$output"
+}
+
+
+function check_help() {
+ local count=0
+ local subcommands_found=0
+
+ for cmd in $(podman_commands "$@"); do
+ dprint "podman $@ $cmd --help"
+ run_podman "$@" $cmd --help
+
+ # The line immediately after 'Usage:' gives us a 1-line synopsis
+ usage=$(echo "$output" | grep -A1 '^Usage:' | tail -1)
+ [ -n "$usage" ] || die "podman $cmd: no Usage message found"
+
+ # If usage ends in '[command]', recurse into subcommands
+ if expr "$usage" : '.*\[command\]$' >/dev/null; then
+ subcommands_found=$(expr $subcommands_found + 1)
+ check_help "$@" $cmd
+ continue
+ fi
+
+ # If usage ends in '[flag]', command takes no more arguments.
+ # Confirm that by running with 'invalid-arg' and expecting failure.
+ if expr "$usage" : '.*\[flags\]$' >/dev/null; then
+ if [ "$cmd" != "help" ]; then
+ run_podman 125 "$@" $cmd invalid-arg
+ is "$output" "Error: .* takes no arguments" \
+ "'podman $@ $cmd' with extra (invalid) arguments"
+ fi
+ fi
+
+ count=$(expr $count + 1)
+ done
+
+ # This can happen if the output of --help changes, such as between
+ # the old command parser and cobra.
+ [ $count -gt 0 ] || \
+ die "Internal error: no commands found in 'podman help $@' list"
+
+ # At least the top level must have some subcommands
+ if [ -z "$*" -a $subcommands_found -eq 0 ]; then
+ die "Internal error: did not find any podman subcommands"
+ fi
+}
+
+
+@test "podman help - basic tests" {
+ # Called with no args -- start with 'podman --help'. check_help() will
+ # recurse for any subcommands.
+ check_help
+}
+
+# vim: filetype=sh
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
new file mode 100644
index 000000000..8ae68f33d
--- /dev/null
+++ b/test/system/030-run.bats
@@ -0,0 +1,34 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "podman run - basic tests" {
+ rand=$(random_string 30)
+ tests="
+true | 0 |
+false | 1 |
+sh -c 'exit 32' | 32 |
+echo $rand | 0 | $rand
+/no/such/command | 127 | Error: container create failed:.*exec:.* no such file or dir
+/etc | 126 | Error: container create failed:.*exec:.* permission denied
+"
+
+ while read cmd expected_rc expected_output; do
+ if [ "$expected_output" = "''" ]; then expected_output=""; fi
+
+ # THIS IS TRICKY: this is what lets us handle a quoted command.
+ # Without this incantation (and the "$@" below), the cmd string
+ # gets passed on as individual tokens: eg "sh" "-c" "'exit" "32'"
+ # (note unmatched opening and closing single-quotes in the last 2).
+ # That results in a bizarre and hard-to-understand failure
+ # in the BATS 'run' invocation.
+ # This should really be done inside parse_table; I can't find
+ # a way to do so.
+ eval set "$cmd"
+
+ run_podman $expected_rc run $IMAGE "$@"
+ is "$output" "$expected_output" "podman run $cmd - output"
+ done < <(parse_table "$tests")
+}
+
+# vim: filetype=sh
diff --git a/test/system/035-logs.bats b/test/system/035-logs.bats
new file mode 100644
index 000000000..debec29b6
--- /dev/null
+++ b/test/system/035-logs.bats
@@ -0,0 +1,24 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# Basic tests for podman logs
+#
+
+load helpers
+
+@test "podman logs - basic test" {
+ rand_string=$(random_string 40)
+
+ run_podman create $IMAGE echo $rand_string
+ cid="$output"
+
+ run_podman logs $cid
+ is "$output" "" "logs on created container: empty"
+
+ run_podman start --attach --interactive $cid
+ is "$output" "$rand_string" "output from podman-start on created ctr"
+ is "$output" "$rand_string" "logs of started container"
+
+ run_podman rm $cid
+}
+
+# vim: filetype=sh
diff --git a/test/system/040-ps.bats b/test/system/040-ps.bats
new file mode 100644
index 000000000..dec2df4d5
--- /dev/null
+++ b/test/system/040-ps.bats
@@ -0,0 +1,38 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "podman ps - basic tests" {
+ rand_name=$(random_string 30)
+
+ run_podman run -d --name $rand_name $IMAGE sleep 5
+ cid=$output
+ is "$cid" "[0-9a-f]\{64\}$"
+
+ # Special case: formatted ps
+ run_podman ps --no-trunc \
+ --format '{{.ID}} {{.Image}} {{.Command}} {{.Names}}'
+ is "$output" "$cid $IMAGE sleep 5 $rand_name" "podman ps"
+
+
+ # Plain old regular ps
+ run_podman ps
+ is "${lines[1]}" \
+ "${cid:0:12} \+$IMAGE \+sleep [0-9]\+ .*second.* $cname"\
+ "output from podman ps"
+
+ # OK. Wait for sleep to finish...
+ run_podman wait $cid
+
+ # ...then make sure container shows up as stopped
+ run_podman ps -a
+ is "${lines[1]}" \
+ "${cid:0:12} \+$IMAGE *sleep .* Exited .* $rand_name" \
+ "podman ps -a"
+
+
+
+ run_podman rm $cid
+}
+
+# vim: filetype=sh
diff --git a/test/system/050-stop.bats b/test/system/050-stop.bats
new file mode 100644
index 000000000..093606ece
--- /dev/null
+++ b/test/system/050-stop.bats
@@ -0,0 +1,67 @@
+#!/usr/bin/env bats
+
+load helpers
+
+# Very simple test
+@test "podman stop - basic test" {
+ run_podman run -d $IMAGE sleep 60
+ cid="$output"
+
+ # Run 'stop'. Time how long it takes.
+ t0=$SECONDS
+ run_podman stop $cid
+ t1=$SECONDS
+
+ # Confirm that container is stopped
+ run_podman inspect --format '{{.State.Status}} {{.State.ExitCode}}' $cid
+ is "$output" "exited \+137" "Status and exit code of stopped container"
+
+ # The initial SIGTERM is ignored, so this operation should take
+ # exactly 10 seconds. Give it some leeway.
+ delta_t=$(( $t1 - $t0 ))
+ [ $delta_t -gt 8 ] ||\
+ die "podman stop: ran too quickly! ($delta_t seconds; expected >= 10)"
+ [ $delta_t -le 14 ] ||\
+ die "podman stop: took too long ($delta_t seconds; expected ~10)"
+
+ run_podman rm $cid
+}
+
+
+# Test fallback
+
+
+# Regression test for #2472
+@test "podman stop - can trap signal" {
+ # Because the --time and --timeout options can be wonky, try three
+ # different variations of this test.
+ for t_opt in '' '--time=5' '--timeout=5'; do
+ # Run a simple container that logs output on SIGTERM
+ run_podman run -d $IMAGE sh -c \
+ "trap 'echo Received SIGTERM, finishing; exit' SIGTERM; echo READY; while :; do sleep 1; done"
+ cid="$output"
+ wait_for_ready $cid
+
+ # Run 'stop' against it...
+ t0=$SECONDS
+ run_podman stop $t_opt $cid
+ t1=$SECONDS
+
+ # ...the container should trap the signal, log it, and exit.
+ run_podman logs $cid
+ is "$output" ".*READY.*Received SIGTERM, finishing" "podman stop $t_opt"
+
+ # Exit code should be 0, because container did its own exit
+ run_podman inspect --format '{{.State.ExitCode}}' $cid
+ is "$output" "0" "Exit code of stopped container"
+
+ # The 'stop' command should return almost instantaneously
+ delta_t=$(( $t1 - $t0 ))
+ [ $delta_t -le 2 ] ||\
+ die "podman stop: took too long ($delta_t seconds; expected <= 2)"
+
+ run_podman rm $cid
+ done
+}
+
+# vim: filetype=sh
diff --git a/test/system/060-mount.bats b/test/system/060-mount.bats
new file mode 100644
index 000000000..3601b7b84
--- /dev/null
+++ b/test/system/060-mount.bats
@@ -0,0 +1,37 @@
+#!/usr/bin/env bats
+
+load helpers
+
+
+@test "podman mount - basic test" {
+ # Only works with root (FIXME: does it work with rootless + vfs?)
+ skip_if_rootless
+
+ f_path=/tmp/tmpfile_$(random_string 8)
+ f_content=$(random_string 30)
+
+ c_name=mount_test_$(random_string 5)
+ run_podman run --name $c_name $IMAGE \
+ sh -c "echo $f_content > $f_path"
+
+ run_podman mount $c_name
+ mount_path=$output
+
+ test -d $mount_path
+ test -e "$mount_path/$f_path"
+ is $(< "$mount_path/$f_path") "$f_content" "contents of file, as read via fs"
+
+ # Make sure that 'podman mount' (no args) returns the expected path
+ run_podman mount --notruncate
+ # FIXME: is it worth the effort to validate the CID ($1) ?
+ reported_mountpoint=$(echo "$output" | awk '{print $2}')
+ is $reported_mountpoint $mount_path "mountpoint reported by 'podman mount'"
+
+ # umount, and make sure files are gone
+ run_podman umount $c_name
+ if [ -e "$mount_path/$f_path" ]; then
+ die "Mounted file exists even after umount: $mount_path/$f_path"
+ fi
+}
+
+# vim: filetype=sh
diff --git a/test/system/070-build.bats b/test/system/070-build.bats
new file mode 100644
index 000000000..25eb36c58
--- /dev/null
+++ b/test/system/070-build.bats
@@ -0,0 +1,28 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# Tests for podman build
+#
+
+load helpers
+
+@test "podman build - basic test" {
+ rand_filename=$(random_string 20)
+ rand_content=$(random_string 50)
+
+ tmpdir=$PODMAN_TMPDIR/build-test
+ run mkdir -p $tmpdir || die "Could not mkdir $tmpdir"
+ dockerfile=$tmpdir/Dockerfile
+ cat >$dockerfile <<EOF
+FROM $IMAGE
+RUN echo $rand_content > /$rand_filename
+EOF
+
+ run_podman build -t build_test --format=docker $tmpdir
+
+ run_podman run --rm build_test cat /$rand_filename
+ is "$output" "$rand_content" "reading generated file in image"
+
+ run_podman rmi build_test
+}
+
+# vim: filetype=sh
diff --git a/test/system/110-history.bats b/test/system/110-history.bats
new file mode 100644
index 000000000..84a1e42b4
--- /dev/null
+++ b/test/system/110-history.bats
@@ -0,0 +1,49 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "podman history - basic tests" {
+ tests="
+ | .*[0-9a-f]\\\{12\\\} .* CMD .* LABEL
+--format '{{.ID}} {{.Created}}' | .*[0-9a-f]\\\{12\\\} .* ago
+--human=false | .*[0-9a-f]\\\{12\\\} *[0-9-]\\\+T[0-9:]\\\+Z
+-qH | .*[0-9a-f]\\\{12\\\}
+--no-trunc | .*[0-9a-f]\\\{64\\\}
+"
+
+ parse_table "$tests" | while read options expect; do
+ if [ "$options" = "''" ]; then options=; fi
+
+ eval set -- "$options"
+
+ run_podman history "$@" $IMAGE
+ is "$output" "$expect" "podman history $options"
+ done
+}
+
+@test "podman history - json" {
+ tests="
+id | [0-9a-f]\\\{64\\\}
+created | [0-9-]\\\+T[0-9:]\\\+\\\.[0-9]\\\+Z
+size | -\\\?[0-9]\\\+
+"
+
+ run_podman history --format json $IMAGE
+
+ parse_table "$tests" | while read field expect; do
+ # HACK: we can't include '|' in the table
+ if [ "$field" = "id" ]; then expect="$expect\|<missing>";fi
+
+ # output is an array of dicts; check each one
+ count=$(echo "$output" | jq '. | length')
+ i=0
+ while [ $i -lt $count ]; do
+ actual=$(echo "$output" | jq -r ".[$i].$field")
+ is "$actual" "$expect\$" "jq .[$i].$field"
+ i=$(expr $i + 1)
+ done
+ done
+
+}
+
+# vim: filetype=sh
diff --git a/test/system/200-pod-top.bats b/test/system/200-pod-top.bats
new file mode 100644
index 000000000..81c4be3ff
--- /dev/null
+++ b/test/system/200-pod-top.bats
@@ -0,0 +1,37 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "podman pod top - containers in different PID namespaces" {
+ skip_if_rootless
+
+ run_podman pod create
+ podid="$output"
+
+ # Start two containers...
+ run_podman run -d --pod $podid $IMAGE top -d 2
+ cid1="$output"
+ run_podman run -d --pod $podid $IMAGE top -d 2
+ cid2="$output"
+
+ # ...and wait for them to actually start.
+ wait_for_output "PID \+PPID \+USER " $cid1
+ wait_for_output "PID \+PPID \+USER " $cid2
+
+ # Both containers have emitted at least one top-like line.
+ # Now run 'pod top', and expect two 'top -d 2' processes running.
+ run_podman pod top $podid
+ is "$output" ".*root.*top -d 2.*root.*top -d 2" "two 'top' containers"
+
+ # There should be a /pause container
+ # FIXME: sometimes there is, sometimes there isn't. If anyone ever
+ # actually figures this out, please either reenable this line or
+ # remove it entirely.
+ #is "$output" ".*0 \+1 \+0 \+[0-9. ?s]\+/pause" "there is a /pause container"
+
+ # Clean up
+ run_podman pod rm -f $podid
+}
+
+
+# vim: filetype=sh
diff --git a/test/system/README.md b/test/system/README.md
new file mode 100644
index 000000000..6ac408f4e
--- /dev/null
+++ b/test/system/README.md
@@ -0,0 +1,82 @@
+Quick overview of podman system tests. The idea is to use BATS,
+but with a framework for making it easy to add new tests and to
+debug failures.
+
+Quick Start
+===========
+
+Look at [030-run.bats](030-run.bats) for a simple but packed example.
+This introduces the basic set of helper functions:
+
+* `setup` (implicit) - resets container storage so there's
+one and only one (standard) image, and no running containers.
+
+* `parse_table` - you can define tables of inputs and expected results,
+then read those in a `while` loop. This makes it easy to add new tests.
+Because bash is not a programming language, the caller of `parse_table`
+sometimes needs to massage the returned values; `015-run.bats` offers
+examples of how to deal with the more typical such issues.
+
+* `run_podman` - runs command defined in `$PODMAN` (default: 'podman'
+but could also be './bin/podman' or 'podman-remote'), with a timeout.
+Checks its exit status.
+
+* `is` - compare actual vs expected output. Emits a useful diagnostic
+on failure.
+
+* `die` - output a properly-formatted message to stderr, and fail test
+
+* `skip_if_rootless` - if rootless, skip this test with a helpful message.
+
+* `random_string` - returns a pseudorandom alphanumeric string
+
+Test files are of the form `NNN-name.bats` where NNN is a three-digit
+number. Please preserve this convention, it simplifies viewing the
+directory and understanding test order. In particular, `00x` tests
+should be reserved for a first-pass fail-fast subset of tests:
+
+ bats test/system/00*.bats || exit 1
+ bats test/system
+
+...the goal being to provide quick feedback on catastrophic failures
+without having to wait for the entire test suite.
+
+
+Analyzing test failures
+=======================
+
+The top priority for this scheme is to make it easy to diagnose
+what went wrong. To that end, `podman_run` always logs all invoked
+commands, their output and exit codes. In a normal run you will never
+see this, but BATS will display it on failure. The goal here is to
+give you everything you need to diagnose without having to rerun tests.
+
+The `is` comparison function is designed to emit useful diagnostics,
+in particular, the actual and expected strings. Please do not use
+the horrible BATS standard of `[ x = y ]`; that's nearly useless
+for tracking down failures.
+
+If the above are not enough to help you track down a failure:
+
+
+Debugging tests
+---------------
+
+Some functions have `dprint` statements. To see the output of these,
+set `PODMAN_TEST_DEBUG="funcname"` where `funcname` is the name of
+the function or perhaps just a substring.
+
+
+Requirements
+============
+
+The `jq` tool is needed for parsing JSON output.
+
+
+Further Details
+===============
+
+TBD. For now, look in [helpers.bash](helpers.bash); each helper function
+has (what are intended to be) helpful header comments. For even more
+examples, see and/or run `helpers.t`; that's a regression test
+and provides a thorough set of examples of how the helpers work.
diff --git a/test/system/TODO.md b/test/system/TODO.md
new file mode 100644
index 000000000..f6110d2e9
--- /dev/null
+++ b/test/system/TODO.md
@@ -0,0 +1,105 @@
+![PODMAN logo](../../logo/podman-logo-source.svg)
+
+# Overview
+
+System tests exercise Podman in the context of a complete, composed environment from
+distribution packages. It should match as closely as possible to how an end-user
+would experience a fresh-install. Dependencies on external configuration and resources
+must be kept minimal, and the tests must be generic and vendor-neutral.
+
+The system-tests must execute cleanly on all tested platforms. They may optionally
+be executed during continuous-integration testing of code-changes, after all other
+testing completes successfully. For a list of tested platforms, please see [the
+CI configuration file.](../../.cirrus.yml)
+
+
+# Execution
+
+When working from a clone of [the libpod repository](https://github.com/containers/libpod),
+the main entry-point for humans and automation is `make localsystem`. When operating
+from a packaged version of the system-tests, the entry-point may vary as appropriate.
+Running the packaged system-tests assumes the version of Podman matches the test
+version, and all standard dependencies are installed.
+
+
+# Test Design and overview
+
+System-tests should be high-level and user work-flow oriented. For example, consider
+how multiple Podman invocations would be used together by an end-user. The set of
+related commands should be considered a single test. If one or more intermediate
+commands fail, the test could still pass if the end-result is still achieved.
+
+
+# *TODO*: List of needed System-tests
+
+***Note***: Common operations (like `rm` and `rmi` for cleanup/reset)
+have been omitted as they are verified by repeated implied use.
+
+- [ ] pull, build, run, attach, commit, diff, inspect
+
+ - Pull existing image from registry
+ - Build new image FROM explicitly pulled image
+ - Run built container in detached mode
+ - Attach to running container, execute command to modify storage.
+ - Commit running container to new image w/ changed ENV VAR
+ - Verify attach + commit using diff
+ - verify changed ENV VAR with inspect
+
+- [ ] Implied pull, create, start, exec, log, stop, wait, rm
+
+ - Create non-existing local image
+ - start stopped container
+ - exec simple command in running container
+ - verify exec result with log
+ - wait on running container
+ - stop running container with 2 second timeout
+ - verify wait in 4 seconds or less
+ - verify stopped by rm **without** --force
+
+- [ ] Implied pull, build, export, modify, import, tag, run, kill
+
+ - Build from Dockerfile FROM non-existing local image
+ - Export built container as tarball
+ - Modify tarball contents
+ - Import tarball
+ - Tag imported image
+ - Run imported image to confirm tarball modification, block on non-special signal
+ - Kill can send non-TERM/KILL signal to container to exit
+ - Confirm exit within timeout
+
+- [ ] Container runlabel, exists, checkpoint, exists, restore, stop, prune
+
+ - Using pre-existing remote image, start it with 'podman container runlabel --pull'
+ - Run a named container that exits immediatly
+ - Confirm 'container exists' zero exit (both containers)
+ - Checkpoint the running container
+ - Confirm 'container exists' non-zero exit (runlabel container)
+ - Confirm 'container exists' zero exit (named container)
+ - Run 'container restore'
+ - Confirm 'container exists' zero exit (both containers)
+ - Stop container
+ - Run 'container prune'
+ - Confirm `podman ps -a` lists no containers
+
+
+# TODO: List of commands to be combined into additional workflows above.
+
+- podman-remote (workflow TBD)
+- history
+- image
+- load
+- mount
+- pause
+- pod
+- port
+- login, push, & logout (difficult, save for last)
+- restart
+- save
+- search
+- stats
+- top
+- umount, unmount
+- unpause
+- volume
+- `--namespace`
+- `--storage-driver`
diff --git a/test/system/helpers.bash b/test/system/helpers.bash
new file mode 100644
index 000000000..431228498
--- /dev/null
+++ b/test/system/helpers.bash
@@ -0,0 +1,349 @@
+# -*- bash -*-
+
+# Podman command to run; may be podman-remote
+PODMAN=${PODMAN:-podman}
+
+# Standard image to use for most tests
+PODMAN_TEST_IMAGE_REGISTRY=${PODMAN_TEST_IMAGE_REGISTRY:-"quay.io"}
+PODMAN_TEST_IMAGE_USER=${PODMAN_TEST_IMAGE_USER:-"libpod"}
+PODMAN_TEST_IMAGE_NAME=${PODMAN_TEST_IMAGE_NAME:-"alpine_labels"}
+PODMAN_TEST_IMAGE_TAG=${PODMAN_TEST_IMAGE_TAG:-"latest"}
+PODMAN_TEST_IMAGE_FQN="$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG"
+
+# Because who wants to spell that out each time?
+IMAGE=$PODMAN_TEST_IMAGE_FQN
+
+# Default timeout for a podman command.
+PODMAN_TIMEOUT=${PODMAN_TIMEOUT:-60}
+
+###############################################################################
+# BEGIN setup/teardown tools
+
+# Provide common setup and teardown functions, but do not name them such!
+# That way individual tests can override with their own setup/teardown,
+# while retaining the ability to include these if they so desire.
+
+# Setup helper: establish a test environment with exactly the images needed
+function basic_setup() {
+ # Clean up all containers
+ run_podman rm --all --force
+
+ # Clean up all images except those desired
+ found_needed_image=
+ run_podman images --all --format '{{.Repository}}:{{.Tag}} {{.ID}}'
+ for line in "${lines[@]}"; do
+ set $line
+ if [ "$1" == "$PODMAN_TEST_IMAGE_FQN" ]; then
+ found_needed_image=1
+ else
+ echo "# setup(): removing stray images" >&3
+ run_podman rmi --force "$1" >/dev/null 2>&1 || true
+ run_podman rmi --force "$2" >/dev/null 2>&1 || true
+ fi
+ done
+
+ # Make sure desired images are present
+ if [ -z "$found_needed_image" ]; then
+ run_podman pull "$PODMAN_TEST_IMAGE_FQN"
+ fi
+
+ # Argh. Although BATS provides $BATS_TMPDIR, it's just /tmp!
+ # That's bloody worthless. Let's make our own, in which subtests
+ # can write whatever they like and trust that it'll be deleted
+ # on cleanup.
+ # TODO: do this outside of setup, so it carries across tests?
+ PODMAN_TMPDIR=$(mktemp -d --tmpdir=${BATS_TMPDIR:-/tmp} podman_bats.XXXXXX)
+}
+
+# Basic teardown: remove all pods and containers
+function basic_teardown() {
+ echo "# [teardown]" >&2
+ run_podman '?' pod rm --all --force
+ run_podman '?' rm --all --force
+
+ /bin/rm -rf $PODMAN_TMPDIR
+}
+
+
+# Provide the above as default methods.
+function setup() {
+ basic_setup
+}
+
+function teardown() {
+ basic_teardown
+}
+
+
+# Helpers useful for tests running rmi
+function archive_image() {
+ local image=$1
+
+ # FIXME: refactor?
+ archive_basename=$(echo $1 | tr -c a-zA-Z0-9._- _)
+ archive=$BATS_TMPDIR/$archive_basename.tar
+
+ run_podman save -o $archive $image
+}
+
+function restore_image() {
+ local image=$1
+
+ archive_basename=$(echo $1 | tr -c a-zA-Z0-9._- _)
+ archive=$BATS_TMPDIR/$archive_basename.tar
+
+ run_podman restore $archive
+}
+
+# END setup/teardown tools
+###############################################################################
+# BEGIN podman helpers
+
+################
+# run_podman # Invoke $PODMAN, with timeout, using BATS 'run'
+################
+#
+# This is the preferred mechanism for invoking podman: first, it
+# invokes $PODMAN, which may be 'podman-remote' or '/some/path/podman'.
+#
+# Second, we use 'timeout' to abort (with a diagnostic) if something
+# takes too long; this is preferable to a CI hang.
+#
+# Third, we log the command run and its output. This doesn't normally
+# appear in BATS output, but it will if there's an error.
+#
+# Next, we check exit status. Since the normal desired code is 0,
+# that's the default; but the first argument can override:
+#
+# run_podman 125 nonexistent-subcommand
+# run_podman '?' some-other-command # let our caller check status
+#
+# Since we use the BATS 'run' mechanism, $output and $status will be
+# defined for our caller.
+#
+function run_podman() {
+ # Number as first argument = expected exit code; default 0
+ expected_rc=0
+ case "$1" in
+ [0-9]) expected_rc=$1; shift;;
+ [1-9][0-9]) expected_rc=$1; shift;;
+ [12][0-9][0-9]) expected_rc=$1; shift;;
+ '?') expected_rc= ; shift;; # ignore exit code
+ esac
+
+ # stdout is only emitted upon error; this echo is to help a debugger
+ echo "\$ $PODMAN $*"
+ run timeout --foreground -v --kill=10 $PODMAN_TIMEOUT $PODMAN "$@"
+ # without "quotes", multiple lines are glommed together into one
+ if [ -n "$output" ]; then
+ echo "$output"
+ fi
+ if [ "$status" -ne 0 ]; then
+ echo -n "[ rc=$status ";
+ if [ -n "$expected_rc" ]; then
+ if [ "$status" -eq "$expected_rc" ]; then
+ echo -n "(expected) ";
+ else
+ echo -n "(** EXPECTED $expected_rc **) ";
+ fi
+ fi
+ echo "]"
+ fi
+
+ if [ "$status" -eq 124 ]; then
+ if expr "$output" : ".*timeout: sending" >/dev/null; then
+ echo "*** TIMED OUT ***"
+ false
+ fi
+ fi
+
+ if [ -n "$expected_rc" ]; then
+ if [ "$status" -ne "$expected_rc" ]; then
+ die "exit code is $status; expected $expected_rc"
+ fi
+ fi
+}
+
+
+# Wait for certain output from a container, indicating that it's ready.
+function wait_for_output {
+ local sleep_delay=5
+ local how_long=$PODMAN_TIMEOUT
+ local expect=
+ local cid=
+
+ # Arg processing. A single-digit number is how long to sleep between
+ # iterations; a 2- or 3-digit number is the total time to wait; all
+ # else are, in order, the string to expect and the container name/ID.
+ local i
+ for i in "$@"; do
+ if expr "$i" : '[0-9]\+$' >/dev/null; then
+ if [ $i -le 9 ]; then
+ sleep_delay=$i
+ else
+ how_long=$i
+ fi
+ elif [ -z "$expect" ]; then
+ expect=$i
+ else
+ cid=$i
+ fi
+ done
+
+ [ -n "$cid" ] || die "FATAL: wait_for_ready: no container name/ID in '$*'"
+
+ t1=$(expr $SECONDS + $how_long)
+ while [ $SECONDS -lt $t1 ]; do
+ run_podman logs $cid
+ if expr "$output" : ".*$expect" >/dev/null; then
+ return
+ fi
+
+ sleep $sleep_delay
+ done
+
+ die "timed out waiting for '$expect' from $cid"
+}
+
+# Shortcut for the lazy
+function wait_for_ready {
+ wait_for_output 'READY' "$@"
+}
+
+# END podman helpers
+###############################################################################
+# BEGIN miscellaneous tools
+
+######################
+# skip_if_rootless # ...with an optional message
+######################
+function skip_if_rootless() {
+ if [ "$(id -u)" -eq 0 ]; then
+ return
+ fi
+
+ skip "${1:-not applicable under rootless podman}"
+}
+
+
+#########
+# die # Abort with helpful message
+#########
+function die() {
+ echo "#/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv" >&2
+ echo "#| FAIL: $*" >&2
+ echo "#\\^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" >&2
+ false
+}
+
+
+########
+# is # Compare actual vs expected string; fail w/diagnostic if mismatch
+########
+#
+# Compares given string against expectations, using 'expr' to allow patterns.
+#
+# Examples:
+#
+# is "$actual" "$expected" "descriptive test name"
+# is "apple" "orange" "name of a test that will fail in most universes"
+# is "apple" "[a-z]\+" "this time it should pass"
+#
+function is() {
+ local actual="$1"
+ local expect="$2"
+ local testname="${3:-FIXME}"
+
+ if [ -z "$expect" ]; then
+ if [ -z "$actual" ]; then
+ return
+ fi
+ expect='[no output]'
+ elif expr "$actual" : "$expect" >/dev/null; then
+ return
+ fi
+
+ # This is a multi-line message, which may in turn contain multi-line
+ # output, so let's format it ourself, readably
+ local -a actual_split
+ readarray -t actual_split <<<"$actual"
+ printf "#/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n" >&2
+ printf "#| FAIL: $testname\n" >&2
+ printf "#| expected: '%s'\n" "$expect" >&2
+ printf "#| actual: '%s'\n" "${actual_split[0]}" >&2
+ local line
+ for line in "${actual_split[@]:1}"; do
+ printf "#| > '%s'\n" "$line" >&2
+ done
+ printf "#\\^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" >&2
+ false
+}
+
+
+############
+# dprint # conditional debug message
+############
+#
+# Set PODMAN_TEST_DEBUG to the name of one or more functions you want to debug
+#
+# Examples:
+#
+# $ PODMAN_TEST_DEBUG=parse_table bats .
+# $ PODMAN_TEST_DEBUG="test_podman_images test_podman_run" bats .
+#
+function dprint() {
+ test -z "$PODMAN_TEST_DEBUG" && return
+
+ caller="${FUNCNAME[1]}"
+
+ # PODMAN_TEST_DEBUG is a space-separated list of desired functions
+ # e.g. "parse_table test_podman_images" (or even just "table")
+ for want in $PODMAN_TEST_DEBUG; do
+ # Check if our calling function matches any of the desired strings
+ if expr "$caller" : ".*$want" >/dev/null; then
+ echo "# ${FUNCNAME[1]}() : $*" >&3
+ return
+ fi
+ done
+}
+
+
+#################
+# parse_table # Split a table on '|' delimiters; return space-separated
+#################
+#
+# See sample .bats scripts for examples. The idea is to list a set of
+# tests in a table, then use simple logic to iterate over each test.
+# Columns are separated using '|' (pipe character) because sometimes
+# we need spaces in our fields.
+#
+function parse_table() {
+ while read line; do
+ test -z "$line" && continue
+
+ declare -a row=()
+ while read col; do
+ dprint "col=<<$col>>"
+ row+=("$col")
+ done < <(echo "$line" | tr '|' '\012' | sed -e 's/^ *//' -e 's/\\/\\\\/g')
+
+ printf "%q " "${row[@]}"
+ printf "\n"
+ done <<<"$1"
+}
+
+
+###################
+# random_string # Returns a pseudorandom human-readable string
+###################
+#
+# Numeric argument, if present, is desired length of string
+#
+function random_string() {
+ local length=${1:-10}
+
+ head /dev/urandom | tr -dc a-zA-Z0-9 | head -c$length
+}
+
+# END miscellaneous tools
+###############################################################################
diff --git a/test/system/helpers.t b/test/system/helpers.t
new file mode 100755
index 000000000..7b4e48a84
--- /dev/null
+++ b/test/system/helpers.t
@@ -0,0 +1,145 @@
+#!/bin/bash
+#
+# regression tests for helpers.bash
+#
+# Some of those helper functions are fragile, and we don't want to break
+# anything if we have to mess with them.
+#
+
+source $(dirname $0)/helpers.bash
+
+die() {
+ echo "$(basename $0): $*" >&2
+ exit 1
+}
+
+# Iterator and return code; updated in check_result()
+testnum=0
+rc=0
+
+###############################################################################
+# BEGIN test the parse_table helper
+
+function check_result {
+ testnum=$(expr $testnum + 1)
+ if [ "$1" = "$2" ]; then
+ echo "ok $testnum $3 = $1"
+ else
+ echo "not ok $testnum $3"
+ echo "# expected: $2"
+ echo "# actual: $1"
+ rc=1
+ fi
+}
+
+# IMPORTANT NOTE: you have to do
+# this: while ... done < <(parse_table)
+# and not: parse_table | while read ...
+#
+# ...because piping to 'while' makes it a subshell, hence testnum and rc
+# will not be updated.
+#
+while read x y z; do
+ check_result "$x" "a" "parse_table simple: column 1"
+ check_result "$y" "b" "parse_table simple: column 2"
+ check_result "$z" "c" "parse_table simple: column 3"
+done < <(parse_table "a | b | c")
+
+# More complicated example, with spaces
+while read x y z; do
+ check_result "$x" "a b" "parse_table with spaces: column 1"
+ check_result "$y" "c d" "parse_table with spaces: column 2"
+ check_result "$z" "e f g" "parse_table with spaces: column 3"
+done < <(parse_table "a b | c d | e f g")
+
+# Multi-row, with spaces and with blank lines
+table="
+a | b | c d e
+d e f | g h | i j
+"
+declare -A expect=(
+ [0,0]="a"
+ [0,1]="b"
+ [0,2]="c d e"
+ [1,0]="d e f"
+ [1,1]="g h"
+ [1,2]="i j"
+)
+row=0
+while read x y z;do
+ check_result "$x" "${expect[$row,0]}" "parse_table multi_row[$row,0]"
+ check_result "$y" "${expect[$row,1]}" "parse_table multi_row[$row,1]"
+ check_result "$z" "${expect[$row,2]}" "parse_table multi_row[$row,2]"
+ row=$(expr $row + 1)
+done < <(parse_table "$table")
+
+# Backslash handling. The first element should have none, the second some
+while read x y;do
+ check_result "$x" '[0-9]{2}' "backslash test - no backslashes"
+ check_result "$y" '[0-9]\{3\}' "backslash test - one backslash each"
+done < <(parse_table "[0-9]{2} | [0-9]\\\{3\\\}")
+
+# Empty strings. I wish we could convert those to real empty strings.
+while read x y z; do
+ check_result "$x" "''" "empty string - left-hand"
+ check_result "$y" "''" "empty string - middle"
+ check_result "$z" "''" "empty string - right"
+done < <(parse_table " | |")
+
+# Quotes
+while read x y z;do
+ check_result "$x" "a 'b c'" "single quotes"
+ check_result "$y" "d \"e f\" g" "double quotes"
+ check_result "$z" "h" "no quotes"
+
+ # FIXME FIXME FIXME: this is the only way I can find to get bash-like
+ # splitting of tokens. It really should be done inside parse_table
+ # but I can't find any way of doing so. If you can find a way, please
+ # update this test and any BATS tests that rely on quoting.
+ eval set "$x"
+ check_result "$1" "a" "single quotes - token split - 1"
+ check_result "$2" "b c" "single quotes - token split - 2"
+ check_result "$3" "" "single quotes - token split - 3"
+
+ eval set "$y"
+ check_result "$1" "d" "double quotes - token split - 1"
+ check_result "$2" "e f" "double quotes - token split - 2"
+ check_result "$3" "g" "double quotes - token split - 3"
+done < <(parse_table "a 'b c' | d \"e f\" g | h")
+
+# END test the parse_table helper
+###############################################################################
+# BEGIN dprint
+
+function dprint_test_1() {
+ dprint "$*"
+}
+
+# parse_table works, might as well use it
+#
+# <value of PODMAN_TEST_DEBUG> | <blank for no msg, - for msg> | <desc>
+#
+table="
+ | | debug unset
+dprint_test | - | substring match
+dprint_test_1 | - | exact match
+dprint_test_10 | | caller name mismatch
+xxx yyy zzz | | multiple callers, no match
+dprint_test_1 xxx yyy zzz | - | multiple callers, match at start
+xxx dprint_test_1 yyy zzz | - | multiple callers, match in middle
+xxx yyy zzz dprint_test_1 | - | multiple callers, match at end
+"
+while read var expect name; do
+ random_string=$(random_string 20)
+ PODMAN_TEST_DEBUG="$var" result=$(dprint_test_1 "$random_string" 3>&1)
+ expect_full=""
+ if [ -n "$expect" -a "$expect" != "''" ]; then
+ expect_full="# dprint_test_1() : $random_string"
+ fi
+ check_result "$result" "$expect_full" "DEBUG='$var' - $name"
+done < <(parse_table "$table")
+
+# END dprint
+###############################################################################
+
+exit $rc
diff --git a/test/system/libpod_suite_test.go b/test/system/libpod_suite_test.go
deleted file mode 100644
index 5de50e4e7..000000000
--- a/test/system/libpod_suite_test.go
+++ /dev/null
@@ -1,217 +0,0 @@
-package system
-
-import (
- "fmt"
- "os"
- "strings"
- "testing"
-
- . "github.com/containers/libpod/test/utils"
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-var (
- PODMAN_BINARY string
- GLOBALOPTIONS = []string{"--cgroup-manager",
- "--cni-config-dir",
- "--config", "-c",
- "--conmon",
- "--cpu-profile",
- "--log-level",
- "--root",
- "--tmpdir",
- "--runroot",
- "--runtime",
- "--storage-driver",
- "--storage-opt",
- "--syslog",
- }
- PODMAN_SUBCMD = []string{"attach",
- "commit",
- "container",
- "build",
- "create",
- "diff",
- "exec",
- "export",
- "history",
- "image",
- "images",
- "import",
- "info",
- "inspect",
- "kill",
- "load",
- "login",
- "logout",
- "logs",
- "mount",
- "pause",
- "ps",
- "pod",
- "port",
- "pull",
- "push",
- "restart",
- "rm",
- "rmi",
- "run",
- "save",
- "search",
- "start",
- "stats",
- "stop",
- "tag",
- "top",
- "umount",
- "unpause",
- "version",
- "wait",
- "h",
- }
- INTEGRATION_ROOT string
- ARTIFACT_DIR = "/tmp/.artifacts"
- ALPINE = "docker.io/library/alpine:latest"
- BB = "docker.io/library/busybox:latest"
- BB_GLIBC = "docker.io/library/busybox:glibc"
- fedoraMinimal = "registry.fedoraproject.org/fedora-minimal:latest"
- nginx = "quay.io/baude/alpine_nginx:latest"
- redis = "docker.io/library/redis:alpine"
- registry = "docker.io/library/registry:2"
- infra = "k8s.gcr.io/pause:3.1"
- defaultWaitTimeout = 90
-)
-
-// PodmanTestSystem struct for command line options
-type PodmanTestSystem struct {
- PodmanTest
- GlobalOptions map[string]string
- PodmanCmdOptions map[string][]string
-}
-
-// TestLibpod ginkgo master function
-func TestLibpod(t *testing.T) {
- RegisterFailHandler(Fail)
- RunSpecs(t, "Libpod Suite")
-}
-
-var _ = BeforeSuite(func() {
-})
-
-// PodmanTestCreate creates a PodmanTestSystem instance for the tests
-func PodmanTestCreate(tempDir string) *PodmanTestSystem {
- var envKey string
- globalOptions := make(map[string]string)
- podmanCmdOptions := make(map[string][]string)
-
- for _, n := range GLOBALOPTIONS {
- envKey = strings.Replace(strings.ToUpper(strings.Trim(n, "-")), "-", "_", -1)
- if isEnvSet(envKey) {
- globalOptions[n] = os.Getenv(envKey)
- }
- }
-
- for _, n := range PODMAN_SUBCMD {
- envKey = strings.Replace("PODMAN_SUBCMD_OPTIONS", "SUBCMD", strings.ToUpper(n), -1)
- if isEnvSet(envKey) {
- podmanCmdOptions[n] = strings.Split(os.Getenv(envKey), " ")
- }
- }
-
- podmanBinary := "podman"
- if os.Getenv("PODMAN_BINARY") != "" {
- podmanBinary = os.Getenv("PODMAN_BINARY")
- }
-
- p := &PodmanTestSystem{
- PodmanTest: PodmanTest{
- PodmanBinary: podmanBinary,
- ArtifactPath: ARTIFACT_DIR,
- TempDir: tempDir,
- },
- GlobalOptions: globalOptions,
- PodmanCmdOptions: podmanCmdOptions,
- }
-
- p.PodmanMakeOptions = p.makeOptions
-
- return p
-}
-
-func (p *PodmanTestSystem) Podman(args []string) *PodmanSession {
- return p.PodmanBase(args)
-}
-
-//MakeOptions assembles all the podman options
-func (p *PodmanTestSystem) makeOptions(args []string) []string {
- var addOptions, subArgs []string
- for _, n := range GLOBALOPTIONS {
- if p.GlobalOptions[n] != "" {
- addOptions = append(addOptions, n, p.GlobalOptions[n])
- }
- }
-
- if len(args) == 0 {
- return addOptions
- }
-
- subCmd := args[0]
- addOptions = append(addOptions, subCmd)
- if subCmd == "unmount" {
- subCmd = "umount"
- }
- if subCmd == "help" {
- subCmd = "h"
- }
-
- if _, ok := p.PodmanCmdOptions[subCmd]; ok {
- m := make(map[string]bool)
- subArgs = p.PodmanCmdOptions[subCmd]
- for i := 0; i < len(subArgs); i++ {
- m[subArgs[i]] = true
- }
- for i := 1; i < len(args); i++ {
- if _, ok := m[args[i]]; !ok {
- subArgs = append(subArgs, args[i])
- }
- }
- } else {
- subArgs = args[1:]
- }
-
- addOptions = append(addOptions, subArgs...)
-
- return addOptions
-}
-
-// Cleanup cleans up the temporary store
-func (p *PodmanTestSystem) Cleanup() {
- // Remove all containers
- stopall := p.Podman([]string{"stop", "-a", "--timeout", "0"})
- stopall.WaitWithDefaultTimeout()
-
- session := p.Podman([]string{"rm", "-fa"})
- session.Wait(90)
- // Nuke tempdir
- if err := os.RemoveAll(p.TempDir); err != nil {
- fmt.Printf("%q\n", err)
- }
-}
-
-// CleanupPod cleans up the temporary store
-func (p *PodmanTestSystem) CleanupPod() {
- // Remove all containers
- session := p.Podman([]string{"pod", "rm", "-fa"})
- session.Wait(90)
- // Nuke tempdir
- if err := os.RemoveAll(p.TempDir); err != nil {
- fmt.Printf("%q\n", err)
- }
-}
-
-// Check if the key is set in Env
-func isEnvSet(key string) bool {
- _, set := os.LookupEnv(key)
- return set
-}
diff --git a/test/system/version_test.go b/test/system/version_test.go
deleted file mode 100644
index ada0093b7..000000000
--- a/test/system/version_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package system
-
-import (
- "fmt"
- "os"
- "regexp"
-
- . "github.com/containers/libpod/test/utils"
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("Podman version test", func() {
- var (
- tempdir string
- err error
- podmanTest *PodmanTestSystem
- )
-
- BeforeEach(func() {
- tempdir, err = CreateTempDirInTempDir()
- if err != nil {
- os.Exit(1)
- }
- podmanTest = PodmanTestCreate(tempdir)
- })
-
- AfterEach(func() {
- podmanTest.Cleanup()
- f := CurrentGinkgoTestDescription()
- timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds())
- GinkgoWriter.Write([]byte(timedResult))
- })
-
- It("Smoking test: podman version with extra args", func() {
- logc := podmanTest.Podman([]string{"version", "anything", "-", "--"})
- logc.WaitWithDefaultTimeout()
- Expect(logc.ExitCode()).To(Equal(0))
- ver := logc.OutputToString()
- Expect(regexp.MatchString("Version:.*?Go Version:.*?OS/Arch", ver)).To(BeTrue())
- })
-
- It("Negative test: podman version with extra flag", func() {
- logc := podmanTest.Podman([]string{"version", "--foo"})
- logc.WaitWithDefaultTimeout()
- Expect(logc.ExitCode()).NotTo(Equal(0))
- err, _ := logc.GrepString("Incorrect Usage: flag provided but not defined: -foo")
- Expect(err).To(BeTrue())
- })
-
-})
diff --git a/test/test_podman_baseline.sh b/test/test_podman_baseline.sh
index 664fd2b03..5c24229bb 100755
--- a/test/test_podman_baseline.sh
+++ b/test/test_podman_baseline.sh
@@ -19,6 +19,7 @@
#######
# See if we want to stop on errors and/or install and then remove Docker.
#######
+HOST_PORT="${HOST_PORT:-8080}"
showerror=0
installdocker=0
usedocker=1
@@ -78,7 +79,99 @@ echo $image
########
# Run container and display contents in /etc
########
-podman run $image ls -alF /etc
+podman run --rm $image ls -alF /etc
+
+########
+# Test networking, bind mounting a file, stdin/stdout redirect
+########
+echo "Testing networking: ..."
+port_test_failed=0
+txt1="Hello, Podman"
+echo "$txt1" > /tmp/hello.txt
+podman run -d --name myweb -p "$HOST_PORT:80" -w /var/www -v /tmp/hello.txt:/var/www/index.txt busybox httpd -f -p 80
+echo "$txt1" | podman exec -i myweb sh -c "cat > /var/www/index2.txt"
+txt2=$( podman exec myweb cat /var/www/index2.txt )
+[ "x$txt1" == "x$txt2" ] && echo "PASS1" || { echo "FAIL1"; port_test_failed=1; }
+txt2=$( podman run --rm --net host busybox wget -qO - http://localhost:$HOST_PORT/index.txt )
+[ "x$txt1" == "x$txt2" ] && echo "PASS2" || { echo "FAIL2"; port_test_failed=1; }
+txt2=$( podman run --rm --net host busybox wget -qO - http://localhost:$HOST_PORT/index2.txt )
+[ "x$txt1" == "x$txt2" ] && echo "PASS3" || { echo "FAIL3"; port_test_failed=1; }
+# podman run --rm --net container:myweb --add-host myweb:127.0.0.1 busybox wget -qO - http://myweb/index.txt
+rm /tmp/hello.txt
+podman stop myweb
+podman rm myweb
+[ "0$port_test_failed" -eq 1 ] && [ "0$showerror" -eq 1 ] && {
+ echo "networking test failed";
+ exit -1;
+}
+
+
+########
+# pull and run many containers in parallel, test locks ..etc.
+########
+prun_test_failed=0
+podman rmi docker.io/library/busybox:latest > /dev/null || :
+for i in `seq 10`
+do ( podman run -d --name b$i docker.io/library/busybox:latest busybox httpd -f -p 80 )&
+done
+echo -e "\nwaiting for creation...\n"
+wait
+echo -e "\ndone\n"
+# assert we have 10 running containers
+count=$( podman ps -q | wc -l )
+[ "x$count" == "x10" ] && echo "PASS" || { echo "FAIL, expecting 10 found $count"; prun_test_failed=1; }
+[ "0$prun_test_failed" -eq 1 ] && [ "0$showerror" -eq 1 ] && {
+ echo "was expecting 10 running containers";
+ exit -1;
+}
+
+prun_test_failed=0
+for i in `seq 10`; do ( podman stop -t=1 b$i; podman rm b$i )& done
+echo -e "\nwaiting for deletion...\n"
+wait
+echo -e "\ndone\n"
+# assert we have 0 running containers
+count=$( podman ps -q | wc -l )
+[ "x$count" == "x0" ] && echo "PASS" || { echo "FAIL, expecting 0 found $count"; prun_test_failed=1; }
+[ "0$prun_test_failed" -eq 1 ] && [ "0$showerror" -eq 1 ] && {
+ echo "was expecting 0 running containers";
+ exit -1;
+}
+
+
+
+########
+# run many containers in parallel for an existing image, test locks ..etc.
+########
+prun_test_failed=0
+podman pull docker.io/library/busybox:latest > /dev/null || :
+for i in `seq 10`
+do ( podman run -d --name c$i docker.io/library/busybox:latest busybox httpd -f -p 80 )&
+done
+echo -e "\nwaiting for creation...\n"
+wait
+echo -e "\ndone\n"
+# assert we have 10 running containers
+count=$( podman ps -q | wc -l )
+[ "x$count" == "x10" ] && echo "PASS" || { echo "FAIL, expecting 10 found $count"; prun_test_failed=1; }
+[ "0$prun_test_failed" -eq 1 ] && [ "0$showerror" -eq 1 ] && {
+ echo "was expecting 10 running containers";
+ exit -1;
+}
+
+
+for i in `seq 10`; do ( podman stop -t=1 c$i; podman rm c$i )& done
+echo -e "\nwaiting for deletion...\n"
+wait
+echo -e "\ndone\n"
+# assert we have 0 running containers
+count=$( podman ps -q | wc -l )
+[ "x$count" == "x0" ] && echo "PASS" || { echo "FAIL, expecting 0 found $count"; prun_test_failed=1; }
+[ "0$prun_test_failed" -eq 1 ] && [ "0$showerror" -eq 1 ] && {
+ echo "was expecting 0 running containers";
+ exit -1;
+}
+
########
# Run Java in the container - should ERROR but never stop