aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2020-07-06 15:55:15 -0400
committerGitHub <noreply@github.com>2020-07-06 15:55:15 -0400
commite3e2b1e65930bfc40c5b60802c4d6ea175169732 (patch)
treede9fbf65281b2d9e69eaa90be2bdee96d3047d5c
parentb8ad7f241aba622b23b2cfab6fb5284cd26125e3 (diff)
parent2fb9bb20df49f665dbc7420a80dc2da57530278f (diff)
downloadpodman-e3e2b1e65930bfc40c5b60802c4d6ea175169732.tar.gz
podman-e3e2b1e65930bfc40c5b60802c4d6ea175169732.tar.bz2
podman-e3e2b1e65930bfc40c5b60802c4d6ea175169732.zip
Merge pull request #6871 from mheon/202_backports
Backports for v2.0.2
-rw-r--r--RELEASE_NOTES.md19
-rw-r--r--cmd/podman/auto-update.go2
-rw-r--r--cmd/podman/common/util.go26
-rw-r--r--cmd/podman/containers/attach.go14
-rw-r--r--cmd/podman/containers/checkpoint.go9
-rw-r--r--cmd/podman/containers/cleanup.go7
-rw-r--r--cmd/podman/containers/create.go1
-rw-r--r--cmd/podman/containers/diff.go9
-rw-r--r--cmd/podman/containers/exec.go15
-rw-r--r--cmd/podman/containers/init.go11
-rw-r--r--cmd/podman/containers/inspect.go3
-rw-r--r--cmd/podman/containers/kill.go21
-rw-r--r--cmd/podman/containers/list.go1
-rw-r--r--cmd/podman/containers/logs.go14
-rw-r--r--cmd/podman/containers/mount.go15
-rw-r--r--cmd/podman/containers/pause.go1
-rw-r--r--cmd/podman/containers/port.go23
-rw-r--r--cmd/podman/containers/ps.go14
-rw-r--r--cmd/podman/containers/restart.go18
-rw-r--r--cmd/podman/containers/restore.go11
-rw-r--r--cmd/podman/containers/rm.go17
-rw-r--r--cmd/podman/containers/run.go1
-rw-r--r--cmd/podman/containers/start.go12
-rw-r--r--cmd/podman/containers/stats.go14
-rw-r--r--cmd/podman/containers/stop.go16
-rw-r--r--cmd/podman/containers/top.go13
-rw-r--r--cmd/podman/containers/unmount.go16
-rw-r--r--cmd/podman/containers/wait.go11
-rw-r--r--cmd/podman/diff.go16
-rw-r--r--cmd/podman/generate/generate.go9
-rw-r--r--cmd/podman/healthcheck/healthcheck.go9
-rw-r--r--cmd/podman/images/build.go10
-rw-r--r--cmd/podman/images/diff.go4
-rw-r--r--cmd/podman/images/image.go9
-rw-r--r--cmd/podman/images/search.go1
-rw-r--r--cmd/podman/inspect.go9
-rw-r--r--cmd/podman/inspect/inspect.go3
-rw-r--r--cmd/podman/main.go11
-rw-r--r--cmd/podman/manifest/manifest.go9
-rw-r--r--cmd/podman/manifest/push.go1
-rw-r--r--cmd/podman/networks/network.go9
-rw-r--r--cmd/podman/parse/common.go112
-rw-r--r--cmd/podman/play/kube.go1
-rw-r--r--cmd/podman/play/play.go9
-rw-r--r--cmd/podman/pods/inspect.go6
-rw-r--r--cmd/podman/pods/kill.go13
-rw-r--r--cmd/podman/pods/pause.go11
-rw-r--r--cmd/podman/pods/pod.go9
-rw-r--r--cmd/podman/pods/ps.go7
-rw-r--r--cmd/podman/pods/restart.go9
-rw-r--r--cmd/podman/pods/rm.go10
-rw-r--r--cmd/podman/pods/start.go9
-rw-r--r--cmd/podman/pods/stats.go7
-rw-r--r--cmd/podman/pods/stop.go9
-rw-r--r--cmd/podman/pods/top.go9
-rw-r--r--cmd/podman/pods/unpause.go12
-rw-r--r--cmd/podman/registry/config.go16
-rw-r--r--cmd/podman/registry/remote.go19
-rw-r--r--cmd/podman/root.go74
-rw-r--r--cmd/podman/system/connection.go1
-rw-r--r--cmd/podman/system/system.go9
-rw-r--r--cmd/podman/validate/args.go119
-rw-r--r--cmd/podman/validate/latest.go15
-rw-r--r--cmd/podman/volumes/volume.go9
-rw-r--r--docs/source/markdown/podman-auto-update.1.md3
-rw-r--r--docs/source/markdown/podman-create.1.md2
-rw-r--r--docs/source/markdown/podman-run.1.md3
-rw-r--r--docs/source/markdown/podman-system-service.1.md4
-rw-r--r--libpod/container_internal.go52
-rw-r--r--libpod/define/errors.go4
-rw-r--r--libpod/events.go13
-rw-r--r--libpod/events/config.go3
-rw-r--r--libpod/events/journal_linux.go3
-rw-r--r--libpod/events/logfile.go17
-rw-r--r--libpod/events/nullout.go6
-rw-r--r--libpod/options.go13
-rw-r--r--libpod/pod_api.go12
-rw-r--r--libpod/runtime_ctr.go2
-rw-r--r--libpod/volume.go36
-rw-r--r--libpod/volume_inspect.go11
-rw-r--r--pkg/api/handlers/compat/events.go6
-rw-r--r--pkg/api/handlers/compat/networks.go2
-rw-r--r--pkg/api/handlers/libpod/volumes.go30
-rw-r--r--pkg/api/server/server.go4
-rw-r--r--pkg/domain/infra/abi/containers.go4
-rw-r--r--pkg/domain/infra/abi/events.go2
-rw-r--r--pkg/domain/infra/abi/pods.go36
-rw-r--r--pkg/domain/infra/abi/volumes.go26
-rw-r--r--pkg/spec/createconfig.go9
-rw-r--r--pkg/specgen/generate/oci.go20
-rw-r--r--pkg/specgen/generate/ports.go112
-rw-r--r--pkg/specgen/specgen.go3
-rw-r--r--pkg/systemd/generate/common.go5
-rw-r--r--pkg/systemd/generate/common_test.go9
-rw-r--r--pkg/terminal/console_unix.go8
-rw-r--r--pkg/terminal/console_windows.go37
-rw-r--r--pkg/varlinkapi/attach.go3
-rw-r--r--pkg/varlinkapi/events.go3
-rw-r--r--test/e2e/common_test.go10
-rw-r--r--test/e2e/ps_test.go11
-rw-r--r--test/e2e/run_networking_test.go24
-rw-r--r--test/e2e/run_userns_test.go27
102 files changed, 939 insertions, 565 deletions
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 44b64f977..c843bd091 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,24 @@
# Release Notes
+## 2.0.2
+### Bugfixes
+- Fixed a bug where the `podman ps` command would not truncate long container commands, resulting in display issues as the column could become extremely wide (the `--no-trunc` flag can be used to print the full command).
+- Fixed a bug where `podman pod` commands operationg on multiple containers (e.g. `podman pod stop` and `podman pod kill`) would not print errors from individual containers, but only a warning that some containers had failed.
+- Fixed a bug where the `podman system service` command would panic if a connection to the Events endpoint hung up early ([#6805](https://github.com/containers/libpod/issues/6805)).
+- Fixed a bug where rootless Podman would create anonymous and named volumes with the wrong owner for containers run with the `--user` directive.
+- Fixed a bug where the `TMPDIR` environment variable was not being defaulted (if unset) to `/var/tmp`.
+- Fixed a bug where the `--publish` flag to `podman create` and `podman run` required that a host port be specified if an IP address was given ([#6806](https://github.com/containers/libpod/issues/6806)).
+- Fixed a bug where in `podman-remote` commands performing an attach (`podman run`, `podman attach`, `podman start --attach`, `podman exec`) did not properly configure the terminal on Windows.
+- Fixed a bug where the `--remote` flag to Podman required an argument, despite being a boolean ([#6704](https://github.com/containers/libpod/issues/6704)).
+- Fixed a bug where the `podman generate systemd --new` command could generate incorrect unit files for a pod if a container in the pod was created using the `--pod=...` flag (with an =, instead of a space, before the pod ID) ([#6766](https://github.com/containers/libpod/issues/6766)).
+- Fixed a bug where `NPROC` and `NOFILE` rlimits could be improperly set for rootless Podman containers
+
+### API
+- Fixed a bug where the timestamp format for Libpod image list endpoint was incorrect - the format has been switched to Unix time.
+- Fixed a bug where the compatability Create endpoint did not handle empty entrypoints properly.
+- Fixed a bug where the compatibility network remove endpoint would improperly handle errors where the network was not found
+- Fixed a bug where containers would be created with improper permissions because of a umask issue ([#6787](https://github.com/containers/libpod/issues/6787))
+
## 2.0.1
### Changes
- The `podman system connection` command was mistakenly omitted from the 2.0 release, and has been included here.
diff --git a/cmd/podman/auto-update.go b/cmd/podman/auto-update.go
index 7a67f3d18..a12eeb6cb 100644
--- a/cmd/podman/auto-update.go
+++ b/cmd/podman/auto-update.go
@@ -16,6 +16,8 @@ var (
autoUpdateDescription = `Auto update containers according to their auto-update policy.
Auto-update policies are specified with the "io.containers.autoupdate" label.
+ Containers are expected to run in systemd units created with "podman-generate-systemd --new",
+ or similar units that create new containers in order to run the updated images.
Note that this command is experimental. Please refer to the podman-auto-update(1) man page for details.`
autoUpdateCommand = &cobra.Command{
Use: "auto-update [flags]",
diff --git a/cmd/podman/common/util.go b/cmd/podman/common/util.go
index a3ce6198c..e21e349d9 100644
--- a/cmd/podman/common/util.go
+++ b/cmd/podman/common/util.go
@@ -184,22 +184,24 @@ func parseSplitPort(hostIP, hostPort *string, ctrPort string, protocol *string)
}
if hostPort != nil {
if *hostPort == "" {
- return newPort, errors.Errorf("must provide a non-empty container host port to publish")
- }
- hostStart, hostLen, err := parseAndValidateRange(*hostPort)
- if err != nil {
- return newPort, errors.Wrapf(err, "error parsing host port")
- }
- if hostLen != ctrLen {
- return newPort, errors.Errorf("host and container port ranges have different lengths: %d vs %d", hostLen, ctrLen)
+ // Set 0 as a placeholder. The server side of Specgen
+ // will find a random, open, unused port to use.
+ newPort.HostPort = 0
+ } else {
+ hostStart, hostLen, err := parseAndValidateRange(*hostPort)
+ if err != nil {
+ return newPort, errors.Wrapf(err, "error parsing host port")
+ }
+ if hostLen != ctrLen {
+ return newPort, errors.Errorf("host and container port ranges have different lengths: %d vs %d", hostLen, ctrLen)
+ }
+ newPort.HostPort = hostStart
}
- newPort.HostPort = hostStart
+ } else {
+ newPort.HostPort = newPort.ContainerPort
}
hport := newPort.HostPort
- if hport == 0 {
- hport = newPort.ContainerPort
- }
logrus.Debugf("Adding port mapping from %d to %d length %d protocol %q", hport, newPort.ContainerPort, newPort.Range, newPort.Protocol)
return newPort, nil
diff --git a/cmd/podman/containers/attach.go b/cmd/podman/containers/attach.go
index 6835d4e32..eca9e0787 100644
--- a/cmd/podman/containers/attach.go
+++ b/cmd/podman/containers/attach.go
@@ -44,10 +44,6 @@ func attachFlags(flags *pflag.FlagSet) {
flags.StringVar(&attachOpts.DetachKeys, "detach-keys", containerConfig.DetachKeys(), "Select the key sequence for detaching a container. Format is a single character `[a-Z]` or a comma separated sequence of `ctrl-<value>`, where `<value>` is one of: `a-z`, `@`, `^`, `[`, `\\`, `]`, `^` or `_`")
flags.BoolVar(&attachOpts.NoStdin, "no-stdin", false, "Do not attach STDIN. The default is false")
flags.BoolVar(&attachOpts.SigProxy, "sig-proxy", true, "Proxy received signals to the process")
- flags.BoolVarP(&attachOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
}
func init() {
@@ -55,22 +51,24 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: attachCommand,
})
- flags := attachCommand.Flags()
- attachFlags(flags)
+ attachFlags(attachCommand.Flags())
+ validate.AddLatestFlag(attachCommand, &attachOpts.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: containerAttachCommand,
Parent: containerCmd,
})
- containerAttachFlags := containerAttachCommand.Flags()
- attachFlags(containerAttachFlags)
+ attachFlags(containerAttachCommand.Flags())
+ validate.AddLatestFlag(containerAttachCommand, &attachOpts.Latest)
+
}
func attach(cmd *cobra.Command, args []string) error {
if len(args) > 1 || (len(args) == 0 && !attachOpts.Latest) {
return errors.Errorf("attach requires the name or id of one running container or the latest flag")
}
+
var name string
if len(args) > 0 {
name = args[0]
diff --git a/cmd/podman/containers/checkpoint.go b/cmd/podman/containers/checkpoint.go
index 6aa4304af..683437000 100644
--- a/cmd/podman/containers/checkpoint.go
+++ b/cmd/podman/containers/checkpoint.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/containers/libpod/v2/pkg/rootless"
"github.com/pkg/errors"
@@ -25,7 +25,7 @@ var (
Long: checkpointDescription,
RunE: checkpoint,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
Example: `podman container checkpoint --keep ctrID
podman container checkpoint --all
@@ -48,12 +48,9 @@ func init() {
flags.BoolVarP(&checkpointOptions.LeaveRunning, "leave-running", "R", false, "Leave the container running after writing checkpoint to disk")
flags.BoolVar(&checkpointOptions.TCPEstablished, "tcp-established", false, "Checkpoint a container with established TCP connections")
flags.BoolVarP(&checkpointOptions.All, "all", "a", false, "Checkpoint all running containers")
- flags.BoolVarP(&checkpointOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.StringVarP(&checkpointOptions.Export, "export", "e", "", "Export the checkpoint image to a tar.gz")
flags.BoolVar(&checkpointOptions.IgnoreRootFS, "ignore-rootfs", false, "Do not include root file-system changes when exporting")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
+ validate.AddLatestFlag(checkpointCommand, &checkpointOptions.Latest)
}
func checkpoint(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/containers/cleanup.go b/cmd/podman/containers/cleanup.go
index f36dcf6d4..5dea77b7a 100644
--- a/cmd/podman/containers/cleanup.go
+++ b/cmd/podman/containers/cleanup.go
@@ -3,9 +3,9 @@ package containers
import (
"fmt"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -24,7 +24,7 @@ var (
Long: cleanupDescription,
RunE: cleanup,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
Example: `podman container cleanup --latest
podman container cleanup ctrID1 ctrID2 ctrID3
@@ -44,11 +44,10 @@ func init() {
})
flags := cleanupCommand.Flags()
flags.BoolVarP(&cleanupOptions.All, "all", "a", false, "Cleans up all containers")
- flags.BoolVarP(&cleanupOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.StringVar(&cleanupOptions.Exec, "exec", "", "Clean up the given exec session instead of the container")
flags.BoolVar(&cleanupOptions.Remove, "rm", false, "After cleanup, remove the container entirely")
flags.BoolVar(&cleanupOptions.RemoveImage, "rmi", false, "After cleanup, remove the image entirely")
-
+ validate.AddLatestFlag(cleanupCommand, &cleanupOptions.Latest)
}
func cleanup(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index dffa9d7fe..cebf0fa4b 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -59,6 +59,7 @@ func createFlags(flags *pflag.FlagSet) {
flags.AddFlagSet(common.GetCreateFlags(&cliVals))
flags.AddFlagSet(common.GetNetFlags())
flags.SetNormalizeFunc(common.AliasFlags)
+
if registry.IsRemote() {
_ = flags.MarkHidden("authfile")
_ = flags.MarkHidden("env-host")
diff --git a/cmd/podman/containers/diff.go b/cmd/podman/containers/diff.go
index d61f92bb7..f39b22ede 100644
--- a/cmd/podman/containers/diff.go
+++ b/cmd/podman/containers/diff.go
@@ -14,8 +14,8 @@ var (
diffCmd = &cobra.Command{
Use: "diff [flags] CONTAINER",
Args: validate.IDOrLatestArgs,
- Short: "Inspect changes on container's file systems",
- Long: `Displays changes on a container filesystem. The container will be compared to its parent layer.`,
+ Short: "Inspect changes to the container's file systems",
+ Long: `Displays changes to the container filesystem's'. The container will be compared to its parent layer.`,
RunE: diff,
Example: `podman container diff myCtr
podman container diff -l --format json myCtr`,
@@ -35,10 +35,7 @@ func init() {
flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
_ = flags.MarkHidden("archive")
flags.StringVar(&diffOpts.Format, "format", "", "Change the output format")
-
- if !registry.IsRemote() {
- flags.BoolVarP(&diffOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- }
+ validate.AddLatestFlag(diffCmd, &diffOpts.Latest)
}
func diff(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/containers/exec.go b/cmd/podman/containers/exec.go
index 4b2f0e9a2..e0fc740b5 100644
--- a/cmd/podman/containers/exec.go
+++ b/cmd/podman/containers/exec.go
@@ -6,6 +6,7 @@ import (
"os"
"github.com/containers/libpod/v2/cmd/podman/registry"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/libpod/define"
"github.com/containers/libpod/v2/pkg/domain/entities"
envLib "github.com/containers/libpod/v2/pkg/env"
@@ -53,14 +54,13 @@ func execFlags(flags *pflag.FlagSet) {
flags.StringArrayVarP(&envInput, "env", "e", []string{}, "Set environment variables")
flags.StringSliceVar(&envFile, "env-file", []string{}, "Read in a file of environment variables")
flags.BoolVarP(&execOpts.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached")
- flags.BoolVarP(&execOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.BoolVar(&execOpts.Privileged, "privileged", false, "Give the process extended Linux capabilities inside the container. The default is false")
flags.BoolVarP(&execOpts.Tty, "tty", "t", false, "Allocate a pseudo-TTY. The default is false")
flags.StringVarP(&execOpts.User, "user", "u", "", "Sets the username or UID used and optionally the groupname or GID for the specified command")
flags.UintVar(&execOpts.PreserveFDs, "preserve-fds", 0, "Pass N additional file descriptors to the container")
flags.StringVarP(&execOpts.WorkDir, "workdir", "w", "", "Working directory inside the container")
+
if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
_ = flags.MarkHidden("preserve-fds")
}
}
@@ -70,20 +70,19 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: execCommand,
})
- flags := execCommand.Flags()
- execFlags(flags)
+ execFlags(execCommand.Flags())
+ validate.AddLatestFlag(execCommand, &execOpts.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: containerExecCommand,
Parent: containerCmd,
})
-
- containerExecFlags := containerExecCommand.Flags()
- execFlags(containerExecFlags)
+ execFlags(containerExecCommand.Flags())
+ validate.AddLatestFlag(containerExecCommand, &execOpts.Latest)
}
-func exec(cmd *cobra.Command, args []string) error {
+func exec(_ *cobra.Command, args []string) error {
var nameOrID string
if len(args) == 0 && !execOpts.Latest {
diff --git a/cmd/podman/containers/init.go b/cmd/podman/containers/init.go
index c1f166d51..98f69fa4b 100644
--- a/cmd/podman/containers/init.go
+++ b/cmd/podman/containers/init.go
@@ -3,9 +3,9 @@ package containers
import (
"fmt"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@@ -20,7 +20,7 @@ var (
Long: initDescription,
RunE: initContainer,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
Example: `podman init --latest
podman init 3c45ef19d893
@@ -45,10 +45,6 @@ var (
func initFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&initOptions.All, "all", "a", false, "Initialize all containers")
- flags.BoolVarP(&initOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
}
func init() {
@@ -58,15 +54,16 @@ func init() {
})
flags := initCommand.Flags()
initFlags(flags)
+ validate.AddLatestFlag(initCommand, &initOptions.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Parent: containerCmd,
Command: containerInitCommand,
})
-
containerInitFlags := containerInitCommand.Flags()
initFlags(containerInitFlags)
+ validate.AddLatestFlag(containerInitCommand, &initOptions.Latest)
}
func initContainer(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/containers/inspect.go b/cmd/podman/containers/inspect.go
index bea5cefd7..9ef3c2c4a 100644
--- a/cmd/podman/containers/inspect.go
+++ b/cmd/podman/containers/inspect.go
@@ -3,6 +3,7 @@ package containers
import (
"github.com/containers/libpod/v2/cmd/podman/inspect"
"github.com/containers/libpod/v2/cmd/podman/registry"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -30,7 +31,7 @@ func init() {
flags := inspectCmd.Flags()
flags.BoolVarP(&inspectOpts.Size, "size", "s", false, "Display total file size")
flags.StringVarP(&inspectOpts.Format, "format", "f", "json", "Format the output to a Go template or json")
- flags.BoolVarP(&inspectOpts.Latest, "latest", "l", false, "Act on the latest container Podman is aware of")
+ validate.AddLatestFlag(inspectCmd, &inspectOpts.Latest)
}
func inspectExec(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/containers/kill.go b/cmd/podman/containers/kill.go
index 22f7383b1..da60fcf52 100644
--- a/cmd/podman/containers/kill.go
+++ b/cmd/podman/containers/kill.go
@@ -5,9 +5,9 @@ import (
"errors"
"fmt"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/containers/libpod/v2/pkg/signal"
"github.com/spf13/cobra"
@@ -22,7 +22,7 @@ var (
Long: killDescription,
RunE: kill,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
Example: `podman kill mywebserver
podman kill 860a4b23
@@ -31,7 +31,7 @@ var (
containerKillCommand = &cobra.Command{
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
Use: killCommand.Use,
Short: killCommand.Short,
@@ -50,10 +50,6 @@ var (
func killFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&killOptions.All, "all", "a", false, "Signal all running containers")
flags.StringVarP(&killOptions.Signal, "signal", "s", "KILL", "Signal to send to the container")
- flags.BoolVarP(&killOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
}
func init() {
@@ -61,20 +57,19 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: killCommand,
})
- flags := killCommand.Flags()
- killFlags(flags)
+ killFlags(killCommand.Flags())
+ validate.AddLatestFlag(killCommand, &killOptions.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: containerKillCommand,
Parent: containerCmd,
})
-
- containerKillFlags := containerKillCommand.Flags()
- killFlags(containerKillFlags)
+ killFlags(containerKillCommand.Flags())
+ validate.AddLatestFlag(containerKillCommand, &killOptions.Latest)
}
-func kill(cmd *cobra.Command, args []string) error {
+func kill(_ *cobra.Command, args []string) error {
var (
err error
errs utils.OutputErrors
diff --git a/cmd/podman/containers/list.go b/cmd/podman/containers/list.go
index e2688623d..2d107d51d 100644
--- a/cmd/podman/containers/list.go
+++ b/cmd/podman/containers/list.go
@@ -29,4 +29,5 @@ func init() {
Parent: containerCmd,
})
listFlagSet(listCmd.Flags())
+ validate.AddLatestFlag(listCmd, &listOpts.Latest)
}
diff --git a/cmd/podman/containers/logs.go b/cmd/podman/containers/logs.go
index 85d3262da..850cb2e1f 100644
--- a/cmd/podman/containers/logs.go
+++ b/cmd/podman/containers/logs.go
@@ -4,6 +4,7 @@ import (
"os"
"github.com/containers/libpod/v2/cmd/podman/registry"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/containers/libpod/v2/pkg/util"
"github.com/pkg/errors"
@@ -68,9 +69,8 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: logsCommand,
})
-
- flags := logsCommand.Flags()
- logsFlags(flags)
+ logsFlags(logsCommand.Flags())
+ validate.AddLatestFlag(logsCommand, &logsOptions.Latest)
// container logs
registry.Commands = append(registry.Commands, registry.CliCommand{
@@ -78,15 +78,13 @@ func init() {
Command: containerLogsCommand,
Parent: containerCmd,
})
-
- containerLogsFlags := containerLogsCommand.Flags()
- logsFlags(containerLogsFlags)
+ logsFlags(containerLogsCommand.Flags())
+ validate.AddLatestFlag(containerLogsCommand, &logsOptions.Latest)
}
func logsFlags(flags *pflag.FlagSet) {
flags.BoolVar(&logsOptions.Details, "details", false, "Show extra details provided to the logs")
flags.BoolVarP(&logsOptions.Follow, "follow", "f", false, "Follow log output. The default is false")
- flags.BoolVarP(&logsOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.StringVar(&logsOptions.SinceRaw, "since", "", "Show logs since TIMESTAMP")
flags.Int64Var(&logsOptions.Tail, "tail", -1, "Output the specified number of LINES at the end of the logs. Defaults to -1, which prints all lines")
flags.BoolVarP(&logsOptions.Timestamps, "timestamps", "t", false, "Output the timestamps in the log")
@@ -95,7 +93,7 @@ func logsFlags(flags *pflag.FlagSet) {
_ = flags.MarkHidden("details")
}
-func logs(cmd *cobra.Command, args []string) error {
+func logs(_ *cobra.Command, args []string) error {
if logsOptions.SinceRaw != "" {
// parse time, error out if something is wrong
since, err := util.ParseInputTime(logsOptions.SinceRaw)
diff --git a/cmd/podman/containers/mount.go b/cmd/podman/containers/mount.go
index f2b66a2cd..44af27801 100644
--- a/cmd/podman/containers/mount.go
+++ b/cmd/podman/containers/mount.go
@@ -6,9 +6,9 @@ import (
"text/tabwriter"
"text/template"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@@ -28,7 +28,7 @@ var (
Long: mountDescription,
RunE: mount,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, true, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, true, false)
},
}
@@ -47,7 +47,6 @@ var (
func mountFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&mountOpts.All, "all", "a", false, "Mount all containers")
flags.StringVar(&mountOpts.Format, "format", "", "Change the output format to Go template")
- flags.BoolVarP(&mountOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.BoolVar(&mountOpts.NoTruncate, "notruncate", false, "Do not truncate output")
}
@@ -56,19 +55,19 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode},
Command: mountCommand,
})
- flags := mountCommand.Flags()
- mountFlags(flags)
+ mountFlags(mountCommand.Flags())
+ validate.AddLatestFlag(mountCommand, &mountOpts.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode},
Command: containerMountCommmand,
Parent: containerCmd,
})
- containerMountFlags := containerMountCommmand.Flags()
- mountFlags(containerMountFlags)
+ mountFlags(containerMountCommmand.Flags())
+ validate.AddLatestFlag(containerMountCommmand, &mountOpts.Latest)
}
-func mount(cmd *cobra.Command, args []string) error {
+func mount(_ *cobra.Command, args []string) error {
var (
errs utils.OutputErrors
)
diff --git a/cmd/podman/containers/pause.go b/cmd/podman/containers/pause.go
index 83a3824cf..33d6ff06f 100644
--- a/cmd/podman/containers/pause.go
+++ b/cmd/podman/containers/pause.go
@@ -66,6 +66,7 @@ func pause(cmd *cobra.Command, args []string) error {
if rootless.IsRootless() && !registry.IsRemote() {
return errors.New("pause is not supported for rootless containers")
}
+
if len(args) < 1 && !pauseOpts.All {
return errors.Errorf("you must provide at least one container name or id")
}
diff --git a/cmd/podman/containers/port.go b/cmd/podman/containers/port.go
index 3ef8f0fde..7e548b6c9 100644
--- a/cmd/podman/containers/port.go
+++ b/cmd/podman/containers/port.go
@@ -5,8 +5,8 @@ import (
"strconv"
"strings"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/pkg/errors"
@@ -23,7 +23,7 @@ var (
Long: portDescription,
RunE: port,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, true, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, true, false)
},
Example: `podman port --all
podman port ctrID 80/tcp
@@ -36,7 +36,7 @@ var (
Long: portDescription,
RunE: portCommand.RunE,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, true, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, true, false)
},
Example: `podman container port --all
podman container port --latest 80`,
@@ -49,10 +49,6 @@ var (
func portFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&portOpts.All, "all", "a", false, "Display port information for all containers")
- flags.BoolVarP(&portOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
}
func init() {
@@ -60,22 +56,19 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: portCommand,
})
-
- flags := portCommand.Flags()
- portFlags(flags)
+ portFlags(portCommand.Flags())
+ validate.AddLatestFlag(portCommand, &portOpts.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: containerPortCommand,
Parent: containerCmd,
})
-
- containerPortflags := containerPortCommand.Flags()
- portFlags(containerPortflags)
-
+ portFlags(containerPortCommand.Flags())
+ validate.AddLatestFlag(containerPortCommand, &portOpts.Latest)
}
-func port(cmd *cobra.Command, args []string) error {
+func port(_ *cobra.Command, args []string) error {
var (
container string
err error
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index 5cd7f40ac..7c84cbae1 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -50,6 +50,7 @@ func init() {
Command: psCommand,
})
listFlagSet(psCommand.Flags())
+ validate.AddLatestFlag(psCommand, &listOpts.Latest)
}
func listFlagSet(flags *pflag.FlagSet) {
@@ -57,7 +58,6 @@ func listFlagSet(flags *pflag.FlagSet) {
flags.StringSliceVarP(&filters, "filter", "f", []string{}, "Filter output based on conditions given")
flags.StringVar(&listOpts.Format, "format", "", "Pretty-print containers to JSON or using a Go template")
flags.IntVarP(&listOpts.Last, "last", "n", -1, "Print the n last created containers (all states)")
- flags.BoolVarP(&listOpts.Latest, "latest", "l", false, "Show the latest container created (all states)")
flags.BoolVar(&listOpts.Namespace, "namespace", false, "Display namespace information")
flags.BoolVar(&listOpts.Namespace, "ns", false, "Display namespace information")
flags.BoolVar(&noTrunc, "no-trunc", false, "Display the extended information")
@@ -69,10 +69,6 @@ func listFlagSet(flags *pflag.FlagSet) {
sort := validate.Value(&listOpts.Sort, "command", "created", "id", "image", "names", "runningfor", "size", "status")
flags.Var(sort, "sort", "Sort output by: "+sort.Choices())
-
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
}
func checkFlags(c *cobra.Command) error {
// latest, and last are mutually exclusive.
@@ -313,7 +309,13 @@ func (l psReporter) Status() string {
// Command returns the container command in string format
func (l psReporter) Command() string {
- return strings.Join(l.ListContainer.Command, " ")
+ command := strings.Join(l.ListContainer.Command, " ")
+ if !noTrunc {
+ if len(command) > 17 {
+ return command[0:17] + "..."
+ }
+ }
+ return command
}
// Size returns the rootfs and virtual sizes in human duration in
diff --git a/cmd/podman/containers/restart.go b/cmd/podman/containers/restart.go
index d3e90c160..393b003a9 100644
--- a/cmd/podman/containers/restart.go
+++ b/cmd/podman/containers/restart.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/libpod/define"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/pkg/errors"
@@ -25,7 +25,7 @@ var (
Long: restartDescription,
RunE: restart,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
Example: `podman restart ctrID
podman restart --latest
@@ -50,12 +50,9 @@ var (
func restartFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&restartOptions.All, "all", "a", false, "Restart all non-running containers")
- flags.BoolVarP(&restartOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.BoolVar(&restartOptions.Running, "running", false, "Restart only running containers when --all is used")
flags.UintVarP(&restartTimeout, "time", "t", containerConfig.Engine.StopTimeout, "Seconds to wait for stop before killing the container")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
+
flags.SetNormalizeFunc(utils.AliasFlags)
}
@@ -64,17 +61,16 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: restartCommand,
})
- flags := restartCommand.Flags()
- restartFlags(flags)
+ restartFlags(restartCommand.Flags())
+ validate.AddLatestFlag(restartCommand, &restartOptions.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: containerRestartCommand,
Parent: containerCmd,
})
-
- containerRestartFlags := containerRestartCommand.Flags()
- restartFlags(containerRestartFlags)
+ restartFlags(containerRestartCommand.Flags())
+ validate.AddLatestFlag(containerRestartCommand, &restartOptions.Latest)
}
func restart(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/containers/restore.go b/cmd/podman/containers/restore.go
index 975087a97..e9e0ad6fc 100644
--- a/cmd/podman/containers/restore.go
+++ b/cmd/podman/containers/restore.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/containers/libpod/v2/pkg/rootless"
"github.com/pkg/errors"
@@ -25,7 +25,7 @@ var (
Long: restoreDescription,
RunE: restore,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, true, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, true, false)
},
Example: `podman container restore ctrID
podman container restore --latest
@@ -46,19 +46,16 @@ func init() {
flags := restoreCommand.Flags()
flags.BoolVarP(&restoreOptions.All, "all", "a", false, "Restore all checkpointed containers")
flags.BoolVarP(&restoreOptions.Keep, "keep", "k", false, "Keep all temporary checkpoint files")
- flags.BoolVarP(&restoreOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.BoolVar(&restoreOptions.TCPEstablished, "tcp-established", false, "Restore a container with established TCP connections")
flags.StringVarP(&restoreOptions.Import, "import", "i", "", "Restore from exported checkpoint archive (tar.gz)")
flags.StringVarP(&restoreOptions.Name, "name", "n", "", "Specify new name for container restored from exported checkpoint (only works with --import)")
flags.BoolVar(&restoreOptions.IgnoreRootFS, "ignore-rootfs", false, "Do not apply root file-system changes when importing from exported checkpoint")
flags.BoolVar(&restoreOptions.IgnoreStaticIP, "ignore-static-ip", false, "Ignore IP address set via --static-ip")
flags.BoolVar(&restoreOptions.IgnoreStaticMAC, "ignore-static-mac", false, "Ignore MAC address set via --mac-address")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
+ validate.AddLatestFlag(restoreCommand, &restoreOptions.Latest)
}
-func restore(cmd *cobra.Command, args []string) error {
+func restore(_ *cobra.Command, args []string) error {
var errs utils.OutputErrors
if rootless.IsRootless() {
return errors.New("restoring a container requires root")
diff --git a/cmd/podman/containers/rm.go b/cmd/podman/containers/rm.go
index 3afda4c5d..427e1e72c 100644
--- a/cmd/podman/containers/rm.go
+++ b/cmd/podman/containers/rm.go
@@ -5,9 +5,9 @@ import (
"fmt"
"strings"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/libpod/define"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/pkg/errors"
@@ -26,7 +26,7 @@ var (
Long: rmDescription,
RunE: rm,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, true)
},
Example: `podman rm imageID
podman rm mywebserver myflaskserver 860a4b23
@@ -40,7 +40,7 @@ var (
Long: rmCommand.Long,
RunE: rmCommand.RunE,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, true)
},
Example: `podman container rm imageID
podman container rm mywebserver myflaskserver 860a4b23
@@ -57,12 +57,11 @@ func rmFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&rmOptions.All, "all", "a", false, "Remove all containers")
flags.BoolVarP(&rmOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing")
flags.BoolVarP(&rmOptions.Force, "force", "f", false, "Force removal of a running or unusable container. The default is false")
- flags.BoolVarP(&rmOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.BoolVar(&rmOptions.Storage, "storage", false, "Remove container from storage library")
flags.BoolVarP(&rmOptions.Volumes, "volumes", "v", false, "Remove anonymous volumes associated with the container")
flags.StringArrayVarP(&rmOptions.CIDFiles, "cidfile", "", nil, "Read the container ID from the file")
+
if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
_ = flags.MarkHidden("ignore")
_ = flags.MarkHidden("cidfile")
_ = flags.MarkHidden("storage")
@@ -75,18 +74,18 @@ func init() {
Command: rmCommand,
})
rmFlags(rmCommand.Flags())
+ validate.AddLatestFlag(rmCommand, &rmOptions.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: containerRmCommand,
Parent: containerCmd,
})
-
- containerRmFlags := containerRmCommand.Flags()
- rmFlags(containerRmFlags)
+ rmFlags(containerRmCommand.Flags())
+ validate.AddLatestFlag(containerRmCommand, &rmOptions.Latest)
}
-func rm(cmd *cobra.Command, args []string) error {
+func rm(_ *cobra.Command, args []string) error {
return removeContainers(args, rmOptions, true)
}
diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go
index c1af2c1d3..638b1c96e 100644
--- a/cmd/podman/containers/run.go
+++ b/cmd/podman/containers/run.go
@@ -61,6 +61,7 @@ func runFlags(flags *pflag.FlagSet) {
flags.SetNormalizeFunc(common.AliasFlags)
flags.BoolVar(&runOpts.SigProxy, "sig-proxy", true, "Proxy received signals to the process")
flags.BoolVar(&runRmi, "rmi", false, "Remove container image unless used by other containers")
+
if registry.IsRemote() {
_ = flags.MarkHidden("authfile")
_ = flags.MarkHidden("env-host")
diff --git a/cmd/podman/containers/start.go b/cmd/podman/containers/start.go
index 3c3bffaba..941588137 100644
--- a/cmd/podman/containers/start.go
+++ b/cmd/podman/containers/start.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/libpod/define"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/pkg/errors"
@@ -44,10 +45,9 @@ func startFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&startOptions.Attach, "attach", "a", false, "Attach container's STDOUT and STDERR")
flags.StringVar(&startOptions.DetachKeys, "detach-keys", containerConfig.DetachKeys(), "Select the key sequence for detaching a container. Format is a single character `[a-Z]` or a comma separated sequence of `ctrl-<value>`, where `<value>` is one of: `a-z`, `@`, `^`, `[`, `\\`, `]`, `^` or `_`")
flags.BoolVarP(&startOptions.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached")
- flags.BoolVarP(&startOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.BoolVar(&startOptions.SigProxy, "sig-proxy", false, "Proxy received signals to the process (default true if attaching, false otherwise)")
+
if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
_ = flags.MarkHidden("sig-proxy")
}
}
@@ -56,17 +56,17 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: startCommand,
})
- flags := startCommand.Flags()
- startFlags(flags)
+ startFlags(startCommand.Flags())
+ validate.AddLatestFlag(startCommand, &startOptions.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: containerStartCommand,
Parent: containerCmd,
})
+ startFlags(containerStartCommand.Flags())
+ validate.AddLatestFlag(containerStartCommand, &startOptions.Latest)
- containerStartFlags := containerStartCommand.Flags()
- startFlags(containerStartFlags)
}
func start(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/containers/stats.go b/cmd/podman/containers/stats.go
index 9b877b3af..86674cfc9 100644
--- a/cmd/podman/containers/stats.go
+++ b/cmd/podman/containers/stats.go
@@ -10,6 +10,7 @@ import (
tm "github.com/buger/goterm"
"github.com/containers/libpod/v2/cmd/podman/registry"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/libpod/define"
"github.com/containers/libpod/v2/pkg/cgroups"
"github.com/containers/libpod/v2/pkg/domain/entities"
@@ -56,12 +57,8 @@ var (
func statFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&statsOptions.All, "all", "a", false, "Show all containers. Only running containers are shown by default. The default is false")
flags.StringVar(&statsOptions.Format, "format", "", "Pretty-print container statistics to JSON or using a Go template")
- flags.BoolVarP(&statsOptions.Latest, "latest", "l", false, "Act on the latest container Podman is aware of")
flags.BoolVar(&statsOptions.NoReset, "no-reset", false, "Disable resetting the screen between intervals")
flags.BoolVar(&statsOptions.NoStream, "no-stream", false, "Disable streaming stats and only pull the first result, default setting is false")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
}
func init() {
@@ -69,17 +66,16 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: statsCommand,
})
- flags := statsCommand.Flags()
- statFlags(flags)
+ statFlags(statsCommand.Flags())
+ validate.AddLatestFlag(statsCommand, &statsOptions.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: containerStatsCommand,
Parent: containerCmd,
})
-
- containerStatsFlags := containerStatsCommand.Flags()
- statFlags(containerStatsFlags)
+ statFlags(containerStatsCommand.Flags())
+ validate.AddLatestFlag(containerStatsCommand, &statsOptions.Latest)
}
// stats is different in that it will assume running containers if
diff --git a/cmd/podman/containers/stop.go b/cmd/podman/containers/stop.go
index 7e741d161..7959918a8 100644
--- a/cmd/podman/containers/stop.go
+++ b/cmd/podman/containers/stop.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@@ -22,7 +22,7 @@ var (
Long: stopDescription,
RunE: stop,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, true)
},
Example: `podman stop ctrID
podman stop --latest
@@ -35,7 +35,7 @@ var (
Long: stopCommand.Long,
RunE: stopCommand.RunE,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, true)
},
Example: `podman container stop ctrID
podman container stop --latest
@@ -52,11 +52,9 @@ func stopFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&stopOptions.All, "all", "a", false, "Stop all running containers")
flags.BoolVarP(&stopOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing")
flags.StringArrayVarP(&stopOptions.CIDFiles, "cidfile", "", nil, "Read the container ID from the file")
- flags.BoolVarP(&stopOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.UintVarP(&stopTimeout, "time", "t", containerConfig.Engine.StopTimeout, "Seconds to wait for stop before killing the container")
if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
_ = flags.MarkHidden("cidfile")
_ = flags.MarkHidden("ignore")
}
@@ -68,8 +66,8 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: stopCommand,
})
- flags := stopCommand.Flags()
- stopFlags(flags)
+ stopFlags(stopCommand.Flags())
+ validate.AddLatestFlag(stopCommand, &stopOptions.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
@@ -77,8 +75,8 @@ func init() {
Parent: containerCmd,
})
- containerStopFlags := containerStopCommand.Flags()
- stopFlags(containerStopFlags)
+ stopFlags(containerStopCommand.Flags())
+ validate.AddLatestFlag(containerStopCommand, &stopOptions.Latest)
}
func stop(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/containers/top.go b/cmd/podman/containers/top.go
index adeba5ee8..079a0ca1e 100644
--- a/cmd/podman/containers/top.go
+++ b/cmd/podman/containers/top.go
@@ -8,6 +8,7 @@ import (
"text/tabwriter"
"github.com/containers/libpod/v2/cmd/podman/registry"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/containers/libpod/v2/pkg/util"
"github.com/pkg/errors"
@@ -51,11 +52,7 @@ podman container top ctrID -eo user,pid,comm`,
func topFlags(flags *pflag.FlagSet) {
flags.SetInterspersed(false)
flags.BoolVar(&topOptions.ListDescriptors, "list-descriptors", false, "")
- flags.BoolVarP(&topOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
_ = flags.MarkHidden("list-descriptors") // meant only for bash completion
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
}
func init() {
@@ -63,8 +60,8 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: topCommand,
})
- flags := topCommand.Flags()
- topFlags(flags)
+ topFlags(topCommand.Flags())
+ validate.AddLatestFlag(topCommand, &topOptions.Latest)
descriptors, err := util.GetContainerPidInformationDescriptors()
if err == nil {
@@ -77,8 +74,8 @@ func init() {
Command: containerTopCommand,
Parent: containerCmd,
})
- containerTopFlags := containerTopCommand.Flags()
- topFlags(containerTopFlags)
+ topFlags(containerTopCommand.Flags())
+ validate.AddLatestFlag(containerTopCommand, &topOptions.Latest)
}
func top(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/containers/unmount.go b/cmd/podman/containers/unmount.go
index 11889e8b0..c40c2be7e 100644
--- a/cmd/podman/containers/unmount.go
+++ b/cmd/podman/containers/unmount.go
@@ -3,9 +3,9 @@ package containers
import (
"fmt"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@@ -25,7 +25,7 @@ var (
Long: description,
RunE: unmount,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
Example: `podman umount ctrID
podman umount ctrID1 ctrID2 ctrID3
@@ -38,7 +38,7 @@ var (
Long: umountCommand.Long,
RunE: umountCommand.RunE,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
Example: `podman container umount ctrID
podman container umount ctrID1 ctrID2 ctrID3
@@ -53,7 +53,6 @@ var (
func umountFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&unmountOpts.All, "all", "a", false, "Umount all of the currently mounted containers")
flags.BoolVarP(&unmountOpts.Force, "force", "f", false, "Force the complete umount all of the currently mounted containers")
- flags.BoolVarP(&unmountOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
}
func init() {
@@ -61,17 +60,16 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode},
Command: umountCommand,
})
- flags := umountCommand.Flags()
- umountFlags(flags)
+ umountFlags(umountCommand.Flags())
+ validate.AddLatestFlag(umountCommand, &unmountOpts.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode},
Command: containerUnmountCommand,
Parent: containerCmd,
})
-
- containerUmountFlags := containerUnmountCommand.Flags()
- umountFlags(containerUmountFlags)
+ umountFlags(containerUnmountCommand.Flags())
+ validate.AddLatestFlag(containerUnmountCommand, &unmountOpts.Latest)
}
func unmount(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/containers/wait.go b/cmd/podman/containers/wait.go
index 82bfb2020..c30bfe405 100644
--- a/cmd/podman/containers/wait.go
+++ b/cmd/podman/containers/wait.go
@@ -47,9 +47,6 @@ var (
func waitFlags(flags *pflag.FlagSet) {
flags.DurationVarP(&waitOptions.Interval, "interval", "i", time.Duration(250), "Milliseconds to wait before polling for completion")
flags.StringVar(&waitCondition, "condition", "stopped", "Condition to wait on")
- if !registry.IsRemote() {
- flags.BoolVarP(&waitOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- }
}
func init() {
@@ -57,17 +54,17 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: waitCommand,
})
- flags := waitCommand.Flags()
- waitFlags(flags)
+ waitFlags(waitCommand.Flags())
+ validate.AddLatestFlag(waitCommand, &waitOptions.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: containerWaitCommand,
Parent: containerCmd,
})
+ waitFlags(containerWaitCommand.Flags())
+ validate.AddLatestFlag(containerWaitCommand, &waitOptions.Latest)
- containerWaitFlags := containerWaitCommand.Flags()
- waitFlags(containerWaitFlags)
}
func wait(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index 14a4529d5..cdd908cf1 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -17,12 +17,11 @@ var (
// Command: podman _diff_ Object_ID
diffDescription = `Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer.`
diffCmd = &cobra.Command{
- Use: "diff [flags] {CONTAINER_ID | IMAGE_ID}",
- Args: validate.IDOrLatestArgs,
- Short: "Display the changes of object's file system",
- Long: diffDescription,
- TraverseChildren: true,
- RunE: diff,
+ Use: "diff [flags] {CONTAINER_ID | IMAGE_ID}",
+ Args: validate.IDOrLatestArgs,
+ Short: "Display the changes to the object's file system",
+ Long: diffDescription,
+ RunE: diff,
Example: `podman diff imageID
podman diff ctrID
podman diff --format json redis:alpine`,
@@ -40,10 +39,7 @@ func init() {
flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
_ = flags.MarkHidden("archive")
flags.StringVar(&diffOpts.Format, "format", "", "Change the output format")
-
- if !registry.IsRemote() {
- flags.BoolVarP(&diffOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- }
+ validate.AddLatestFlag(diffCmd, &diffOpts.Latest)
}
func diff(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/generate/generate.go b/cmd/podman/generate/generate.go
index 3b3cb238d..d85d93347 100644
--- a/cmd/podman/generate/generate.go
+++ b/cmd/podman/generate/generate.go
@@ -11,11 +11,10 @@ import (
var (
// Command: podman _generate_
generateCmd = &cobra.Command{
- Use: "generate",
- Short: "Generate structured data based on containers and pods.",
- Long: "Generate structured data (e.g., Kubernetes yaml or systemd units) based on containers and pods.",
- TraverseChildren: true,
- RunE: validate.SubCommandExists,
+ Use: "generate",
+ Short: "Generate structured data based on containers and pods.",
+ Long: "Generate structured data (e.g., Kubernetes yaml or systemd units) based on containers and pods.",
+ RunE: validate.SubCommandExists,
}
containerConfig = util.DefaultContainerConfig()
)
diff --git a/cmd/podman/healthcheck/healthcheck.go b/cmd/podman/healthcheck/healthcheck.go
index 8b5d7bf80..fdf40e872 100644
--- a/cmd/podman/healthcheck/healthcheck.go
+++ b/cmd/podman/healthcheck/healthcheck.go
@@ -10,11 +10,10 @@ import (
var (
// Command: healthcheck
healthCmd = &cobra.Command{
- Use: "healthcheck",
- Short: "Manage health checks on containers",
- Long: "Run health checks on containers",
- TraverseChildren: true,
- RunE: validate.SubCommandExists,
+ Use: "healthcheck",
+ Short: "Manage health checks on containers",
+ Long: "Run health checks on containers",
+ RunE: validate.SubCommandExists,
}
)
diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go
index 40a9a8e7f..3ea74b4af 100644
--- a/cmd/podman/images/build.go
+++ b/cmd/podman/images/build.go
@@ -40,11 +40,11 @@ var (
// Command: podman _diff_ Object_ID
buildDescription = "Builds an OCI or Docker image using instructions from one or more Containerfiles and a specified build context directory."
buildCmd = &cobra.Command{
- Use: "build [flags] [CONTEXT]",
- Short: "Build an image using instructions from Containerfiles",
- Long: buildDescription,
- TraverseChildren: true,
- RunE: build,
+ Use: "build [flags] [CONTEXT]",
+ Short: "Build an image using instructions from Containerfiles",
+ Long: buildDescription,
+ Args: cobra.MaximumNArgs(1),
+ RunE: build,
Example: `podman build .
podman build --creds=username:password -t imageName -f Containerfile.simple .
podman build --layers --force-rm --tag imageName .`,
diff --git a/cmd/podman/images/diff.go b/cmd/podman/images/diff.go
index cd674ee9c..10a1c06ec 100644
--- a/cmd/podman/images/diff.go
+++ b/cmd/podman/images/diff.go
@@ -14,8 +14,8 @@ var (
diffCmd = &cobra.Command{
Use: "diff [flags] IMAGE",
Args: cobra.ExactArgs(1),
- Short: "Inspect changes on image's file systems",
- Long: `Displays changes on a image's filesystem. The image will be compared to its parent layer.`,
+ Short: "Inspect changes to the image's file systems",
+ Long: `Displays changes to the image's filesystem. The image will be compared to its parent layer.`,
RunE: diff,
Example: `podman image diff myImage
podman image diff --format json redis:alpine`,
diff --git a/cmd/podman/images/image.go b/cmd/podman/images/image.go
index 85c1afc0e..89badd035 100644
--- a/cmd/podman/images/image.go
+++ b/cmd/podman/images/image.go
@@ -13,11 +13,10 @@ var (
// Command: podman _image_
imageCmd = &cobra.Command{
- Use: "image",
- Short: "Manage images",
- Long: "Manage images",
- TraverseChildren: true,
- RunE: validate.SubCommandExists,
+ Use: "image",
+ Short: "Manage images",
+ Long: "Manage images",
+ RunE: validate.SubCommandExists,
}
)
diff --git a/cmd/podman/images/search.go b/cmd/podman/images/search.go
index 7c5bd890d..f1a2cda96 100644
--- a/cmd/podman/images/search.go
+++ b/cmd/podman/images/search.go
@@ -86,6 +86,7 @@ func searchFlags(flags *pflag.FlagSet) {
flags.BoolVar(&searchOptions.NoTrunc, "no-trunc", false, "Do not truncate the output")
flags.StringVar(&searchOptions.Authfile, "authfile", auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.BoolVar(&searchOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
+
if registry.IsRemote() {
_ = flags.MarkHidden("authfile")
_ = flags.MarkHidden("tls-verify")
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index 667271aaf..4dd6b4a9a 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -10,11 +10,10 @@ import (
var (
// Command: podman _inspect_ Object_ID
inspectCmd = &cobra.Command{
- Use: "inspect [flags] {CONTAINER_ID | IMAGE_ID}",
- Short: "Display the configuration of object denoted by ID",
- Long: "Displays the low-level information on an object identified by name or ID",
- TraverseChildren: true,
- RunE: inspectExec,
+ Use: "inspect [flags] {CONTAINER_ID | IMAGE_ID}",
+ Short: "Display the configuration of object denoted by ID",
+ Long: "Displays the low-level information on an object identified by name or ID",
+ RunE: inspectExec,
Example: `podman inspect fedora
podman inspect --type image fedora
podman inspect CtrID ImgID
diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go
index ce51bc1e9..6fcca597b 100644
--- a/cmd/podman/inspect/inspect.go
+++ b/cmd/podman/inspect/inspect.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/v2/cmd/podman/registry"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -32,8 +33,8 @@ func AddInspectFlagSet(cmd *cobra.Command) *entities.InspectOptions {
flags.BoolVarP(&opts.Size, "size", "s", false, "Display total file size")
flags.StringVarP(&opts.Format, "format", "f", "json", "Format the output to a Go template or json")
flags.StringVarP(&opts.Type, "type", "t", AllType, fmt.Sprintf("Specify inspect-oject type (%q, %q or %q)", ImageType, ContainerType, AllType))
- flags.BoolVarP(&opts.Latest, "latest", "l", false, "Act on the latest container Podman is aware of")
+ validate.AddLatestFlag(cmd, &opts.Latest)
return &opts
}
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 77cadc842..5f740a006 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -16,7 +16,9 @@ import (
_ "github.com/containers/libpod/v2/cmd/podman/system"
_ "github.com/containers/libpod/v2/cmd/podman/volumes"
"github.com/containers/libpod/v2/pkg/rootless"
+ "github.com/containers/libpod/v2/pkg/terminal"
"github.com/containers/storage/pkg/reexec"
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -27,6 +29,11 @@ func main() {
return
}
+ // Hard code TMPDIR functions to use /var/tmp, if user did not override
+ if _, ok := os.LookupEnv("TMPDIR"); !ok {
+ os.Setenv("TMPDIR", "/var/tmp")
+ }
+
cfg := registry.PodmanConfig()
for _, c := range registry.Commands {
for _, m := range c.Mode {
@@ -53,6 +60,10 @@ func main() {
}
}
}
+ if err := terminal.SetConsole(); err != nil {
+ logrus.Error(err)
+ os.Exit(1)
+ }
Execute()
os.Exit(0)
diff --git a/cmd/podman/manifest/manifest.go b/cmd/podman/manifest/manifest.go
index 2bdbec662..f992705c1 100644
--- a/cmd/podman/manifest/manifest.go
+++ b/cmd/podman/manifest/manifest.go
@@ -10,11 +10,10 @@ import (
var (
manifestDescription = "Creates, modifies, and pushes manifest lists and image indexes."
manifestCmd = &cobra.Command{
- Use: "manifest",
- Short: "Manipulate manifest lists and image indexes",
- Long: manifestDescription,
- TraverseChildren: true,
- RunE: validate.SubCommandExists,
+ Use: "manifest",
+ Short: "Manipulate manifest lists and image indexes",
+ Long: manifestDescription,
+ RunE: validate.SubCommandExists,
Example: `podman manifest add mylist:v1.11 image:v1.11-amd64
podman manifest create localhost/list
podman manifest inspect localhost/list
diff --git a/cmd/podman/manifest/push.go b/cmd/podman/manifest/push.go
index 226dc716c..d1eb37ae5 100644
--- a/cmd/podman/manifest/push.go
+++ b/cmd/podman/manifest/push.go
@@ -49,6 +49,7 @@ func init() {
flags.StringVar(&manifestPushOpts.SignBy, "sign-by", "", "sign the image using a GPG key with the specified `FINGERPRINT`")
flags.BoolVar(&manifestPushOpts.TLSVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")
flags.BoolVarP(&manifestPushOpts.Quiet, "quiet", "q", false, "don't output progress information when pushing lists")
+
if registry.IsRemote() {
_ = flags.MarkHidden("authfile")
_ = flags.MarkHidden("cert-dir")
diff --git a/cmd/podman/networks/network.go b/cmd/podman/networks/network.go
index aa319f15e..953e4678c 100644
--- a/cmd/podman/networks/network.go
+++ b/cmd/podman/networks/network.go
@@ -10,11 +10,10 @@ import (
var (
// Command: podman _network_
networkCmd = &cobra.Command{
- Use: "network",
- Short: "Manage networks",
- Long: "Manage networks",
- TraverseChildren: true,
- RunE: validate.SubCommandExists,
+ Use: "network",
+ Short: "Manage networks",
+ Long: "Manage networks",
+ RunE: validate.SubCommandExists,
}
)
diff --git a/cmd/podman/parse/common.go b/cmd/podman/parse/common.go
deleted file mode 100644
index b3aa88da2..000000000
--- a/cmd/podman/parse/common.go
+++ /dev/null
@@ -1,112 +0,0 @@
-package parse
-
-import (
- "github.com/pkg/errors"
- "github.com/spf13/cobra"
-)
-
-// TODO: the two functions here are almost identical. It may be worth looking
-// into generalizing the two a bit more and share code but time is scarce and
-// we only live once.
-
-// CheckAllLatestAndCIDFile checks that --all and --latest are used correctly.
-// If cidfile is set, also check for the --cidfile flag.
-func CheckAllLatestAndCIDFile(c *cobra.Command, args []string, ignoreArgLen bool, cidfile bool) error {
- argLen := len(args)
- if c.Flags().Lookup("all") == nil || c.Flags().Lookup("latest") == nil {
- if !cidfile {
- return errors.New("unable to lookup values for 'latest' or 'all'")
- } else if c.Flags().Lookup("cidfile") == nil {
- return errors.New("unable to lookup values for 'latest', 'all' or 'cidfile'")
- }
- }
-
- specifiedAll, _ := c.Flags().GetBool("all")
- specifiedLatest, _ := c.Flags().GetBool("latest")
- specifiedCIDFile := false
- if cid, _ := c.Flags().GetStringArray("cidfile"); len(cid) > 0 {
- specifiedCIDFile = true
- }
-
- if specifiedCIDFile && (specifiedAll || specifiedLatest) {
- return errors.Errorf("--all, --latest and --cidfile cannot be used together")
- } else if specifiedAll && specifiedLatest {
- return errors.Errorf("--all and --latest cannot be used together")
- }
-
- if (argLen > 0) && specifiedAll {
- return errors.Errorf("no arguments are needed with --all")
- }
-
- if ignoreArgLen {
- return nil
- }
-
- if argLen > 0 {
- if specifiedLatest {
- return errors.Errorf("no arguments are needed with --latest")
- } else if cidfile && (specifiedLatest || specifiedCIDFile) {
- return errors.Errorf("no arguments are needed with --latest or --cidfile")
- }
- }
-
- if specifiedCIDFile {
- return nil
- }
-
- if argLen < 1 && !specifiedAll && !specifiedLatest && !specifiedCIDFile {
- return errors.Errorf("you must provide at least one name or id")
- }
- return nil
-}
-
-// CheckAllLatestAndPodIDFile checks that --all and --latest are used correctly.
-// If withIDFile is set, also check for the --pod-id-file flag.
-func CheckAllLatestAndPodIDFile(c *cobra.Command, args []string, ignoreArgLen bool, withIDFile bool) error {
- argLen := len(args)
- if c.Flags().Lookup("all") == nil || c.Flags().Lookup("latest") == nil {
- if !withIDFile {
- return errors.New("unable to lookup values for 'latest' or 'all'")
- } else if c.Flags().Lookup("pod-id-file") == nil {
- return errors.New("unable to lookup values for 'latest', 'all' or 'pod-id-file'")
- }
- }
-
- specifiedAll, _ := c.Flags().GetBool("all")
- specifiedLatest, _ := c.Flags().GetBool("latest")
- specifiedPodIDFile := false
- if pid, _ := c.Flags().GetStringArray("pod-id-file"); len(pid) > 0 {
- specifiedPodIDFile = true
- }
-
- if specifiedPodIDFile && (specifiedAll || specifiedLatest) {
- return errors.Errorf("--all, --latest and --pod-id-file cannot be used together")
- } else if specifiedAll && specifiedLatest {
- return errors.Errorf("--all and --latest cannot be used together")
- }
-
- if (argLen > 0) && specifiedAll {
- return errors.Errorf("no arguments are needed with --all")
- }
-
- if ignoreArgLen {
- return nil
- }
-
- if argLen > 0 {
- if specifiedLatest {
- return errors.Errorf("no arguments are needed with --latest")
- } else if withIDFile && (specifiedLatest || specifiedPodIDFile) {
- return errors.Errorf("no arguments are needed with --latest or --pod-id-file")
- }
- }
-
- if specifiedPodIDFile {
- return nil
- }
-
- if argLen < 1 && !specifiedAll && !specifiedLatest && !specifiedPodIDFile {
- return errors.Errorf("you must provide at least one name or id")
- }
- return nil
-}
diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go
index 3567295bf..9bd5c10db 100644
--- a/cmd/podman/play/kube.go
+++ b/cmd/podman/play/kube.go
@@ -61,7 +61,6 @@ func init() {
flags.StringVar(&kubeOptions.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
flags.StringVar(&kubeOptions.SeccompProfileRoot, "seccomp-profile-root", defaultSeccompRoot, "Directory path for seccomp profiles")
}
-
_ = flags.MarkHidden("signature-policy")
}
diff --git a/cmd/podman/play/play.go b/cmd/podman/play/play.go
index f7018eafb..eb8873595 100644
--- a/cmd/podman/play/play.go
+++ b/cmd/podman/play/play.go
@@ -10,11 +10,10 @@ import (
var (
// Command: podman _play_
playCmd = &cobra.Command{
- Use: "play",
- Short: "Play a pod and its containers from a structured file.",
- Long: "Play structured data (e.g., Kubernetes pod or service yaml) based on containers and pods.",
- TraverseChildren: true,
- RunE: validate.SubCommandExists,
+ Use: "play",
+ Short: "Play a pod and its containers from a structured file.",
+ Long: "Play structured data (e.g., Kubernetes pod or service yaml) based on containers and pods.",
+ RunE: validate.SubCommandExists,
}
)
diff --git a/cmd/podman/pods/inspect.go b/cmd/podman/pods/inspect.go
index 7d31385de..e21c7a74b 100644
--- a/cmd/podman/pods/inspect.go
+++ b/cmd/podman/pods/inspect.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/v2/cmd/podman/registry"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -36,11 +37,8 @@ func init() {
Parent: podCmd,
})
flags := inspectCmd.Flags()
- flags.BoolVarP(&inspectOptions.Latest, "latest", "l", false, "Act on the latest pod podman is aware of")
flags.StringVarP(&inspectOptions.Format, "format", "f", "json", "Format the output to a Go template or json")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
+ validate.AddLatestFlag(inspectCmd, &inspectOptions.Latest)
}
func inspect(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/pods/kill.go b/cmd/podman/pods/kill.go
index 2076d55e9..2f4930897 100644
--- a/cmd/podman/pods/kill.go
+++ b/cmd/podman/pods/kill.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -21,7 +21,7 @@ var (
Long: podKillDescription,
RunE: kill,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
Example: `podman pod kill podID
podman pod kill --signal TERM mywebserver
@@ -41,14 +41,11 @@ func init() {
})
flags := killCommand.Flags()
flags.BoolVarP(&killOpts.All, "all", "a", false, "Kill all containers in all pods")
- flags.BoolVarP(&killOpts.Latest, "latest", "l", false, "Act on the latest pod podman is aware of")
flags.StringVarP(&killOpts.Signal, "signal", "s", "KILL", "Signal to send to the containers in the pod")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
-
+ validate.AddLatestFlag(killCommand, &killOpts.Latest)
}
-func kill(cmd *cobra.Command, args []string) error {
+
+func kill(_ *cobra.Command, args []string) error {
var (
errs utils.OutputErrors
)
diff --git a/cmd/podman/pods/pause.go b/cmd/podman/pods/pause.go
index d495db601..f79d88973 100644
--- a/cmd/podman/pods/pause.go
+++ b/cmd/podman/pods/pause.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -21,7 +21,7 @@ var (
Long: podPauseDescription,
RunE: pause,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
Example: `podman pod pause podID1 podID2
podman pod pause --latest
@@ -41,12 +41,9 @@ func init() {
})
flags := pauseCommand.Flags()
flags.BoolVarP(&pauseOptions.All, "all", "a", false, "Pause all running pods")
- flags.BoolVarP(&pauseOptions.Latest, "latest", "l", false, "Act on the latest pod podman is aware of")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
+ validate.AddLatestFlag(pauseCommand, &pauseOptions.Latest)
}
-func pause(cmd *cobra.Command, args []string) error {
+func pause(_ *cobra.Command, args []string) error {
var (
errs utils.OutputErrors
)
diff --git a/cmd/podman/pods/pod.go b/cmd/podman/pods/pod.go
index 6eccade22..fff5ea615 100644
--- a/cmd/podman/pods/pod.go
+++ b/cmd/podman/pods/pod.go
@@ -14,11 +14,10 @@ var (
// Command: podman _pod_
podCmd = &cobra.Command{
- Use: "pod",
- Short: "Manage pods",
- Long: "Pods are a group of one or more containers sharing the same network, pid and ipc namespaces.",
- TraverseChildren: true,
- RunE: validate.SubCommandExists,
+ Use: "pod",
+ Short: "Manage pods",
+ Long: "Pods are a group of one or more containers sharing the same network, pid and ipc namespaces.",
+ RunE: validate.SubCommandExists,
}
containerConfig = util.DefaultContainerConfig()
)
diff --git a/cmd/podman/pods/ps.go b/cmd/podman/pods/ps.go
index 49407d39b..7a1221480 100644
--- a/cmd/podman/pods/ps.go
+++ b/cmd/podman/pods/ps.go
@@ -53,18 +53,15 @@ func init() {
// TODO should we make this a [] ?
flags.StringSliceVarP(&inputFilters, "filter", "f", []string{}, "Filter output based on conditions given")
flags.StringVar(&psInput.Format, "format", "", "Pretty-print pods to JSON or using a Go template")
- flags.BoolVarP(&psInput.Latest, "latest", "l", false, "Act on the latest pod podman is aware of")
flags.BoolVar(&psInput.Namespace, "namespace", false, "Display namespace information of the pod")
flags.BoolVar(&psInput.Namespace, "ns", false, "Display namespace information of the pod")
flags.BoolVar(&noTrunc, "no-trunc", false, "Do not truncate pod and container IDs")
flags.BoolVarP(&psInput.Quiet, "quiet", "q", false, "Print the numeric IDs of the pods only")
flags.StringVar(&psInput.Sort, "sort", "created", "Sort output by created, id, name, or number")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
+ validate.AddLatestFlag(psCmd, &psInput.Latest)
}
-func pods(cmd *cobra.Command, args []string) error {
+func pods(cmd *cobra.Command, _ []string) error {
var (
w io.Writer = os.Stdout
row string
diff --git a/cmd/podman/pods/restart.go b/cmd/podman/pods/restart.go
index 7ca6b3cac..77d9f62d4 100644
--- a/cmd/podman/pods/restart.go
+++ b/cmd/podman/pods/restart.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -21,7 +21,7 @@ var (
Long: podRestartDescription,
RunE: restart,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
Example: `podman pod restart podID1 podID2
podman pod restart --latest
@@ -42,10 +42,7 @@ func init() {
flags := restartCommand.Flags()
flags.BoolVarP(&restartOptions.All, "all", "a", false, "Restart all running pods")
- flags.BoolVarP(&restartOptions.Latest, "latest", "l", false, "Restart the latest pod podman is aware of")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
+ validate.AddLatestFlag(restartCommand, &restartOptions.Latest)
}
func restart(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/pods/rm.go b/cmd/podman/pods/rm.go
index 60972da76..3e07b31e9 100644
--- a/cmd/podman/pods/rm.go
+++ b/cmd/podman/pods/rm.go
@@ -5,9 +5,9 @@ import (
"fmt"
"github.com/containers/libpod/v2/cmd/podman/common"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -30,7 +30,7 @@ var (
Long: podRmDescription,
RunE: rm,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndPodIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndPodIDFile(cmd, args, false, true)
},
Example: `podman pod rm mywebserverpod
podman pod rm -f 860a4b23
@@ -49,15 +49,15 @@ func init() {
flags.BoolVarP(&rmOptions.All, "all", "a", false, "Remove all running pods")
flags.BoolVarP(&rmOptions.Force, "force", "f", false, "Force removal of a running pod by first stopping all containers, then removing all containers in the pod. The default is false")
flags.BoolVarP(&rmOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified pod is missing")
- flags.BoolVarP(&rmOptions.Latest, "latest", "l", false, "Remove the latest pod podman is aware of")
flags.StringArrayVarP(&rmOptions.PodIDFiles, "pod-id-file", "", nil, "Read the pod ID from the file")
+ validate.AddLatestFlag(rmCommand, &rmOptions.Latest)
+
if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
_ = flags.MarkHidden("ignore")
}
}
-func rm(cmd *cobra.Command, args []string) error {
+func rm(_ *cobra.Command, args []string) error {
ids, err := common.ReadPodIDFiles(rmOptions.PodIDFiles)
if err != nil {
return err
diff --git a/cmd/podman/pods/start.go b/cmd/podman/pods/start.go
index db09f1bce..586737fb2 100644
--- a/cmd/podman/pods/start.go
+++ b/cmd/podman/pods/start.go
@@ -5,9 +5,9 @@ import (
"fmt"
"github.com/containers/libpod/v2/cmd/podman/common"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -29,7 +29,7 @@ var (
Long: podStartDescription,
RunE: start,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndPodIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndPodIDFile(cmd, args, false, true)
},
Example: `podman pod start podID
podman pod start --latest
@@ -50,11 +50,8 @@ func init() {
flags := startCommand.Flags()
flags.BoolVarP(&startOptions.All, "all", "a", false, "Restart all running pods")
- flags.BoolVarP(&startOptions.Latest, "latest", "l", false, "Restart the latest pod podman is aware of")
flags.StringArrayVarP(&startOptions.PodIDFiles, "pod-id-file", "", nil, "Read the pod ID from the file")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
+ validate.AddLatestFlag(startCommand, &startOptions.Latest)
}
func start(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/pods/stats.go b/cmd/podman/pods/stats.go
index 19ff750aa..930a6d15c 100644
--- a/cmd/podman/pods/stats.go
+++ b/cmd/podman/pods/stats.go
@@ -13,6 +13,7 @@ import (
"github.com/buger/goterm"
"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/v2/cmd/podman/registry"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/containers/libpod/v2/pkg/util/camelcase"
"github.com/spf13/cobra"
@@ -55,13 +56,9 @@ func init() {
flags := statsCmd.Flags()
flags.BoolVarP(&statsOptions.All, "all", "a", false, "Provide stats for all pods")
flags.StringVar(&statsOptions.Format, "format", "", "Pretty-print container statistics to JSON or using a Go template")
- flags.BoolVarP(&statsOptions.Latest, "latest", "l", false, "Provide stats on the latest pod Podman is aware of")
flags.BoolVar(&statsOptions.NoReset, "no-reset", false, "Disable resetting the screen when streaming")
flags.BoolVar(&statsOptions.NoStream, "no-stream", false, "Disable streaming stats and only pull the first result")
-
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
+ validate.AddLatestFlag(statsCmd, &statsOptions.Latest)
}
func stats(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/pods/stop.go b/cmd/podman/pods/stop.go
index afe3b6eae..84190fd08 100644
--- a/cmd/podman/pods/stop.go
+++ b/cmd/podman/pods/stop.go
@@ -5,9 +5,9 @@ import (
"fmt"
"github.com/containers/libpod/v2/cmd/podman/common"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -34,7 +34,7 @@ var (
Long: podStopDescription,
RunE: stop,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndPodIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndPodIDFile(cmd, args, false, true)
},
Example: `podman pod stop mywebserverpod
podman pod stop --latest
@@ -51,13 +51,14 @@ func init() {
flags := stopCommand.Flags()
flags.BoolVarP(&stopOptions.All, "all", "a", false, "Stop all running pods")
flags.BoolVarP(&stopOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified pod is missing")
- flags.BoolVarP(&stopOptions.Latest, "latest", "l", false, "Stop the latest pod podman is aware of")
flags.UintVarP(&stopOptions.TimeoutCLI, "time", "t", containerConfig.Engine.StopTimeout, "Seconds to wait for pod stop before killing the container")
flags.StringArrayVarP(&stopOptions.PodIDFiles, "pod-id-file", "", nil, "Read the pod ID from the file")
+ validate.AddLatestFlag(stopCommand, &stopOptions.Latest)
+
if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
_ = flags.MarkHidden("ignore")
}
+
flags.SetNormalizeFunc(utils.AliasFlags)
}
diff --git a/cmd/podman/pods/top.go b/cmd/podman/pods/top.go
index 551eeccac..840d2da0a 100644
--- a/cmd/podman/pods/top.go
+++ b/cmd/podman/pods/top.go
@@ -8,6 +8,7 @@ import (
"text/tabwriter"
"github.com/containers/libpod/v2/cmd/podman/registry"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/containers/libpod/v2/pkg/util"
"github.com/pkg/errors"
@@ -50,15 +51,11 @@ func init() {
flags := topCommand.Flags()
flags.SetInterspersed(false)
flags.BoolVar(&topOptions.ListDescriptors, "list-descriptors", false, "")
- flags.BoolVarP(&topOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
-
_ = flags.MarkHidden("list-descriptors") // meant only for bash completion
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
+ validate.AddLatestFlag(topCommand, &topOptions.Latest)
}
-func top(cmd *cobra.Command, args []string) error {
+func top(_ *cobra.Command, args []string) error {
if topOptions.ListDescriptors {
descriptors, err := util.GetContainerPidInformationDescriptors()
if err != nil {
diff --git a/cmd/podman/pods/unpause.go b/cmd/podman/pods/unpause.go
index 09f2e472d..f96f3481c 100644
--- a/cmd/podman/pods/unpause.go
+++ b/cmd/podman/pods/unpause.go
@@ -4,9 +4,9 @@ import (
"context"
"fmt"
- "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/utils"
+ "github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -21,7 +21,7 @@ var (
Long: podUnpauseDescription,
RunE: unpause,
Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
Example: `podman pod unpause podID1 podID2
podman pod unpause --all
@@ -41,12 +41,10 @@ func init() {
})
flags := unpauseCommand.Flags()
flags.BoolVarP(&unpauseOptions.All, "all", "a", false, "Pause all running pods")
- flags.BoolVarP(&unpauseOptions.Latest, "latest", "l", false, "Act on the latest pod podman is aware of")
- if registry.IsRemote() {
- _ = flags.MarkHidden("latest")
- }
+ validate.AddLatestFlag(unpauseCommand, &unpauseOptions.Latest)
}
-func unpause(cmd *cobra.Command, args []string) error {
+
+func unpause(_ *cobra.Command, args []string) error {
var (
errs utils.OutputErrors
)
diff --git a/cmd/podman/registry/config.go b/cmd/podman/registry/config.go
index 85bf5f944..75e67b35d 100644
--- a/cmd/podman/registry/config.go
+++ b/cmd/podman/registry/config.go
@@ -5,7 +5,6 @@ import (
"os"
"path/filepath"
"runtime"
- "strings"
"sync"
"github.com/containers/common/pkg/config"
@@ -45,7 +44,7 @@ func newPodmanConfig() {
case "linux":
// Some linux clients might only be compiled without ABI
// support (e.g., podman-remote).
- if abiSupport {
+ if abiSupport && !remoteOverride {
mode = entities.ABIMode
} else {
mode = entities.TunnelMode
@@ -55,19 +54,6 @@ func newPodmanConfig() {
os.Exit(1)
}
- // Check if need to fallback to the tunnel mode if --remote is used.
- if abiSupport && mode == entities.ABIMode {
- // cobra.Execute() may not be called yet, so we peek at os.Args.
- for _, v := range os.Args {
- // Prefix checking works because of how default EngineMode's
- // have been defined.
- if strings.HasPrefix(v, "--remote") {
- mode = entities.TunnelMode
- break
- }
- }
- }
-
cfg, err := config.NewConfig("")
if err != nil {
fmt.Fprint(os.Stderr, "Failed to obtain podman configuration: "+err.Error())
diff --git a/cmd/podman/registry/remote.go b/cmd/podman/registry/remote.go
index 3040c4c2a..006a1b900 100644
--- a/cmd/podman/registry/remote.go
+++ b/cmd/podman/registry/remote.go
@@ -1,9 +1,26 @@
package registry
import (
+ "os"
+ "sync"
+
"github.com/containers/libpod/v2/pkg/domain/entities"
+ "github.com/spf13/cobra"
+)
+
+var (
+ // Was --remote given on command line
+ remoteOverride bool
+ remoteSync sync.Once
)
+// IsRemote returns true if podman was built to run remote
+// Use in init() functions as a initialization check
func IsRemote() bool {
- return podmanOptions.EngineMode == entities.TunnelMode
+ remoteSync.Do(func() {
+ remote := &cobra.Command{}
+ remote.Flags().BoolVarP(&remoteOverride, "remote", "r", false, "")
+ _ = remote.ParseFlags(os.Args)
+ })
+ return podmanOptions.EngineMode == entities.TunnelMode || remoteOverride
}
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index 1ca358e71..7c54da91a 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -6,6 +6,7 @@ import (
"path"
"runtime"
"runtime/pprof"
+ "strconv"
"strings"
"github.com/containers/common/pkg/config"
@@ -20,7 +21,6 @@ import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
- "github.com/spf13/pflag"
)
// HelpTemplate is the help template for podman commands
@@ -79,7 +79,7 @@ func init() {
syslogHook,
)
- rootFlags(registry.PodmanConfig(), rootCmd.PersistentFlags())
+ rootFlags(rootCmd, registry.PodmanConfig())
// "version" is a local flag to avoid collisions with sub-commands that use "-v"
var dummyVersion bool
@@ -111,6 +111,15 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
cfg := registry.PodmanConfig()
+ // Validate --remote and --latest not given on same command
+ latest := cmd.Flags().Lookup("latest")
+ if latest != nil {
+ value, _ := strconv.ParseBool(latest.Value.String())
+ if cfg.Remote && value {
+ return errors.Errorf("For %s \"--remote\" and \"--latest\", are mutually exclusive flags", cmd.CommandPath())
+ }
+ }
+
// Prep the engines
if _, err := registry.NewImageEngine(cmd, args); err != nil {
return err
@@ -193,7 +202,7 @@ func loggingHook() {
}
}
if !found {
- fmt.Fprintf(os.Stderr, "Log Level \"%s\" is not supported, choose from: %s\n", logLevel, strings.Join(logLevels, ", "))
+ fmt.Fprintf(os.Stderr, "Log Level %q is not supported, choose from: %s\n", logLevel, strings.Join(logLevels, ", "))
os.Exit(1)
}
@@ -209,44 +218,45 @@ func loggingHook() {
}
}
-func rootFlags(opts *entities.PodmanConfig, flags *pflag.FlagSet) {
- // V2 flags
- flags.BoolVarP(&opts.Remote, "remote", "r", false, "Access remote Podman service (default false)")
+func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) {
+ cfg := opts.Config
+ lFlags := cmd.Flags()
custom, _ := config.ReadCustomConfig()
defaultURI := custom.Engine.RemoteURI
if defaultURI == "" {
defaultURI = registry.DefaultAPIAddress()
}
- flags.StringVar(&opts.URI, "url", defaultURI, "URL to access Podman service (CONTAINER_HOST)")
- flags.StringVar(&opts.Identity, "identity", custom.Engine.RemoteIdentity, "path to SSH identity file, (CONTAINER_SSHKEY)")
-
- cfg := opts.Config
- flags.StringVar(&cfg.Engine.CgroupManager, "cgroup-manager", cfg.Engine.CgroupManager, "Cgroup manager to use (\"cgroupfs\"|\"systemd\")")
- flags.StringVar(&opts.CPUProfile, "cpu-profile", "", "Path for the cpu profiling results")
- flags.StringVar(&opts.ConmonPath, "conmon", "", "Path of the conmon binary")
- flags.StringVar(&cfg.Engine.NetworkCmdPath, "network-cmd-path", cfg.Engine.NetworkCmdPath, "Path to the command for configuring the network")
- flags.StringVar(&cfg.Network.NetworkConfigDir, "cni-config-dir", cfg.Network.NetworkConfigDir, "Path of the configuration directory for CNI networks")
- flags.StringVar(&cfg.Containers.DefaultMountsFile, "default-mounts-file", cfg.Containers.DefaultMountsFile, "Path to default mounts file")
- flags.StringVar(&cfg.Engine.EventsLogger, "events-backend", cfg.Engine.EventsLogger, `Events backend to use ("file"|"journald"|"none")`)
- flags.StringSliceVar(&cfg.Engine.HooksDir, "hooks-dir", cfg.Engine.HooksDir, "Set the OCI hooks directory path (may be set multiple times)")
- flags.IntVar(&opts.MaxWorks, "max-workers", (runtime.NumCPU()*3)+1, "The maximum number of workers for parallel operations")
- flags.StringVar(&cfg.Engine.Namespace, "namespace", cfg.Engine.Namespace, "Set the libpod namespace, used to create separate views of the containers and pods on the system")
- flags.StringVar(&cfg.Engine.StaticDir, "root", "", "Path to the root directory in which data, including images, is stored")
- flags.StringVar(&opts.RegistriesConf, "registries-conf", "", "Path to a registries.conf to use for image processing")
- flags.StringVar(&opts.Runroot, "runroot", "", "Path to the 'run directory' where all state information is stored")
- flags.StringVar(&opts.RuntimePath, "runtime", "", "Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc")
+ lFlags.BoolVarP(&opts.Remote, "remote", "r", false, "Access remote Podman service (default false)")
+ lFlags.StringVar(&opts.URI, "url", defaultURI, "URL to access Podman service (CONTAINER_HOST)")
+ lFlags.StringVar(&opts.Identity, "identity", custom.Engine.RemoteIdentity, "path to SSH identity file, (CONTAINER_SSHKEY)")
+
+ pFlags := cmd.PersistentFlags()
+ pFlags.StringVar(&cfg.Engine.CgroupManager, "cgroup-manager", cfg.Engine.CgroupManager, "Cgroup manager to use (\"cgroupfs\"|\"systemd\")")
+ pFlags.StringVar(&opts.CPUProfile, "cpu-profile", "", "Path for the cpu profiling results")
+ pFlags.StringVar(&opts.ConmonPath, "conmon", "", "Path of the conmon binary")
+ pFlags.StringVar(&cfg.Engine.NetworkCmdPath, "network-cmd-path", cfg.Engine.NetworkCmdPath, "Path to the command for configuring the network")
+ pFlags.StringVar(&cfg.Network.NetworkConfigDir, "cni-config-dir", cfg.Network.NetworkConfigDir, "Path of the configuration directory for CNI networks")
+ pFlags.StringVar(&cfg.Containers.DefaultMountsFile, "default-mounts-file", cfg.Containers.DefaultMountsFile, "Path to default mounts file")
+ pFlags.StringVar(&cfg.Engine.EventsLogger, "events-backend", cfg.Engine.EventsLogger, `Events backend to use ("file"|"journald"|"none")`)
+ pFlags.StringSliceVar(&cfg.Engine.HooksDir, "hooks-dir", cfg.Engine.HooksDir, "Set the OCI hooks directory path (may be set multiple times)")
+ pFlags.IntVar(&opts.MaxWorks, "max-workers", (runtime.NumCPU()*3)+1, "The maximum number of workers for parallel operations")
+ pFlags.StringVar(&cfg.Engine.Namespace, "namespace", cfg.Engine.Namespace, "Set the libpod namespace, used to create separate views of the containers and pods on the system")
+ pFlags.StringVar(&cfg.Engine.StaticDir, "root", "", "Path to the root directory in which data, including images, is stored")
+ pFlags.StringVar(&opts.RegistriesConf, "registries-conf", "", "Path to a registries.conf to use for image processing")
+ pFlags.StringVar(&opts.Runroot, "runroot", "", "Path to the 'run directory' where all state information is stored")
+ pFlags.StringVar(&opts.RuntimePath, "runtime", "", "Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc")
// -s is deprecated due to conflict with -s on subcommands
- flags.StringVar(&opts.StorageDriver, "storage-driver", "", "Select which storage driver is used to manage storage of images and containers (default is overlay)")
- flags.StringArrayVar(&opts.StorageOpts, "storage-opt", []string{}, "Used to pass an option to the storage driver")
+ pFlags.StringVar(&opts.StorageDriver, "storage-driver", "", "Select which storage driver is used to manage storage of images and containers (default is overlay)")
+ pFlags.StringArrayVar(&opts.StorageOpts, "storage-opt", []string{}, "Used to pass an option to the storage driver")
- flags.StringVar(&opts.Engine.TmpDir, "tmpdir", "", "Path to the tmp directory for libpod state content.\n\nNote: use the environment variable 'TMPDIR' to change the temporary storage location for container images, '/var/tmp'.\n")
- flags.BoolVar(&opts.Trace, "trace", false, "Enable opentracing output (default false)")
+ pFlags.StringVar(&opts.Engine.TmpDir, "tmpdir", "", "Path to the tmp directory for libpod state content.\n\nNote: use the environment variable 'TMPDIR' to change the temporary storage location for container images, '/var/tmp'.\n")
+ pFlags.BoolVar(&opts.Trace, "trace", false, "Enable opentracing output (default false)")
// Override default --help information of `--help` global flag
var dummyHelp bool
- flags.BoolVar(&dummyHelp, "help", false, "Help for podman")
- flags.StringVar(&logLevel, "log-level", logLevel, fmt.Sprintf("Log messages above specified level (%s)", strings.Join(logLevels, ", ")))
+ pFlags.BoolVar(&dummyHelp, "help", false, "Help for podman")
+ pFlags.StringVar(&logLevel, "log-level", logLevel, fmt.Sprintf("Log messages above specified level (%s)", strings.Join(logLevels, ", ")))
// Hide these flags for both ABI and Tunneling
for _, f := range []string{
@@ -256,13 +266,13 @@ func rootFlags(opts *entities.PodmanConfig, flags *pflag.FlagSet) {
"registries-conf",
"trace",
} {
- if err := flags.MarkHidden(f); err != nil {
+ if err := pFlags.MarkHidden(f); err != nil {
logrus.Warnf("unable to mark %s flag as hidden: %s", f, err.Error())
}
}
// Only create these flags for ABI connections
if !registry.IsRemote() {
- flags.BoolVar(&useSyslog, "syslog", false, "Output logging information to syslog as well as the console (default false)")
+ pFlags.BoolVar(&useSyslog, "syslog", false, "Output logging information to syslog as well as the console (default false)")
}
}
diff --git a/cmd/podman/system/connection.go b/cmd/podman/system/connection.go
index cb22522aa..bdb113ea3 100644
--- a/cmd/podman/system/connection.go
+++ b/cmd/podman/system/connection.go
@@ -60,7 +60,6 @@ func init() {
})
flags := connectionCmd.Flags()
- flags.StringVar(&cOpts.Identity, "identity", "", "path to ssh identity file")
flags.IntVarP(&cOpts.Port, "port", "p", 22, "port number for destination")
flags.StringVar(&cOpts.UDSPath, "socket-path", "", "path to podman socket on remote host. (default '/run/podman/podman.sock' or '/run/user/{uid}/podman/podman.sock)")
}
diff --git a/cmd/podman/system/system.go b/cmd/podman/system/system.go
index 6c4b26955..2dd6cf774 100644
--- a/cmd/podman/system/system.go
+++ b/cmd/podman/system/system.go
@@ -13,11 +13,10 @@ var (
// Command: podman _system_
systemCmd = &cobra.Command{
- Use: "system",
- Short: "Manage podman",
- Long: "Manage podman",
- TraverseChildren: true,
- RunE: validate.SubCommandExists,
+ Use: "system",
+ Short: "Manage podman",
+ Long: "Manage podman",
+ RunE: validate.SubCommandExists,
}
)
diff --git a/cmd/podman/validate/args.go b/cmd/podman/validate/args.go
index 69240798f..a33f47959 100644
--- a/cmd/podman/validate/args.go
+++ b/cmd/podman/validate/args.go
@@ -2,6 +2,7 @@ package validate
import (
"fmt"
+ "strconv"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -25,8 +26,122 @@ func SubCommandExists(cmd *cobra.Command, args []string) error {
// IDOrLatestArgs used to validate a nameOrId was provided or the "--latest" flag
func IDOrLatestArgs(cmd *cobra.Command, args []string) error {
- if len(args) > 1 || (len(args) == 0 && !cmd.Flag("latest").Changed) {
- return fmt.Errorf("`%s` requires a name, id or the \"--latest\" flag", cmd.CommandPath())
+ if len(args) > 1 {
+ return fmt.Errorf("`%s` accepts at most one argument", cmd.CommandPath())
+ }
+
+ latest := cmd.Flag("latest")
+ if latest != nil {
+ given, _ := strconv.ParseBool(cmd.Flag("latest").Value.String())
+ if len(args) == 0 && !given {
+ return fmt.Errorf("%q requires a name, id, or the \"--latest\" flag", cmd.CommandPath())
+ }
+ }
+ return nil
+}
+
+// TODO: the two functions CheckAllLatestAndCIDFile and CheckAllLatestAndPodIDFile are almost identical.
+// It may be worth looking into generalizing the two a bit more and share code but time is scarce and
+// we only live once.
+
+// CheckAllLatestAndCIDFile checks that --all and --latest are used correctly.
+// If cidfile is set, also check for the --cidfile flag.
+func CheckAllLatestAndCIDFile(c *cobra.Command, args []string, ignoreArgLen bool, cidfile bool) error {
+ argLen := len(args)
+ if c.Flags().Lookup("all") == nil || c.Flags().Lookup("latest") == nil {
+ if !cidfile {
+ return errors.New("unable to lookup values for 'latest' or 'all'")
+ } else if c.Flags().Lookup("cidfile") == nil {
+ return errors.New("unable to lookup values for 'latest', 'all' or 'cidfile'")
+ }
+ }
+
+ specifiedAll, _ := c.Flags().GetBool("all")
+ specifiedLatest, _ := c.Flags().GetBool("latest")
+ specifiedCIDFile := false
+ if cid, _ := c.Flags().GetStringArray("cidfile"); len(cid) > 0 {
+ specifiedCIDFile = true
+ }
+
+ if specifiedCIDFile && (specifiedAll || specifiedLatest) {
+ return errors.Errorf("--all, --latest and --cidfile cannot be used together")
+ } else if specifiedAll && specifiedLatest {
+ return errors.Errorf("--all and --latest cannot be used together")
+ }
+
+ if (argLen > 0) && specifiedAll {
+ return errors.Errorf("no arguments are needed with --all")
+ }
+
+ if ignoreArgLen {
+ return nil
+ }
+
+ if argLen > 0 {
+ if specifiedLatest {
+ return errors.Errorf("no arguments are needed with --latest")
+ } else if cidfile && (specifiedLatest || specifiedCIDFile) {
+ return errors.Errorf("no arguments are needed with --latest or --cidfile")
+ }
+ }
+
+ if specifiedCIDFile {
+ return nil
+ }
+
+ if argLen < 1 && !specifiedAll && !specifiedLatest && !specifiedCIDFile {
+ return errors.Errorf("you must provide at least one name or id")
+ }
+ return nil
+}
+
+// CheckAllLatestAndPodIDFile checks that --all and --latest are used correctly.
+// If withIDFile is set, also check for the --pod-id-file flag.
+func CheckAllLatestAndPodIDFile(c *cobra.Command, args []string, ignoreArgLen bool, withIDFile bool) error {
+ argLen := len(args)
+ if c.Flags().Lookup("all") == nil || c.Flags().Lookup("latest") == nil {
+ if !withIDFile {
+ return errors.New("unable to lookup values for 'latest' or 'all'")
+ } else if c.Flags().Lookup("pod-id-file") == nil {
+ return errors.New("unable to lookup values for 'latest', 'all' or 'pod-id-file'")
+ }
+ }
+
+ specifiedAll, _ := c.Flags().GetBool("all")
+ specifiedLatest, _ := c.Flags().GetBool("latest")
+ specifiedPodIDFile := false
+ if pid, _ := c.Flags().GetStringArray("pod-id-file"); len(pid) > 0 {
+ specifiedPodIDFile = true
+ }
+
+ if specifiedPodIDFile && (specifiedAll || specifiedLatest) {
+ return errors.Errorf("--all, --latest and --pod-id-file cannot be used together")
+ } else if specifiedAll && specifiedLatest {
+ return errors.Errorf("--all and --latest cannot be used together")
+ }
+
+ if (argLen > 0) && specifiedAll {
+ return errors.Errorf("no arguments are needed with --all")
+ }
+
+ if ignoreArgLen {
+ return nil
+ }
+
+ if argLen > 0 {
+ if specifiedLatest {
+ return errors.Errorf("no arguments are needed with --latest")
+ } else if withIDFile && (specifiedLatest || specifiedPodIDFile) {
+ return errors.Errorf("no arguments are needed with --latest or --pod-id-file")
+ }
+ }
+
+ if specifiedPodIDFile {
+ return nil
+ }
+
+ if argLen < 1 && !specifiedAll && !specifiedLatest && !specifiedPodIDFile {
+ return errors.Errorf("you must provide at least one name or id")
}
return nil
}
diff --git a/cmd/podman/validate/latest.go b/cmd/podman/validate/latest.go
new file mode 100644
index 000000000..0ebed7227
--- /dev/null
+++ b/cmd/podman/validate/latest.go
@@ -0,0 +1,15 @@
+package validate
+
+import (
+ "github.com/containers/libpod/v2/cmd/podman/registry"
+ "github.com/spf13/cobra"
+)
+
+func AddLatestFlag(cmd *cobra.Command, b *bool) {
+ // Initialization flag verification
+ cmd.Flags().BoolVarP(b, "latest", "l", false,
+ "Act on the latest container podman is aware of\nNot supported with the \"--remote\" flag")
+ if registry.IsRemote() {
+ _ = cmd.Flags().MarkHidden("latest")
+ }
+}
diff --git a/cmd/podman/volumes/volume.go b/cmd/podman/volumes/volume.go
index 4514be88a..3ef20a027 100644
--- a/cmd/podman/volumes/volume.go
+++ b/cmd/podman/volumes/volume.go
@@ -13,11 +13,10 @@ var (
// Command: podman _volume_
volumeCmd = &cobra.Command{
- Use: "volume",
- Short: "Manage volumes",
- Long: "Volumes are created in and can be shared between containers",
- TraverseChildren: true,
- RunE: validate.SubCommandExists,
+ Use: "volume",
+ Short: "Manage volumes",
+ Long: "Volumes are created in and can be shared between containers",
+ RunE: validate.SubCommandExists,
}
)
diff --git a/docs/source/markdown/podman-auto-update.1.md b/docs/source/markdown/podman-auto-update.1.md
index 90e581e42..73d75be1f 100644
--- a/docs/source/markdown/podman-auto-update.1.md
+++ b/docs/source/markdown/podman-auto-update.1.md
@@ -23,6 +23,9 @@ Note that `podman auto-update` relies on systemd and requires a fully-qualified
This enforcement is necessary to know which image to actually check and pull.
If an image ID was used, Podman would not know which image to check/pull anymore.
+Moreover, the systemd units are expected to be generated with `podman-generate-systemd --new`, or similar units that create new containers in order to run the updated images.
+Systemd units that start and stop a container cannot run a new image.
+
## OPTIONS
**--authfile**=*path*
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 3ec91a3ad..7c2903e33 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -623,6 +623,8 @@ When specifying ranges for both, the number of container ports in the range must
(e.g., `podman run -p 1234-1236:1222-1224 --name thisWorks -t busybox`
but not `podman run -p 1230-1236:1230-1240 --name RangeContainerPortsBiggerThanRangeHostPorts -t busybox`)
With ip: `podman run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage`
+Host port does not have to be specified (e.g. `podman run -p 127.0.0.1::80`).
+If it is not, the container port will be randomly assigned a port on the host.
Use `podman port` to see the actual mapping: `podman port CONTAINER $CONTAINERPORT`
**--publish-all**, **-P**=*true|false*
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index 7e91a06a3..6b6ab03f6 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -632,6 +632,9 @@ Both hostPort and containerPort can be specified as a range of ports.
When specifying ranges for both, the number of container ports in the range must match the number of host ports in the range.
+Host port does not have to be specified (e.g. `podman run -p 127.0.0.1::80`).
+If it is not, the container port will be randomly assigned a port on the host.
+
Use **podman port** to see the actual mapping: **podman port $CONTAINER $CONTAINERPORT**.
**--publish-all**, **-P**=**true**|**false**
diff --git a/docs/source/markdown/podman-system-service.1.md b/docs/source/markdown/podman-system-service.1.md
index 3ae414f7a..7d18a6832 100644
--- a/docs/source/markdown/podman-system-service.1.md
+++ b/docs/source/markdown/podman-system-service.1.md
@@ -13,6 +13,10 @@ If no endpoint is provided, defaults will be used. The default endpoint for a r
service is *unix:/run/podman/podman.sock* and rootless is *unix:/$XDG_RUNTIME_DIR/podman/podman.sock* (for
example *unix:/run/user/1000/podman/podman.sock*)
+The REST API provided by **podman system service** is split into two parts: a compatibility layer offering support for the Docker v1.40 API, and a Podman-native Libpod layer.
+Documentation for the latter is available at *https://docs.podman.io/en/latest/_static/api.html*.
+Both APIs are versioned, but the server will not reject requests with an unsupported version set.
+
## OPTIONS
**--time**, **-t**
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 934fe220f..7a547e565 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1015,6 +1015,12 @@ func (c *Container) init(ctx context.Context, retainRetries bool) error {
return err
}
+ for _, v := range c.config.NamedVolumes {
+ if err := c.chownVolume(v.Name); err != nil {
+ return err
+ }
+ }
+
// With the spec complete, do an OCI create
if err := c.ociRuntime.CreateContainer(c, nil); err != nil {
// Fedora 31 is carrying a patch to display improved error
@@ -1508,6 +1514,48 @@ func (c *Container) mountNamedVolume(v *ContainerNamedVolume, mountpoint string)
return vol, nil
}
+// Chown the specified volume if necessary.
+func (c *Container) chownVolume(volumeName string) error {
+ vol, err := c.runtime.state.Volume(volumeName)
+ if err != nil {
+ return errors.Wrapf(err, "error retrieving named volume %s for container %s", volumeName, c.ID())
+ }
+
+ uid := int(c.config.Spec.Process.User.UID)
+ gid := int(c.config.Spec.Process.User.GID)
+
+ vol.lock.Lock()
+ defer vol.lock.Unlock()
+
+ // The volume may need a copy-up. Check the state.
+ if err := vol.update(); err != nil {
+ return err
+ }
+
+ if vol.state.NeedsChown {
+ vol.state.NeedsChown = false
+ vol.state.UIDChowned = uid
+ vol.state.GIDChowned = gid
+
+ if err := vol.save(); err != nil {
+ return err
+ }
+ err := filepath.Walk(vol.MountPoint(), func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if err := os.Chown(path, uid, gid); err != nil {
+ return err
+ }
+ return nil
+ })
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
// cleanupStorage unmounts and cleans up the container's root filesystem
func (c *Container) cleanupStorage() error {
if !c.state.Mounted {
@@ -1854,8 +1902,8 @@ func (c *Container) unmount(force bool) error {
// this should be from chrootarchive.
// Container MUST be mounted before calling.
func (c *Container) copyWithTarFromImage(source, dest string) error {
- a := archive.NewDefaultArchiver()
-
+ mappings := idtools.NewIDMappingsFromMaps(c.config.IDMappings.UIDMap, c.config.IDMappings.GIDMap)
+ a := archive.NewArchiver(mappings)
if err := c.copyOwnerAndPerms(source, dest); err != nil {
return err
}
diff --git a/libpod/define/errors.go b/libpod/define/errors.go
index d41e00648..1e9179353 100644
--- a/libpod/define/errors.go
+++ b/libpod/define/errors.go
@@ -70,6 +70,10 @@ var (
// ErrInternal indicates an internal library error
ErrInternal = errors.New("internal libpod error")
+ // ErrPodPartialFail indicates that a pod operation was only partially
+ // successful, and some containers within the pod failed.
+ ErrPodPartialFail = errors.New("some containers failed")
+
// ErrDetach indicates that an attach session was manually detached by
// the user.
ErrDetach = utils.ErrDetach
diff --git a/libpod/events.go b/libpod/events.go
index 74c910004..7560940a5 100644
--- a/libpod/events.go
+++ b/libpod/events.go
@@ -1,6 +1,7 @@
package libpod
import (
+ "context"
"fmt"
"github.com/containers/libpod/v2/libpod/events"
@@ -75,16 +76,16 @@ func (v *Volume) newVolumeEvent(status events.Status) {
// Events is a wrapper function for everyone to begin tailing the events log
// with options
-func (r *Runtime) Events(options events.ReadOptions) error {
+func (r *Runtime) Events(ctx context.Context, options events.ReadOptions) error {
eventer, err := r.newEventer()
if err != nil {
return err
}
- return eventer.Read(options)
+ return eventer.Read(ctx, options)
}
// GetEvents reads the event log and returns events based on input filters
-func (r *Runtime) GetEvents(filters []string) ([]*events.Event, error) {
+func (r *Runtime) GetEvents(ctx context.Context, filters []string) ([]*events.Event, error) {
var readErr error
eventChannel := make(chan *events.Event)
options := events.ReadOptions{
@@ -98,7 +99,7 @@ func (r *Runtime) GetEvents(filters []string) ([]*events.Event, error) {
return nil, err
}
go func() {
- readErr = eventer.Read(options)
+ readErr = eventer.Read(ctx, options)
}()
if readErr != nil {
return nil, readErr
@@ -112,7 +113,7 @@ func (r *Runtime) GetEvents(filters []string) ([]*events.Event, error) {
// GetLastContainerEvent takes a container name or ID and an event status and returns
// the last occurrence of the container event
-func (r *Runtime) GetLastContainerEvent(nameOrID string, containerEvent events.Status) (*events.Event, error) {
+func (r *Runtime) GetLastContainerEvent(ctx context.Context, nameOrID string, containerEvent events.Status) (*events.Event, error) {
// check to make sure the event.Status is valid
if _, err := events.StringToStatus(containerEvent.String()); err != nil {
return nil, err
@@ -122,7 +123,7 @@ func (r *Runtime) GetLastContainerEvent(nameOrID string, containerEvent events.S
fmt.Sprintf("event=%s", containerEvent),
"type=container",
}
- containerEvents, err := r.GetEvents(filters)
+ containerEvents, err := r.GetEvents(ctx, filters)
if err != nil {
return nil, err
}
diff --git a/libpod/events/config.go b/libpod/events/config.go
index 8fe551c5d..c34408e63 100644
--- a/libpod/events/config.go
+++ b/libpod/events/config.go
@@ -1,6 +1,7 @@
package events
import (
+ "context"
"time"
"github.com/pkg/errors"
@@ -52,7 +53,7 @@ type Eventer interface {
// Write an event to a backend
Write(event Event) error
// Read an event from the backend
- Read(options ReadOptions) error
+ Read(ctx context.Context, options ReadOptions) error
// String returns the type of event logger
String() string
}
diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go
index 482435038..d341ca7b5 100644
--- a/libpod/events/journal_linux.go
+++ b/libpod/events/journal_linux.go
@@ -3,6 +3,7 @@
package events
import (
+ "context"
"fmt"
"strconv"
"time"
@@ -53,7 +54,7 @@ func (e EventJournalD) Write(ee Event) error {
}
// Read reads events from the journal and sends qualified events to the event channel
-func (e EventJournalD) Read(options ReadOptions) error {
+func (e EventJournalD) Read(ctx context.Context, options ReadOptions) error {
defer close(options.EventChannel)
eventOptions, err := generateEventOptions(options.Filters, options.Since, options.Until)
if err != nil {
diff --git a/libpod/events/logfile.go b/libpod/events/logfile.go
index 93e6fa3c9..28d0dc07e 100644
--- a/libpod/events/logfile.go
+++ b/libpod/events/logfile.go
@@ -1,6 +1,7 @@
package events
import (
+ "context"
"fmt"
"os"
@@ -40,7 +41,7 @@ func (e EventLogFile) Write(ee Event) error {
}
// Reads from the log file
-func (e EventLogFile) Read(options ReadOptions) error {
+func (e EventLogFile) Read(ctx context.Context, options ReadOptions) error {
defer close(options.EventChannel)
eventOptions, err := generateEventOptions(options.Filters, options.Since, options.Until)
if err != nil {
@@ -50,6 +51,17 @@ func (e EventLogFile) Read(options ReadOptions) error {
if err != nil {
return err
}
+ funcDone := make(chan bool)
+ copy := true
+ go func() {
+ select {
+ case <-funcDone:
+ // Do nothing
+ case <-ctx.Done():
+ copy = false
+ t.Kill(errors.New("hangup by client"))
+ }
+ }()
for line := range t.Lines {
event, err := newEventFromJSONString(line.Text)
if err != nil {
@@ -65,10 +77,11 @@ func (e EventLogFile) Read(options ReadOptions) error {
for _, filter := range eventOptions {
include = include && filter(event)
}
- if include {
+ if include && copy {
options.EventChannel <- event
}
}
+ funcDone <- true
return nil
}
diff --git a/libpod/events/nullout.go b/libpod/events/nullout.go
index f3b36e609..3eca9e8db 100644
--- a/libpod/events/nullout.go
+++ b/libpod/events/nullout.go
@@ -1,5 +1,9 @@
package events
+import (
+ "context"
+)
+
// EventToNull is an eventer type that only performs write operations
// and only writes to /dev/null. It is meant for unittests only
type EventToNull struct{}
@@ -10,7 +14,7 @@ func (e EventToNull) Write(ee Event) error {
}
// Read does nothing. Do not use it.
-func (e EventToNull) Read(options ReadOptions) error {
+func (e EventToNull) Read(ctx context.Context, options ReadOptions) error {
return nil
}
diff --git a/libpod/options.go b/libpod/options.go
index 573806308..3120a35d7 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1485,6 +1485,19 @@ func WithVolumeGID(gid int) VolumeCreateOption {
}
}
+// WithVolumeNeedsChown sets the NeedsChown flag for the volume.
+func WithVolumeNeedsChown() VolumeCreateOption {
+ return func(volume *Volume) error {
+ if volume.valid {
+ return define.ErrVolumeFinalized
+ }
+
+ volume.state.NeedsChown = true
+
+ return nil
+ }
+}
+
// withSetAnon sets a bool notifying libpod that this volume is anonymous and
// should be removed when containers using it are removed and volumes are
// specified for removal.
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index 14e6647be..a02b171e1 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -59,7 +59,7 @@ func (p *Pod) Start(ctx context.Context) (map[string]error, error) {
}
if len(ctrErrors) > 0 {
- return ctrErrors, errors.Wrapf(define.ErrCtrExists, "error starting some containers")
+ return ctrErrors, errors.Wrapf(define.ErrPodPartialFail, "error starting some containers")
}
defer p.newPodEvent(events.Start)
return nil, nil
@@ -139,7 +139,7 @@ func (p *Pod) StopWithTimeout(ctx context.Context, cleanup bool, timeout int) (m
}
if len(ctrErrors) > 0 {
- return ctrErrors, errors.Wrapf(define.ErrCtrExists, "error stopping some containers")
+ return ctrErrors, errors.Wrapf(define.ErrPodPartialFail, "error stopping some containers")
}
defer p.newPodEvent(events.Stop)
return nil, nil
@@ -208,7 +208,7 @@ func (p *Pod) Pause() (map[string]error, error) {
}
if len(ctrErrors) > 0 {
- return ctrErrors, errors.Wrapf(define.ErrCtrExists, "error pausing some containers")
+ return ctrErrors, errors.Wrapf(define.ErrPodPartialFail, "error pausing some containers")
}
defer p.newPodEvent(events.Pause)
return nil, nil
@@ -267,7 +267,7 @@ func (p *Pod) Unpause() (map[string]error, error) {
}
if len(ctrErrors) > 0 {
- return ctrErrors, errors.Wrapf(define.ErrCtrExists, "error unpausing some containers")
+ return ctrErrors, errors.Wrapf(define.ErrPodPartialFail, "error unpausing some containers")
}
defer p.newPodEvent(events.Unpause)
@@ -321,7 +321,7 @@ func (p *Pod) Restart(ctx context.Context) (map[string]error, error) {
}
if len(ctrErrors) > 0 {
- return ctrErrors, errors.Wrapf(define.ErrCtrExists, "error stopping some containers")
+ return ctrErrors, errors.Wrapf(define.ErrPodPartialFail, "error stopping some containers")
}
p.newPodEvent(events.Stop)
p.newPodEvent(events.Start)
@@ -387,7 +387,7 @@ func (p *Pod) Kill(signal uint) (map[string]error, error) {
}
if len(ctrErrors) > 0 {
- return ctrErrors, errors.Wrapf(define.ErrCtrExists, "error killing some containers")
+ return ctrErrors, errors.Wrapf(define.ErrPodPartialFail, "error killing some containers")
}
defer p.newPodEvent(events.Kill)
return nil, nil
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 4010c9bea..c073aabb5 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -309,7 +309,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
logrus.Debugf("Creating new volume %s for container", vol.Name)
// The volume does not exist, so we need to create it.
- volOptions := []VolumeCreateOption{WithVolumeName(vol.Name), WithVolumeUID(ctr.RootUID()), WithVolumeGID(ctr.RootGID())}
+ volOptions := []VolumeCreateOption{WithVolumeName(vol.Name), WithVolumeUID(ctr.RootUID()), WithVolumeGID(ctr.RootGID()), WithVolumeNeedsChown()}
if isAnonymous {
volOptions = append(volOptions, withSetAnon())
}
diff --git a/libpod/volume.go b/libpod/volume.go
index 72b080d1a..438957086 100644
--- a/libpod/volume.go
+++ b/libpod/volume.go
@@ -64,6 +64,14 @@ type VolumeState struct {
// create time, then cleared after the copy up is done and never set
// again.
NeedsCopyUp bool `json:"notYetMounted,omitempty"`
+ // NeedsChown indicates that the next time the volume is mounted into
+ // a container, the container will chown the volume to the container process
+ // UID/GID.
+ NeedsChown bool `json:"notYetChowned,omitempty"`
+ // UIDChowned is the UID the volume was chowned to.
+ UIDChowned int `json:"uidChowned,omitempty"`
+ // GIDChowned is the GID the volume was chowned to.
+ GIDChowned int `json:"gidChowned,omitempty"`
}
// Name retrieves the volume's name
@@ -113,13 +121,33 @@ func (v *Volume) Anonymous() bool {
}
// UID returns the UID the volume will be created as.
-func (v *Volume) UID() int {
- return v.config.UID
+func (v *Volume) UID() (int, error) {
+ v.lock.Lock()
+ defer v.lock.Unlock()
+
+ if !v.valid {
+ return -1, define.ErrVolumeRemoved
+ }
+
+ if v.state.UIDChowned > 0 {
+ return v.state.UIDChowned, nil
+ }
+ return v.config.UID, nil
}
// GID returns the GID the volume will be created as.
-func (v *Volume) GID() int {
- return v.config.GID
+func (v *Volume) GID() (int, error) {
+ v.lock.Lock()
+ defer v.lock.Unlock()
+
+ if !v.valid {
+ return -1, define.ErrVolumeRemoved
+ }
+
+ if v.state.GIDChowned > 0 {
+ return v.state.GIDChowned, nil
+ }
+ return v.config.GID, nil
}
// CreatedTime returns the time the volume was created at. It was not tracked
diff --git a/libpod/volume_inspect.go b/libpod/volume_inspect.go
index 5258792eb..85848f84f 100644
--- a/libpod/volume_inspect.go
+++ b/libpod/volume_inspect.go
@@ -65,8 +65,15 @@ func (v *Volume) Inspect() (*InspectVolumeData, error) {
for k, v := range v.config.Options {
data.Options[k] = v
}
- data.UID = v.config.UID
- data.GID = v.config.GID
+ var err error
+ data.UID, err = v.UID()
+ if err != nil {
+ return nil, err
+ }
+ data.GID, err = v.GID()
+ if err != nil {
+ return nil, err
+ }
data.Anonymous = v.config.IsAnon
return data, nil
diff --git a/pkg/api/handlers/compat/events.go b/pkg/api/handlers/compat/events.go
index 215d7c972..5acc94153 100644
--- a/pkg/api/handlers/compat/events.go
+++ b/pkg/api/handlers/compat/events.go
@@ -1,6 +1,7 @@
package compat
import (
+ "context"
"fmt"
"net/http"
@@ -45,13 +46,15 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
fromStart = true
}
+ eventCtx, eventCancel := context.WithCancel(r.Context())
eventChannel := make(chan *events.Event)
go func() {
readOpts := events.ReadOptions{FromStart: fromStart, Stream: query.Stream, Filters: libpodFilters, EventChannel: eventChannel, Since: query.Since, Until: query.Until}
- eventsError = runtime.Events(readOpts)
+ eventsError = runtime.Events(eventCtx, readOpts)
}()
if eventsError != nil {
utils.InternalServerError(w, eventsError)
+ eventCancel()
close(eventChannel)
return
}
@@ -59,6 +62,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
// If client disappears we need to stop listening for events
go func(done <-chan struct{}) {
<-done
+ eventCancel()
if _, ok := <-eventChannel; ok {
close(eventChannel)
}
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go
index fe7d8888e..2e11c0edb 100644
--- a/pkg/api/handlers/compat/networks.go
+++ b/pkg/api/handlers/compat/networks.go
@@ -285,7 +285,7 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
return
}
if !exists {
- utils.Error(w, "network not found", http.StatusNotFound, err)
+ utils.Error(w, "network not found", http.StatusNotFound, network.ErrNetworkNotFound)
return
}
if err := network.RemoveNetwork(config, name); err != nil {
diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go
index f9a651c5d..0d83218e3 100644
--- a/pkg/api/handlers/libpod/volumes.go
+++ b/pkg/api/handlers/libpod/volumes.go
@@ -86,6 +86,17 @@ func InspectVolume(w http.ResponseWriter, r *http.Request) {
utils.VolumeNotFound(w, name, err)
return
}
+ var uid, gid int
+ uid, err = vol.UID()
+ if err != nil {
+ utils.Error(w, "Error fetching volume UID", http.StatusInternalServerError, err)
+ return
+ }
+ gid, err = vol.GID()
+ if err != nil {
+ utils.Error(w, "Error fetching volume GID", http.StatusInternalServerError, err)
+ return
+ }
volResponse := entities.VolumeConfigResponse{
Name: vol.Name(),
Driver: vol.Driver(),
@@ -94,8 +105,8 @@ func InspectVolume(w http.ResponseWriter, r *http.Request) {
Labels: vol.Labels(),
Scope: vol.Scope(),
Options: vol.Options(),
- UID: vol.UID(),
- GID: vol.GID(),
+ UID: uid,
+ GID: gid,
}
utils.WriteResponse(w, http.StatusOK, volResponse)
}
@@ -130,6 +141,17 @@ func ListVolumes(w http.ResponseWriter, r *http.Request) {
}
volumeConfigs := make([]*entities.VolumeListReport, 0, len(vols))
for _, v := range vols {
+ var uid, gid int
+ uid, err = v.UID()
+ if err != nil {
+ utils.Error(w, "Error fetching volume UID", http.StatusInternalServerError, err)
+ return
+ }
+ gid, err = v.GID()
+ if err != nil {
+ utils.Error(w, "Error fetching volume GID", http.StatusInternalServerError, err)
+ return
+ }
config := entities.VolumeConfigResponse{
Name: v.Name(),
Driver: v.Driver(),
@@ -138,8 +160,8 @@ func ListVolumes(w http.ResponseWriter, r *http.Request) {
Labels: v.Labels(),
Scope: v.Scope(),
Options: v.Options(),
- UID: v.UID(),
- GID: v.GID(),
+ UID: uid,
+ GID: gid,
}
volumeConfigs = append(volumeConfigs, &entities.VolumeListReport{VolumeConfigResponse: config})
}
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index d68f6893a..8af6d3186 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -173,6 +173,10 @@ func (s *APIServer) Serve() error {
}()
}
+ // Before we start serving, ensure umask is properly set for container
+ // creation.
+ _ = syscall.Umask(0022)
+
go func() {
err := s.Server.Serve(s.Listener)
if err != nil && err != http.ErrServerClosed {
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index d5dce0b0f..596fc2cc1 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -741,7 +741,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
if ecode, err := ctr.Wait(); err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr {
// Check events
- event, err := ic.Libpod.GetLastContainerEvent(ctr.ID(), events.Exited)
+ event, err := ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited)
if err != nil {
logrus.Errorf("Cannot get exit code: %v", err)
exitCode = define.ExecErrorCodeNotFound
@@ -871,7 +871,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
if ecode, err := ctr.Wait(); err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr {
// Check events
- event, err := ic.Libpod.GetLastContainerEvent(ctr.ID(), events.Exited)
+ event, err := ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited)
if err != nil {
logrus.Errorf("Cannot get exit code: %v", err)
report.ExitCode = define.ExecErrorCodeNotFound
diff --git a/pkg/domain/infra/abi/events.go b/pkg/domain/infra/abi/events.go
index 50d7727ce..7a8185445 100644
--- a/pkg/domain/infra/abi/events.go
+++ b/pkg/domain/infra/abi/events.go
@@ -9,5 +9,5 @@ import (
func (ic *ContainerEngine) Events(ctx context.Context, opts entities.EventsOptions) error {
readOpts := events.ReadOptions{FromStart: opts.FromStart, Stream: opts.Stream, Filters: opts.Filter, EventChannel: opts.EventChan, Since: opts.Since, Until: opts.Until}
- return ic.Libpod.Events(readOpts)
+ return ic.Libpod.Events(ctx, readOpts)
}
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
index e8d55989f..d1f465362 100644
--- a/pkg/domain/infra/abi/pods.go
+++ b/pkg/domain/infra/abi/pods.go
@@ -67,14 +67,14 @@ func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opt
for _, p := range pods {
report := entities.PodKillReport{Id: p.ID()}
conErrs, err := p.Kill(uint(sig))
- if err != nil {
+ if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
report.Errs = []error{err}
reports = append(reports, &report)
continue
}
if len(conErrs) > 0 {
- for _, err := range conErrs {
- report.Errs = append(report.Errs, err)
+ for id, err := range conErrs {
+ report.Errs = append(report.Errs, errors.Wrapf(err, "error killing container %s", id))
}
reports = append(reports, &report)
continue
@@ -93,13 +93,13 @@ func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, op
for _, p := range pods {
report := entities.PodPauseReport{Id: p.ID()}
errs, err := p.Pause()
- if err != nil {
+ if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
report.Errs = []error{err}
continue
}
if len(errs) > 0 {
- for _, v := range errs {
- report.Errs = append(report.Errs, v)
+ for id, v := range errs {
+ report.Errs = append(report.Errs, errors.Wrapf(v, "error pausing container %s", id))
}
reports = append(reports, &report)
continue
@@ -118,13 +118,13 @@ func (ic *ContainerEngine) PodUnpause(ctx context.Context, namesOrIds []string,
for _, p := range pods {
report := entities.PodUnpauseReport{Id: p.ID()}
errs, err := p.Unpause()
- if err != nil {
+ if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
report.Errs = []error{err}
continue
}
if len(errs) > 0 {
- for _, v := range errs {
- report.Errs = append(report.Errs, v)
+ for id, v := range errs {
+ report.Errs = append(report.Errs, errors.Wrapf(v, "error unpausing container %s", id))
}
reports = append(reports, &report)
continue
@@ -143,13 +143,13 @@ func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, opt
for _, p := range pods {
report := entities.PodStopReport{Id: p.ID()}
errs, err := p.StopWithTimeout(ctx, false, options.Timeout)
- if err != nil {
+ if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
report.Errs = []error{err}
continue
}
if len(errs) > 0 {
- for _, v := range errs {
- report.Errs = append(report.Errs, v)
+ for id, v := range errs {
+ report.Errs = append(report.Errs, errors.Wrapf(v, "error stopping container %s", id))
}
reports = append(reports, &report)
continue
@@ -168,14 +168,14 @@ func (ic *ContainerEngine) PodRestart(ctx context.Context, namesOrIds []string,
for _, p := range pods {
report := entities.PodRestartReport{Id: p.ID()}
errs, err := p.Restart(ctx)
- if err != nil {
+ if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
report.Errs = []error{err}
reports = append(reports, &report)
continue
}
if len(errs) > 0 {
- for _, v := range errs {
- report.Errs = append(report.Errs, v)
+ for id, v := range errs {
+ report.Errs = append(report.Errs, errors.Wrapf(v, "error restarting container %s", id))
}
reports = append(reports, &report)
continue
@@ -195,14 +195,14 @@ func (ic *ContainerEngine) PodStart(ctx context.Context, namesOrIds []string, op
for _, p := range pods {
report := entities.PodStartReport{Id: p.ID()}
errs, err := p.Start(ctx)
- if err != nil {
+ if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
report.Errs = []error{err}
reports = append(reports, &report)
continue
}
if len(errs) > 0 {
- for _, v := range errs {
- report.Errs = append(report.Errs, v)
+ for id, v := range errs {
+ report.Errs = append(report.Errs, errors.Wrapf(v, "error starting container %s", id))
}
reports = append(reports, &report)
continue
diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go
index 861617eb6..8db89899e 100644
--- a/pkg/domain/infra/abi/volumes.go
+++ b/pkg/domain/infra/abi/volumes.go
@@ -95,6 +95,15 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
}
reports := make([]*entities.VolumeInspectReport, 0, len(vols))
for _, v := range vols {
+ var uid, gid int
+ uid, err = v.UID()
+ if err != nil {
+ return nil, err
+ }
+ gid, err = v.GID()
+ if err != nil {
+ return nil, err
+ }
config := entities.VolumeConfigResponse{
Name: v.Name(),
Driver: v.Driver(),
@@ -103,8 +112,8 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
Labels: v.Labels(),
Scope: v.Scope(),
Options: v.Options(),
- UID: v.UID(),
- GID: v.GID(),
+ UID: uid,
+ GID: gid,
}
reports = append(reports, &entities.VolumeInspectReport{VolumeConfigResponse: &config})
}
@@ -141,6 +150,15 @@ func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeL
}
reports := make([]*entities.VolumeListReport, 0, len(vols))
for _, v := range vols {
+ var uid, gid int
+ uid, err = v.UID()
+ if err != nil {
+ return nil, err
+ }
+ gid, err = v.GID()
+ if err != nil {
+ return nil, err
+ }
config := entities.VolumeConfigResponse{
Name: v.Name(),
Driver: v.Driver(),
@@ -149,8 +167,8 @@ func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeL
Labels: v.Labels(),
Scope: v.Scope(),
Options: v.Options(),
- UID: v.UID(),
- GID: v.GID(),
+ UID: uid,
+ GID: gid,
}
reports = append(reports, &entities.VolumeListReport{VolumeConfigResponse: config})
}
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index b1d6be016..879c66895 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -287,10 +287,11 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l
options = append(options, libpod.WithCommand(c.UserCommand))
}
- // Add entrypoint unconditionally
- // If it's empty it's because it was explicitly set to "" or the image
- // does not have one
- options = append(options, libpod.WithEntrypoint(c.Entrypoint))
+ // Add entrypoint if it was set
+ // If it's empty it's because it was explicitly set to ""
+ if c.Entrypoint != nil {
+ options = append(options, libpod.WithEntrypoint(c.Entrypoint))
+ }
// TODO: MNT, USER, CGROUP
options = append(options, libpod.WithStopSignal(c.StopSignal))
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index 3732d5431..0a485e7cd 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -52,10 +52,14 @@ func addRlimits(s *specgen.SpecGenerator, g *generate.Generator) error {
if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit); err != nil {
logrus.Warnf("failed to return RLIMIT_NOFILE ulimit %q", err)
}
- current = rlimit.Cur
- max = rlimit.Max
+ if rlimit.Cur < current {
+ current = rlimit.Cur
+ }
+ if rlimit.Max < max {
+ max = rlimit.Max
+ }
}
- g.AddProcessRlimits("RLIMIT_NOFILE", current, max)
+ g.AddProcessRlimits("RLIMIT_NOFILE", max, current)
}
if !nprocSet {
max := kernelMax
@@ -65,10 +69,14 @@ func addRlimits(s *specgen.SpecGenerator, g *generate.Generator) error {
if err := unix.Getrlimit(unix.RLIMIT_NPROC, &rlimit); err != nil {
logrus.Warnf("failed to return RLIMIT_NPROC ulimit %q", err)
}
- current = rlimit.Cur
- max = rlimit.Max
+ if rlimit.Cur < current {
+ current = rlimit.Cur
+ }
+ if rlimit.Max < max {
+ max = rlimit.Max
+ }
}
- g.AddProcessRlimits("RLIMIT_NPROC", current, max)
+ g.AddProcessRlimits("RLIMIT_NPROC", max, current)
}
return nil
diff --git a/pkg/specgen/generate/ports.go b/pkg/specgen/generate/ports.go
index b529fd4cd..9412ecfbf 100644
--- a/pkg/specgen/generate/ports.go
+++ b/pkg/specgen/generate/ports.go
@@ -43,6 +43,8 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
containerPortValidate[proto] = make(map[string]map[uint16]uint16)
}
+ postAssignHostPort := false
+
// Iterate through all port mappings, generating OCICNI PortMapping
// structs and validating there is no overlap.
for _, port := range portMappings {
@@ -71,9 +73,6 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
return nil, nil, nil, errors.Errorf("container port number must be non-0")
}
hostPort := port.HostPort
- if hostPort == 0 {
- hostPort = containerPort
- }
if uint32(len-1)+uint32(containerPort) > 65535 {
return nil, nil, nil, errors.Errorf("container port range exceeds maximum allowable port number")
}
@@ -105,26 +104,42 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
cPort := containerPort + index
hPort := hostPort + index
- if cPort == 0 || hPort == 0 {
- return nil, nil, nil, errors.Errorf("host and container ports cannot be 0")
- }
-
- testCPort := ctrPortMap[cPort]
- if testCPort != 0 && testCPort != hPort {
- // This is an attempt to redefine a port
- return nil, nil, nil, errors.Errorf("conflicting port mappings for container port %d (protocol %s)", cPort, p)
+ if cPort == 0 {
+ return nil, nil, nil, errors.Errorf("container port cannot be 0")
}
- ctrPortMap[cPort] = hPort
- testHPort := hostPortMap[hPort]
- if testHPort != 0 && testHPort != cPort {
- return nil, nil, nil, errors.Errorf("conflicting port mappings for host port %d (protocol %s)", hPort, p)
- }
- hostPortMap[hPort] = cPort
-
- // If we have an exact duplicate, just continue
- if testCPort == hPort && testHPort == cPort {
- continue
+ // Host port is allowed to be 0. If it is, we
+ // select a random port on the host.
+ // This will happen *after* all other ports are
+ // placed, to ensure we don't accidentally
+ // select a port that a later mapping wanted.
+ if hPort == 0 {
+ // If we already have a host port
+ // assigned to their container port -
+ // just use that.
+ if ctrPortMap[cPort] != 0 {
+ hPort = ctrPortMap[cPort]
+ } else {
+ postAssignHostPort = true
+ }
+ } else {
+ testCPort := ctrPortMap[cPort]
+ if testCPort != 0 && testCPort != hPort {
+ // This is an attempt to redefine a port
+ return nil, nil, nil, errors.Errorf("conflicting port mappings for container port %d (protocol %s)", cPort, p)
+ }
+ ctrPortMap[cPort] = hPort
+
+ testHPort := hostPortMap[hPort]
+ if testHPort != 0 && testHPort != cPort {
+ return nil, nil, nil, errors.Errorf("conflicting port mappings for host port %d (protocol %s)", hPort, p)
+ }
+ hostPortMap[hPort] = cPort
+
+ // If we have an exact duplicate, just continue
+ if testCPort == hPort && testHPort == cPort {
+ continue
+ }
}
// We appear to be clear. Make an OCICNI port
@@ -142,6 +157,61 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
}
}
+ // Handle any 0 host ports now by setting random container ports.
+ if postAssignHostPort {
+ remadeMappings := make([]ocicni.PortMapping, 0, len(finalMappings))
+
+ // Iterate over all
+ for _, p := range finalMappings {
+ if p.HostPort != 0 {
+ remadeMappings = append(remadeMappings, p)
+ continue
+ }
+
+ hostIPMap := hostPortValidate[p.Protocol]
+ ctrIPMap := containerPortValidate[p.Protocol]
+
+ hostPortMap, ok := hostIPMap[p.HostIP]
+ if !ok {
+ hostPortMap = make(map[uint16]uint16)
+ hostIPMap[p.HostIP] = hostPortMap
+ }
+ ctrPortMap, ok := ctrIPMap[p.HostIP]
+ if !ok {
+ ctrPortMap = make(map[uint16]uint16)
+ ctrIPMap[p.HostIP] = ctrPortMap
+ }
+
+ // See if container port has been used elsewhere
+ if ctrPortMap[uint16(p.ContainerPort)] != 0 {
+ // Duplicate definition. Let's not bother
+ // including it.
+ continue
+ }
+
+ // Max retries to ensure we don't loop forever.
+ for i := 0; i < 15; i++ {
+ candidate, err := getRandomPort()
+ if err != nil {
+ return nil, nil, nil, errors.Wrapf(err, "error getting candidate host port for container port %d", p.ContainerPort)
+ }
+
+ if hostPortMap[uint16(candidate)] == 0 {
+ logrus.Debugf("Successfully assigned container port %d to host port %d (IP %s Protocol %s)", p.ContainerPort, candidate, p.HostIP, p.Protocol)
+ hostPortMap[uint16(candidate)] = uint16(p.ContainerPort)
+ ctrPortMap[uint16(p.ContainerPort)] = uint16(candidate)
+ p.HostPort = int32(candidate)
+ break
+ }
+ }
+ if p.HostPort == 0 {
+ return nil, nil, nil, errors.Errorf("could not find open host port to map container port %d to", p.ContainerPort)
+ }
+ remadeMappings = append(remadeMappings, p)
+ }
+ return remadeMappings, containerPortValidate, hostPortValidate, nil
+ }
+
return finalMappings, containerPortValidate, hostPortValidate, nil
}
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index 03e840ab4..327c15c5a 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -430,7 +430,8 @@ type PortMapping struct {
ContainerPort uint16 `json:"container_port"`
// HostPort is the port number that will be forwarded from the host into
// the container.
- // If omitted, will be assumed to be identical to
+ // If omitted, a random port on the host (guaranteed to be over 1024)
+ // will be assigned.
HostPort uint16 `json:"host_port,omitempty"`
// Range is the number of ports that will be forwarded, starting at
// HostPort and ContainerPort and counting up.
diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go
index fe56dc874..d6d18a810 100644
--- a/pkg/systemd/generate/common.go
+++ b/pkg/systemd/generate/common.go
@@ -1,6 +1,8 @@
package generate
import (
+ "strings"
+
"github.com/pkg/errors"
)
@@ -44,6 +46,9 @@ func filterPodFlags(command []string) []string {
i++
continue
}
+ if strings.HasPrefix(s, "--pod=") || strings.HasPrefix(s, "--pod-id-file=") {
+ continue
+ }
processed = append(processed, s)
}
return processed
diff --git a/pkg/systemd/generate/common_test.go b/pkg/systemd/generate/common_test.go
index f53bb7828..389c30f59 100644
--- a/pkg/systemd/generate/common_test.go
+++ b/pkg/systemd/generate/common_test.go
@@ -1,6 +1,7 @@
package generate
import (
+ "strings"
"testing"
"github.com/stretchr/testify/assert"
@@ -14,12 +15,16 @@ func TestFilterPodFlags(t *testing.T) {
{[]string{"podman", "pod", "create"}},
{[]string{"podman", "pod", "create", "--name", "foo"}},
{[]string{"podman", "pod", "create", "--pod-id-file", "foo"}},
+ {[]string{"podman", "pod", "create", "--pod-id-file=foo"}},
{[]string{"podman", "run", "--pod", "foo"}},
+ {[]string{"podman", "run", "--pod=foo"}},
}
for _, test := range tests {
processed := filterPodFlags(test.input)
- assert.NotContains(t, processed, "--pod-id-file")
- assert.NotContains(t, processed, "--pod")
+ for _, s := range processed {
+ assert.False(t, strings.HasPrefix(s, "--pod-id-file"))
+ assert.False(t, strings.HasPrefix(s, "--pod"))
+ }
}
}
diff --git a/pkg/terminal/console_unix.go b/pkg/terminal/console_unix.go
new file mode 100644
index 000000000..6eee6aa2f
--- /dev/null
+++ b/pkg/terminal/console_unix.go
@@ -0,0 +1,8 @@
+// +build !windows
+
+package terminal
+
+// SetConsole for non-windows environments is a no-op
+func SetConsole() error {
+ return nil
+}
diff --git a/pkg/terminal/console_windows.go b/pkg/terminal/console_windows.go
new file mode 100644
index 000000000..c7691857c
--- /dev/null
+++ b/pkg/terminal/console_windows.go
@@ -0,0 +1,37 @@
+// +build windows
+
+package terminal
+
+import (
+ "github.com/sirupsen/logrus"
+ "golang.org/x/sys/windows"
+)
+
+// SetConsole switches the windows terminal mode to be able to handle colors, etc
+func SetConsole() error {
+ if err := setConsoleMode(windows.Stdout, windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err != nil {
+ return err
+ }
+ if err := setConsoleMode(windows.Stderr, windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err != nil {
+ return err
+ }
+ if err := setConsoleMode(windows.Stdin, windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err != nil {
+ return err
+ }
+ return nil
+}
+
+func setConsoleMode(handle windows.Handle, flags uint32) error {
+ var mode uint32
+ err := windows.GetConsoleMode(handle, &mode)
+ if err != nil {
+ return err
+ }
+ if err := windows.SetConsoleMode(handle, mode|flags); err != nil {
+ // In similar code, it is not considered an error if we cannot set the
+ // console mode. Following same line of thinking here.
+ logrus.WithError(err).Error("Failed to set console mode for cli")
+ }
+
+ return nil
+}
diff --git a/pkg/varlinkapi/attach.go b/pkg/varlinkapi/attach.go
index 731d89b8f..8acf2a1b6 100644
--- a/pkg/varlinkapi/attach.go
+++ b/pkg/varlinkapi/attach.go
@@ -4,6 +4,7 @@ package varlinkapi
import (
"bufio"
+ "context"
"io"
"github.com/containers/libpod/v2/libpod"
@@ -89,7 +90,7 @@ func (i *VarlinkAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys s
if ecode, err := ctr.Wait(); err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr {
// Check events
- event, err := i.Runtime.GetLastContainerEvent(ctr.ID(), events.Exited)
+ event, err := i.Runtime.GetLastContainerEvent(context.Background(), ctr.ID(), events.Exited)
if err != nil {
logrus.Errorf("Cannot get exit code: %v", err)
exitCode = define.ExecErrorCodeNotFound
diff --git a/pkg/varlinkapi/events.go b/pkg/varlinkapi/events.go
index 2e468b706..910b64a57 100644
--- a/pkg/varlinkapi/events.go
+++ b/pkg/varlinkapi/events.go
@@ -3,6 +3,7 @@
package varlinkapi
import (
+ "context"
"time"
"github.com/containers/libpod/v2/libpod/events"
@@ -27,7 +28,7 @@ func (i *VarlinkAPI) GetEvents(call iopodman.VarlinkCall, filter []string, since
eventChannel := make(chan *events.Event)
go func() {
readOpts := events.ReadOptions{FromStart: fromStart, Stream: stream, Filters: filter, EventChannel: eventChannel}
- eventsError = i.Runtime.Events(readOpts)
+ eventsError = i.Runtime.Events(context.Background(), readOpts)
}()
if eventsError != nil {
return call.ReplyErrorOccurred(eventsError.Error())
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index 87c476ecc..6633f3a53 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -143,6 +143,12 @@ var _ = SynchronizedBeforeSuite(func() []byte {
fmt.Println(err)
os.Exit(1)
}
+
+ // If running remote, we need to stop the associated podman system service
+ if podman.RemoteTest {
+ podman.StopRemoteService()
+ }
+
return []byte(path)
}, func(data []byte) {
LockTmpDir = string(data)
@@ -173,6 +179,10 @@ var _ = SynchronizedAfterSuite(func() {},
fmt.Printf("%q\n", err)
}
+ // If running remote, we need to stop the associated podman system service
+ if podmanTest.RemoteTest {
+ podmanTest.StopRemoteService()
+ }
// for localized tests, this removes the image cache dir and for remote tests
// this is a no-op
removeCache()
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 3d583bb8c..152c85704 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -466,4 +466,15 @@ var _ = Describe("Podman ps", func() {
Expect(ps.ExitCode()).To(Equal(0))
Expect(ps.OutputToString()).To(ContainSubstring("0.0.0.0:8080->80/tcp"))
})
+
+ It("podman ps truncate long create commad", func() {
+ session := podmanTest.Podman([]string{"run", ALPINE, "echo", "very", "long", "create", "command"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"ps", "-a"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.OutputToString()).To(ContainSubstring("echo very long cr..."))
+ })
+
})
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index dd018b910..6c049c5c1 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -184,6 +184,30 @@ var _ = Describe("Podman run networking", func() {
Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostIP).To(Equal(""))
})
+ It("podman run -p 127.0.0.1::8080/udp", func() {
+ name := "testctr"
+ session := podmanTest.Podman([]string{"create", "-t", "-p", "127.0.0.1::8080/udp", "--name", name, ALPINE, "/bin/sh"})
+ session.WaitWithDefaultTimeout()
+ inspectOut := podmanTest.InspectContainer(name)
+ Expect(len(inspectOut)).To(Equal(1))
+ Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1))
+ Expect(len(inspectOut[0].NetworkSettings.Ports["8080/udp"])).To(Equal(1))
+ Expect(inspectOut[0].NetworkSettings.Ports["8080/udp"][0].HostPort).To(Not(Equal("8080")))
+ Expect(inspectOut[0].NetworkSettings.Ports["8080/udp"][0].HostIP).To(Equal("127.0.0.1"))
+ })
+
+ It("podman run -p :8080", func() {
+ name := "testctr"
+ session := podmanTest.Podman([]string{"create", "-t", "-p", ":8080", "--name", name, ALPINE, "/bin/sh"})
+ session.WaitWithDefaultTimeout()
+ inspectOut := podmanTest.InspectContainer(name)
+ Expect(len(inspectOut)).To(Equal(1))
+ Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1))
+ Expect(len(inspectOut[0].NetworkSettings.Ports["8080/tcp"])).To(Equal(1))
+ Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostPort).To(Not(Equal("8080")))
+ Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostIP).To(Equal(""))
+ })
+
It("podman run network expose host port 80 to container port 8000", func() {
SkipIfRootless()
session := podmanTest.Podman([]string{"run", "-dt", "-p", "80:8000", ALPINE, "/bin/sh"})
diff --git a/test/e2e/run_userns_test.go b/test/e2e/run_userns_test.go
index e48a427d2..c0d98f7b1 100644
--- a/test/e2e/run_userns_test.go
+++ b/test/e2e/run_userns_test.go
@@ -245,4 +245,31 @@ var _ = Describe("Podman UserNS support", func() {
ok, _ := session.GrepString("4998")
Expect(ok).To(BeTrue())
})
+
+ It("podman --user with volume", func() {
+ tests := []struct {
+ uid, gid, arg, vol string
+ }{
+ {"0", "0", "0:0", "vol-0"},
+ {"1000", "0", "1000", "vol-1"},
+ {"1000", "1000", "1000:1000", "vol-2"},
+ }
+
+ for _, tt := range tests {
+ session := podmanTest.Podman([]string{"run", "-d", "--user", tt.arg, "--mount", "type=volume,src=" + tt.vol + ",dst=/home/user", "alpine", "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ inspectUID := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .UID }}", tt.vol})
+ inspectUID.WaitWithDefaultTimeout()
+ Expect(inspectUID.ExitCode()).To(Equal(0))
+ Expect(inspectUID.OutputToString()).To(Equal(tt.uid))
+
+ // Make sure we're defaulting to 0.
+ inspectGID := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .GID }}", tt.vol})
+ inspectGID.WaitWithDefaultTimeout()
+ Expect(inspectGID.ExitCode()).To(Equal(0))
+ Expect(inspectGID.OutputToString()).To(Equal(tt.gid))
+ }
+ })
})