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